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.', }, };