diff --git a/.storybook/main.ts b/.storybook/main.ts index 98f274486f..5453627f34 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,7 +1,6 @@ -// This file has been automatically migrated to valid ESM format by Storybook. +import { defineMain } from '@storybook/react-vite/node'; import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'; -import type { StorybookConfig } from '@storybook/react-vite'; import { join, dirname, posix } from 'path'; @@ -42,7 +41,7 @@ function getAbsolutePath(value: string): any { return dirname(require.resolve(join(value, 'package.json'))); } -const config: StorybookConfig = { +export default defineMain({ stories, addons: [ getAbsolutePath('@storybook/addon-links'), @@ -130,6 +129,4 @@ const config: StorybookConfig = { return config; }, -}; - -export default config; +}); diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 9ce26b8cf5..10200ae12d 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,8 +1,12 @@ -import React, { useEffect } from 'react'; +import addonA11y from '@storybook/addon-a11y'; +import addonDocs from '@storybook/addon-docs'; +import addonThemes from '@storybook/addon-themes'; +import addonLinks from '@storybook/addon-links'; +import { definePreview } from '@storybook/react-vite'; +import { useEffect } from 'react'; import { TestApiProvider } from '@backstage/test-utils'; import { Content, AlertDisplay } from '@backstage/core-components'; import { apis } from './support/apis'; -import type { Decorator, Preview } from '@storybook/react-vite'; import { useGlobals } from 'storybook/preview-api'; import { UnifiedThemeProvider, themes } from '@backstage/theme'; import { allModes } from './modes'; @@ -16,7 +20,7 @@ import './storybook.css'; // Custom themes import './themes/spotify.css'; -const preview: Preview = { +export default definePreview({ globalTypes: { themeMode: { name: 'Theme Mode', @@ -47,15 +51,17 @@ const preview: Preview = { }, }, }, + initialGlobals: { themeMode: 'light', themeName: 'backstage', }, + parameters: { layout: 'fullscreen', backgrounds: { - disabled: true, + disable: true, }, controls: { @@ -102,6 +108,7 @@ const preview: Preview = { }, }, }, + decorators: [ Story => { const [globals] = useGlobals(); @@ -140,6 +147,6 @@ const preview: Preview = { ); }, ], -}; -export default preview; + addons: [addonLinks(), addonThemes(), addonDocs(), addonA11y()], +}); diff --git a/packages/ui/src/components/Accordion/Accordion.stories.tsx b/packages/ui/src/components/Accordion/Accordion.stories.tsx index 6640bd5d6a..541cce5c84 100644 --- a/packages/ui/src/components/Accordion/Accordion.stories.tsx +++ b/packages/ui/src/components/Accordion/Accordion.stories.tsx @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Accordion, AccordionTrigger, @@ -36,15 +35,12 @@ const Content = () => ( ); -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Accordion', component: Accordion, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: () => ( @@ -53,9 +49,9 @@ export const Default: Story = { ), -}; +}); -export const WithSubtitle: Story = { +export const WithSubtitle = meta.story({ render: () => ( ), -}; +}); -export const CustomTrigger: Story = { +export const CustomTrigger = meta.story({ render: () => ( @@ -87,9 +83,9 @@ export const CustomTrigger: Story = { ), -}; +}); -export const DefaultExpanded: Story = { +export const DefaultExpanded = meta.story({ render: () => ( @@ -98,9 +94,9 @@ export const DefaultExpanded: Story = { ), -}; +}); -export const GroupSingleOpen: Story = { +export const GroupSingleOpen = meta.story({ render: () => ( @@ -136,9 +132,9 @@ export const GroupSingleOpen: Story = { ), -}; +}); -export const GroupMultipleOpen: Story = { +export const GroupMultipleOpen = meta.story({ render: () => ( @@ -174,4 +170,4 @@ export const GroupMultipleOpen: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Avatar/Avatar.stories.tsx b/packages/ui/src/components/Avatar/Avatar.stories.tsx index 582d82393e..75c1e68a67 100644 --- a/packages/ui/src/components/Avatar/Avatar.stories.tsx +++ b/packages/ui/src/components/Avatar/Avatar.stories.tsx @@ -13,36 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Avatar } from './index'; import { Flex, Text } from '../..'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Avatar', component: Avatar, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { src: 'https://avatars.githubusercontent.com/u/1540635?v=4', name: 'Charles de Dreuille', }, -}; +}); -export const Fallback: Story = { +export const Fallback = meta.story({ args: { - ...Default.args, + ...Default.input.args, src: 'https://avatars.githubusercontent.com/u/15406AAAAAAAAA', }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -62,11 +58,11 @@ export const Sizes: Story = { ), -}; +}); -export const Purpose: Story = { +export const Purpose = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -93,4 +89,4 @@ export const Purpose: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Box/Box.stories.tsx b/packages/ui/src/components/Box/Box.stories.tsx index 6637f45740..766a6668c7 100644 --- a/packages/ui/src/components/Box/Box.stories.tsx +++ b/packages/ui/src/components/Box/Box.stories.tsx @@ -1,3 +1,4 @@ +import preview from '../../../../../.storybook/preview'; /* * Copyright 2024 The Backstage Authors * @@ -15,11 +16,10 @@ */ import { ReactNode } from 'react'; -import type { Meta, StoryObj } from '@storybook/react-vite'; import { Box } from './Box'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Box', component: Box, argTypes: { @@ -31,10 +31,7 @@ const meta = { control: false, }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const diagonalStripePattern = (() => { const svg = ` @@ -47,7 +44,7 @@ const diagonalStripePattern = (() => { return `data:image/svg+xml,${encodeURIComponent(svg)}`; })(); -export const Default: Story = { +export const Default = meta.story({ args: { width: '64px', height: '64px', @@ -63,10 +60,10 @@ export const Default: Story = { color: '#2563eb', }, }, -}; +}); -export const Margin: Story = { - args: { ...Default.args }, +export const Margin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -89,10 +86,10 @@ export const Margin: Story = { ), -}; +}); -export const ResponsiveMargin: Story = { - args: { ...Default.args }, +export const ResponsiveMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -115,10 +112,10 @@ export const ResponsiveMargin: Story = { ), -}; +}); -export const CustomMargin: Story = { - args: { ...Default.args }, +export const CustomMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -141,10 +138,10 @@ export const CustomMargin: Story = { ), -}; +}); -export const CustomResponsiveMargin: Story = { - args: { ...Default.args }, +export const CustomResponsiveMargin = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -167,10 +164,10 @@ export const CustomResponsiveMargin: Story = { ), -}; +}); -export const Padding: Story = { - args: { ...Default.args }, +export const Padding = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -193,10 +190,10 @@ export const Padding: Story = { ), -}; +}); -export const ResponsivePadding: Story = { - args: { ...Default.args }, +export const ResponsivePadding = meta.story({ + args: { ...Default.input.args }, render: args => ( ), -}; +}); -export const CustomPadding: Story = { - args: { ...Default.args }, +export const CustomPadding = meta.story({ + args: { ...Default.input.args }, render: args => ( @@ -263,10 +260,10 @@ export const CustomPadding: Story = { ), -}; +}); -export const CustomResponsivePadding: Story = { - args: { ...Default.args }, +export const CustomResponsivePadding = meta.story({ + args: { ...Default.input.args }, render: args => ( ), -}; +}); const CardDisplay = ({ children }: { children?: ReactNode }) => { return ( @@ -327,7 +324,7 @@ const CardDisplay = ({ children }: { children?: ReactNode }) => { ); }; -export const Display: Story = { +export const Display = meta.story({ render: args => ( @@ -346,4 +343,4 @@ export const Display: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Button/Button.stories.tsx b/packages/ui/src/components/Button/Button.stories.tsx index 4734770aa4..141db4da96 100644 --- a/packages/ui/src/components/Button/Button.stories.tsx +++ b/packages/ui/src/components/Button/Button.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Button } from './Button'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { RiArrowRightSLine, RiCloudLine } from '@remixicon/react'; import { useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Button', component: Button, argTypes: { @@ -34,18 +33,15 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Button', }, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ args: { children: 'Button', }, @@ -69,9 +65,9 @@ export const Variants: Story = { ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { children: 'Button', }, @@ -85,9 +81,9 @@ export const Sizes: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { children: 'Button', }, @@ -102,9 +98,9 @@ export const WithIcons: Story = { /> ), -}; +}); -export const FullWidth: Story = { +export const FullWidth = meta.story({ args: { children: 'Button', }, @@ -119,9 +115,9 @@ export const FullWidth: Story = { /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { children: 'Button', variant: { @@ -149,12 +145,12 @@ export const Responsive: Story = { sm: 'medium', }, }, -}; +}); const variants = ['primary', 'secondary'] as const; const sizes = ['small', 'medium'] as const; -export const Playground: Story = { +export const Playground = meta.story({ args: { children: 'Button', }, @@ -212,9 +208,9 @@ export const Playground: Story = { ))} ), -}; +}); -export const Loading: Story = { +export const Loading = meta.story({ render: () => { const [isLoading, setIsLoading] = useState(false); @@ -231,9 +227,9 @@ export const Loading: Story = { ); }, -}; +}); -export const LoadingVariants: Story = { +export const LoadingVariants = meta.story({ render: () => ( Primary @@ -289,4 +285,4 @@ export const LoadingVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx b/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx index 97072c3664..be6dad7754 100644 --- a/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx +++ b/packages/ui/src/components/ButtonIcon/ButtonIcon.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { ButtonIcon } from './ButtonIcon'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { RiCloudLine } from '@remixicon/react'; import { useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/ButtonIcon', component: ButtonIcon, argTypes: { @@ -34,16 +33,13 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: () => } />, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ render: () => ( } variant="primary" /> @@ -51,18 +47,18 @@ export const Variants: Story = { } variant="tertiary" /> ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ render: () => ( } size="small" /> } size="medium" /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( } variant="primary" /> @@ -70,9 +66,9 @@ export const Disabled: Story = { } variant="tertiary" /> ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { variant: { initial: 'primary', @@ -84,9 +80,9 @@ export const Responsive: Story = { }, }, render: args => } />, -}; +}); -export const Loading: Story = { +export const Loading = meta.story({ render: () => { const [isLoading, setIsLoading] = useState(false); @@ -106,9 +102,9 @@ export const Loading: Story = { /> ); }, -}; +}); -export const LoadingVariants: Story = { +export const LoadingVariants = meta.story({ render: () => ( Primary @@ -172,4 +168,4 @@ export const LoadingVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx b/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx index 7d288065a4..4b9b9b747c 100644 --- a/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx +++ b/packages/ui/src/components/ButtonLink/ButtonLink.stories.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { ButtonLink } from './ButtonLink'; import { Flex } from '../Flex'; import { MemoryRouter } from 'react-router-dom'; import { RiArrowRightSLine, RiCloudLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/ButtonLink', component: ButtonLink, decorators: [ @@ -40,18 +41,15 @@ const meta = { options: ['primary', 'secondary'], }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Button', }, -}; +}); -export const Variants: Story = { +export const Variants = meta.story({ render: () => ( ), -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { children: 'Button', }, @@ -96,9 +94,9 @@ export const Sizes: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { children: 'Button', }, @@ -113,9 +111,9 @@ export const WithIcons: Story = { /> ), -}; +}); -export const FullWidth: Story = { +export const FullWidth = meta.story({ args: { children: 'Button', }, @@ -130,9 +128,9 @@ export const FullWidth: Story = { /> ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ render: () => ( @@ -146,9 +144,9 @@ export const Disabled: Story = { ), -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { children: 'Button', variant: { @@ -160,4 +158,4 @@ export const Responsive: Story = { sm: 'medium', }, }, -}; +}); diff --git a/packages/ui/src/components/Card/Card.stories.tsx b/packages/ui/src/components/Card/Card.stories.tsx index 170d2b7984..f2a9c9bf07 100644 --- a/packages/ui/src/components/Card/Card.stories.tsx +++ b/packages/ui/src/components/Card/Card.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Card, CardHeader, CardBody, CardFooter } from './Card'; import { Text } from '../..'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Card', component: Card, subcomponents: { CardHeader, CardBody, CardFooter }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: args => ( Header @@ -35,19 +31,19 @@ export const Default: Story = { Footer ), -}; +}); -export const CustomSize: Story = { +export const CustomSize = meta.story({ args: { style: { width: '300px', height: '200px', }, }, - render: Default.render, -}; + render: Default.input.render, +}); -export const WithLongBody: Story = { +export const WithLongBody = meta.story({ render: () => ( @@ -77,7 +73,7 @@ export const WithLongBody: Story = { ), -}; +}); const ListRow = ({ children }: { children: React.ReactNode }) => { return ( @@ -99,7 +95,7 @@ const ListRow = ({ children }: { children: React.ReactNode }) => { ); }; -export const WithListRow: Story = { +export const WithListRow = meta.story({ render: () => ( @@ -128,4 +124,4 @@ export const WithListRow: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Checkbox/Checkbox.stories.tsx b/packages/ui/src/components/Checkbox/Checkbox.stories.tsx index a41b7f2c8d..c5318cc6fb 100644 --- a/packages/ui/src/components/Checkbox/Checkbox.stories.tsx +++ b/packages/ui/src/components/Checkbox/Checkbox.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,27 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Checkbox } from './Checkbox'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Checkbox', component: Checkbox, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: 'Accept terms and conditions', }, -}; +}); -export const AllVariants: Story = { - ...Default, +export const AllVariants = meta.story({ + ...Default.input, render: () => ( Unchecked @@ -44,4 +40,4 @@ export const AllVariants: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Container/Container.stories.tsx b/packages/ui/src/components/Container/Container.stories.tsx index 504cb3de87..44ff6f2d17 100644 --- a/packages/ui/src/components/Container/Container.stories.tsx +++ b/packages/ui/src/components/Container/Container.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Box } from '../Box/Box'; import { Container } from './Container'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Container', component: Container, parameters: { @@ -32,10 +31,7 @@ const meta = { control: 'text', }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const DecorativeBox = () => ( ( /> ); -export const Default: Story = { +export const Default = meta.story({ args: { children: , }, -}; +}); -export const Preview: Story = { +export const Preview = meta.story({ render: () => (
), -}; +}); -export const WithPaddingY: Story = { +export const WithPaddingY = meta.story({ args: { - ...Default.args, + ...Default.input.args, py: '4', }, -}; +}); -export const WithPaddingTop: Story = { +export const WithPaddingTop = meta.story({ args: { - ...Default.args, + ...Default.input.args, pt: '4', }, -}; +}); -export const WithPaddingBottom: Story = { +export const WithPaddingBottom = meta.story({ args: { - ...Default.args, + ...Default.input.args, pb: '4', }, -}; +}); -export const WithMarginY: Story = { +export const WithMarginY = meta.story({ args: { - ...Default.args, + ...Default.input.args, my: '4', }, -}; +}); -export const WithMarginTop: Story = { +export const WithMarginTop = meta.story({ args: { - ...Default.args, + ...Default.input.args, mt: '4', }, -}; +}); -export const WithMarginBottom: Story = { +export const WithMarginBottom = meta.story({ args: { - ...Default.args, + ...Default.input.args, mb: '4', }, -}; +}); diff --git a/packages/ui/src/components/Dialog/Dialog.stories.tsx b/packages/ui/src/components/Dialog/Dialog.stories.tsx index 98d2492913..7c7edc1801 100644 --- a/packages/ui/src/components/Dialog/Dialog.stories.tsx +++ b/packages/ui/src/components/Dialog/Dialog.stories.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; + +import preview from '../../../../../.storybook/preview'; import { Dialog, DialogTrigger, @@ -24,7 +25,7 @@ import { import { Button, Flex, Text, TextField, Select } from '@backstage/ui'; import { useArgs } from 'storybook/preview-api'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Dialog', component: Dialog, args: { @@ -35,12 +36,9 @@ const meta = { isOpen: { control: 'boolean' }, defaultOpen: { control: 'boolean' }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ render: args => { return ( @@ -62,17 +60,15 @@ export const Default: Story = { ); }, -}; +}); -export const Open: Story = { +export const Open = Default.extend({ args: { - ...Default.args, defaultOpen: true, }, - render: Default.render, -}; +}); -export const NoTrigger: Story = { +export const NoTrigger = meta.story({ args: { isOpen: true, }, @@ -100,9 +96,9 @@ export const NoTrigger: Story = { ); }, -}; +}); -export const FixedWidth: Story = { +export const FixedWidth = meta.story({ args: { defaultOpen: true, width: 600, @@ -145,35 +141,35 @@ export const FixedWidth: Story = { ), -}; +}); -export const FixedHeight: Story = { +export const FixedHeight = meta.story({ args: { defaultOpen: true, height: 500, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const FixedWidthAndHeight: Story = { +export const FixedWidthAndHeight = meta.story({ args: { defaultOpen: true, width: 600, height: 400, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const FullWidthAndHeight: Story = { +export const FullWidthAndHeight = meta.story({ args: { defaultOpen: true, width: '100%', height: '100%', }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const Confirmation: Story = { +export const Confirmation = meta.story({ args: { isOpen: true, }, @@ -199,9 +195,9 @@ export const Confirmation: Story = { ), -}; +}); -export const WithForm: Story = { +export const WithForm = meta.story({ args: { isOpen: true, }, @@ -235,20 +231,20 @@ export const WithForm: Story = { ), -}; +}); -export const PreviewFixedWidthAndHeight: Story = { +export const PreviewFixedWidthAndHeight = meta.story({ args: { defaultOpen: undefined, width: 600, height: 400, }, - render: FixedWidth.render, -}; + render: FixedWidth.input.render, +}); -export const PreviewWithForm: Story = { +export const PreviewWithForm = meta.story({ args: { defaultOpen: undefined, }, - render: WithForm.render, -}; + render: WithForm.input.render, +}); diff --git a/packages/ui/src/components/FieldError/FieldError.stories.tsx b/packages/ui/src/components/FieldError/FieldError.stories.tsx index 1922e12a0d..a0b2a05b92 100644 --- a/packages/ui/src/components/FieldError/FieldError.stories.tsx +++ b/packages/ui/src/components/FieldError/FieldError.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,21 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { TextField, Input, Form } from 'react-aria-components'; import { FieldError } from './FieldError'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/FieldError', component: FieldError, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); // Show error with server validation using Form component -export const WithServerValidation: Story = { +export const WithServerValidation = meta.story({ render: () => (
), -}; +}); // Show error using children -export const WithCustomMessage: Story = { +export const WithCustomMessage = meta.story({ render: () => ( This is a custom error message. ), -}; +}); // Show error with render prop function -export const WithRenderProp: Story = { +export const WithRenderProp = meta.story({ render: () => ( ), -}; +}); diff --git a/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx b/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx index d0e8f3e4fb..178df67284 100644 --- a/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx +++ b/packages/ui/src/components/FieldLabel/FieldLabel.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { FieldLabel } from './FieldLabel'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/FieldLabel', component: FieldLabel, argTypes: { @@ -31,35 +30,32 @@ const meta = { control: 'text', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { label: 'Label', }, -}; +}); -export const WithSecondaryLabel: Story = { +export const WithSecondaryLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, secondaryLabel: 'Secondary Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...Default.args, + ...Default.input.args, description: 'Description', }, -}; +}); -export const WithAllFields: Story = { +export const WithAllFields = meta.story({ args: { - ...Default.args, + ...Default.input.args, secondaryLabel: 'Secondary Label', description: 'Description', }, -}; +}); diff --git a/packages/ui/src/components/Flex/Flex.stories.tsx b/packages/ui/src/components/Flex/Flex.stories.tsx index 87854e89c7..17ee740997 100644 --- a/packages/ui/src/components/Flex/Flex.stories.tsx +++ b/packages/ui/src/components/Flex/Flex.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Flex } from './Flex'; import { Text } from '../Text'; import { Box } from '../Box'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Flex', component: Flex, argTypes: { @@ -36,10 +35,7 @@ const meta = { options: ['row', 'column', 'row-reverse', 'column-reverse'], }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const DecorativeBox = ({ width = '48px', @@ -78,7 +74,7 @@ const DecorativeBox = ({ ); }; -export const Default: Story = { +export const Default = meta.story({ args: { children: ( <> @@ -88,23 +84,23 @@ export const Default: Story = { ), }, -}; +}); -export const ColumnDirection: Story = { +export const ColumnDirection = meta.story({ args: { - ...Default.args, + ...Default.input.args, direction: 'column', }, -}; +}); -export const RowDirection: Story = { +export const RowDirection = meta.story({ args: { - ...Default.args, + ...Default.input.args, direction: 'row', }, -}; +}); -export const AlignStartInColumn: Story = { +export const AlignStartInColumn = meta.story({ args: { align: 'start', direction: 'column', @@ -116,9 +112,9 @@ export const AlignStartInColumn: Story = { ), -}; +}); -export const AlignStartInRow: Story = { +export const AlignStartInRow = meta.story({ args: { align: 'start', direction: 'row', @@ -130,9 +126,9 @@ export const AlignStartInRow: Story = { ), -}; +}); -export const AlignCenterInColumn: Story = { +export const AlignCenterInColumn = meta.story({ args: { align: 'center', direction: 'column', @@ -144,9 +140,9 @@ export const AlignCenterInColumn: Story = { ), -}; +}); -export const AlignCenterInRow: Story = { +export const AlignCenterInRow = meta.story({ args: { align: 'center', direction: 'row', @@ -158,9 +154,9 @@ export const AlignCenterInRow: Story = { ), -}; +}); -export const AlignEndInColumn: Story = { +export const AlignEndInColumn = meta.story({ args: { align: 'end', direction: 'column', @@ -172,9 +168,9 @@ export const AlignEndInColumn: Story = { ), -}; +}); -export const AlignEndInRow: Story = { +export const AlignEndInRow = meta.story({ args: { align: 'end', direction: 'row', @@ -186,9 +182,9 @@ export const AlignEndInRow: Story = { ), -}; +}); -export const ResponsiveAlign: Story = { +export const ResponsiveAlign = meta.story({ args: { align: { xs: 'start', md: 'center', lg: 'end' }, }, @@ -199,9 +195,9 @@ export const ResponsiveAlign: Story = { ), -}; +}); -export const ResponsiveGap: Story = { +export const ResponsiveGap = meta.story({ args: { gap: { xs: '4', md: '8', lg: '12' }, }, @@ -212,9 +208,9 @@ export const ResponsiveGap: Story = { ), -}; +}); -export const LargeGap: Story = { +export const LargeGap = meta.story({ args: { gap: '8', }, @@ -225,9 +221,9 @@ export const LargeGap: Story = { ), -}; +}); -export const WithTextTruncate: Story = { +export const WithTextTruncate = meta.story({ render: () => ( @@ -246,4 +242,4 @@ export const WithTextTruncate: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Grid/Grid.stories.tsx b/packages/ui/src/components/Grid/Grid.stories.tsx index 66ea346b4f..56251b6085 100644 --- a/packages/ui/src/components/Grid/Grid.stories.tsx +++ b/packages/ui/src/components/Grid/Grid.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { Grid } from './Grid'; import type { GridItemProps } from './types'; import { Box } from '../Box/Box'; import { Flex } from '../Flex'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Grid', component: Grid.Root, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const FakeBox = () => ( ( /> ); -export const Default: Story = { +export const Default = meta.story({ args: { children: ( <> @@ -51,16 +47,16 @@ export const Default: Story = { ), }, -}; +}); -export const LargeGap: Story = { +export const LargeGap = meta.story({ args: { - ...Default.args, + ...Default.input.args, gap: '64px', }, -}; +}); -export const ColumnSizes: Story = { +export const ColumnSizes = meta.story({ args: { columns: '12', }, @@ -78,9 +74,9 @@ export const ColumnSizes: Story = { ))} ), -}; +}); -export const RowAndColumns: Story = { +export const RowAndColumns = meta.story({ args: { columns: '12', }, @@ -106,4 +102,4 @@ export const RowAndColumns: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Header/Header.stories.tsx b/packages/ui/src/components/Header/Header.stories.tsx index 6ccda8bb50..7d1aa3a00a 100644 --- a/packages/ui/src/components/Header/Header.stories.tsx +++ b/packages/ui/src/components/Header/Header.stories.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import type { Meta, StoryObj, StoryFn } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { Header } from './Header'; import type { HeaderTab } from './types'; import { @@ -36,16 +37,13 @@ import { } from '@remixicon/react'; import { HeaderPageBreadcrumb } from '../HeaderPage/types'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Header', component: Header, parameters: { layout: 'fullscreen', }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const withRouter = (Story: StoryFn) => ( @@ -199,19 +197,19 @@ const layoutDecorator = [ withRouter, ]; -export const Default: Story = { +export const Default = meta.story({ args: {}, decorators: [withRouter], -}; +}); -export const WithTabs: Story = { +export const WithTabs = meta.story({ args: { tabs, }, decorators: [withRouter], -}; +}); -export const WithCustomActions: Story = { +export const WithCustomActions = meta.story({ args: {}, decorators: [withRouter], render: args => ( @@ -240,20 +238,20 @@ export const WithCustomActions: Story = { } /> ), -}; +}); -export const WithAllOptionsAndTabs: Story = { +export const WithAllOptionsAndTabs = meta.story({ args: { - ...WithCustomActions.args, + ...WithCustomActions.input.args, tabs, }, decorators: [withRouter], - render: WithCustomActions.render, -}; + render: WithCustomActions.input.render, +}); -export const WithHeaderPage: Story = { +export const WithHeaderPage = meta.story({ args: { - ...WithAllOptionsAndTabs.args, + ...WithAllOptionsAndTabs.input.args, }, decorators: [withRouter], render: args => ( @@ -276,9 +274,9 @@ export const WithHeaderPage: Story = { /> ), -}; +}); -export const WithLayout: Story = { +export const WithLayout = meta.story({ decorators: layoutDecorator, render: args => ( <> @@ -291,9 +289,9 @@ export const WithLayout: Story = { /> ), -}; +}); -export const WithLayoutNoTabs: Story = { +export const WithLayoutNoTabs = meta.story({ decorators: layoutDecorator, render: args => ( <> @@ -301,9 +299,9 @@ export const WithLayoutNoTabs: Story = { ), -}; +}); -export const WithEverything: Story = { +export const WithEverything = meta.story({ args: { tabs, titleLink: '/', @@ -333,9 +331,9 @@ export const WithEverything: Story = { /> ), -}; +}); -export const WithMockedURLCampaigns: Story = { +export const WithMockedURLCampaigns = meta.story({ args: { tabs, }, @@ -353,9 +351,9 @@ export const WithMockedURLCampaigns: Story = { ), -}; +}); -export const WithMockedURLIntegrations: Story = { +export const WithMockedURLIntegrations = meta.story({ args: { tabs, }, @@ -373,9 +371,9 @@ export const WithMockedURLIntegrations: Story = { ), -}; +}); -export const WithMockedURLNoMatch: Story = { +export const WithMockedURLNoMatch = meta.story({ args: { tabs, }, @@ -397,9 +395,9 @@ export const WithMockedURLNoMatch: Story = { ), -}; +}); -export const WithTabsMatchingStrategies: Story = { +export const WithTabsMatchingStrategies = meta.story({ args: { title: 'Route Matching Demo', tabs: [ @@ -457,9 +455,9 @@ export const WithTabsMatchingStrategies: Story = { ), -}; +}); -export const WithTabsExactMatching: Story = { +export const WithTabsExactMatching = meta.story({ args: { title: 'Exact Matching Demo', tabs: [ @@ -496,9 +494,9 @@ export const WithTabsExactMatching: Story = { ), -}; +}); -export const WithTabsPrefixMatchingDeep: Story = { +export const WithTabsPrefixMatchingDeep = meta.story({ args: { title: 'Deep Nesting Demo', tabs: [ @@ -548,4 +546,4 @@ export const WithTabsPrefixMatchingDeep: Story = { ), -}; +}); diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx index ab527bcda4..0631a6111d 100644 --- a/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx +++ b/packages/ui/src/components/HeaderPage/HeaderPage.stories.tsx @@ -1,3 +1,4 @@ +import preview from '../../../../../.storybook/preview'; /* * Copyright 2025 The Backstage Authors * @@ -14,7 +15,7 @@ * limitations under the License. */ -import type { Meta, StoryObj, StoryFn } from '@storybook/react-vite'; +import type { StoryFn } from '@storybook/react-vite'; import { HeaderPage } from './HeaderPage'; import type { HeaderTab } from '../Header/types'; import { MemoryRouter } from 'react-router-dom'; @@ -29,16 +30,13 @@ import { } from '../../'; import { RiMore2Line } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/HeaderPage', component: HeaderPage, parameters: { layout: 'fullscreen', }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const tabs: HeaderTab[] = [ { @@ -130,25 +128,25 @@ const layoutDecorator = [ ), ]; -export const Default: Story = { +export const Default = meta.story({ args: { title: 'Page Title', }, -}; +}); -export const WithTabs: Story = { +export const WithTabs = meta.story({ args: { - ...Default.args, + ...Default.input.args, tabs, }, decorators: [withRouter], -}; +}); -export const WithCustomActions: Story = { +export const WithCustomActions = meta.story({ decorators: [withRouter], render: () => ( @@ -174,48 +172,44 @@ export const WithCustomActions: Story = { } /> ), -}; +}); -export const WithBreadcrumbs: Story = { +export const WithBreadcrumbs = meta.story({ decorators: [withRouter], args: { - ...Default.args, + ...Default.input.args, breadcrumbs: [{ label: 'Home', href: '/' }], }, -}; +}); -export const WithLongBreadcrumbs: Story = { +export const WithLongBreadcrumbs = meta.story({ decorators: [withRouter], args: { - ...Default.args, + ...Default.input.args, breadcrumbs: [ { label: 'Home', href: '/' }, { label: 'Long Breadcrumb Name', href: '/long-breadcrumb' }, ], }, -}; +}); -export const WithEverything: Story = { +export const WithEverything = meta.story({ decorators: [withRouter], render: () => ( Custom action} breadcrumbs={[{ label: 'Home', href: '/' }]} /> ), -}; +}); -export const WithLayout: Story = { - args: { - ...WithEverything.args, - }, - decorators: [withRouter, ...layoutDecorator], - render: WithEverything.render, -}; +export const WithLayout = WithEverything.extend({ + decorators: [...layoutDecorator], +}); -export const WithTabsMatchingStrategies: Story = { +export const WithTabsMatchingStrategies = meta.story({ args: { title: 'Route Matching Demo', tabs: [ @@ -273,9 +267,9 @@ export const WithTabsMatchingStrategies: Story = { ), -}; +}); -export const WithTabsExactMatching: Story = { +export const WithTabsExactMatching = meta.story({ args: { title: 'Exact Matching Demo', tabs: [ @@ -312,9 +306,9 @@ export const WithTabsExactMatching: Story = { ), -}; +}); -export const WithTabsPrefixMatchingDeep: Story = { +export const WithTabsPrefixMatchingDeep = meta.story({ args: { title: 'Deep Nesting Demo', tabs: [ @@ -364,4 +358,4 @@ export const WithTabsPrefixMatchingDeep: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Link/Link.stories.tsx b/packages/ui/src/components/Link/Link.stories.tsx index 37f142c4dc..7d680e5616 100644 --- a/packages/ui/src/components/Link/Link.stories.tsx +++ b/packages/ui/src/components/Link/Link.stories.tsx @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; +import type { StoryFn } from '@storybook/react-vite'; import { Link } from './Link'; import { Flex } from '../Flex'; import { Text } from '../Text'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Link', component: Link, args: { @@ -33,29 +34,26 @@ const meta = { ), ], -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { href: '/', children: 'Sign up for Backstage', }, -}; +}); -export const ExternalLink: Story = { +export const ExternalLink = meta.story({ args: { href: 'https://backstage.io', children: 'Sign up for Backstage', target: '_blank', }, -}; +}); -export const AllVariants: Story = { +export const AllVariants = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -69,9 +67,9 @@ export const AllVariants: Story = { ), -}; +}); -export const AllColors: Story = { +export const AllColors = meta.story({ render: () => ( ), -}; +}); -export const AllWeights: Story = { +export const AllWeights = meta.story({ render: () => ( @@ -225,9 +223,9 @@ export const AllWeights: Story = { ), -}; +}); -export const Truncate: Story = { +export const Truncate = meta.story({ args: { children: "A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is in the painting?", @@ -235,21 +233,21 @@ export const Truncate: Story = { truncate: true, style: { width: '480px' }, }, -}; +}); -export const Responsive: Story = { +export const Responsive = meta.story({ args: { - ...Default.args, + ...Default.input.args, variant: { xs: 'title-x-small', md: 'body-x-small', }, }, -}; +}); -export const Playground: Story = { +export const Playground = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -269,4 +267,4 @@ export const Playground: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/Menu.stories.tsx b/packages/ui/src/components/Menu/Menu.stories.tsx index 7171b3ef83..ffe184d4ae 100644 --- a/packages/ui/src/components/Menu/Menu.stories.tsx +++ b/packages/ui/src/components/Menu/Menu.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, SubmenuTrigger, @@ -38,7 +38,7 @@ import { import { MemoryRouter } from 'react-router-dom'; import { useEffect, useState } from 'react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Menu', component: MenuTrigger, decorators: [ @@ -48,10 +48,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -65,7 +62,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Preview: Story = { +export const Preview = meta.story({ args: { children: null, }, @@ -91,11 +88,11 @@ export const Preview: Story = { ), -}; +}); -export const PreviewSubmenu: Story = { +export const PreviewSubmenu = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -119,11 +116,11 @@ export const PreviewSubmenu: Story = { ), -}; +}); -export const PreviewIcons: Story = { +export const PreviewIcons = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -135,11 +132,11 @@ export const PreviewIcons: Story = { ), -}; +}); -export const PreviewSections: Story = { +export const PreviewSections = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -159,11 +156,11 @@ export const PreviewSections: Story = { ), -}; +}); -export const PreviewSeparators: Story = { +export const PreviewSeparators = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -180,11 +177,11 @@ export const PreviewSeparators: Story = { ), -}; +}); -export const PreviewLinks: Story = { +export const PreviewLinks = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -198,11 +195,11 @@ export const PreviewLinks: Story = { ), -}; +}); -export const Opened: Story = { +export const Opened = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -214,11 +211,11 @@ export const Opened: Story = { ), -}; +}); -export const WithIcons: Story = { +export const WithIcons = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -230,11 +227,11 @@ export const WithIcons: Story = { ), -}; +}); -export const WithSections: Story = { +export const WithSections = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -254,11 +251,11 @@ export const WithSections: Story = { ), -}; +}); -export const WithSeparators: Story = { +export const WithSeparators = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -275,11 +272,11 @@ export const WithSeparators: Story = { ), -}; +}); -export const WithColors: Story = { +export const WithColors = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -295,11 +292,11 @@ export const WithColors: Story = { ), -}; +}); -export const WithLinks: Story = { +export const WithLinks = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -313,11 +310,11 @@ export const WithLinks: Story = { ), -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => ( @@ -341,11 +338,11 @@ export const Submenu: Story = { ), -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -376,11 +373,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -411,9 +408,9 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); -export const WithScroll: Story = { +export const WithScroll = meta.story({ args: { children: null, }, @@ -446,4 +443,4 @@ export const WithScroll: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx b/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx index c0e1aca932..af68ec9415 100644 --- a/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx +++ b/packages/ui/src/components/Menu/MenuAutocomplete.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, SubmenuTrigger, @@ -26,7 +26,7 @@ import { Button } from '../..'; import { useState, useEffect } from 'react'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuAutocomplete', component: MenuTrigger, decorators: [ @@ -36,10 +36,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -53,7 +50,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -72,11 +69,11 @@ export const Default: Story = { ), -}; +}); -export const PreviewAutocompleteMenu: Story = { +export const PreviewAutocompleteMenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => ( @@ -93,11 +90,11 @@ export const PreviewAutocompleteMenu: Story = { ), -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -132,11 +129,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -172,11 +169,11 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => ( @@ -197,4 +194,4 @@ export const Submenu: Story = { ), -}; +}); diff --git a/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx b/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx index bf66f5f8fd..e1c22fbd9e 100644 --- a/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx +++ b/packages/ui/src/components/Menu/MenuAutocompleteListBox.stories.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, MenuAutocompleteListbox, @@ -28,7 +28,7 @@ import { useEffect, useState } from 'react'; import { Selection } from 'react-aria-components'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuAutocompleteListBox', component: MenuTrigger, decorators: [ @@ -38,10 +38,7 @@ const meta = { ), ], -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const options = [ { label: 'Apple', value: 'apple' }, @@ -55,7 +52,7 @@ const options = [ { label: 'Honeydew', value: 'honeydew' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -83,11 +80,11 @@ export const Default: Story = { ); }, -}; +}); -export const PreviewListbox: Story = { +export const PreviewListbox = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -113,11 +110,11 @@ export const PreviewListbox: Story = { ); }, -}; +}); -export const PreviewListboxMultiple: Story = { +export const PreviewListboxMultiple = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -144,11 +141,11 @@ export const PreviewListboxMultiple: Story = { ); }, -}; +}); -export const Submenu: Story = { +export const Submenu = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState( @@ -182,11 +179,11 @@ export const Submenu: Story = { ); }, -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -221,11 +218,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -261,4 +258,4 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/Menu/MenuListBox.stories.tsx b/packages/ui/src/components/Menu/MenuListBox.stories.tsx index 72284fb6b9..2297598d0c 100644 --- a/packages/ui/src/components/Menu/MenuListBox.stories.tsx +++ b/packages/ui/src/components/Menu/MenuListBox.stories.tsx @@ -14,14 +14,14 @@ * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { MenuTrigger, MenuListBox, MenuListBoxItem } from './index'; import { Button, Flex, Text } from '../..'; import { useEffect, useState } from 'react'; import { Selection } from 'react-aria-components'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/MenuListBox', component: MenuTrigger, decorators: [ @@ -31,12 +31,9 @@ const meta = { ), ], -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { children: null, }, @@ -50,11 +47,11 @@ export const Default: Story = { ), -}; +}); -export const Controlled: Story = { +export const Controlled = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [selected, setSelected] = useState(new Set(['paul'])); @@ -86,11 +83,11 @@ export const Controlled: Story = { ); }, -}; +}); -export const Virtualized: Story = { +export const Virtualized = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -121,11 +118,11 @@ export const Virtualized: Story = { ); }, -}; +}); -export const VirtualizedMaxHeight: Story = { +export const VirtualizedMaxHeight = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: () => { const [pokemon, setPokemon] = useState< @@ -156,4 +153,4 @@ export const VirtualizedMaxHeight: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/PasswordField/PasswordField.stories.tsx b/packages/ui/src/components/PasswordField/PasswordField.stories.tsx index 1867e5b7bf..5f6a74d992 100644 --- a/packages/ui/src/components/PasswordField/PasswordField.stories.tsx +++ b/packages/ui/src/components/PasswordField/PasswordField.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { PasswordField } from './PasswordField'; import { Form } from 'react-aria-components'; import { Flex } from '../Flex'; import { FieldLabel } from '../FieldLabel'; import { RiSparklingLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/PasswordField', component: PasswordField, argTypes: { @@ -32,12 +31,9 @@ const meta = { control: 'object', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { name: 'secret', placeholder: 'Enter a secret', @@ -45,11 +41,11 @@ export const Default: Story = { maxWidth: '300px', }, }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -57,79 +53,79 @@ export const Sizes: Story = { } /> ), -}; +}); -export const DefaultValue: Story = { +export const DefaultValue = meta.story({ args: { - ...Default.args, + ...Default.input.args, defaultValue: 'https://example.com', }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Description', }, -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( } /> ), -}; +}); -export const DisabledWithIcon: Story = { +export const DisabledWithIcon = meta.story({ args: { - ...WithIcon.args, + ...WithIcon.input.args, isDisabled: true, }, - render: WithIcon.render, -}; + render: WithIcon.input.render, +}); -export const ShowError: Story = { +export const ShowError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => (
), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, validate: value => (value === 'admin' ? 'Nice try!' : null), }, -}; +}); -export const CustomField: Story = { +export const CustomField = meta.story({ render: () => ( <> ), -}; +}); diff --git a/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx index df7a826c50..4f3465dade 100644 --- a/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx +++ b/packages/ui/src/components/RadioGroup/RadioGroup.stories.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Backstage Authors + * Copyright 2025 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,19 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; +import preview from '../../../../../.storybook/preview'; import { RadioGroup, Radio } from './RadioGroup'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/RadioGroup', component: RadioGroup, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { label: 'What is your favorite pokemon?', }, @@ -36,11 +32,11 @@ export const Default: Story = { Squirtle ), -}; +}); -export const Horizontal: Story = { +export const Horizontal = meta.story({ args: { - ...Default.args, + ...Default.input.args, orientation: 'horizontal', }, render: args => ( @@ -50,11 +46,11 @@ export const Horizontal: Story = { Squirtle ), -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, render: args => ( @@ -64,11 +60,11 @@ export const Disabled: Story = { Squirtle ), -}; +}); -export const DisabledSingle: Story = { +export const DisabledSingle = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -79,11 +75,11 @@ export const DisabledSingle: Story = { Squirtle ), -}; +}); -export const DisabledAndSelected: Story = { +export const DisabledAndSelected = meta.story({ args: { - ...Default.args, + ...Default.input.args, value: 'charmander', }, render: args => ( @@ -95,11 +91,11 @@ export const DisabledAndSelected: Story = { Squirtle ), -}; +}); -export const Invalid: Story = { +export const Invalid = meta.story({ args: { - ...Default.args, + ...Default.input.args, name: 'pokemon', isInvalid: true, }, @@ -112,11 +108,11 @@ export const Invalid: Story = { Squirtle ), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...Default.args, + ...Default.input.args, name: 'pokemon', defaultValue: 'charmander', validationBehavior: 'aria', @@ -129,11 +125,11 @@ export const Validation: Story = { Squirtle ), -}; +}); -export const ReadOnly: Story = { +export const ReadOnly = meta.story({ args: { - ...Default.args, + ...Default.input.args, isReadOnly: true, defaultValue: 'charmander', }, @@ -144,4 +140,4 @@ export const ReadOnly: Story = { Squirtle ), -}; +}); diff --git a/packages/ui/src/components/SearchField/SearchField.stories.tsx b/packages/ui/src/components/SearchField/SearchField.stories.tsx index 96f0310e73..2e07e742ad 100644 --- a/packages/ui/src/components/SearchField/SearchField.stories.tsx +++ b/packages/ui/src/components/SearchField/SearchField.stories.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ +import preview from '../../../../../.storybook/preview'; import { useState } from 'react'; -import type { Meta, StoryObj } from '@storybook/react-vite'; import { SearchField } from './SearchField'; import { Form } from 'react-aria-components'; import { Flex } from '../Flex'; @@ -26,7 +26,7 @@ import { Button } from '../Button'; import { Header } from '../Header'; import { MemoryRouter } from 'react-router-dom'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/SearchField', component: SearchField, argTypes: { @@ -40,12 +40,9 @@ const meta = { control: 'text', }, }, -} satisfies Meta; +}); -export default meta; -type Story = StoryObj; - -export const Default: Story = { +export const Default = meta.story({ args: { name: 'url', style: { @@ -53,11 +50,11 @@ export const Default: Story = { }, 'aria-label': 'Search', }, -}; +}); -export const Sizes: Story = { +export const Sizes = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( @@ -65,46 +62,46 @@ export const Sizes: Story = { ), -}; +}); -export const DefaultValue: Story = { +export const DefaultValue = meta.story({ args: { - ...Default.args, + ...Default.input.args, defaultValue: 'https://example.com', }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Label', }, -}; +}); -export const WithDescription: Story = { +export const WithDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Description', }, -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Default.args, + ...Default.input.args, isDisabled: true, }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...Default.args, + ...Default.input.args, }, render: args => ( } /> ), -}; +}); -export const DisabledWithIcon: Story = { +export const DisabledWithIcon = meta.story({ args: { - ...WithIcon.args, + ...WithIcon.input.args, isDisabled: true, }, -}; +}); -export const ShowError: Story = { +export const ShowError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => (
), -}; +}); -export const Validation: Story = { +export const Validation = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, validate: value => (value === 'admin' ? 'Nice try!' : null), }, -}; +}); -export const CustomField: Story = { +export const CustomField = meta.story({ render: () => ( <> ), -}; +}); -export const StartCollapsed: Story = { +export const StartCollapsed = meta.story({ args: { - ...Default.args, + ...Default.input.args, startCollapsed: true, }, @@ -174,18 +171,18 @@ export const StartCollapsed: Story = { ), -}; +}); -export const StartCollapsedWithValue: Story = { +export const StartCollapsedWithValue = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, defaultValue: 'https://example.com', }, render: args => , -}; +}); -export const InHeader: Story = { +export const InHeader = meta.story({ decorators: [ Story => ( @@ -217,11 +214,11 @@ export const InHeader: Story = { /> ), -}; +}); -export const StartCollapsedInHeader: Story = { +export const StartCollapsedInHeader = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, decorators: [ Story => ( @@ -254,11 +251,11 @@ export const StartCollapsedInHeader: Story = { /> ), -}; +}); -export const StartCollapsedWithButtons: Story = { +export const StartCollapsedWithButtons = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: args => ( @@ -284,11 +281,11 @@ export const StartCollapsedWithButtons: Story = { ), -}; +}); -export const StartCollapsedWithOnChange: Story = { +export const StartCollapsedWithOnChange = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: args => { const handleChange = (value: string) => { @@ -305,11 +302,11 @@ export const StartCollapsedWithOnChange: Story = { ); }, -}; +}); -export const StartCollapsedControlledEmpty: Story = { +export const StartCollapsedControlledEmpty = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: function Render(args) { const [value, setValue] = useState(''); @@ -324,11 +321,11 @@ export const StartCollapsedControlledEmpty: Story = { ); }, -}; +}); -export const StartCollapsedControlledWithValue: Story = { +export const StartCollapsedControlledWithValue = meta.story({ args: { - ...StartCollapsed.args, + ...StartCollapsed.input.args, }, render: function Render(args) { const [value, setValue] = useState('Component'); @@ -343,4 +340,4 @@ export const StartCollapsedControlledWithValue: Story = { ); }, -}; +}); diff --git a/packages/ui/src/components/Select/Select.stories.tsx b/packages/ui/src/components/Select/Select.stories.tsx index 18263fe710..e3c2ad41aa 100644 --- a/packages/ui/src/components/Select/Select.stories.tsx +++ b/packages/ui/src/components/Select/Select.stories.tsx @@ -13,22 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { Meta, StoryObj } from '@storybook/react-vite'; + +import preview from '../../../../../.storybook/preview'; import { Select } from './Select'; import { Flex } from '../Flex'; import { Form } from 'react-aria-components'; import { RiCloudLine } from '@remixicon/react'; -const meta = { +const meta = preview.meta({ title: 'Backstage UI/Select', component: Select, args: { style: { width: 300 }, }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; +}); const fontOptions = [ { value: 'sans', label: 'Sans-serif' }, @@ -66,23 +64,23 @@ const skills = [ { value: 'swift', label: 'Swift' }, ]; -export const Default: Story = { +export const Default = meta.story({ args: { options: fontOptions, name: 'font', }, -}; +}); -export const Searchable: Story = { +export const Searchable = meta.story({ args: { label: 'Country', searchable: true, searchPlaceholder: 'Search countries...', options: countries, }, -}; +}); -export const MultipleSelection: Story = { +export const MultipleSelection = meta.story({ args: { label: 'Select multiple options', selectionMode: 'multiple', @@ -93,9 +91,9 @@ export const MultipleSelection: Story = { { value: 'option4', label: 'Option 4' }, ], }, -}; +}); -export const SearchableMultiple: Story = { +export const SearchableMultiple = meta.story({ args: { label: 'Skills', searchable: true, @@ -103,9 +101,9 @@ export const SearchableMultiple: Story = { searchPlaceholder: 'Filter skills...', options: skills, }, -}; +}); -export const Preview: Story = { +export const Preview = meta.story({ args: { label: 'Font Family', options: fontOptions, @@ -113,40 +111,40 @@ export const Preview: Story = { name: 'font', style: { maxWidth: 260 }, }, -}; +}); -export const WithLabel: Story = { +export const WithLabel = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Font Family', }, -}; +}); -export const WithFullWidth: Story = { +export const WithFullWidth = meta.story({ args: { - ...Default.args, + ...Default.input.args, label: 'Font Family', style: { width: '100%' }, }, -}; +}); -export const WithLabelAndDescription: Story = { +export const WithLabelAndDescription = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, description: 'Choose a font family for your document', }, -}; +}); -export const WithIcon: Story = { +export const WithIcon = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, }, render: args => } /> ), -}; +}); -export const Required: Story = { +export const Required = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, isRequired: true, }, -}; +}); -export const Disabled: Story = { +export const Disabled = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, isDisabled: true, }, -}; +}); -export const DisabledOption: Story = { +export const DisabledOption = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, disabledKeys: ['cursive', 'serif'], }, -}; +}); -export const NoOptions: Story = { +export const NoOptions = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, options: undefined, }, -}; +}); -export const WithValue: Story = { +export const WithValue = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, selectedKey: 'mono', defaultSelectedKey: 'serif', }, -}; +}); -export const WithDefaultValue: Story = { +export const WithDefaultValue = meta.story({ args: { - ...Preview.args, + ...Preview.input.args, defaultSelectedKey: 'serif', options: fontOptions, name: 'font', }, -}; +}); const generateOptions = (count = 100) => { const firstWords = [ @@ -323,17 +321,17 @@ const generateOptions = (count = 100) => { })); }; -export const WithManyOptions: Story = { +export const WithManyOptions = meta.story({ args: { label: 'Font Family', options: generateOptions(), name: 'font', }, -}; +}); -export const WithError: Story = { +export const WithError = meta.story({ args: { - ...WithLabel.args, + ...WithLabel.input.args, name: 'font', }, render: args => ( @@ -341,9 +339,9 @@ export const WithError: Story = {