@ayasofyazilim/ui 0.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.
Files changed (236) hide show
  1. package/__mocks__/canvas.ts +8 -0
  2. package/components.json +21 -0
  3. package/eslint.config.js +4 -0
  4. package/jest-environment.js +37 -0
  5. package/jest.config.ts +47 -0
  6. package/jest.setup.ts +69 -0
  7. package/package.json +124 -0
  8. package/postcss.config.mjs +6 -0
  9. package/src/aria/index.tsx +1 -0
  10. package/src/aria/number-field.tsx +41 -0
  11. package/src/components/.gitkeep +0 -0
  12. package/src/components/accordion.tsx +66 -0
  13. package/src/components/alert-dialog.tsx +157 -0
  14. package/src/components/alert.tsx +70 -0
  15. package/src/components/aspect-ratio.tsx +11 -0
  16. package/src/components/avatar.tsx +53 -0
  17. package/src/components/badge.tsx +67 -0
  18. package/src/components/breadcrumb.tsx +109 -0
  19. package/src/components/button-group.tsx +83 -0
  20. package/src/components/button.tsx +68 -0
  21. package/src/components/calendar.tsx +219 -0
  22. package/src/components/card.tsx +92 -0
  23. package/src/components/carousel.tsx +241 -0
  24. package/src/components/chart.tsx +363 -0
  25. package/src/components/checkbox.tsx +32 -0
  26. package/src/components/collapsible.tsx +33 -0
  27. package/src/components/command.tsx +184 -0
  28. package/src/components/context-menu.tsx +252 -0
  29. package/src/components/dialog.tsx +144 -0
  30. package/src/components/drawer.tsx +135 -0
  31. package/src/components/dropdown-menu.tsx +258 -0
  32. package/src/components/empty.tsx +100 -0
  33. package/src/components/field.tsx +248 -0
  34. package/src/components/form.tsx +169 -0
  35. package/src/components/hover-card.tsx +44 -0
  36. package/src/components/input-group.tsx +170 -0
  37. package/src/components/input-otp.tsx +77 -0
  38. package/src/components/input.tsx +21 -0
  39. package/src/components/item.tsx +193 -0
  40. package/src/components/kbd.tsx +28 -0
  41. package/src/components/label.tsx +24 -0
  42. package/src/components/menubar.tsx +276 -0
  43. package/src/components/navigation-menu.tsx +168 -0
  44. package/src/components/pagination.tsx +130 -0
  45. package/src/components/popover.tsx +88 -0
  46. package/src/components/progress.tsx +31 -0
  47. package/src/components/radio-group.tsx +45 -0
  48. package/src/components/resizable.tsx +56 -0
  49. package/src/components/scroll-area.tsx +58 -0
  50. package/src/components/select.tsx +189 -0
  51. package/src/components/separator.tsx +28 -0
  52. package/src/components/sheet.tsx +140 -0
  53. package/src/components/sidebar.tsx +862 -0
  54. package/src/components/skeleton.tsx +13 -0
  55. package/src/components/slider.tsx +63 -0
  56. package/src/components/sonner.tsx +40 -0
  57. package/src/components/spinner.tsx +16 -0
  58. package/src/components/stepper.tsx +291 -0
  59. package/src/components/switch.tsx +31 -0
  60. package/src/components/table.tsx +133 -0
  61. package/src/components/tabs.tsx +66 -0
  62. package/src/components/textarea.tsx +18 -0
  63. package/src/components/toggle-group.tsx +83 -0
  64. package/src/components/toggle.tsx +47 -0
  65. package/src/components/tooltip.tsx +66 -0
  66. package/src/custom/action-button.tsx +48 -0
  67. package/src/custom/async-select.tsx +287 -0
  68. package/src/custom/awesome-not-found.tsx +116 -0
  69. package/src/custom/charts/area-chart.tsx +147 -0
  70. package/src/custom/charts/bar-chart.tsx +233 -0
  71. package/src/custom/charts/chart-card.tsx +103 -0
  72. package/src/custom/charts/index.tsx +16 -0
  73. package/src/custom/charts/pie-chart.tsx +168 -0
  74. package/src/custom/charts/radar-chart.tsx +126 -0
  75. package/src/custom/checkbox-tree.tsx +100 -0
  76. package/src/custom/combobox.tsx +296 -0
  77. package/src/custom/confirm-dialog.tsx +102 -0
  78. package/src/custom/country-selector.tsx +204 -0
  79. package/src/custom/date-picker/calendar-rac.tsx +109 -0
  80. package/src/custom/date-picker/datefield-rac.tsx +84 -0
  81. package/src/custom/date-picker/index.tsx +273 -0
  82. package/src/custom/date-picker/types/index.ts +4 -0
  83. package/src/custom/date-picker/utils/index.ts +42 -0
  84. package/src/custom/date-picker-old.tsx +50 -0
  85. package/src/custom/date-tooltip.tsx +98 -0
  86. package/src/custom/document-scanner/consts.ts +5 -0
  87. package/src/custom/document-scanner/corner-adjustment/action-buttons.tsx +33 -0
  88. package/src/custom/document-scanner/corner-adjustment/corner-handle.tsx +43 -0
  89. package/src/custom/document-scanner/corner-adjustment/hooks/use-corner-drag.ts +85 -0
  90. package/src/custom/document-scanner/corner-adjustment/index.tsx +125 -0
  91. package/src/custom/document-scanner/corner-adjustment/types.ts +53 -0
  92. package/src/custom/document-scanner/corner-adjustment/utils/clip-path.ts +22 -0
  93. package/src/custom/document-scanner/corner-adjustment/zoom-magnifier.tsx +115 -0
  94. package/src/custom/document-scanner/hooks/use-document-capture.ts +81 -0
  95. package/src/custom/document-scanner/hooks/use-document-scanner.ts +80 -0
  96. package/src/custom/document-scanner/hooks/use-perspective-crop.ts +38 -0
  97. package/src/custom/document-scanner/index.tsx +255 -0
  98. package/src/custom/document-scanner/lib.ts +407 -0
  99. package/src/custom/document-scanner/types.ts +205 -0
  100. package/src/custom/document-scanner/utils/perspective-correction.ts +139 -0
  101. package/src/custom/document-viewer/controllers.tsx +98 -0
  102. package/src/custom/document-viewer/index.tsx +43 -0
  103. package/src/custom/document-viewer/renderers/image.tsx +37 -0
  104. package/src/custom/document-viewer/renderers/index.tsx +2 -0
  105. package/src/custom/document-viewer/renderers/pdf.tsx +105 -0
  106. package/src/custom/email-input/domains.json +159 -0
  107. package/src/custom/email-input/email.tsx +229 -0
  108. package/src/custom/email-input/index.tsx +4 -0
  109. package/src/custom/email-input/types.ts +104 -0
  110. package/src/custom/file-uploader.tsx +541 -0
  111. package/src/custom/filter-component/fields/async-select.tsx +33 -0
  112. package/src/custom/filter-component/fields/date.tsx +60 -0
  113. package/src/custom/filter-component/fields/multi-select.tsx +30 -0
  114. package/src/custom/filter-component/index.tsx +217 -0
  115. package/src/custom/image-canvas.tsx +260 -0
  116. package/src/custom/json-editor.tsx +22 -0
  117. package/src/custom/master-data-grid/components/dialogs/column-settings-dialog.tsx +100 -0
  118. package/src/custom/master-data-grid/components/dialogs/index.ts +1 -0
  119. package/src/custom/master-data-grid/components/filters/client-filter.tsx +368 -0
  120. package/src/custom/master-data-grid/components/filters/filter-input.tsx +256 -0
  121. package/src/custom/master-data-grid/components/filters/index.ts +3 -0
  122. package/src/custom/master-data-grid/components/filters/inline-column-filter.tsx +233 -0
  123. package/src/custom/master-data-grid/components/filters/multi-filter-dialog.tsx +90 -0
  124. package/src/custom/master-data-grid/components/filters/server-filter.tsx +255 -0
  125. package/src/custom/master-data-grid/components/master-data-grid.tsx +472 -0
  126. package/src/custom/master-data-grid/components/pagination/index.ts +1 -0
  127. package/src/custom/master-data-grid/components/pagination/pagination.tsx +178 -0
  128. package/src/custom/master-data-grid/components/table/cell-renderer.tsx +634 -0
  129. package/src/custom/master-data-grid/components/table/header-cell.tsx +162 -0
  130. package/src/custom/master-data-grid/components/table/index.ts +4 -0
  131. package/src/custom/master-data-grid/components/table/table-body-renderer.tsx +113 -0
  132. package/src/custom/master-data-grid/components/table/virtual-body.tsx +138 -0
  133. package/src/custom/master-data-grid/components/toolbar/index.ts +1 -0
  134. package/src/custom/master-data-grid/components/toolbar/toolbar.tsx +314 -0
  135. package/src/custom/master-data-grid/hooks/index.ts +3 -0
  136. package/src/custom/master-data-grid/hooks/use-columns.tsx +332 -0
  137. package/src/custom/master-data-grid/hooks/use-editing.ts +106 -0
  138. package/src/custom/master-data-grid/hooks/use-table-state-reducer.ts +157 -0
  139. package/src/custom/master-data-grid/hooks/use-table-state.ts +31 -0
  140. package/src/custom/master-data-grid/index.ts +16 -0
  141. package/src/custom/master-data-grid/types.ts +466 -0
  142. package/src/custom/master-data-grid/utils/column-generator.tsx +306 -0
  143. package/src/custom/master-data-grid/utils/export-utils.ts +67 -0
  144. package/src/custom/master-data-grid/utils/filter-fns.ts +290 -0
  145. package/src/custom/master-data-grid/utils/index.ts +8 -0
  146. package/src/custom/master-data-grid/utils/pinning-utils.ts +88 -0
  147. package/src/custom/master-data-grid/utils/translation-utils.ts +42 -0
  148. package/src/custom/multi-select.tsx +432 -0
  149. package/src/custom/password-input.tsx +194 -0
  150. package/src/custom/phone-input.tsx +172 -0
  151. package/src/custom/schema-form/custom/index.tsx +1 -0
  152. package/src/custom/schema-form/custom/label.tsx +53 -0
  153. package/src/custom/schema-form/fields/base-input-field.tsx +82 -0
  154. package/src/custom/schema-form/fields/field.tsx +67 -0
  155. package/src/custom/schema-form/fields/index.tsx +5 -0
  156. package/src/custom/schema-form/fields/object.tsx +12 -0
  157. package/src/custom/schema-form/fields/table-array/array-field-item.tsx +90 -0
  158. package/src/custom/schema-form/fields/table-array/array-field-template.tsx +115 -0
  159. package/src/custom/schema-form/index.tsx +259 -0
  160. package/src/custom/schema-form/templates/description.tsx +20 -0
  161. package/src/custom/schema-form/templates/index.tsx +2 -0
  162. package/src/custom/schema-form/templates/submit.tsx +32 -0
  163. package/src/custom/schema-form/types.ts +64 -0
  164. package/src/custom/schema-form/utils/index.ts +4 -0
  165. package/src/custom/schema-form/utils/schema-dependency.ts +655 -0
  166. package/src/custom/schema-form/utils/schemas.ts +289 -0
  167. package/src/custom/schema-form/utils/validation.ts +23 -0
  168. package/src/custom/schema-form/widgets/boolean.tsx +77 -0
  169. package/src/custom/schema-form/widgets/combobox.tsx +274 -0
  170. package/src/custom/schema-form/widgets/date.tsx +59 -0
  171. package/src/custom/schema-form/widgets/email.tsx +34 -0
  172. package/src/custom/schema-form/widgets/index.tsx +10 -0
  173. package/src/custom/schema-form/widgets/password.tsx +40 -0
  174. package/src/custom/schema-form/widgets/phone.tsx +40 -0
  175. package/src/custom/schema-form/widgets/select.tsx +105 -0
  176. package/src/custom/schema-form/widgets/selectable.tsx +25 -0
  177. package/src/custom/schema-form/widgets/string-array.tsx +296 -0
  178. package/src/custom/schema-form/widgets/url.tsx +56 -0
  179. package/src/custom/section-layout-v2.tsx +212 -0
  180. package/src/custom/select-tabs.tsx +109 -0
  181. package/src/custom/selectable.tsx +316 -0
  182. package/src/custom/stepper.tsx +236 -0
  183. package/src/custom/tab-layout.tsx +213 -0
  184. package/src/custom/tanstack-table/fields/index.tsx +12 -0
  185. package/src/custom/tanstack-table/fields/tanstack-table-action-dialogs.tsx +89 -0
  186. package/src/custom/tanstack-table/fields/tanstack-table-column-header.tsx +66 -0
  187. package/src/custom/tanstack-table/fields/tanstack-table-filter-date.tsx +180 -0
  188. package/src/custom/tanstack-table/fields/tanstack-table-filter-faceted.tsx +158 -0
  189. package/src/custom/tanstack-table/fields/tanstack-table-filter-text.tsx +76 -0
  190. package/src/custom/tanstack-table/fields/tanstack-table-pagination.tsx +136 -0
  191. package/src/custom/tanstack-table/fields/tanstack-table-plain-table.tsx +142 -0
  192. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-confirmation.tsx +77 -0
  193. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-custom-dialog.tsx +87 -0
  194. package/src/custom/tanstack-table/fields/tanstack-table-row-actions.tsx +151 -0
  195. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-custom-dialog.tsx +88 -0
  196. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-schemaform-dialog.tsx +47 -0
  197. package/src/custom/tanstack-table/fields/tanstack-table-toolbar.tsx +143 -0
  198. package/src/custom/tanstack-table/fields/tanstack-table-view-options.tsx +171 -0
  199. package/src/custom/tanstack-table/index.tsx +244 -0
  200. package/src/custom/tanstack-table/types/index.ts +328 -0
  201. package/src/custom/tanstack-table/utils/cell-with-actions.tsx +21 -0
  202. package/src/custom/tanstack-table/utils/column-names.ts +26 -0
  203. package/src/custom/tanstack-table/utils/columns-by-row-data.tsx +312 -0
  204. package/src/custom/tanstack-table/utils/editable-columns-by-row-data.tsx +219 -0
  205. package/src/custom/tanstack-table/utils/faceted-boolean-options.tsx +22 -0
  206. package/src/custom/tanstack-table/utils/index.tsx +10 -0
  207. package/src/custom/tanstack-table/utils/pinning-styles.ts +57 -0
  208. package/src/custom/tanstack-table/utils/table.tsx +83 -0
  209. package/src/custom/tanstack-table/utils/test-conditions.ts +17 -0
  210. package/src/custom/timeline.tsx +208 -0
  211. package/src/custom/tree.tsx +200 -0
  212. package/src/custom/tscanify/browser.ts +66 -0
  213. package/src/custom/tscanify/index.ts +51 -0
  214. package/src/custom/tscanify/tscanify-browser.ts +522 -0
  215. package/src/custom/tscanify/tscanify.ts +262 -0
  216. package/src/custom/tscanify/types.ts +22 -0
  217. package/src/custom/webcam.tsx +737 -0
  218. package/src/hooks/.gitkeep +0 -0
  219. package/src/hooks/use-callback-ref.ts +27 -0
  220. package/src/hooks/use-controllable-state.ts +67 -0
  221. package/src/hooks/use-debounce.ts +19 -0
  222. package/src/hooks/use-is-visible.ts +23 -0
  223. package/src/hooks/use-media-query.ts +21 -0
  224. package/src/hooks/use-mobile.ts +21 -0
  225. package/src/hooks/use-on-window-resize.ts +15 -0
  226. package/src/hooks/use-scroll.tsx +22 -0
  227. package/src/lib/utils.ts +61 -0
  228. package/src/lib/zod.ts +2 -0
  229. package/src/styles/core.css +57 -0
  230. package/src/styles/globals.css +130 -0
  231. package/src/test/email-input.test.tsx +217 -0
  232. package/src/test/password-input.test.tsx +92 -0
  233. package/src/test/select-tabs.test.tsx +302 -0
  234. package/src/test/selectable.test.tsx +1093 -0
  235. package/tsconfig.json +13 -0
  236. package/tsconfig.lint.json +8 -0
@@ -0,0 +1,862 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Slot } from "@radix-ui/react-slot";
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+ import { PanelLeftIcon } from "lucide-react";
7
+ import { useIsMobile } from "../hooks/use-mobile";
8
+ import { cn } from "../lib/utils";
9
+ import { Button } from "./button";
10
+ import { Input } from "./input";
11
+ import { Separator } from "./separator";
12
+ import {
13
+ Sheet,
14
+ SheetContent,
15
+ SheetDescription,
16
+ SheetHeader,
17
+ SheetTitle,
18
+ } from "./sheet";
19
+ import { Skeleton } from "./skeleton";
20
+ import {
21
+ Tooltip,
22
+ TooltipContent,
23
+ TooltipProvider,
24
+ TooltipTrigger,
25
+ } from "./tooltip";
26
+
27
+ const SIDEBAR_COOKIE_NAME = "sidebar_state";
28
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
29
+ const SIDEBAR_WIDTH = "16rem";
30
+ const SIDEBAR_WIDTH_MOBILE = "18rem";
31
+ const SIDEBAR_WIDTH_ICON = "3rem";
32
+ const SIDEBAR_KEYBOARD_SHORTCUT = "b";
33
+
34
+ type SidebarState = {
35
+ open: boolean;
36
+ openMobile: boolean;
37
+ };
38
+
39
+ type SidebarContextProps = {
40
+ sidebars: Record<string, SidebarState>;
41
+ registerSidebar: (name: string, initialState?: Partial<SidebarState>) => void;
42
+ unregisterSidebar: (name: string) => void;
43
+ setSidebarState: (
44
+ name: string,
45
+ state:
46
+ | Partial<SidebarState>
47
+ | ((prev: SidebarState) => Partial<SidebarState>)
48
+ ) => void;
49
+ toggleSidebar: (name: string) => void;
50
+ isMobile: boolean;
51
+ };
52
+
53
+ const SidebarContext = React.createContext<SidebarContextProps | null>(null);
54
+
55
+ function useSidebar(name: string) {
56
+ const context = React.useContext(SidebarContext);
57
+ if (!context) {
58
+ throw new Error("useSidebar must be used within a SidebarProvider.");
59
+ }
60
+
61
+ const sidebarState = context.sidebars[name] ?? {
62
+ open: false,
63
+ openMobile: false,
64
+ };
65
+
66
+ const state = sidebarState.open ? "expanded" : "collapsed";
67
+
68
+ return {
69
+ state,
70
+ open: sidebarState.open,
71
+ setOpen: (open: boolean) => context.setSidebarState(name, { open }),
72
+ openMobile: sidebarState.openMobile,
73
+ setOpenMobile: (openMobile: boolean) =>
74
+ context.setSidebarState(name, { openMobile }),
75
+ isMobile: context.isMobile,
76
+ toggleSidebar: () => context.toggleSidebar(name),
77
+ };
78
+ }
79
+
80
+ function SidebarProvider({
81
+ defaultOpen = true,
82
+ open: openProp,
83
+ onOpenChange: setOpenProp,
84
+ className,
85
+ style,
86
+ children,
87
+ ...props
88
+ }: React.ComponentProps<"div"> & {
89
+ defaultOpen?: boolean | string[];
90
+ open?: string[];
91
+ onOpenChange?: (open: string[]) => void;
92
+ }) {
93
+ const isMobile = useIsMobile();
94
+ const [sidebars, setSidebars] = React.useState<Record<string, SidebarState>>(
95
+ {}
96
+ );
97
+ const initialRegistrations = React.useRef<Set<string>>(new Set());
98
+
99
+ const registerSidebar = React.useCallback(
100
+ (name: string, initialState?: Partial<SidebarState>) => {
101
+ setSidebars((prev) => {
102
+ if (prev[name]) return prev;
103
+
104
+ let open = false;
105
+ if (openProp) {
106
+ open = openProp.includes(name);
107
+ } else {
108
+ if (typeof defaultOpen === "boolean") {
109
+ open = defaultOpen;
110
+ } else if (Array.isArray(defaultOpen)) {
111
+ open = defaultOpen.includes(name);
112
+ }
113
+ }
114
+ if (!initialRegistrations.current.has(name)) {
115
+ initialRegistrations.current.add(name);
116
+ }
117
+
118
+ return {
119
+ ...prev,
120
+ [name]: {
121
+ open,
122
+ openMobile: false,
123
+ ...initialState,
124
+ },
125
+ };
126
+ });
127
+ },
128
+ [defaultOpen, openProp]
129
+ );
130
+
131
+ const unregisterSidebar = React.useCallback((name: string) => {
132
+ setSidebars((prev) => {
133
+ const next = { ...prev };
134
+ delete next[name];
135
+ return next;
136
+ });
137
+ initialRegistrations.current.delete(name);
138
+ }, []);
139
+
140
+ React.useEffect(() => {
141
+ if (openProp) {
142
+ setSidebars((prev) => {
143
+ const next = { ...prev };
144
+ Object.keys(next).forEach((name) => {
145
+ if (next[name]) {
146
+ next[name] = {
147
+ ...next[name],
148
+ open: openProp.includes(name),
149
+ };
150
+ }
151
+ });
152
+ return next;
153
+ });
154
+ }
155
+ }, [openProp]);
156
+
157
+ const setSidebarState = React.useCallback(
158
+ (
159
+ name: string,
160
+ state:
161
+ | Partial<SidebarState>
162
+ | ((prev: SidebarState) => Partial<SidebarState>)
163
+ ) => {
164
+ setSidebars((prev) => {
165
+ const currentState = prev[name] ?? {
166
+ open: false,
167
+ openMobile: false,
168
+ };
169
+ const newState =
170
+ typeof state === "function" ? state(currentState) : state;
171
+ const next = {
172
+ ...prev,
173
+ [name]: { ...currentState, ...newState },
174
+ };
175
+
176
+ const openSidebars = Object.entries(next)
177
+ .filter(([_, sidebarState]) => sidebarState?.open === true)
178
+ .map(([sidebarName]) => sidebarName);
179
+
180
+ openSidebars.forEach((sidebarName) => {
181
+ const sidebarState = next[sidebarName];
182
+ if (sidebarState) {
183
+ document.cookie = `${SIDEBAR_COOKIE_NAME}_${sidebarName}=${sidebarState.open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
184
+ }
185
+ });
186
+
187
+ if (setOpenProp) {
188
+ setOpenProp(openSidebars);
189
+ }
190
+
191
+ return next;
192
+ });
193
+ },
194
+ [setOpenProp]
195
+ );
196
+
197
+ const toggleSidebar = React.useCallback(
198
+ (name: string) => {
199
+ setSidebarState(name, (prev: SidebarState) => {
200
+ return isMobile
201
+ ? { openMobile: !prev.openMobile }
202
+ : { open: !prev.open };
203
+ });
204
+ },
205
+ [isMobile, setSidebarState]
206
+ );
207
+
208
+ React.useEffect(() => {
209
+ const handleKeyDown = (event: KeyboardEvent) => {
210
+ if (
211
+ event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
212
+ (event.metaKey || event.ctrlKey)
213
+ ) {
214
+ event.preventDefault();
215
+ Object.keys(sidebars).forEach((name) => toggleSidebar(name));
216
+ }
217
+ };
218
+
219
+ window.addEventListener("keydown", handleKeyDown);
220
+ return () => window.removeEventListener("keydown", handleKeyDown);
221
+ }, [toggleSidebar, sidebars]);
222
+
223
+ const contextValue = React.useMemo<SidebarContextProps>(
224
+ () => ({
225
+ sidebars,
226
+ registerSidebar,
227
+ unregisterSidebar,
228
+ setSidebarState,
229
+ toggleSidebar,
230
+ isMobile,
231
+ }),
232
+ [
233
+ sidebars,
234
+ registerSidebar,
235
+ unregisterSidebar,
236
+ setSidebarState,
237
+ toggleSidebar,
238
+ isMobile,
239
+ ]
240
+ );
241
+
242
+ return (
243
+ <SidebarContext.Provider value={contextValue}>
244
+ <TooltipProvider delayDuration={0}>
245
+ <div
246
+ data-slot="sidebar-wrapper"
247
+ style={
248
+ {
249
+ "--sidebar-width": SIDEBAR_WIDTH,
250
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
251
+ ...style,
252
+ } as React.CSSProperties
253
+ }
254
+ className={cn(
255
+ "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
256
+ className
257
+ )}
258
+ {...props}
259
+ >
260
+ {children}
261
+ </div>
262
+ </TooltipProvider>
263
+ </SidebarContext.Provider>
264
+ );
265
+ }
266
+
267
+ function Sidebar({
268
+ name,
269
+ side = "left",
270
+ variant = "sidebar",
271
+ collapsible = "offcanvas",
272
+ className,
273
+ children,
274
+ ...props
275
+ }: React.ComponentProps<"div"> & {
276
+ name: string;
277
+ side?: "left" | "right";
278
+ variant?: "sidebar" | "floating" | "inset";
279
+ collapsible?: "offcanvas" | "icon" | "none";
280
+ }) {
281
+ const context = React.useContext(SidebarContext);
282
+ if (!context) {
283
+ throw new Error("Sidebar must be used within a SidebarProvider.");
284
+ }
285
+
286
+ const { registerSidebar, unregisterSidebar } = context;
287
+
288
+ React.useLayoutEffect(() => {
289
+ registerSidebar(name);
290
+ return () => unregisterSidebar(name);
291
+ }, [name, registerSidebar, unregisterSidebar]);
292
+
293
+ const { state, openMobile, setOpenMobile } = useSidebar(name);
294
+
295
+ if (collapsible === "none") {
296
+ return (
297
+ <div
298
+ data-slot="sidebar"
299
+ className={cn(
300
+ "group/sidebar bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
301
+ className
302
+ )}
303
+ {...props}
304
+ >
305
+ {children}
306
+ </div>
307
+ );
308
+ }
309
+
310
+ if (context.isMobile) {
311
+ return (
312
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
313
+ <SheetContent
314
+ data-sidebar="sidebar"
315
+ data-slot="sidebar"
316
+ data-mobile="true"
317
+ className={cn(
318
+ "group/sidebar bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",
319
+ className
320
+ )}
321
+ style={
322
+ {
323
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
324
+ } as React.CSSProperties
325
+ }
326
+ side={side}
327
+ >
328
+ <SheetHeader className="sr-only">
329
+ <SheetTitle>Sidebar</SheetTitle>
330
+ <SheetDescription>Displays the mobile sidebar.</SheetDescription>
331
+ </SheetHeader>
332
+ <div className="flex h-full w-full flex-col">{children}</div>
333
+ </SheetContent>
334
+ </Sheet>
335
+ );
336
+ }
337
+
338
+ return (
339
+ <div
340
+ className="group peer text-sidebar-foreground hidden md:block"
341
+ data-state={state}
342
+ data-collapsible={state === "collapsed" ? collapsible : ""}
343
+ data-variant={variant}
344
+ data-side={side}
345
+ data-slot="sidebar"
346
+ >
347
+ <div
348
+ data-slot="sidebar-gap"
349
+ className={cn(
350
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
351
+ "group-data-[collapsible=offcanvas]:w-0",
352
+ "group-data-[side=right]:rotate-180",
353
+ variant === "floating" || variant === "inset"
354
+ ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
355
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
356
+ )}
357
+ />
358
+ <div
359
+ data-slot="sidebar-container"
360
+ className={cn(
361
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
362
+ side === "left"
363
+ ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
364
+ : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
365
+ variant === "floating" || variant === "inset"
366
+ ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
367
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
368
+ className
369
+ )}
370
+ {...props}
371
+ >
372
+ <div
373
+ data-sidebar="sidebar"
374
+ data-slot="sidebar-inner"
375
+ className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
376
+ >
377
+ {children}
378
+ </div>
379
+ </div>
380
+ </div>
381
+ );
382
+ }
383
+
384
+ function SidebarTrigger({
385
+ className,
386
+ onClick,
387
+ name,
388
+ ...props
389
+ }: React.ComponentProps<typeof Button> & {
390
+ name: string;
391
+ }) {
392
+ const { toggleSidebar } = useSidebar(name);
393
+
394
+ return (
395
+ <Button
396
+ data-sidebar="trigger"
397
+ data-slot="sidebar-trigger"
398
+ variant="ghost"
399
+ size="icon"
400
+ className={cn("size-7", className)}
401
+ onClick={(event) => {
402
+ onClick?.(event);
403
+ toggleSidebar();
404
+ }}
405
+ {...props}
406
+ >
407
+ <PanelLeftIcon />
408
+ <span className="sr-only">Toggle Sidebar</span>
409
+ </Button>
410
+ );
411
+ }
412
+
413
+ function SidebarRail({
414
+ className,
415
+ name,
416
+ ...props
417
+ }: React.ComponentProps<"button"> & {
418
+ name: string;
419
+ }) {
420
+ const { toggleSidebar } = useSidebar(name);
421
+
422
+ return (
423
+ <button
424
+ data-sidebar="rail"
425
+ data-slot="sidebar-rail"
426
+ aria-label="Toggle Sidebar"
427
+ tabIndex={-1}
428
+ onClick={toggleSidebar}
429
+ title="Toggle Sidebar"
430
+ className={cn(
431
+ "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 sm:flex",
432
+ "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize!",
433
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
434
+ "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
435
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
436
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
437
+ className
438
+ )}
439
+ {...props}
440
+ />
441
+ );
442
+ }
443
+
444
+ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
445
+ return (
446
+ <main
447
+ data-slot="sidebar-inset"
448
+ className={cn(
449
+ "bg-background relative flex w-full flex-1 flex-col",
450
+ "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
451
+ className
452
+ )}
453
+ {...props}
454
+ />
455
+ );
456
+ }
457
+
458
+ function SidebarInput({
459
+ className,
460
+ ...props
461
+ }: React.ComponentProps<typeof Input>) {
462
+ return (
463
+ <Input
464
+ data-slot="sidebar-input"
465
+ data-sidebar="input"
466
+ className={cn("bg-background h-8 w-full shadow-none", className)}
467
+ {...props}
468
+ />
469
+ );
470
+ }
471
+
472
+ function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
473
+ return (
474
+ <div
475
+ data-slot="sidebar-header"
476
+ data-sidebar="header"
477
+ className={cn("flex flex-col gap-2 p-2", className)}
478
+ {...props}
479
+ />
480
+ );
481
+ }
482
+
483
+ function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
484
+ return (
485
+ <div
486
+ data-slot="sidebar-footer"
487
+ data-sidebar="footer"
488
+ className={cn("flex flex-col gap-2 p-2", className)}
489
+ {...props}
490
+ />
491
+ );
492
+ }
493
+
494
+ function SidebarSeparator({
495
+ className,
496
+ ...props
497
+ }: React.ComponentProps<typeof Separator>) {
498
+ return (
499
+ <Separator
500
+ data-slot="sidebar-separator"
501
+ data-sidebar="separator"
502
+ className={cn("bg-sidebar-border mx-2 w-auto", className)}
503
+ {...props}
504
+ />
505
+ );
506
+ }
507
+
508
+ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
509
+ return (
510
+ <div
511
+ data-slot="sidebar-content"
512
+ data-sidebar="content"
513
+ className={cn(
514
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
515
+ className
516
+ )}
517
+ {...props}
518
+ />
519
+ );
520
+ }
521
+
522
+ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
523
+ return (
524
+ <div
525
+ data-slot="sidebar-group"
526
+ data-sidebar="group"
527
+ className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
528
+ {...props}
529
+ />
530
+ );
531
+ }
532
+
533
+ function SidebarGroupLabel({
534
+ className,
535
+ asChild = false,
536
+ ...props
537
+ }: React.ComponentProps<"div"> & { asChild?: boolean }) {
538
+ const Comp = asChild ? Slot : "div";
539
+
540
+ return (
541
+ <Comp
542
+ data-slot="sidebar-group-label"
543
+ data-sidebar="group-label"
544
+ className={cn(
545
+ "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
546
+ "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
547
+ className
548
+ )}
549
+ {...props}
550
+ />
551
+ );
552
+ }
553
+
554
+ function SidebarGroupAction({
555
+ className,
556
+ asChild = false,
557
+ ...props
558
+ }: React.ComponentProps<"button"> & { asChild?: boolean }) {
559
+ const Comp = asChild ? Slot : "button";
560
+
561
+ return (
562
+ <Comp
563
+ data-slot="sidebar-group-action"
564
+ data-sidebar="group-action"
565
+ className={cn(
566
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
567
+ "after:absolute after:-inset-2 md:after:hidden",
568
+ "group-data-[collapsible=icon]:hidden",
569
+ className
570
+ )}
571
+ {...props}
572
+ />
573
+ );
574
+ }
575
+
576
+ function SidebarGroupContent({
577
+ className,
578
+ ...props
579
+ }: React.ComponentProps<"div">) {
580
+ return (
581
+ <div
582
+ data-slot="sidebar-group-content"
583
+ data-sidebar="group-content"
584
+ className={cn("w-full text-sm", className)}
585
+ {...props}
586
+ />
587
+ );
588
+ }
589
+
590
+ function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
591
+ return (
592
+ <ul
593
+ data-slot="sidebar-menu"
594
+ data-sidebar="menu"
595
+ className={cn("flex w-full min-w-0 flex-col gap-1", className)}
596
+ {...props}
597
+ />
598
+ );
599
+ }
600
+
601
+ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
602
+ return (
603
+ <li
604
+ data-slot="sidebar-menu-item"
605
+ data-sidebar="menu-item"
606
+ className={cn("group/menu-item relative", className)}
607
+ {...props}
608
+ />
609
+ );
610
+ }
611
+
612
+ const sidebarMenuButtonVariants = cva(
613
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
614
+ {
615
+ variants: {
616
+ variant: {
617
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
618
+ outline:
619
+ "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
620
+ },
621
+ size: {
622
+ default: "h-8 text-sm",
623
+ sm: "h-7 text-xs",
624
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
625
+ },
626
+ },
627
+ defaultVariants: {
628
+ variant: "default",
629
+ size: "default",
630
+ },
631
+ }
632
+ );
633
+
634
+ function SidebarMenuButton({
635
+ asChild = false,
636
+ isActive = false,
637
+ variant = "default",
638
+ size = "default",
639
+ tooltip,
640
+ className,
641
+ name,
642
+ ...props
643
+ }: React.ComponentProps<"button"> & {
644
+ asChild?: boolean;
645
+ isActive?: boolean;
646
+ tooltip?: string | React.ComponentProps<typeof TooltipContent>;
647
+ name: string;
648
+ } & VariantProps<typeof sidebarMenuButtonVariants>) {
649
+ const Comp = asChild ? Slot : "button";
650
+ const { isMobile, state } = useSidebar(name);
651
+
652
+ const button = (
653
+ <Comp
654
+ data-slot="sidebar-menu-button"
655
+ data-sidebar="menu-button"
656
+ data-size={size}
657
+ data-active={isActive}
658
+ className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
659
+ {...props}
660
+ />
661
+ );
662
+
663
+ if (!tooltip) {
664
+ return button;
665
+ }
666
+
667
+ if (typeof tooltip === "string") {
668
+ tooltip = {
669
+ children: tooltip,
670
+ };
671
+ }
672
+
673
+ return (
674
+ <Tooltip>
675
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
676
+ <TooltipContent
677
+ side="right"
678
+ align="center"
679
+ hidden={state !== "collapsed" || isMobile}
680
+ {...tooltip}
681
+ />
682
+ </Tooltip>
683
+ );
684
+ }
685
+
686
+ function SidebarMenuAction({
687
+ className,
688
+ asChild = false,
689
+ showOnHover = false,
690
+ ...props
691
+ }: React.ComponentProps<"button"> & {
692
+ asChild?: boolean;
693
+ showOnHover?: boolean;
694
+ }) {
695
+ const Comp = asChild ? Slot : "button";
696
+
697
+ return (
698
+ <Comp
699
+ data-slot="sidebar-menu-action"
700
+ data-sidebar="menu-action"
701
+ className={cn(
702
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
703
+ "after:absolute after:-inset-2 md:after:hidden",
704
+ "peer-data-[size=sm]/menu-button:top-1",
705
+ "peer-data-[size=default]/menu-button:top-1.5",
706
+ "peer-data-[size=lg]/menu-button:top-2.5",
707
+ "group-data-[collapsible=icon]:hidden",
708
+ showOnHover &&
709
+ "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
710
+ className
711
+ )}
712
+ {...props}
713
+ />
714
+ );
715
+ }
716
+
717
+ function SidebarMenuBadge({
718
+ className,
719
+ ...props
720
+ }: React.ComponentProps<"div">) {
721
+ return (
722
+ <div
723
+ data-slot="sidebar-menu-badge"
724
+ data-sidebar="menu-badge"
725
+ className={cn(
726
+ "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
727
+ "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
728
+ "peer-data-[size=sm]/menu-button:top-1",
729
+ "peer-data-[size=default]/menu-button:top-1.5",
730
+ "peer-data-[size=lg]/menu-button:top-2.5",
731
+ "group-data-[collapsible=icon]:hidden",
732
+ className
733
+ )}
734
+ {...props}
735
+ />
736
+ );
737
+ }
738
+
739
+ function SidebarMenuSkeleton({
740
+ className,
741
+ showIcon = false,
742
+ ...props
743
+ }: React.ComponentProps<"div"> & {
744
+ showIcon?: boolean;
745
+ }) {
746
+ const width = React.useMemo(() => {
747
+ return `${Math.floor(Math.random() * 40) + 50}%`;
748
+ }, []);
749
+
750
+ return (
751
+ <div
752
+ data-slot="sidebar-menu-skeleton"
753
+ data-sidebar="menu-skeleton"
754
+ className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
755
+ {...props}
756
+ >
757
+ {showIcon && (
758
+ <Skeleton
759
+ className="size-4 rounded-md"
760
+ data-sidebar="menu-skeleton-icon"
761
+ />
762
+ )}
763
+ <Skeleton
764
+ className="h-4 max-w-(--skeleton-width) flex-1"
765
+ data-sidebar="menu-skeleton-text"
766
+ style={
767
+ {
768
+ "--skeleton-width": width,
769
+ } as React.CSSProperties
770
+ }
771
+ />
772
+ </div>
773
+ );
774
+ }
775
+
776
+ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
777
+ return (
778
+ <ul
779
+ data-slot="sidebar-menu-sub"
780
+ data-sidebar="menu-sub"
781
+ className={cn(
782
+ "border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
783
+ "group-data-[collapsible=icon]:hidden",
784
+ className
785
+ )}
786
+ {...props}
787
+ />
788
+ );
789
+ }
790
+
791
+ function SidebarMenuSubItem({
792
+ className,
793
+ ...props
794
+ }: React.ComponentProps<"li">) {
795
+ return (
796
+ <li
797
+ data-slot="sidebar-menu-sub-item"
798
+ data-sidebar="menu-sub-item"
799
+ className={cn("group/menu-sub-item relative", className)}
800
+ {...props}
801
+ />
802
+ );
803
+ }
804
+
805
+ function SidebarMenuSubButton({
806
+ asChild = false,
807
+ size = "md",
808
+ isActive = false,
809
+ className,
810
+ ...props
811
+ }: React.ComponentProps<"a"> & {
812
+ asChild?: boolean;
813
+ size?: "sm" | "md";
814
+ isActive?: boolean;
815
+ }) {
816
+ const Comp = asChild ? Slot : "a";
817
+
818
+ return (
819
+ <Comp
820
+ data-slot="sidebar-menu-sub-button"
821
+ data-sidebar="menu-sub-button"
822
+ data-size={size}
823
+ data-active={isActive}
824
+ className={cn(
825
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
826
+ "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
827
+ size === "sm" && "text-xs",
828
+ size === "md" && "text-sm",
829
+ "group-data-[collapsible=icon]:hidden",
830
+ className
831
+ )}
832
+ {...props}
833
+ />
834
+ );
835
+ }
836
+
837
+ export {
838
+ Sidebar,
839
+ SidebarContent,
840
+ SidebarFooter,
841
+ SidebarGroup,
842
+ SidebarGroupAction,
843
+ SidebarGroupContent,
844
+ SidebarGroupLabel,
845
+ SidebarHeader,
846
+ SidebarInput,
847
+ SidebarInset,
848
+ SidebarMenu,
849
+ SidebarMenuAction,
850
+ SidebarMenuBadge,
851
+ SidebarMenuButton,
852
+ SidebarMenuItem,
853
+ SidebarMenuSkeleton,
854
+ SidebarMenuSub,
855
+ SidebarMenuSubButton,
856
+ SidebarMenuSubItem,
857
+ SidebarProvider,
858
+ SidebarRail,
859
+ SidebarSeparator,
860
+ SidebarTrigger,
861
+ useSidebar,
862
+ };