@syscore/ui-library 1.1.9 → 1.1.11

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 (141) hide show
  1. package/client/App.tsx +47 -0
  2. package/client/components/icons/ConceptIcons.tsx +667 -0
  3. package/client/components/icons/NavAccount.tsx +31 -0
  4. package/client/components/icons/NavBullet.tsx +19 -0
  5. package/client/components/icons/NavLogo.tsx +36 -0
  6. package/client/components/icons/ProviderBadges.tsx +295 -0
  7. package/client/components/icons/ProviderSeals.tsx +319 -0
  8. package/client/components/icons/SealHealthSafetyRating.tsx +65 -0
  9. package/client/components/icons/SealIwbiMember.tsx +86 -0
  10. package/client/components/icons/SealWell.tsx +84 -0
  11. package/client/components/icons/SealWellCertification.tsx +138 -0
  12. package/client/components/icons/SealWellCommunity.tsx +122 -0
  13. package/client/components/icons/SealWellResidence.tsx +122 -0
  14. package/client/components/icons/SealWorksWithWell.tsx +140 -0
  15. package/client/components/icons/UtilityAccordion.tsx +21 -0
  16. package/client/components/icons/UtilityChevronDown.tsx +36 -0
  17. package/client/components/icons/UtilityClassification.tsx +45 -0
  18. package/client/components/icons/UtilityClose.tsx +41 -0
  19. package/client/components/icons/UtilityDrag.tsx +69 -0
  20. package/client/components/icons/UtilityEdit.tsx +42 -0
  21. package/client/components/icons/UtilityOptions.tsx +45 -0
  22. package/client/components/icons/UtilityPortfolio.tsx +87 -0
  23. package/client/components/icons/UtilityReset.tsx +41 -0
  24. package/client/components/icons/UtilityScoring.tsx +43 -0
  25. package/client/components/icons/UtilitySearch.tsx +38 -0
  26. package/client/components/icons/UtilitySort.tsx +52 -0
  27. package/client/components/icons/UtilityText.tsx +34 -0
  28. package/client/components/icons/WaterMarkWWWProducts.tsx +26 -0
  29. package/client/components/icons/WaterMarkWellProjects.tsx +30 -0
  30. package/client/components/icons/WatermarkMemberOrg.tsx +59 -0
  31. package/client/components/icons/WellSeal.tsx +79 -0
  32. package/client/components/icons/X.tsx +35 -0
  33. package/client/components/ui/Navigation.tsx +958 -0
  34. package/client/components/ui/SearchField.tsx +157 -0
  35. package/client/components/ui/StrategyTable.tsx +303 -0
  36. package/client/components/ui/Tag.tsx +127 -0
  37. package/client/components/ui/alert-dialog.tsx +1 -1
  38. package/client/components/ui/button.tsx +67 -127
  39. package/client/components/ui/calendar.tsx +2 -2
  40. package/client/components/ui/card.tsx +10 -13
  41. package/client/components/ui/carousel.tsx +56 -46
  42. package/client/components/ui/command.tsx +27 -16
  43. package/client/components/ui/dialog.tsx +113 -92
  44. package/client/components/ui/label.tsx +5 -3
  45. package/client/components/ui/menubar.tsx +1 -1
  46. package/client/components/ui/pagination.tsx +3 -3
  47. package/client/components/ui/sidebar.tsx +1 -1
  48. package/client/components/ui/tabs.tsx +350 -5
  49. package/client/components/ui/toggle.tsx +71 -19
  50. package/client/components/ui/tooltip.tsx +69 -18
  51. package/client/global.css +635 -58
  52. package/client/hooks/UseTabs.tsx +35 -0
  53. package/client/hooks/use-mobile.tsx +21 -0
  54. package/client/hooks/use-segmented-control.ts +42 -0
  55. package/client/hooks/use-toast.ts +188 -0
  56. package/client/pages/Index.tsx +88 -0
  57. package/client/pages/NotFound.tsx +29 -0
  58. package/client/ui/Accordion/Accordion.stories.tsx +74 -0
  59. package/client/ui/Alert/Alert.stories.tsx +82 -0
  60. package/client/ui/AlertDialog/AlertDialog.stories.tsx +106 -0
  61. package/client/ui/AspectRatio.stories.tsx +78 -0
  62. package/client/ui/Avatar/Avatar.stories.tsx +94 -0
  63. package/client/ui/Badge/Badge.stories.tsx +60 -0
  64. package/client/ui/Breadcrumb/Breadcrumb.stories.tsx +97 -0
  65. package/client/ui/Button.stories.tsx +429 -0
  66. package/client/ui/Calendar/Calendar.stories.tsx +99 -0
  67. package/client/ui/Card.stories.tsx +84 -0
  68. package/client/ui/Carousel/Carousel.stories.tsx +85 -0
  69. package/client/ui/Chart/Chart.stories.tsx +58 -0
  70. package/client/ui/Checkbox/Checkbox.stories.tsx +112 -0
  71. package/client/ui/Collapsible/Collapsible.stories.tsx +101 -0
  72. package/client/ui/Colors.stories.tsx +1041 -0
  73. package/client/ui/Command/Command.stories.tsx +97 -0
  74. package/client/ui/ContextMenu/ContextMenu.stories.tsx +74 -0
  75. package/client/ui/Dialog.stories.tsx +69 -0
  76. package/client/ui/Drawer/Drawer.stories.tsx +87 -0
  77. package/client/ui/DropdownMenu/DropdownMenu.stories.tsx +139 -0
  78. package/client/ui/Form/Form.stories.tsx +74 -0
  79. package/client/ui/HoverCard/HoverCard.stories.tsx +94 -0
  80. package/client/ui/Icons.stories.tsx +328 -0
  81. package/client/ui/Input/Input.stories.tsx +69 -0
  82. package/client/ui/InputOTP/InputOTP.stories.tsx +85 -0
  83. package/client/ui/Label.stories.tsx +66 -0
  84. package/client/ui/Menubar/Menubar.stories.tsx +88 -0
  85. package/client/ui/Navigation.stories.tsx +57 -0
  86. package/client/ui/NavigationMenu/NavigationMenu.stories.tsx +106 -0
  87. package/client/ui/Pagination/Pagination.stories.tsx +115 -0
  88. package/client/ui/Popover/Popover.stories.tsx +99 -0
  89. package/client/ui/Progress/Progress.stories.tsx +63 -0
  90. package/client/ui/RadioGroup/RadioGroup.stories.tsx +110 -0
  91. package/client/ui/Resizable/Resizable.stories.tsx +88 -0
  92. package/client/ui/ScrollArea/ScrollArea.stories.tsx +64 -0
  93. package/client/ui/SearchField.stories.tsx +63 -0
  94. package/client/ui/Select/Select.stories.tsx +111 -0
  95. package/client/ui/Separator/Separator.stories.tsx +67 -0
  96. package/client/ui/Sheet/Sheet.stories.tsx +138 -0
  97. package/client/ui/Sidebar/Sidebar.stories.tsx +92 -0
  98. package/client/ui/Skeleton/Skeleton.stories.tsx +65 -0
  99. package/client/ui/Slider/Slider.stories.tsx +101 -0
  100. package/client/ui/Sonner/Sonner.stories.tsx +48 -0
  101. package/client/ui/StrategyTable.stories.tsx +138 -0
  102. package/client/ui/Switch/Switch.stories.tsx +96 -0
  103. package/client/ui/Table/Table.stories.tsx +135 -0
  104. package/client/ui/Tabs.stories.tsx +33 -0
  105. package/client/ui/Tag.stories.tsx +190 -0
  106. package/client/ui/Textarea/Textarea.stories.tsx +56 -0
  107. package/client/ui/Toast/Toast.stories.tsx +76 -0
  108. package/client/ui/Toaster/Toaster.stories.tsx +52 -0
  109. package/client/ui/Toggle.stories.tsx +248 -0
  110. package/client/ui/ToggleGroup/ToggleGroup.stories.tsx +88 -0
  111. package/client/ui/Tooltip.stories.tsx +72 -0
  112. package/client/ui/Typography.stories.tsx +421 -0
  113. package/client/ui/WELLDashboard/WELLDashboard.stories.tsx +115 -0
  114. package/client/ui/WELLDashboard/index.tsx +221 -0
  115. package/client/vite-env.d.ts +1 -0
  116. package/dist/ui/fonts/FT-Made/FTMade-Regular.otf +0 -0
  117. package/dist/ui/fonts/FT-Made/FTMade-Regular.ttf +0 -0
  118. package/dist/ui/fonts/FT-Made/FTMade-Regular.woff +0 -0
  119. package/dist/ui/fonts/FT-Made/FTMade-Regular.woff2 +0 -0
  120. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-black.otf +0 -0
  121. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-blackitalic.otf +0 -0
  122. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-bold.otf +0 -0
  123. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-bolditalic.otf +0 -0
  124. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extrabold.otf +0 -0
  125. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extrabolditalic.otf +0 -0
  126. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extralight.otf +0 -0
  127. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extralightitalic.otf +0 -0
  128. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-italic.otf +0 -0
  129. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-light.otf +0 -0
  130. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-lightitalic.otf +0 -0
  131. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-medium.otf +0 -0
  132. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-mediumitalic.otf +0 -0
  133. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-regular.otf +0 -0
  134. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-semibold.otf +0 -0
  135. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-semibolditalic.otf +0 -0
  136. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-thin.otf +0 -0
  137. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-thinitalic.otf +0 -0
  138. package/dist/ui/index.cjs.js +1 -1
  139. package/dist/ui/index.d.ts +2 -1
  140. package/dist/ui/index.es.js +563 -329
  141. package/package.json +4 -2
@@ -0,0 +1,35 @@
1
+ import { useState, useCallback } from "react";
2
+
3
+ export type Tab = {
4
+ label: string;
5
+ value: string;
6
+ subRoutes?: unknown;
7
+ };
8
+
9
+ interface UseTabsProps {
10
+ tabs: Tab[];
11
+ initialTabId: string;
12
+ }
13
+
14
+ export function useTabs({ tabs, initialTabId }: UseTabsProps) {
15
+ const initialIndex = tabs.findIndex((tab) => tab.value === initialTabId);
16
+ const [selectedTabIndex, setSelectedTabIndex] = useState(
17
+ initialIndex >= 0 ? initialIndex : 0
18
+ );
19
+
20
+ const setSelectedTab = useCallback(([index, direction]: [number, number]) => {
21
+ setSelectedTabIndex(index);
22
+ }, []);
23
+
24
+ const selectedTab = tabs[selectedTabIndex] || tabs[0];
25
+
26
+ return {
27
+ tabProps: {
28
+ tabs,
29
+ selectedTabIndex,
30
+ setSelectedTab,
31
+ },
32
+ selectedTab,
33
+ };
34
+ }
35
+
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
7
+ undefined,
8
+ );
9
+
10
+ React.useEffect(() => {
11
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12
+ const onChange = () => {
13
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
+ };
15
+ mql.addEventListener("change", onChange);
16
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17
+ return () => mql.removeEventListener("change", onChange);
18
+ }, []);
19
+
20
+ return !!isMobile;
21
+ }
@@ -0,0 +1,42 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+
3
+ export interface UseSegmentedControlOptions<T extends string> {
4
+ value?: T;
5
+ defaultValue?: T;
6
+ onValueChange?: (value: T) => void;
7
+ }
8
+
9
+ export function useSegmentedControl<T extends string>({
10
+ value,
11
+ defaultValue,
12
+ onValueChange,
13
+ }: UseSegmentedControlOptions<T>) {
14
+ const [internalValue, setInternalValue] = useState<T | undefined>(
15
+ value ?? defaultValue,
16
+ );
17
+
18
+ // Sync with controlled value
19
+ useEffect(() => {
20
+ if (value !== undefined) {
21
+ setInternalValue(value);
22
+ }
23
+ }, [value]);
24
+
25
+ const handleValueChange = useCallback(
26
+ (newValue: T) => {
27
+ if (value === undefined) {
28
+ setInternalValue(newValue);
29
+ }
30
+ onValueChange?.(newValue);
31
+ },
32
+ [value, onValueChange],
33
+ );
34
+
35
+ const currentValue = value ?? internalValue;
36
+
37
+ return {
38
+ value: currentValue,
39
+ onValueChange: handleValueChange,
40
+ };
41
+ }
42
+
@@ -0,0 +1,188 @@
1
+ import * as React from "react";
2
+
3
+ import type { ToastActionElement, ToastProps } from "@/components/ui/toast";
4
+
5
+ const TOAST_LIMIT = 1;
6
+ const TOAST_REMOVE_DELAY = 1000000;
7
+
8
+ type ToasterToast = ToastProps & {
9
+ id: string;
10
+ title?: React.ReactNode;
11
+ description?: React.ReactNode;
12
+ action?: ToastActionElement;
13
+ };
14
+
15
+ const actionTypes = {
16
+ ADD_TOAST: "ADD_TOAST",
17
+ UPDATE_TOAST: "UPDATE_TOAST",
18
+ DISMISS_TOAST: "DISMISS_TOAST",
19
+ REMOVE_TOAST: "REMOVE_TOAST",
20
+ } as const;
21
+
22
+ let count = 0;
23
+
24
+ function genId() {
25
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
26
+ return count.toString();
27
+ }
28
+
29
+ type ActionType = typeof actionTypes;
30
+
31
+ type Action =
32
+ | {
33
+ type: ActionType["ADD_TOAST"];
34
+ toast: ToasterToast;
35
+ }
36
+ | {
37
+ type: ActionType["UPDATE_TOAST"];
38
+ toast: Partial<ToasterToast>;
39
+ }
40
+ | {
41
+ type: ActionType["DISMISS_TOAST"];
42
+ toastId?: ToasterToast["id"];
43
+ }
44
+ | {
45
+ type: ActionType["REMOVE_TOAST"];
46
+ toastId?: ToasterToast["id"];
47
+ };
48
+
49
+ interface State {
50
+ toasts: ToasterToast[];
51
+ }
52
+
53
+ const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
54
+
55
+ const addToRemoveQueue = (toastId: string) => {
56
+ if (toastTimeouts.has(toastId)) {
57
+ return;
58
+ }
59
+
60
+ const timeout = setTimeout(() => {
61
+ toastTimeouts.delete(toastId);
62
+ dispatch({
63
+ type: "REMOVE_TOAST",
64
+ toastId: toastId,
65
+ });
66
+ }, TOAST_REMOVE_DELAY);
67
+
68
+ toastTimeouts.set(toastId, timeout);
69
+ };
70
+
71
+ export const reducer = (state: State, action: Action): State => {
72
+ switch (action.type) {
73
+ case "ADD_TOAST":
74
+ return {
75
+ ...state,
76
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
77
+ };
78
+
79
+ case "UPDATE_TOAST":
80
+ return {
81
+ ...state,
82
+ toasts: state.toasts.map((t) =>
83
+ t.id === action.toast.id ? { ...t, ...action.toast } : t,
84
+ ),
85
+ };
86
+
87
+ case "DISMISS_TOAST": {
88
+ const { toastId } = action;
89
+
90
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
91
+ // but I'll keep it here for simplicity
92
+ if (toastId) {
93
+ addToRemoveQueue(toastId);
94
+ } else {
95
+ state.toasts.forEach((toast) => {
96
+ addToRemoveQueue(toast.id);
97
+ });
98
+ }
99
+
100
+ return {
101
+ ...state,
102
+ toasts: state.toasts.map((t) =>
103
+ t.id === toastId || toastId === undefined
104
+ ? {
105
+ ...t,
106
+ open: false,
107
+ }
108
+ : t,
109
+ ),
110
+ };
111
+ }
112
+ case "REMOVE_TOAST":
113
+ if (action.toastId === undefined) {
114
+ return {
115
+ ...state,
116
+ toasts: [],
117
+ };
118
+ }
119
+ return {
120
+ ...state,
121
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
122
+ };
123
+ }
124
+ };
125
+
126
+ const listeners: Array<(state: State) => void> = [];
127
+
128
+ let memoryState: State = { toasts: [] };
129
+
130
+ function dispatch(action: Action) {
131
+ memoryState = reducer(memoryState, action);
132
+ listeners.forEach((listener) => {
133
+ listener(memoryState);
134
+ });
135
+ }
136
+
137
+ type Toast = Omit<ToasterToast, "id">;
138
+
139
+ function toast({ ...props }: Toast) {
140
+ const id = genId();
141
+
142
+ const update = (props: ToasterToast) =>
143
+ dispatch({
144
+ type: "UPDATE_TOAST",
145
+ toast: { ...props, id },
146
+ });
147
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
148
+
149
+ dispatch({
150
+ type: "ADD_TOAST",
151
+ toast: {
152
+ ...props,
153
+ id,
154
+ open: true,
155
+ onOpenChange: (open) => {
156
+ if (!open) dismiss();
157
+ },
158
+ },
159
+ });
160
+
161
+ return {
162
+ id: id,
163
+ dismiss,
164
+ update,
165
+ };
166
+ }
167
+
168
+ function useToast() {
169
+ const [state, setState] = React.useState<State>(memoryState);
170
+
171
+ React.useEffect(() => {
172
+ listeners.push(setState);
173
+ return () => {
174
+ const index = listeners.indexOf(setState);
175
+ if (index > -1) {
176
+ listeners.splice(index, 1);
177
+ }
178
+ };
179
+ }, [state]);
180
+
181
+ return {
182
+ ...state,
183
+ toast,
184
+ dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
185
+ };
186
+ }
187
+
188
+ export { useToast, toast };
@@ -0,0 +1,88 @@
1
+ import { useMemo } from "react";
2
+ import { Button } from "../ui/Button";
3
+
4
+ export default function Index() {
5
+ const commands = useMemo(
6
+ () => [
7
+ { label: "Start Storybook", cmd: "pnpm storybook" },
8
+ { label: "Build UI library", cmd: "pnpm build:ui" },
9
+ ],
10
+ [],
11
+ );
12
+
13
+ return (
14
+ <div className="min-h-screen bg-[radial-gradient(60%_80%_at_50%_-20%,hsl(252_95%_90%/.6),transparent_70%),linear-gradient(to_bottom_right,hsl(258_90%_98%),hsl(240_20%_98%))]">
15
+ <section className="px-6 py-20 md:py-28">
16
+ <div className="mx-auto max-w-6xl text-center">
17
+ <span className="inline-flex items-center gap-2 rounded-full bg-violet-100 px-3 py-1 text-xs font-semibold text-violet-700 ring-1 ring-inset ring-violet-200">
18
+ React UI Library
19
+ </span>
20
+ <h1 className="mt-6 text-4xl font-extrabold tracking-tight text-foreground sm:text-5xl">
21
+ Elegant, composable components for modern apps
22
+ </h1>
23
+ <p className="mx-auto mt-4 max-w-2xl text-muted-foreground">
24
+ View and develop components in Storybook. Ship a reusable package
25
+ you can import like any other React library.
26
+ </p>
27
+ <div className="mt-8 flex flex-wrap items-center justify-center gap-3">
28
+ <Button size="lg" className="shadow-lg">
29
+ Open Storybook
30
+ </Button>
31
+ <Button variant="secondary" size="lg">
32
+ Install Library
33
+ </Button>
34
+ </div>
35
+ <div className="mx-auto mt-10 grid max-w-3xl grid-cols-1 gap-3 text-left sm:grid-cols-2">
36
+ {commands.map((c) => (
37
+ <div
38
+ key={c.cmd}
39
+ className="rounded-lg border bg-card/70 p-4 shadow-xs backdrop-blur-sm"
40
+ >
41
+ <p className="text-xs font-semibold text-muted-foreground">
42
+ {c.label}
43
+ </p>
44
+ <code className="mt-1 block select-all rounded-md bg-foreground/95 px-3 py-2 font-mono text-[12px] text-background">
45
+ {c.cmd}
46
+ </code>
47
+ </div>
48
+ ))}
49
+ </div>
50
+ </div>
51
+ </section>
52
+
53
+ <section className="px-6 pb-24">
54
+ <div className="mx-auto max-w-6xl">
55
+ <div className="mb-6 flex items-end justify-between">
56
+ <h2 className="text-left text-2xl font-bold text-foreground">
57
+ Button component
58
+ </h2>
59
+ <p className="text-sm text-muted-foreground">
60
+ Variants and sizes ready to use
61
+ </p>
62
+ </div>
63
+ <div className="grid grid-cols-1 gap-6 rounded-xl border bg-card/60 p-6 shadow-xs backdrop-blur-sm md:grid-cols-2">
64
+ <div>
65
+ <h3 className="text-sm font-semibold text-foreground">
66
+ Variants
67
+ </h3>
68
+ <div className="mt-3 flex flex-wrap items-center gap-3">
69
+ <Button>Primary</Button>
70
+ <Button variant="secondary">Secondary</Button>
71
+ <Button variant="ghost">Ghost</Button>
72
+ <Button variant="destructive">Destructive</Button>
73
+ </div>
74
+ </div>
75
+ <div>
76
+ <h3 className="text-sm font-semibold text-foreground">Sizes</h3>
77
+ <div className="mt-3 flex flex-wrap items-center gap-3">
78
+ <Button size="sm">Small</Button>
79
+ <Button size="md">Medium</Button>
80
+ <Button size="lg">Large</Button>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </section>
86
+ </div>
87
+ );
88
+ }
@@ -0,0 +1,29 @@
1
+ import { useLocation } from "react-router-dom";
2
+ import { useEffect } from "react";
3
+
4
+ const NotFound = () => {
5
+ const location = useLocation();
6
+
7
+ useEffect(() => {
8
+ console.error(
9
+ "404 Error: User attempted to access non-existent route:",
10
+ location.pathname,
11
+ );
12
+ }, [location.pathname]);
13
+
14
+ return (
15
+ <div className="min-h-screen flex items-center justify-center bg-muted">
16
+ <div className="text-center">
17
+ <h1 className="text-4xl font-bold mb-4 text-foreground">404</h1>
18
+ <p className="text-xl text-muted-foreground mb-4">
19
+ Oops! Page not found
20
+ </p>
21
+ <a href="/" className="text-primary hover:text-primary/80 underline">
22
+ Return to Home
23
+ </a>
24
+ </div>
25
+ </div>
26
+ );
27
+ };
28
+
29
+ export default NotFound;
@@ -0,0 +1,74 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ Accordion,
4
+ AccordionItem,
5
+ AccordionTrigger,
6
+ AccordionContent,
7
+ } from "../../components/ui/accordion";
8
+
9
+ const meta = {
10
+ title: "UI/Accordion",
11
+ component: Accordion,
12
+ tags: ["autodocs"],
13
+ parameters: {
14
+ layout: "padded",
15
+ },
16
+ } satisfies Meta<typeof Accordion>;
17
+
18
+ export default meta;
19
+
20
+ type Story = StoryObj<typeof meta>;
21
+
22
+ export const Default: Story = {
23
+ render: () => (
24
+ <Accordion type="single" collapsible className="w-full max-w-md">
25
+ <AccordionItem value="item-1">
26
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
27
+ <AccordionContent>
28
+ Yes. It adheres to the WAI-ARIA design pattern.
29
+ </AccordionContent>
30
+ </AccordionItem>
31
+ <AccordionItem value="item-2">
32
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
33
+ <AccordionContent>
34
+ Yes. It comes with default styles you can customize using CSS.
35
+ </AccordionContent>
36
+ </AccordionItem>
37
+ <AccordionItem value="item-3">
38
+ <AccordionTrigger>Is it animated?</AccordionTrigger>
39
+ <AccordionContent>
40
+ Yes. It&apos;s animated by default, but you can disable it if you
41
+ prefer.
42
+ </AccordionContent>
43
+ </AccordionItem>
44
+ </Accordion>
45
+ ),
46
+ };
47
+
48
+ export const Multiple: Story = {
49
+ render: () => (
50
+ <Accordion type="multiple" className="w-full max-w-md">
51
+ <AccordionItem value="item-1">
52
+ <AccordionTrigger>Feature One</AccordionTrigger>
53
+ <AccordionContent>
54
+ This is the content for feature one. You can open multiple items at
55
+ once.
56
+ </AccordionContent>
57
+ </AccordionItem>
58
+ <AccordionItem value="item-2">
59
+ <AccordionTrigger>Feature Two</AccordionTrigger>
60
+ <AccordionContent>
61
+ This is the content for feature two. All sections can be expanded
62
+ simultaneously.
63
+ </AccordionContent>
64
+ </AccordionItem>
65
+ <AccordionItem value="item-3">
66
+ <AccordionTrigger>Feature Three</AccordionTrigger>
67
+ <AccordionContent>
68
+ This is the content for feature three. Great for detailed information
69
+ display.
70
+ </AccordionContent>
71
+ </AccordionItem>
72
+ </Accordion>
73
+ ),
74
+ };
@@ -0,0 +1,82 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Alert, AlertTitle, AlertDescription } from "../../components/ui/alert";
3
+ import { AlertCircle, Terminal, CheckCircle2 } from "lucide-react";
4
+
5
+ const meta = {
6
+ title: "UI/Alert",
7
+ component: Alert,
8
+ tags: ["autodocs"],
9
+ parameters: {
10
+ layout: "padded",
11
+ },
12
+ } satisfies Meta<typeof Alert>;
13
+
14
+ export default meta;
15
+
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ export const Default: Story = {
19
+ render: () => (
20
+ <Alert>
21
+ <Terminal className="h-4 w-4" />
22
+ <AlertTitle>Heads up!</AlertTitle>
23
+ <AlertDescription>
24
+ You can add components to your app using the code below.
25
+ </AlertDescription>
26
+ </Alert>
27
+ ),
28
+ };
29
+
30
+ export const Destructive: Story = {
31
+ render: () => (
32
+ <Alert variant="destructive">
33
+ <AlertCircle className="h-4 w-4" />
34
+ <AlertTitle>Error</AlertTitle>
35
+ <AlertDescription>
36
+ Your session has expired. Please log in again.
37
+ </AlertDescription>
38
+ </Alert>
39
+ ),
40
+ };
41
+
42
+ export const Success: Story = {
43
+ render: () => (
44
+ <Alert>
45
+ <CheckCircle2 className="h-4 w-4" />
46
+ <AlertTitle>Success</AlertTitle>
47
+ <AlertDescription>
48
+ Your changes have been saved successfully.
49
+ </AlertDescription>
50
+ </Alert>
51
+ ),
52
+ };
53
+
54
+ export const AllVariants: Story = {
55
+ render: () => (
56
+ <div className="space-y-4 max-w-md">
57
+ <Alert>
58
+ <Terminal className="h-4 w-4" />
59
+ <AlertTitle>Heads up!</AlertTitle>
60
+ <AlertDescription>
61
+ You can add components to your app using the code below.
62
+ </AlertDescription>
63
+ </Alert>
64
+
65
+ <Alert variant="destructive">
66
+ <AlertCircle className="h-4 w-4" />
67
+ <AlertTitle>Error</AlertTitle>
68
+ <AlertDescription>
69
+ Your session has expired. Please log in again.
70
+ </AlertDescription>
71
+ </Alert>
72
+
73
+ <Alert>
74
+ <CheckCircle2 className="h-4 w-4" />
75
+ <AlertTitle>Success</AlertTitle>
76
+ <AlertDescription>
77
+ Your changes have been saved successfully.
78
+ </AlertDescription>
79
+ </Alert>
80
+ </div>
81
+ ),
82
+ };
@@ -0,0 +1,106 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ AlertDialog,
4
+ AlertDialogTrigger,
5
+ AlertDialogContent,
6
+ AlertDialogHeader,
7
+ AlertDialogTitle,
8
+ AlertDialogDescription,
9
+ AlertDialogFooter,
10
+ AlertDialogAction,
11
+ AlertDialogCancel,
12
+ } from "../../components/ui/alert-dialog";
13
+ import { Button } from "../../components/ui/button";
14
+ import { useState } from "react";
15
+
16
+ const meta = {
17
+ title: "UI/AlertDialog",
18
+ component: AlertDialog,
19
+ tags: ["autodocs"],
20
+ parameters: {
21
+ layout: "centered",
22
+ },
23
+ } satisfies Meta<typeof AlertDialog>;
24
+
25
+ export default meta;
26
+
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ export const Default: Story = {
30
+ render: () => {
31
+ const [open, setOpen] = useState(false);
32
+ return (
33
+ <AlertDialog open={open} onOpenChange={setOpen}>
34
+ <AlertDialogTrigger asChild>
35
+ <Button>Open Alert</Button>
36
+ </AlertDialogTrigger>
37
+ <AlertDialogContent>
38
+ <AlertDialogHeader>
39
+ <AlertDialogTitle>Confirm Action</AlertDialogTitle>
40
+ <AlertDialogDescription>
41
+ Are you sure you want to proceed with this action?
42
+ </AlertDialogDescription>
43
+ </AlertDialogHeader>
44
+ <AlertDialogFooter>
45
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
46
+ <AlertDialogAction>Continue</AlertDialogAction>
47
+ </AlertDialogFooter>
48
+ </AlertDialogContent>
49
+ </AlertDialog>
50
+ );
51
+ },
52
+ };
53
+
54
+ export const Delete: Story = {
55
+ render: () => {
56
+ const [open, setOpen] = useState(false);
57
+ return (
58
+ <AlertDialog open={open} onOpenChange={setOpen}>
59
+ <AlertDialogTrigger asChild>
60
+ <Button variant="destructive">Delete Item</Button>
61
+ </AlertDialogTrigger>
62
+ <AlertDialogContent>
63
+ <AlertDialogHeader>
64
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
65
+ <AlertDialogDescription>
66
+ This action cannot be undone. This will permanently delete the
67
+ item.
68
+ </AlertDialogDescription>
69
+ </AlertDialogHeader>
70
+ <AlertDialogFooter>
71
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
72
+ <AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
73
+ Delete
74
+ </AlertDialogAction>
75
+ </AlertDialogFooter>
76
+ </AlertDialogContent>
77
+ </AlertDialog>
78
+ );
79
+ },
80
+ };
81
+
82
+ export const Warning: Story = {
83
+ render: () => {
84
+ const [open, setOpen] = useState(false);
85
+ return (
86
+ <AlertDialog open={open} onOpenChange={setOpen}>
87
+ <AlertDialogTrigger asChild>
88
+ <Button variant="outline">Show Warning</Button>
89
+ </AlertDialogTrigger>
90
+ <AlertDialogContent>
91
+ <AlertDialogHeader>
92
+ <AlertDialogTitle>Warning</AlertDialogTitle>
93
+ <AlertDialogDescription>
94
+ This action will have significant consequences. Please confirm
95
+ that you understand the risks.
96
+ </AlertDialogDescription>
97
+ </AlertDialogHeader>
98
+ <AlertDialogFooter>
99
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
100
+ <AlertDialogAction>I Understand</AlertDialogAction>
101
+ </AlertDialogFooter>
102
+ </AlertDialogContent>
103
+ </AlertDialog>
104
+ );
105
+ },
106
+ };