@ponti-studios/ui 2.0.1 → 3.0.0
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/README.md +36 -3
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +3 -0
- package/dist/components/data-display/accordion.d.ts +10 -0
- package/dist/components/data-display/accordion.js +53 -0
- package/{src/components/data-display/index.ts → dist/components/data-display/index.d.ts} +1 -10
- package/dist/components/data-display/index.js +8 -0
- package/dist/components/data-display/metric-card.d.ts +9 -0
- package/dist/components/data-display/metric-card.js +25 -0
- package/dist/components/data-display/sort-controls.d.ts +13 -0
- package/dist/components/data-display/sort-controls.js +57 -0
- package/dist/components/data-display/sort-row.d.ts +10 -0
- package/dist/components/data-display/sort-row.js +52 -0
- package/dist/components/data-display/table.d.ts +10 -0
- package/dist/components/data-display/table.js +57 -0
- package/dist/components/feedback/alert.d.ts +9 -0
- package/dist/components/feedback/alert.js +38 -0
- package/dist/components/feedback/empty-state.d.ts +18 -0
- package/dist/components/feedback/empty-state.js +36 -0
- package/{src/components/feedback/index.ts → dist/components/feedback/index.d.ts} +2 -0
- package/dist/components/feedback/index.js +7 -0
- package/dist/components/feedback/progress.d.ts +6 -0
- package/dist/components/feedback/progress.js +25 -0
- package/dist/components/feedback/skeleton.d.ts +2 -0
- package/dist/components/feedback/skeleton.js +11 -0
- package/dist/components/feedback/spinner.d.ts +14 -0
- package/dist/components/feedback/spinner.js +27 -0
- package/dist/components/feedback/update-guard.d.ts +13 -0
- package/dist/components/feedback/update-guard.js +38 -0
- package/dist/components/filters/active-filters-bar.d.ts +14 -0
- package/dist/components/filters/active-filters-bar.js +44 -0
- package/dist/components/filters/filter-chip.d.ts +11 -0
- package/dist/components/filters/filter-chip.js +33 -0
- package/dist/components/filters/filter-select.d.ts +17 -0
- package/dist/components/filters/filter-select.js +46 -0
- package/dist/components/filters/index.js +4 -0
- package/dist/components/forms/checkbox.d.ts +4 -0
- package/dist/components/forms/checkbox.js +24 -0
- package/dist/components/forms/date-month-select.d.ts +11 -0
- package/dist/components/forms/date-month-select.js +47 -0
- package/dist/components/forms/date-picker.d.ts +60 -0
- package/dist/components/forms/date-picker.js +193 -0
- package/dist/components/forms/date-utils.d.ts +14 -0
- package/dist/components/forms/date-utils.js +18 -0
- package/dist/components/forms/drop-zone.d.ts +42 -0
- package/dist/components/forms/drop-zone.js +184 -0
- package/{src/components/forms/index.ts → dist/components/forms/index.d.ts} +3 -9
- package/dist/components/forms/index.js +17 -0
- package/dist/components/forms/input.d.ts +3 -0
- package/dist/components/forms/input.js +15 -0
- package/dist/components/forms/label.d.ts +3 -0
- package/dist/components/forms/label.js +14 -0
- package/dist/components/forms/passkey-management.d.ts +14 -0
- package/dist/components/forms/passkey-management.js +132 -0
- package/dist/components/forms/radio-group.d.ts +6 -0
- package/dist/components/forms/radio-group.js +28 -0
- package/dist/components/forms/select.d.ts +18 -0
- package/dist/components/forms/select.js +103 -0
- package/dist/components/forms/slider.d.ts +9 -0
- package/dist/components/forms/slider.js +25 -0
- package/dist/components/forms/stepper.d.ts +15 -0
- package/dist/components/forms/stepper.js +41 -0
- package/dist/components/forms/switch.d.ts +6 -0
- package/dist/components/forms/switch.js +21 -0
- package/dist/components/forms/text-field.d.ts +15 -0
- package/dist/components/forms/text-field.js +46 -0
- package/dist/components/forms/text-field.types.d.ts +8 -0
- package/dist/components/forms/textarea.d.ts +3 -0
- package/dist/components/forms/textarea.js +14 -0
- package/dist/components/layout/index.js +5 -0
- package/dist/components/layout/particle-background.d.ts +19 -0
- package/dist/components/layout/particle-background.js +171 -0
- package/dist/components/layout/scroll-area.d.ts +9 -0
- package/dist/components/layout/scroll-area.js +35 -0
- package/dist/components/layout/section-intro.d.ts +12 -0
- package/dist/components/layout/section-intro.js +28 -0
- package/dist/components/layout/surface-panel.d.ts +7 -0
- package/dist/components/layout/surface-panel.js +11 -0
- package/dist/components/navigation/app-navigation.d.ts +67 -0
- package/dist/components/navigation/app-navigation.js +106 -0
- package/{src/components/navigation/index.ts → dist/components/navigation/index.d.ts} +1 -7
- package/dist/components/navigation/index.js +4 -0
- package/dist/components/navigation/pagination-controls.d.ts +7 -0
- package/dist/components/navigation/pagination-controls.js +50 -0
- package/dist/components/navigation/tabs.d.ts +7 -0
- package/dist/components/navigation/tabs.js +35 -0
- package/dist/components/overlays/bottom-sheet.d.ts +20 -0
- package/dist/components/overlays/bottom-sheet.js +101 -0
- package/dist/components/overlays/command.d.ts +29 -0
- package/dist/components/overlays/command.js +123 -0
- package/dist/components/overlays/dialog.d.ts +30 -0
- package/dist/components/overlays/dialog.js +105 -0
- package/dist/components/overlays/dropdown-menu.d.ts +29 -0
- package/dist/components/overlays/dropdown-menu.js +128 -0
- package/dist/components/overlays/index.d.ts +7 -0
- package/dist/components/overlays/index.js +8 -0
- package/dist/components/overlays/popover.d.ts +14 -0
- package/dist/components/overlays/popover.js +56 -0
- package/dist/components/overlays/sheet.d.ts +27 -0
- package/dist/components/overlays/sheet.js +81 -0
- package/dist/components/overlays/tooltip.d.ts +10 -0
- package/dist/components/overlays/tooltip.js +23 -0
- package/dist/components/primitives/avatar.d.ts +14 -0
- package/dist/components/primitives/avatar.js +72 -0
- package/dist/components/primitives/badge.d.ts +7 -0
- package/dist/components/primitives/badge.js +27 -0
- package/dist/components/primitives/button.d.ts +13 -0
- package/dist/components/primitives/button.js +113 -0
- package/{src/components/primitives/button.types.ts → dist/components/primitives/button.types.d.ts} +4 -6
- package/dist/components/primitives/card.d.ts +9 -0
- package/dist/components/primitives/card.js +56 -0
- package/{src/components/primitives/index.ts → dist/components/primitives/index.d.ts} +1 -9
- package/dist/components/primitives/index.js +7 -0
- package/dist/components/primitives/segmented-control.d.ts +20 -0
- package/dist/components/primitives/segmented-control.js +27 -0
- package/dist/components/primitives/separator.d.ts +4 -0
- package/dist/components/primitives/separator.js +16 -0
- package/dist/constants/chart-colors.d.ts +33 -0
- package/dist/constants/chart-colors.js +31 -0
- package/dist/hooks/index.js +9 -0
- package/{src/hooks/sort.types.ts → dist/hooks/sort.types.d.ts} +2 -4
- package/dist/hooks/use-api-client.d.ts +30 -0
- package/dist/hooks/use-api-client.js +106 -0
- package/dist/hooks/use-debounced-value.d.ts +1 -0
- package/dist/hooks/use-debounced-value.js +12 -0
- package/dist/hooks/use-derived-filter-state.d.ts +20 -0
- package/dist/hooks/use-derived-filter-state.js +39 -0
- package/dist/hooks/use-filter-state.d.ts +12 -0
- package/dist/hooks/use-filter-state.js +37 -0
- package/dist/hooks/use-media-query.d.ts +6 -0
- package/dist/hooks/use-media-query.js +27 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +14 -0
- package/dist/hooks/use-sort.d.ts +11 -0
- package/dist/hooks/use-sort.js +14 -0
- package/{src/index.ts → dist/index.d.ts} +4 -32
- package/dist/index.js +15 -0
- package/dist/integrations/service-worker.d.ts +2 -0
- package/dist/integrations/service-worker.js +2 -0
- package/dist/lib/auth.d.ts +2 -0
- package/dist/lib/auth.js +7 -0
- package/dist/lib/clipboard.d.ts +1 -0
- package/dist/lib/clipboard.js +10 -0
- package/dist/lib/index.js +4 -0
- package/{src/lib/slot.tsx → dist/lib/slot.d.ts} +2 -15
- package/dist/lib/slot.js +14 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +8 -0
- package/dist/native/components.d.ts +41 -0
- package/dist/native/components.js +135 -0
- package/dist/native/index.js +3 -0
- package/dist/native/theme.d.ts +19 -0
- package/dist/native/theme.js +58 -0
- package/dist/styles/tokens/css-vars.d.ts +7 -0
- package/dist/styles/tokens/css-vars.js +5 -0
- package/dist/styles/tokens/generated/dark.colors.generated.d.ts +40 -0
- package/dist/styles/tokens/generated/dark.colors.generated.js +39 -0
- package/dist/styles/tokens/generated/foundations.generated.d.ts +323 -0
- package/dist/styles/tokens/generated/foundations.generated.js +453 -0
- package/dist/styles/tokens/generated/light.colors.generated.d.ts +40 -0
- package/dist/styles/tokens/generated/light.colors.generated.js +39 -0
- package/dist/styles/tokens/index.d.ts +317 -0
- package/dist/styles/tokens/index.js +14 -0
- package/dist/styles.css +1 -1
- package/dist/translations/en.d.ts +34 -0
- package/dist/translations/index.d.ts +39 -0
- package/dist/translations/ui-provider.d.ts +9 -0
- package/dist/translations/ui-provider.js +16 -0
- package/dist/types/upload.d.ts +36 -0
- package/package.json +50 -33
- package/src/components/data-display/accordion.stories.tsx +0 -57
- package/src/components/data-display/accordion.tsx +0 -86
- package/src/components/data-display/metric-card.stories.tsx +0 -48
- package/src/components/data-display/metric-card.tsx +0 -20
- package/src/components/data-display/sort-controls.stories.tsx +0 -45
- package/src/components/data-display/sort-controls.tsx +0 -96
- package/src/components/data-display/sort-row.tsx +0 -88
- package/src/components/data-display/table.stories.tsx +0 -75
- package/src/components/data-display/table.tsx +0 -80
- package/src/components/feedback/alert.stories.tsx +0 -51
- package/src/components/feedback/alert.tsx +0 -64
- package/src/components/feedback/empty-state.tsx +0 -76
- package/src/components/feedback/progress.stories.tsx +0 -54
- package/src/components/feedback/progress.tsx +0 -41
- package/src/components/feedback/skeleton.stories.tsx +0 -36
- package/src/components/feedback/skeleton.tsx +0 -7
- package/src/components/feedback/spinner.stories.tsx +0 -52
- package/src/components/feedback/spinner.tsx +0 -47
- package/src/components/feedback/update-guard.stories.tsx +0 -28
- package/src/components/feedback/update-guard.tsx +0 -57
- package/src/components/filters/active-filters-bar.stories.tsx +0 -114
- package/src/components/filters/active-filters-bar.tsx +0 -61
- package/src/components/filters/filter-chip.tsx +0 -57
- package/src/components/filters/filter-select.stories.tsx +0 -71
- package/src/components/filters/filter-select.tsx +0 -68
- package/src/components/forms/checkbox.stories.tsx +0 -35
- package/src/components/forms/checkbox.tsx +0 -38
- package/src/components/forms/date-month-select.stories.tsx +0 -26
- package/src/components/forms/date-month-select.tsx +0 -79
- package/src/components/forms/date-picker.stories.tsx +0 -188
- package/src/components/forms/date-picker.tsx +0 -303
- package/src/components/forms/date-utils.ts +0 -37
- package/src/components/forms/drop-zone.stories.tsx +0 -140
- package/src/components/forms/drop-zone.tsx +0 -298
- package/src/components/forms/input.stories.tsx +0 -47
- package/src/components/forms/input.tsx +0 -24
- package/src/components/forms/label.stories.tsx +0 -16
- package/src/components/forms/label.tsx +0 -25
- package/src/components/forms/passkey-management.stories.tsx +0 -85
- package/src/components/forms/passkey-management.tsx +0 -168
- package/src/components/forms/radio-group.stories.tsx +0 -46
- package/src/components/forms/radio-group.tsx +0 -44
- package/src/components/forms/select.stories.tsx +0 -207
- package/src/components/forms/select.tsx +0 -182
- package/src/components/forms/slider.stories.tsx +0 -70
- package/src/components/forms/slider.tsx +0 -50
- package/src/components/forms/stepper.stories.tsx +0 -111
- package/src/components/forms/stepper.tsx +0 -66
- package/src/components/forms/switch.stories.tsx +0 -144
- package/src/components/forms/switch.tsx +0 -39
- package/src/components/forms/text-field.stories.tsx +0 -87
- package/src/components/forms/text-field.tsx +0 -75
- package/src/components/forms/text-field.types.ts +0 -9
- package/src/components/forms/textarea.stories.tsx +0 -150
- package/src/components/forms/textarea.tsx +0 -22
- package/src/components/layout/particle-background.stories.tsx +0 -38
- package/src/components/layout/particle-background.tsx +0 -378
- package/src/components/layout/scroll-area.stories.tsx +0 -91
- package/src/components/layout/scroll-area.tsx +0 -79
- package/src/components/layout/section-intro.stories.tsx +0 -29
- package/src/components/layout/section-intro.tsx +0 -31
- package/src/components/layout/surface-panel.stories.tsx +0 -32
- package/src/components/layout/surface-panel.tsx +0 -23
- package/src/components/navigation/app-navigation.stories.tsx +0 -217
- package/src/components/navigation/app-navigation.tsx +0 -234
- package/src/components/navigation/pagination-controls.stories.tsx +0 -41
- package/src/components/navigation/pagination-controls.tsx +0 -46
- package/src/components/navigation/tabs.stories.tsx +0 -48
- package/src/components/navigation/tabs.tsx +0 -52
- package/src/components/overlays/bottom-sheet.stories.tsx +0 -52
- package/src/components/overlays/bottom-sheet.tsx +0 -179
- package/src/components/overlays/command.stories.tsx +0 -65
- package/src/components/overlays/command.tsx +0 -227
- package/src/components/overlays/dialog.stories.tsx +0 -148
- package/src/components/overlays/dialog.tsx +0 -203
- package/src/components/overlays/dropdown-menu.stories.tsx +0 -74
- package/src/components/overlays/dropdown-menu.tsx +0 -236
- package/src/components/overlays/index.ts +0 -56
- package/src/components/overlays/popover.stories.tsx +0 -51
- package/src/components/overlays/popover.tsx +0 -78
- package/src/components/overlays/sheet.stories.tsx +0 -68
- package/src/components/overlays/sheet.tsx +0 -155
- package/src/components/overlays/tooltip.stories.tsx +0 -29
- package/src/components/overlays/tooltip.tsx +0 -41
- package/src/components/primitives/avatar-placeholder.svg +0 -13
- package/src/components/primitives/avatar.stories.tsx +0 -72
- package/src/components/primitives/avatar.tsx +0 -136
- package/src/components/primitives/badge.stories.tsx +0 -43
- package/src/components/primitives/badge.tsx +0 -43
- package/src/components/primitives/button.stories.tsx +0 -113
- package/src/components/primitives/button.tsx +0 -131
- package/src/components/primitives/card.stories.tsx +0 -59
- package/src/components/primitives/card.tsx +0 -66
- package/src/components/primitives/segmented-control.stories.tsx +0 -54
- package/src/components/primitives/segmented-control.tsx +0 -73
- package/src/components/primitives/separator.stories.tsx +0 -34
- package/src/components/primitives/separator.tsx +0 -27
- package/src/constants/chart-colors.ts +0 -39
- package/src/env.d.ts +0 -9
- package/src/hooks/use-api-client.ts +0 -122
- package/src/hooks/use-debounced-value.ts +0 -12
- package/src/hooks/use-derived-filter-state.ts +0 -70
- package/src/hooks/use-filter-state.ts +0 -66
- package/src/hooks/use-media-query.ts +0 -69
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-sort.ts +0 -20
- package/src/lib/auth.ts +0 -5
- package/src/lib/clipboard.ts +0 -8
- package/src/lib/utils.ts +0 -6
- package/src/native/components.tsx +0 -198
- package/src/native/theme.tsx +0 -69
- package/src/storybook/controls.ts +0 -117
- package/src/storybook/options.ts +0 -52
- package/src/styles/build.ts +0 -1
- package/src/styles/index.css +0 -423
- package/src/styles/nokia.css +0 -36
- package/src/styles/package.css +0 -3
- package/src/styles/tokens/chart-colors.stories.tsx +0 -189
- package/src/styles/tokens/color-systems.stories.tsx +0 -190
- package/src/styles/tokens/css-vars.ts +0 -15
- package/src/styles/tokens/generated/dark-class.css +0 -39
- package/src/styles/tokens/generated/dark.colors.generated.ts +0 -39
- package/src/styles/tokens/generated/dark.css +0 -39
- package/src/styles/tokens/generated/foundations.css +0 -149
- package/src/styles/tokens/generated/foundations.generated.ts +0 -454
- package/src/styles/tokens/generated/light.colors.generated.ts +0 -39
- package/src/styles/tokens/generated/light.css +0 -39
- package/src/styles/tokens/index.ts +0 -70
- package/src/styles/tokens/layout.stories.tsx +0 -50
- package/src/styles/tokens/scripts/check-foundations.mjs +0 -126
- package/src/styles/tokens/scripts/check-source.mjs +0 -53
- package/src/styles/tokens/source/dark.tokens.json +0 -138
- package/src/styles/tokens/source/foundations.tokens.json +0 -344
- package/src/styles/tokens/source/light.tokens.json +0 -138
- package/src/styles/tokens/style-dictionary.dark-class.json +0 -16
- package/src/styles/tokens/style-dictionary.dark-storybook.json +0 -16
- package/src/styles/tokens/style-dictionary.dark.json +0 -21
- package/src/styles/tokens/style-dictionary.foundations.json +0 -21
- package/src/styles/tokens/style-dictionary.light-storybook.json +0 -16
- package/src/styles/tokens/style-dictionary.light.json +0 -21
- package/src/styles/tokens/typography.stories.tsx +0 -157
- package/src/translations/en.ts +0 -34
- package/src/translations/index.ts +0 -32
- package/src/types/upload.ts +0 -42
- /package/{src/components/filters/index.ts → dist/components/filters/index.d.ts} +0 -0
- /package/{src/components/layout/index.ts → dist/components/layout/index.d.ts} +0 -0
- /package/{src/hooks/index.ts → dist/hooks/index.d.ts} +0 -0
- /package/{src/lib/index.ts → dist/lib/index.d.ts} +0 -0
- /package/{src/native/index.ts → dist/native/index.d.ts} +0 -0
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { userEvent, within } from "storybook/test";
|
|
4
|
-
|
|
5
|
-
import { Button } from "../primitives/button";
|
|
6
|
-
import { Navigation } from "./app-navigation";
|
|
7
|
-
|
|
8
|
-
const meta: Meta<typeof Navigation> = {
|
|
9
|
-
title: "Navigation/AppNavigation",
|
|
10
|
-
component: Navigation,
|
|
11
|
-
tags: ["autodocs"],
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: "fullscreen",
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
export default meta;
|
|
17
|
-
type Story = StoryObj<typeof meta>;
|
|
18
|
-
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
// Shared helpers
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
|
|
23
|
-
const defaultLinks = [
|
|
24
|
-
{ href: "/features", label: "Features" },
|
|
25
|
-
{ href: "/pricing", label: "Pricing" },
|
|
26
|
-
{ href: "/blog", label: "Blog" },
|
|
27
|
-
{ href: "/about", label: "About" },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
/** Adds a little page content so the navigation can be viewed in context. */
|
|
31
|
-
function PageContent({
|
|
32
|
-
message = "Page content appears below the sticky nav.",
|
|
33
|
-
}: {
|
|
34
|
-
message?: string;
|
|
35
|
-
}) {
|
|
36
|
-
return (
|
|
37
|
-
<div className="p-8">
|
|
38
|
-
<p className="text-muted-foreground text-sm">{message}</p>
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Stories
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
export const Default: Story = {
|
|
48
|
-
render: () => (
|
|
49
|
-
<>
|
|
50
|
-
<Navigation>
|
|
51
|
-
<Navigation.Brand>
|
|
52
|
-
<a href="/">Acme</a>
|
|
53
|
-
</Navigation.Brand>
|
|
54
|
-
|
|
55
|
-
<Navigation.List>
|
|
56
|
-
{defaultLinks.map((link) => (
|
|
57
|
-
<Navigation.Item key={link.href} href={link.href}>
|
|
58
|
-
{link.label}
|
|
59
|
-
</Navigation.Item>
|
|
60
|
-
))}
|
|
61
|
-
</Navigation.List>
|
|
62
|
-
|
|
63
|
-
<Navigation.Action>
|
|
64
|
-
<Button size="md" asChild>
|
|
65
|
-
<a href="/get-started">Get started</a>
|
|
66
|
-
</Button>
|
|
67
|
-
</Navigation.Action>
|
|
68
|
-
</Navigation>
|
|
69
|
-
<PageContent />
|
|
70
|
-
</>
|
|
71
|
-
),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const NoCta: Story = {
|
|
75
|
-
render: () => (
|
|
76
|
-
<>
|
|
77
|
-
<Navigation>
|
|
78
|
-
<Navigation.Brand>
|
|
79
|
-
<a href="/">Acme</a>
|
|
80
|
-
</Navigation.Brand>
|
|
81
|
-
<Navigation.List>
|
|
82
|
-
{defaultLinks.map((link) => (
|
|
83
|
-
<Navigation.Item key={link.href} href={link.href}>
|
|
84
|
-
{link.label}
|
|
85
|
-
</Navigation.Item>
|
|
86
|
-
))}
|
|
87
|
-
</Navigation.List>
|
|
88
|
-
</Navigation>
|
|
89
|
-
<PageContent message="Same nav, no Action content." />
|
|
90
|
-
</>
|
|
91
|
-
),
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* `Navigation.Item` (and any of the other pieces) support the same
|
|
96
|
-
* `asChild` composition as `Button`: pass your router's `Link` (or
|
|
97
|
-
* anything else) as the single child. This story stands in for a router
|
|
98
|
-
* `Link` with a plain anchor that no-ops on click, since Storybook has no
|
|
99
|
-
* router.
|
|
100
|
-
*/
|
|
101
|
-
export const WithCustomRouterLink: Story = {
|
|
102
|
-
render: () => {
|
|
103
|
-
const activeHref = "/pricing";
|
|
104
|
-
return (
|
|
105
|
-
<>
|
|
106
|
-
<Navigation>
|
|
107
|
-
<Navigation.Brand>
|
|
108
|
-
<a href="/" data-router-link="stand-in" onClick={(e) => e.preventDefault()}>
|
|
109
|
-
Acme
|
|
110
|
-
</a>
|
|
111
|
-
</Navigation.Brand>
|
|
112
|
-
|
|
113
|
-
<Navigation.List>
|
|
114
|
-
{defaultLinks.map((link) => (
|
|
115
|
-
<Navigation.Item key={link.href} asChild active={link.href === activeHref}>
|
|
116
|
-
<a href={link.href} data-router-link="stand-in" onClick={(e) => e.preventDefault()}>
|
|
117
|
-
{link.label}
|
|
118
|
-
</a>
|
|
119
|
-
</Navigation.Item>
|
|
120
|
-
))}
|
|
121
|
-
</Navigation.List>
|
|
122
|
-
|
|
123
|
-
<Navigation.Action>
|
|
124
|
-
<Button size="md" asChild>
|
|
125
|
-
<a
|
|
126
|
-
href="/get-started"
|
|
127
|
-
data-router-link="stand-in"
|
|
128
|
-
onClick={(e) => e.preventDefault()}
|
|
129
|
-
>
|
|
130
|
-
Get started
|
|
131
|
-
</a>
|
|
132
|
-
</Button>
|
|
133
|
-
</Navigation.Action>
|
|
134
|
-
</Navigation>
|
|
135
|
-
<PageContent message="Every link here is a custom element composed via asChild - open the elements panel to see data-router-link on each one, and the /pricing item's data-active/aria-current." />
|
|
136
|
-
</>
|
|
137
|
-
);
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Composition means arbitrary content can sit alongside the link list and
|
|
143
|
-
* action area without any prop-shape changes to `Navigation` itself.
|
|
144
|
-
*/
|
|
145
|
-
export const WithExtraContent: Story = {
|
|
146
|
-
render: () => (
|
|
147
|
-
<>
|
|
148
|
-
<Navigation>
|
|
149
|
-
<Navigation.Brand>
|
|
150
|
-
<a href="/">Acme</a>
|
|
151
|
-
</Navigation.Brand>
|
|
152
|
-
|
|
153
|
-
<Navigation.List>
|
|
154
|
-
{defaultLinks.slice(0, 2).map((link) => (
|
|
155
|
-
<Navigation.Item key={link.href} href={link.href}>
|
|
156
|
-
{link.label}
|
|
157
|
-
</Navigation.Item>
|
|
158
|
-
))}
|
|
159
|
-
</Navigation.List>
|
|
160
|
-
|
|
161
|
-
<input
|
|
162
|
-
type="search"
|
|
163
|
-
placeholder="Search..."
|
|
164
|
-
className="h-9 w-40 rounded-md border bg-background px-3 text-sm"
|
|
165
|
-
/>
|
|
166
|
-
|
|
167
|
-
<Navigation.Action>
|
|
168
|
-
<Button size="md" variant="outline" asChild>
|
|
169
|
-
<a href="/get-started">Get started</a>
|
|
170
|
-
</Button>
|
|
171
|
-
</Navigation.Action>
|
|
172
|
-
</Navigation>
|
|
173
|
-
<PageContent message="A search input sits directly between the link list and the action area — no endContent prop needed." />
|
|
174
|
-
</>
|
|
175
|
-
),
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* `@internal` — undocumented Nokia 3310-style LCD skin for the mobile Sheet
|
|
180
|
-
* menu, opted into via `variant="nokia"`. Only affects the mobile Sheet, so
|
|
181
|
-
* this story forces a mobile viewport and auto-opens the menu trigger.
|
|
182
|
-
*/
|
|
183
|
-
export const Nokia: Story = {
|
|
184
|
-
parameters: {
|
|
185
|
-
viewport: { defaultViewport: "mobile1" },
|
|
186
|
-
chromatic: { viewports: [375] },
|
|
187
|
-
},
|
|
188
|
-
render: () => (
|
|
189
|
-
<>
|
|
190
|
-
<Navigation variant="nokia">
|
|
191
|
-
<Navigation.Brand>
|
|
192
|
-
<a href="/">Acme</a>
|
|
193
|
-
</Navigation.Brand>
|
|
194
|
-
|
|
195
|
-
<Navigation.List>
|
|
196
|
-
{defaultLinks.map((link) => (
|
|
197
|
-
<Navigation.Item key={link.href} href={link.href} active={link.href === "/pricing"}>
|
|
198
|
-
{link.label}
|
|
199
|
-
</Navigation.Item>
|
|
200
|
-
))}
|
|
201
|
-
</Navigation.List>
|
|
202
|
-
|
|
203
|
-
<Navigation.Action>
|
|
204
|
-
<Button size="md" asChild>
|
|
205
|
-
<a href="/get-started">Get started</a>
|
|
206
|
-
</Button>
|
|
207
|
-
</Navigation.Action>
|
|
208
|
-
</Navigation>
|
|
209
|
-
<PageContent message="Open the menu button to see the Nokia 3310-style LCD skin." />
|
|
210
|
-
</>
|
|
211
|
-
),
|
|
212
|
-
play: async ({ canvasElement }) => {
|
|
213
|
-
const canvas = within(canvasElement);
|
|
214
|
-
const trigger = canvas.getByRole("button", { name: /open menu/i });
|
|
215
|
-
await userEvent.click(trigger);
|
|
216
|
-
},
|
|
217
|
-
};
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { Menu } from "lucide-react";
|
|
2
|
-
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
import { Slot } from "../../lib/slot";
|
|
7
|
-
import { Sheet, SheetClose, SheetContent, SheetTitle, SheetTrigger } from "../overlays/sheet";
|
|
8
|
-
import { Button } from "../primitives/button";
|
|
9
|
-
|
|
10
|
-
type MobileMenuState = {
|
|
11
|
-
/** True while rendering inside the mobile Sheet copy of the nav content. */
|
|
12
|
-
isMobile: boolean;
|
|
13
|
-
variant?: NavigationVariant;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const MobileMenuContext = React.createContext<MobileMenuState>({ isMobile: false });
|
|
17
|
-
|
|
18
|
-
/** @internal Undocumented — not part of the public API surface. */
|
|
19
|
-
type NavigationVariant = "nokia";
|
|
20
|
-
|
|
21
|
-
// Nokia 3310-style monochrome LCD skin for the mobile Sheet. See
|
|
22
|
-
// src/styles/nokia.css for the palette/font tokens and scanline texture.
|
|
23
|
-
const NOKIA_SHEET_CLASSNAME =
|
|
24
|
-
"nokia-screen rounded-none border-[6px] border-nokia-bezel bg-nokia-screen p-4 font-nokia text-nokia-ink shadow-[0_0_0_3px_var(--color-nokia-screen-deep),0_10px_30px_-6px_rgba(0,0,0,0.65)]";
|
|
25
|
-
const NOKIA_SHEET_CLOSE_CLASSNAME =
|
|
26
|
-
"text-nokia-ink hover:bg-nokia-ink hover:text-nokia-screen rounded-none border-2 border-nokia-ink";
|
|
27
|
-
const NOKIA_LIST_CLASSNAME = "!grid grid-cols-3 gap-3";
|
|
28
|
-
const NOKIA_ITEM_CLASSNAME =
|
|
29
|
-
"!h-auto !max-h-none w-full flex-col justify-center gap-1 rounded-none border-2 border-nokia-ink/40 px-2 py-3 text-center font-nokia text-base tracking-widest uppercase hover:bg-transparent active:bg-nokia-ink active:text-nokia-screen data-[active]:border-nokia-ink data-[active]:bg-nokia-ink data-[active]:text-nokia-screen";
|
|
30
|
-
|
|
31
|
-
export interface NavigationRootProps {
|
|
32
|
-
children: ReactNode;
|
|
33
|
-
ariaLabel?: string;
|
|
34
|
-
className?: string;
|
|
35
|
-
/**
|
|
36
|
-
* @internal Undocumented mobile-Sheet skin, not part of the public API
|
|
37
|
-
* (no README/Storybook entry). Opt in at your own risk.
|
|
38
|
-
*/
|
|
39
|
-
variant?: NavigationVariant;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Sticky nav shell. Compose it with `Navigation.Brand`, `Navigation.List`
|
|
44
|
-
* (containing `Navigation.Item`s), and any other content — a CTA `Button`,
|
|
45
|
-
* a search input, a notification bell — as plain children. `Navigation`
|
|
46
|
-
* only owns the responsive chrome: `Navigation.Brand` stays visible at
|
|
47
|
-
* every width, everything else collapses into a Sheet-based mobile menu
|
|
48
|
-
* below `sm`, reusing the exact elements you composed (not a parallel data
|
|
49
|
-
* shape) so `Navigation.Item`'s active state and `asChild` composition
|
|
50
|
-
* behave identically in both places.
|
|
51
|
-
*/
|
|
52
|
-
function NavigationRoot({
|
|
53
|
-
children,
|
|
54
|
-
ariaLabel = "Primary navigation",
|
|
55
|
-
className,
|
|
56
|
-
variant,
|
|
57
|
-
}: NavigationRootProps) {
|
|
58
|
-
const [mobileOpen, setMobileOpen] = React.useState(false);
|
|
59
|
-
const isNokia = variant === "nokia";
|
|
60
|
-
|
|
61
|
-
const items = React.Children.toArray(children);
|
|
62
|
-
const brand = items.find(
|
|
63
|
-
(child) => React.isValidElement(child) && child.type === NavigationBrand,
|
|
64
|
-
);
|
|
65
|
-
const rest = items.filter((child) => child !== brand);
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<header className="bg-background/95 supports-backdrop-filter:bg-background/60 sticky top-0 z-50 flex w-full justify-center border-b px-4 backdrop-blur">
|
|
69
|
-
<nav
|
|
70
|
-
className={cn(
|
|
71
|
-
"flex min-h-14 w-full max-w-7xl items-center justify-between gap-6",
|
|
72
|
-
className,
|
|
73
|
-
)}
|
|
74
|
-
aria-label={ariaLabel}
|
|
75
|
-
>
|
|
76
|
-
<div className="flex min-w-0 items-center">{brand}</div>
|
|
77
|
-
|
|
78
|
-
<div className="ml-auto hidden min-w-0 items-center gap-6 sm:flex">{rest}</div>
|
|
79
|
-
|
|
80
|
-
<div className="ml-auto flex items-center sm:hidden">
|
|
81
|
-
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
|
82
|
-
<SheetTrigger asChild>
|
|
83
|
-
<Button
|
|
84
|
-
variant="outline"
|
|
85
|
-
size="icon"
|
|
86
|
-
aria-label={mobileOpen ? "Close menu" : "Open menu"}
|
|
87
|
-
>
|
|
88
|
-
<Menu className="size-4" aria-hidden="true" />
|
|
89
|
-
</Button>
|
|
90
|
-
</SheetTrigger>
|
|
91
|
-
<SheetContent
|
|
92
|
-
className={isNokia ? NOKIA_SHEET_CLASSNAME : undefined}
|
|
93
|
-
closeClassName={isNokia ? NOKIA_SHEET_CLOSE_CLASSNAME : undefined}
|
|
94
|
-
>
|
|
95
|
-
<SheetTitle className="sr-only">Navigation menu</SheetTitle>
|
|
96
|
-
<div className="mt-8 flex flex-1 flex-col gap-4">
|
|
97
|
-
<MobileMenuContext.Provider value={{ isMobile: true, variant }}>
|
|
98
|
-
{rest}
|
|
99
|
-
</MobileMenuContext.Provider>
|
|
100
|
-
</div>
|
|
101
|
-
</SheetContent>
|
|
102
|
-
</Sheet>
|
|
103
|
-
</div>
|
|
104
|
-
</nav>
|
|
105
|
-
</header>
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface NavigationBrandProps {
|
|
110
|
-
children: ReactNode;
|
|
111
|
-
className?: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** Always visible, at every viewport width — compose your own link/logo markup directly. */
|
|
115
|
-
function NavigationBrand({ children, className }: NavigationBrandProps) {
|
|
116
|
-
return <div className={cn("flex items-center font-semibold", className)}>{children}</div>;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface NavigationListProps {
|
|
120
|
-
children: ReactNode;
|
|
121
|
-
className?: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Semantic `<ul>` of `Navigation.Item`s. Lays out horizontally on desktop, stacks inside the mobile Sheet. */
|
|
125
|
-
function NavigationList({ children, className }: NavigationListProps) {
|
|
126
|
-
const { isMobile, variant } = React.useContext(MobileMenuContext);
|
|
127
|
-
const isNokia = isMobile && variant === "nokia";
|
|
128
|
-
return (
|
|
129
|
-
<ul
|
|
130
|
-
className={cn(
|
|
131
|
-
"flex items-center gap-1",
|
|
132
|
-
isMobile && "flex-col items-stretch gap-1",
|
|
133
|
-
isNokia && NOKIA_LIST_CLASSNAME,
|
|
134
|
-
className,
|
|
135
|
-
)}
|
|
136
|
-
>
|
|
137
|
-
{children}
|
|
138
|
-
</ul>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
interface NavigationItemOwnProps {
|
|
143
|
-
active?: boolean;
|
|
144
|
-
/** Apply the item styling to a single child (e.g. your router's `Link`) instead of rendering an `<a>`. */
|
|
145
|
-
asChild?: boolean;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export type NavigationItemProps = NavigationItemOwnProps &
|
|
149
|
-
Omit<ComponentPropsWithoutRef<"a">, keyof NavigationItemOwnProps>;
|
|
150
|
-
|
|
151
|
-
/** A single nav link, wrapped in `<li>`. Auto-closes the mobile Sheet on click when rendered there. */
|
|
152
|
-
function NavigationItem({
|
|
153
|
-
active = false,
|
|
154
|
-
asChild = false,
|
|
155
|
-
className,
|
|
156
|
-
children,
|
|
157
|
-
...props
|
|
158
|
-
}: NavigationItemProps) {
|
|
159
|
-
const { isMobile, variant } = React.useContext(MobileMenuContext);
|
|
160
|
-
const isNokia = isMobile && variant === "nokia";
|
|
161
|
-
const itemClassName = cn(
|
|
162
|
-
"inline-flex h-9 max-h-9 shrink-0 items-center px-3 py-2 text-sm font-medium hover:bg-muted hover:text-muted-foreground data-[active]:font-semibold data-[active]:text-foreground",
|
|
163
|
-
isNokia && NOKIA_ITEM_CLASSNAME,
|
|
164
|
-
className,
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const content = asChild ? (
|
|
168
|
-
<Slot
|
|
169
|
-
{...props}
|
|
170
|
-
data-active={active || undefined}
|
|
171
|
-
aria-current={active ? "page" : undefined}
|
|
172
|
-
className={itemClassName}
|
|
173
|
-
>
|
|
174
|
-
{children}
|
|
175
|
-
</Slot>
|
|
176
|
-
) : (
|
|
177
|
-
<a
|
|
178
|
-
{...props}
|
|
179
|
-
data-active={active || undefined}
|
|
180
|
-
aria-current={active ? "page" : undefined}
|
|
181
|
-
className={itemClassName}
|
|
182
|
-
>
|
|
183
|
-
{children}
|
|
184
|
-
</a>
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
return <li>{isMobile ? <SheetClose asChild>{content}</SheetClose> : content}</li>;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export interface NavigationActionProps {
|
|
191
|
-
children: ReactNode;
|
|
192
|
-
className?: string;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Layout wrapper for a CTA, avatar menu, theme toggle, etc. — bring your
|
|
197
|
-
* own `Button`, no dedicated CTA component needed. Content here does not
|
|
198
|
-
* auto-close the mobile Sheet on click (it may hold more than one
|
|
199
|
-
* element, or non-navigational controls) — use `Navigation.Item` instead
|
|
200
|
-
* for a link that should close the menu when tapped.
|
|
201
|
-
*/
|
|
202
|
-
function NavigationAction({ children, className }: NavigationActionProps) {
|
|
203
|
-
const { isMobile, variant } = React.useContext(MobileMenuContext);
|
|
204
|
-
const isNokia = isMobile && variant === "nokia";
|
|
205
|
-
return (
|
|
206
|
-
<div
|
|
207
|
-
className={cn(
|
|
208
|
-
"flex items-center gap-3",
|
|
209
|
-
isMobile && "mt-2 flex-col items-stretch gap-3 border-t pt-4",
|
|
210
|
-
isNokia && "border-nokia-ink/40",
|
|
211
|
-
className,
|
|
212
|
-
)}
|
|
213
|
-
>
|
|
214
|
-
{children}
|
|
215
|
-
</div>
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
type NavigationComponent = typeof NavigationRoot & {
|
|
220
|
-
Brand: typeof NavigationBrand;
|
|
221
|
-
List: typeof NavigationList;
|
|
222
|
-
Item: typeof NavigationItem;
|
|
223
|
-
Action: typeof NavigationAction;
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
export const Navigation: NavigationComponent = Object.assign(NavigationRoot, {
|
|
227
|
-
Brand: NavigationBrand,
|
|
228
|
-
List: NavigationList,
|
|
229
|
-
Item: NavigationItem,
|
|
230
|
-
Action: NavigationAction,
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
/** @deprecated Use `Navigation` instead. */
|
|
234
|
-
export const AppNavigation = Navigation;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
|
|
4
|
-
import { PaginationControls } from "./pagination-controls";
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
title: "Navigation/PaginationControls",
|
|
8
|
-
component: PaginationControls,
|
|
9
|
-
tags: ["autodocs"],
|
|
10
|
-
} satisfies Meta<typeof PaginationControls>;
|
|
11
|
-
|
|
12
|
-
export default meta;
|
|
13
|
-
type Story = StoryObj<typeof meta>;
|
|
14
|
-
|
|
15
|
-
function PaginationPreview({ totalPages }: { totalPages: number }) {
|
|
16
|
-
const [currentPage, setCurrentPage] = useState(0);
|
|
17
|
-
return (
|
|
18
|
-
<PaginationControls
|
|
19
|
-
currentPage={currentPage}
|
|
20
|
-
totalPages={totalPages}
|
|
21
|
-
onPageChange={setCurrentPage}
|
|
22
|
-
/>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const baseArgs = {
|
|
27
|
-
currentPage: 0,
|
|
28
|
-
totalPages: 5,
|
|
29
|
-
onPageChange: () => {},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const Default: Story = {
|
|
33
|
-
args: baseArgs,
|
|
34
|
-
render: () => <PaginationPreview totalPages={5} />,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const SinglePage: Story = {
|
|
38
|
-
name: "Single page (disabled controls)",
|
|
39
|
-
args: { ...baseArgs, totalPages: 1 },
|
|
40
|
-
render: () => <PaginationPreview totalPages={1} />,
|
|
41
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
2
|
-
|
|
3
|
-
import { Button } from "../primitives/button";
|
|
4
|
-
|
|
5
|
-
export interface PaginationControlsProps {
|
|
6
|
-
currentPage: number;
|
|
7
|
-
totalPages: number;
|
|
8
|
-
onPageChange: (page: number) => void;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Zero-indexed prev/next pagination control. */
|
|
12
|
-
export function PaginationControls({
|
|
13
|
-
currentPage,
|
|
14
|
-
totalPages,
|
|
15
|
-
onPageChange,
|
|
16
|
-
}: PaginationControlsProps) {
|
|
17
|
-
return (
|
|
18
|
-
<div className="border-border bg-background text-foreground inline-flex w-fit shrink-0 items-center self-start overflow-hidden rounded-full border text-sm">
|
|
19
|
-
<Button
|
|
20
|
-
type="button"
|
|
21
|
-
variant="outline"
|
|
22
|
-
size="icon"
|
|
23
|
-
className="rounded-none border-0 border-r bg-transparent shadow-none"
|
|
24
|
-
onClick={() => onPageChange(currentPage - 1)}
|
|
25
|
-
disabled={currentPage === 0}
|
|
26
|
-
aria-label="Previous page"
|
|
27
|
-
>
|
|
28
|
-
<ChevronLeft className="size-4" aria-hidden />
|
|
29
|
-
</Button>
|
|
30
|
-
<span className="min-w-20 px-3 text-center text-xs tabular-nums">
|
|
31
|
-
{currentPage + 1} of {totalPages}
|
|
32
|
-
</span>
|
|
33
|
-
<Button
|
|
34
|
-
type="button"
|
|
35
|
-
variant="outline"
|
|
36
|
-
size="icon"
|
|
37
|
-
className="rounded-none border-0 border-l bg-transparent shadow-none"
|
|
38
|
-
onClick={() => onPageChange(currentPage + 1)}
|
|
39
|
-
disabled={currentPage >= totalPages - 1}
|
|
40
|
-
aria-label="Next page"
|
|
41
|
-
>
|
|
42
|
-
<ChevronRight className="size-4" aria-hidden />
|
|
43
|
-
</Button>
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
|
|
3
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs";
|
|
4
|
-
|
|
5
|
-
const meta = {
|
|
6
|
-
title: "Navigation/Tabs",
|
|
7
|
-
component: Tabs,
|
|
8
|
-
tags: ["autodocs"],
|
|
9
|
-
} satisfies Meta<typeof Tabs>;
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
type Story = StoryObj<typeof meta>;
|
|
13
|
-
|
|
14
|
-
export const Default: Story = {
|
|
15
|
-
render: () => (
|
|
16
|
-
<Tabs defaultValue="account" className="w-[400px]">
|
|
17
|
-
<TabsList>
|
|
18
|
-
<TabsTrigger value="account">Account</TabsTrigger>
|
|
19
|
-
<TabsTrigger value="password">Password</TabsTrigger>
|
|
20
|
-
</TabsList>
|
|
21
|
-
<TabsContent value="account">
|
|
22
|
-
<p className="text-muted-foreground p-4 text-sm">
|
|
23
|
-
Make changes to your account here. Click save when you're done.
|
|
24
|
-
</p>
|
|
25
|
-
</TabsContent>
|
|
26
|
-
<TabsContent value="password">
|
|
27
|
-
<p className="text-muted-foreground p-4 text-sm">
|
|
28
|
-
Change your password here. After saving, you'll be logged out.
|
|
29
|
-
</p>
|
|
30
|
-
</TabsContent>
|
|
31
|
-
</Tabs>
|
|
32
|
-
),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const Vertical: Story = {
|
|
36
|
-
render: () => (
|
|
37
|
-
<Tabs defaultValue="tab1" orientation="vertical" className="w-[400px]">
|
|
38
|
-
<TabsList>
|
|
39
|
-
<TabsTrigger value="tab1">Account</TabsTrigger>
|
|
40
|
-
<TabsTrigger value="tab2">Billing</TabsTrigger>
|
|
41
|
-
<TabsTrigger value="tab3">Security</TabsTrigger>
|
|
42
|
-
</TabsList>
|
|
43
|
-
<TabsContent value="tab1">Account settings</TabsContent>
|
|
44
|
-
<TabsContent value="tab2">Billing information</TabsContent>
|
|
45
|
-
<TabsContent value="tab3">Security settings</TabsContent>
|
|
46
|
-
</Tabs>
|
|
47
|
-
),
|
|
48
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../../lib/utils";
|
|
5
|
-
|
|
6
|
-
function Tabs({ ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
7
|
-
return <TabsPrimitive.Root data-slot="tabs" {...props} />;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
|
|
11
|
-
return (
|
|
12
|
-
<TabsPrimitive.List
|
|
13
|
-
data-slot="tabs-list"
|
|
14
|
-
className={cn(
|
|
15
|
-
"bg-muted flex h-auto w-full items-center gap-1 rounded-full border p-1",
|
|
16
|
-
className,
|
|
17
|
-
)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Tab>) {
|
|
24
|
-
return (
|
|
25
|
-
<TabsPrimitive.Tab
|
|
26
|
-
data-slot="tabs-trigger"
|
|
27
|
-
className={cn(
|
|
28
|
-
"text-foreground flex flex-1 items-center justify-center gap-2 rounded-full px-3 py-2 text-sm font-medium whitespace-nowrap transition-all",
|
|
29
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
30
|
-
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
|
|
31
|
-
"data-active:ring-1 data-active:ring-inset data-active:bg-background data-active:text-foreground data-active:ring-border",
|
|
32
|
-
className,
|
|
33
|
-
)}
|
|
34
|
-
{...props}
|
|
35
|
-
/>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Panel>) {
|
|
40
|
-
return (
|
|
41
|
-
<TabsPrimitive.Panel
|
|
42
|
-
data-slot="tabs-content"
|
|
43
|
-
className={cn(
|
|
44
|
-
"focus-visible:bg-muted/10 mt-2 rounded-md focus-visible:border focus-visible:outline-none",
|
|
45
|
-
className,
|
|
46
|
-
)}
|
|
47
|
-
{...props}
|
|
48
|
-
/>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
|
|
3
|
-
import { BottomSheet } from "./bottom-sheet";
|
|
4
|
-
|
|
5
|
-
const meta = {
|
|
6
|
-
title: "Overlays/BottomSheet",
|
|
7
|
-
component: BottomSheet,
|
|
8
|
-
tags: ["autodocs"],
|
|
9
|
-
} satisfies Meta<typeof BottomSheet>;
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
type Story = StoryObj<typeof meta>;
|
|
13
|
-
|
|
14
|
-
export const Default: Story = {
|
|
15
|
-
args: {
|
|
16
|
-
label: "Example panel",
|
|
17
|
-
children: "Panel content",
|
|
18
|
-
},
|
|
19
|
-
render: () => (
|
|
20
|
-
<div className="bg-muted relative h-105 w-120 overflow-hidden rounded-xl border">
|
|
21
|
-
<BottomSheet
|
|
22
|
-
label="Example panel"
|
|
23
|
-
defaultExpanded
|
|
24
|
-
className="bg-card absolute inset-x-4 bottom-4 max-h-[70%] rounded-2xl border shadow-lg"
|
|
25
|
-
scrollClassName="p-4"
|
|
26
|
-
>
|
|
27
|
-
<p className="text-sm font-semibold">Drag the handle or press it to collapse.</p>
|
|
28
|
-
<p className="text-muted-foreground mt-1 text-sm">
|
|
29
|
-
Non-modal persistent panel. Positioning and sizing are app-owned via className.
|
|
30
|
-
</p>
|
|
31
|
-
</BottomSheet>
|
|
32
|
-
</div>
|
|
33
|
-
),
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const Collapsed: Story = {
|
|
37
|
-
args: {
|
|
38
|
-
label: "Example panel",
|
|
39
|
-
children: "Panel content",
|
|
40
|
-
},
|
|
41
|
-
render: () => (
|
|
42
|
-
<div className="bg-muted relative h-105 w-120 overflow-hidden rounded-xl border">
|
|
43
|
-
<BottomSheet
|
|
44
|
-
label="Example panel"
|
|
45
|
-
className="bg-card absolute inset-x-4 bottom-4 max-h-[70%] rounded-2xl border shadow-lg"
|
|
46
|
-
scrollClassName="p-4"
|
|
47
|
-
>
|
|
48
|
-
<p className="text-sm font-semibold">Starts collapsed to its 48px peek.</p>
|
|
49
|
-
</BottomSheet>
|
|
50
|
-
</div>
|
|
51
|
-
),
|
|
52
|
-
};
|