@bearmenu/ui 0.1.1 → 0.5.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.
Files changed (113) hide show
  1. package/dist/{chunk-2CUFS5LF.js → chunk-2BMJRXQX.js} +1 -1
  2. package/dist/chunk-HLQ2IRE7.js +279 -0
  3. package/dist/chunk-IQASCH2V.js +25 -0
  4. package/dist/{chunk-UXAYXRFN.js → chunk-QJ54Z7TC.js} +15 -1
  5. package/dist/{chunk-X6GATUI2.js → chunk-UISA4CIG.js} +1 -0
  6. package/dist/components/alert-dialog.js +1 -1
  7. package/dist/components/button.js +1 -1
  8. package/dist/components/calendar.d.ts +9 -7
  9. package/dist/components/calendar.js +153 -39
  10. package/dist/components/card.d.ts +2 -1
  11. package/dist/components/card.js +1 -1
  12. package/dist/components/carousel.js +1 -1
  13. package/dist/components/checkbox.js +3 -25
  14. package/dist/components/dropdown-menu.js +1 -1
  15. package/dist/components/empty-state.js +1 -1
  16. package/dist/components/haptic-button.js +1 -1
  17. package/dist/components/link-button.js +1 -1
  18. package/dist/components/multi-select-combobox.js +1 -1
  19. package/dist/components/multi-select-menu.d.ts +26 -0
  20. package/dist/components/multi-select-menu.js +71 -0
  21. package/dist/components/pagination.js +1 -1
  22. package/dist/components/phone-frame.d.ts +17 -0
  23. package/dist/components/phone-frame.js +41 -0
  24. package/dist/components/place-about-tab.d.ts +17 -0
  25. package/dist/components/place-about-tab.js +6 -0
  26. package/dist/components/place-card.d.ts +17 -0
  27. package/dist/components/place-card.js +145 -0
  28. package/dist/components/place-details-mobile.d.ts +18 -0
  29. package/dist/components/place-details-mobile.js +187 -0
  30. package/dist/components/place-types.d.ts +145 -0
  31. package/dist/components/place-types.js +1 -0
  32. package/dist/components/search-bar.js +1 -1
  33. package/dist/components/searchable-select.js +1 -1
  34. package/dist/components/skeleton-card.js +1 -1
  35. package/dist/components/skeleton.js +1 -1
  36. package/dist/components/sliding-panels.js +1 -1
  37. package/dist/components/sonner.js +11 -2
  38. package/dist/components/tabs.js +1 -1
  39. package/dist/components/toaster.js +1 -1
  40. package/package.json +28 -9
  41. package/src/components/accordion.stories.tsx +51 -0
  42. package/src/components/alert-dialog.stories.tsx +45 -0
  43. package/src/components/alert.stories.tsx +85 -0
  44. package/src/components/aspect-ratio.stories.tsx +47 -0
  45. package/src/components/avatar.stories.tsx +66 -0
  46. package/src/components/badge.stories.tsx +60 -0
  47. package/src/components/breadcrumb.stories.tsx +63 -0
  48. package/src/components/button.stories.tsx +115 -0
  49. package/src/components/button.tsx +1 -1
  50. package/src/components/calendar.stories.tsx +47 -0
  51. package/src/components/calendar.tsx +160 -40
  52. package/src/components/card.stories.tsx +72 -0
  53. package/src/components/card.tsx +13 -1
  54. package/src/components/carousel.stories.tsx +62 -0
  55. package/src/components/checkbox.stories.tsx +54 -0
  56. package/src/components/checkbox.tsx +1 -1
  57. package/src/components/collapsible.stories.tsx +34 -0
  58. package/src/components/command.stories.tsx +64 -0
  59. package/src/components/currency-input.stories.tsx +50 -0
  60. package/src/components/dialog.stories.tsx +75 -0
  61. package/src/components/drawer.stories.tsx +47 -0
  62. package/src/components/dropdown-menu.stories.tsx +64 -0
  63. package/src/components/dropdown-menu.tsx +1 -1
  64. package/src/components/empty-state.stories.tsx +67 -0
  65. package/src/components/form.stories.tsx +73 -0
  66. package/src/components/haptic-button.stories.tsx +41 -0
  67. package/src/components/input-otp.stories.tsx +42 -0
  68. package/src/components/input.stories.tsx +41 -0
  69. package/src/components/label.stories.tsx +35 -0
  70. package/src/components/markdown-renderer.stories.tsx +45 -0
  71. package/src/components/multi-select-combobox.stories.tsx +78 -0
  72. package/src/components/multi-select-menu.tsx +96 -0
  73. package/src/components/pagination.stories.tsx +48 -0
  74. package/src/components/phone-frame.stories.tsx +51 -0
  75. package/src/components/phone-frame.test.tsx +82 -0
  76. package/src/components/phone-frame.tsx +59 -0
  77. package/src/components/place-about-tab.stories.tsx +164 -0
  78. package/src/components/place-about-tab.test.tsx +325 -0
  79. package/src/components/place-about-tab.tsx +474 -0
  80. package/src/components/place-card.stories.tsx +120 -0
  81. package/src/components/place-card.test.tsx +187 -0
  82. package/src/components/place-card.tsx +187 -0
  83. package/src/components/place-details-mobile.tsx +251 -0
  84. package/src/components/place-types.ts +127 -0
  85. package/src/components/popover.stories.tsx +42 -0
  86. package/src/components/progress.stories.tsx +35 -0
  87. package/src/components/radio-group.stories.tsx +46 -0
  88. package/src/components/rating.stories.tsx +45 -0
  89. package/src/components/scroll-area.stories.tsx +48 -0
  90. package/src/components/search-bar.stories.tsx +92 -0
  91. package/src/components/searchable-select.stories.tsx +55 -0
  92. package/src/components/select.stories.tsx +92 -0
  93. package/src/components/separator.stories.tsx +33 -0
  94. package/src/components/sheet.stories.tsx +95 -0
  95. package/src/components/skeleton-card.stories.tsx +53 -0
  96. package/src/components/skeleton.stories.tsx +42 -0
  97. package/src/components/skeleton.tsx +1 -0
  98. package/src/components/slider.stories.tsx +27 -0
  99. package/src/components/sliding-panels.stories.tsx +68 -0
  100. package/src/components/sonner.tsx +17 -2
  101. package/src/components/sticky-container.stories.tsx +33 -0
  102. package/src/components/switch.stories.tsx +35 -0
  103. package/src/components/table.stories.tsx +60 -0
  104. package/src/components/tabs.stories.tsx +53 -0
  105. package/src/components/tabs.tsx +1 -1
  106. package/src/components/text.stories.tsx +82 -0
  107. package/src/components/textarea.stories.tsx +35 -0
  108. package/src/components/toast.stories.tsx +63 -0
  109. package/src/components/toggle-group.stories.tsx +60 -0
  110. package/src/components/toggle.stories.tsx +48 -0
  111. package/src/components/tooltip.stories.tsx +71 -0
  112. package/src/globals.css +14 -2
  113. package/src/test/setup.ts +9 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Structural mirror of the openapi `Place` schema, decoupled from any one app's
3
+ * generated types. Both FE and admin map their domain shapes into this type
4
+ * before passing data to `<PlaceCard>` / `<PlaceAboutTab>`.
5
+ */
6
+ export type PlacePreview = {
7
+ id: string
8
+ slug: string
9
+ name: string
10
+ description?: string
11
+ generative_summary?: string
12
+ review_summary?: string
13
+ open_now?: boolean
14
+ rating?: { rating: number; count: number }
15
+ review_count?: number
16
+ hours?: PlaceHourBlock[]
17
+ today_schedule?: PlaceHourBlock[]
18
+ location?: {
19
+ address?: string
20
+ geolocation?: { lat: number | string; lon: number | string }
21
+ distance?: { meters?: number }
22
+ }
23
+ price_dishes?: PlacePriceRange
24
+ price_drinks?: PlacePriceRange
25
+ cuisines?: string[]
26
+ amenities?: string[]
27
+ payment_options?: string[]
28
+ accessibility_features?: string[]
29
+ parking_options?: string[]
30
+ landmarks?: Array<{ name: string; distance_meters?: number }>
31
+ areas?: Array<{ name: string }>
32
+ busyness?: Array<{ hour: number; score: number }>
33
+ type?: string
34
+ business_status?: 'operational' | 'closed_temporarily' | 'closed_permanently'
35
+ phone?: string
36
+ website_url?: string
37
+ socials?: { instagram_url?: string; facebook_url?: string }
38
+ /**
39
+ * Pre-resolved thumbnail URL. Callers compute this themselves
40
+ * (FE: `https://cdn.bear.menu/places/${slug}-thumbnail.jpg`,
41
+ * admin: form's primary photo URL or blob URL).
42
+ */
43
+ thumbnail_url?: string
44
+ }
45
+
46
+ export type PlaceHourBlock = { opens_at: number; closes_at: number }
47
+
48
+ export type PlacePriceRange = {
49
+ price_range_low?: number
50
+ price_range_high?: number
51
+ }
52
+
53
+ /** Labels passed to `<PlaceCard>`. All translation happens in the caller. */
54
+ export type PlaceCardLabels = {
55
+ open: string
56
+ closed: string
57
+ until: string
58
+ opensAt: string
59
+ currency: string
60
+ }
61
+
62
+ /**
63
+ * Labels passed to `<PlaceAboutTab>`. All translation happens in the caller.
64
+ *
65
+ * Dynamic suffix maps (`amenityLabels`, etc.) translate API enum values like
66
+ * `wheelchair_accessible_entrance` into human strings. Missing keys fall back
67
+ * to the raw enum value (with underscores → spaces).
68
+ */
69
+ export type PlaceAboutTabLabels = {
70
+ overview: string
71
+ description: string
72
+ whatPeopleSay: string
73
+ contactAndLocation: string
74
+ address: string
75
+ instagram: string
76
+ facebook: string
77
+ todayHours: string
78
+ statusOpen: string
79
+ statusClosed: string
80
+ typicalBusyness: string
81
+ cuisines: string
82
+ amenities: string
83
+ paymentOptions: string
84
+ accessibility: string
85
+ parking: string
86
+ nearbyLandmarks: string
87
+ neighborhood: string
88
+ businessInformation: string
89
+ type: string
90
+ status: string
91
+ amenityLabels: Record<string, string>
92
+ paymentLabels: Record<string, string>
93
+ accessibilityLabels: Record<string, string>
94
+ parkingLabels: Record<string, string>
95
+ typeLabels: Record<string, string>
96
+ statusLabels: Record<string, string>
97
+ }
98
+
99
+ /** Discriminator for `<PlaceAboutTab>`'s `onLinkClick` callback. */
100
+ export type PlaceLinkKind = 'phone' | 'website' | 'instagram' | 'facebook' | 'address'
101
+
102
+ /**
103
+ * Labels passed to `<PlaceDetailsMobile>`. Extends `PlaceAboutTabLabels` with
104
+ * the header/tab-strip strings unique to the mobile place-details surface.
105
+ */
106
+ export type PlaceDetailsMobileLabels = PlaceAboutTabLabels & {
107
+ /** Tab strip — "About" is highlighted, the rest are visual placeholders. */
108
+ tabs: {
109
+ menu: string
110
+ about: string
111
+ reviews: string
112
+ events: string
113
+ }
114
+ /** Status badge over the hero image and the inline open/closed pill in the info row. */
115
+ statusBadge: {
116
+ openNow: string
117
+ closed: string
118
+ /** Inserted with surrounding " · " separators. e.g. "Closes at" */
119
+ closesAt: string
120
+ opensAt: string
121
+ opensTomorrow: string
122
+ }
123
+ /** Review count formatter. Pass a translator that handles ICU pluralization. */
124
+ reviewCount: (count: number) => string
125
+ /** "No image available" fallback shown when no thumbnail is set. */
126
+ noImageAvailable: string
127
+ }
@@ -0,0 +1,42 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover";
3
+ import { Button } from "./button";
4
+ import { Input } from "./input";
5
+ import { Label } from "./label";
6
+
7
+ const meta = {
8
+ title: "Components/Popover",
9
+ component: Popover,
10
+ tags: ["autodocs"],
11
+ } satisfies Meta<typeof Popover>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Default: Story = {
17
+ render: () => (
18
+ <Popover>
19
+ <PopoverTrigger asChild>
20
+ <Button variant="outline">Open Popover</Button>
21
+ </PopoverTrigger>
22
+ <PopoverContent>
23
+ <div className="grid gap-4">
24
+ <div className="space-y-2">
25
+ <h4 className="font-medium leading-none">Dimensions</h4>
26
+ <p className="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
27
+ </div>
28
+ <div className="grid gap-2">
29
+ <div className="grid grid-cols-3 items-center gap-4">
30
+ <Label htmlFor="width">Width</Label>
31
+ <Input id="width" defaultValue="100%" className="col-span-2 h-8" />
32
+ </div>
33
+ <div className="grid grid-cols-3 items-center gap-4">
34
+ <Label htmlFor="height">Height</Label>
35
+ <Input id="height" defaultValue="25px" className="col-span-2 h-8" />
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </PopoverContent>
40
+ </Popover>
41
+ ),
42
+ };
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Progress } from "./progress";
3
+
4
+ const meta = {
5
+ title: "Components/Progress",
6
+ component: Progress,
7
+ tags: ["autodocs"],
8
+ } satisfies Meta<typeof Progress>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ render: () => <Progress value={60} className="w-[300px]" />,
15
+ };
16
+
17
+ export const Empty: Story = {
18
+ render: () => <Progress value={0} className="w-[300px]" />,
19
+ };
20
+
21
+ export const Full: Story = {
22
+ render: () => <Progress value={100} className="w-[300px]" />,
23
+ };
24
+
25
+ export const AllStates: Story = {
26
+ render: () => (
27
+ <div className="flex flex-col gap-4 w-[300px]">
28
+ <Progress value={0} />
29
+ <Progress value={25} />
30
+ <Progress value={50} />
31
+ <Progress value={75} />
32
+ <Progress value={100} />
33
+ </div>
34
+ ),
35
+ };
@@ -0,0 +1,46 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { RadioGroup, RadioGroupItem } from "./radio-group";
3
+ import { Label } from "./label";
4
+
5
+ const meta = {
6
+ title: "Components/RadioGroup",
7
+ component: RadioGroup,
8
+ tags: ["autodocs"],
9
+ } satisfies Meta<typeof RadioGroup>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ export const Default: Story = {
15
+ render: () => (
16
+ <RadioGroup defaultValue="option-1">
17
+ <div className="flex items-center space-x-2">
18
+ <RadioGroupItem value="option-1" id="r1" />
19
+ <Label htmlFor="r1">Option One</Label>
20
+ </div>
21
+ <div className="flex items-center space-x-2">
22
+ <RadioGroupItem value="option-2" id="r2" />
23
+ <Label htmlFor="r2">Option Two</Label>
24
+ </div>
25
+ <div className="flex items-center space-x-2">
26
+ <RadioGroupItem value="option-3" id="r3" />
27
+ <Label htmlFor="r3">Option Three</Label>
28
+ </div>
29
+ </RadioGroup>
30
+ ),
31
+ };
32
+
33
+ export const Disabled: Story = {
34
+ render: () => (
35
+ <RadioGroup defaultValue="option-1" disabled>
36
+ <div className="flex items-center space-x-2">
37
+ <RadioGroupItem value="option-1" id="rd1" />
38
+ <Label htmlFor="rd1">Disabled selected</Label>
39
+ </div>
40
+ <div className="flex items-center space-x-2">
41
+ <RadioGroupItem value="option-2" id="rd2" />
42
+ <Label htmlFor="rd2">Disabled unselected</Label>
43
+ </div>
44
+ </RadioGroup>
45
+ ),
46
+ };
@@ -0,0 +1,45 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Rating } from "./rating";
3
+
4
+ const meta = {
5
+ title: "Components/Rating",
6
+ component: Rating,
7
+ tags: ["autodocs"],
8
+ } satisfies Meta<typeof Rating>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ render: () => <Rating value={4} reviewCount={128} />,
15
+ };
16
+
17
+ export const HalfStar: Story = {
18
+ render: () => <Rating value={3.5} reviewCount={42} />,
19
+ };
20
+
21
+ export const Sizes: Story = {
22
+ render: () => (
23
+ <div className="flex flex-col gap-3">
24
+ <Rating value={4} size="sm" reviewCount={10} />
25
+ <Rating value={4} size="md" reviewCount={10} />
26
+ <Rating value={4} size="lg" reviewCount={10} />
27
+ </div>
28
+ ),
29
+ };
30
+
31
+ export const NoCount: Story = {
32
+ render: () => <Rating value={5} showCount={false} />,
33
+ };
34
+
35
+ export const AllRatings: Story = {
36
+ render: () => (
37
+ <div className="flex flex-col gap-2">
38
+ <Rating value={1} reviewCount={5} />
39
+ <Rating value={2} reviewCount={12} />
40
+ <Rating value={3} reviewCount={34} />
41
+ <Rating value={4} reviewCount={89} />
42
+ <Rating value={5} reviewCount={201} />
43
+ </div>
44
+ ),
45
+ };
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { ScrollArea, ScrollBar } from "./scroll-area";
3
+ import { Separator } from "./separator";
4
+
5
+ const meta = {
6
+ title: "Components/ScrollArea",
7
+ component: ScrollArea,
8
+ tags: ["autodocs"],
9
+ } satisfies Meta<typeof ScrollArea>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ const tags = Array.from({ length: 50 }).map((_, i) => `Item ${i + 1}`);
15
+
16
+ export const Vertical: Story = {
17
+ render: () => (
18
+ <ScrollArea className="h-72 w-48 rounded-md border">
19
+ <div className="p-4">
20
+ <h4 className="mb-4 text-sm font-medium leading-none">Items</h4>
21
+ {tags.map((tag) => (
22
+ <div key={tag}>
23
+ <div className="text-sm">{tag}</div>
24
+ <Separator className="my-2" />
25
+ </div>
26
+ ))}
27
+ </div>
28
+ </ScrollArea>
29
+ ),
30
+ };
31
+
32
+ export const Horizontal: Story = {
33
+ render: () => (
34
+ <ScrollArea className="w-96 whitespace-nowrap rounded-md border">
35
+ <div className="flex w-max space-x-4 p-4">
36
+ {Array.from({ length: 20 }).map((_, i) => (
37
+ <div
38
+ key={i}
39
+ className="w-[150px] shrink-0 rounded-md border p-4 text-center text-sm"
40
+ >
41
+ Card {i + 1}
42
+ </div>
43
+ ))}
44
+ </div>
45
+ <ScrollBar orientation="horizontal" />
46
+ </ScrollArea>
47
+ ),
48
+ };
@@ -0,0 +1,92 @@
1
+ import { useState } from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { SearchBar } from "./search-bar";
4
+
5
+ const meta = {
6
+ title: "Components/SearchBar",
7
+ component: SearchBar,
8
+ tags: ["autodocs"],
9
+ } satisfies Meta<typeof SearchBar>;
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof meta>;
13
+
14
+ function SearchBarDemo() {
15
+ const [value, setValue] = useState("");
16
+ return <SearchBar value={value} onChange={setValue} placeholder="Search restaurants..." />;
17
+ }
18
+
19
+ export const Default: Story = {
20
+ render: () => <SearchBarDemo />,
21
+ };
22
+
23
+ export const Editorial: Story = {
24
+ render: () => {
25
+ const [value, setValue] = useState("");
26
+ return (
27
+ <SearchBar
28
+ value={value}
29
+ onChange={setValue}
30
+ variant="editorial"
31
+ placeholder="Search..."
32
+ className="w-[400px]"
33
+ />
34
+ );
35
+ },
36
+ };
37
+
38
+ export const Primary: Story = {
39
+ render: () => {
40
+ const [value, setValue] = useState("");
41
+ return (
42
+ <SearchBar
43
+ value={value}
44
+ onChange={setValue}
45
+ variant="primary"
46
+ placeholder="Search..."
47
+ className="w-[400px]"
48
+ />
49
+ );
50
+ },
51
+ };
52
+
53
+ export const Secondary: Story = {
54
+ render: () => {
55
+ const [value, setValue] = useState("");
56
+ return (
57
+ <SearchBar
58
+ value={value}
59
+ onChange={setValue}
60
+ variant="secondary"
61
+ placeholder="Search..."
62
+ className="w-[400px]"
63
+ />
64
+ );
65
+ },
66
+ };
67
+
68
+ export const Compact: Story = {
69
+ render: () => {
70
+ const [value, setValue] = useState("");
71
+ return (
72
+ <SearchBar
73
+ value={value}
74
+ onChange={setValue}
75
+ size="compact"
76
+ placeholder="Quick search..."
77
+ className="w-[300px]"
78
+ />
79
+ );
80
+ },
81
+ };
82
+
83
+ export const Searching: Story = {
84
+ render: () => (
85
+ <SearchBar
86
+ value="pizza"
87
+ isSearching
88
+ placeholder="Search..."
89
+ className="w-[400px]"
90
+ />
91
+ ),
92
+ };
@@ -0,0 +1,55 @@
1
+ import { useState } from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { SearchableSelect } from "./searchable-select";
4
+ import { Label } from "./label";
5
+
6
+ const meta = {
7
+ title: "Components/SearchableSelect",
8
+ component: SearchableSelect,
9
+ tags: ["autodocs"],
10
+ } satisfies Meta<typeof SearchableSelect>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ const frameworks = [
16
+ { value: "next", label: "Next.js", description: "The React Framework" },
17
+ { value: "remix", label: "Remix", description: "Full Stack Web Framework" },
18
+ { value: "astro", label: "Astro", description: "Content-first Framework" },
19
+ { value: "nuxt", label: "Nuxt", description: "The Intuitive Vue Framework" },
20
+ { value: "svelte", label: "SvelteKit", description: "Web development, streamlined" },
21
+ ];
22
+
23
+ function SearchableSelectDemo() {
24
+ const [value, setValue] = useState<string | undefined>();
25
+ return (
26
+ <div className="w-[300px] space-y-2">
27
+ <Label>Framework</Label>
28
+ <SearchableSelect
29
+ options={frameworks}
30
+ value={value}
31
+ onValueChange={setValue}
32
+ placeholder="Select a framework..."
33
+ searchPlaceholder="Search frameworks..."
34
+ />
35
+ </div>
36
+ );
37
+ }
38
+
39
+ export const Default: Story = {
40
+ render: () => <SearchableSelectDemo />,
41
+ };
42
+
43
+ export const Disabled: Story = {
44
+ render: () => (
45
+ <div className="w-[300px]">
46
+ <SearchableSelect
47
+ options={frameworks}
48
+ value={undefined}
49
+ onValueChange={() => {}}
50
+ disabled
51
+ placeholder="Disabled..."
52
+ />
53
+ </div>
54
+ ),
55
+ };
@@ -0,0 +1,92 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectGroup,
6
+ SelectItem,
7
+ SelectLabel,
8
+ SelectSeparator,
9
+ SelectTrigger,
10
+ SelectValue,
11
+ } from "./select";
12
+ import { Label } from "./label";
13
+
14
+ const meta = {
15
+ title: "Components/Select",
16
+ tags: ["autodocs"],
17
+ component: Select,
18
+ } satisfies Meta<typeof Select>;
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Default: Story = {
24
+ render: () => (
25
+ <Select>
26
+ <SelectTrigger className="w-[200px]">
27
+ <SelectValue placeholder="Select a fruit" />
28
+ </SelectTrigger>
29
+ <SelectContent>
30
+ <SelectItem value="apple">Apple</SelectItem>
31
+ <SelectItem value="banana">Banana</SelectItem>
32
+ <SelectItem value="cherry">Cherry</SelectItem>
33
+ <SelectItem value="grape">Grape</SelectItem>
34
+ </SelectContent>
35
+ </Select>
36
+ ),
37
+ };
38
+
39
+ export const WithLabel: Story = {
40
+ render: () => (
41
+ <div className="grid gap-1.5">
42
+ <Label>Country</Label>
43
+ <Select>
44
+ <SelectTrigger className="w-[200px]">
45
+ <SelectValue placeholder="Select country" />
46
+ </SelectTrigger>
47
+ <SelectContent>
48
+ <SelectItem value="us">United States</SelectItem>
49
+ <SelectItem value="uk">United Kingdom</SelectItem>
50
+ <SelectItem value="ro">Romania</SelectItem>
51
+ <SelectItem value="de">Germany</SelectItem>
52
+ </SelectContent>
53
+ </Select>
54
+ </div>
55
+ ),
56
+ };
57
+
58
+ export const WithGroups: Story = {
59
+ render: () => (
60
+ <Select>
61
+ <SelectTrigger className="w-[200px]">
62
+ <SelectValue placeholder="Select a food" />
63
+ </SelectTrigger>
64
+ <SelectContent>
65
+ <SelectGroup>
66
+ <SelectLabel>Fruits</SelectLabel>
67
+ <SelectItem value="apple">Apple</SelectItem>
68
+ <SelectItem value="banana">Banana</SelectItem>
69
+ </SelectGroup>
70
+ <SelectSeparator />
71
+ <SelectGroup>
72
+ <SelectLabel>Vegetables</SelectLabel>
73
+ <SelectItem value="carrot">Carrot</SelectItem>
74
+ <SelectItem value="broccoli">Broccoli</SelectItem>
75
+ </SelectGroup>
76
+ </SelectContent>
77
+ </Select>
78
+ ),
79
+ };
80
+
81
+ export const Disabled: Story = {
82
+ render: () => (
83
+ <Select disabled>
84
+ <SelectTrigger className="w-[200px]">
85
+ <SelectValue placeholder="Disabled" />
86
+ </SelectTrigger>
87
+ <SelectContent>
88
+ <SelectItem value="a">Option A</SelectItem>
89
+ </SelectContent>
90
+ </Select>
91
+ ),
92
+ };
@@ -0,0 +1,33 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Separator } from "./separator";
3
+
4
+ const meta = {
5
+ title: "Components/Separator",
6
+ component: Separator,
7
+ tags: ["autodocs"],
8
+ } satisfies Meta<typeof Separator>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Horizontal: Story = {
14
+ render: () => (
15
+ <div className="w-[300px]">
16
+ <p className="text-sm text-foreground">Section one</p>
17
+ <Separator className="my-4" />
18
+ <p className="text-sm text-foreground">Section two</p>
19
+ </div>
20
+ ),
21
+ };
22
+
23
+ export const Vertical: Story = {
24
+ render: () => (
25
+ <div className="flex items-center gap-4 h-8">
26
+ <span className="text-sm">Item 1</span>
27
+ <Separator orientation="vertical" />
28
+ <span className="text-sm">Item 2</span>
29
+ <Separator orientation="vertical" />
30
+ <span className="text-sm">Item 3</span>
31
+ </div>
32
+ ),
33
+ };