From 2a570642269c69fff6dd573eddddc5fbb39e84f9 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Tue, 27 Jan 2026 17:19:08 +0100 Subject: [PATCH] docs(ui): comprehensive documentation improvements for all components Improves documentation quality and consistency across all UI components. Props documentation: - Added descriptions to all props across all components - Fixed prop types to match source implementations - Added missing props (onAction, isInvalid, aria-label, etc.) - Corrected default values and removed non-existent props - Converted props-definition files to .tsx for Chip component usage Examples and snippets: - Added side-by-side layout option to Snippet component - Fixed snippet/preview mismatches - Improved example code indentation and formatting - Added live previews to Container, Box, Grid examples - Wrapped Skeleton examples in themed Box for visibility API reference: - Added ReactAriaLinks to all components - Updated React Aria URLs to react-aria.adobe.com format - Cleaned up verbose prose and standardized descriptions Other: - Updated PageTitle descriptions to 5-12 word format - Varied example intro phrasing for consistency Signed-off-by: Johan Persson --- docs-ui/src/app/components/accordion/page.mdx | 29 +- .../components/accordion/props-definition.ts | 23 ++ docs-ui/src/app/components/avatar/page.mdx | 14 +- .../app/components/avatar/props-definition.ts | 28 -- .../components/avatar/props-definition.tsx | 41 ++ docs-ui/src/app/components/avatar/snippets.ts | 22 +- docs-ui/src/app/components/box/components.tsx | 60 +-- docs-ui/src/app/components/box/page.mdx | 29 +- .../app/components/box/props-definition.ts | 24 -- .../app/components/box/props-definition.tsx | 46 +++ docs-ui/src/app/components/box/snippets.ts | 34 +- .../src/app/components/button-icon/page.mdx | 17 +- .../button-icon/props-definition.ts | 31 -- .../button-icon/props-definition.tsx | 64 +++ .../app/components/button-icon/snippets.ts | 3 +- .../src/app/components/button-link/page.mdx | 27 +- .../button-link/props-definition.ts | 32 -- .../button-link/props-definition.tsx | 74 ++++ docs-ui/src/app/components/button/page.mdx | 43 ++- .../app/components/button/props-definition.ts | 30 -- .../components/button/props-definition.tsx | 69 ++++ docs-ui/src/app/components/button/snippets.ts | 72 ++-- .../src/app/components/card/components.tsx | 5 +- docs-ui/src/app/components/card/page.mdx | 31 +- .../app/components/card/props-definition.ts | 18 +- docs-ui/src/app/components/card/snippets.ts | 21 +- docs-ui/src/app/components/checkbox/page.mdx | 11 +- .../components/checkbox/props-definition.ts | 35 +- .../app/components/container/components.tsx | 41 +- docs-ui/src/app/components/container/page.mdx | 29 +- .../components/container/props-definition.ts | 44 ++- .../src/app/components/container/snippets.ts | 8 +- .../src/app/components/dialog/components.tsx | 14 + docs-ui/src/app/components/dialog/page.mdx | 20 +- .../app/components/dialog/props-definition.ts | 52 +-- docs-ui/src/app/components/dialog/snippets.ts | 13 +- .../src/app/components/flex/components.tsx | 75 ++-- docs-ui/src/app/components/flex/page.mdx | 51 ++- .../app/components/flex/props-definition.ts | 27 -- .../app/components/flex/props-definition.tsx | 64 +++ docs-ui/src/app/components/flex/snippets.ts | 28 +- .../src/app/components/grid/components.tsx | 91 +++-- docs-ui/src/app/components/grid/page.mdx | 44 ++- .../app/components/grid/props-definition.ts | 22 -- .../app/components/grid/props-definition.tsx | 113 ++++++ docs-ui/src/app/components/grid/snippets.ts | 19 +- .../app/components/header-page/components.tsx | 37 +- .../src/app/components/header-page/page.mdx | 35 +- .../header-page/props-definition.ts | 89 ----- .../header-page/props-definition.tsx | 69 ++++ .../app/components/header-page/snippets.ts | 41 +- .../src/app/components/header/components.tsx | 34 +- docs-ui/src/app/components/header/page.mdx | 31 +- .../app/components/header/props-definition.ts | 83 ---- .../components/header/props-definition.tsx | 63 +++ docs-ui/src/app/components/header/snippets.ts | 91 +---- .../src/app/components/link/components.tsx | 82 ++-- docs-ui/src/app/components/link/page.mdx | 36 +- .../app/components/link/props-definition.ts | 45 --- .../app/components/link/props-definition.tsx | 73 ++++ docs-ui/src/app/components/link/snippets.ts | 53 +-- .../src/app/components/menu/components.tsx | 46 ++- docs-ui/src/app/components/menu/page.mdx | 123 +++--- .../app/components/menu/props-definition.ts | 241 ------------ .../app/components/menu/props-definition.tsx | 364 ++++++++++++++++++ docs-ui/src/app/components/menu/snippets.ts | 75 ++-- .../components/password-field/components.tsx | 31 +- .../app/components/password-field/page.mdx | 50 ++- .../password-field/props-definition.ts | 26 -- .../password-field/props-definition.tsx | 77 ++++ .../app/components/password-field/snippets.ts | 22 +- .../src/app/components/popover/components.tsx | 48 ++- docs-ui/src/app/components/popover/page.mdx | 45 ++- .../components/popover/props-definition.ts | 54 ++- .../src/app/components/popover/snippets.ts | 44 ++- .../src/app/components/radio-group/page.mdx | 38 +- .../radio-group/props-definition.ts | 30 -- .../radio-group/props-definition.tsx | 91 +++++ .../app/components/radio-group/snippets.ts | 7 +- .../components/search-field/components.tsx | 35 +- .../src/app/components/search-field/page.mdx | 26 +- .../search-field/props-definition.ts | 34 -- .../search-field/props-definition.tsx | 85 ++++ .../app/components/search-field/snippets.ts | 31 +- docs-ui/src/app/components/select/page.mdx | 66 ++-- .../app/components/select/props-definition.ts | 111 ------ .../components/select/props-definition.tsx | 137 +++++++ docs-ui/src/app/components/select/snippets.ts | 2 +- .../app/components/skeleton/components.tsx | 45 ++- docs-ui/src/app/components/skeleton/page.mdx | 40 +- .../components/skeleton/props-definition.ts | 13 +- .../src/app/components/skeleton/snippets.ts | 44 ++- docs-ui/src/app/components/switch/page.mdx | 19 +- .../app/components/switch/props-definition.ts | 72 ++-- docs-ui/src/app/components/table/page.mdx | 21 +- .../app/components/table/props-definition.tsx | 7 - docs-ui/src/app/components/tabs/page.mdx | 64 ++- .../app/components/tabs/props-definition.ts | 28 +- docs-ui/src/app/components/tabs/snippets.ts | 11 + docs-ui/src/app/components/tag-group/page.mdx | 33 +- .../components/tag-group/props-definition.ts | 62 --- .../components/tag-group/props-definition.tsx | 89 +++++ .../app/components/text-field/components.tsx | 6 +- .../src/app/components/text-field/page.mdx | 27 +- .../components/text-field/props-definition.ts | 30 -- .../text-field/props-definition.tsx | 85 ++++ .../src/app/components/text-field/snippets.ts | 8 +- .../src/app/components/text/components.tsx | 13 +- docs-ui/src/app/components/text/page.mdx | 27 +- .../app/components/text/props-definition.ts | 55 --- .../app/components/text/props-definition.tsx | 81 ++++ docs-ui/src/app/components/text/snippets.ts | 13 +- .../components/toggle-button-group/page.mdx | 35 +- .../toggle-button-group/props-definition.ts | 22 +- .../toggle-button-group/snippets.ts | 12 +- .../src/app/components/toggle-button/page.mdx | 18 +- .../toggle-button/props-definition.ts | 46 ++- .../app/components/toggle-button/snippets.ts | 2 +- .../src/app/components/tooltip/components.tsx | 28 +- docs-ui/src/app/components/tooltip/page.mdx | 36 +- .../components/tooltip/props-definition.ts | 55 --- .../components/tooltip/props-definition.tsx | 79 ++++ .../src/app/components/tooltip/snippets.ts | 27 +- .../app/components/visually-hidden/page.mdx | 6 +- .../visually-hidden/props-definition.ts | 2 + docs-ui/src/components/Chip/styles.module.css | 2 +- .../src/components/PropsTable/PropsTable.tsx | 8 +- docs-ui/src/components/Snippet/client.tsx | 20 + docs-ui/src/components/Snippet/index.tsx | 3 + .../src/components/Snippet/styles.module.css | 40 ++ docs-ui/src/utils/propDefs.ts | 34 +- 131 files changed, 3561 insertions(+), 2296 deletions(-) delete mode 100644 docs-ui/src/app/components/avatar/props-definition.ts create mode 100644 docs-ui/src/app/components/avatar/props-definition.tsx delete mode 100644 docs-ui/src/app/components/box/props-definition.ts create mode 100644 docs-ui/src/app/components/box/props-definition.tsx delete mode 100644 docs-ui/src/app/components/button-icon/props-definition.ts create mode 100644 docs-ui/src/app/components/button-icon/props-definition.tsx delete mode 100644 docs-ui/src/app/components/button-link/props-definition.ts create mode 100644 docs-ui/src/app/components/button-link/props-definition.tsx delete mode 100644 docs-ui/src/app/components/button/props-definition.ts create mode 100644 docs-ui/src/app/components/button/props-definition.tsx delete mode 100644 docs-ui/src/app/components/flex/props-definition.ts create mode 100644 docs-ui/src/app/components/flex/props-definition.tsx delete mode 100644 docs-ui/src/app/components/grid/props-definition.ts create mode 100644 docs-ui/src/app/components/grid/props-definition.tsx delete mode 100644 docs-ui/src/app/components/header-page/props-definition.ts create mode 100644 docs-ui/src/app/components/header-page/props-definition.tsx delete mode 100644 docs-ui/src/app/components/header/props-definition.ts create mode 100644 docs-ui/src/app/components/header/props-definition.tsx delete mode 100644 docs-ui/src/app/components/link/props-definition.ts create mode 100644 docs-ui/src/app/components/link/props-definition.tsx delete mode 100644 docs-ui/src/app/components/menu/props-definition.ts create mode 100644 docs-ui/src/app/components/menu/props-definition.tsx delete mode 100644 docs-ui/src/app/components/password-field/props-definition.ts create mode 100644 docs-ui/src/app/components/password-field/props-definition.tsx delete mode 100644 docs-ui/src/app/components/radio-group/props-definition.ts create mode 100644 docs-ui/src/app/components/radio-group/props-definition.tsx delete mode 100644 docs-ui/src/app/components/search-field/props-definition.ts create mode 100644 docs-ui/src/app/components/search-field/props-definition.tsx delete mode 100644 docs-ui/src/app/components/select/props-definition.ts create mode 100644 docs-ui/src/app/components/select/props-definition.tsx delete mode 100644 docs-ui/src/app/components/tag-group/props-definition.ts create mode 100644 docs-ui/src/app/components/tag-group/props-definition.tsx delete mode 100644 docs-ui/src/app/components/text-field/props-definition.ts create mode 100644 docs-ui/src/app/components/text-field/props-definition.tsx delete mode 100644 docs-ui/src/app/components/text/props-definition.ts create mode 100644 docs-ui/src/app/components/text/props-definition.tsx delete mode 100644 docs-ui/src/app/components/tooltip/props-definition.ts create mode 100644 docs-ui/src/app/components/tooltip/props-definition.tsx diff --git a/docs-ui/src/app/components/accordion/page.mdx b/docs-ui/src/app/components/accordion/page.mdx index 83d650507b..486c93ec80 100644 --- a/docs-ui/src/app/components/accordion/page.mdx +++ b/docs-ui/src/app/components/accordion/page.mdx @@ -28,10 +28,16 @@ import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { AccordionDefinition } from '../../../utils/definitions'; import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; + +export const reactAriaUrls = { + disclosure: 'https://react-aria.adobe.com/Disclosure', + disclosureGroup: 'https://react-aria.adobe.com/DisclosureGroup', +}; ` element. + + ### AccordionTrigger Trigger component with built-in animated chevron icon. Renders a heading element (defaults to `

`, configurable via `level` prop) wrapping a ``; export const buttonResponsiveSnippet = ``; export const variantsSnippet = ` - - - - `; + + + +`; export const sizesSnippet = ` - - - `; + + +`; export const withIconsSnippet = ` - - - - `; + + + +`; export const disabledSnippet = ` - - - - `; + + + +`; export const loadingSnippet = ``; + Load more items +`; export const asLinkSnippet = ` - - Button - - `; + + Button + +`; diff --git a/docs-ui/src/app/components/card/components.tsx b/docs-ui/src/app/components/card/components.tsx index 08fa940be8..d10e4d7bce 100644 --- a/docs-ui/src/app/components/card/components.tsx +++ b/docs-ui/src/app/components/card/components.tsx @@ -18,7 +18,7 @@ export const Default = () => { ); }; -export const CustomSize = () => { +export const HeaderAndBody = () => { return ( { }} > Header - Body - Footer + Body content without a footer ); }; diff --git a/docs-ui/src/app/components/card/page.mdx b/docs-ui/src/app/components/card/page.mdx index e0b6e81fff..6f410fcd97 100644 --- a/docs-ui/src/app/components/card/page.mdx +++ b/docs-ui/src/app/components/card/page.mdx @@ -10,10 +10,10 @@ import { import { cardUsageSnippet, defaultSnippet, - customSizeSnippet, + headerAndBodySnippet, withLongBodySnippet, } from './snippets'; -import { Default, CustomSize, WithLongBody } from './components'; +import { Default, HeaderAndBody, WithLongBody } from './components'; import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { CardDefinition } from '../../../utils/definitions'; @@ -21,7 +21,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; } code={defaultSnippet} /> @@ -32,54 +32,53 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ## API reference -### Card +All Card components extend `HTMLDivElement` attributes. -A card component that can be used to display content in a box. +### Card ### CardHeader -To display a header in a card, use the `CardHeader` component. This will be fixed at the top of the card. +Fixed at the top of the card. ### CardBody -To display content in a card, use the `CardBody` component. This will automatically fill the card. +Scrollable content area that fills available space. ### CardFooter -To display a footer in a card, use the `CardFooter` component. This will be fixed at the bottom of the card. +Fixed at the bottom of the card. ## Examples -### Custom size +### Header and body only -Here's a view when card has a custom size. +Cards can omit the footer section. } - code={customSizeSnippet} - open + layout="side-by-side" + preview={} + code={headerAndBodySnippet} /> -### With long body +### Scrollable body -Here's a view when card has a long body. +When body content exceeds the available height, CardBody scrolls while header and footer remain fixed. } code={withLongBodySnippet} - open /> diff --git a/docs-ui/src/app/components/card/props-definition.ts b/docs-ui/src/app/components/card/props-definition.ts index bb7bdad0dd..b3e3776648 100644 --- a/docs-ui/src/app/components/card/props-definition.ts +++ b/docs-ui/src/app/components/card/props-definition.ts @@ -1,30 +1,38 @@ import { classNamePropDefs, stylePropDefs, - childrenPropDefs, type PropDef, } from '@/utils/propDefs'; +const optionalChildrenPropDef: Record = { + children: { + type: 'enum', + values: ['ReactNode'], + responsive: false, + description: 'Content to display inside the component.', + }, +}; + export const cardPropDefs: Record = { - ...childrenPropDefs, + ...optionalChildrenPropDef, ...classNamePropDefs, ...stylePropDefs, }; export const cardHeaderPropDefs: Record = { - ...childrenPropDefs, + ...optionalChildrenPropDef, ...classNamePropDefs, ...stylePropDefs, }; export const cardBodyPropDefs: Record = { - ...childrenPropDefs, + ...optionalChildrenPropDef, ...classNamePropDefs, ...stylePropDefs, }; export const cardFooterPropDefs: Record = { - ...childrenPropDefs, + ...optionalChildrenPropDef, ...classNamePropDefs, ...stylePropDefs, }; diff --git a/docs-ui/src/app/components/card/snippets.ts b/docs-ui/src/app/components/card/snippets.ts index b5de9a7008..6f956e5518 100644 --- a/docs-ui/src/app/components/card/snippets.ts +++ b/docs-ui/src/app/components/card/snippets.ts @@ -6,33 +6,40 @@ export const cardUsageSnippet = `import { Card, CardHeader, CardBody, CardFooter Footer `; -export const defaultSnippet = ` +export const defaultSnippet = ` Header Body Footer `; -export const customSizeSnippet = ` +export const headerAndBodySnippet = ` Header - Body - Footer + Body content without a footer `; -export const withLongBodySnippet = ` +export const withLongBodySnippet = `import { Text } from '@backstage/ui'; + + Header This is the first paragraph of a long body text that demonstrates how - the Card component handles extensive content. + the Card component handles extensive content. The card should adjust + accordingly to display all the text properly while maintaining its + structure. Here's a second paragraph that adds more content to our card body. + Having multiple paragraphs helps to visualize how spacing works within + the card component. This third paragraph continues to add more text to ensure we have a - proper demonstration of a card with significant content. + proper demonstration of a card with significant content. This makes it + easier to test scrolling behavior and overall layout when content + exceeds the initial view. diff --git a/docs-ui/src/app/components/checkbox/page.mdx b/docs-ui/src/app/components/checkbox/page.mdx index aaf73d7210..9657b471da 100644 --- a/docs-ui/src/app/components/checkbox/page.mdx +++ b/docs-ui/src/app/components/checkbox/page.mdx @@ -12,10 +12,15 @@ import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { CheckboxDefinition } from '../../../utils/definitions'; import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; + +export const reactAriaUrls = { + checkbox: 'https://react-aria.adobe.com/Checkbox', +}; } code={defaultSnippet} /> @@ -28,12 +33,12 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; + + ## Examples ### All variants -Here's a view when checkboxes have different variants. - = { children: { type: 'enum', - values: ['React.ReactNode'], - responsive: false, + values: ['ReactNode'], + required: true, + description: 'Label displayed next to the checkbox.', }, isSelected: { - type: 'enum', - values: ['boolean'], - responsive: false, + type: 'boolean', + description: 'Controls checked state (controlled mode).', }, defaultSelected: { - type: 'enum', - values: ['boolean'], - responsive: false, + type: 'boolean', + description: 'Initial checked state (uncontrolled mode).', }, onChange: { type: 'enum', values: ['(isSelected: boolean) => void'], - responsive: false, + description: 'Called when the checked state changes.', }, isDisabled: { - type: 'enum', - values: ['boolean'], - responsive: false, + type: 'boolean', + description: 'Prevents interaction and applies disabled styling.', }, isRequired: { - type: 'enum', - values: ['boolean'], - responsive: false, + type: 'boolean', + description: 'Marks the checkbox as required for form validation.', + }, + isIndeterminate: { + type: 'boolean', + description: 'Shows a mixed state, typically for "select all" checkboxes.', }, name: { type: 'string', - responsive: false, + description: 'Name attribute for form submission.', }, value: { type: 'string', - responsive: false, + description: 'Value attribute for form submission.', }, ...classNamePropDefs, ...stylePropDefs, diff --git a/docs-ui/src/app/components/container/components.tsx b/docs-ui/src/app/components/container/components.tsx index 7032b3f620..76eaf56ff1 100644 --- a/docs-ui/src/app/components/container/components.tsx +++ b/docs-ui/src/app/components/container/components.tsx @@ -1,24 +1,33 @@ 'use client'; +import { Container } from '../../../../../packages/ui/src/components/Container/Container'; import { Box } from '../../../../../packages/ui/src/components/Box/Box'; - -const DecorativeBox = () => ( - -); +import { Text } from '../../../../../packages/ui/src/components/Text/Text'; export const Preview = () => { return ( -
- -
+ + Content is centered with max-width + + ); +}; + +export const BasicUsagePreview = () => { + return ( + + Hello World + Hello World + Hello World + + ); +}; + +export const ResponsiveSpacingPreview = () => { + return ( + + Hello World + Hello World + Hello World + ); }; diff --git a/docs-ui/src/app/components/container/page.mdx b/docs-ui/src/app/components/container/page.mdx index 87bc55829e..4ffca3bfc5 100644 --- a/docs-ui/src/app/components/container/page.mdx +++ b/docs-ui/src/app/components/container/page.mdx @@ -8,7 +8,11 @@ import { containerSimpleSnippet, containerResponsiveSnippet, } from './snippets'; -import { Preview } from './components'; +import { + Preview, + BasicUsagePreview, + ResponsiveSpacingPreview, +} from './components'; import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { ContainerDefinition } from '../../../utils/definitions'; @@ -17,7 +21,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; } code={previewSnippet} /> @@ -32,18 +36,23 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ## Examples -### Simple +### Basic Usage -A simple example of how to use the Container component. +} + code={containerSimpleSnippet} + layout="side-by-side" +/> - +### Responsive Spacing -### Responsive padding & margin +Spacing props accept breakpoint objects for responsive behavior. -The Container component also supports responsive values, making it easy to -create responsive designs. - - +} + code={containerResponsiveSnippet} + layout="side-by-side" +/> diff --git a/docs-ui/src/app/components/container/props-definition.ts b/docs-ui/src/app/components/container/props-definition.ts index 0980520365..797aec9e92 100644 --- a/docs-ui/src/app/components/container/props-definition.ts +++ b/docs-ui/src/app/components/container/props-definition.ts @@ -1,12 +1,52 @@ import { classNamePropDefs, stylePropDefs, - gapPropDefs, + spacingValues, type PropDef, } from '@/utils/propDefs'; export const containerPropDefs: Record = { - ...gapPropDefs, + children: { + type: 'enum', + values: ['ReactNode'], + description: 'Content to render inside the container.', + }, + my: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Vertical margin (top and bottom).', + }, + mt: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Top margin.', + }, + mb: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Bottom margin.', + }, + py: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Vertical padding (top and bottom).', + }, + pt: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Top padding.', + }, + pb: { + type: 'enum | string', + values: spacingValues, + responsive: true, + description: 'Bottom padding.', + }, ...classNamePropDefs, ...stylePropDefs, }; diff --git a/docs-ui/src/app/components/container/snippets.ts b/docs-ui/src/app/components/container/snippets.ts index 83f4dabbbc..b16c1b81fd 100644 --- a/docs-ui/src/app/components/container/snippets.ts +++ b/docs-ui/src/app/components/container/snippets.ts @@ -2,9 +2,9 @@ export const containerUsageSnippet = `import { Container } from "@backstage/ui"; Hello World!`; -export const previewSnippet = `
- -
`; +export const previewSnippet = ` + Content is centered with max-width +`; export const containerSimpleSnippet = ` Hello World @@ -12,7 +12,7 @@ export const containerSimpleSnippet = ` Hello World `; -export const containerResponsiveSnippet = ` +export const containerResponsiveSnippet = ` Hello World Hello World Hello World diff --git a/docs-ui/src/app/components/dialog/components.tsx b/docs-ui/src/app/components/dialog/components.tsx index 3a1fd8c2c9..18ab1bf9c5 100644 --- a/docs-ui/src/app/components/dialog/components.tsx +++ b/docs-ui/src/app/components/dialog/components.tsx @@ -58,6 +58,20 @@ export const PreviewFixedWidthAndHeight = () => ( quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. + + Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut + fugit, sed quia consequuntur magni dolores eos qui ratione + voluptatem sequi nesciunt. + + + Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, + consectetur, adipisci velit, sed quia non numquam eius modi tempora + incidunt ut labore et dolore magnam aliquam quaerat voluptatem. + + + Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis + suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur. + diff --git a/docs-ui/src/app/components/dialog/page.mdx b/docs-ui/src/app/components/dialog/page.mdx index 1910cef5a8..12ce2d4135 100644 --- a/docs-ui/src/app/components/dialog/page.mdx +++ b/docs-ui/src/app/components/dialog/page.mdx @@ -12,7 +12,6 @@ import { dialogHeaderPropDefs, dialogBodyPropDefs, dialogFooterPropDefs, - dialogClosePropDefs, } from './props-definition'; import { dialogUsageSnippet, @@ -26,10 +25,16 @@ import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { DialogDefinition } from '../../../utils/definitions'; import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; + +export const reactAriaUrls = { + dialogTrigger: 'https://react-aria.adobe.com/Modal#dialogtrigger', + modal: 'https://react-aria.adobe.com/Modal', +}; + + ### Dialog The main dialog container that renders as a modal overlay. + + ### DialogHeader Displays the dialog title with a built-in close button. + + ### DialogBody The main content area of the dialog with optional scrolling. @@ -94,7 +108,7 @@ Dialog with a fixed height body that scrolls when content overflows. ### Dialog with Form -Dialog containing form elements for user input. +Forms can be embedded in the dialog body. = { - children: { type: 'enum', values: ['ReactNode'], responsive: false }, + children: { + type: 'enum', + values: ['ReactNode'], + description: 'Trigger element and dialog content.', + }, isOpen: { type: 'boolean', description: 'Whether the overlay is open by default (controlled).', @@ -23,66 +27,66 @@ export const dialogTriggerPropDefs: Record = { }; export const dialogPropDefs: Record = { - children: { type: 'enum', values: ['ReactNode'], responsive: false }, + children: { + type: 'enum', + values: ['ReactNode'], + description: 'Dialog content (DialogHeader, DialogBody, DialogFooter).', + }, isOpen: { type: 'boolean', - description: 'Whether the overlay is open by default (controlled).', + description: 'Whether the overlay is open (controlled mode).', }, defaultOpen: { type: 'boolean', - description: 'Whether the overlay is open by default (uncontrolled).', + description: 'Initial open state (uncontrolled mode).', }, onOpenChange: { type: 'enum', values: ['(isOpen: boolean) => void'], - description: - "Handler that is called when the overlay's open state changes.", + description: 'Called when the open state changes.', }, width: { type: 'enum', values: ['number', 'string'], - responsive: false, + default: '400', + description: 'Fixed width in pixels (number) or CSS units (string).', }, height: { type: 'enum', values: ['number', 'string'], - responsive: false, + default: 'auto', + description: 'Fixed height in pixels (number) or CSS units (string).', }, ...classNamePropDefs, ...stylePropDefs, }; export const dialogHeaderPropDefs: Record = { - children: { type: 'enum', values: ['ReactNode'], responsive: false }, + children: { + type: 'enum', + values: ['ReactNode'], + description: 'Dialog title text.', + }, ...classNamePropDefs, ...stylePropDefs, }; export const dialogBodyPropDefs: Record = { - children: { type: 'enum', values: ['ReactNode'], responsive: false }, - height: { + children: { type: 'enum', - values: ['number', 'string'], - responsive: false, + values: ['ReactNode'], + description: 'Main content of the dialog.', }, ...classNamePropDefs, ...stylePropDefs, }; export const dialogFooterPropDefs: Record = { - children: { type: 'enum', values: ['ReactNode'], responsive: false }, - ...classNamePropDefs, - ...stylePropDefs, -}; - -export const dialogClosePropDefs: Record = { - variant: { + children: { type: 'enum', - values: ['primary', 'secondary', 'tertiary'], - default: 'secondary', - responsive: false, + values: ['ReactNode'], + description: 'Action buttons or footer content.', }, - children: { type: 'enum', values: ['ReactNode'], responsive: false }, ...classNamePropDefs, ...stylePropDefs, }; diff --git a/docs-ui/src/app/components/dialog/snippets.ts b/docs-ui/src/app/components/dialog/snippets.ts index c1ad50578b..440ff417e8 100644 --- a/docs-ui/src/app/components/dialog/snippets.ts +++ b/docs-ui/src/app/components/dialog/snippets.ts @@ -53,11 +53,14 @@ export const dialogWithFormSnippet = ` - + `; diff --git a/docs-ui/src/app/components/skeleton/components.tsx b/docs-ui/src/app/components/skeleton/components.tsx index 277aa17ae3..9f83a013db 100644 --- a/docs-ui/src/app/components/skeleton/components.tsx +++ b/docs-ui/src/app/components/skeleton/components.tsx @@ -2,30 +2,43 @@ import { Skeleton } from '../../../../../packages/ui/src/components/Skeleton/Skeleton'; import { Flex } from '../../../../../packages/ui/src/components/Flex/Flex'; +import { Box } from '../../../../../packages/ui/src/components/Box/Box'; -export const Demo1 = () => { +export const CardPlaceholder = () => { return ( - - + - - - - - - + + + + + + ); +}; + +export const AvatarWithText = () => { + return ( + + + + + + + - +
); }; -export const Demo2 = () => { +export const Rounded = () => { return ( - - - - - + + + + + + + ); }; diff --git a/docs-ui/src/app/components/skeleton/page.mdx b/docs-ui/src/app/components/skeleton/page.mdx index 42f8975b5a..b7d218af89 100644 --- a/docs-ui/src/app/components/skeleton/page.mdx +++ b/docs-ui/src/app/components/skeleton/page.mdx @@ -2,8 +2,13 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; import { skeletonPropDefs } from './props-definition'; -import { skeletonUsageSnippet, demo1Snippet, demo2Snippet } from './snippets'; -import { Demo1, Demo2 } from './components'; +import { + skeletonUsageSnippet, + cardPlaceholderSnippet, + avatarWithTextSnippet, + roundedSnippet, +} from './snippets'; +import { CardPlaceholder, AvatarWithText, Rounded } from './components'; import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { ChangelogComponent } from '@/components/ChangelogComponent'; @@ -14,7 +19,12 @@ import { SkeletonDefinition } from '../../../utils/definitions'; description="Use to show a placeholder while content is loading." /> -} code={demo2Snippet} /> +} + code={cardPlaceholderSnippet} +/> ## Usage @@ -22,21 +32,29 @@ import { SkeletonDefinition } from '../../../utils/definitions'; ## API reference +Skeleton extends standard HTML div attributes. + ## Examples -### Demo 1 +### Rounded -You can use a mix of different sizes to create a more complex skeleton. +} + code={roundedSnippet} +/> -} code={demo1Snippet} open /> +### Avatar with text -### Demo 2 - -You can use a mix of different sizes to create a more complex skeleton. - -} code={demo2Snippet} open /> +} + code={avatarWithTextSnippet} +/> diff --git a/docs-ui/src/app/components/skeleton/props-definition.ts b/docs-ui/src/app/components/skeleton/props-definition.ts index bb80024bcd..8c14c4c0ec 100644 --- a/docs-ui/src/app/components/skeleton/props-definition.ts +++ b/docs-ui/src/app/components/skeleton/props-definition.ts @@ -6,19 +6,22 @@ import { export const skeletonPropDefs: Record = { width: { - type: 'number', + type: 'string', default: '80', - responsive: false, + description: + 'The width of the skeleton. Accepts a number (pixels) or CSS string value.', }, height: { - type: 'number', + type: 'string', default: '24', - responsive: false, + description: + 'The height of the skeleton. Accepts a number (pixels) or CSS string value.', }, rounded: { type: 'boolean', default: 'false', - responsive: false, + description: + 'Whether to apply fully rounded corners (for circular shapes).', }, ...classNamePropDefs, ...stylePropDefs, diff --git a/docs-ui/src/app/components/skeleton/snippets.ts b/docs-ui/src/app/components/skeleton/snippets.ts index 981ac5ff0c..84bbec1616 100644 --- a/docs-ui/src/app/components/skeleton/snippets.ts +++ b/docs-ui/src/app/components/skeleton/snippets.ts @@ -1,26 +1,30 @@ -export const skeletonUsageSnippet = `import { Flex, Skeleton } from '@backstage/ui'; +export const skeletonUsageSnippet = `import { Skeleton } from '@backstage/ui'; - - - - -`; +`; -export const demo1Snippet = ` - +export const cardPlaceholderSnippet = ` - - - - - - + + + + +`; + +export const avatarWithTextSnippet = ` + + + + + + -`; +`; -export const demo2Snippet = ` - - - -`; +export const roundedSnippet = ` + + + + + +`; diff --git a/docs-ui/src/app/components/switch/page.mdx b/docs-ui/src/app/components/switch/page.mdx index 494a046f47..1f893aea36 100644 --- a/docs-ui/src/app/components/switch/page.mdx +++ b/docs-ui/src/app/components/switch/page.mdx @@ -1,6 +1,7 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; import { switchPropDefs } from './props-definition'; import { snippetUsage, defaultSnippet, disabledSnippet } from './snippets'; import { Default, Disabled } from './components'; @@ -9,9 +10,13 @@ import { Theming } from '@/components/Theming'; import { ChangelogComponent } from '@/components/ChangelogComponent'; import { SwitchDefinition } from '../../../utils/definitions'; +export const reactAriaUrls = { + switch: 'https://react-aria.adobe.com/Switch', +}; + } code={defaultSnippet} /> @@ -24,19 +29,13 @@ import { SwitchDefinition } from '../../../utils/definitions'; + + ## Examples ### Disabled -A switch can be disabled using the `isDisabled` prop. - -} - code={disabledSnippet} -/> +} code={disabledSnippet} /> diff --git a/docs-ui/src/app/components/switch/props-definition.ts b/docs-ui/src/app/components/switch/props-definition.ts index 769c93aac8..eeab3e64b8 100644 --- a/docs-ui/src/app/components/switch/props-definition.ts +++ b/docs-ui/src/app/components/switch/props-definition.ts @@ -2,66 +2,44 @@ import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; import type { PropDef } from '@/utils/propDefs'; export const switchPropDefs: Record = { - autoFocus: { - type: 'boolean', - }, - defaultSelected: { - type: 'boolean', - }, - ...classNamePropDefs, - isDisabled: { - type: 'boolean', - }, - isReadOnly: { - type: 'boolean', + label: { + type: 'string', + description: 'Text label displayed next to the switch.', }, isSelected: { type: 'boolean', + description: + 'Controlled selected state. Use with onChange for controlled behavior.', }, - label: { - type: 'string', - }, - name: { - type: 'string', + defaultSelected: { + type: 'boolean', + description: 'Initial selected state for uncontrolled usage.', }, onChange: { type: 'enum', values: ['(isSelected: boolean) => void'], + description: 'Called when the switch state changes.', }, - onFocus: { - type: 'enum', - values: ['(e: FocusEvent) => void'], + isDisabled: { + type: 'boolean', + description: 'Prevents user interaction when true.', }, - onBlur: { - type: 'enum', - values: ['(e: FocusEvent) => void'], + isReadOnly: { + type: 'boolean', + description: 'Makes the switch non-interactive but still focusable.', }, - onFocusChange: { - type: 'enum', - values: ['(isFocused: boolean) => void'], + name: { + type: 'string', + description: 'Form field name for form submission.', }, - onKeyDown: { - type: 'enum', - values: ['(e: KeyboardEvent) => void'], - }, - onKeyUp: { - type: 'enum', - values: ['(e: KeyboardEvent) => void'], - }, - onHoverStart: { - type: 'enum', - values: ['(e: HoverEvent) => void'], - }, - onHoverEnd: { - type: 'enum', - values: ['(e: HoverEvent) => void'], - }, - onHoverChange: { - type: 'enum', - values: ['(isHovered: boolean) => void'], - }, - ...stylePropDefs, value: { type: 'string', + description: 'Form field value submitted when selected.', }, + autoFocus: { + type: 'boolean', + description: 'Focuses the switch on mount.', + }, + ...classNamePropDefs, + ...stylePropDefs, }; diff --git a/docs-ui/src/app/components/table/page.mdx b/docs-ui/src/app/components/table/page.mdx index e39f89f5e9..6eb280cbe2 100644 --- a/docs-ui/src/app/components/table/page.mdx +++ b/docs-ui/src/app/components/table/page.mdx @@ -13,7 +13,6 @@ import { PrimitivesExample, } from './components'; import { - tablePropsColumns, tableReturnColumns, useTableOptionsPropDefs, useTableReturnPropDefs, @@ -163,7 +162,7 @@ You can also disable specific rows from being clicked using `getIsDisabled`: -} /> +} code={tableRowActionsHrefSnippet} /> ### Empty State @@ -225,7 +224,7 @@ The `useTable` hook manages data fetching, pagination, sorting, and filtering. **Options** - + **Return Value** @@ -235,27 +234,27 @@ The `useTable` hook manages data fetching, pagination, sorting, and filtering. The main table component. - + ### ColumnConfig - + ### CellText - + ### CellProfile - + ### TablePagination - + ### Primitives @@ -263,7 +262,7 @@ Low-level components for building custom table layouts. #### TableRoot - + @@ -277,13 +276,13 @@ Low-level components for building custom table layouts. #### Column - + #### Row - + diff --git a/docs-ui/src/app/components/table/props-definition.tsx b/docs-ui/src/app/components/table/props-definition.tsx index 58c8f197a7..e653f67c8a 100644 --- a/docs-ui/src/app/components/table/props-definition.tsx +++ b/docs-ui/src/app/components/table/props-definition.tsx @@ -9,13 +9,6 @@ import { Chip } from '@/components/Chip'; // PropsTable Column Configuration (Table docs use description instead of responsive) // ============================================================================= -export const tablePropsColumns = [ - { key: 'prop' as const, width: '15%' }, - { key: 'type' as const, width: '25%' }, - { key: 'default' as const, width: '15%' }, - { key: 'description' as const, width: '45%' }, -]; - // For return values (no default column) export const tableReturnColumns = [ { key: 'prop' as const, width: '15%' }, diff --git a/docs-ui/src/app/components/tabs/page.mdx b/docs-ui/src/app/components/tabs/page.mdx index 0b9478a503..6925127943 100644 --- a/docs-ui/src/app/components/tabs/page.mdx +++ b/docs-ui/src/app/components/tabs/page.mdx @@ -1,6 +1,7 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; import { tabsPropDefs, tabListPropDefs, @@ -13,6 +14,7 @@ import { defaultSelectedKeySnippet, disabledTabsSnippet, orientationSnippet, + urlNavigationSnippet, } from './snippets'; import { Default, @@ -25,9 +27,13 @@ import { Theming } from '@/components/Theming'; import { TabsDefinition } from '../../../utils/definitions'; import { ChangelogComponent } from '@/components/ChangelogComponent'; +export const reactAriaUrls = { + tabs: 'https://react-aria.adobe.com/Tabs', +}; + } code={defaultSnippet} /> @@ -40,40 +46,70 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ### Tabs -Groups the tabs and the corresponding panels. Renders a `
` element. +Container that groups the tab list and panels. + + +### TabList + +Container for the tab buttons. + + + + + ### Tab -An individual interactive tab button that toggles the corresponding panel. Renders a ` - I am a tooltip + + Helpful information ); }; + +export const Placement = () => { + return ( + + + + Top tooltip + + + + Right tooltip + + + + Bottom tooltip + + + + Left tooltip + + + ); +}; diff --git a/docs-ui/src/app/components/tooltip/page.mdx b/docs-ui/src/app/components/tooltip/page.mdx index 35d650c99b..8a9711d56c 100644 --- a/docs-ui/src/app/components/tooltip/page.mdx +++ b/docs-ui/src/app/components/tooltip/page.mdx @@ -1,17 +1,26 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; +import { ReactAriaLink } from '@/components/ReactAriaLink'; import { tooltipTriggerPropDefs, tooltipPropDefs } from './props-definition'; -import { tooltipUsageSnippet, defaultSnippet } from './snippets'; -import { Default } from './components'; +import { + tooltipUsageSnippet, + defaultSnippet, + placementSnippet, +} from './snippets'; +import { Default, Placement } from './components'; import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; import { TooltipDefinition } from '../../../utils/definitions'; import { ChangelogComponent } from '@/components/ChangelogComponent'; +export const reactAriaUrls = { + tooltip: 'https://react-aria.adobe.com/Tooltip', +}; + } code={defaultSnippet} align="center" /> @@ -24,16 +33,33 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ### TooltipTrigger -The trigger will wrap both the trigger and the tooltip. +Wraps the trigger element and tooltip content. + + ### Tooltip -The tooltip will wrap the content of the tooltip. +The tooltip content that appears on hover or focus. + + +## Examples + +### Placement + +The tooltip appears in the specified direction relative to the trigger. + +} + code={placementSnippet} + align="center" +/> + diff --git a/docs-ui/src/app/components/tooltip/props-definition.ts b/docs-ui/src/app/components/tooltip/props-definition.ts deleted file mode 100644 index dc0919f4cc..0000000000 --- a/docs-ui/src/app/components/tooltip/props-definition.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - childrenPropDefs, - classNamePropDefs, - stylePropDefs, -} from '@/utils/propDefs'; -import type { PropDef } from '@/utils/propDefs'; - -export const tooltipTriggerPropDefs: Record = { - isDisabled: { - type: 'boolean', - }, - delay: { - type: 'number', - default: '600', - }, - closeDelay: { - type: 'number', - default: '500', - }, - isOpen: { - type: 'boolean', - }, - defaultOpen: { - type: 'boolean', - }, - ...childrenPropDefs, -}; - -export const tooltipPropDefs: Record = { - triggerRef: { - type: 'enum', - values: ['RefObject'], - }, - isEntering: { - type: 'boolean', - }, - isExiting: { - type: 'boolean', - }, - placement: { - type: 'enum', - values: ['top', 'right', 'bottom', 'left'], - }, - containerPadding: { - type: 'number', - default: '12', - }, - offset: { - type: 'number', - default: '0', - }, - ...childrenPropDefs, - ...classNamePropDefs, - ...stylePropDefs, -}; diff --git a/docs-ui/src/app/components/tooltip/props-definition.tsx b/docs-ui/src/app/components/tooltip/props-definition.tsx new file mode 100644 index 0000000000..16dc9133dd --- /dev/null +++ b/docs-ui/src/app/components/tooltip/props-definition.tsx @@ -0,0 +1,79 @@ +import { + childrenPropDefs, + classNamePropDefs, + stylePropDefs, +} from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; +import { Chip } from '@/components/Chip'; + +export const tooltipTriggerPropDefs: Record = { + delay: { + type: 'number', + default: 600, + description: 'Milliseconds before tooltip appears on hover.', + }, + closeDelay: { + type: 'number', + default: 0, + description: 'Milliseconds before tooltip hides after leaving trigger.', + }, + trigger: { + type: 'enum', + values: ['focus'], + description: ( + <> + Set to focus for focus-only tooltips that do not appear on + hover. + + ), + }, + isOpen: { + type: 'boolean', + description: 'Controlled open state. Use with onOpenChange.', + }, + defaultOpen: { + type: 'boolean', + description: 'Initial open state for uncontrolled usage.', + }, + isDisabled: { + type: 'boolean', + description: 'Prevents the tooltip from appearing.', + }, + ...childrenPropDefs, +}; + +export const tooltipPropDefs: Record = { + placement: { + type: 'enum', + values: [ + 'top', + 'top start', + 'top end', + 'bottom', + 'bottom start', + 'bottom end', + 'left', + 'left top', + 'left bottom', + 'right', + 'right top', + 'right bottom', + ], + default: 'top', + description: + 'Position relative to the trigger element. Compound placements include alignment.', + }, + offset: { + type: 'number', + default: 4, + description: 'Distance in pixels from the trigger element.', + }, + containerPadding: { + type: 'number', + default: 12, + description: 'Padding from viewport edge when repositioning.', + }, + ...childrenPropDefs, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/docs-ui/src/app/components/tooltip/snippets.ts b/docs-ui/src/app/components/tooltip/snippets.ts index 1cf9fb66da..68b7d1b0c7 100644 --- a/docs-ui/src/app/components/tooltip/snippets.ts +++ b/docs-ui/src/app/components/tooltip/snippets.ts @@ -1,11 +1,30 @@ export const tooltipUsageSnippet = `import { TooltipTrigger, Tooltip, Button } from '@backstage/ui'; - - I am a tooltip + + Helpful information `; export const defaultSnippet = ` - - I am a tooltip + + Helpful information `; + +export const placementSnippet = ` + + + Top tooltip + + + + Right tooltip + + + + Bottom tooltip + + + + Left tooltip + +`; diff --git a/docs-ui/src/app/components/visually-hidden/page.mdx b/docs-ui/src/app/components/visually-hidden/page.mdx index 07b4bff28d..c72250231f 100644 --- a/docs-ui/src/app/components/visually-hidden/page.mdx +++ b/docs-ui/src/app/components/visually-hidden/page.mdx @@ -28,11 +28,11 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; +This component also accepts all standard HTML `div` attributes. + ## Examples -### Example Usage - -Here's an example of providing screen reader context for a list of links in a footer. +### Hidden headings = { type: 'enum', values: ['ReactNode'], responsive: false, + description: + 'Content to hide visually while remaining accessible to screen readers.', }, ...classNamePropDefs, ...stylePropDefs, diff --git a/docs-ui/src/components/Chip/styles.module.css b/docs-ui/src/components/Chip/styles.module.css index 80c37d8899..d752ae2602 100644 --- a/docs-ui/src/components/Chip/styles.module.css +++ b/docs-ui/src/components/Chip/styles.module.css @@ -1,5 +1,5 @@ .chip { - display: inline; + display: inline-block; font-family: monospace; font-size: 13px; border-radius: 6px; diff --git a/docs-ui/src/components/PropsTable/PropsTable.tsx b/docs-ui/src/components/PropsTable/PropsTable.tsx index e1324b88b9..25311a2ec3 100644 --- a/docs-ui/src/components/PropsTable/PropsTable.tsx +++ b/docs-ui/src/components/PropsTable/PropsTable.tsx @@ -16,10 +16,10 @@ interface ColumnConfig { } const defaultColumns: ColumnConfig[] = [ - { key: 'prop', width: '16%' }, - { key: 'type', width: '50%' }, - { key: 'default', width: '20%' }, - { key: 'responsive', width: '14%' }, + { key: 'prop' as const, width: '15%' }, + { key: 'type' as const, width: '25%' }, + { key: 'default' as const, width: '15%' }, + { key: 'description' as const, width: '45%' }, ]; const columnLabels: Record = { diff --git a/docs-ui/src/components/Snippet/client.tsx b/docs-ui/src/components/Snippet/client.tsx index 04284c3249..2041218a12 100644 --- a/docs-ui/src/components/Snippet/client.tsx +++ b/docs-ui/src/components/Snippet/client.tsx @@ -12,6 +12,7 @@ interface SnippetProps { py?: number; open?: boolean; height?: string | number; + layout?: 'stacked' | 'side-by-side'; } export const SnippetClient = ({ @@ -22,9 +23,28 @@ export const SnippetClient = ({ py = 2, open = false, height = 'auto', + layout = 'stacked', }: SnippetProps) => { const [isOpen, setIsOpen] = useState(open); + if (layout === 'side-by-side') { + return ( +
+
+
{codeContent}
+
+
+
+ {preview} +
+
+
+ ); + } + return ( { return ( ); }; diff --git a/docs-ui/src/components/Snippet/styles.module.css b/docs-ui/src/components/Snippet/styles.module.css index ed5bd22def..20f74c4df8 100644 --- a/docs-ui/src/components/Snippet/styles.module.css +++ b/docs-ui/src/components/Snippet/styles.module.css @@ -60,3 +60,43 @@ opacity: 1; } } + +/* Side-by-side layout */ +.sideBySide { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + align-items: stretch; +} + +.sideBySideCode { + min-width: 0; + overflow: auto; + display: flex; + flex-direction: column; +} + +.codeWrapper { + flex: 1; + display: flex; + flex-direction: column; +} + +.codeWrapper > div { + flex: 1; + margin-bottom: 0; +} + +.sideBySidePreview { + border-radius: 8px; + box-shadow: inset 0 0 0 1px var(--border); + background-color: var(--bui-bg-surface-0); + padding: 1px; + min-width: 0; + display: flex; + flex-direction: column; +} + +.sideBySidePreview > .previewContent { + flex: 1; +} diff --git a/docs-ui/src/utils/propDefs.ts b/docs-ui/src/utils/propDefs.ts index 2dd4f5c25a..575d53e81e 100644 --- a/docs-ui/src/utils/propDefs.ts +++ b/docs-ui/src/utils/propDefs.ts @@ -36,6 +36,7 @@ export { breakpoints }; export type { Breakpoint }; export const spacingValues = [ + '0', '0.5', '1', '1.5', @@ -50,8 +51,7 @@ export const spacingValues = [ '10', '11', '12', - '13', - '14', + 'auto', ]; export const paddingPropDefs = ( @@ -61,36 +61,43 @@ export const paddingPropDefs = ( type: 'enum | string', values: spacingValues, responsive: true, + description: 'Padding on all sides.', }, px: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Horizontal padding (left and right).', }, py: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Vertical padding (top and bottom).', }, pt: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Padding on the top.', }, pr: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Padding on the right.', }, pb: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Padding on the bottom.', }, pl: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Padding on the left.', }, }); @@ -101,36 +108,43 @@ export const marginPropDefs = ( type: 'enum | string', values: spacingValues, responsive: true, + description: 'Margin on all sides.', }, mx: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Horizontal margin (left and right).', }, my: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Vertical margin (top and bottom).', }, mt: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Margin on the top.', }, mr: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Margin on the right.', }, mb: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Margin on the bottom.', }, ml: { type: 'enum | string', values: spacingValues, responsive: true, + description: 'Margin on the left.', }, }); @@ -160,36 +174,36 @@ export const gapPropDefs: Record = { export const widthPropDefs: Record = { width: { type: 'string', - default: '0', responsive: true, + description: 'Sets the width of the element. Accepts CSS values.', }, minWidth: { type: 'string', - default: '0', responsive: true, + description: 'Sets the minimum width. Element cannot shrink below this.', }, maxWidth: { type: 'string', - default: '0', responsive: true, + description: 'Sets the maximum width. Element cannot grow beyond this.', }, }; export const heightPropDefs: Record = { height: { type: 'string', - default: '0', responsive: true, + description: 'Sets the height of the element. Accepts CSS values.', }, minHeight: { type: 'string', - default: '0', responsive: true, + description: 'Sets the minimum height. Element cannot shrink below this.', }, maxHeight: { type: 'string', - default: '0', responsive: true, + description: 'Sets the maximum height. Element cannot grow beyond this.', }, }; @@ -197,8 +211,8 @@ export const positionPropDefs: Record = { position: { type: 'enum', values: ['static', 'relative', 'absolute', 'fixed', 'sticky'], - default: 'static', responsive: true, + description: 'CSS positioning scheme for the element.', }, }; @@ -206,6 +220,7 @@ export const classNamePropDefs: Record = { className: { type: 'string', responsive: false, + description: 'Additional CSS class name for custom styling.', }, }; @@ -214,6 +229,7 @@ export const stylePropDefs: Record = { type: 'enum', values: ['CSSProperties'], responsive: false, + description: 'Inline CSS styles object.', }, };