diff --git a/.changeset/shaggy-zebras-kick.md b/.changeset/shaggy-zebras-kick.md new file mode 100644 index 0000000000..0d8c7f8031 --- /dev/null +++ b/.changeset/shaggy-zebras-kick.md @@ -0,0 +1,8 @@ +--- +"@marigold/docs": patch +"@marigold/components": major +"@marigold/theme-b2b": patch +"@marigold/theme-core": patch +--- + +[DST-461]: refactor `` component diff --git a/docs/content/components/content/message/message-error.demo.tsx b/docs/content/components/content/message/message-error.demo.tsx index f4aa191ed5..606cd79d59 100644 --- a/docs/content/components/content/message/message-error.demo.tsx +++ b/docs/content/components/content/message/message-error.demo.tsx @@ -1,7 +1,10 @@ import { Message, Text } from '@marigold/components'; export default () => ( - - Hello, I am a simple error message. + + Wrong here. + + Hello, I am a simple error message. + ); diff --git a/docs/content/components/content/message/message-info.demo.tsx b/docs/content/components/content/message/message-info.demo.tsx index 1dac2877eb..69833b4f18 100644 --- a/docs/content/components/content/message/message-info.demo.tsx +++ b/docs/content/components/content/message/message-info.demo.tsx @@ -1,7 +1,10 @@ import { Message, Text } from '@marigold/components'; export default () => ( - - Hello, I am a simple info message. + + There is an update available. + + Hello, I am a simple info message. + ); diff --git a/docs/content/components/content/message/message-warn.demo.tsx b/docs/content/components/content/message/message-warn.demo.tsx index 9a9688aa77..e6b23ed78d 100644 --- a/docs/content/components/content/message/message-warn.demo.tsx +++ b/docs/content/components/content/message/message-warn.demo.tsx @@ -1,7 +1,10 @@ import { Message, Text } from '@marigold/components'; export default () => ( - - Hello, I am a simple warning message. + + Danger Zone! + + Hello, I am a simple warning message. + ); diff --git a/docs/content/components/content/message/message.mdx b/docs/content/components/content/message/message.mdx index a40a994c45..c3d1081cfe 100644 --- a/docs/content/components/content/message/message.mdx +++ b/docs/content/components/content/message/message.mdx @@ -1,12 +1,15 @@ --- title: Message caption: Display a short message with important informations. +badge: updated --- The `` component is used to capture the users atention to provide information. It is meant to show only very relevant information. The title should contain the most relevant information about the message. This component should not be added on a dynymic way. +To properly structure the ``, use `` to add the title. For displaying text or similar content, use `` + There are currently three different variants of the `` component. The `info` variant is set as default. Inside the `` it lends itself to using the [``](/componentss/text/) component. ## Import diff --git a/docs/content/components/form/datepicker/datepicker.mdx b/docs/content/components/form/datepicker/datepicker.mdx index 13684ed97f..1132af2e5b 100644 --- a/docs/content/components/form/datepicker/datepicker.mdx +++ b/docs/content/components/form/datepicker/datepicker.mdx @@ -63,9 +63,12 @@ The `value` and `onChange` props can be used to control the `DatePicker`. When using a datepicker, relying on the standard JavaScript `Date` object for its value can result in timezone inconsistencies and incorrect date display. That's why the datepicker uses a specific `DateValue` type from [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/) instead. This library handles correct international date manipulation across calendars, time zones, and other localization concerns. - - `@internationalized/date` is a peer dependency. If it's not already in your - project, you'll need to install it. + + @internationalized/date + + `@internationalized/date` is a peer dependency. If it's not already in your + project, you'll need to install it. + The simplest way to parse a Date for the datepicker is by using `parseAbsoluteToLocal`. This function converts an absolute date and time into the current user's local time zone. diff --git a/docs/content/components/form/fieldgroup/field-group.mdx b/docs/content/components/form/fieldgroup/field-group.mdx index c7e9a0c6f8..cc63884036 100644 --- a/docs/content/components/form/fieldgroup/field-group.mdx +++ b/docs/content/components/form/fieldgroup/field-group.mdx @@ -5,8 +5,11 @@ caption: A component for organizing and structuring form data on the layout leve The `` designed primarily for handling of complex forms and semantic representation of fields structure and the layout in `theme-core` . - + + For your information! + The `` is a component to layout the label and the fieldbase itself. On that you can use `labelWidth` which is a string type to set the width of the label. Because the label is set to the left side in the `core-theme`, it has only an impact on that. + ### Import diff --git a/docs/content/components/form/form/form.mdx b/docs/content/components/form/form/form.mdx index 646f678888..859e6de046 100644 --- a/docs/content/components/form/form/form.mdx +++ b/docs/content/components/form/form/form.mdx @@ -99,6 +99,9 @@ As you can see in the previous server errors example, when a user submits a form

- - You can find more examples and usages of the `

` component on the [Validation](/concepts/validation) page and in the [Forms](/recipes/form-recipes) recipes. + + Want more?! + + You can find more examples and usages of the `` component on the [Validation](/concepts/validation) page and in the [Forms](/recipes/form-recipes) recipes. + diff --git a/docs/content/components/hooks-and-utils/extendTheme/extendTheme.mdx b/docs/content/components/hooks-and-utils/extendTheme/extendTheme.mdx index 569e3afb5a..0c9fca78ba 100644 --- a/docs/content/components/hooks-and-utils/extendTheme/extendTheme.mdx +++ b/docs/content/components/hooks-and-utils/extendTheme/extendTheme.mdx @@ -5,9 +5,12 @@ caption: Function used to customize theme components styles. With `extendTheme` you can add more variants and sizes to these components. It takes in the current theme you pass and returns an updated theme with added styles and configurations. - - You can **only** add a new variant to the theme, and you **should not** - override variant in the current theme. + + Adding new variant + + You can **only** add a new variant to the theme, and you **should not** + override variant in the current theme. + ## Import diff --git a/docs/content/develop/component-guidelines.mdx b/docs/content/develop/component-guidelines.mdx index 85f27b9d6b..acc1a383df 100644 --- a/docs/content/develop/component-guidelines.mdx +++ b/docs/content/develop/component-guidelines.mdx @@ -63,24 +63,30 @@ components Example of how we write tests: ```tsx -test('accepts a variant with parts and an icon', () => { +test('accepts a variant with parts and an icon and support grid areas', () => { render( - - Danger + + info + Danger ); - const container = screen.getByTestId('messages'); const title = screen.getByText('info'); const content = screen.getByText('Danger'); + // eslint-disable-next-line testing-library/no-node-access + const icon = container.firstChild; expect(container.className).toMatchInlineSnapshot( - `"grid auto-rows-min grid-cols-[min-content_auto] gap-1 text-orange-700"` + `"grid auto-rows-min text-orange-700"` + ); + expect(content.className).toMatchInlineSnapshot( + `"[grid-area:content] items-end"` ); - expect(content.className).toMatchInlineSnapshot(`"col-start-2 items-end"`); expect(title.className).toMatchInlineSnapshot( - `"col-start-2 row-start-1 self-center font-bold"` + `"[grid-area:title] font-bold"` ); + + expect(icon).toBeInTheDocument(); }); ``` @@ -109,19 +115,6 @@ const meta = { options: ['info', 'warning', 'error'], description: 'The variants of the message', }, - messageTitle: { - control: { - type: 'text', - }, - description: 'Content', - table: { - type: { summary: 'string' }, - defaultValue: { summary: 'Danger Zone!' }, - }, - }, - }, - args: { - messageTitle: 'Danger Zone!', }, } satisfies Meta; @@ -131,7 +124,10 @@ type Story = StoryObj; export const Basic: Story = { render: args => ( - Hello, I am a simple message. + Hint + + Hello, I am a simple message. + ), }; @@ -199,8 +195,11 @@ type RemovedProps = 'className'; export interface ComponentProps extends Omit {} ``` - + + Escape hatch + Use a regular `
` (or any other HTML element) and add available classes from our theme. + ### A UI Component must be themable diff --git a/docs/content/introduction/design-token-guidelines.mdx b/docs/content/introduction/design-token-guidelines.mdx index d5440f8aac..4412d2f4cc 100644 --- a/docs/content/introduction/design-token-guidelines.mdx +++ b/docs/content/introduction/design-token-guidelines.mdx @@ -6,11 +6,14 @@ order: 4 On this page, you'll discover detailed specifications for design tokens — the foundational elements that unify the visual language of your brand or products. Explore how design tokens are constructed and find information on where each token is applied within the design ecosystem. - + + View the tokens + For those interested in understanding our token structure, the most effective way is to explore the JSON structure directly. Note that tokens directly derived from Tailwind CSS are omitted for brevity. [View tokens as JSON](https://jsonhero.io/j/1IFlkqLbLbSM) + ## Naming Convention @@ -35,9 +38,12 @@ The name of a design token describes how it should be used, with each part indic Color tokens leverage the primitive tokens that form the color palettes of our design system. They provide a systematic approach to managing and applying colors consistently across various elements, while ensuring a cohesive and harmonious visual identity. - - Text color tokens can also be employed to colorize icons since they all have - the `currentColor` CSS rule applied. + + Icon Color + + Text color tokens can also be employed to colorize icons since they all have + the `currentColor` CSS rule applied. + ### Text @@ -174,10 +180,13 @@ There are no semantic values assigned to these tokens, as their usage does not n Height tokens follow a 4-pixel grid convention, implying that their values are adjusted in increments of 4 pixels. Each token represents a multiplier of that grid. For example, a value of 2 would equate to 8 pixels. - - The relevance of height is limited to specific components. In numerous cases, - a component's size must align with its contents. Therefore, the use of tokens - is not obligatory in every instance. + + Not mandatory + + The relevance of height is limited to specific components. In numerous + cases, a component's size must align with its contents. Therefore, the use + of tokens is not obligatory in every instance. + #### Intents diff --git a/docs/content/introduction/design-tokens.mdx b/docs/content/introduction/design-tokens.mdx index 121c25525c..a59b7400e9 100644 --- a/docs/content/introduction/design-tokens.mdx +++ b/docs/content/introduction/design-tokens.mdx @@ -7,9 +7,12 @@ badge: updated Design tokens are the foundational elements of our design system, defining key aspects of our product's visual language. They enable consistency and flexibility, allowing us to maintain a unified look and feel across all user interfaces. - - Since we have two themes, the values displayed show the available tokens in - the currently selected theme. + + Changing Theme + + Since we have two themes, the values displayed show the available tokens in + the currently selected theme. + ## Colors diff --git a/docs/content/introduction/getting-started.mdx b/docs/content/introduction/getting-started.mdx index ad35bff15f..0d4696aa34 100644 --- a/docs/content/introduction/getting-started.mdx +++ b/docs/content/introduction/getting-started.mdx @@ -8,9 +8,12 @@ To integrate Marigold into your React app, follow the steps outlined below. Mari Please bear in mind that certain steps may vary depending on your specific setup. You can find examples for the most common setups down below. - - Experience Marigold right away by trying it out in our [interactive - playground](https://play.marigold-ui.io/)! + + Good to know! + + Experience Marigold right away by trying it out in our [interactive + playground](https://play.marigold-ui.io/)! + ## Installation @@ -166,10 +169,13 @@ module.exports = { This will set up TailwindCSS as a PostCSS plugin and works with common tools, like `vite` or `next.js`. - - If you are using TypeScript, make sure to set the [module - resolution](https://www.typescriptlang.org/tsconfig#moduleResolution) to - `'nodenext'` since the theme packages are using ESM. + + TypeScript Configuration + + If you are using TypeScript, make sure to set the [module + resolution](https://www.typescriptlang.org/tsconfig#moduleResolution) to + `'nodenext'` since the theme packages are using ESM. + After configuring Tailwind CSS and adding the preset, wrap your app with the MarigoldProvider. Unlike before, you no longer have to import the CSS file of the selected theme separately. diff --git a/docs/content/patterns/building-forms/building-forms.mdx b/docs/content/patterns/building-forms/building-forms.mdx index 753cea1683..2172b40af6 100644 --- a/docs/content/patterns/building-forms/building-forms.mdx +++ b/docs/content/patterns/building-forms/building-forms.mdx @@ -94,10 +94,13 @@ In HTML, forms are build using the `` element, which wraps a set of input The simplest way to get data from a form is using the browser's [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) API during the `onSubmit` event. This can be passed directly to `fetch`, or converted into a regular JavaScript object using `Object.fromEntries`. - - Make sure to include the name attribute in each field, as it uniquely - identifies each form element, facilitating server-side processing and ensuring - a key-value pair for data submission. + + Names are important! + + Make sure to include the name attribute in each field, as it uniquely + identifies each form element, facilitating server-side processing and + ensuring a key-value pair for data submission. + Below is a basic example of extracting data from an [uncontrolled](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components) form. Submitting a promo code won't trigger a regular form submission; instead, it will display the provided data. diff --git a/docs/content/recipes/form-recipes.mdx b/docs/content/recipes/form-recipes.mdx index 2b000401fa..da3f2ce2c6 100644 --- a/docs/content/recipes/form-recipes.mdx +++ b/docs/content/recipes/form-recipes.mdx @@ -7,8 +7,11 @@ We used for these examples form components like ``, [``]( `` is wrapped around the other components as you can see in the examples below. With its prop `labelWidth` we set the width of the label to a certain amount, so it has a clean look. - - Please note that the form components need to have a label prop. + + Note + + Please note that the form components need to have a label prop. + ## Organization Search Form diff --git a/packages/components/src/Message/Context.tsx b/packages/components/src/Message/Context.tsx new file mode 100644 index 0000000000..75e6eec370 --- /dev/null +++ b/packages/components/src/Message/Context.tsx @@ -0,0 +1,12 @@ +import { createContext, useContext } from 'react'; + +export const SectionMessageContext = createContext<{ + classNames: { + container: string; + icon: string; + title: string; + content: string; + }; +}>({} as any); + +export const useSectionMessageContext = () => useContext(SectionMessageContext); diff --git a/packages/components/src/Message/Message.stories.tsx b/packages/components/src/Message/Message.stories.tsx index 57cb231fac..03675a3320 100644 --- a/packages/components/src/Message/Message.stories.tsx +++ b/packages/components/src/Message/Message.stories.tsx @@ -14,19 +14,6 @@ const meta = { options: ['success', 'info', 'warning', 'error'], description: 'The variants of the message', }, - messageTitle: { - control: { - type: 'text', - }, - description: 'Content', - table: { - type: { summary: 'string' }, - defaultValue: { summary: 'Danger Zone!' }, - }, - }, - }, - args: { - messageTitle: 'Danger Zone!', }, } satisfies Meta; @@ -36,7 +23,10 @@ type Story = StoryObj; export const Basic: Story = { render: args => ( - Hello, I am a simple message. + Danger Zone! + + Hello, I am a simple message. + ), }; @@ -44,11 +34,13 @@ export const Basic: Story = { export const MultiLineTitle: Story = { render: args => (
- - I am really not that good at righting copy texts, sorry. + + + I am really not that good at righting copy texts, sorry. + + + Hey! You! I am an info box! Please notice me, it might help you! +
), @@ -57,15 +49,18 @@ export const MultiLineTitle: Story = { export const LongMessage: Story = { render: args => ( - - In up so discovery my middleton eagerness dejection explained. - Estimating excellence ye contrasted insensible as. Oh up unsatiable - advantages decisively as at interested. Present suppose in esteems in - demesne colonel it to. End horrible she landlord screened stanhill. - Repeated offended you opinions off dissuade ask packages screened. She - alteration everything sympathize impossible his get compliment. - Collected few extremity suffering met had sportsman. - + Danger Zone! + + + In up so discovery my middleton eagerness dejection explained. + Estimating excellence ye contrasted insensible as. Oh up unsatiable + advantages decisively as at interested. Present suppose in esteems in + demesne colonel it to. End horrible she landlord screened stanhill. + Repeated offended you opinions off dissuade ask packages screened. She + alteration everything sympathize impossible his get compliment. + Collected few extremity suffering met had sportsman. + + ), }; diff --git a/packages/components/src/Message/Message.test.tsx b/packages/components/src/Message/Message.test.tsx index 462317c5c1..6e30630594 100644 --- a/packages/components/src/Message/Message.test.tsx +++ b/packages/components/src/Message/Message.test.tsx @@ -1,5 +1,4 @@ import { screen } from '@testing-library/react'; -import { createRef } from 'react'; import { Theme, ThemeProvider, cva } from '@marigold/system'; @@ -51,8 +50,9 @@ const { render } = setup({ theme }); test('message container supports base styling and themeSection', () => { render( - - Default + + Default + Default Content ); @@ -60,10 +60,11 @@ test('message container supports base styling and themeSection', () => { expect(message).toHaveClass(`text-blue-500`); }); -test('accepts a variant with parts and an icon', () => { +test('accepts a variant with parts and an icon and support grid areas', () => { render( - - Danger + + info + Danger ); const container = screen.getByTestId('messages'); @@ -73,11 +74,13 @@ test('accepts a variant with parts and an icon', () => { const icon = container.firstChild; expect(container.className).toMatchInlineSnapshot( - `"grid auto-rows-min grid-cols-[min-content_auto] gap-1 text-orange-700"` + `"grid auto-rows-min text-orange-700"` + ); + expect(content.className).toMatchInlineSnapshot( + `"[grid-area:content] items-end"` ); - expect(content.className).toMatchInlineSnapshot(`"col-start-2 items-end"`); expect(title.className).toMatchInlineSnapshot( - `"col-start-2 row-start-1 self-center font-bold"` + `"[grid-area:title] font-bold"` ); expect(icon).toBeInTheDocument(); @@ -85,8 +88,9 @@ test('accepts a variant with parts and an icon', () => { test('accepts error variant', () => { render( - - Error + + error + Error ); @@ -97,8 +101,9 @@ test('accepts error variant', () => { test('accepts size', () => { render( - - error + + error + Error ); const message = screen.getByTestId(/messages/); @@ -109,8 +114,9 @@ test('accepts size', () => { test('renders correct HTML element', () => { render( - - Default + + messages + default ); @@ -118,16 +124,3 @@ test('renders correct HTML element', () => { expect(message instanceof HTMLDivElement).toBeTruthy(); }); - -test('forwards ref', () => { - const ref = createRef(); - render( - - - Default - - - ); - - expect(ref.current instanceof HTMLDivElement).toBeTruthy(); -}); diff --git a/packages/components/src/Message/Message.tsx b/packages/components/src/Message/Message.tsx index a5afddb2cd..31d9d6e4e5 100755 --- a/packages/components/src/Message/Message.tsx +++ b/packages/components/src/Message/Message.tsx @@ -1,9 +1,10 @@ -import { forwardRef } from 'react'; -import type { ReactNode } from 'react'; - import { cn, useClassNames } from '@marigold/system'; import { HtmlProps } from '@marigold/types'; +import { SectionMessageContext } from './Context'; +import { SectionMessageContent } from './SectionMessageContent'; +import { SectionMessageTitle } from './SectionMessageTitle'; + // Icons // --------------- const icons = { @@ -64,43 +65,40 @@ const icons = { // Props // --------------- export interface MessageProps extends Omit, 'className'> { - /** - * Set a message title. This is required. - */ - messageTitle: ReactNode; variant?: keyof typeof icons; size?: string; } // Component // --------------- -export const Message = forwardRef( - ({ messageTitle, variant = 'info', size, children, ...props }, ref) => { - const classNames = useClassNames({ component: 'Message', variant, size }); - const Icon = icons[variant]; +export const Message = ({ + variant = 'info', + size, + children, + ...props +}: MessageProps) => { + const classNames = useClassNames({ component: 'Message', variant, size }); + const Icon = icons[variant]; - return ( + return ( +
-
- -
- {messageTitle} +
-
{children}
+ {children}
- ); - } -); +
+ ); +}; + +Message.Title = SectionMessageTitle; +Message.Content = SectionMessageContent; diff --git a/packages/components/src/Message/SectionMessageContent.tsx b/packages/components/src/Message/SectionMessageContent.tsx new file mode 100644 index 0000000000..e000a13a68 --- /dev/null +++ b/packages/components/src/Message/SectionMessageContent.tsx @@ -0,0 +1,20 @@ +import type { ReactNode } from 'react'; + +import { cn } from '@marigold/system'; + +import { useSectionMessageContext } from './Context'; + +export interface SectionMessageContentProps { + children?: ReactNode; +} + +export const SectionMessageContent = ({ + children, +}: SectionMessageContentProps) => { + const { classNames } = useSectionMessageContext(); + return ( +
+ {children} +
+ ); +}; diff --git a/packages/components/src/Message/SectionMessageTitle.tsx b/packages/components/src/Message/SectionMessageTitle.tsx new file mode 100644 index 0000000000..ae675881e1 --- /dev/null +++ b/packages/components/src/Message/SectionMessageTitle.tsx @@ -0,0 +1,16 @@ +import type { ReactNode } from 'react'; + +import { cn } from '@marigold/system'; + +import { useSectionMessageContext } from './Context'; + +export interface SectionMessageTitleProps { + children?: ReactNode; +} + +export const SectionMessageTitle = ({ children }: SectionMessageTitleProps) => { + const { classNames } = useSectionMessageContext(); + return ( +
{children}
+ ); +}; diff --git a/themes/theme-b2b/src/components/Message.styles.ts b/themes/theme-b2b/src/components/Message.styles.ts index 97438e5721..7fe5a5d1c2 100644 --- a/themes/theme-b2b/src/components/Message.styles.ts +++ b/themes/theme-b2b/src/components/Message.styles.ts @@ -3,6 +3,7 @@ import { ThemeComponent, cva } from '@marigold/system'; export const Message: ThemeComponent<'Message'> = { container: cva( [ + 'grid-cols-[min-content,auto] gap-1 [grid-template-areas:"icon_title""content_content"]', 'bg-bg-surface border-y-2 border-l-[16px] border-r-2 border-solid text-sm', 'items-center px-4 pb-4 pt-2', ], diff --git a/themes/theme-core/src/components/Message.styles.ts b/themes/theme-core/src/components/Message.styles.ts index 8f45f9e8be..c09666ddd1 100644 --- a/themes/theme-core/src/components/Message.styles.ts +++ b/themes/theme-core/src/components/Message.styles.ts @@ -1,16 +1,19 @@ import { ThemeComponent, cva } from '@marigold/system'; export const Message: ThemeComponent<'Message'> = { - container: cva('bg-bg-base border border-solid px-4 py-2 text-[13px]', { - variants: { - variant: { - warning: 'border-border-warning', - error: 'border-border-error', - info: 'border-border-info', - success: 'border-border-success', + container: cva( + 'bg-bg-base border border-solid px-4 py-2 text-[13px] [grid-template-areas:"title""content"]', + { + variants: { + variant: { + warning: 'border-border-warning', + error: 'border-border-error', + info: 'border-border-info', + success: 'border-border-success', + }, }, - }, - }), + } + ), title: cva('font-bold', { variants: { variant: { diff --git a/themes/theme-docs/src/components/Message.styles.ts b/themes/theme-docs/src/components/Message.styles.ts index aff47d87c9..be06a9e7a9 100644 --- a/themes/theme-docs/src/components/Message.styles.ts +++ b/themes/theme-docs/src/components/Message.styles.ts @@ -1,15 +1,21 @@ import { ThemeComponent, cva } from '@marigold/system'; export const Message: ThemeComponent<'Message'> = { - container: cva('not-prose relative w-full rounded-lg p-4 pl-11', { - variants: { - variant: { - info: 'bg-bg-info text-text-info', - warning: 'bg-bg-warning text-text-warning', + container: cva( + [ + 'not-prose items-center rounded-lg p-4', + 'grid-cols-[min-content,auto] gap-1 [grid-template-areas:"icon_title_title""none_content_content"]', + ], + { + variants: { + variant: { + info: 'bg-bg-info text-text-info', + warning: 'bg-bg-warning text-text-warning', + }, }, - }, - }), - icon: cva('absolute left-3 top-3 block size-6'), + } + ), + icon: cva('size-6'), title: cva('mb-1 font-bold leading-none tracking-tight'), content: cva('text-sm [&_p]:leading-relaxed'), };