@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,111 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
|
|
4
|
-
import { booleanControl, hiddenControl, numberControl } from "../../storybook/controls";
|
|
5
|
-
import { Stepper } from "./stepper";
|
|
6
|
-
|
|
7
|
-
const meta = {
|
|
8
|
-
title: "Forms/Stepper",
|
|
9
|
-
component: Stepper,
|
|
10
|
-
tags: ["autodocs"],
|
|
11
|
-
argTypes: {
|
|
12
|
-
value: numberControl("Current value", { defaultValue: 1 }),
|
|
13
|
-
min: numberControl("Minimum allowed value", { defaultValue: 0 }),
|
|
14
|
-
max: numberControl("Maximum allowed value", { defaultValue: 100 }),
|
|
15
|
-
step: numberControl("Amount to change per click", { defaultValue: 1 }),
|
|
16
|
-
disabled: booleanControl("Prevents user interaction", false),
|
|
17
|
-
onChange: hiddenControl,
|
|
18
|
-
},
|
|
19
|
-
} satisfies Meta<typeof Stepper>;
|
|
20
|
-
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
|
|
24
|
-
function StepperPreview({
|
|
25
|
-
value,
|
|
26
|
-
min,
|
|
27
|
-
max,
|
|
28
|
-
step,
|
|
29
|
-
disabled,
|
|
30
|
-
format,
|
|
31
|
-
}: {
|
|
32
|
-
value: number;
|
|
33
|
-
min?: number;
|
|
34
|
-
max?: number;
|
|
35
|
-
step?: number;
|
|
36
|
-
disabled?: boolean;
|
|
37
|
-
format?: (value: number) => string;
|
|
38
|
-
}) {
|
|
39
|
-
const [currentValue, setCurrentValue] = useState(value);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Stepper
|
|
43
|
-
value={currentValue}
|
|
44
|
-
min={min}
|
|
45
|
-
max={max}
|
|
46
|
-
step={step}
|
|
47
|
-
disabled={disabled}
|
|
48
|
-
format={format}
|
|
49
|
-
onChange={setCurrentValue}
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const Default: Story = {
|
|
55
|
-
args: {
|
|
56
|
-
value: 1,
|
|
57
|
-
min: 0,
|
|
58
|
-
max: 10,
|
|
59
|
-
step: 1,
|
|
60
|
-
onChange: () => {},
|
|
61
|
-
},
|
|
62
|
-
render: (args) => (
|
|
63
|
-
<StepperPreview value={args.value} min={args.min} max={args.max} step={args.step} />
|
|
64
|
-
),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const AtMin: Story = {
|
|
68
|
-
args: {
|
|
69
|
-
value: 0,
|
|
70
|
-
min: 0,
|
|
71
|
-
max: 10,
|
|
72
|
-
onChange: () => {},
|
|
73
|
-
},
|
|
74
|
-
render: (args) => <StepperPreview value={args.value} min={args.min} max={args.max} />,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export const AtMax: Story = {
|
|
78
|
-
args: {
|
|
79
|
-
value: 10,
|
|
80
|
-
min: 0,
|
|
81
|
-
max: 10,
|
|
82
|
-
onChange: () => {},
|
|
83
|
-
},
|
|
84
|
-
render: (args) => <StepperPreview value={args.value} min={args.min} max={args.max} />,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export const Disabled: Story = {
|
|
88
|
-
args: {
|
|
89
|
-
value: 3,
|
|
90
|
-
disabled: true,
|
|
91
|
-
onChange: () => {},
|
|
92
|
-
},
|
|
93
|
-
render: (args) => <StepperPreview value={args.value} disabled={args.disabled} />,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const CustomFormat: Story = {
|
|
97
|
-
args: {
|
|
98
|
-
value: 5,
|
|
99
|
-
min: 0,
|
|
100
|
-
max: 20,
|
|
101
|
-
onChange: () => {},
|
|
102
|
-
},
|
|
103
|
-
render: (args) => (
|
|
104
|
-
<StepperPreview
|
|
105
|
-
value={args.value}
|
|
106
|
-
min={args.min}
|
|
107
|
-
max={args.max}
|
|
108
|
-
format={(value) => `${value} guests`}
|
|
109
|
-
/>
|
|
110
|
-
),
|
|
111
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Minus, Plus } from "lucide-react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
4
|
-
import { Button } from "../primitives/button";
|
|
5
|
-
|
|
6
|
-
interface StepperProps {
|
|
7
|
-
value: number;
|
|
8
|
-
min?: number;
|
|
9
|
-
max?: number;
|
|
10
|
-
step?: number;
|
|
11
|
-
format?: (value: number) => string;
|
|
12
|
-
onChange: (value: number) => void;
|
|
13
|
-
className?: string;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
increaseLabel?: string;
|
|
16
|
-
decreaseLabel?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function Stepper({
|
|
20
|
-
value,
|
|
21
|
-
min = 0,
|
|
22
|
-
max = 100,
|
|
23
|
-
step = 1,
|
|
24
|
-
format,
|
|
25
|
-
onChange,
|
|
26
|
-
className,
|
|
27
|
-
disabled,
|
|
28
|
-
increaseLabel = "Increase",
|
|
29
|
-
decreaseLabel = "Decrease",
|
|
30
|
-
}: StepperProps) {
|
|
31
|
-
const atMin = value <= min;
|
|
32
|
-
const atMax = value >= max;
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<div className={cn("border-input bg-muted flex items-center rounded-lg border", className)}>
|
|
36
|
-
<Button
|
|
37
|
-
type="button"
|
|
38
|
-
variant="ghost"
|
|
39
|
-
onClick={() => onChange(Math.max(min, value - step))}
|
|
40
|
-
disabled={disabled || atMin}
|
|
41
|
-
className="text-muted-foreground rounded-none rounded-l-lg border-r"
|
|
42
|
-
aria-label={decreaseLabel}
|
|
43
|
-
>
|
|
44
|
-
<Minus className="size-3.5" />
|
|
45
|
-
</Button>
|
|
46
|
-
<div className="flex min-w-[3ch] flex-1 items-center justify-center px-3">
|
|
47
|
-
<span className="text-foreground text-sm font-semibold tabular-nums">
|
|
48
|
-
{format ? format(value) : value}
|
|
49
|
-
</span>
|
|
50
|
-
</div>
|
|
51
|
-
<Button
|
|
52
|
-
type="button"
|
|
53
|
-
variant="ghost"
|
|
54
|
-
onClick={() => onChange(Math.min(max, value + step))}
|
|
55
|
-
disabled={disabled || atMax}
|
|
56
|
-
className="text-muted-foreground rounded-none rounded-r-lg border-l"
|
|
57
|
-
aria-label={increaseLabel}
|
|
58
|
-
>
|
|
59
|
-
<Plus className="size-3.5" />
|
|
60
|
-
</Button>
|
|
61
|
-
</div>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export { Stepper };
|
|
66
|
-
export type { StepperProps };
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
|
|
4
|
-
import { booleanControl, selectControl } from "../../storybook/controls";
|
|
5
|
-
import { switchSizeOptions } from "../../storybook/options";
|
|
6
|
-
import { Switch } from "./switch";
|
|
7
|
-
|
|
8
|
-
const meta = {
|
|
9
|
-
title: "Forms/Switch",
|
|
10
|
-
component: Switch,
|
|
11
|
-
tags: ["autodocs"],
|
|
12
|
-
argTypes: {
|
|
13
|
-
checked: booleanControl("Controlled on/off state of the switch", false),
|
|
14
|
-
disabled: booleanControl("Prevents user interaction and applies disabled styling", false),
|
|
15
|
-
size: selectControl(switchSizeOptions, "Size variant of the switch", {
|
|
16
|
-
defaultValue: "default",
|
|
17
|
-
}),
|
|
18
|
-
},
|
|
19
|
-
} satisfies Meta<typeof Switch>;
|
|
20
|
-
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
|
|
24
|
-
function SwitchPreview({
|
|
25
|
-
checked,
|
|
26
|
-
disabled = false,
|
|
27
|
-
id,
|
|
28
|
-
label,
|
|
29
|
-
size = "default",
|
|
30
|
-
}: {
|
|
31
|
-
checked: boolean;
|
|
32
|
-
disabled: boolean;
|
|
33
|
-
id: string;
|
|
34
|
-
label: string;
|
|
35
|
-
size: "default" | "sm";
|
|
36
|
-
}) {
|
|
37
|
-
const [currentChecked, setCurrentChecked] = useState(checked);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
setCurrentChecked(checked);
|
|
41
|
-
}, [checked]);
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div className="flex items-center space-x-2">
|
|
45
|
-
<Switch
|
|
46
|
-
id={id}
|
|
47
|
-
checked={currentChecked}
|
|
48
|
-
disabled={disabled}
|
|
49
|
-
onCheckedChange={setCurrentChecked}
|
|
50
|
-
size={size}
|
|
51
|
-
/>
|
|
52
|
-
<label htmlFor={id} className="text-foreground text-sm leading-none font-medium">
|
|
53
|
-
{label}
|
|
54
|
-
</label>
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const Default: Story = {
|
|
60
|
-
args: {
|
|
61
|
-
checked: false,
|
|
62
|
-
},
|
|
63
|
-
render: (args) => (
|
|
64
|
-
<SwitchPreview
|
|
65
|
-
checked={args.checked ?? false}
|
|
66
|
-
disabled={args.disabled ?? false}
|
|
67
|
-
id="switch-default"
|
|
68
|
-
label="Airplane Mode"
|
|
69
|
-
size={args.size ?? "default"}
|
|
70
|
-
/>
|
|
71
|
-
),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const WithLabel: Story = {
|
|
75
|
-
args: {
|
|
76
|
-
checked: false,
|
|
77
|
-
size: "default",
|
|
78
|
-
},
|
|
79
|
-
render: (args) => (
|
|
80
|
-
<SwitchPreview
|
|
81
|
-
checked={args.checked ?? false}
|
|
82
|
-
disabled={args.disabled ?? false}
|
|
83
|
-
id="airplane-mode"
|
|
84
|
-
label="Airplane Mode"
|
|
85
|
-
size={args.size ?? "default"}
|
|
86
|
-
/>
|
|
87
|
-
),
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const Checked: Story = {
|
|
91
|
-
args: {
|
|
92
|
-
checked: true,
|
|
93
|
-
},
|
|
94
|
-
render: (args) => (
|
|
95
|
-
<SwitchPreview
|
|
96
|
-
checked={args.checked ?? true}
|
|
97
|
-
disabled={args.disabled ?? false}
|
|
98
|
-
id="notifications"
|
|
99
|
-
label="Enable Notifications"
|
|
100
|
-
size={args.size ?? "default"}
|
|
101
|
-
/>
|
|
102
|
-
),
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
export const Disabled: Story = {
|
|
106
|
-
args: {
|
|
107
|
-
checked: false,
|
|
108
|
-
disabled: true,
|
|
109
|
-
},
|
|
110
|
-
render: (args) => (
|
|
111
|
-
<div className="flex flex-col gap-3">
|
|
112
|
-
<SwitchPreview
|
|
113
|
-
checked={args.checked ?? false}
|
|
114
|
-
disabled={args.disabled ?? false}
|
|
115
|
-
id="disabled-off"
|
|
116
|
-
label="Disabled off"
|
|
117
|
-
size={args.size ?? "default"}
|
|
118
|
-
/>
|
|
119
|
-
<SwitchPreview
|
|
120
|
-
checked
|
|
121
|
-
disabled={args.disabled ?? false}
|
|
122
|
-
id="disabled-on"
|
|
123
|
-
label="Disabled on"
|
|
124
|
-
size={args.size ?? "default"}
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
),
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export const Small: Story = {
|
|
131
|
-
args: {
|
|
132
|
-
checked: false,
|
|
133
|
-
size: "sm",
|
|
134
|
-
},
|
|
135
|
-
render: (args) => (
|
|
136
|
-
<SwitchPreview
|
|
137
|
-
checked={args.checked ?? false}
|
|
138
|
-
disabled={args.disabled ?? false}
|
|
139
|
-
id="small"
|
|
140
|
-
label="Small switch"
|
|
141
|
-
size={args.size ?? "default"}
|
|
142
|
-
/>
|
|
143
|
-
),
|
|
144
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../../lib/utils";
|
|
5
|
-
|
|
6
|
-
function Switch({
|
|
7
|
-
className,
|
|
8
|
-
size = "default",
|
|
9
|
-
...props
|
|
10
|
-
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
|
11
|
-
size?: "sm" | "default";
|
|
12
|
-
}) {
|
|
13
|
-
return (
|
|
14
|
-
<SwitchPrimitive.Root
|
|
15
|
-
data-slot="switch"
|
|
16
|
-
data-size={size}
|
|
17
|
-
className={cn(
|
|
18
|
-
"peer inline-flex shrink-0 items-center rounded-full border border-transparent p-px",
|
|
19
|
-
"data-checked:bg-primary data-unchecked:bg-input data-checked:justify-end data-unchecked:justify-start",
|
|
20
|
-
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
|
21
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
22
|
-
size === "default" ? "h-[1.15rem] w-8" : "h-3.5 w-6",
|
|
23
|
-
className,
|
|
24
|
-
)}
|
|
25
|
-
{...props}
|
|
26
|
-
>
|
|
27
|
-
<SwitchPrimitive.Thumb
|
|
28
|
-
data-slot="switch-thumb"
|
|
29
|
-
data-size={size}
|
|
30
|
-
className={cn(
|
|
31
|
-
"pointer-events-none block rounded-full bg-background shadow-sm ring-1 ring-border/5 transition-all",
|
|
32
|
-
size === "default" ? "size-4" : "size-3",
|
|
33
|
-
)}
|
|
34
|
-
/>
|
|
35
|
-
</SwitchPrimitive.Root>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export { Switch };
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { expect, userEvent, within } from "storybook/test";
|
|
3
|
-
|
|
4
|
-
import { booleanControl, selectControl, textControl } from "../../storybook/controls";
|
|
5
|
-
import { textFieldTypeOptions } from "../../storybook/options";
|
|
6
|
-
import { TextField } from "./text-field";
|
|
7
|
-
|
|
8
|
-
const meta = {
|
|
9
|
-
title: "Forms/TextField",
|
|
10
|
-
component: TextField,
|
|
11
|
-
tags: ["autodocs"],
|
|
12
|
-
argTypes: {
|
|
13
|
-
label: textControl("Label displayed above the field"),
|
|
14
|
-
type: selectControl(textFieldTypeOptions, "Input type used by the field", {
|
|
15
|
-
defaultValue: "text",
|
|
16
|
-
}),
|
|
17
|
-
placeholder: textControl("Placeholder text shown when the field is empty"),
|
|
18
|
-
helpText: textControl("Supporting text shown below the field"),
|
|
19
|
-
error: textControl("Validation error text shown below the field"),
|
|
20
|
-
disabled: booleanControl("Prevents user interaction and applies disabled styling", false),
|
|
21
|
-
required: booleanControl("Marks the field as required for form submission", false),
|
|
22
|
-
},
|
|
23
|
-
} satisfies Meta<typeof TextField>;
|
|
24
|
-
|
|
25
|
-
export default meta;
|
|
26
|
-
type Story = StoryObj<typeof meta>;
|
|
27
|
-
|
|
28
|
-
export const Default: Story = {
|
|
29
|
-
args: {
|
|
30
|
-
label: "Email",
|
|
31
|
-
placeholder: "you@example.com",
|
|
32
|
-
type: "email",
|
|
33
|
-
},
|
|
34
|
-
play: async ({ canvasElement }) => {
|
|
35
|
-
const canvas = within(canvasElement);
|
|
36
|
-
const input = canvas.getByLabelText("Email");
|
|
37
|
-
|
|
38
|
-
await userEvent.click(input);
|
|
39
|
-
await userEvent.type(input, "you@example.com");
|
|
40
|
-
|
|
41
|
-
await expect(input).toHaveFocus();
|
|
42
|
-
await expect(input).toHaveValue("you@example.com");
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const WithHelpText: Story = {
|
|
47
|
-
args: {
|
|
48
|
-
label: "Search",
|
|
49
|
-
helpText: "Press Enter to submit",
|
|
50
|
-
placeholder: "Search notes",
|
|
51
|
-
type: "search",
|
|
52
|
-
},
|
|
53
|
-
play: async ({ canvasElement }) => {
|
|
54
|
-
const canvas = within(canvasElement);
|
|
55
|
-
|
|
56
|
-
await expect(canvas.getByText("Press Enter to submit")).toBeInTheDocument();
|
|
57
|
-
await expect(canvas.getByLabelText("Search")).toBeEnabled();
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const Error: Story = {
|
|
62
|
-
args: {
|
|
63
|
-
label: "Password",
|
|
64
|
-
error: "Password is required",
|
|
65
|
-
type: "password",
|
|
66
|
-
},
|
|
67
|
-
play: async ({ canvasElement }) => {
|
|
68
|
-
const canvas = within(canvasElement);
|
|
69
|
-
const input = canvas.getByLabelText("Password");
|
|
70
|
-
|
|
71
|
-
await expect(input).toHaveAttribute("aria-invalid", "true");
|
|
72
|
-
await expect(canvas.getByText("Password is required")).toBeInTheDocument();
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export const Disabled: Story = {
|
|
77
|
-
args: {
|
|
78
|
-
disabled: true,
|
|
79
|
-
label: "Handle",
|
|
80
|
-
placeholder: "@hominem",
|
|
81
|
-
},
|
|
82
|
-
play: async ({ canvasElement }) => {
|
|
83
|
-
const canvas = within(canvasElement);
|
|
84
|
-
|
|
85
|
-
await expect(canvas.getByLabelText("Handle")).toBeDisabled();
|
|
86
|
-
},
|
|
87
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
4
|
-
import { Input } from "./input";
|
|
5
|
-
import type { TextFieldBaseProps, TextFieldType } from "./text-field.types";
|
|
6
|
-
|
|
7
|
-
interface TextFieldProps extends Omit<React.ComponentProps<"input">, "type">, TextFieldBaseProps {
|
|
8
|
-
type?: TextFieldType | undefined;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* TextField — composed input with label, helper text, and error state.
|
|
13
|
-
* Replaces raw `<input>` + `<label>` + error span patterns in feature code.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* <TextField label="Email" type="email" error={errors.email?.message} />
|
|
17
|
-
* <TextField label="Search" type="search" helpText="Press Enter to search" />
|
|
18
|
-
*/
|
|
19
|
-
function TextField({
|
|
20
|
-
id,
|
|
21
|
-
label,
|
|
22
|
-
helpText,
|
|
23
|
-
error,
|
|
24
|
-
className,
|
|
25
|
-
disabled,
|
|
26
|
-
type = "text",
|
|
27
|
-
...inputProps
|
|
28
|
-
}: TextFieldProps) {
|
|
29
|
-
const generatedId = React.useId();
|
|
30
|
-
const inputId = id ?? generatedId;
|
|
31
|
-
const descriptionId = `${inputId}-description`;
|
|
32
|
-
const errorId = `${inputId}-error`;
|
|
33
|
-
|
|
34
|
-
if (!label && !helpText && !error) {
|
|
35
|
-
return (
|
|
36
|
-
<Input id={inputId} className={className} disabled={disabled} type={type} {...inputProps} />
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<div className="flex flex-col gap-1.5">
|
|
42
|
-
{label && (
|
|
43
|
-
<label
|
|
44
|
-
htmlFor={inputId}
|
|
45
|
-
className={cn(
|
|
46
|
-
"text-foreground text-sm font-medium",
|
|
47
|
-
inputProps.required && "after:text-destructive-text after:ml-0.5 after:content-['*']",
|
|
48
|
-
)}
|
|
49
|
-
>
|
|
50
|
-
{label}
|
|
51
|
-
</label>
|
|
52
|
-
)}
|
|
53
|
-
<Input
|
|
54
|
-
id={inputId}
|
|
55
|
-
className={className}
|
|
56
|
-
disabled={disabled}
|
|
57
|
-
type={type}
|
|
58
|
-
aria-describedby={error ? errorId : helpText ? descriptionId : undefined}
|
|
59
|
-
aria-invalid={error ? true : undefined}
|
|
60
|
-
{...inputProps}
|
|
61
|
-
/>
|
|
62
|
-
{error ? (
|
|
63
|
-
<p id={errorId} role="alert" className="text-destructive-text text-sm">
|
|
64
|
-
{error}
|
|
65
|
-
</p>
|
|
66
|
-
) : helpText ? (
|
|
67
|
-
<p id={descriptionId} className="text-muted-foreground text-sm">
|
|
68
|
-
{helpText}
|
|
69
|
-
</p>
|
|
70
|
-
) : null}
|
|
71
|
-
</div>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export { TextField, type TextFieldProps };
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export type TextFieldType = "text" | "email" | "password" | "search";
|
|
2
|
-
|
|
3
|
-
export interface TextFieldBaseProps {
|
|
4
|
-
disabled?: boolean | undefined;
|
|
5
|
-
error?: string | undefined;
|
|
6
|
-
helpText?: string | undefined;
|
|
7
|
-
label?: string | undefined;
|
|
8
|
-
id?: string | undefined;
|
|
9
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import type { ComponentProps } from "react";
|
|
3
|
-
import { expect, userEvent, within } from "storybook/test";
|
|
4
|
-
|
|
5
|
-
import { booleanControl, numberControl, textControl } from "../../storybook/controls";
|
|
6
|
-
import { Textarea } from "./textarea";
|
|
7
|
-
|
|
8
|
-
function TextareaField({
|
|
9
|
-
error,
|
|
10
|
-
helpText,
|
|
11
|
-
id,
|
|
12
|
-
label,
|
|
13
|
-
...props
|
|
14
|
-
}: ComponentProps<typeof Textarea> & {
|
|
15
|
-
error?: string;
|
|
16
|
-
helpText?: string;
|
|
17
|
-
id: string;
|
|
18
|
-
label: string;
|
|
19
|
-
}) {
|
|
20
|
-
const helpId = helpText ? `${id}-help` : undefined;
|
|
21
|
-
const errorId = error ? `${id}-error` : undefined;
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div className="grid gap-2">
|
|
25
|
-
<label htmlFor={id} className="text-foreground text-sm leading-none font-medium">
|
|
26
|
-
{label}
|
|
27
|
-
</label>
|
|
28
|
-
<Textarea
|
|
29
|
-
id={id}
|
|
30
|
-
aria-describedby={[helpId, errorId].filter(Boolean).join(" ") || undefined}
|
|
31
|
-
aria-invalid={error ? true : undefined}
|
|
32
|
-
{...props}
|
|
33
|
-
/>
|
|
34
|
-
{helpText ? (
|
|
35
|
-
<p id={helpId} className="text-muted-foreground text-sm">
|
|
36
|
-
{helpText}
|
|
37
|
-
</p>
|
|
38
|
-
) : null}
|
|
39
|
-
{error ? (
|
|
40
|
-
<p id={errorId} className="text-destructive-text text-sm" role="alert">
|
|
41
|
-
{error}
|
|
42
|
-
</p>
|
|
43
|
-
) : null}
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const meta = {
|
|
49
|
-
title: "Forms/Textarea",
|
|
50
|
-
component: Textarea,
|
|
51
|
-
tags: ["autodocs"],
|
|
52
|
-
argTypes: {
|
|
53
|
-
placeholder: textControl("Placeholder text shown when the textarea is empty"),
|
|
54
|
-
rows: numberControl("Number of visible text lines", { min: 1, max: 20, defaultValue: 4 }),
|
|
55
|
-
disabled: booleanControl("Prevents user interaction and applies disabled styling", false),
|
|
56
|
-
},
|
|
57
|
-
} satisfies Meta<typeof Textarea>;
|
|
58
|
-
|
|
59
|
-
export default meta;
|
|
60
|
-
type Story = StoryObj<typeof meta>;
|
|
61
|
-
|
|
62
|
-
export const Default: Story = {
|
|
63
|
-
args: {
|
|
64
|
-
placeholder: "Enter your notes here",
|
|
65
|
-
rows: 4,
|
|
66
|
-
},
|
|
67
|
-
render: (args) => <TextareaField id="notes" label="Notes" {...args} />,
|
|
68
|
-
play: async ({ canvasElement }) => {
|
|
69
|
-
const canvas = within(canvasElement);
|
|
70
|
-
const textarea = canvas.getByLabelText("Notes") as HTMLTextAreaElement;
|
|
71
|
-
|
|
72
|
-
await userEvent.click(textarea);
|
|
73
|
-
await userEvent.type(textarea, "Sample note content");
|
|
74
|
-
|
|
75
|
-
await expect(textarea).toHaveValue("Sample note content");
|
|
76
|
-
await expect(textarea).toHaveFocus();
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export const WithHelpText: Story = {
|
|
81
|
-
args: {
|
|
82
|
-
placeholder: "Write a detailed description...",
|
|
83
|
-
rows: 5,
|
|
84
|
-
},
|
|
85
|
-
render: (args) => (
|
|
86
|
-
<TextareaField
|
|
87
|
-
id="description"
|
|
88
|
-
label="Description"
|
|
89
|
-
helpText="Markdown formatting is supported"
|
|
90
|
-
{...args}
|
|
91
|
-
/>
|
|
92
|
-
),
|
|
93
|
-
play: async ({ canvasElement }) => {
|
|
94
|
-
const canvas = within(canvasElement);
|
|
95
|
-
|
|
96
|
-
await expect(canvas.getByText("Markdown formatting is supported")).toBeInTheDocument();
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export const Error: Story = {
|
|
101
|
-
args: {
|
|
102
|
-
placeholder: "Write something...",
|
|
103
|
-
rows: 3,
|
|
104
|
-
},
|
|
105
|
-
render: (args) => (
|
|
106
|
-
<TextareaField
|
|
107
|
-
id="message"
|
|
108
|
-
label="Message"
|
|
109
|
-
error="Message is required and cannot be empty"
|
|
110
|
-
{...args}
|
|
111
|
-
/>
|
|
112
|
-
),
|
|
113
|
-
play: async ({ canvasElement }) => {
|
|
114
|
-
const canvas = within(canvasElement);
|
|
115
|
-
|
|
116
|
-
await expect(canvas.getByRole("alert")).toHaveTextContent(
|
|
117
|
-
"Message is required and cannot be empty",
|
|
118
|
-
);
|
|
119
|
-
},
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export const Disabled: Story = {
|
|
123
|
-
args: {
|
|
124
|
-
disabled: true,
|
|
125
|
-
placeholder: "This field is disabled",
|
|
126
|
-
rows: 4,
|
|
127
|
-
},
|
|
128
|
-
render: (args) => <TextareaField id="archived-notes" label="Archived Notes" {...args} />,
|
|
129
|
-
play: async ({ canvasElement }) => {
|
|
130
|
-
const canvas = within(canvasElement);
|
|
131
|
-
const textarea = canvas.getByLabelText("Archived Notes");
|
|
132
|
-
|
|
133
|
-
await expect(textarea).toBeDisabled();
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
export const LargeField: Story = {
|
|
138
|
-
args: {
|
|
139
|
-
placeholder: "Write as much as you need...",
|
|
140
|
-
rows: 8,
|
|
141
|
-
},
|
|
142
|
-
render: (args) => (
|
|
143
|
-
<TextareaField
|
|
144
|
-
id="long-form-content"
|
|
145
|
-
label="Long Form Content"
|
|
146
|
-
helpText="Use this field for extended writing"
|
|
147
|
-
{...args}
|
|
148
|
-
/>
|
|
149
|
-
),
|
|
150
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
4
|
-
|
|
5
|
-
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
6
|
-
return (
|
|
7
|
-
<textarea
|
|
8
|
-
data-slot="textarea"
|
|
9
|
-
className={cn(
|
|
10
|
-
"border-input flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base transition-colors md:text-sm",
|
|
11
|
-
"placeholder:text-muted-foreground",
|
|
12
|
-
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
|
13
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
14
|
-
"aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
|
|
15
|
-
className,
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
/>
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export { Textarea };
|