@snowcone-app/ui 0.1.43 → 0.2.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/CHANGELOG.md +26 -0
- package/README.md +18 -4
- package/package.json +9 -5
- package/src/components/CanvasIsolationBoundary.tsx +202 -0
- package/src/components/LoadingOverlayPrism.tsx +251 -0
- package/src/composed/AddToCart.tsx +229 -0
- package/src/composed/ArtAlignment.tsx +703 -0
- package/src/composed/ArtSelector.tsx +290 -0
- package/src/composed/ArtworkCustomizer.tsx +212 -0
- package/src/composed/CanvasEditor.tsx +79 -0
- package/src/composed/ColorPicker.tsx +111 -0
- package/src/composed/CurrentSelectionDisplay.tsx +86 -0
- package/src/composed/HeroProductImage.tsx +1071 -0
- package/src/composed/Lightbox.index.ts +2 -0
- package/src/composed/Lightbox.tsx +230 -0
- package/src/composed/PlacementClipShapeSelector.tsx +88 -0
- package/src/composed/PlacementTabs.tsx +179 -0
- package/src/composed/ProductCard.tsx +298 -0
- package/src/composed/ProductGallery.tsx +54 -0
- package/src/composed/ProductImage.tsx +129 -0
- package/src/composed/ProductList.tsx +147 -0
- package/src/composed/ProductOptions.tsx +305 -0
- package/src/composed/RealtimeMockup.tsx +121 -0
- package/src/composed/TileCount.tsx +348 -0
- package/src/composed/carousels/HeroCarousel.tsx +240 -0
- package/src/composed/carousels/MobileProductCarousel.tsx +1002 -0
- package/src/composed/carousels/index.ts +11 -0
- package/src/composed/carousels/types.ts +58 -0
- package/src/composed/grids/MasonryGrid.tsx +238 -0
- package/src/composed/grids/index.ts +9 -0
- package/src/composed/search/CurrentRefinements.tsx +80 -0
- package/src/composed/search/Filters.tsx +49 -0
- package/src/composed/search/FiltersButton.tsx +57 -0
- package/src/composed/search/FiltersDrawer.tsx +375 -0
- package/src/composed/search/ProductGrid.tsx +118 -0
- package/src/composed/search/ProductHit.tsx +56 -0
- package/src/composed/search/SearchBox.tsx +109 -0
- package/src/composed/search/SearchProvider.tsx +136 -0
- package/src/composed/search/facetConfig.ts +16 -0
- package/src/composed/search/index.ts +22 -0
- package/src/composed/search/meilisearchAdapter.ts +20 -0
- package/src/composed/search/types.ts +22 -0
- package/src/composed/zoom/EnhancedImageViewer.tsx +505 -0
- package/src/composed/zoom/ResponsiveZoom.tsx +134 -0
- package/src/composed/zoom/ZoomOverlay.tsx +194 -0
- package/src/composed/zoom/index.ts +12 -0
- package/src/composed/zoom/types.ts +12 -0
- package/src/design-system/ColorPalette.tsx +126 -0
- package/src/design-system/ColorSwatch.tsx +49 -0
- package/src/design-system/DesignSystemPage.tsx +130 -0
- package/src/design-system/ThemeSwitcher.tsx +181 -0
- package/src/design-system/TypographyScale.tsx +106 -0
- package/src/design-system/index.ts +5 -0
- package/src/ecommerce/stories/HeroProductImage.stories.tsx +66 -0
- package/src/ecommerce/stories/PDPHeroGallery.stories.tsx +105 -0
- package/src/ecommerce/stories/PDPInfoPanel.stories.tsx +472 -0
- package/src/ecommerce/stories/PDPLayout.stories.tsx +365 -0
- package/src/hooks/useBrand.ts +41 -0
- package/src/hooks/useCanvasContext.ts +127 -0
- package/src/hooks/useDeviceDetection.ts +64 -0
- package/src/hooks/useFocusTrap.ts +70 -0
- package/src/hooks/useImagePreloader.ts +268 -0
- package/src/hooks/useImageTransition.ts +608 -0
- package/src/hooks/usePlacementsProcessor.ts +74 -0
- package/src/hooks/useProductGallery.ts +193 -0
- package/src/hooks/useProductPage.ts +467 -0
- package/src/hooks/useRenderGuard.ts +96 -0
- package/src/hooks/useScrollDirection.ts +196 -0
- package/src/hooks/viewport/index.ts +25 -0
- package/src/hooks/viewport/useContainerWidth.ts +59 -0
- package/src/hooks/viewport/useMediaQuery.ts +52 -0
- package/src/hooks/viewport/useResponsiveImageCap.ts +149 -0
- package/src/hooks/viewport/useViewportDimensions.ts +135 -0
- package/src/hooks/viewport/useWideMonitorMode.ts +150 -0
- package/src/hooks/visibility/index.ts +15 -0
- package/src/hooks/visibility/observerPool.ts +150 -0
- package/src/index.ts +240 -0
- package/src/layouts/hero-zoom/HeroShrinkLayout.tsx +209 -0
- package/src/layouts/hero-zoom/HeroZoomLayout.tsx +351 -0
- package/src/layouts/hero-zoom/index.ts +30 -0
- package/src/layouts/hero-zoom/stories/HeroZoomLayout.stories.tsx +350 -0
- package/src/layouts/hero-zoom/types.ts +113 -0
- package/src/layouts/hero-zoom/useHeroZoomScales.ts +156 -0
- package/src/layouts/index.ts +9 -0
- package/src/layouts/pdp/EdgeBlurBox.tsx +210 -0
- package/src/layouts/pdp/ImageBlurExtension.tsx +215 -0
- package/src/layouts/pdp/ImageEdgeBlur.tsx +215 -0
- package/src/layouts/pdp/PDPLayout.tsx +246 -0
- package/src/layouts/pdp/SimpleImageBlur.tsx +140 -0
- package/src/layouts/pdp/index.ts +40 -0
- package/src/lib/env.ts +15 -0
- package/src/lib/locale.ts +167 -0
- package/src/lib/router.tsx +46 -0
- package/src/lib/utils.ts +6 -0
- package/src/lightbox/README.md +77 -0
- package/src/next/index.tsx +26 -0
- package/src/patterns/MockupPriorityProvider.tsx +1014 -0
- package/src/patterns/Product.tsx +850 -0
- package/src/patterns/ProductPageProvider.tsx +224 -0
- package/src/patterns/RealtimeProvider.tsx +1162 -0
- package/src/patterns/ShopProvider.tsx +603 -0
- package/src/personalization/PersonalizationBridge.tsx +235 -0
- package/src/personalization/PersonalizationContext.ts +29 -0
- package/src/personalization/PersonalizationInputs.tsx +110 -0
- package/src/personalization/PersonalizationProvider.tsx +407 -0
- package/src/personalization/canvas-stub.d.ts +22 -0
- package/src/personalization/index.ts +43 -0
- package/src/personalization/types.ts +48 -0
- package/src/personalization/usePersonalization.ts +32 -0
- package/src/personalization/usePersonalizationShimmer.ts +159 -0
- package/src/personalization/utils.ts +59 -0
- package/src/primitives/BrandLogo.tsx +65 -0
- package/src/primitives/BrandName.tsx +51 -0
- package/src/primitives/Button.tsx +123 -0
- package/src/primitives/ColorSwatch.tsx +221 -0
- package/src/primitives/DragHintAnimation.tsx +190 -0
- package/src/primitives/EdgeSwipeGuards.tsx +60 -0
- package/src/primitives/FloatingActionGroup.tsx +176 -0
- package/src/primitives/ProductPrice.tsx +171 -0
- package/src/primitives/ProgressiveBlur.tsx +295 -0
- package/src/primitives/ThemeToggle.tsx +125 -0
- package/src/primitives/__tests__/story-coverage.test.ts +98 -0
- package/src/primitives/accordion.tsx +280 -0
- package/src/primitives/badge.tsx +137 -0
- package/src/primitives/card.tsx +61 -0
- package/src/primitives/checkbox.tsx +56 -0
- package/src/primitives/collapsible.tsx +51 -0
- package/src/primitives/drawer.tsx +828 -0
- package/src/primitives/dropdown-menu.tsx +197 -0
- package/src/primitives/fieldset.tsx +73 -0
- package/src/primitives/index.ts +138 -0
- package/src/primitives/input.tsx +91 -0
- package/src/primitives/kbd.tsx +130 -0
- package/src/primitives/label.tsx +20 -0
- package/src/primitives/link.tsx +182 -0
- package/src/primitives/popover.tsx +80 -0
- package/src/primitives/radio-group.tsx +79 -0
- package/src/primitives/scroll-fade.tsx +159 -0
- package/src/primitives/select.tsx +170 -0
- package/src/primitives/separator.tsx +25 -0
- package/src/primitives/slider.tsx +221 -0
- package/src/primitives/spinner.tsx +72 -0
- package/src/primitives/stories/Accordion.stories.tsx +121 -0
- package/src/primitives/stories/Badge.stories.tsx +221 -0
- package/src/primitives/stories/Button.stories.tsx +185 -0
- package/src/primitives/stories/Card.stories.tsx +171 -0
- package/src/primitives/stories/Checkbox.stories.tsx +214 -0
- package/src/primitives/stories/Collapsible.stories.tsx +230 -0
- package/src/primitives/stories/Drawer.stories.tsx +378 -0
- package/src/primitives/stories/DropdownMenu.stories.tsx +182 -0
- package/src/primitives/stories/Fieldset.stories.tsx +212 -0
- package/src/primitives/stories/Input.stories.tsx +172 -0
- package/src/primitives/stories/Kbd.stories.tsx +183 -0
- package/src/primitives/stories/Label.stories.tsx +98 -0
- package/src/primitives/stories/Link.stories.tsx +260 -0
- package/src/primitives/stories/Popover.stories.tsx +178 -0
- package/src/primitives/stories/RadioGroup.stories.tsx +205 -0
- package/src/primitives/stories/Select.stories.tsx +222 -0
- package/src/primitives/stories/Separator.stories.tsx +134 -0
- package/src/primitives/stories/Slider.stories.tsx +203 -0
- package/src/primitives/stories/Spinner.stories.tsx +142 -0
- package/src/primitives/stories/Surface.stories.tsx +257 -0
- package/src/primitives/stories/Switch.stories.tsx +131 -0
- package/src/primitives/stories/Tabs.stories.tsx +275 -0
- package/src/primitives/stories/TextField.stories.tsx +139 -0
- package/src/primitives/stories/Textarea.stories.tsx +148 -0
- package/src/primitives/stories/Tooltip.stories.tsx +119 -0
- package/src/primitives/surface.tsx +86 -0
- package/src/primitives/switch.tsx +35 -0
- package/src/primitives/tabs.tsx +206 -0
- package/src/primitives/text-field.tsx +84 -0
- package/src/primitives/textarea.tsx +50 -0
- package/src/primitives/tooltip.tsx +58 -0
- package/src/services/CanvasExportService.ts +518 -0
- package/src/styles/base.css +380 -0
- package/src/styles/defaults.css +280 -0
- package/src/styles/globals.css +1242 -0
- package/src/styles/index.css +17 -0
- package/src/styles/ne-themes.css +4740 -0
- package/src/styles/tailwind.css +11 -0
- package/src/styles/tokens.css +117 -0
- package/src/styles/utilities.css +188 -0
- package/src/themes/apply-theme.ts +449 -0
- package/src/themes/getThemeStyles.ts +454 -0
- package/src/themes/index.ts +48 -0
- package/src/themes/oklch-theme.ts +283 -0
- package/src/themes/presets.ts +989 -0
- package/src/themes/types.ts +386 -0
- package/src/themes/useTheme.tsx +450 -0
- package/src/utils/dev-warnings.ts +161 -0
- package/src/utils/devWarnings.ts +153 -0
- package/dist/styles.css +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Icon } from '@iconify/react';
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuTrigger,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuCheckboxItem,
|
|
10
|
+
DropdownMenuRadioItem,
|
|
11
|
+
DropdownMenuLabel,
|
|
12
|
+
DropdownMenuSeparator,
|
|
13
|
+
DropdownMenuShortcut,
|
|
14
|
+
DropdownMenuGroup,
|
|
15
|
+
DropdownMenuSub,
|
|
16
|
+
DropdownMenuSubContent,
|
|
17
|
+
DropdownMenuSubTrigger,
|
|
18
|
+
DropdownMenuRadioGroup,
|
|
19
|
+
} from '../dropdown-menu';
|
|
20
|
+
import { Button } from '../button';
|
|
21
|
+
|
|
22
|
+
const meta: Meta<typeof DropdownMenu> = {
|
|
23
|
+
title: 'UI/DropdownMenu',
|
|
24
|
+
component: DropdownMenu,
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: 'centered',
|
|
27
|
+
},
|
|
28
|
+
tags: ['autodocs'],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default meta;
|
|
32
|
+
type Story = StoryObj<typeof meta>;
|
|
33
|
+
|
|
34
|
+
export const Default: Story = {
|
|
35
|
+
render: () => (
|
|
36
|
+
<DropdownMenu>
|
|
37
|
+
<DropdownMenuTrigger asChild>
|
|
38
|
+
<Button variant="secondary">Open Menu</Button>
|
|
39
|
+
</DropdownMenuTrigger>
|
|
40
|
+
<DropdownMenuContent className="w-56">
|
|
41
|
+
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
42
|
+
<DropdownMenuGroup>
|
|
43
|
+
<DropdownMenuItem>
|
|
44
|
+
<Icon icon="gravity-ui:person" />
|
|
45
|
+
Profile
|
|
46
|
+
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
|
47
|
+
</DropdownMenuItem>
|
|
48
|
+
<DropdownMenuItem>
|
|
49
|
+
<Icon icon="gravity-ui:gear" />
|
|
50
|
+
Settings
|
|
51
|
+
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
|
52
|
+
</DropdownMenuItem>
|
|
53
|
+
</DropdownMenuGroup>
|
|
54
|
+
<DropdownMenuSeparator />
|
|
55
|
+
<DropdownMenuItem>
|
|
56
|
+
<Icon icon="gravity-ui:arrow-right-from-square" />
|
|
57
|
+
Log out
|
|
58
|
+
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
|
59
|
+
</DropdownMenuItem>
|
|
60
|
+
</DropdownMenuContent>
|
|
61
|
+
</DropdownMenu>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const WithCheckboxItems: Story = {
|
|
66
|
+
render: () => {
|
|
67
|
+
const [showStatusBar, setShowStatusBar] = useState(true);
|
|
68
|
+
const [showActivityBar, setShowActivityBar] = useState(false);
|
|
69
|
+
const [showPanel, setShowPanel] = useState(false);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<DropdownMenu>
|
|
73
|
+
<DropdownMenuTrigger asChild>
|
|
74
|
+
<Button variant="secondary">View Options</Button>
|
|
75
|
+
</DropdownMenuTrigger>
|
|
76
|
+
<DropdownMenuContent className="w-56">
|
|
77
|
+
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
|
|
78
|
+
<DropdownMenuCheckboxItem checked={showStatusBar} onCheckedChange={setShowStatusBar}>
|
|
79
|
+
Status Bar
|
|
80
|
+
</DropdownMenuCheckboxItem>
|
|
81
|
+
<DropdownMenuCheckboxItem checked={showActivityBar} onCheckedChange={setShowActivityBar}>
|
|
82
|
+
Activity Bar
|
|
83
|
+
</DropdownMenuCheckboxItem>
|
|
84
|
+
<DropdownMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>
|
|
85
|
+
Panel
|
|
86
|
+
</DropdownMenuCheckboxItem>
|
|
87
|
+
</DropdownMenuContent>
|
|
88
|
+
</DropdownMenu>
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const WithRadioItems: Story = {
|
|
94
|
+
render: () => {
|
|
95
|
+
const [position, setPosition] = useState('bottom');
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<DropdownMenu>
|
|
99
|
+
<DropdownMenuTrigger asChild>
|
|
100
|
+
<Button variant="secondary">Panel Position</Button>
|
|
101
|
+
</DropdownMenuTrigger>
|
|
102
|
+
<DropdownMenuContent className="w-56">
|
|
103
|
+
<DropdownMenuLabel>Panel Position</DropdownMenuLabel>
|
|
104
|
+
<DropdownMenuRadioGroup value={position} onValueChange={setPosition}>
|
|
105
|
+
<DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
|
|
106
|
+
<DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
|
|
107
|
+
<DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>
|
|
108
|
+
</DropdownMenuRadioGroup>
|
|
109
|
+
</DropdownMenuContent>
|
|
110
|
+
</DropdownMenu>
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const WithSubMenu: Story = {
|
|
116
|
+
render: () => (
|
|
117
|
+
<DropdownMenu>
|
|
118
|
+
<DropdownMenuTrigger asChild>
|
|
119
|
+
<Button variant="secondary">More Options</Button>
|
|
120
|
+
</DropdownMenuTrigger>
|
|
121
|
+
<DropdownMenuContent className="w-56">
|
|
122
|
+
<DropdownMenuItem>
|
|
123
|
+
<Icon icon="gravity-ui:file" />
|
|
124
|
+
New File
|
|
125
|
+
</DropdownMenuItem>
|
|
126
|
+
<DropdownMenuSub>
|
|
127
|
+
<DropdownMenuSubTrigger>
|
|
128
|
+
<Icon icon="gravity-ui:persons" />
|
|
129
|
+
Invite users
|
|
130
|
+
</DropdownMenuSubTrigger>
|
|
131
|
+
<DropdownMenuSubContent>
|
|
132
|
+
<DropdownMenuItem>
|
|
133
|
+
<Icon icon="gravity-ui:envelope" />
|
|
134
|
+
Email
|
|
135
|
+
</DropdownMenuItem>
|
|
136
|
+
<DropdownMenuItem>
|
|
137
|
+
<Icon icon="gravity-ui:comment" />
|
|
138
|
+
Message
|
|
139
|
+
</DropdownMenuItem>
|
|
140
|
+
<DropdownMenuSeparator />
|
|
141
|
+
<DropdownMenuItem>
|
|
142
|
+
<Icon icon="gravity-ui:circle-plus" />
|
|
143
|
+
More...
|
|
144
|
+
</DropdownMenuItem>
|
|
145
|
+
</DropdownMenuSubContent>
|
|
146
|
+
</DropdownMenuSub>
|
|
147
|
+
<DropdownMenuSeparator />
|
|
148
|
+
<DropdownMenuItem>
|
|
149
|
+
<Icon icon="gravity-ui:gear" />
|
|
150
|
+
Settings
|
|
151
|
+
</DropdownMenuItem>
|
|
152
|
+
</DropdownMenuContent>
|
|
153
|
+
</DropdownMenu>
|
|
154
|
+
),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const ContextMenuStyle: Story = {
|
|
158
|
+
render: () => (
|
|
159
|
+
<DropdownMenu>
|
|
160
|
+
<DropdownMenuTrigger asChild>
|
|
161
|
+
<Button variant="ghost" size="icon">
|
|
162
|
+
<Icon icon="gravity-ui:ellipsis" className="size-5" />
|
|
163
|
+
</Button>
|
|
164
|
+
</DropdownMenuTrigger>
|
|
165
|
+
<DropdownMenuContent align="end">
|
|
166
|
+
<DropdownMenuItem>
|
|
167
|
+
<Icon icon="gravity-ui:pencil" />
|
|
168
|
+
Edit
|
|
169
|
+
</DropdownMenuItem>
|
|
170
|
+
<DropdownMenuItem>
|
|
171
|
+
<Icon icon="gravity-ui:copy" />
|
|
172
|
+
Duplicate
|
|
173
|
+
</DropdownMenuItem>
|
|
174
|
+
<DropdownMenuSeparator />
|
|
175
|
+
<DropdownMenuItem className="text-danger">
|
|
176
|
+
<Icon icon="gravity-ui:trash-bin" />
|
|
177
|
+
Delete
|
|
178
|
+
</DropdownMenuItem>
|
|
179
|
+
</DropdownMenuContent>
|
|
180
|
+
</DropdownMenu>
|
|
181
|
+
),
|
|
182
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Fieldset, Legend } from '../fieldset';
|
|
3
|
+
import { TextField } from '../text-field';
|
|
4
|
+
import { Input } from '../input';
|
|
5
|
+
import { Label } from '../label';
|
|
6
|
+
import { RadioGroup, Radio } from '../radio-group';
|
|
7
|
+
import { Checkbox } from '../checkbox';
|
|
8
|
+
import { Card, CardContent, CardHeader, CardTitle } from '../card';
|
|
9
|
+
import { Button } from '../button';
|
|
10
|
+
|
|
11
|
+
const meta: Meta<typeof Fieldset> = {
|
|
12
|
+
title: 'UI/Fieldset',
|
|
13
|
+
component: Fieldset,
|
|
14
|
+
parameters: {
|
|
15
|
+
layout: 'centered',
|
|
16
|
+
},
|
|
17
|
+
tags: ['autodocs'],
|
|
18
|
+
argTypes: {
|
|
19
|
+
disabled: {
|
|
20
|
+
control: 'boolean',
|
|
21
|
+
description: 'When true, all form elements inside will be disabled',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof meta>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<Fieldset className="w-[300px]">
|
|
32
|
+
<Legend>Personal Information</Legend>
|
|
33
|
+
<TextField>
|
|
34
|
+
<Label>First Name</Label>
|
|
35
|
+
<Input placeholder="John" />
|
|
36
|
+
</TextField>
|
|
37
|
+
<TextField>
|
|
38
|
+
<Label>Last Name</Label>
|
|
39
|
+
<Input placeholder="Doe" />
|
|
40
|
+
</TextField>
|
|
41
|
+
</Fieldset>
|
|
42
|
+
),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithRadioGroup: Story = {
|
|
46
|
+
render: () => (
|
|
47
|
+
<Fieldset className="w-[300px]">
|
|
48
|
+
<Legend>Notification Preferences</Legend>
|
|
49
|
+
<RadioGroup defaultValue="email">
|
|
50
|
+
<div className="flex items-center space-x-2">
|
|
51
|
+
<Radio value="email" id="pref-email" />
|
|
52
|
+
<Label htmlFor="pref-email">Email</Label>
|
|
53
|
+
</div>
|
|
54
|
+
<div className="flex items-center space-x-2">
|
|
55
|
+
<Radio value="sms" id="pref-sms" />
|
|
56
|
+
<Label htmlFor="pref-sms">SMS</Label>
|
|
57
|
+
</div>
|
|
58
|
+
<div className="flex items-center space-x-2">
|
|
59
|
+
<Radio value="push" id="pref-push" />
|
|
60
|
+
<Label htmlFor="pref-push">Push Notifications</Label>
|
|
61
|
+
</div>
|
|
62
|
+
</RadioGroup>
|
|
63
|
+
</Fieldset>
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const WithCheckboxes: Story = {
|
|
68
|
+
render: () => (
|
|
69
|
+
<Fieldset className="w-[300px]">
|
|
70
|
+
<Legend>Interests</Legend>
|
|
71
|
+
<div className="space-y-2">
|
|
72
|
+
<div className="flex items-center space-x-2">
|
|
73
|
+
<Checkbox id="interest-tech" />
|
|
74
|
+
<Label htmlFor="interest-tech">Technology</Label>
|
|
75
|
+
</div>
|
|
76
|
+
<div className="flex items-center space-x-2">
|
|
77
|
+
<Checkbox id="interest-design" />
|
|
78
|
+
<Label htmlFor="interest-design">Design</Label>
|
|
79
|
+
</div>
|
|
80
|
+
<div className="flex items-center space-x-2">
|
|
81
|
+
<Checkbox id="interest-business" />
|
|
82
|
+
<Label htmlFor="interest-business">Business</Label>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</Fieldset>
|
|
86
|
+
),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const Disabled: Story = {
|
|
90
|
+
render: () => (
|
|
91
|
+
<Fieldset className="w-[300px]" disabled>
|
|
92
|
+
<Legend>Disabled Fieldset</Legend>
|
|
93
|
+
<TextField>
|
|
94
|
+
<Label>Name</Label>
|
|
95
|
+
<Input placeholder="Cannot edit" />
|
|
96
|
+
</TextField>
|
|
97
|
+
<TextField>
|
|
98
|
+
<Label>Email</Label>
|
|
99
|
+
<Input type="email" placeholder="Cannot edit" />
|
|
100
|
+
</TextField>
|
|
101
|
+
</Fieldset>
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const MultipleFieldsets: Story = {
|
|
106
|
+
render: () => (
|
|
107
|
+
<form className="w-[350px] space-y-6">
|
|
108
|
+
<Fieldset>
|
|
109
|
+
<Legend>Account Information</Legend>
|
|
110
|
+
<TextField>
|
|
111
|
+
<Label>Username</Label>
|
|
112
|
+
<Input placeholder="Choose a username" />
|
|
113
|
+
</TextField>
|
|
114
|
+
<TextField>
|
|
115
|
+
<Label>Email</Label>
|
|
116
|
+
<Input type="email" placeholder="your@email.com" />
|
|
117
|
+
</TextField>
|
|
118
|
+
</Fieldset>
|
|
119
|
+
|
|
120
|
+
<Fieldset>
|
|
121
|
+
<Legend>Security</Legend>
|
|
122
|
+
<TextField>
|
|
123
|
+
<Label>Password</Label>
|
|
124
|
+
<Input type="password" placeholder="Create password" />
|
|
125
|
+
</TextField>
|
|
126
|
+
<TextField>
|
|
127
|
+
<Label>Confirm Password</Label>
|
|
128
|
+
<Input type="password" placeholder="Confirm password" />
|
|
129
|
+
</TextField>
|
|
130
|
+
</Fieldset>
|
|
131
|
+
|
|
132
|
+
<Fieldset>
|
|
133
|
+
<Legend>Preferences</Legend>
|
|
134
|
+
<div className="flex items-center space-x-2">
|
|
135
|
+
<Checkbox id="newsletter" />
|
|
136
|
+
<Label htmlFor="newsletter">Subscribe to newsletter</Label>
|
|
137
|
+
</div>
|
|
138
|
+
<div className="flex items-center space-x-2">
|
|
139
|
+
<Checkbox id="terms" />
|
|
140
|
+
<Label htmlFor="terms">I agree to the terms</Label>
|
|
141
|
+
</div>
|
|
142
|
+
</Fieldset>
|
|
143
|
+
</form>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const OnCard: Story = {
|
|
148
|
+
render: () => (
|
|
149
|
+
<Card className="w-[400px]">
|
|
150
|
+
<CardHeader>
|
|
151
|
+
<CardTitle>Registration Form</CardTitle>
|
|
152
|
+
</CardHeader>
|
|
153
|
+
<CardContent className="space-y-6">
|
|
154
|
+
<Fieldset>
|
|
155
|
+
<Legend>Contact Details</Legend>
|
|
156
|
+
<TextField>
|
|
157
|
+
<Label>Full Name</Label>
|
|
158
|
+
<Input placeholder="Enter your name" />
|
|
159
|
+
</TextField>
|
|
160
|
+
<TextField>
|
|
161
|
+
<Label>Phone</Label>
|
|
162
|
+
<Input type="tel" placeholder="+1 (555) 000-0000" />
|
|
163
|
+
</TextField>
|
|
164
|
+
</Fieldset>
|
|
165
|
+
|
|
166
|
+
<Fieldset>
|
|
167
|
+
<Legend>Communication</Legend>
|
|
168
|
+
<RadioGroup defaultValue="email">
|
|
169
|
+
<div className="flex items-center space-x-2">
|
|
170
|
+
<Radio value="email" id="comm-email" />
|
|
171
|
+
<Label htmlFor="comm-email">Contact via Email</Label>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="flex items-center space-x-2">
|
|
174
|
+
<Radio value="phone" id="comm-phone" />
|
|
175
|
+
<Label htmlFor="comm-phone">Contact via Phone</Label>
|
|
176
|
+
</div>
|
|
177
|
+
</RadioGroup>
|
|
178
|
+
</Fieldset>
|
|
179
|
+
|
|
180
|
+
<Button className="w-full">Submit</Button>
|
|
181
|
+
</CardContent>
|
|
182
|
+
</Card>
|
|
183
|
+
),
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const DisabledExample: Story = {
|
|
187
|
+
name: 'Disabled Example',
|
|
188
|
+
render: () => (
|
|
189
|
+
<div className="w-[350px] space-y-4">
|
|
190
|
+
<p className="text-sm text-foreground/60 mb-4">
|
|
191
|
+
Fieldset is used for semantic grouping of form controls.
|
|
192
|
+
Use the <code>disabled</code> prop to disable all child form elements.
|
|
193
|
+
</p>
|
|
194
|
+
|
|
195
|
+
<Fieldset>
|
|
196
|
+
<Legend>Normal Fieldset</Legend>
|
|
197
|
+
<TextField>
|
|
198
|
+
<Label>Input</Label>
|
|
199
|
+
<Input placeholder="Editable" />
|
|
200
|
+
</TextField>
|
|
201
|
+
</Fieldset>
|
|
202
|
+
|
|
203
|
+
<Fieldset disabled>
|
|
204
|
+
<Legend>Disabled Fieldset</Legend>
|
|
205
|
+
<TextField>
|
|
206
|
+
<Label>Input</Label>
|
|
207
|
+
<Input placeholder="Disabled" />
|
|
208
|
+
</TextField>
|
|
209
|
+
</Fieldset>
|
|
210
|
+
</div>
|
|
211
|
+
),
|
|
212
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Icon } from '@iconify/react';
|
|
3
|
+
import { Input } from '../input';
|
|
4
|
+
import { Label } from '../label';
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle } from '../card';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Input> = {
|
|
8
|
+
title: 'UI/Input',
|
|
9
|
+
component: Input,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'centered',
|
|
12
|
+
},
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
argTypes: {
|
|
15
|
+
type: {
|
|
16
|
+
control: 'select',
|
|
17
|
+
options: ['text', 'email', 'password', 'number', 'search', 'tel', 'url'],
|
|
18
|
+
},
|
|
19
|
+
disabled: {
|
|
20
|
+
control: 'boolean',
|
|
21
|
+
description: 'Disables the input',
|
|
22
|
+
},
|
|
23
|
+
isInvalid: {
|
|
24
|
+
control: 'boolean',
|
|
25
|
+
description: 'Shows error state',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
type Story = StoryObj<typeof meta>;
|
|
32
|
+
|
|
33
|
+
export const Default: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
placeholder: 'Enter text...',
|
|
36
|
+
},
|
|
37
|
+
decorators: [
|
|
38
|
+
(Story) => (
|
|
39
|
+
<div className="w-[300px]">
|
|
40
|
+
<Story />
|
|
41
|
+
</div>
|
|
42
|
+
),
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const WithLabel: Story = {
|
|
47
|
+
render: () => (
|
|
48
|
+
<div className="flex w-full max-w-sm flex-col gap-1.5">
|
|
49
|
+
<Label htmlFor="email">Email</Label>
|
|
50
|
+
<Input type="email" id="email" placeholder="Enter your email" />
|
|
51
|
+
</div>
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const WithStartContent: Story = {
|
|
56
|
+
render: () => (
|
|
57
|
+
<div className="w-[300px]">
|
|
58
|
+
<Input
|
|
59
|
+
placeholder="Search..."
|
|
60
|
+
startContent={<Icon icon="gravity-ui:magnifier" className="size-4" />}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const WithEndContent: Story = {
|
|
67
|
+
render: () => (
|
|
68
|
+
<div className="w-[300px]">
|
|
69
|
+
<Input
|
|
70
|
+
type="password"
|
|
71
|
+
placeholder="Enter password"
|
|
72
|
+
endContent={<Icon icon="gravity-ui:eye" className="size-4 cursor-pointer" />}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const WithBothContent: Story = {
|
|
79
|
+
render: () => (
|
|
80
|
+
<div className="w-[300px]">
|
|
81
|
+
<Input
|
|
82
|
+
type="text"
|
|
83
|
+
placeholder="Amount"
|
|
84
|
+
startContent={<span className="text-sm">$</span>}
|
|
85
|
+
endContent={<span className="text-sm">.00</span>}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Invalid: Story = {
|
|
92
|
+
render: () => (
|
|
93
|
+
<div className="flex w-full max-w-sm flex-col gap-1.5">
|
|
94
|
+
<Label htmlFor="email-invalid">Email</Label>
|
|
95
|
+
<Input type="email" id="email-invalid" placeholder="Enter email" isInvalid />
|
|
96
|
+
<p className="text-sm text-danger">Please enter a valid email address.</p>
|
|
97
|
+
</div>
|
|
98
|
+
),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const Disabled: Story = {
|
|
102
|
+
args: {
|
|
103
|
+
placeholder: 'Disabled input',
|
|
104
|
+
disabled: true,
|
|
105
|
+
},
|
|
106
|
+
decorators: [
|
|
107
|
+
(Story) => (
|
|
108
|
+
<div className="w-[300px]">
|
|
109
|
+
<Story />
|
|
110
|
+
</div>
|
|
111
|
+
),
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
export const File: Story = {
|
|
117
|
+
render: () => (
|
|
118
|
+
<div className="flex w-full max-w-sm flex-col gap-1.5">
|
|
119
|
+
<Label htmlFor="file">Upload File</Label>
|
|
120
|
+
<Input id="file" type="file" />
|
|
121
|
+
</div>
|
|
122
|
+
),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const FormExample: Story = {
|
|
126
|
+
render: () => (
|
|
127
|
+
<form className="w-full max-w-sm space-y-4">
|
|
128
|
+
<div className="space-y-1.5">
|
|
129
|
+
<Label htmlFor="name">Full Name</Label>
|
|
130
|
+
<Input id="name" placeholder="John Doe" />
|
|
131
|
+
</div>
|
|
132
|
+
<div className="space-y-1.5">
|
|
133
|
+
<Label htmlFor="form-email">Email</Label>
|
|
134
|
+
<Input
|
|
135
|
+
id="form-email"
|
|
136
|
+
type="email"
|
|
137
|
+
placeholder="john@example.com"
|
|
138
|
+
startContent={<Icon icon="gravity-ui:envelope" className="size-4" />}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
<div className="space-y-1.5">
|
|
142
|
+
<Label htmlFor="phone">Phone</Label>
|
|
143
|
+
<Input
|
|
144
|
+
id="phone"
|
|
145
|
+
type="tel"
|
|
146
|
+
placeholder="+1 (555) 000-0000"
|
|
147
|
+
startContent={<Icon icon="gravity-ui:smartphone" className="size-4" />}
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
</form>
|
|
151
|
+
),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const OnCard: Story = {
|
|
155
|
+
render: () => (
|
|
156
|
+
<Card className="w-[350px]">
|
|
157
|
+
<CardHeader>
|
|
158
|
+
<CardTitle>Contact Info</CardTitle>
|
|
159
|
+
</CardHeader>
|
|
160
|
+
<CardContent className="space-y-4">
|
|
161
|
+
<div className="space-y-1.5">
|
|
162
|
+
<Label htmlFor="card-name">Name</Label>
|
|
163
|
+
<Input id="card-name" placeholder="John Doe" />
|
|
164
|
+
</div>
|
|
165
|
+
<div className="space-y-1.5">
|
|
166
|
+
<Label htmlFor="card-email">Email</Label>
|
|
167
|
+
<Input id="card-email" type="email" placeholder="john@example.com" />
|
|
168
|
+
</div>
|
|
169
|
+
</CardContent>
|
|
170
|
+
</Card>
|
|
171
|
+
),
|
|
172
|
+
};
|