@sovereignfs/ui 0.45.0 → 0.83.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Accordion.module.css +1 -1
- package/dist/Alert.module.css +1 -1
- package/dist/AppsLauncher.module.css +96 -0
- package/dist/Avatar.module.css +1 -1
- package/dist/Badge.module.css +30 -7
- package/dist/BalanceChip.module.css +1 -1
- package/dist/Button.module.css +18 -2
- package/dist/Card.module.css +1 -1
- package/dist/CardTile.module.css +181 -0
- package/dist/CodeTextarea.module.css +1 -1
- package/dist/Collapsible.module.css +1 -1
- package/dist/ColorPicker.module.css +132 -0
- package/dist/Combobox.module.css +2 -2
- package/dist/Command.module.css +1 -1
- package/dist/ConfirmDialog.module.css +2 -2
- package/dist/ConsentPrompt.module.css +21 -0
- package/dist/DatePicker.module.css +1 -1
- package/dist/Dialog.module.css +130 -21
- package/dist/Drawer.module.css +36 -7
- package/dist/Header.module.css +62 -0
- package/dist/HeaderFooterLayout.module.css +21 -0
- package/dist/IconPicker.module.css +1 -1
- package/dist/Input.module.css +1 -1
- package/dist/Kbd.module.css +1 -1
- package/dist/LegalLinks.module.css +24 -0
- package/dist/Markdown.module.css +73 -0
- package/dist/Menu.module.css +1 -0
- package/dist/Message.module.css +1 -1
- package/dist/MessageScroller.module.css +12 -1
- package/dist/MobileAppsDrawer.module.css +82 -0
- package/dist/MobileFooter.module.css +73 -0
- package/dist/MobileHeader.module.css +76 -0
- package/dist/NavList.module.css +130 -0
- package/dist/NavTabs.module.css +1 -1
- package/dist/NotificationsPanel.module.css +258 -0
- package/dist/OverlayHeader.module.css +1 -1
- package/dist/PageContainer.module.css +82 -0
- package/dist/PageHeader.module.css +54 -0
- package/dist/PageLayout.module.css +51 -0
- package/dist/Popover.module.css +1 -1
- package/dist/QuantityStepper.module.css +1 -1
- package/dist/Resizable.module.css +3 -3
- package/dist/RootLayout.module.css +12 -0
- package/dist/SegmentedControl.module.css +1 -1
- package/dist/Select.module.css +1 -1
- package/dist/Sheet.module.css +4 -1
- package/dist/SplitPane.module.css +4 -4
- package/dist/StatusBadge.module.css +1 -1
- package/dist/StepStrip.module.css +53 -0
- package/dist/SuggestionInput.module.css +2 -2
- package/dist/SwipableMobileCarousel.module.css +64 -0
- package/dist/SwipableMobileCarouselDots.module.css +64 -0
- package/dist/SwipableMobileCarouselSlideParts.module.css +29 -0
- package/dist/SwipeStack.module.css +101 -0
- package/dist/SystemBanner.module.css +10 -0
- package/dist/Table.module.css +2 -2
- package/dist/Tabs.module.css +1 -1
- package/dist/TagInput.module.css +2 -2
- package/dist/Textarea.module.css +9 -1
- package/dist/ThreeColumnLayout.module.css +35 -0
- package/dist/Toast.module.css +62 -3
- package/dist/Tooltip.module.css +1 -1
- package/dist/UserMenu.module.css +90 -0
- package/dist/index.d.ts +1680 -30
- package/dist/index.js +4618 -1443
- package/dist/tokens/primitives.css +36 -0
- package/dist/tokens/semantic.css +32 -0
- package/dist/tokens/theme-presets.css +33 -0
- package/package.json +32 -12
- package/src/__tests__/package-json.test.ts +8 -0
- package/src/components/Accordion/Accordion.module.css +1 -1
- package/src/components/Alert/Alert.module.css +1 -1
- package/src/components/AppsLauncher/AppsLauncher.module.css +96 -0
- package/src/components/AppsLauncher/AppsLauncher.stories.tsx +58 -0
- package/src/components/AppsLauncher/AppsLauncher.tsx +117 -0
- package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +52 -0
- package/src/components/Avatar/Avatar.module.css +1 -1
- package/src/components/Badge/Badge.module.css +30 -7
- package/src/components/Badge/Badge.stories.tsx +16 -4
- package/src/components/Badge/Badge.tsx +8 -11
- package/src/components/Badge/__tests__/Badge.test.tsx +4 -2
- package/src/components/BalanceChip/BalanceChip.module.css +1 -1
- package/src/components/Button/Button.module.css +18 -2
- package/src/components/Card/Card.module.css +1 -1
- package/src/components/CardTile/CardTile.module.css +181 -0
- package/src/components/CardTile/CardTile.stories.tsx +86 -0
- package/src/components/CardTile/CardTile.tsx +128 -0
- package/src/components/CardTile/__tests__/CardTile.test.tsx +56 -0
- package/src/components/CodeTextarea/CodeTextarea.module.css +1 -1
- package/src/components/Collapsible/Collapsible.module.css +1 -1
- package/src/components/ColorPicker/ColorPicker.module.css +132 -0
- package/src/components/ColorPicker/ColorPicker.stories.tsx +80 -0
- package/src/components/ColorPicker/ColorPicker.tsx +157 -0
- package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +117 -0
- package/src/components/Combobox/Combobox.module.css +2 -2
- package/src/components/Command/Command.module.css +1 -1
- package/src/components/ConfirmDialog/ConfirmDialog.module.css +2 -2
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +28 -2
- package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +71 -3
- package/src/components/ConsentPrompt/ConsentPrompt.module.css +21 -0
- package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +31 -0
- package/src/components/ConsentPrompt/ConsentPrompt.tsx +66 -0
- package/src/components/ContextMenu/ContextMenu.tsx +1 -1
- package/src/components/DatePicker/DatePicker.module.css +1 -1
- package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +58 -0
- package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +45 -0
- package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +100 -0
- package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +119 -0
- package/src/components/Dialog/Dialog.module.css +130 -21
- package/src/components/Dialog/Dialog.stories.tsx +179 -2
- package/src/components/Dialog/Dialog.tsx +137 -94
- package/src/components/Dialog/__tests__/Dialog.test.tsx +190 -9
- package/src/components/DragHandleRow/DragHandleRow.tsx +2 -21
- package/src/components/Drawer/Drawer.module.css +36 -7
- package/src/components/Drawer/Drawer.stories.tsx +44 -0
- package/src/components/Drawer/Drawer.tsx +27 -66
- package/src/components/Drawer/__tests__/Drawer.test.tsx +55 -6
- package/src/components/GripIcon/GripIcon.tsx +27 -0
- package/src/components/Header/Header.module.css +62 -0
- package/src/components/Header/Header.stories.tsx +452 -0
- package/src/components/Header/Header.tsx +102 -0
- package/src/components/Header/__tests__/Header.test.tsx +104 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +21 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +111 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +54 -0
- package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +58 -0
- package/src/components/Icon/icons/arrow-left-right.tsx +23 -0
- package/src/components/Icon/icons/bold.tsx +20 -0
- package/src/components/Icon/icons/calendar.tsx +4 -4
- package/src/components/Icon/icons/carrot.tsx +3 -3
- package/src/components/Icon/icons/circle-chevron-left.tsx +21 -0
- package/src/components/Icon/icons/code.tsx +21 -0
- package/src/components/Icon/icons/copy.tsx +21 -0
- package/src/components/Icon/icons/credit-card.tsx +21 -0
- package/src/components/Icon/icons/database.tsx +22 -0
- package/src/components/Icon/icons/download.tsx +22 -0
- package/src/components/Icon/icons/file-text.tsx +24 -0
- package/src/components/Icon/icons/folder-closed.tsx +21 -0
- package/src/components/Icon/icons/folder-open.tsx +20 -0
- package/src/components/Icon/icons/folder.tsx +20 -0
- package/src/components/Icon/icons/folders.tsx +21 -0
- package/src/components/Icon/icons/hat-glasses.tsx +24 -0
- package/src/components/Icon/icons/history.tsx +22 -0
- package/src/components/Icon/icons/inbox.tsx +21 -0
- package/src/components/Icon/icons/index.ts +169 -1
- package/src/components/Icon/icons/italic.tsx +22 -0
- package/src/components/Icon/icons/layers.tsx +22 -0
- package/src/components/Icon/icons/layout-dashboard.tsx +23 -0
- package/src/components/Icon/icons/layout-grid.tsx +23 -0
- package/src/components/Icon/icons/link.tsx +21 -0
- package/src/components/Icon/icons/list-ordered.tsx +25 -0
- package/src/components/Icon/icons/list.tsx +25 -0
- package/src/components/Icon/icons/luggage.tsx +24 -0
- package/src/components/Icon/icons/map-pin.tsx +21 -0
- package/src/components/Icon/icons/menu.tsx +22 -0
- package/src/components/Icon/icons/minus.tsx +20 -0
- package/src/components/Icon/icons/paint-bucket.tsx +23 -0
- package/src/components/Icon/icons/panel-left.tsx +21 -0
- package/src/components/Icon/icons/pin.tsx +21 -0
- package/src/components/Icon/icons/rectangle-ellipsis.tsx +23 -0
- package/src/components/Icon/icons/refresh-cw.tsx +23 -0
- package/src/components/Icon/icons/rotate-cw.tsx +21 -0
- package/src/components/Icon/icons/route.tsx +22 -0
- package/src/components/Icon/icons/send.tsx +21 -0
- package/src/components/Icon/icons/share-2.tsx +24 -0
- package/src/components/Icon/icons/sheet.tsx +24 -0
- package/src/components/Icon/icons/smartphone.tsx +21 -0
- package/src/components/Icon/icons/square-kanban.tsx +23 -0
- package/src/components/Icon/icons/table.tsx +23 -0
- package/src/components/Icon/icons/user-round-plus.tsx +23 -0
- package/src/components/Icon/icons/users.tsx +23 -0
- package/src/components/IconPicker/IconPicker.module.css +1 -1
- package/src/components/Input/Input.module.css +1 -1
- package/src/components/Input/Input.tsx +8 -2
- package/src/components/Kbd/Kbd.module.css +1 -1
- package/src/components/LegalLinks/LegalLinks.module.css +24 -0
- package/src/components/LegalLinks/LegalLinks.stories.tsx +22 -0
- package/src/components/LegalLinks/LegalLinks.tsx +40 -0
- package/src/components/Markdown/Markdown.module.css +73 -0
- package/src/components/Markdown/Markdown.stories.tsx +40 -0
- package/src/components/Markdown/Markdown.tsx +305 -0
- package/src/components/Markdown/__tests__/Markdown.test.tsx +144 -0
- package/src/components/Menu/Menu.module.css +1 -0
- package/src/components/Menu/Menu.tsx +72 -22
- package/src/components/Menu/__tests__/Menu.test.tsx +30 -0
- package/src/components/Menubar/Menubar.tsx +1 -1
- package/src/components/Message/Message.module.css +1 -1
- package/src/components/MessageScroller/MessageScroller.module.css +12 -1
- package/src/components/MessageScroller/MessageScroller.tsx +12 -0
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +82 -0
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +78 -0
- package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +80 -0
- package/src/components/MobileFooter/MobileFooter.module.css +73 -0
- package/src/components/MobileFooter/MobileFooter.stories.tsx +47 -0
- package/src/components/MobileFooter/MobileFooter.tsx +122 -0
- package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +129 -0
- package/src/components/MobileHeader/MobileHeader.module.css +76 -0
- package/src/components/MobileHeader/MobileHeader.stories.tsx +57 -0
- package/src/components/MobileHeader/MobileHeader.tsx +90 -0
- package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +113 -0
- package/src/components/NavList/NavList.module.css +130 -0
- package/src/components/NavList/NavList.tsx +136 -0
- package/src/components/NavList/__tests__/NavList.test.tsx +109 -0
- package/src/components/NavTabs/NavTabs.module.css +1 -1
- package/src/components/NavTabs/NavTabs.tsx +39 -11
- package/src/components/NotificationsPanel/NotificationsPanel.module.css +258 -0
- package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +61 -0
- package/src/components/NotificationsPanel/NotificationsPanel.tsx +187 -0
- package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +78 -0
- package/src/components/OfflineGate/OfflineGate.tsx +44 -0
- package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +66 -0
- package/src/components/OverlayHeader/OverlayHeader.module.css +1 -1
- package/src/components/OverlayHeader/OverlayHeader.tsx +19 -4
- package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +18 -0
- package/src/components/PageContainer/PageContainer.module.css +82 -0
- package/src/components/PageContainer/PageContainer.tsx +64 -0
- package/src/components/PageContainer/__tests__/PageContainer.test.tsx +70 -0
- package/src/components/PageHeader/PageHeader.module.css +54 -0
- package/src/components/PageHeader/PageHeader.tsx +157 -2
- package/src/components/PageHeader/__tests__/PageHeader.test.tsx +103 -0
- package/src/components/PageLayout/PageLayout.module.css +51 -0
- package/src/components/PageLayout/PageLayout.stories.tsx +73 -0
- package/src/components/PageLayout/PageLayout.tsx +51 -0
- package/src/components/PageLayout/__tests__/PageLayout.test.tsx +34 -0
- package/src/components/Popover/Popover.module.css +1 -1
- package/src/components/Popover/Popover.tsx +86 -4
- package/src/components/Popover/__tests__/Popover.test.tsx +165 -0
- package/src/components/QuantityStepper/QuantityStepper.module.css +1 -1
- package/src/components/Resizable/Resizable.module.css +3 -3
- package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +24 -0
- package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +73 -0
- package/src/components/RootLayout/RootLayout.module.css +12 -0
- package/src/components/RootLayout/RootLayout.stories.tsx +125 -0
- package/src/components/RootLayout/RootLayout.tsx +185 -0
- package/src/components/RootLayout/__tests__/RootLayout.test.tsx +161 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +1 -1
- package/src/components/Select/Select.module.css +1 -1
- package/src/components/Sheet/Sheet.module.css +4 -1
- package/src/components/Sheet/Sheet.tsx +14 -56
- package/src/components/SplitPane/SplitPane.module.css +4 -4
- package/src/components/StatusBadge/StatusBadge.module.css +1 -1
- package/src/components/StepStrip/StepStrip.module.css +53 -0
- package/src/components/StepStrip/StepStrip.tsx +74 -0
- package/src/components/SuggestionInput/SuggestionInput.module.css +2 -2
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +64 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +243 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +35 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +42 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +18 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +21 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +29 -0
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +214 -0
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +61 -0
- package/src/components/SwipableMobileCarousel/context.ts +13 -0
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +64 -0
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +73 -0
- package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +63 -0
- package/src/components/SwipeStack/SwipeStack.module.css +101 -0
- package/src/components/SwipeStack/SwipeStack.tsx +199 -0
- package/src/components/SwipeStack/SwipeStackCard.tsx +22 -0
- package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +169 -0
- package/src/components/SystemBanner/SystemBanner.module.css +10 -0
- package/src/components/Table/Table.module.css +2 -2
- package/src/components/Tabs/Tabs.module.css +1 -1
- package/src/components/TagInput/TagInput.module.css +2 -2
- package/src/components/Textarea/Textarea.module.css +9 -1
- package/src/components/Textarea/Textarea.tsx +28 -5
- package/src/components/Textarea/__tests__/Textarea.test.tsx +23 -1
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +35 -0
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +152 -0
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +87 -0
- package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +78 -0
- package/src/components/Toast/Toast.module.css +62 -3
- package/src/components/Toast/Toast.stories.tsx +1 -1
- package/src/components/Tooltip/Tooltip.module.css +1 -1
- package/src/components/UserMenu/UserMenu.module.css +90 -0
- package/src/components/UserMenu/UserMenu.stories.tsx +49 -0
- package/src/components/UserMenu/UserMenu.tsx +132 -0
- package/src/components/UserMenu/__tests__/UserMenu.test.tsx +77 -0
- package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +126 -0
- package/src/hooks/__tests__/useIsOffline.test.tsx +53 -0
- package/src/hooks/__tests__/useOfflineTileState.test.tsx +69 -0
- package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +118 -0
- package/src/hooks/__tests__/useReorderSensors.test.ts +26 -0
- package/src/hooks/__tests__/useResponsiveLayout.test.tsx +87 -0
- package/src/hooks/__tests__/useSnapCarousel.test.tsx +175 -0
- package/src/hooks/__tests__/useSwipeReveal.test.tsx +110 -0
- package/src/hooks/__tests__/useSwipeStack.test.tsx +155 -0
- package/src/hooks/index.ts +27 -0
- package/src/hooks/useCarouselRouteSync.ts +92 -0
- package/src/hooks/useIsOffline.ts +41 -0
- package/src/hooks/useOfflineTileState.ts +45 -0
- package/src/hooks/usePublishShellChromeHeight.ts +96 -0
- package/src/hooks/useReorderSensors.ts +88 -0
- package/src/hooks/useResponsiveLayout.ts +36 -0
- package/src/hooks/useSnapCarousel.ts +284 -0
- package/src/hooks/useSwipeReveal.ts +107 -0
- package/src/hooks/useSwipeStack.ts +235 -0
- package/src/index.ts +124 -3
- package/src/overlay-shell.ts +159 -0
- package/src/stories/DesignSystemOverview.stories.tsx +933 -6
- package/src/stories/DeviceOnlyGate.stories.tsx +35 -0
- package/src/stories/DeviceStorageKeyGate.stories.tsx +57 -0
- package/src/stories/GripIcon.stories.tsx +29 -0
- package/src/stories/InteractionHooks.stories.tsx +483 -0
- package/src/stories/LayoutSystem.stories.tsx +639 -0
- package/src/stories/MenuEntries.stories.tsx +86 -0
- package/src/stories/MobilePatterns.stories.tsx +247 -2
- package/src/stories/NavList.stories.tsx +147 -0
- package/src/stories/NavTabs.stories.tsx +18 -0
- package/src/stories/OfflineGate.stories.tsx +42 -0
- package/src/stories/PageContainer.stories.tsx +82 -0
- package/src/stories/PageHeader.stories.tsx +65 -1
- package/src/stories/ResponsiveSurface.stories.tsx +47 -0
- package/src/stories/StepStrip.stories.tsx +76 -0
- package/src/stories/SwipableMobileCarousel.stories.tsx +362 -0
- package/src/stories/SwipeStack.stories.tsx +200 -0
- package/src/stories/Textarea.stories.tsx +12 -0
- package/src/stories/TokenGallery.stories.tsx +115 -0
- package/src/tokens/primitives.css +36 -0
- package/src/tokens/semantic.css +32 -0
- package/src/tokens/theme-presets.css +33 -0
- package/src/tokens/theme-presets.ts +72 -0
|
@@ -5,7 +5,15 @@ import { Button } from '../components/Button/Button';
|
|
|
5
5
|
const meta = {
|
|
6
6
|
title: 'Components/PageHeader',
|
|
7
7
|
component: PageHeader,
|
|
8
|
-
parameters: {
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'padded',
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
"A page's title section. Web: title + description on the left, action on the right. Mobile: an optional back button, a single-line title (description drops out), the same action slot, and an optional vertical-ellipsis menu trigger — a compact single row, generalized from Kanban's own hand-rolled MobileBoardHeader. The web/mobile fork is ResponsiveSurface; only one tree is ever mounted.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
9
17
|
} satisfies Meta<typeof PageHeader>;
|
|
10
18
|
|
|
11
19
|
export default meta;
|
|
@@ -29,3 +37,59 @@ export const WithAction: Story = {
|
|
|
29
37
|
action: <Button size="sm">Invite user</Button>,
|
|
30
38
|
},
|
|
31
39
|
};
|
|
40
|
+
|
|
41
|
+
/** A leading icon before the title text, on both breakpoints — e.g. a
|
|
42
|
+
* folder-detail page pairing `folder-open` with the folder's own name. */
|
|
43
|
+
export const WithIcon: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
title: 'Handbook',
|
|
46
|
+
icon: 'folder-open',
|
|
47
|
+
action: <Button size="sm">Share</Button>,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** For use under a shell/plugin that already renders its own `<h1>` — e.g.
|
|
52
|
+
* Console's per-page headers sitting below `<h1>Console</h1>`. Visually
|
|
53
|
+
* identical to the default story; only the rendered tag changes. */
|
|
54
|
+
export const NestedHeadingLevel: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
title: 'Users',
|
|
57
|
+
description: 'Manage who has access to this instance.',
|
|
58
|
+
headingLevel: 2,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** Below the mobile breakpoint: description drops out of the compact row
|
|
63
|
+
* (generalized from Kanban's own hand-rolled MobileBoardHeader, which has
|
|
64
|
+
* no subtitle handling either), action stays — same content, adapts itself
|
|
65
|
+
* if it needs to look different at this width. */
|
|
66
|
+
export const Mobile: Story = {
|
|
67
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
68
|
+
args: {
|
|
69
|
+
title: 'Users',
|
|
70
|
+
description: 'Manage who has access to this instance.',
|
|
71
|
+
action: <Button size="sm">Invite user</Button>,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** onBack shows a back button to the left of the title — mobile only, no
|
|
76
|
+
* web equivalent. */
|
|
77
|
+
export const MobileWithBack: Story = {
|
|
78
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
79
|
+
args: {
|
|
80
|
+
title: 'Sv Wallet',
|
|
81
|
+
onBack: () => undefined,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** onMenuClick shows a vertical-ellipsis trigger at the far right — mobile
|
|
86
|
+
* only, no web equivalent. Typically opens a drawer/menu; PageHeader has no
|
|
87
|
+
* opinion on what it contains. */
|
|
88
|
+
export const MobileWithMenu: Story = {
|
|
89
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
90
|
+
args: {
|
|
91
|
+
title: 'Sovereign Platform',
|
|
92
|
+
onBack: () => undefined,
|
|
93
|
+
onMenuClick: () => undefined,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { ResponsiveSurface } from '../components/ResponsiveSurface/ResponsiveSurface';
|
|
3
|
+
|
|
4
|
+
function demoTree(label: string) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
style={{
|
|
8
|
+
padding: 'var(--sv-space-6)',
|
|
9
|
+
textAlign: 'center',
|
|
10
|
+
fontFamily: 'var(--sv-font-family)',
|
|
11
|
+
fontSize: 'var(--sv-font-size-sm)',
|
|
12
|
+
color: 'var(--sv-color-text-primary)',
|
|
13
|
+
border: '1px dashed var(--sv-color-border)',
|
|
14
|
+
borderRadius: 'var(--sv-radius-md)',
|
|
15
|
+
}}
|
|
16
|
+
>
|
|
17
|
+
{label}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const meta = {
|
|
23
|
+
title: 'Components/ResponsiveSurface',
|
|
24
|
+
component: ResponsiveSurface,
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: 'padded',
|
|
27
|
+
docs: {
|
|
28
|
+
description: {
|
|
29
|
+
component:
|
|
30
|
+
'Renders an entirely different component tree below a breakpoint, not a CSS squeeze of the same one — only the active side is ever mounted. See also the useResponsiveLayout hook for non-JSX values.',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
web: demoTree('Web tree — e.g. a three-column layout'),
|
|
36
|
+
mobile: demoTree('Mobile tree — an entirely different component'),
|
|
37
|
+
},
|
|
38
|
+
} satisfies Meta<typeof ResponsiveSurface>;
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
type Story = StoryObj<typeof meta>;
|
|
42
|
+
|
|
43
|
+
export const Default: Story = {};
|
|
44
|
+
|
|
45
|
+
export const MobileViewport: Story = {
|
|
46
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
47
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
import { StepStrip, type StepStripItem } from '../components/StepStrip/StepStrip';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof StepStrip> = {
|
|
6
|
+
title: 'Components/StepStrip',
|
|
7
|
+
component: StepStrip,
|
|
8
|
+
parameters: { layout: 'padded' },
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof StepStrip>;
|
|
14
|
+
|
|
15
|
+
interface Stop extends StepStripItem {
|
|
16
|
+
label: string;
|
|
17
|
+
sublabel: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const STOPS: Stop[] = [
|
|
21
|
+
{ id: 'lisbon', label: 'Lisbon', sublabel: 'Aug 26 – 28 · 2 days' },
|
|
22
|
+
{ id: 'porto', label: 'Porto', sublabel: 'Aug 28 – 30 · 2 days' },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const chipStyle = (isActive: boolean) => ({
|
|
26
|
+
boxSizing: 'border-box' as const,
|
|
27
|
+
minWidth: '160px',
|
|
28
|
+
padding: 'var(--sv-space-3) var(--sv-space-4)',
|
|
29
|
+
borderRadius: 'var(--sv-radius-lg)',
|
|
30
|
+
border: `1px solid ${isActive ? 'var(--sv-color-text-primary)' : 'var(--sv-color-border)'}`,
|
|
31
|
+
background: isActive ? 'var(--sv-color-text-primary)' : 'var(--sv-color-surface-raised)',
|
|
32
|
+
color: isActive ? 'var(--sv-color-surface)' : 'var(--sv-color-text-primary)',
|
|
33
|
+
cursor: 'pointer',
|
|
34
|
+
textAlign: 'left' as const,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function StopStripDemo() {
|
|
38
|
+
const [activeId, setActiveId] = useState<string>('lisbon');
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<StepStrip
|
|
42
|
+
items={STOPS}
|
|
43
|
+
activeId={activeId}
|
|
44
|
+
aria-label="Trip stops"
|
|
45
|
+
onAdd={() => alert('Add a stop')}
|
|
46
|
+
addLabel="Add a stop"
|
|
47
|
+
renderItem={(stop, { isActive }) => (
|
|
48
|
+
<button type="button" style={chipStyle(isActive)} onClick={() => setActiveId(stop.id)}>
|
|
49
|
+
<div style={{ fontWeight: 600, fontSize: 'var(--sv-font-size-sm)' }}>{stop.label}</div>
|
|
50
|
+
<div style={{ fontSize: 'var(--sv-font-size-xs)', opacity: 0.8 }}>{stop.sublabel}</div>
|
|
51
|
+
</button>
|
|
52
|
+
)}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const Default: Story = {
|
|
58
|
+
render: () => <StopStripDemo />,
|
|
59
|
+
name: 'Stop strip (click to select, trailing add chip)',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const NoAddAffordance: Story = {
|
|
63
|
+
render: () => (
|
|
64
|
+
<StepStrip
|
|
65
|
+
items={STOPS}
|
|
66
|
+
activeId="porto"
|
|
67
|
+
aria-label="Trip stops"
|
|
68
|
+
renderItem={(stop, { isActive }) => (
|
|
69
|
+
<div style={chipStyle(isActive)}>
|
|
70
|
+
<div style={{ fontWeight: 600, fontSize: 'var(--sv-font-size-sm)' }}>{stop.label}</div>
|
|
71
|
+
<div style={{ fontSize: 'var(--sv-font-size-xs)', opacity: 0.8 }}>{stop.sublabel}</div>
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
/>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
import { SwipableMobileCarousel } from '../components/SwipableMobileCarousel/SwipableMobileCarousel';
|
|
4
|
+
import { SwipableMobileCarouselSlide } from '../components/SwipableMobileCarousel/SwipableMobileCarouselSlide';
|
|
5
|
+
import { SwipableMobileCarouselSlideHeader } from '../components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader';
|
|
6
|
+
import { SwipableMobileCarouselSlideBody } from '../components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody';
|
|
7
|
+
import { SwipableMobileCarouselSlideFooter } from '../components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter';
|
|
8
|
+
import { SwipableMobileCarouselDots } from '../components/SwipableMobileCarouselDots/SwipableMobileCarouselDots';
|
|
9
|
+
|
|
10
|
+
const SLIDES = [
|
|
11
|
+
{ key: 'lists', label: 'Lists' },
|
|
12
|
+
{ key: 'groceries', label: 'Groceries' },
|
|
13
|
+
{ key: 'errands', label: 'Errands' },
|
|
14
|
+
{ key: 'work', label: 'Work' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function slideBodyStyle(): React.CSSProperties {
|
|
18
|
+
return {
|
|
19
|
+
display: 'flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
justifyContent: 'center',
|
|
22
|
+
height: '100%',
|
|
23
|
+
fontFamily: 'var(--sv-font-family)',
|
|
24
|
+
color: 'var(--sv-color-text-primary)',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function headerStyle(): React.CSSProperties {
|
|
29
|
+
return {
|
|
30
|
+
padding: 'var(--sv-space-4)',
|
|
31
|
+
fontFamily: 'var(--sv-font-family)',
|
|
32
|
+
fontWeight: 'var(--sv-font-weight-semibold)',
|
|
33
|
+
color: 'var(--sv-color-text-primary)',
|
|
34
|
+
borderBottom: '1px solid var(--sv-color-border)',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function CarouselFrame({ children }: { children: React.ReactNode }) {
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
height: 480,
|
|
43
|
+
maxWidth: 375,
|
|
44
|
+
margin: '0 auto',
|
|
45
|
+
border: '1px solid var(--sv-color-border)',
|
|
46
|
+
borderRadius: 'var(--sv-radius-md)',
|
|
47
|
+
overflow: 'hidden',
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function DefaultDemo() {
|
|
56
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
57
|
+
return (
|
|
58
|
+
<CarouselFrame>
|
|
59
|
+
<SwipableMobileCarousel
|
|
60
|
+
activeIndex={activeIndex}
|
|
61
|
+
onSettle={setActiveIndex}
|
|
62
|
+
aria-label="Task lists"
|
|
63
|
+
>
|
|
64
|
+
{SLIDES.map((slide) => (
|
|
65
|
+
<SwipableMobileCarouselSlide key={slide.key} slideKey={slide.key} label={slide.label}>
|
|
66
|
+
<SwipableMobileCarouselSlideHeader>
|
|
67
|
+
<div style={headerStyle()}>{slide.label}</div>
|
|
68
|
+
</SwipableMobileCarouselSlideHeader>
|
|
69
|
+
<SwipableMobileCarouselSlideBody>
|
|
70
|
+
<div style={slideBodyStyle()}>{slide.label} content</div>
|
|
71
|
+
</SwipableMobileCarouselSlideBody>
|
|
72
|
+
</SwipableMobileCarouselSlide>
|
|
73
|
+
))}
|
|
74
|
+
</SwipableMobileCarousel>
|
|
75
|
+
</CarouselFrame>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function LazyLoadingBodyDemo() {
|
|
80
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
81
|
+
const [loadedKeys, setLoadedKeys] = useState<Set<string>>(new Set(['lists']));
|
|
82
|
+
|
|
83
|
+
function simulateLoad(key: string) {
|
|
84
|
+
setTimeout(() => setLoadedKeys((s) => new Set(s).add(key)), 1200);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<CarouselFrame>
|
|
89
|
+
<SwipableMobileCarousel
|
|
90
|
+
activeIndex={activeIndex}
|
|
91
|
+
onSettle={(i) => {
|
|
92
|
+
setActiveIndex(i);
|
|
93
|
+
const key = SLIDES[i]?.key;
|
|
94
|
+
if (key && !loadedKeys.has(key)) simulateLoad(key);
|
|
95
|
+
}}
|
|
96
|
+
aria-label="Task lists (simulated fetch)"
|
|
97
|
+
>
|
|
98
|
+
{SLIDES.map((slide) => (
|
|
99
|
+
<SwipableMobileCarouselSlide key={slide.key} slideKey={slide.key} label={slide.label}>
|
|
100
|
+
{/* The title renders immediately from already-known metadata —
|
|
101
|
+
only the Body below waits on its own simulated 1.2s fetch. */}
|
|
102
|
+
<SwipableMobileCarouselSlideHeader>
|
|
103
|
+
<div style={headerStyle()}>{slide.label}</div>
|
|
104
|
+
</SwipableMobileCarouselSlideHeader>
|
|
105
|
+
<SwipableMobileCarouselSlideBody loading={!loadedKeys.has(slide.key)}>
|
|
106
|
+
<div style={slideBodyStyle()}>{slide.label} content (loaded)</div>
|
|
107
|
+
</SwipableMobileCarouselSlideBody>
|
|
108
|
+
</SwipableMobileCarouselSlide>
|
|
109
|
+
))}
|
|
110
|
+
</SwipableMobileCarousel>
|
|
111
|
+
</CarouselFrame>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function CustomIndicatorDemo() {
|
|
116
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
117
|
+
return (
|
|
118
|
+
<CarouselFrame>
|
|
119
|
+
<SwipableMobileCarousel
|
|
120
|
+
activeIndex={activeIndex}
|
|
121
|
+
onSettle={setActiveIndex}
|
|
122
|
+
aria-label="Task lists"
|
|
123
|
+
renderIndicator={({ count, activeIndex: i, onJump }) => (
|
|
124
|
+
<div
|
|
125
|
+
style={{
|
|
126
|
+
position: 'absolute',
|
|
127
|
+
top: 8,
|
|
128
|
+
right: 8,
|
|
129
|
+
fontFamily: 'var(--sv-font-family)',
|
|
130
|
+
fontSize: 'var(--sv-font-size-sm)',
|
|
131
|
+
color: 'var(--sv-color-text-primary)',
|
|
132
|
+
background: 'var(--sv-color-surface-raised)',
|
|
133
|
+
borderRadius: 'var(--sv-radius-md)',
|
|
134
|
+
padding: 'var(--sv-space-1) var(--sv-space-2)',
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
<button type="button" onClick={() => onJump(Math.max(0, i - 1))}>
|
|
138
|
+
‹
|
|
139
|
+
</button>{' '}
|
|
140
|
+
{i + 1} / {count}{' '}
|
|
141
|
+
<button type="button" onClick={() => onJump(Math.min(count - 1, i + 1))}>
|
|
142
|
+
›
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
>
|
|
147
|
+
{SLIDES.map((slide) => (
|
|
148
|
+
<SwipableMobileCarouselSlide key={slide.key} slideKey={slide.key} label={slide.label}>
|
|
149
|
+
<SwipableMobileCarouselSlideHeader>
|
|
150
|
+
<div style={headerStyle()}>{slide.label}</div>
|
|
151
|
+
</SwipableMobileCarouselSlideHeader>
|
|
152
|
+
<SwipableMobileCarouselSlideBody>
|
|
153
|
+
<div style={slideBodyStyle()}>{slide.label} content</div>
|
|
154
|
+
</SwipableMobileCarouselSlideBody>
|
|
155
|
+
</SwipableMobileCarouselSlide>
|
|
156
|
+
))}
|
|
157
|
+
</SwipableMobileCarousel>
|
|
158
|
+
</CarouselFrame>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function NoIndicatorDemo() {
|
|
163
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
164
|
+
return (
|
|
165
|
+
<CarouselFrame>
|
|
166
|
+
<SwipableMobileCarousel
|
|
167
|
+
activeIndex={activeIndex}
|
|
168
|
+
onSettle={setActiveIndex}
|
|
169
|
+
aria-label="Task lists"
|
|
170
|
+
renderIndicator={null}
|
|
171
|
+
>
|
|
172
|
+
{SLIDES.map((slide) => (
|
|
173
|
+
<SwipableMobileCarouselSlide key={slide.key} slideKey={slide.key} label={slide.label}>
|
|
174
|
+
<SwipableMobileCarouselSlideHeader>
|
|
175
|
+
<div style={headerStyle()}>{slide.label}</div>
|
|
176
|
+
</SwipableMobileCarouselSlideHeader>
|
|
177
|
+
<SwipableMobileCarouselSlideBody>
|
|
178
|
+
<div style={slideBodyStyle()}>{slide.label} content</div>
|
|
179
|
+
</SwipableMobileCarouselSlideBody>
|
|
180
|
+
</SwipableMobileCarouselSlide>
|
|
181
|
+
))}
|
|
182
|
+
</SwipableMobileCarousel>
|
|
183
|
+
</CarouselFrame>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function FooterDemo() {
|
|
188
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
189
|
+
return (
|
|
190
|
+
<CarouselFrame>
|
|
191
|
+
<SwipableMobileCarousel
|
|
192
|
+
activeIndex={activeIndex}
|
|
193
|
+
onSettle={setActiveIndex}
|
|
194
|
+
aria-label="Task lists"
|
|
195
|
+
>
|
|
196
|
+
{SLIDES.map((slide) => (
|
|
197
|
+
<SwipableMobileCarouselSlide key={slide.key} slideKey={slide.key} label={slide.label}>
|
|
198
|
+
<SwipableMobileCarouselSlideHeader>
|
|
199
|
+
<div style={headerStyle()}>{slide.label}</div>
|
|
200
|
+
</SwipableMobileCarouselSlideHeader>
|
|
201
|
+
<SwipableMobileCarouselSlideBody>
|
|
202
|
+
<div style={slideBodyStyle()}>{slide.label} content</div>
|
|
203
|
+
</SwipableMobileCarouselSlideBody>
|
|
204
|
+
<SwipableMobileCarouselSlideFooter>
|
|
205
|
+
<div
|
|
206
|
+
style={{
|
|
207
|
+
padding: 'var(--sv-space-3) var(--sv-space-4)',
|
|
208
|
+
borderTop: '1px solid var(--sv-color-border)',
|
|
209
|
+
fontFamily: 'var(--sv-font-family)',
|
|
210
|
+
fontSize: 'var(--sv-font-size-sm)',
|
|
211
|
+
color: 'var(--sv-color-text-muted)',
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
+ Add to {slide.label}
|
|
215
|
+
</div>
|
|
216
|
+
</SwipableMobileCarouselSlideFooter>
|
|
217
|
+
</SwipableMobileCarouselSlide>
|
|
218
|
+
))}
|
|
219
|
+
</SwipableMobileCarousel>
|
|
220
|
+
</CarouselFrame>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function DotsStandaloneDemo() {
|
|
225
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
226
|
+
return (
|
|
227
|
+
<SwipableMobileCarouselDots
|
|
228
|
+
count={4}
|
|
229
|
+
activeIndex={activeIndex}
|
|
230
|
+
onJump={setActiveIndex}
|
|
231
|
+
labels={['Lists', 'Groceries', 'Errands', 'Work']}
|
|
232
|
+
aria-label="Task lists"
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Matches the real scenario `density="compact"` was added for: a many-list
|
|
238
|
+
// mobile task manager whose default-spacing dot row reads as long/cramped in
|
|
239
|
+
// a 375px viewport — see docs/design-system.md's carousel section.
|
|
240
|
+
const MANY_LABELS = [
|
|
241
|
+
'Lists',
|
|
242
|
+
'Starred',
|
|
243
|
+
'List 1',
|
|
244
|
+
'Groceries',
|
|
245
|
+
'Work',
|
|
246
|
+
'List 2',
|
|
247
|
+
'List 3',
|
|
248
|
+
'List 4',
|
|
249
|
+
'List 5',
|
|
250
|
+
'List 6',
|
|
251
|
+
'List 7',
|
|
252
|
+
'List 8',
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
function DotsManyDemo({ density }: { density?: 'default' | 'compact' }) {
|
|
256
|
+
const [activeIndex, setActiveIndex] = useState(2);
|
|
257
|
+
return (
|
|
258
|
+
<div style={{ maxWidth: 375, margin: '0 auto' }}>
|
|
259
|
+
<SwipableMobileCarouselDots
|
|
260
|
+
count={MANY_LABELS.length}
|
|
261
|
+
activeIndex={activeIndex}
|
|
262
|
+
onJump={setActiveIndex}
|
|
263
|
+
labels={MANY_LABELS}
|
|
264
|
+
aria-label="Task lists"
|
|
265
|
+
density={density}
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const meta = {
|
|
272
|
+
title: 'Components/SwipableMobileCarousel',
|
|
273
|
+
component: SwipableMobileCarousel,
|
|
274
|
+
parameters: {
|
|
275
|
+
layout: 'padded',
|
|
276
|
+
docs: {
|
|
277
|
+
description: {
|
|
278
|
+
component:
|
|
279
|
+
"A compound component for swiping between full-width slides (each an independent route/view on mobile), wrapping useSnapCarousel. Owns rendering and mount-window mechanics only — it has no opinion on where slide data lives. Do NOT aggregate cross-slide data or mount a detail overlay (Sheet, Dialog) inside a Slide's children; see docs/design-system.md's carousel section.",
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
// Every story below supplies its own render(), which is stateful (activeIndex
|
|
284
|
+
// lives in useState) — these args only satisfy the required-prop typing.
|
|
285
|
+
args: {
|
|
286
|
+
activeIndex: 0,
|
|
287
|
+
onSettle: () => {},
|
|
288
|
+
'aria-label': 'Task lists',
|
|
289
|
+
children: null,
|
|
290
|
+
},
|
|
291
|
+
} satisfies Meta<typeof SwipableMobileCarousel>;
|
|
292
|
+
|
|
293
|
+
export default meta;
|
|
294
|
+
type Story = StoryObj<typeof meta>;
|
|
295
|
+
|
|
296
|
+
export const Default: Story = { render: () => <DefaultDemo /> };
|
|
297
|
+
|
|
298
|
+
export const LazyLoadingBody: Story = {
|
|
299
|
+
render: () => <LazyLoadingBodyDemo />,
|
|
300
|
+
parameters: {
|
|
301
|
+
docs: {
|
|
302
|
+
description: {
|
|
303
|
+
story:
|
|
304
|
+
'Swipe to a new slide — its title renders immediately from already-known metadata, while only the Body region shows a brief loading placeholder for its simulated 1.2s fetch. This is the fix for the "whole slide blanks out, title included, until its own fetch resolves" bug.',
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export const CustomIndicator: Story = { render: () => <CustomIndicatorDemo /> };
|
|
311
|
+
|
|
312
|
+
export const NoIndicator: Story = { render: () => <NoIndicatorDemo /> };
|
|
313
|
+
|
|
314
|
+
export const WithFooter: Story = { render: () => <FooterDemo /> };
|
|
315
|
+
|
|
316
|
+
export const MobileViewport: Story = {
|
|
317
|
+
render: () => <DefaultDemo />,
|
|
318
|
+
parameters: { viewport: { defaultViewport: 'mobile1' } },
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
// SwipableMobileCarouselDots — standalone, also this carousel's default
|
|
323
|
+
// indicator. Grouped in this file rather than its own (Table's sub-parts
|
|
324
|
+
// share one story file too), though it has its own component subfolder and
|
|
325
|
+
// barrel export for independent reuse.
|
|
326
|
+
// ---------------------------------------------------------------------------
|
|
327
|
+
|
|
328
|
+
export const DotsStandalone: Story = {
|
|
329
|
+
render: () => <DotsStandaloneDemo />,
|
|
330
|
+
parameters: {
|
|
331
|
+
docs: {
|
|
332
|
+
description: {
|
|
333
|
+
story:
|
|
334
|
+
'SwipableMobileCarouselDots used on its own, outside a carousel — a real role="tablist"/role="tab" component (tappable, labeled, focusable), unlike the aria-hidden decorative dots both sovereign-tasks and sovereign-shopper currently hand-roll.',
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
export const DotsManyDefault: Story = {
|
|
341
|
+
render: () => <DotsManyDemo />,
|
|
342
|
+
parameters: {
|
|
343
|
+
docs: {
|
|
344
|
+
description: {
|
|
345
|
+
story:
|
|
346
|
+
'Default density with 12 slides in a 375px viewport — the row reads as long/cramped once an instance has more than a handful of lists. Compare to DotsManyCompact.',
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
export const DotsManyCompact: Story = {
|
|
353
|
+
render: () => <DotsManyDemo density="compact" />,
|
|
354
|
+
parameters: {
|
|
355
|
+
docs: {
|
|
356
|
+
description: {
|
|
357
|
+
story:
|
|
358
|
+
'density="compact" halves the gap between dots and shrinks each dot\'s own hit target from 20px to 16px — the visible 6px dot itself is unchanged; only its surrounding tap-target box shrinks. Opt-in: every existing consumer\'s spacing is unchanged unless it passes this prop.',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
};
|