@goplusvn/core 0.1.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 (223) hide show
  1. package/dist/audit/index.d.mts +115 -0
  2. package/dist/audit/index.d.ts +115 -0
  3. package/dist/audit/index.js +204 -0
  4. package/dist/audit/index.js.map +1 -0
  5. package/dist/audit/index.mjs +200 -0
  6. package/dist/audit/index.mjs.map +1 -0
  7. package/dist/auth/index.d.mts +86 -0
  8. package/dist/auth/index.d.ts +86 -0
  9. package/dist/auth/index.js +210 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/index.mjs +198 -0
  12. package/dist/auth/index.mjs.map +1 -0
  13. package/dist/button-1dWvP9Ib.d.mts +30 -0
  14. package/dist/button-1dWvP9Ib.d.ts +30 -0
  15. package/dist/calendar-2QzdEo1z.d.mts +20 -0
  16. package/dist/calendar-2QzdEo1z.d.ts +20 -0
  17. package/dist/code-generation/index.d.mts +30 -0
  18. package/dist/code-generation/index.d.ts +30 -0
  19. package/dist/code-generation/index.js +31 -0
  20. package/dist/code-generation/index.js.map +1 -0
  21. package/dist/code-generation/index.mjs +28 -0
  22. package/dist/code-generation/index.mjs.map +1 -0
  23. package/dist/configs/index.d.mts +175 -0
  24. package/dist/configs/index.d.ts +175 -0
  25. package/dist/configs/index.js +254 -0
  26. package/dist/configs/index.js.map +1 -0
  27. package/dist/configs/index.mjs +233 -0
  28. package/dist/configs/index.mjs.map +1 -0
  29. package/dist/crud/index.d.mts +646 -0
  30. package/dist/crud/index.d.ts +646 -0
  31. package/dist/crud/index.js +11772 -0
  32. package/dist/crud/index.js.map +1 -0
  33. package/dist/crud/index.mjs +11665 -0
  34. package/dist/crud/index.mjs.map +1 -0
  35. package/dist/crud/server.d.mts +20 -0
  36. package/dist/crud/server.d.ts +20 -0
  37. package/dist/crud/server.js +123 -0
  38. package/dist/crud/server.js.map +1 -0
  39. package/dist/crud/server.mjs +120 -0
  40. package/dist/crud/server.mjs.map +1 -0
  41. package/dist/data-table-skeleton-12NA8Mjx.d.mts +39 -0
  42. package/dist/data-table-skeleton-12NA8Mjx.d.ts +39 -0
  43. package/dist/dialog-bKfjZMTd.d.mts +22 -0
  44. package/dist/dialog-bKfjZMTd.d.ts +22 -0
  45. package/dist/dynamic-icon-DrGIiu2N.d.mts +10 -0
  46. package/dist/dynamic-icon-DrGIiu2N.d.ts +10 -0
  47. package/dist/home/index.d.mts +269 -0
  48. package/dist/home/index.d.ts +269 -0
  49. package/dist/home/index.js +1678 -0
  50. package/dist/home/index.js.map +1 -0
  51. package/dist/home/index.mjs +1635 -0
  52. package/dist/home/index.mjs.map +1 -0
  53. package/dist/hooks/index.d.mts +7 -0
  54. package/dist/hooks/index.d.ts +7 -0
  55. package/dist/hooks/index.js +8316 -0
  56. package/dist/hooks/index.js.map +1 -0
  57. package/dist/hooks/index.mjs +8255 -0
  58. package/dist/hooks/index.mjs.map +1 -0
  59. package/dist/index-50hpiPrV.d.ts +116 -0
  60. package/dist/index-B9zQVEVi.d.mts +116 -0
  61. package/dist/index.d.mts +5 -0
  62. package/dist/index.d.ts +5 -0
  63. package/dist/index.js +123 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/index.mjs +118 -0
  66. package/dist/index.mjs.map +1 -0
  67. package/dist/infrastructure/index.d.mts +423 -0
  68. package/dist/infrastructure/index.d.ts +423 -0
  69. package/dist/infrastructure/index.js +633 -0
  70. package/dist/infrastructure/index.js.map +1 -0
  71. package/dist/infrastructure/index.mjs +619 -0
  72. package/dist/infrastructure/index.mjs.map +1 -0
  73. package/dist/label-DWTEkNPo.d.ts +226 -0
  74. package/dist/label-LPpdcoBx.d.mts +226 -0
  75. package/dist/layout/index.d.mts +48 -0
  76. package/dist/layout/index.d.ts +48 -0
  77. package/dist/layout/index.js +117 -0
  78. package/dist/layout/index.js.map +1 -0
  79. package/dist/layout/index.mjs +90 -0
  80. package/dist/layout/index.mjs.map +1 -0
  81. package/dist/navigation/index.d.mts +16 -0
  82. package/dist/navigation/index.d.ts +16 -0
  83. package/dist/navigation/index.js +53 -0
  84. package/dist/navigation/index.js.map +1 -0
  85. package/dist/navigation/index.mjs +50 -0
  86. package/dist/navigation/index.mjs.map +1 -0
  87. package/dist/notification/index.d.mts +105 -0
  88. package/dist/notification/index.d.ts +105 -0
  89. package/dist/notification/index.js +278 -0
  90. package/dist/notification/index.js.map +1 -0
  91. package/dist/notification/index.mjs +274 -0
  92. package/dist/notification/index.mjs.map +1 -0
  93. package/dist/organization/index.d.mts +99 -0
  94. package/dist/organization/index.d.ts +99 -0
  95. package/dist/organization/index.js +360 -0
  96. package/dist/organization/index.js.map +1 -0
  97. package/dist/organization/index.mjs +352 -0
  98. package/dist/organization/index.mjs.map +1 -0
  99. package/dist/plugin/index.d.mts +83 -0
  100. package/dist/plugin/index.d.ts +83 -0
  101. package/dist/plugin/index.js +86 -0
  102. package/dist/plugin/index.js.map +1 -0
  103. package/dist/plugin/index.mjs +84 -0
  104. package/dist/plugin/index.mjs.map +1 -0
  105. package/dist/providers/index.d.mts +25 -0
  106. package/dist/providers/index.d.ts +25 -0
  107. package/dist/providers/index.js +84 -0
  108. package/dist/providers/index.js.map +1 -0
  109. package/dist/providers/index.mjs +77 -0
  110. package/dist/providers/index.mjs.map +1 -0
  111. package/dist/rbac/index.d.mts +226 -0
  112. package/dist/rbac/index.d.ts +226 -0
  113. package/dist/rbac/index.js +4784 -0
  114. package/dist/rbac/index.js.map +1 -0
  115. package/dist/rbac/index.mjs +4722 -0
  116. package/dist/rbac/index.mjs.map +1 -0
  117. package/dist/rbac/permissions.d.mts +26 -0
  118. package/dist/rbac/permissions.d.ts +26 -0
  119. package/dist/rbac/permissions.js +94 -0
  120. package/dist/rbac/permissions.js.map +1 -0
  121. package/dist/rbac/permissions.mjs +90 -0
  122. package/dist/rbac/permissions.mjs.map +1 -0
  123. package/dist/rbac/server.d.mts +1 -0
  124. package/dist/rbac/server.d.ts +1 -0
  125. package/dist/rbac/server.js +128 -0
  126. package/dist/rbac/server.js.map +1 -0
  127. package/dist/rbac/server.mjs +124 -0
  128. package/dist/rbac/server.mjs.map +1 -0
  129. package/dist/schemas/index.d.mts +1257 -0
  130. package/dist/schemas/index.d.ts +1257 -0
  131. package/dist/schemas/index.js +572 -0
  132. package/dist/schemas/index.js.map +1 -0
  133. package/dist/schemas/index.mjs +523 -0
  134. package/dist/schemas/index.mjs.map +1 -0
  135. package/dist/server-QuYCTa89.d.mts +83 -0
  136. package/dist/server-QuYCTa89.d.ts +83 -0
  137. package/dist/sonner-C74GlRDQ.d.mts +71 -0
  138. package/dist/sonner-C74GlRDQ.d.ts +71 -0
  139. package/dist/status-BOXZgIqX.d.mts +12 -0
  140. package/dist/status-BOXZgIqX.d.ts +12 -0
  141. package/dist/system/index.d.mts +77 -0
  142. package/dist/system/index.d.ts +77 -0
  143. package/dist/system/index.js +102 -0
  144. package/dist/system/index.js.map +1 -0
  145. package/dist/system/index.mjs +100 -0
  146. package/dist/system/index.mjs.map +1 -0
  147. package/dist/tabs-C6FfBwPY.d.mts +18 -0
  148. package/dist/tabs-C6FfBwPY.d.ts +18 -0
  149. package/dist/tenant-provider-B8eC_Wpb.d.mts +27 -0
  150. package/dist/tenant-provider-B8eC_Wpb.d.ts +27 -0
  151. package/dist/types/index.d.mts +469 -0
  152. package/dist/types/index.d.ts +469 -0
  153. package/dist/types/index.js +25 -0
  154. package/dist/types/index.js.map +1 -0
  155. package/dist/types/index.mjs +21 -0
  156. package/dist/types/index.mjs.map +1 -0
  157. package/dist/ui/auth.d.mts +39 -0
  158. package/dist/ui/auth.d.ts +39 -0
  159. package/dist/ui/auth.js +4941 -0
  160. package/dist/ui/auth.js.map +1 -0
  161. package/dist/ui/auth.mjs +4896 -0
  162. package/dist/ui/auth.mjs.map +1 -0
  163. package/dist/ui/crud.d.mts +2 -0
  164. package/dist/ui/crud.d.ts +2 -0
  165. package/dist/ui/crud.js +4 -0
  166. package/dist/ui/crud.js.map +1 -0
  167. package/dist/ui/crud.mjs +3 -0
  168. package/dist/ui/crud.mjs.map +1 -0
  169. package/dist/ui/data-display.d.mts +596 -0
  170. package/dist/ui/data-display.d.ts +596 -0
  171. package/dist/ui/data-display.js +5307 -0
  172. package/dist/ui/data-display.js.map +1 -0
  173. package/dist/ui/data-display.mjs +5212 -0
  174. package/dist/ui/data-display.mjs.map +1 -0
  175. package/dist/ui/feedback.d.mts +55 -0
  176. package/dist/ui/feedback.d.ts +55 -0
  177. package/dist/ui/feedback.js +2608 -0
  178. package/dist/ui/feedback.js.map +1 -0
  179. package/dist/ui/feedback.mjs +2526 -0
  180. package/dist/ui/feedback.mjs.map +1 -0
  181. package/dist/ui/forms.d.mts +309 -0
  182. package/dist/ui/forms.d.ts +309 -0
  183. package/dist/ui/forms.js +4656 -0
  184. package/dist/ui/forms.js.map +1 -0
  185. package/dist/ui/forms.mjs +4571 -0
  186. package/dist/ui/forms.mjs.map +1 -0
  187. package/dist/ui/index.d.mts +331 -0
  188. package/dist/ui/index.d.ts +331 -0
  189. package/dist/ui/index.js +16953 -0
  190. package/dist/ui/index.js.map +1 -0
  191. package/dist/ui/index.mjs +16598 -0
  192. package/dist/ui/index.mjs.map +1 -0
  193. package/dist/ui/primitives/client.d.mts +61 -0
  194. package/dist/ui/primitives/client.d.ts +61 -0
  195. package/dist/ui/primitives/client.js +3408 -0
  196. package/dist/ui/primitives/client.js.map +1 -0
  197. package/dist/ui/primitives/client.mjs +3256 -0
  198. package/dist/ui/primitives/client.mjs.map +1 -0
  199. package/dist/ui/primitives.d.mts +113 -0
  200. package/dist/ui/primitives.d.ts +113 -0
  201. package/dist/ui/primitives.js +3356 -0
  202. package/dist/ui/primitives.js.map +1 -0
  203. package/dist/ui/primitives.mjs +3227 -0
  204. package/dist/ui/primitives.mjs.map +1 -0
  205. package/dist/user/index.d.mts +228 -0
  206. package/dist/user/index.d.ts +228 -0
  207. package/dist/user/index.js +4306 -0
  208. package/dist/user/index.js.map +1 -0
  209. package/dist/user/index.mjs +4260 -0
  210. package/dist/user/index.mjs.map +1 -0
  211. package/dist/utils/index.d.mts +205 -0
  212. package/dist/utils/index.d.ts +205 -0
  213. package/dist/utils/index.js +574 -0
  214. package/dist/utils/index.js.map +1 -0
  215. package/dist/utils/index.mjs +514 -0
  216. package/dist/utils/index.mjs.map +1 -0
  217. package/dist/workflow/index.d.mts +40 -0
  218. package/dist/workflow/index.d.ts +40 -0
  219. package/dist/workflow/index.js +3710 -0
  220. package/dist/workflow/index.js.map +1 -0
  221. package/dist/workflow/index.mjs +3677 -0
  222. package/dist/workflow/index.mjs.map +1 -0
  223. package/package.json +311 -0
@@ -0,0 +1,4722 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import * as React12 from 'react';
4
+ import { memo, useState, useEffect, useCallback, createContext, useMemo, useRef, useContext } from 'react';
5
+ import { cva } from 'class-variance-authority';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
9
+ import { Shield, ShieldCheck, Key, Users, Search, X, Upload, Download, Plus, Edit, Copy, Trash2, ChevronDown, Check, ChevronUp, Loader2, KeyRound, UserCheck, UserX, PanelLeft, ChevronsUpDown } from 'lucide-react';
10
+ import '@radix-ui/react-dropdown-menu';
11
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
12
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
13
+ import 'next/link';
14
+ import { useRouter } from 'next/navigation';
15
+ import 'next/image';
16
+ import 'react-day-picker';
17
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
18
+ import * as SelectPrimitive from '@radix-ui/react-select';
19
+ import '@radix-ui/react-popover';
20
+ import '@radix-ui/react-switch';
21
+ import * as LabelPrimitive from '@radix-ui/react-label';
22
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
23
+ import 'react-resizable-panels';
24
+ import '@radix-ui/react-slider';
25
+ import '@radix-ui/react-toggle';
26
+ import '@radix-ui/react-toggle-group';
27
+ import '@radix-ui/react-menubar';
28
+ import '@radix-ui/react-navigation-menu';
29
+ import '@radix-ui/react-context-menu';
30
+ import 'vaul';
31
+ import '@radix-ui/react-progress';
32
+ import { toast } from 'sonner';
33
+ import 'framer-motion';
34
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
35
+ import { useSession } from 'next-auth/react';
36
+ import 'react-use';
37
+ import '@radix-ui/react-direction';
38
+ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
39
+ import '@radix-ui/react-radio-group';
40
+ import 'cmdk';
41
+ import 'date-fns';
42
+ import dynamic from 'next/dynamic';
43
+ import 'emoji-picker-react';
44
+ import 'react-dropzone';
45
+ import 'input-otp';
46
+ import 'react-phone-number-input';
47
+ import '@tiptap/extension-color';
48
+ import '@tiptap/extension-image';
49
+ import '@tiptap/extension-link';
50
+ import '@tiptap/extension-placeholder';
51
+ import '@tiptap/extension-text-align';
52
+ import '@tiptap/extension-text-style';
53
+ import '@tiptap/extension-typography';
54
+ import '@tiptap/extension-underline';
55
+ import '@tiptap/react';
56
+ import '@tiptap/starter-kit';
57
+ import 'react-hook-form';
58
+ import 'recharts';
59
+ import 'embla-carousel-react';
60
+ import '@radix-ui/react-accordion';
61
+ import '@dnd-kit/sortable';
62
+ import '@dnd-kit/utilities';
63
+ import '@dnd-kit/core';
64
+ import 'react-dom';
65
+ import '@radix-ui/react-aspect-ratio';
66
+ import 'hast-util-to-jsx-runtime';
67
+ import 'shiki/bundle/web';
68
+ import '@radix-ui/react-collapsible';
69
+ import '@radix-ui/react-hover-card';
70
+ import '@hookform/resolvers/zod';
71
+ import useSWR from 'swr';
72
+
73
+ var __getOwnPropNames = Object.getOwnPropertyNames;
74
+ var __esm = (fn, res) => function __init() {
75
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
76
+ };
77
+ function cn(...inputs) {
78
+ return twMerge(clsx(inputs));
79
+ }
80
+ var Logger, logger;
81
+ var init_utils = __esm({
82
+ "src/utils/index.ts"() {
83
+ Logger = class {
84
+ log(level, message, context, error) {
85
+ const entry = {
86
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
87
+ level,
88
+ message,
89
+ context
90
+ };
91
+ if (error instanceof Error) {
92
+ entry.error = {
93
+ name: error.name,
94
+ message: error.message,
95
+ stack: error.stack
96
+ };
97
+ } else if (error) {
98
+ entry.error = error;
99
+ }
100
+ const logString = JSON.stringify(entry);
101
+ switch (level) {
102
+ case "error":
103
+ console.error(logString);
104
+ break;
105
+ case "warn":
106
+ console.warn(logString);
107
+ break;
108
+ case "debug":
109
+ if (process.env.NODE_ENV === "development") console.debug(logString);
110
+ break;
111
+ default:
112
+ console.log(logString);
113
+ }
114
+ }
115
+ info(message, context) {
116
+ this.log("info", message, context);
117
+ }
118
+ warn(message, context) {
119
+ this.log("warn", message, context);
120
+ }
121
+ error(message, error, context) {
122
+ this.log("error", message, context, error);
123
+ }
124
+ debug(message, context) {
125
+ this.log("debug", message, context);
126
+ }
127
+ };
128
+ logger = new Logger();
129
+ }
130
+ });
131
+ var buttonVariants, Button;
132
+ var init_button = __esm({
133
+ "src/ui/primitives/button.tsx"() {
134
+ init_utils();
135
+ buttonVariants = cva(
136
+ "inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
137
+ {
138
+ variants: {
139
+ variant: {
140
+ // Existing variants (backwards-compatible)
141
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
142
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
143
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
144
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
145
+ ghost: "hover:bg-accent hover:text-accent-foreground",
146
+ link: "text-primary underline-offset-4 hover:underline",
147
+ // New Plane-inspired variants using semantic tokens
148
+ accent: "bg-accent-primary text-text-on-color hover:bg-accent-primary-hover active:bg-accent-primary-active disabled:bg-layer-disabled disabled:text-text-disabled",
149
+ danger: "bg-danger text-text-on-color hover:bg-danger-hover active:bg-danger-hover disabled:bg-layer-disabled disabled:text-text-disabled",
150
+ "danger-outline": "border border-danger bg-layer-2 text-danger-text hover:bg-danger-subtle active:bg-danger-subtle disabled:border-border-subtle disabled:bg-layer-2 disabled:text-text-disabled",
151
+ success: "bg-success-semantic text-text-on-color hover:bg-success-semantic/90 active:bg-success-semantic/80 disabled:bg-layer-disabled disabled:text-text-disabled",
152
+ tertiary: "bg-layer-3 text-text-secondary hover:bg-layer-3-hover active:bg-layer-3-hover disabled:bg-transparent disabled:text-text-disabled"
153
+ },
154
+ size: {
155
+ // Existing sizes (backwards-compatible)
156
+ default: "h-10 px-4 py-2",
157
+ sm: "h-9 rounded-md px-3",
158
+ lg: "h-11 rounded-md px-8",
159
+ icon: "h-10 w-10",
160
+ // New ERP-specific compact sizes
161
+ xs: "h-7 rounded-sm px-2 text-xs",
162
+ compact: "h-8 rounded-md px-3 text-xs",
163
+ "icon-sm": "h-8 w-8",
164
+ "icon-xs": "h-7 w-7"
165
+ }
166
+ },
167
+ defaultVariants: {
168
+ variant: "default",
169
+ size: "default"
170
+ }
171
+ }
172
+ );
173
+ Button = React12.forwardRef(
174
+ ({ className, variant, size, asChild = false, loading = false, prependIcon, appendIcon, children, disabled, ...props }, ref) => {
175
+ if (asChild) {
176
+ return /* @__PURE__ */ jsx(
177
+ Slot,
178
+ {
179
+ className: cn(buttonVariants({ variant, size }), className),
180
+ ref,
181
+ ...{ disabled: disabled || loading },
182
+ ...props,
183
+ children: React12.isValidElement(children) && (prependIcon || appendIcon) ? React12.cloneElement(children, {}, /* @__PURE__ */ jsxs(Fragment, { children: [
184
+ prependIcon && React12.cloneElement(prependIcon, {
185
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4")
186
+ }),
187
+ children.props.children,
188
+ appendIcon && React12.cloneElement(appendIcon, {
189
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4")
190
+ })
191
+ ] })) : children
192
+ }
193
+ );
194
+ }
195
+ return /* @__PURE__ */ jsxs(
196
+ "button",
197
+ {
198
+ className: cn(buttonVariants({ variant, size }), className),
199
+ ref,
200
+ disabled: disabled || loading,
201
+ ...props,
202
+ children: [
203
+ prependIcon && React12.cloneElement(prependIcon, {
204
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4")
205
+ }),
206
+ children,
207
+ appendIcon && React12.cloneElement(appendIcon, {
208
+ className: cn("shrink-0", size === "xs" || size === "compact" ? "size-3.5" : "size-4")
209
+ })
210
+ ]
211
+ }
212
+ );
213
+ }
214
+ );
215
+ Button.displayName = "Button";
216
+ }
217
+ });
218
+ function Badge({ className, variant, size, ...props }) {
219
+ return /* @__PURE__ */ jsx("div", { className: cn(badgeVariants({ variant, size }), className), ...props });
220
+ }
221
+ var badgeVariants;
222
+ var init_badge = __esm({
223
+ "src/ui/primitives/badge.tsx"() {
224
+ init_utils();
225
+ badgeVariants = cva(
226
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
227
+ {
228
+ variants: {
229
+ variant: {
230
+ // Existing variants (backwards-compatible)
231
+ default: "border-transparent bg-primary text-primary-foreground",
232
+ secondary: "border-transparent bg-secondary text-secondary-foreground",
233
+ destructive: "border-transparent bg-destructive text-destructive-foreground",
234
+ outline: "text-foreground",
235
+ // Enhanced semantic variants (using Design Tokens)
236
+ success: "border-transparent bg-success-subtle text-success-text",
237
+ warning: "border-transparent bg-warning-subtle text-warning-text",
238
+ danger: "border-transparent bg-danger-subtle text-danger-text",
239
+ info: "border-transparent bg-info-subtle text-info-text",
240
+ accent: "border-transparent bg-accent-primary-subtle text-accent-primary"
241
+ },
242
+ size: {
243
+ default: "",
244
+ sm: "px-1.5 py-0 text-[10px]",
245
+ lg: "px-3 py-1 text-sm"
246
+ }
247
+ },
248
+ defaultVariants: {
249
+ variant: "default",
250
+ size: "default"
251
+ }
252
+ }
253
+ );
254
+ }
255
+ });
256
+ var Input;
257
+ var init_input = __esm({
258
+ "src/ui/primitives/input.tsx"() {
259
+ init_utils();
260
+ Input = React12.forwardRef(
261
+ ({ className, type, ...props }, ref) => {
262
+ return /* @__PURE__ */ jsx(
263
+ "input",
264
+ {
265
+ type,
266
+ className: cn(
267
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
268
+ className
269
+ ),
270
+ ref,
271
+ ...props
272
+ }
273
+ );
274
+ }
275
+ );
276
+ Input.displayName = "Input";
277
+ }
278
+ });
279
+ var Checkbox;
280
+ var init_checkbox = __esm({
281
+ "src/ui/primitives/checkbox.tsx"() {
282
+ "use client";
283
+ init_utils();
284
+ Checkbox = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
285
+ CheckboxPrimitive.Root,
286
+ {
287
+ ref,
288
+ className: cn(
289
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
290
+ className
291
+ ),
292
+ ...props,
293
+ children: /* @__PURE__ */ jsx(
294
+ CheckboxPrimitive.Indicator,
295
+ {
296
+ className: cn("flex items-center justify-center text-current"),
297
+ children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" })
298
+ }
299
+ )
300
+ }
301
+ ));
302
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
303
+ }
304
+ });
305
+ var Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter;
306
+ var init_card = __esm({
307
+ "src/ui/primitives/card.tsx"() {
308
+ init_utils();
309
+ Card = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
310
+ "div",
311
+ {
312
+ ref,
313
+ className: cn(
314
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
315
+ className
316
+ ),
317
+ ...props
318
+ }
319
+ ));
320
+ Card.displayName = "Card";
321
+ CardHeader = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
322
+ "div",
323
+ {
324
+ ref,
325
+ className: cn("flex flex-col space-y-1.5 p-6", className),
326
+ ...props
327
+ }
328
+ ));
329
+ CardHeader.displayName = "CardHeader";
330
+ CardTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
331
+ "h3",
332
+ {
333
+ ref,
334
+ className: cn(
335
+ "text-2xl font-semibold leading-none tracking-tight",
336
+ className
337
+ ),
338
+ ...props
339
+ }
340
+ ));
341
+ CardTitle.displayName = "CardTitle";
342
+ CardDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
343
+ "p",
344
+ {
345
+ ref,
346
+ className: cn("text-sm text-muted-foreground", className),
347
+ ...props
348
+ }
349
+ ));
350
+ CardDescription.displayName = "CardDescription";
351
+ CardContent = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
352
+ CardContent.displayName = "CardContent";
353
+ CardFooter = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
354
+ "div",
355
+ {
356
+ ref,
357
+ className: cn("flex items-center p-6 pt-0", className),
358
+ ...props
359
+ }
360
+ ));
361
+ CardFooter.displayName = "CardFooter";
362
+ }
363
+ });
364
+ var Separator;
365
+ var init_separator = __esm({
366
+ "src/ui/primitives/separator.tsx"() {
367
+ init_utils();
368
+ Separator = React12.forwardRef(
369
+ ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx(
370
+ "div",
371
+ {
372
+ ref,
373
+ className: cn(
374
+ "shrink-0 bg-border",
375
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
376
+ className
377
+ ),
378
+ ...props
379
+ }
380
+ )
381
+ );
382
+ Separator.displayName = "Separator";
383
+ }
384
+ });
385
+ var Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption;
386
+ var init_table = __esm({
387
+ "src/ui/primitives/table.tsx"() {
388
+ init_utils();
389
+ Table = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
390
+ "table",
391
+ {
392
+ ref,
393
+ className: cn("w-max min-w-full caption-bottom text-xs", className),
394
+ ...props
395
+ }
396
+ ) }));
397
+ Table.displayName = "Table";
398
+ TableHeader = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
399
+ TableHeader.displayName = "TableHeader";
400
+ TableBody = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
401
+ "tbody",
402
+ {
403
+ ref,
404
+ className: cn("[&_tr:last-child]:border-0", className),
405
+ ...props
406
+ }
407
+ ));
408
+ TableBody.displayName = "TableBody";
409
+ TableFooter = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
410
+ "tfoot",
411
+ {
412
+ ref,
413
+ className: cn(
414
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
415
+ className
416
+ ),
417
+ ...props
418
+ }
419
+ ));
420
+ TableFooter.displayName = "TableFooter";
421
+ TableRow = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
422
+ "tr",
423
+ {
424
+ ref,
425
+ className: cn(
426
+ "border-b transition-colors even:bg-muted/30 data-[state=selected]:bg-muted",
427
+ className
428
+ ),
429
+ ...props
430
+ }
431
+ ));
432
+ TableRow.displayName = "TableRow";
433
+ TableHead = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
434
+ "th",
435
+ {
436
+ ref,
437
+ className: cn(
438
+ "h-9 px-3 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
439
+ className
440
+ ),
441
+ ...props
442
+ }
443
+ ));
444
+ TableHead.displayName = "TableHead";
445
+ TableCell = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
446
+ "td",
447
+ {
448
+ ref,
449
+ className: cn("px-3 py-1.5 align-middle [&:has([role=checkbox])]:pr-0 text-xs", className),
450
+ ...props
451
+ }
452
+ ));
453
+ TableCell.displayName = "TableCell";
454
+ TableCaption = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
455
+ "caption",
456
+ {
457
+ ref,
458
+ className: cn("mt-4 text-sm text-muted-foreground", className),
459
+ ...props
460
+ }
461
+ ));
462
+ TableCaption.displayName = "TableCaption";
463
+ }
464
+ });
465
+ var init_dropdown_menu = __esm({
466
+ "src/ui/primitives/dropdown-menu.tsx"() {
467
+ "use client";
468
+ }
469
+ });
470
+ var Dialog, DialogPortal, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription;
471
+ var init_dialog = __esm({
472
+ "src/ui/primitives/dialog.tsx"() {
473
+ "use client";
474
+ init_utils();
475
+ Dialog = DialogPrimitive.Root;
476
+ DialogPortal = DialogPrimitive.Portal;
477
+ DialogOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
478
+ DialogPrimitive.Overlay,
479
+ {
480
+ ref,
481
+ className: cn(
482
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
483
+ className
484
+ ),
485
+ ...props
486
+ }
487
+ ));
488
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
489
+ DialogContent = React12.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
490
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
491
+ /* @__PURE__ */ jsxs(
492
+ DialogPrimitive.Content,
493
+ {
494
+ ref,
495
+ className: cn(
496
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
497
+ className
498
+ ),
499
+ ...props,
500
+ children: [
501
+ children,
502
+ /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
503
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
504
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
505
+ ] })
506
+ ]
507
+ }
508
+ )
509
+ ] }));
510
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
511
+ DialogHeader = ({
512
+ className,
513
+ ...props
514
+ }) => /* @__PURE__ */ jsx(
515
+ "div",
516
+ {
517
+ className: cn(
518
+ "flex flex-col space-y-1.5 text-center sm:text-left",
519
+ className
520
+ ),
521
+ ...props
522
+ }
523
+ );
524
+ DialogHeader.displayName = "DialogHeader";
525
+ DialogFooter = ({
526
+ className,
527
+ ...props
528
+ }) => /* @__PURE__ */ jsx(
529
+ "div",
530
+ {
531
+ className: cn(
532
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
533
+ className
534
+ ),
535
+ ...props
536
+ }
537
+ );
538
+ DialogFooter.displayName = "DialogFooter";
539
+ DialogTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
540
+ DialogPrimitive.Title,
541
+ {
542
+ ref,
543
+ className: cn(
544
+ "text-lg font-semibold leading-none tracking-tight",
545
+ className
546
+ ),
547
+ ...props
548
+ }
549
+ ));
550
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
551
+ DialogDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
552
+ DialogPrimitive.Description,
553
+ {
554
+ ref,
555
+ className: cn("text-sm text-muted-foreground", className),
556
+ ...props
557
+ }
558
+ ));
559
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
560
+ }
561
+ });
562
+ var TabsList, TabsTrigger, TabsContent;
563
+ var init_tabs = __esm({
564
+ "src/ui/primitives/tabs.tsx"() {
565
+ "use client";
566
+ init_utils();
567
+ TabsList = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
568
+ TabsPrimitive.List,
569
+ {
570
+ ref,
571
+ className: cn(
572
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
573
+ className
574
+ ),
575
+ ...props
576
+ }
577
+ ));
578
+ TabsList.displayName = TabsPrimitive.List.displayName;
579
+ TabsTrigger = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
580
+ TabsPrimitive.Trigger,
581
+ {
582
+ ref,
583
+ className: cn(
584
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
585
+ className
586
+ ),
587
+ ...props
588
+ }
589
+ ));
590
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
591
+ TabsContent = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
592
+ TabsPrimitive.Content,
593
+ {
594
+ ref,
595
+ className: cn(
596
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
597
+ className
598
+ ),
599
+ ...props
600
+ }
601
+ ));
602
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
603
+ }
604
+ });
605
+ var init_breadcrumb = __esm({
606
+ "src/ui/primitives/breadcrumb.tsx"() {
607
+ }
608
+ });
609
+ var init_keyboard = __esm({
610
+ "src/ui/primitives/keyboard.tsx"() {
611
+ }
612
+ });
613
+ var init_pagination = __esm({
614
+ "src/ui/primitives/pagination.tsx"() {
615
+ }
616
+ });
617
+ var init_status_badge = __esm({
618
+ "src/ui/primitives/status-badge.tsx"() {
619
+ }
620
+ });
621
+ var init_command_menu = __esm({
622
+ "src/ui/layout/command-menu.tsx"() {
623
+ "use client";
624
+ }
625
+ });
626
+ var init_logo = __esm({
627
+ "src/ui/layout/logo.tsx"() {
628
+ "use client";
629
+ }
630
+ });
631
+ var init_sidebar_group_icon_menu = __esm({
632
+ "src/ui/layout/sidebar-group-icon-menu.tsx"() {
633
+ "use client";
634
+ }
635
+ });
636
+ var init_sidebar = __esm({
637
+ "src/ui/layout/sidebar.tsx"() {
638
+ "use client";
639
+ }
640
+ });
641
+ var init_calendar = __esm({
642
+ "src/ui/primitives/calendar.tsx"() {
643
+ "use client";
644
+ init_utils();
645
+ init_button();
646
+ }
647
+ });
648
+ function ScrollArea({
649
+ orientation,
650
+ className,
651
+ children,
652
+ ...props
653
+ }) {
654
+ return /* @__PURE__ */ jsxs(
655
+ ScrollAreaPrimitive.Root,
656
+ {
657
+ "data-slot": "scroll-area",
658
+ className: cn("relative overflow-hidden", className),
659
+ ...props,
660
+ children: [
661
+ /* @__PURE__ */ jsx(
662
+ ScrollAreaPrimitive.Viewport,
663
+ {
664
+ "data-slot": "scroll-area-viewport",
665
+ className: "h-full w-full rounded-[inherit]",
666
+ children
667
+ }
668
+ ),
669
+ /* @__PURE__ */ jsx(ScrollBar, { orientation }),
670
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
671
+ ]
672
+ }
673
+ );
674
+ }
675
+ function ScrollBar({
676
+ className,
677
+ orientation = "vertical",
678
+ ...props
679
+ }) {
680
+ return /* @__PURE__ */ jsx(
681
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
682
+ {
683
+ "data-slot": "scroll-area-scrollbar",
684
+ orientation,
685
+ className: cn(
686
+ "flex touch-none select-none transition-colors",
687
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
688
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
689
+ className
690
+ ),
691
+ ...props,
692
+ children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
693
+ }
694
+ );
695
+ }
696
+ var init_scroll_area = __esm({
697
+ "src/ui/primitives/scroll-area.tsx"() {
698
+ "use client";
699
+ init_utils();
700
+ }
701
+ });
702
+ var init_combobox = __esm({
703
+ "src/ui/primitives/combobox.tsx"() {
704
+ "use client";
705
+ }
706
+ });
707
+ function Select({
708
+ ...props
709
+ }) {
710
+ return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
711
+ }
712
+ function SelectValue({
713
+ ...props
714
+ }) {
715
+ return /* @__PURE__ */ jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
716
+ }
717
+ function SelectTrigger({
718
+ className,
719
+ children,
720
+ ...props
721
+ }) {
722
+ return /* @__PURE__ */ jsxs(
723
+ SelectPrimitive.Trigger,
724
+ {
725
+ "data-slot": "select-trigger",
726
+ className: cn(
727
+ "cursor-pointer flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
728
+ className
729
+ ),
730
+ ...props,
731
+ children: [
732
+ children,
733
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
734
+ ]
735
+ }
736
+ );
737
+ }
738
+ function SelectScrollUpButton({
739
+ className,
740
+ ...props
741
+ }) {
742
+ return /* @__PURE__ */ jsx(
743
+ SelectPrimitive.ScrollUpButton,
744
+ {
745
+ "data-slot": "select-scroll-up-button",
746
+ className: cn(
747
+ "flex cursor-pointer items-center justify-center py-1",
748
+ className
749
+ ),
750
+ ...props,
751
+ children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
752
+ }
753
+ );
754
+ }
755
+ function SelectScrollDownButton({
756
+ className,
757
+ ...props
758
+ }) {
759
+ return /* @__PURE__ */ jsx(
760
+ SelectPrimitive.ScrollDownButton,
761
+ {
762
+ "data-slot": "select-scroll-down-button",
763
+ className: cn(
764
+ "flex cursor-pointer items-center justify-center py-1",
765
+ className
766
+ ),
767
+ ...props,
768
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
769
+ }
770
+ );
771
+ }
772
+ function SelectContent({
773
+ className,
774
+ children,
775
+ position = "popper",
776
+ ...props
777
+ }) {
778
+ return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
779
+ SelectPrimitive.Content,
780
+ {
781
+ "data-slot": "select-content",
782
+ className: cn(
783
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
784
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
785
+ className
786
+ ),
787
+ position,
788
+ ...props,
789
+ children: [
790
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
791
+ /* @__PURE__ */ jsx(
792
+ SelectPrimitive.Viewport,
793
+ {
794
+ className: cn(
795
+ "p-1",
796
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
797
+ ),
798
+ children
799
+ }
800
+ ),
801
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
802
+ ]
803
+ }
804
+ ) });
805
+ }
806
+ function SelectItem({
807
+ className,
808
+ children,
809
+ ...props
810
+ }) {
811
+ return /* @__PURE__ */ jsxs(
812
+ SelectPrimitive.Item,
813
+ {
814
+ "data-slot": "select-item",
815
+ className: cn(
816
+ "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
817
+ className
818
+ ),
819
+ ...props,
820
+ children: [
821
+ /* @__PURE__ */ jsx("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
822
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
823
+ ]
824
+ }
825
+ );
826
+ }
827
+ var init_select = __esm({
828
+ "src/ui/primitives/select.tsx"() {
829
+ "use client";
830
+ init_utils();
831
+ }
832
+ });
833
+ var init_popover = __esm({
834
+ "src/ui/primitives/popover.tsx"() {
835
+ "use client";
836
+ }
837
+ });
838
+ var init_switch = __esm({
839
+ "src/ui/primitives/switch.tsx"() {
840
+ "use client";
841
+ }
842
+ });
843
+ var Label3;
844
+ var init_label = __esm({
845
+ "src/ui/primitives/label.tsx"() {
846
+ "use client";
847
+ init_utils();
848
+ Label3 = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
849
+ LabelPrimitive.Root,
850
+ {
851
+ ref,
852
+ className: cn(
853
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
854
+ className
855
+ ),
856
+ ...props
857
+ }
858
+ ));
859
+ Label3.displayName = LabelPrimitive.Root.displayName;
860
+ }
861
+ });
862
+ function TooltipProvider({
863
+ delayDuration = 0,
864
+ ...props
865
+ }) {
866
+ return /* @__PURE__ */ jsx(
867
+ TooltipPrimitive.Provider,
868
+ {
869
+ "data-slot": "tooltip-provider",
870
+ delayDuration,
871
+ ...props
872
+ }
873
+ );
874
+ }
875
+ function Tooltip({
876
+ ...props
877
+ }) {
878
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
879
+ }
880
+ function TooltipTrigger({
881
+ className,
882
+ ...props
883
+ }) {
884
+ return /* @__PURE__ */ jsx(
885
+ TooltipPrimitive.Trigger,
886
+ {
887
+ "data-slot": "tooltip-trigger",
888
+ className: cn("cursor-pointer", className),
889
+ ...props
890
+ }
891
+ );
892
+ }
893
+ function TooltipContent({
894
+ className,
895
+ sideOffset = 0,
896
+ ...props
897
+ }) {
898
+ return /* @__PURE__ */ jsx(
899
+ TooltipPrimitive.Content,
900
+ {
901
+ "data-slot": "tooltip-content",
902
+ sideOffset,
903
+ className: cn(
904
+ "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
905
+ className
906
+ ),
907
+ ...props
908
+ }
909
+ );
910
+ }
911
+ var init_tooltip = __esm({
912
+ "src/ui/primitives/tooltip.tsx"() {
913
+ "use client";
914
+ init_utils();
915
+ }
916
+ });
917
+ var init_resizable = __esm({
918
+ "src/ui/primitives/resizable.tsx"() {
919
+ "use client";
920
+ }
921
+ });
922
+ var init_slider = __esm({
923
+ "src/ui/primitives/slider.tsx"() {
924
+ "use client";
925
+ }
926
+ });
927
+ var init_toggle = __esm({
928
+ "src/ui/primitives/toggle.tsx"() {
929
+ "use client";
930
+ cva(
931
+ "cursor-pointer inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
932
+ {
933
+ variants: {
934
+ variant: {
935
+ default: "bg-transparent",
936
+ outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"
937
+ },
938
+ size: {
939
+ default: "h-9 px-3",
940
+ sm: "h-8 px-2",
941
+ lg: "h-10 px-3"
942
+ }
943
+ },
944
+ defaultVariants: {
945
+ variant: "default",
946
+ size: "default"
947
+ }
948
+ }
949
+ );
950
+ }
951
+ });
952
+ var init_toggle_group = __esm({
953
+ "src/ui/primitives/toggle-group.tsx"() {
954
+ "use client";
955
+ createContext({
956
+ size: "default",
957
+ variant: "default"
958
+ });
959
+ }
960
+ });
961
+ var init_menubar = __esm({
962
+ "src/ui/primitives/menubar.tsx"() {
963
+ "use client";
964
+ }
965
+ });
966
+ var init_navigation_menu = __esm({
967
+ "src/ui/primitives/navigation-menu.tsx"() {
968
+ cva(
969
+ "group cursor-pointer inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
970
+ );
971
+ }
972
+ });
973
+ var init_sticky_layout = __esm({
974
+ "src/ui/primitives/sticky-layout.tsx"() {
975
+ }
976
+ });
977
+ var init_prefetch_link = __esm({
978
+ "src/ui/primitives/prefetch-link.tsx"() {
979
+ "use client";
980
+ }
981
+ });
982
+ var init_dynamic_icon = __esm({
983
+ "src/ui/primitives/dynamic-icon.tsx"() {
984
+ "use client";
985
+ }
986
+ });
987
+ var InputNumber;
988
+ var init_input_number = __esm({
989
+ "src/ui/primitives/input-number.tsx"() {
990
+ "use client";
991
+ init_utils();
992
+ init_input();
993
+ InputNumber = React12.forwardRef(
994
+ ({ value, onChange, className, decimalScale = 0, suffix, ...props }, ref) => {
995
+ const [displayValue, setDisplayValue] = React12.useState("");
996
+ const parseDisplayValue = (val) => {
997
+ const clean = val.replace(/\./g, "").replace(",", ".");
998
+ return Number(clean);
999
+ };
1000
+ const formatNumber = React12.useCallback(
1001
+ (num) => {
1002
+ return new Intl.NumberFormat("vi-VN", {
1003
+ maximumFractionDigits: decimalScale,
1004
+ minimumFractionDigits: 0
1005
+ }).format(num);
1006
+ },
1007
+ [decimalScale]
1008
+ );
1009
+ React12.useEffect(() => {
1010
+ if (value === null || value === void 0 || value === "") {
1011
+ setDisplayValue("");
1012
+ return;
1013
+ }
1014
+ const numValue = Number(value);
1015
+ if (isNaN(numValue)) return;
1016
+ const currentNum = parseDisplayValue(displayValue);
1017
+ if (currentNum !== numValue) {
1018
+ setDisplayValue(formatNumber(numValue));
1019
+ }
1020
+ }, [value, decimalScale, displayValue, formatNumber]);
1021
+ const handleChange = (e) => {
1022
+ const rawValue = e.target.value;
1023
+ let cleanVal = rawValue.replace(/[^0-9,]/g, "");
1024
+ const parts = cleanVal.split(",");
1025
+ if (parts.length > 2) {
1026
+ cleanVal = parts[0] + "," + parts.slice(1).join("");
1027
+ }
1028
+ if (cleanVal === "") {
1029
+ setDisplayValue("");
1030
+ onChange?.(null);
1031
+ return;
1032
+ }
1033
+ const [integerPart, decimalPart] = cleanVal.split(",");
1034
+ let formattedInteger = integerPart;
1035
+ if (integerPart) {
1036
+ formattedInteger = new Intl.NumberFormat("vi-VN").format(
1037
+ Number(integerPart)
1038
+ );
1039
+ }
1040
+ let newDisplayValue = formattedInteger;
1041
+ let finalDecimalPart = decimalPart;
1042
+ if (decimalPart !== void 0) {
1043
+ if (decimalScale !== void 0 && decimalPart.length > decimalScale) {
1044
+ finalDecimalPart = decimalPart.substring(0, decimalScale);
1045
+ }
1046
+ newDisplayValue += "," + finalDecimalPart;
1047
+ }
1048
+ setDisplayValue(newDisplayValue);
1049
+ let numStr = integerPart;
1050
+ if (finalDecimalPart !== void 0) {
1051
+ numStr += "." + finalDecimalPart;
1052
+ }
1053
+ const numValue = Number(numStr.replace(/\./g, ""));
1054
+ onChange?.(numValue);
1055
+ };
1056
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1057
+ /* @__PURE__ */ jsx(
1058
+ Input,
1059
+ {
1060
+ ...props,
1061
+ ref,
1062
+ type: "text",
1063
+ inputMode: "numeric",
1064
+ value: displayValue,
1065
+ onChange: handleChange,
1066
+ className: cn("pr-8", className)
1067
+ }
1068
+ ),
1069
+ suffix && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none text-muted-foreground text-sm", children: suffix })
1070
+ ] });
1071
+ }
1072
+ );
1073
+ InputNumber.displayName = "InputNumber";
1074
+ }
1075
+ });
1076
+ function Sheet({
1077
+ ...props
1078
+ }) {
1079
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "sheet", ...props });
1080
+ }
1081
+ function SheetPortal({
1082
+ ...props
1083
+ }) {
1084
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
1085
+ }
1086
+ function SheetOverlay({
1087
+ className,
1088
+ ...props
1089
+ }) {
1090
+ return /* @__PURE__ */ jsx(
1091
+ DialogPrimitive.Overlay,
1092
+ {
1093
+ "data-slot": "sheet-overlay",
1094
+ className: cn(
1095
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1096
+ className
1097
+ ),
1098
+ ...props
1099
+ }
1100
+ );
1101
+ }
1102
+ function SheetContent({
1103
+ className,
1104
+ children,
1105
+ side = "right",
1106
+ ...props
1107
+ }) {
1108
+ return /* @__PURE__ */ jsxs(SheetPortal, { children: [
1109
+ /* @__PURE__ */ jsx(SheetOverlay, {}),
1110
+ /* @__PURE__ */ jsx(
1111
+ DialogPrimitive.Content,
1112
+ {
1113
+ "data-slot": "sheet-content",
1114
+ className: cn(sheetVariants({ side }), className),
1115
+ ...props,
1116
+ children
1117
+ }
1118
+ )
1119
+ ] });
1120
+ }
1121
+ function SheetTitle({
1122
+ className,
1123
+ ...props
1124
+ }) {
1125
+ return /* @__PURE__ */ jsx(
1126
+ DialogPrimitive.Title,
1127
+ {
1128
+ "data-slot": "sheet-title",
1129
+ className: cn("text-lg font-semibold text-foreground", className),
1130
+ ...props
1131
+ }
1132
+ );
1133
+ }
1134
+ var sheetVariants;
1135
+ var init_sheet = __esm({
1136
+ "src/ui/feedback/sheet.tsx"() {
1137
+ "use client";
1138
+ init_utils();
1139
+ sheetVariants = cva(
1140
+ "fixed z-50 gap-4 bg-background p-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
1141
+ {
1142
+ variants: {
1143
+ side: {
1144
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1145
+ bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
1146
+ left: "inset-y-0 left-0 h-full w-72 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
1147
+ right: "inset-y-0 right-0 h-full w-72 border-s data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
1148
+ start: "inset-y-0 start-0 h-full w-72 border-e data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left data-[state=closed]:rtl:slide-out-to-right data-[state=open]:rtl:slide-in-from-right sm:max-w-sm",
1149
+ end: "inset-y-0 end-0 h-full w-72 border-s data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right data-[state=closed]:rtl:slide-out-to-left data-[state=open]:rtl:slide-in-from-left sm:max-w-sm"
1150
+ }
1151
+ },
1152
+ defaultVariants: {
1153
+ side: "right"
1154
+ }
1155
+ }
1156
+ );
1157
+ }
1158
+ });
1159
+ var init_context_menu = __esm({
1160
+ "src/ui/feedback/context-menu.tsx"() {
1161
+ "use client";
1162
+ }
1163
+ });
1164
+ var init_drawer = __esm({
1165
+ "src/ui/feedback/drawer.tsx"() {
1166
+ "use client";
1167
+ }
1168
+ });
1169
+ var init_progress = __esm({
1170
+ "src/ui/feedback/progress.tsx"() {
1171
+ "use client";
1172
+ }
1173
+ });
1174
+ var init_sonner = __esm({
1175
+ "src/ui/feedback/sonner.tsx"() {
1176
+ "use client";
1177
+ }
1178
+ });
1179
+
1180
+ // src/ui/primitives/client.ts
1181
+ var init_client = __esm({
1182
+ "src/ui/primitives/client.ts"() {
1183
+ "use client";
1184
+ init_calendar();
1185
+ init_combobox();
1186
+ init_scroll_area();
1187
+ init_select();
1188
+ init_popover();
1189
+ init_dropdown_menu();
1190
+ init_switch();
1191
+ init_checkbox();
1192
+ init_label();
1193
+ init_tooltip();
1194
+ init_sidebar2();
1195
+ init_resizable();
1196
+ init_slider();
1197
+ init_toggle();
1198
+ init_toggle_group();
1199
+ init_menubar();
1200
+ init_navigation_menu();
1201
+ init_sticky_layout();
1202
+ init_prefetch_link();
1203
+ init_dynamic_icon();
1204
+ init_input_number();
1205
+ init_sheet();
1206
+ init_context_menu();
1207
+ init_drawer();
1208
+ init_progress();
1209
+ init_sonner();
1210
+ }
1211
+ });
1212
+ var init_language_dropdown = __esm({
1213
+ "src/ui/layout/language-dropdown.tsx"() {
1214
+ "use client";
1215
+ }
1216
+ });
1217
+ var init_footer = __esm({
1218
+ "src/ui/layout/footer.tsx"() {
1219
+ }
1220
+ });
1221
+ var init_header_breadcrumb = __esm({
1222
+ "src/ui/layout/header-breadcrumb.tsx"() {
1223
+ "use client";
1224
+ }
1225
+ });
1226
+ var init_animated_list = __esm({
1227
+ "src/ui/layout/animated-list.tsx"() {
1228
+ }
1229
+ });
1230
+ var init_animated_sidebar = __esm({
1231
+ "src/ui/layout/animated-sidebar.tsx"() {
1232
+ "use client";
1233
+ }
1234
+ });
1235
+ var init_customizer = __esm({
1236
+ "src/ui/layout/customizer.tsx"() {
1237
+ "use client";
1238
+ }
1239
+ });
1240
+ function Avatar({
1241
+ className,
1242
+ ...props
1243
+ }) {
1244
+ return /* @__PURE__ */ jsx(
1245
+ AvatarPrimitive.Root,
1246
+ {
1247
+ "data-slot": "avatar",
1248
+ className: cn("relative flex h-10 w-10 shrink-0", className),
1249
+ ...props
1250
+ }
1251
+ );
1252
+ }
1253
+ function AvatarImage({
1254
+ className,
1255
+ ...props
1256
+ }) {
1257
+ return /* @__PURE__ */ jsx(
1258
+ AvatarPrimitive.Image,
1259
+ {
1260
+ "data-slot": "avatar-image",
1261
+ className: cn(
1262
+ "aspect-square h-full w-full bg-muted rounded-lg object-cover",
1263
+ className
1264
+ ),
1265
+ ...props
1266
+ }
1267
+ );
1268
+ }
1269
+ function AvatarFallback({
1270
+ className,
1271
+ ...props
1272
+ }) {
1273
+ return /* @__PURE__ */ jsx(
1274
+ AvatarPrimitive.Fallback,
1275
+ {
1276
+ className: cn(
1277
+ "flex h-full w-full items-center justify-center bg-muted rounded-lg",
1278
+ className
1279
+ ),
1280
+ ...props
1281
+ }
1282
+ );
1283
+ }
1284
+ var init_avatar = __esm({
1285
+ "src/ui/data-display/avatar.tsx"() {
1286
+ "use client";
1287
+ init_utils();
1288
+ cva(
1289
+ "transition duration-300 hover:scale-105 hover:z-10",
1290
+ {
1291
+ variants: {
1292
+ size: {
1293
+ default: "h-10 w-10",
1294
+ sm: "h-9 w-9 text-sm",
1295
+ lg: "h-11 w-11"
1296
+ }
1297
+ },
1298
+ defaultVariants: {
1299
+ size: "default"
1300
+ }
1301
+ }
1302
+ );
1303
+ }
1304
+ });
1305
+ function useTabContentCache() {
1306
+ const context = useContext(TabContentCacheContext);
1307
+ return context ?? noopTabContentCache;
1308
+ }
1309
+ var TabContentCacheContext, noopTabContentCache;
1310
+ var init_tab_content_cache = __esm({
1311
+ "src/ui/layout/tab-content-cache.tsx"() {
1312
+ "use client";
1313
+ TabContentCacheContext = createContext(void 0);
1314
+ noopTabContentCache = {
1315
+ getCachedContent: () => null,
1316
+ setCachedContent: () => {
1317
+ },
1318
+ clearCache: () => {
1319
+ },
1320
+ clearAllCache: () => {
1321
+ },
1322
+ isCached: () => false
1323
+ };
1324
+ }
1325
+ });
1326
+ function useTabNavigation() {
1327
+ const context = useContext(TabNavigationContext);
1328
+ return context ?? noopTabNavigation;
1329
+ }
1330
+ var TabNavigationContext, noopTabNavigation;
1331
+ var init_tab_navigation_provider = __esm({
1332
+ "src/ui/layout/tab-navigation-provider.tsx"() {
1333
+ "use client";
1334
+ TabNavigationContext = createContext(void 0);
1335
+ noopTabNavigation = {
1336
+ tabs: [],
1337
+ activeTabId: null,
1338
+ addTab: () => {
1339
+ },
1340
+ removeTab: () => {
1341
+ },
1342
+ setActiveTab: () => {
1343
+ },
1344
+ clearTabs: () => {
1345
+ },
1346
+ removeOtherTabs: () => {
1347
+ },
1348
+ removeTabsToRight: () => {
1349
+ },
1350
+ goToNextTab: () => {
1351
+ },
1352
+ goToPreviousTab: () => {
1353
+ },
1354
+ goToTabByIndex: () => {
1355
+ },
1356
+ closeAndGoToParent: () => {
1357
+ }
1358
+ };
1359
+ }
1360
+ });
1361
+ var init_user_dropdown = __esm({
1362
+ "src/ui/layout/user-dropdown.tsx"() {
1363
+ "use client";
1364
+ }
1365
+ });
1366
+ var init_notification_dropdown = __esm({
1367
+ "src/ui/layout/notification-dropdown.tsx"() {
1368
+ "use client";
1369
+ }
1370
+ });
1371
+ var init_mode_dropdown = __esm({
1372
+ "src/ui/layout/mode-dropdown.tsx"() {
1373
+ "use client";
1374
+ }
1375
+ });
1376
+ var init_full_screen_toggle = __esm({
1377
+ "src/ui/layout/full-screen-toggle.tsx"() {
1378
+ "use client";
1379
+ }
1380
+ });
1381
+ var init_route_cache = __esm({
1382
+ "src/ui/layout/route-cache.tsx"() {
1383
+ "use client";
1384
+ createContext(
1385
+ void 0
1386
+ );
1387
+ }
1388
+ });
1389
+ var init_page_tabs = __esm({
1390
+ "src/ui/layout/page-tabs.tsx"() {
1391
+ "use client";
1392
+ }
1393
+ });
1394
+ var init_toggle_mobile_sidebar = __esm({
1395
+ "src/ui/layout/toggle-mobile-sidebar.tsx"() {
1396
+ "use client";
1397
+ }
1398
+ });
1399
+ var init_top_bar_header_menubar = __esm({
1400
+ "src/ui/layout/top-bar-header-menubar.tsx"() {
1401
+ "use client";
1402
+ }
1403
+ });
1404
+ var init_vertical_layout_header = __esm({
1405
+ "src/ui/layout/vertical-layout-header.tsx"() {
1406
+ "use client";
1407
+ }
1408
+ });
1409
+ var init_horizontal_layout_header = __esm({
1410
+ "src/ui/layout/horizontal-layout-header.tsx"() {
1411
+ "use client";
1412
+ }
1413
+ });
1414
+ var init_vertical_layout = __esm({
1415
+ "src/ui/layout/vertical-layout.tsx"() {
1416
+ "use client";
1417
+ }
1418
+ });
1419
+ var init_horizontal_layout = __esm({
1420
+ "src/ui/layout/horizontal-layout.tsx"() {
1421
+ "use client";
1422
+ }
1423
+ });
1424
+ var init_main_layout = __esm({
1425
+ "src/ui/layout/main-layout.tsx"() {
1426
+ "use client";
1427
+ }
1428
+ });
1429
+
1430
+ // src/ui/layout/index.tsx
1431
+ var init_layout = __esm({
1432
+ "src/ui/layout/index.tsx"() {
1433
+ init_sidebar();
1434
+ init_language_dropdown();
1435
+ init_footer();
1436
+ init_logo();
1437
+ init_header_breadcrumb();
1438
+ init_animated_list();
1439
+ init_animated_sidebar();
1440
+ init_command_menu();
1441
+ init_sidebar_group_icon_menu();
1442
+ init_customizer();
1443
+ init_user_dropdown();
1444
+ init_notification_dropdown();
1445
+ init_mode_dropdown();
1446
+ init_full_screen_toggle();
1447
+ init_page_tabs();
1448
+ init_tab_navigation_provider();
1449
+ init_route_cache();
1450
+ init_toggle_mobile_sidebar();
1451
+ init_top_bar_header_menubar();
1452
+ init_vertical_layout_header();
1453
+ init_horizontal_layout_header();
1454
+ init_vertical_layout();
1455
+ init_horizontal_layout();
1456
+ init_main_layout();
1457
+ init_tab_content_cache();
1458
+ }
1459
+ });
1460
+
1461
+ // src/hooks/use-tenant.ts
1462
+ var init_use_tenant = __esm({
1463
+ "src/hooks/use-tenant.ts"() {
1464
+ }
1465
+ });
1466
+ function useMediaQuery(query) {
1467
+ const [matches, setMatches] = useState(false);
1468
+ useEffect(() => {
1469
+ if (typeof window !== "undefined") {
1470
+ const media = window.matchMedia(query);
1471
+ setMatches(media.matches);
1472
+ const listener = (event) => setMatches(event.matches);
1473
+ media.addEventListener("change", listener);
1474
+ return () => media.removeEventListener("change", listener);
1475
+ }
1476
+ }, [query]);
1477
+ return matches;
1478
+ }
1479
+ function useMobile() {
1480
+ return useMediaQuery("(max-width: 768px)");
1481
+ }
1482
+ var init_hooks = __esm({
1483
+ "src/hooks/index.tsx"() {
1484
+ "use client";
1485
+ init_use_tenant();
1486
+ createContext(null);
1487
+ }
1488
+ });
1489
+ var init_alert = __esm({
1490
+ "src/ui/feedback/alert.tsx"() {
1491
+ cva(
1492
+ "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
1493
+ {
1494
+ variants: {
1495
+ variant: {
1496
+ default: "bg-background text-foreground",
1497
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
1498
+ }
1499
+ },
1500
+ defaultVariants: {
1501
+ variant: "default"
1502
+ }
1503
+ }
1504
+ );
1505
+ }
1506
+ });
1507
+ var GlobalErrorEmitter;
1508
+ var init_error_dialog = __esm({
1509
+ "src/ui/feedback/error-dialog.tsx"() {
1510
+ "use client";
1511
+ GlobalErrorEmitter = class {
1512
+ constructor() {
1513
+ this.listeners = [];
1514
+ }
1515
+ subscribe(listener) {
1516
+ this.listeners.push(listener);
1517
+ return () => {
1518
+ this.listeners = this.listeners.filter((l) => l !== listener);
1519
+ };
1520
+ }
1521
+ emit(data) {
1522
+ this.listeners.forEach((listener) => listener(data));
1523
+ }
1524
+ };
1525
+ new GlobalErrorEmitter();
1526
+ createContext(null);
1527
+ }
1528
+ });
1529
+ function AlertDialog({
1530
+ ...props
1531
+ }) {
1532
+ return /* @__PURE__ */ jsx(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
1533
+ }
1534
+ function AlertDialogPortal({
1535
+ ...props
1536
+ }) {
1537
+ return /* @__PURE__ */ jsx(AlertDialogPrimitive.Portal, { "data-slot": "alert-dialog-portal", ...props });
1538
+ }
1539
+ function AlertDialogOverlay({
1540
+ className,
1541
+ ...props
1542
+ }) {
1543
+ return /* @__PURE__ */ jsx(
1544
+ AlertDialogPrimitive.Overlay,
1545
+ {
1546
+ "data-slot": "alert-dialog-overlay",
1547
+ className: cn(
1548
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1549
+ className
1550
+ ),
1551
+ ...props
1552
+ }
1553
+ );
1554
+ }
1555
+ function AlertDialogContent({
1556
+ className,
1557
+ ...props
1558
+ }) {
1559
+ return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
1560
+ /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
1561
+ /* @__PURE__ */ jsx(
1562
+ AlertDialogPrimitive.Content,
1563
+ {
1564
+ "data-slot": "alert-dialog-content",
1565
+ className: cn(
1566
+ "fixed top-[50%] left-[50%] z-50 w-full max-w-[calc(100%-2rem)] grid bg-background translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:max-w-lg",
1567
+ className
1568
+ ),
1569
+ ...props
1570
+ }
1571
+ )
1572
+ ] });
1573
+ }
1574
+ function AlertDialogHeader({
1575
+ className,
1576
+ ...props
1577
+ }) {
1578
+ return /* @__PURE__ */ jsx(
1579
+ "div",
1580
+ {
1581
+ "data-slot": "alert-dialog-header",
1582
+ className: cn(
1583
+ "flex flex-col space-y-2 text-center sm:text-left",
1584
+ className
1585
+ ),
1586
+ ...props
1587
+ }
1588
+ );
1589
+ }
1590
+ function AlertDialogFooter({
1591
+ className,
1592
+ ...props
1593
+ }) {
1594
+ return /* @__PURE__ */ jsx(
1595
+ "div",
1596
+ {
1597
+ "data-slot": "alert-dialog-footer",
1598
+ className: cn(
1599
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2",
1600
+ className
1601
+ ),
1602
+ ...props
1603
+ }
1604
+ );
1605
+ }
1606
+ function AlertDialogTitle({
1607
+ className,
1608
+ ...props
1609
+ }) {
1610
+ return /* @__PURE__ */ jsx(
1611
+ AlertDialogPrimitive.Title,
1612
+ {
1613
+ "data-slot": "alert-dialog-title",
1614
+ className: cn("text-lg font-semibold", className),
1615
+ ...props
1616
+ }
1617
+ );
1618
+ }
1619
+ function AlertDialogDescription({
1620
+ className,
1621
+ ...props
1622
+ }) {
1623
+ return /* @__PURE__ */ jsx(
1624
+ AlertDialogPrimitive.Description,
1625
+ {
1626
+ "data-slot": "alert-dialog-description",
1627
+ className: cn("text-sm text-muted-foreground", className),
1628
+ ...props
1629
+ }
1630
+ );
1631
+ }
1632
+ function AlertDialogAction({
1633
+ className,
1634
+ ...props
1635
+ }) {
1636
+ return /* @__PURE__ */ jsx(
1637
+ AlertDialogPrimitive.Action,
1638
+ {
1639
+ className: cn(buttonVariants(), className),
1640
+ ...props
1641
+ }
1642
+ );
1643
+ }
1644
+ function AlertDialogCancel({
1645
+ className,
1646
+ ...props
1647
+ }) {
1648
+ return /* @__PURE__ */ jsx(
1649
+ AlertDialogPrimitive.Cancel,
1650
+ {
1651
+ className: cn(
1652
+ buttonVariants({ variant: "outline" }),
1653
+ "mt-2 sm:mt-0",
1654
+ className
1655
+ ),
1656
+ ...props
1657
+ }
1658
+ );
1659
+ }
1660
+ var init_feedback = __esm({
1661
+ "src/ui/feedback/index.tsx"() {
1662
+ init_primitives();
1663
+ init_utils();
1664
+ init_primitives();
1665
+ init_progress();
1666
+ init_sheet();
1667
+ init_alert();
1668
+ init_context_menu();
1669
+ init_drawer();
1670
+ init_sonner();
1671
+ init_error_dialog();
1672
+ }
1673
+ });
1674
+ function useSidebar() {
1675
+ const context = React12.useContext(SidebarContext);
1676
+ if (!context) {
1677
+ throw new Error("useSidebar must be used within a SidebarProvider.");
1678
+ }
1679
+ return context;
1680
+ }
1681
+ var SIDEBAR_WIDTH, SIDEBAR_WIDTH_MOBILE, SIDEBAR_WIDTH_ICON, SIDEBAR_KEYBOARD_SHORTCUT, SidebarContext, SidebarProvider, Sidebar, SidebarTrigger, SidebarRail, SidebarInset, SidebarInput, SidebarHeader, SidebarFooter, SidebarSeparator, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarGroupAction, SidebarGroupContent, SidebarMenu, SidebarMenuItem, sidebarMenuButtonVariants, SidebarMenuButton, SidebarMenuAction, SidebarMenuBadge, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton;
1682
+ var init_sidebar2 = __esm({
1683
+ "src/ui/primitives/sidebar.tsx"() {
1684
+ "use client";
1685
+ init_hooks();
1686
+ init_utils();
1687
+ init_button();
1688
+ init_feedback();
1689
+ init_tooltip();
1690
+ SIDEBAR_WIDTH = "16rem";
1691
+ SIDEBAR_WIDTH_MOBILE = "18rem";
1692
+ SIDEBAR_WIDTH_ICON = "3rem";
1693
+ SIDEBAR_KEYBOARD_SHORTCUT = "b";
1694
+ SidebarContext = React12.createContext(null);
1695
+ SidebarProvider = React12.forwardRef(
1696
+ ({
1697
+ defaultOpen = false,
1698
+ open: openProp,
1699
+ onOpenChange: setOpenProp,
1700
+ className,
1701
+ style,
1702
+ children,
1703
+ ...props
1704
+ }, ref) => {
1705
+ const isMobile = useMobile();
1706
+ const [openMobile, setOpenMobile] = React12.useState(false);
1707
+ const [hoverOpen, setHoverOpen] = React12.useState(false);
1708
+ const [_open, _setOpen] = React12.useState(defaultOpen);
1709
+ const open = openProp ?? _open;
1710
+ const setOpen = React12.useCallback(
1711
+ (value) => {
1712
+ if (setOpenProp) {
1713
+ return setOpenProp(typeof value === "function" ? value(open) : value);
1714
+ }
1715
+ _setOpen(value);
1716
+ },
1717
+ [setOpenProp, open]
1718
+ );
1719
+ const toggleSidebar = React12.useCallback(() => {
1720
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
1721
+ }, [isMobile, setOpen, setOpenMobile]);
1722
+ React12.useEffect(() => {
1723
+ const handleKeyDown = (event) => {
1724
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
1725
+ event.preventDefault();
1726
+ toggleSidebar();
1727
+ }
1728
+ };
1729
+ window.addEventListener("keydown", handleKeyDown);
1730
+ return () => window.removeEventListener("keydown", handleKeyDown);
1731
+ }, [toggleSidebar]);
1732
+ const state = open ? "expanded" : "collapsed";
1733
+ const isHoverExpanded = !open && hoverOpen;
1734
+ const contextValue = React12.useMemo(
1735
+ () => ({
1736
+ state,
1737
+ open,
1738
+ setOpen,
1739
+ isMobile,
1740
+ openMobile,
1741
+ setOpenMobile,
1742
+ toggleSidebar,
1743
+ hoverOpen,
1744
+ setHoverOpen,
1745
+ isHoverExpanded
1746
+ }),
1747
+ [
1748
+ state,
1749
+ open,
1750
+ setOpen,
1751
+ isMobile,
1752
+ openMobile,
1753
+ setOpenMobile,
1754
+ toggleSidebar,
1755
+ hoverOpen,
1756
+ setHoverOpen,
1757
+ isHoverExpanded
1758
+ ]
1759
+ );
1760
+ return /* @__PURE__ */ jsx(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx(
1761
+ "div",
1762
+ {
1763
+ style: {
1764
+ "--sidebar-width": SIDEBAR_WIDTH,
1765
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
1766
+ ...style
1767
+ },
1768
+ className: cn(
1769
+ "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
1770
+ className
1771
+ ),
1772
+ ref,
1773
+ ...props,
1774
+ children
1775
+ }
1776
+ ) }) });
1777
+ }
1778
+ );
1779
+ SidebarProvider.displayName = "SidebarProvider";
1780
+ Sidebar = React12.forwardRef(
1781
+ ({
1782
+ side = "left",
1783
+ variant = "sidebar",
1784
+ collapsible = "offcanvas",
1785
+ hoverExpandEnabled = true,
1786
+ className,
1787
+ children,
1788
+ ...props
1789
+ }, ref) => {
1790
+ const {
1791
+ isMobile,
1792
+ state,
1793
+ openMobile,
1794
+ setOpenMobile,
1795
+ setHoverOpen,
1796
+ isHoverExpanded
1797
+ } = useSidebar();
1798
+ const handleMouseEnter = React12.useCallback(() => {
1799
+ if (hoverExpandEnabled && state === "collapsed" && collapsible === "icon") {
1800
+ setHoverOpen(true);
1801
+ }
1802
+ }, [hoverExpandEnabled, state, collapsible, setHoverOpen]);
1803
+ const handleMouseLeave = React12.useCallback(() => {
1804
+ if (hoverExpandEnabled) {
1805
+ setHoverOpen(false);
1806
+ }
1807
+ }, [hoverExpandEnabled, setHoverOpen]);
1808
+ if (collapsible === "none") {
1809
+ return /* @__PURE__ */ jsx(
1810
+ "div",
1811
+ {
1812
+ className: cn(
1813
+ "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
1814
+ className
1815
+ ),
1816
+ ref,
1817
+ ...props,
1818
+ children
1819
+ }
1820
+ );
1821
+ }
1822
+ if (isMobile) {
1823
+ return /* @__PURE__ */ jsx(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ jsxs(
1824
+ SheetContent,
1825
+ {
1826
+ "data-sidebar": "sidebar",
1827
+ "data-mobile": "true",
1828
+ className: "w-(--sidebar-width) bg-background p-0 text-foreground [&>button]:hidden",
1829
+ style: {
1830
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE
1831
+ },
1832
+ side,
1833
+ children: [
1834
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Mobile Menu" }),
1835
+ /* @__PURE__ */ jsx("div", { className: "flex h-full w-full flex-col", children })
1836
+ ]
1837
+ }
1838
+ ) });
1839
+ }
1840
+ return /* @__PURE__ */ jsxs(
1841
+ "div",
1842
+ {
1843
+ ref,
1844
+ className: cn(
1845
+ "group peer hidden md:block transition-colors duration-200",
1846
+ // Blue bg + white text when collapsed, white bg + dark text when expanded/hover
1847
+ state === "collapsed" && !isHoverExpanded ? "text-sidebar-foreground" : "text-foreground"
1848
+ ),
1849
+ "data-state": state,
1850
+ "data-hover-expanded": isHoverExpanded,
1851
+ "data-collapsible": state === "collapsed" ? collapsible : "",
1852
+ "data-variant": variant,
1853
+ "data-side": side,
1854
+ onMouseEnter: handleMouseEnter,
1855
+ onMouseLeave: handleMouseLeave,
1856
+ children: [
1857
+ /* @__PURE__ */ jsx(
1858
+ "div",
1859
+ {
1860
+ className: cn(
1861
+ "duration-200 relative h-svh w-(--sidebar-width) bg-transparent transition-[width] ease-linear",
1862
+ "group-data-[collapsible=offcanvas]:w-0",
1863
+ "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
1864
+ variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
1865
+ )
1866
+ }
1867
+ ),
1868
+ /* @__PURE__ */ jsx(
1869
+ "div",
1870
+ {
1871
+ className: cn(
1872
+ "duration-200 fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] ease-linear md:flex",
1873
+ side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
1874
+ // Adjustments for collapsible=icon
1875
+ variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_8px)] group-data-[collapsible=icon]:px-2.5" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[collapsible=icon]:border-r group-data-[collapsible=icon]:px-0",
1876
+ // Hover expand - override icon width to full width on hover
1877
+ "group-data-[hover-expanded=true]:!w-(--sidebar-width) group-data-[hover-expanded=true]:shadow-xl group-data-[hover-expanded=true]:z-[100]",
1878
+ className
1879
+ ),
1880
+ ...props,
1881
+ children: /* @__PURE__ */ jsx(
1882
+ "div",
1883
+ {
1884
+ "data-sidebar": "sidebar",
1885
+ className: cn(
1886
+ "flex h-full w-full flex-col border-r transition-colors duration-200",
1887
+ // Blue background when collapsed, white when expanded/hover
1888
+ "group-data-[state=collapsed]:bg-sidebar group-data-[state=collapsed]:border-sidebar-border",
1889
+ "group-data-[state=expanded]:bg-background group-data-[state=expanded]:border-border",
1890
+ "group-data-[hover-expanded=true]:!bg-background group-data-[hover-expanded=true]:!border-border",
1891
+ "group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
1892
+ ),
1893
+ children
1894
+ }
1895
+ )
1896
+ }
1897
+ )
1898
+ ]
1899
+ }
1900
+ );
1901
+ }
1902
+ );
1903
+ Sidebar.displayName = "Sidebar";
1904
+ SidebarTrigger = React12.forwardRef(({ className, onClick, ...props }, ref) => {
1905
+ const { toggleSidebar } = useSidebar();
1906
+ return /* @__PURE__ */ jsxs(
1907
+ Button,
1908
+ {
1909
+ ref,
1910
+ "data-sidebar": "trigger",
1911
+ variant: "ghost",
1912
+ size: "icon",
1913
+ className: cn("h-7 w-7", className),
1914
+ onClick: (event) => {
1915
+ onClick?.(event);
1916
+ toggleSidebar();
1917
+ },
1918
+ ...props,
1919
+ children: [
1920
+ /* @__PURE__ */ jsx(PanelLeft, {}),
1921
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Toggle Sidebar" })
1922
+ ]
1923
+ }
1924
+ );
1925
+ });
1926
+ SidebarTrigger.displayName = "SidebarTrigger";
1927
+ SidebarRail = React12.forwardRef(({ className, ...props }, ref) => {
1928
+ const { toggleSidebar } = useSidebar();
1929
+ return /* @__PURE__ */ jsx(
1930
+ "button",
1931
+ {
1932
+ ref,
1933
+ "data-sidebar": "rail",
1934
+ "aria-label": "Toggle Sidebar",
1935
+ tabIndex: -1,
1936
+ onClick: toggleSidebar,
1937
+ title: "Toggle Sidebar",
1938
+ className: cn(
1939
+ "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex",
1940
+ "[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
1941
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
1942
+ "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar",
1943
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
1944
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
1945
+ className
1946
+ ),
1947
+ ...props
1948
+ }
1949
+ );
1950
+ });
1951
+ SidebarRail.displayName = "SidebarRail";
1952
+ SidebarInset = React12.forwardRef(({ className, ...props }, ref) => {
1953
+ return /* @__PURE__ */ jsx(
1954
+ "main",
1955
+ {
1956
+ ref,
1957
+ className: cn(
1958
+ "relative flex min-h-svh flex-1 flex-col bg-muted/40 transition-[margin] duration-200 ease-linear",
1959
+ "peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] 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",
1960
+ className
1961
+ ),
1962
+ ...props
1963
+ }
1964
+ );
1965
+ });
1966
+ SidebarInset.displayName = "SidebarInset";
1967
+ SidebarInput = React12.forwardRef(({ className, ...props }, ref) => {
1968
+ return /* @__PURE__ */ jsx(
1969
+ "input",
1970
+ {
1971
+ ref,
1972
+ "data-sidebar": "input",
1973
+ className: cn(
1974
+ "flex h-8 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1975
+ className
1976
+ ),
1977
+ ...props
1978
+ }
1979
+ );
1980
+ });
1981
+ SidebarInput.displayName = "SidebarInput";
1982
+ SidebarHeader = React12.forwardRef(({ className, ...props }, ref) => {
1983
+ return /* @__PURE__ */ jsx(
1984
+ "div",
1985
+ {
1986
+ ref,
1987
+ "data-sidebar": "header",
1988
+ className: cn("flex flex-col gap-2 p-2", className),
1989
+ ...props
1990
+ }
1991
+ );
1992
+ });
1993
+ SidebarHeader.displayName = "SidebarHeader";
1994
+ SidebarFooter = React12.forwardRef(({ className, ...props }, ref) => {
1995
+ return /* @__PURE__ */ jsx(
1996
+ "div",
1997
+ {
1998
+ ref,
1999
+ "data-sidebar": "footer",
2000
+ className: cn("flex flex-col gap-2 p-2", className),
2001
+ ...props
2002
+ }
2003
+ );
2004
+ });
2005
+ SidebarFooter.displayName = "SidebarFooter";
2006
+ SidebarSeparator = React12.forwardRef(({ className, ...props }, ref) => {
2007
+ return /* @__PURE__ */ jsx(
2008
+ "div",
2009
+ {
2010
+ ref,
2011
+ "data-sidebar": "separator",
2012
+ className: cn("mx-2 h-[1px] w-auto bg-sidebar-border", className),
2013
+ ...props
2014
+ }
2015
+ );
2016
+ });
2017
+ SidebarSeparator.displayName = "SidebarSeparator";
2018
+ SidebarContent = React12.forwardRef(({ className, ...props }, ref) => {
2019
+ return /* @__PURE__ */ jsx(
2020
+ "div",
2021
+ {
2022
+ ref,
2023
+ "data-sidebar": "content",
2024
+ className: cn(
2025
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto",
2026
+ // Hide overflow when collapsed, but show when hover-expanded
2027
+ "group-data-[collapsible=icon]:overflow-hidden group-data-[hover-expanded=true]:!overflow-auto",
2028
+ className
2029
+ ),
2030
+ ...props
2031
+ }
2032
+ );
2033
+ });
2034
+ SidebarContent.displayName = "SidebarContent";
2035
+ SidebarGroup = React12.forwardRef(({ className, ...props }, ref) => {
2036
+ return /* @__PURE__ */ jsx(
2037
+ "div",
2038
+ {
2039
+ ref,
2040
+ "data-sidebar": "group",
2041
+ className: cn("relative flex w-full min-w-0 flex-col p-2", className),
2042
+ ...props
2043
+ }
2044
+ );
2045
+ });
2046
+ SidebarGroup.displayName = "SidebarGroup";
2047
+ SidebarGroupLabel = React12.forwardRef(({ className, asChild = false, ...props }, ref) => {
2048
+ const Comp = asChild ? Slot : "div";
2049
+ return /* @__PURE__ */ jsx(
2050
+ Comp,
2051
+ {
2052
+ ref,
2053
+ "data-sidebar": "group-label",
2054
+ className: cn(
2055
+ "duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-bold text-primary uppercase tracking-wider outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
2056
+ // Hide when collapsed, show when hover-expanded
2057
+ "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
2058
+ "group-data-[hover-expanded=true]:!mt-0 group-data-[hover-expanded=true]:!opacity-100",
2059
+ className
2060
+ ),
2061
+ ...props
2062
+ }
2063
+ );
2064
+ });
2065
+ SidebarGroupLabel.displayName = "SidebarGroupLabel";
2066
+ SidebarGroupAction = React12.forwardRef(({ className, asChild = false, ...props }, ref) => {
2067
+ const Comp = asChild ? Slot : "button";
2068
+ return /* @__PURE__ */ jsx(
2069
+ Comp,
2070
+ {
2071
+ ref,
2072
+ "data-sidebar": "group-action",
2073
+ className: cn(
2074
+ "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
2075
+ // Increases the hit area of the button on mobile.
2076
+ "after:absolute after:-inset-2 after:md:hidden",
2077
+ "group-data-[collapsible=icon]:hidden",
2078
+ className
2079
+ ),
2080
+ ...props
2081
+ }
2082
+ );
2083
+ });
2084
+ SidebarGroupAction.displayName = "SidebarGroupAction";
2085
+ SidebarGroupContent = React12.forwardRef(({ className, ...props }, ref) => {
2086
+ return /* @__PURE__ */ jsx(
2087
+ "div",
2088
+ {
2089
+ ref,
2090
+ "data-sidebar": "group-content",
2091
+ className: cn("w-full text-sm", className),
2092
+ ...props
2093
+ }
2094
+ );
2095
+ });
2096
+ SidebarGroupContent.displayName = "SidebarGroupContent";
2097
+ SidebarMenu = React12.forwardRef(({ className, ...props }, ref) => {
2098
+ return /* @__PURE__ */ jsx(
2099
+ "ul",
2100
+ {
2101
+ ref,
2102
+ "data-sidebar": "menu",
2103
+ className: cn("flex w-full min-w-0 flex-col gap-1", className),
2104
+ ...props
2105
+ }
2106
+ );
2107
+ });
2108
+ SidebarMenu.displayName = "SidebarMenu";
2109
+ SidebarMenuItem = React12.forwardRef(({ className, ...props }, ref) => {
2110
+ return /* @__PURE__ */ jsx(
2111
+ "li",
2112
+ {
2113
+ ref,
2114
+ "data-sidebar": "menu-item",
2115
+ className: cn("group/menu-item relative", className),
2116
+ ...props
2117
+ }
2118
+ );
2119
+ });
2120
+ SidebarMenuItem.displayName = "SidebarMenuItem";
2121
+ sidebarMenuButtonVariants = cva(
2122
+ // Base styles + hover-expand overrides
2123
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none 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-[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 group-data-[hover-expanded=true]:!size-auto group-data-[hover-expanded=true]:!w-full group-data-[hover-expanded=true]:!p-2",
2124
+ {
2125
+ variants: {
2126
+ variant: {
2127
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
2128
+ outline: "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))]"
2129
+ },
2130
+ size: {
2131
+ default: "h-8 text-sm",
2132
+ sm: "h-7 text-xs",
2133
+ lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0"
2134
+ },
2135
+ isActive: {
2136
+ true: "bg-primary/10 text-primary font-bold"
2137
+ }
2138
+ },
2139
+ defaultVariants: {
2140
+ variant: "default",
2141
+ size: "default"
2142
+ }
2143
+ }
2144
+ );
2145
+ SidebarMenuButton = React12.forwardRef(
2146
+ ({
2147
+ asChild = false,
2148
+ isActive = false,
2149
+ variant = "default",
2150
+ size = "default",
2151
+ tooltip,
2152
+ className,
2153
+ ...props
2154
+ }, ref) => {
2155
+ const Comp = asChild ? Slot : "button";
2156
+ const { isMobile, state } = useSidebar();
2157
+ const button = /* @__PURE__ */ jsx(
2158
+ Comp,
2159
+ {
2160
+ ref,
2161
+ "data-sidebar": "menu-button",
2162
+ "data-size": size,
2163
+ "data-active": isActive,
2164
+ className: cn(
2165
+ sidebarMenuButtonVariants({ variant, size, isActive }),
2166
+ className
2167
+ ),
2168
+ ...props
2169
+ }
2170
+ );
2171
+ if (!tooltip) {
2172
+ return button;
2173
+ }
2174
+ if (typeof tooltip === "string") {
2175
+ tooltip = {
2176
+ children: tooltip
2177
+ };
2178
+ }
2179
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
2180
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: button }),
2181
+ /* @__PURE__ */ jsx(
2182
+ TooltipContent,
2183
+ {
2184
+ side: "right",
2185
+ align: "center",
2186
+ hidden: state !== "collapsed" || isMobile,
2187
+ ...tooltip
2188
+ }
2189
+ )
2190
+ ] });
2191
+ }
2192
+ );
2193
+ SidebarMenuButton.displayName = "SidebarMenuButton";
2194
+ SidebarMenuAction = React12.forwardRef(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
2195
+ const Comp = asChild ? Slot : "button";
2196
+ return /* @__PURE__ */ jsx(
2197
+ Comp,
2198
+ {
2199
+ ref,
2200
+ "data-sidebar": "menu-action",
2201
+ className: cn(
2202
+ "absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
2203
+ // Increases the hit area of the button on mobile.
2204
+ "after:absolute after:-inset-2 after:md:hidden",
2205
+ "peer-data-[size=sm]/menu-button:top-1",
2206
+ "peer-data-[size=default]/menu-button:top-1.5",
2207
+ "peer-data-[size=lg]/menu-button:top-2.5",
2208
+ "group-data-[collapsible=icon]:hidden",
2209
+ showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
2210
+ className
2211
+ ),
2212
+ ...props
2213
+ }
2214
+ );
2215
+ });
2216
+ SidebarMenuAction.displayName = "SidebarMenuAction";
2217
+ SidebarMenuBadge = React12.forwardRef(({ className, ...props }, ref) => {
2218
+ return /* @__PURE__ */ jsx(
2219
+ "div",
2220
+ {
2221
+ ref,
2222
+ "data-sidebar": "menu-badge",
2223
+ className: cn(
2224
+ "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 text-sidebar-foreground select-none",
2225
+ "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
2226
+ "peer-data-[size=sm]/menu-button:top-1",
2227
+ "peer-data-[size=default]/menu-button:top-1.5",
2228
+ "peer-data-[size=lg]/menu-button:top-2.5",
2229
+ "group-data-[collapsible=icon]:hidden",
2230
+ className
2231
+ ),
2232
+ ...props
2233
+ }
2234
+ );
2235
+ });
2236
+ SidebarMenuBadge.displayName = "SidebarMenuBadge";
2237
+ SidebarMenuSkeleton = React12.forwardRef(({ className, showIcon = false, ...props }, ref) => {
2238
+ const width = React12.useMemo(() => {
2239
+ return `${Math.floor(Math.random() * 40) + 50}%`;
2240
+ }, []);
2241
+ return /* @__PURE__ */ jsxs(
2242
+ "div",
2243
+ {
2244
+ ref,
2245
+ "data-sidebar": "menu-skeleton",
2246
+ className: cn("flex h-8 items-center gap-2 rounded-md px-2", className),
2247
+ ...props,
2248
+ children: [
2249
+ showIcon && /* @__PURE__ */ jsx(
2250
+ "div",
2251
+ {
2252
+ className: "size-4 rounded-md animate-pulse bg-muted",
2253
+ "data-sidebar": "menu-skeleton-icon"
2254
+ }
2255
+ ),
2256
+ /* @__PURE__ */ jsx(
2257
+ "div",
2258
+ {
2259
+ className: "h-4 flex-1 max-w-[--skeleton-width] animate-pulse bg-muted rounded-full",
2260
+ "data-sidebar": "menu-skeleton-text",
2261
+ style: {
2262
+ "--skeleton-width": width
2263
+ }
2264
+ }
2265
+ )
2266
+ ]
2267
+ }
2268
+ );
2269
+ });
2270
+ SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
2271
+ SidebarMenuSub = React12.forwardRef(({ className, ...props }, ref) => {
2272
+ return /* @__PURE__ */ jsx(
2273
+ "ul",
2274
+ {
2275
+ ref,
2276
+ "data-sidebar": "menu-sub",
2277
+ className: cn(
2278
+ "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
2279
+ // Hide when collapsed, show when hover-expanded
2280
+ "group-data-[collapsible=icon]:hidden group-data-[hover-expanded=true]:!flex",
2281
+ className
2282
+ ),
2283
+ ...props
2284
+ }
2285
+ );
2286
+ });
2287
+ SidebarMenuSub.displayName = "SidebarMenuSub";
2288
+ SidebarMenuSubItem = React12.forwardRef(({ ...props }, ref) => /* @__PURE__ */ jsx("li", { ref, ...props }));
2289
+ SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
2290
+ SidebarMenuSubButton = React12.forwardRef(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
2291
+ const Comp = asChild ? Slot : "a";
2292
+ return /* @__PURE__ */ jsx(
2293
+ Comp,
2294
+ {
2295
+ ref,
2296
+ "data-sidebar": "menu-sub-button",
2297
+ "data-size": size,
2298
+ "data-active": isActive,
2299
+ className: cn(
2300
+ "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring 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 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 text-xs",
2301
+ "data-[active=true]:bg-primary/15 data-[active=true]:!text-primary data-[active=true]:font-bold",
2302
+ size === "sm" && "text-xs",
2303
+ size === "md" && "text-sm",
2304
+ className
2305
+ ),
2306
+ ...props
2307
+ }
2308
+ );
2309
+ });
2310
+ SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
2311
+ }
2312
+ });
2313
+ function Spinner({ size = "md", className }) {
2314
+ const sizeClasses = {
2315
+ sm: "h-4 w-4",
2316
+ md: "h-6 w-6",
2317
+ lg: "h-8 w-8"
2318
+ };
2319
+ return /* @__PURE__ */ jsx(
2320
+ "div",
2321
+ {
2322
+ className: cn(
2323
+ "animate-spin rounded-full border-2 border-current border-t-transparent",
2324
+ sizeClasses[size],
2325
+ className
2326
+ )
2327
+ }
2328
+ );
2329
+ }
2330
+ var Textarea, ButtonLoading;
2331
+ var init_primitives = __esm({
2332
+ "src/ui/primitives/index.tsx"() {
2333
+ init_utils();
2334
+ init_button();
2335
+ init_badge();
2336
+ init_button();
2337
+ init_input();
2338
+ init_checkbox();
2339
+ init_card();
2340
+ init_separator();
2341
+ init_card();
2342
+ init_table();
2343
+ init_dropdown_menu();
2344
+ init_dialog();
2345
+ init_tabs();
2346
+ init_breadcrumb();
2347
+ init_keyboard();
2348
+ init_pagination();
2349
+ init_status_badge();
2350
+ init_sidebar2();
2351
+ init_popover();
2352
+ init_scroll_area();
2353
+ init_calendar();
2354
+ init_resizable();
2355
+ init_slider();
2356
+ init_switch();
2357
+ init_tooltip();
2358
+ init_select();
2359
+ init_menubar();
2360
+ init_navigation_menu();
2361
+ init_toggle();
2362
+ init_toggle_group();
2363
+ init_combobox();
2364
+ init_label();
2365
+ Textarea = React12.forwardRef(
2366
+ ({ className, ...props }, ref) => {
2367
+ return /* @__PURE__ */ jsx(
2368
+ "textarea",
2369
+ {
2370
+ className: cn(
2371
+ "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
2372
+ className
2373
+ ),
2374
+ ref,
2375
+ ...props
2376
+ }
2377
+ );
2378
+ }
2379
+ );
2380
+ Textarea.displayName = "Textarea";
2381
+ ButtonLoading = React12.forwardRef(({ className, isLoading, children, disabled, ...props }, ref) => {
2382
+ return /* @__PURE__ */ jsxs(
2383
+ Button,
2384
+ {
2385
+ className: cn("gap-2", className),
2386
+ disabled: isLoading || disabled,
2387
+ ref,
2388
+ ...props,
2389
+ children: [
2390
+ isLoading && /* @__PURE__ */ jsx(Spinner, { size: "sm" }),
2391
+ children
2392
+ ]
2393
+ }
2394
+ );
2395
+ });
2396
+ ButtonLoading.displayName = "ButtonLoading";
2397
+ }
2398
+ });
2399
+ var init_radio_group = __esm({
2400
+ "src/ui/forms/radio-group.tsx"() {
2401
+ "use client";
2402
+ }
2403
+ });
2404
+ var init_rating = __esm({
2405
+ "src/ui/forms/rating.tsx"() {
2406
+ "use client";
2407
+ cva(
2408
+ "transition-all duration-100 ease-in-out hover:scale-110",
2409
+ {
2410
+ variants: {
2411
+ size: {
2412
+ sm: "w-4 h-4",
2413
+ default: "w-6 h-6",
2414
+ lg: "w-8 h-8"
2415
+ },
2416
+ variant: {
2417
+ default: "text-yellow-400",
2418
+ primary: "text-primary",
2419
+ muted: "text-muted-foreground"
2420
+ },
2421
+ filled: {
2422
+ true: "",
2423
+ false: "text-gray-200"
2424
+ }
2425
+ },
2426
+ defaultVariants: {
2427
+ size: "default",
2428
+ variant: "default",
2429
+ filled: false
2430
+ }
2431
+ }
2432
+ );
2433
+ }
2434
+ });
2435
+ var init_command = __esm({
2436
+ "src/ui/forms/command.tsx"() {
2437
+ "use client";
2438
+ }
2439
+ });
2440
+ var MultiSelect;
2441
+ var init_multi_select = __esm({
2442
+ "src/ui/forms/multi-select.tsx"() {
2443
+ "use client";
2444
+ init_utils();
2445
+ init_primitives();
2446
+ init_client();
2447
+ MultiSelect = React12.forwardRef(
2448
+ ({
2449
+ options,
2450
+ value: controlledValue,
2451
+ onValueChange,
2452
+ defaultValue = [],
2453
+ placeholder = "Select options...",
2454
+ searchPlaceholder = "Search...",
2455
+ emptyText = "No option found.",
2456
+ maxCount = 3,
2457
+ disabled = false,
2458
+ responsive = false,
2459
+ className,
2460
+ id
2461
+ }, ref) => {
2462
+ const [internalValue, setInternalValue] = useState(defaultValue);
2463
+ const [open, setOpen] = useState(false);
2464
+ const [searchValue, setSearchValue] = useState("");
2465
+ const isControlled = controlledValue !== void 0;
2466
+ const value = isControlled ? controlledValue : internalValue;
2467
+ const containerRef = useRef(null);
2468
+ const searchInputRef = useRef(null);
2469
+ const dropdownRef = useRef(null);
2470
+ const buttonRef = useRef(null);
2471
+ const [politeMessage, setPoliteMessage] = useState("");
2472
+ const [assertiveMessage, setAssertiveMessage] = useState("");
2473
+ const prevSelectedCount = useRef(value.length);
2474
+ const announce = useCallback(
2475
+ (message, priority = "polite") => {
2476
+ if (priority === "assertive") {
2477
+ setAssertiveMessage(message);
2478
+ setTimeout(() => setAssertiveMessage(""), 100);
2479
+ } else {
2480
+ setPoliteMessage(message);
2481
+ setTimeout(() => setPoliteMessage(""), 100);
2482
+ }
2483
+ },
2484
+ []
2485
+ );
2486
+ const [screenSize, setScreenSize] = useState("desktop");
2487
+ useEffect(() => {
2488
+ if (typeof window === "undefined") return;
2489
+ const handleResize = () => {
2490
+ const width = window.innerWidth;
2491
+ if (width < 640) {
2492
+ setScreenSize("mobile");
2493
+ } else if (width < 1024) {
2494
+ setScreenSize("tablet");
2495
+ } else {
2496
+ setScreenSize("desktop");
2497
+ }
2498
+ };
2499
+ handleResize();
2500
+ window.addEventListener("resize", handleResize);
2501
+ return () => window.removeEventListener("resize", handleResize);
2502
+ }, []);
2503
+ const getResponsiveSettings = useCallback(() => {
2504
+ if (!responsive) {
2505
+ return {
2506
+ maxCount,
2507
+ compactMode: false
2508
+ };
2509
+ }
2510
+ if (responsive === true) {
2511
+ const defaultResponsive = {
2512
+ mobile: { maxCount: 2, compactMode: true },
2513
+ tablet: { maxCount: 4, compactMode: false },
2514
+ desktop: { maxCount: 6, compactMode: false }
2515
+ };
2516
+ const currentSettings2 = defaultResponsive[screenSize];
2517
+ return {
2518
+ maxCount: currentSettings2?.maxCount ?? maxCount,
2519
+ compactMode: currentSettings2?.compactMode ?? false
2520
+ };
2521
+ }
2522
+ const currentSettings = responsive[screenSize];
2523
+ return {
2524
+ maxCount: currentSettings?.maxCount ?? maxCount,
2525
+ compactMode: currentSettings?.compactMode ?? false
2526
+ };
2527
+ }, [responsive, screenSize, maxCount]);
2528
+ const responsiveSettings = getResponsiveSettings();
2529
+ const filteredOptions = useMemo(() => {
2530
+ if (!searchValue.trim()) {
2531
+ return options;
2532
+ }
2533
+ const searchLower = searchValue.toLowerCase();
2534
+ return options.filter(
2535
+ (option) => option.label.toLowerCase().includes(searchLower) || String(option.value).toLowerCase().includes(searchLower)
2536
+ );
2537
+ }, [options, searchValue]);
2538
+ useEffect(() => {
2539
+ if (!open) {
2540
+ setSearchValue("");
2541
+ }
2542
+ }, [open]);
2543
+ useEffect(() => {
2544
+ if (open && searchInputRef.current) {
2545
+ setTimeout(() => {
2546
+ searchInputRef.current?.focus();
2547
+ }, 50);
2548
+ }
2549
+ }, [open]);
2550
+ useEffect(() => {
2551
+ if (!open) return;
2552
+ const handleClickOutside = (event) => {
2553
+ const target = event.target;
2554
+ if (containerRef.current && !containerRef.current.contains(target) && dropdownRef.current && !dropdownRef.current.contains(target)) {
2555
+ if (target.closest('[data-slot="dialog-content"]')) {
2556
+ return;
2557
+ }
2558
+ setOpen(false);
2559
+ }
2560
+ };
2561
+ const handleEscape = (event) => {
2562
+ if (event.key === "Escape" && open) {
2563
+ event.stopPropagation();
2564
+ setOpen(false);
2565
+ }
2566
+ };
2567
+ document.addEventListener("mousedown", handleClickOutside, true);
2568
+ document.addEventListener("keydown", handleEscape, true);
2569
+ return () => {
2570
+ document.removeEventListener("mousedown", handleClickOutside, true);
2571
+ document.removeEventListener("keydown", handleEscape, true);
2572
+ };
2573
+ }, [open]);
2574
+ useEffect(() => {
2575
+ const selectedCount = value.length;
2576
+ const totalOptions = options.filter((opt) => !opt.disabled).length;
2577
+ if (selectedCount !== prevSelectedCount.current) {
2578
+ const diff = selectedCount - prevSelectedCount.current;
2579
+ if (diff > 0) {
2580
+ announce(`${selectedCount} of ${totalOptions} options selected.`);
2581
+ } else if (diff < 0) {
2582
+ announce(
2583
+ `Option removed. ${selectedCount} of ${totalOptions} options selected.`
2584
+ );
2585
+ }
2586
+ prevSelectedCount.current = selectedCount;
2587
+ }
2588
+ }, [value, announce, options]);
2589
+ const updateValue = useCallback(
2590
+ (newValue) => {
2591
+ if (!isControlled) {
2592
+ setInternalValue(newValue);
2593
+ }
2594
+ onValueChange?.(newValue);
2595
+ },
2596
+ [isControlled, onValueChange]
2597
+ );
2598
+ const handleSelect = useCallback(
2599
+ (optionValue) => {
2600
+ const option = options.find((opt) => opt.value === optionValue);
2601
+ if (option?.disabled) {
2602
+ return;
2603
+ }
2604
+ const newValue = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
2605
+ updateValue(newValue);
2606
+ },
2607
+ [value, options, updateValue]
2608
+ );
2609
+ const handleSelectAll = useCallback(() => {
2610
+ updateValue(
2611
+ filteredOptions.filter((opt) => !opt.disabled).map((opt) => opt.value)
2612
+ );
2613
+ }, [updateValue, filteredOptions]);
2614
+ const handleClearAll = useCallback(() => {
2615
+ updateValue([]);
2616
+ }, [updateValue]);
2617
+ const handleRemove = useCallback(
2618
+ (optionValue, e) => {
2619
+ e.stopPropagation();
2620
+ updateValue(value.filter((v) => v !== optionValue));
2621
+ },
2622
+ [updateValue, value]
2623
+ );
2624
+ const clearExtraOptions = useCallback(() => {
2625
+ const newSelectedValues = value.slice(0, responsiveSettings.maxCount);
2626
+ updateValue(newSelectedValues);
2627
+ }, [value, responsiveSettings.maxCount, updateValue]);
2628
+ React12.useImperativeHandle(
2629
+ ref,
2630
+ () => ({
2631
+ reset: () => {
2632
+ updateValue(defaultValue);
2633
+ setOpen(false);
2634
+ setSearchValue("");
2635
+ },
2636
+ getSelectedValues: () => value,
2637
+ setSelectedValues: (values) => {
2638
+ updateValue(values);
2639
+ },
2640
+ clear: () => {
2641
+ updateValue([]);
2642
+ },
2643
+ focus: () => {
2644
+ buttonRef.current?.focus();
2645
+ }
2646
+ }),
2647
+ [value, defaultValue, updateValue]
2648
+ );
2649
+ const selectedOptions = options.filter(
2650
+ (option) => value.includes(option.value)
2651
+ );
2652
+ const getBadgeColor = (index) => {
2653
+ const colors = [
2654
+ "bg-blue-100 text-blue-700 hover:bg-blue-200",
2655
+ "bg-green-100 text-green-700 hover:bg-green-200",
2656
+ "bg-purple-100 text-purple-700 hover:bg-purple-200",
2657
+ "bg-orange-100 text-orange-700 hover:bg-orange-200",
2658
+ "bg-pink-100 text-pink-700 hover:bg-pink-200",
2659
+ "bg-cyan-100 text-cyan-700 hover:bg-cyan-200"
2660
+ ];
2661
+ return colors[index % colors.length];
2662
+ };
2663
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative w-full", children: [
2664
+ /* @__PURE__ */ jsxs("div", { className: "sr-only", children: [
2665
+ /* @__PURE__ */ jsx("div", { "aria-live": "polite", "aria-atomic": "true", role: "status", children: politeMessage }),
2666
+ /* @__PURE__ */ jsx("div", { "aria-live": "assertive", "aria-atomic": "true", role: "alert", children: assertiveMessage })
2667
+ ] }),
2668
+ /* @__PURE__ */ jsxs(
2669
+ Button,
2670
+ {
2671
+ ref: buttonRef,
2672
+ type: "button",
2673
+ variant: "outline",
2674
+ role: "combobox",
2675
+ "aria-expanded": open,
2676
+ disabled,
2677
+ className: cn(
2678
+ "w-full justify-between h-auto min-h-10 px-3 py-2",
2679
+ responsiveSettings.compactMode && "min-h-8 text-sm",
2680
+ className
2681
+ ),
2682
+ id,
2683
+ onClick: (e) => {
2684
+ e.stopPropagation();
2685
+ setOpen(!open);
2686
+ },
2687
+ children: [
2688
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: selectedOptions.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2689
+ selectedOptions.slice(0, responsiveSettings.maxCount).map((option, index) => /* @__PURE__ */ jsxs(
2690
+ Badge,
2691
+ {
2692
+ className: cn(
2693
+ "mr-1 mb-1",
2694
+ getBadgeColor(index),
2695
+ responsiveSettings.compactMode && "text-xs px-1.5 py-0.5"
2696
+ ),
2697
+ onClick: (e) => handleRemove(option.value, e),
2698
+ children: [
2699
+ option.icon && !responsiveSettings.compactMode && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }),
2700
+ option.label,
2701
+ /* @__PURE__ */ jsx(
2702
+ "div",
2703
+ {
2704
+ role: "button",
2705
+ tabIndex: 0,
2706
+ className: "ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 cursor-pointer",
2707
+ onKeyDown: (e) => {
2708
+ if (e.key === "Enter") {
2709
+ handleRemove(option.value, e);
2710
+ }
2711
+ },
2712
+ onMouseDown: (e) => {
2713
+ e.preventDefault();
2714
+ e.stopPropagation();
2715
+ },
2716
+ onClick: (e) => handleRemove(option.value, e),
2717
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-muted-foreground hover:text-foreground" })
2718
+ }
2719
+ )
2720
+ ]
2721
+ },
2722
+ String(option.value)
2723
+ )),
2724
+ value.length > responsiveSettings.maxCount && /* @__PURE__ */ jsxs(
2725
+ Badge,
2726
+ {
2727
+ className: cn(
2728
+ "mr-1 mb-1 bg-muted text-muted-foreground hover:bg-muted",
2729
+ responsiveSettings.compactMode && "text-xs px-1.5 py-0.5"
2730
+ ),
2731
+ children: [
2732
+ "+",
2733
+ value.length - responsiveSettings.maxCount,
2734
+ " more",
2735
+ /* @__PURE__ */ jsx(
2736
+ "div",
2737
+ {
2738
+ role: "button",
2739
+ tabIndex: 0,
2740
+ className: "ml-1 ring-offset-background rounded-full outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 cursor-pointer",
2741
+ onClick: (e) => {
2742
+ e.stopPropagation();
2743
+ clearExtraOptions();
2744
+ },
2745
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
2746
+ }
2747
+ )
2748
+ ]
2749
+ }
2750
+ )
2751
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) }),
2752
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
2753
+ ]
2754
+ }
2755
+ ),
2756
+ open && /* @__PURE__ */ jsx(
2757
+ "div",
2758
+ {
2759
+ ref: dropdownRef,
2760
+ className: "absolute z-[100] mt-1 w-full rounded-md border bg-popover text-popover-foreground shadow-md",
2761
+ style: {
2762
+ top: "100%",
2763
+ left: 0
2764
+ },
2765
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
2766
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center border-b px-3 py-2", children: [
2767
+ /* @__PURE__ */ jsx(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
2768
+ /* @__PURE__ */ jsx(
2769
+ Input,
2770
+ {
2771
+ ref: searchInputRef,
2772
+ placeholder: searchPlaceholder,
2773
+ value: searchValue,
2774
+ onChange: (e) => {
2775
+ e.stopPropagation();
2776
+ setSearchValue(e.target.value);
2777
+ },
2778
+ onKeyDown: (e) => {
2779
+ e.stopPropagation();
2780
+ if (e.key === "Escape") {
2781
+ e.preventDefault();
2782
+ setOpen(false);
2783
+ }
2784
+ },
2785
+ onClick: (e) => {
2786
+ e.stopPropagation();
2787
+ },
2788
+ onFocus: (e) => {
2789
+ e.stopPropagation();
2790
+ },
2791
+ className: "border-0 focus-visible:ring-0 focus-visible:ring-offset-0 h-9 bg-transparent px-0"
2792
+ }
2793
+ ),
2794
+ searchValue && /* @__PURE__ */ jsx(
2795
+ Button,
2796
+ {
2797
+ type: "button",
2798
+ variant: "ghost",
2799
+ size: "sm",
2800
+ className: "h-6 w-6 p-0",
2801
+ onClick: (e) => {
2802
+ e.stopPropagation();
2803
+ setSearchValue("");
2804
+ searchInputRef.current?.focus();
2805
+ },
2806
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
2807
+ }
2808
+ )
2809
+ ] }),
2810
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b p-1", children: [
2811
+ /* @__PURE__ */ jsx(
2812
+ Button,
2813
+ {
2814
+ type: "button",
2815
+ variant: "ghost",
2816
+ size: "sm",
2817
+ className: "h-8 px-2 text-xs",
2818
+ onClick: (e) => {
2819
+ e.stopPropagation();
2820
+ handleSelectAll();
2821
+ },
2822
+ children: "Select All"
2823
+ }
2824
+ ),
2825
+ /* @__PURE__ */ jsx(
2826
+ Button,
2827
+ {
2828
+ type: "button",
2829
+ variant: "ghost",
2830
+ size: "sm",
2831
+ className: "h-8 px-2 text-xs",
2832
+ onClick: (e) => {
2833
+ e.stopPropagation();
2834
+ handleClearAll();
2835
+ },
2836
+ children: "Clear All"
2837
+ }
2838
+ )
2839
+ ] }),
2840
+ /* @__PURE__ */ jsx(ScrollArea, { className: "max-h-[300px]", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyText }) : /* @__PURE__ */ jsx("div", { className: "p-1", children: filteredOptions.map((option) => {
2841
+ const isSelected = value.includes(option.value);
2842
+ const isDisabled = option.disabled || false;
2843
+ return /* @__PURE__ */ jsxs(
2844
+ "div",
2845
+ {
2846
+ role: "option",
2847
+ "aria-selected": isSelected,
2848
+ "aria-disabled": isDisabled,
2849
+ className: cn(
2850
+ "relative flex select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
2851
+ isDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-accent hover:text-accent-foreground",
2852
+ isSelected && !isDisabled && "bg-accent text-accent-foreground"
2853
+ ),
2854
+ onMouseDown: (e) => {
2855
+ e.preventDefault();
2856
+ e.stopPropagation();
2857
+ },
2858
+ onClick: (e) => {
2859
+ e.preventDefault();
2860
+ e.stopPropagation();
2861
+ if (!isDisabled) {
2862
+ handleSelect(option.value);
2863
+ }
2864
+ },
2865
+ children: [
2866
+ /* @__PURE__ */ jsx(
2867
+ "div",
2868
+ {
2869
+ className: cn(
2870
+ "mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
2871
+ isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
2872
+ ),
2873
+ children: /* @__PURE__ */ jsx(Check, { className: cn("h-4 w-4") })
2874
+ }
2875
+ ),
2876
+ option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
2877
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: option.label })
2878
+ ]
2879
+ },
2880
+ String(option.value)
2881
+ );
2882
+ }) }) }),
2883
+ /* @__PURE__ */ jsx("div", { className: "border-t p-2", children: /* @__PURE__ */ jsx(
2884
+ Button,
2885
+ {
2886
+ type: "button",
2887
+ variant: "outline",
2888
+ size: "sm",
2889
+ className: "w-full h-8 text-xs",
2890
+ onClick: (e) => {
2891
+ e.stopPropagation();
2892
+ setOpen(false);
2893
+ },
2894
+ children: "Close"
2895
+ }
2896
+ ) })
2897
+ ] })
2898
+ }
2899
+ )
2900
+ ] });
2901
+ }
2902
+ );
2903
+ MultiSelect.displayName = "MultiSelect";
2904
+ }
2905
+ });
2906
+ var init_date_picker = __esm({
2907
+ "src/ui/forms/date-picker.tsx"() {
2908
+ "use client";
2909
+ }
2910
+ });
2911
+ var init_date_range_picker = __esm({
2912
+ "src/ui/forms/date-range-picker.tsx"() {
2913
+ "use client";
2914
+ }
2915
+ });
2916
+ var init_input_time = __esm({
2917
+ "src/ui/forms/input-time.tsx"() {
2918
+ "use client";
2919
+ }
2920
+ });
2921
+ var init_date_time_picker = __esm({
2922
+ "src/ui/forms/date-time-picker.tsx"() {
2923
+ "use client";
2924
+ }
2925
+ });
2926
+ var init_emoji_picker = __esm({
2927
+ "src/ui/forms/emoji-picker.tsx"() {
2928
+ "use client";
2929
+ dynamic(
2930
+ () => {
2931
+ return import('emoji-picker-react');
2932
+ },
2933
+ { ssr: false }
2934
+ );
2935
+ }
2936
+ });
2937
+ var init_file_thumbnail = __esm({
2938
+ "src/ui/forms/file-thumbnail.tsx"() {
2939
+ }
2940
+ });
2941
+ var init_file_dropzone = __esm({
2942
+ "src/ui/forms/file-dropzone.tsx"() {
2943
+ "use client";
2944
+ }
2945
+ });
2946
+ var init_input_file = __esm({
2947
+ "src/ui/forms/input-file.tsx"() {
2948
+ "use client";
2949
+ }
2950
+ });
2951
+ var init_input_group = __esm({
2952
+ "src/ui/forms/input-group.tsx"() {
2953
+ "use client";
2954
+ }
2955
+ });
2956
+ var init_input_otp = __esm({
2957
+ "src/ui/forms/input-otp.tsx"() {
2958
+ "use client";
2959
+ }
2960
+ });
2961
+ var init_input_phone = __esm({
2962
+ "src/ui/forms/input-phone.tsx"() {
2963
+ "use client";
2964
+ }
2965
+ });
2966
+ var init_input_spin = __esm({
2967
+ "src/ui/forms/input-spin.tsx"() {
2968
+ "use client";
2969
+ }
2970
+ });
2971
+ var init_input_tags = __esm({
2972
+ "src/ui/forms/input-tags.tsx"() {
2973
+ "use client";
2974
+ }
2975
+ });
2976
+ var init_multiple_date_picker = __esm({
2977
+ "src/ui/forms/multiple-date-picker.tsx"() {
2978
+ "use client";
2979
+ }
2980
+ });
2981
+ var init_time_picker = __esm({
2982
+ "src/ui/forms/time-picker.tsx"() {
2983
+ "use client";
2984
+ }
2985
+ });
2986
+ var init_editor = __esm({
2987
+ "src/ui/forms/editor/index.tsx"() {
2988
+ "use client";
2989
+ }
2990
+ });
2991
+ var init_forms = __esm({
2992
+ "src/ui/forms/index.tsx"() {
2993
+ "use client";
2994
+ init_radio_group();
2995
+ init_rating();
2996
+ init_command();
2997
+ init_multi_select();
2998
+ init_date_picker();
2999
+ init_date_range_picker();
3000
+ init_date_time_picker();
3001
+ init_emoji_picker();
3002
+ init_file_dropzone();
3003
+ init_file_thumbnail();
3004
+ init_input_file();
3005
+ init_input_group();
3006
+ init_input_otp();
3007
+ init_input_phone();
3008
+ init_input_spin();
3009
+ init_input_tags();
3010
+ init_input_time();
3011
+ init_multiple_date_picker();
3012
+ init_time_picker();
3013
+ init_editor();
3014
+ createContext(
3015
+ {}
3016
+ );
3017
+ createContext(
3018
+ {}
3019
+ );
3020
+ }
3021
+ });
3022
+ var init_formatted_number_input = __esm({
3023
+ "src/ui/data-display/formatted-number-input.tsx"() {
3024
+ "use client";
3025
+ }
3026
+ });
3027
+ var init_data_table_pagination = __esm({
3028
+ "src/ui/data-display/data-table-pagination.tsx"() {
3029
+ "use client";
3030
+ }
3031
+ });
3032
+ var init_kpi_card = __esm({
3033
+ "src/ui/data-display/kpi-card.tsx"() {
3034
+ "use client";
3035
+ }
3036
+ });
3037
+ var THEME_STYLES, CompactStatBar;
3038
+ var init_compact_stat_bar = __esm({
3039
+ "src/ui/data-display/compact-stat-bar.tsx"() {
3040
+ init_utils();
3041
+ THEME_STYLES = {
3042
+ dark: {
3043
+ wrapper: "hover:bg-[#181d26]/5 dark:hover:bg-slate-100/5",
3044
+ box: "bg-[#181d26] group-hover:bg-[#0a2e0e] dark:bg-slate-800 dark:group-hover:bg-slate-700",
3045
+ icon: "text-white",
3046
+ label: "text-[#181d26] dark:text-slate-300"
3047
+ },
3048
+ green: {
3049
+ wrapper: "hover:bg-[#006400]/10",
3050
+ box: "bg-[#006400] group-hover:bg-[#39bf45]",
3051
+ icon: "text-white",
3052
+ label: "text-[#006400] dark:text-[#39bf45]"
3053
+ },
3054
+ blue: {
3055
+ wrapper: "hover:bg-[#254fad]/10",
3056
+ box: "bg-[#254fad] group-hover:bg-[#1d3d8f]",
3057
+ icon: "text-white",
3058
+ label: "text-[#254fad] dark:text-[#60a5fa]"
3059
+ },
3060
+ purple: {
3061
+ wrapper: "hover:bg-[#7C3AED]/10",
3062
+ box: "bg-[#7C3AED] group-hover:bg-[#6D28D9]",
3063
+ icon: "text-white",
3064
+ label: "text-[#7C3AED] dark:text-[#a78bfa]"
3065
+ },
3066
+ orange: {
3067
+ wrapper: "hover:bg-[#EA580C]/10",
3068
+ box: "bg-[#EA580C] group-hover:bg-[#C2410C]",
3069
+ icon: "text-white",
3070
+ label: "text-[#EA580C] dark:text-[#fb923c]"
3071
+ },
3072
+ emerald: {
3073
+ wrapper: "hover:bg-[#059669]/10",
3074
+ box: "bg-[#059669] group-hover:bg-[#047857]",
3075
+ icon: "text-white",
3076
+ label: "text-[#059669] dark:text-[#34d399]"
3077
+ },
3078
+ primary: {
3079
+ wrapper: "hover:bg-primary/10",
3080
+ box: "bg-primary group-hover:bg-primary/90",
3081
+ icon: "text-primary-foreground",
3082
+ label: "text-primary"
3083
+ },
3084
+ destructive: {
3085
+ wrapper: "hover:bg-destructive/10",
3086
+ box: "bg-destructive group-hover:bg-destructive/90",
3087
+ icon: "text-destructive-foreground",
3088
+ label: "text-destructive"
3089
+ },
3090
+ muted: {
3091
+ wrapper: "hover:bg-muted/50",
3092
+ box: "bg-muted group-hover:bg-muted-foreground/20",
3093
+ icon: "text-muted-foreground",
3094
+ label: "text-muted-foreground"
3095
+ },
3096
+ rose: {
3097
+ wrapper: "hover:bg-[#E11D48]/10",
3098
+ box: "bg-[#E11D48] group-hover:bg-[#BE123C]",
3099
+ icon: "text-white",
3100
+ label: "text-[#E11D48] dark:text-[#fb7185]"
3101
+ }
3102
+ };
3103
+ CompactStatBar = memo(function CompactStatBar2({
3104
+ items,
3105
+ className
3106
+ }) {
3107
+ if (!items || items.length === 0) return null;
3108
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col md:flex-row md:items-stretch gap-2 pb-1", className), children: /* @__PURE__ */ jsx("div", { className: "flex items-stretch overflow-x-auto no-scrollbar flex-1 bg-white dark:bg-[#1e293b] border border-slate-200 dark:border-slate-800 shadow-sm rounded-[10px] divide-x divide-slate-100 dark:divide-slate-800", children: items.map((item) => {
3109
+ const theme = THEME_STYLES[item.colorTheme || "dark"];
3110
+ const Icon2 = item.icon;
3111
+ return /* @__PURE__ */ jsxs(
3112
+ "div",
3113
+ {
3114
+ className: cn(
3115
+ "flex items-center gap-3 min-w-fit px-5 py-2 flex-1 transition-colors group cursor-default",
3116
+ theme.wrapper
3117
+ ),
3118
+ children: [
3119
+ /* @__PURE__ */ jsx(
3120
+ "div",
3121
+ {
3122
+ className: cn(
3123
+ "p-1.5 rounded-md transition-colors shadow-sm shrink-0",
3124
+ theme.box
3125
+ ),
3126
+ children: /* @__PURE__ */ jsx(Icon2, { className: cn("w-3.5 h-3.5", theme.icon), strokeWidth: 2.5 })
3127
+ }
3128
+ ),
3129
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3130
+ /* @__PURE__ */ jsx(
3131
+ "span",
3132
+ {
3133
+ className: cn(
3134
+ "text-[9px] font-bold uppercase tracking-wider mb-0.5",
3135
+ item.isHighlighted ? "text-emerald-600 dark:text-emerald-400" : theme.label
3136
+ ),
3137
+ children: item.label
3138
+ }
3139
+ ),
3140
+ /* @__PURE__ */ jsx("span", { className: cn(
3141
+ "font-black leading-none",
3142
+ item.isHighlighted ? "text-[22px] text-emerald-700 dark:text-emerald-400" : "text-[17px] text-slate-900 dark:text-white"
3143
+ ), children: item.value })
3144
+ ] })
3145
+ ]
3146
+ },
3147
+ item.id
3148
+ );
3149
+ }) }) });
3150
+ });
3151
+ }
3152
+ });
3153
+ var init_show_more_text = __esm({
3154
+ "src/ui/data-display/show-more-text.tsx"() {
3155
+ "use client";
3156
+ }
3157
+ });
3158
+ var init_chart = __esm({
3159
+ "src/ui/data-display/chart.tsx"() {
3160
+ "use client";
3161
+ createContext(null);
3162
+ }
3163
+ });
3164
+ var init_carousel = __esm({
3165
+ "src/ui/data-display/carousel.tsx"() {
3166
+ "use client";
3167
+ createContext(null);
3168
+ }
3169
+ });
3170
+ var init_accordion = __esm({
3171
+ "src/ui/data-display/accordion.tsx"() {
3172
+ "use client";
3173
+ }
3174
+ });
3175
+ var init_kanban_item = __esm({
3176
+ "src/ui/data-display/kanban/kanban-item.tsx"() {
3177
+ }
3178
+ });
3179
+ var init_kanban_column = __esm({
3180
+ "src/ui/data-display/kanban/kanban-column.tsx"() {
3181
+ }
3182
+ });
3183
+ var init_kanban_board = __esm({
3184
+ "src/ui/data-display/kanban/kanban-board.tsx"() {
3185
+ }
3186
+ });
3187
+
3188
+ // src/ui/data-display/kanban/kanban-types.ts
3189
+ var init_kanban_types = __esm({
3190
+ "src/ui/data-display/kanban/kanban-types.ts"() {
3191
+ }
3192
+ });
3193
+
3194
+ // src/ui/data-display/kanban/index.ts
3195
+ var init_kanban = __esm({
3196
+ "src/ui/data-display/kanban/index.ts"() {
3197
+ init_kanban_board();
3198
+ init_kanban_column();
3199
+ init_kanban_item();
3200
+ init_kanban_types();
3201
+ }
3202
+ });
3203
+ var init_aspect_ratio = __esm({
3204
+ "src/ui/data-display/aspect-ratio.tsx"() {
3205
+ "use client";
3206
+ }
3207
+ });
3208
+ var init_bento_grid = __esm({
3209
+ "src/ui/data-display/bento-grid.tsx"() {
3210
+ }
3211
+ });
3212
+ var init_highlight = __esm({
3213
+ "src/ui/data-display/highlight.tsx"() {
3214
+ }
3215
+ });
3216
+ var init_code_block_highlight = __esm({
3217
+ "src/ui/data-display/code-block-highlight.tsx"() {
3218
+ "use client";
3219
+ }
3220
+ });
3221
+ var init_collapsible = __esm({
3222
+ "src/ui/data-display/collapsible.tsx"() {
3223
+ "use client";
3224
+ }
3225
+ });
3226
+ var init_hover_card = __esm({
3227
+ "src/ui/data-display/hover-card.tsx"() {
3228
+ "use client";
3229
+ }
3230
+ });
3231
+ var init_iphone_15_pro = __esm({
3232
+ "src/ui/data-display/iphone-15-pro.tsx"() {
3233
+ }
3234
+ });
3235
+ var init_media_grid = __esm({
3236
+ "src/ui/data-display/media-grid.tsx"() {
3237
+ "use client";
3238
+ }
3239
+ });
3240
+ var init_safari = __esm({
3241
+ "src/ui/data-display/safari.tsx"() {
3242
+ }
3243
+ });
3244
+ var init_timeline = __esm({
3245
+ "src/ui/data-display/timeline.tsx"() {
3246
+ cva("grid", {
3247
+ variants: {
3248
+ align: {
3249
+ left: "[&>li]:grid-cols-[0_min-content_1fr]",
3250
+ right: "[&>li]:grid-cols-[1fr_min-content]",
3251
+ center: "[&>li]:grid-cols-[1fr_min-content_1fr]"
3252
+ }
3253
+ },
3254
+ defaultVariants: {
3255
+ align: "left"
3256
+ }
3257
+ });
3258
+ cva("grid items-center gap-x-2", {
3259
+ variants: {
3260
+ status: {
3261
+ done: "text-foreground",
3262
+ default: "text-muted-foreground"
3263
+ }
3264
+ },
3265
+ defaultVariants: {
3266
+ status: "default"
3267
+ }
3268
+ });
3269
+ cva("row-start-2 row-end-2 pb-8", {
3270
+ variants: {
3271
+ side: {
3272
+ start: "col-start-3 col-end-4 me-auto text-start",
3273
+ end: "col-start-1 col-end-2 ms-auto text-end"
3274
+ }
3275
+ },
3276
+ defaultVariants: {
3277
+ side: "start"
3278
+ }
3279
+ });
3280
+ cva(
3281
+ "row-start-1 row-end-1 line-clamp-1 max-w-full truncate",
3282
+ {
3283
+ variants: {
3284
+ side: {
3285
+ start: "col-start-3 col-end-4 me-auto text-start",
3286
+ end: "col-start-1 col-end-2 ms-auto text-end"
3287
+ },
3288
+ variant: {
3289
+ primary: "text-base font-medium text-foreground",
3290
+ secondary: "text-sm font-light text-muted-foreground"
3291
+ }
3292
+ },
3293
+ defaultVariants: {
3294
+ side: "start",
3295
+ variant: "primary"
3296
+ }
3297
+ }
3298
+ );
3299
+ }
3300
+ });
3301
+
3302
+ // src/ui/data-display/data-table/index.ts
3303
+ var init_data_table = __esm({
3304
+ "src/ui/data-display/data-table/index.ts"() {
3305
+ }
3306
+ });
3307
+
3308
+ // src/ui/data-display/index.tsx
3309
+ var init_data_display = __esm({
3310
+ "src/ui/data-display/index.tsx"() {
3311
+ "use client";
3312
+ init_formatted_number_input();
3313
+ init_data_table_pagination();
3314
+ init_avatar();
3315
+ init_kpi_card();
3316
+ init_compact_stat_bar();
3317
+ init_show_more_text();
3318
+ init_chart();
3319
+ init_carousel();
3320
+ init_accordion();
3321
+ init_kanban();
3322
+ init_aspect_ratio();
3323
+ init_bento_grid();
3324
+ init_code_block_highlight();
3325
+ init_collapsible();
3326
+ init_highlight();
3327
+ init_hover_card();
3328
+ init_iphone_15_pro();
3329
+ init_media_grid();
3330
+ init_safari();
3331
+ init_timeline();
3332
+ init_data_table();
3333
+ }
3334
+ });
3335
+ var init_auth_layout = __esm({
3336
+ "src/ui/auth/auth-layout.tsx"() {
3337
+ "use client";
3338
+ }
3339
+ });
3340
+ var init_sign_in_form = __esm({
3341
+ "src/ui/auth/sign-in-form.tsx"() {
3342
+ "use client";
3343
+ }
3344
+ });
3345
+ var init_register_form = __esm({
3346
+ "src/ui/auth/register-form.tsx"() {
3347
+ "use client";
3348
+ }
3349
+ });
3350
+ var init_oauth_links = __esm({
3351
+ "src/ui/auth/oauth-links.tsx"() {
3352
+ "use client";
3353
+ }
3354
+ });
3355
+ var init_forgot_password_form = __esm({
3356
+ "src/ui/auth/forgot-password-form.tsx"() {
3357
+ "use client";
3358
+ }
3359
+ });
3360
+ var init_new_password_form = __esm({
3361
+ "src/ui/auth/new-password-form.tsx"() {
3362
+ "use client";
3363
+ }
3364
+ });
3365
+ var init_verify_email_form = __esm({
3366
+ "src/ui/auth/verify-email-form.tsx"() {
3367
+ "use client";
3368
+ }
3369
+ });
3370
+
3371
+ // src/ui/auth/index.tsx
3372
+ var init_auth = __esm({
3373
+ "src/ui/auth/index.tsx"() {
3374
+ init_auth_layout();
3375
+ init_sign_in_form();
3376
+ init_register_form();
3377
+ init_oauth_links();
3378
+ init_forgot_password_form();
3379
+ init_new_password_form();
3380
+ init_verify_email_form();
3381
+ }
3382
+ });
3383
+ var init_job_management = __esm({
3384
+ "src/ui/management/job-management.tsx"() {
3385
+ "use client";
3386
+ }
3387
+ });
3388
+ var init_audit_log_page = __esm({
3389
+ "src/ui/management/audit-log-page.tsx"() {
3390
+ "use client";
3391
+ }
3392
+ });
3393
+ var init_cache_management = __esm({
3394
+ "src/ui/management/cache-management.tsx"() {
3395
+ "use client";
3396
+ }
3397
+ });
3398
+
3399
+ // src/ui/management/index.ts
3400
+ var init_management = __esm({
3401
+ "src/ui/management/index.ts"() {
3402
+ init_job_management();
3403
+ init_audit_log_page();
3404
+ init_cache_management();
3405
+ }
3406
+ });
3407
+ var init_not_found = __esm({
3408
+ "src/ui/pages/not-found.tsx"() {
3409
+ }
3410
+ });
3411
+
3412
+ // src/ui/index.tsx
3413
+ var init_ui = __esm({
3414
+ "src/ui/index.tsx"() {
3415
+ init_primitives();
3416
+ init_client();
3417
+ init_forms();
3418
+ init_data_display();
3419
+ init_feedback();
3420
+ init_layout();
3421
+ init_auth();
3422
+ init_management();
3423
+ init_not_found();
3424
+ }
3425
+ });
3426
+
3427
+ // src/rbac/index.ts
3428
+ init_utils();
3429
+
3430
+ // src/infrastructure/cache/cache.ts
3431
+ var MemoryCache = class {
3432
+ constructor(options) {
3433
+ this.store = /* @__PURE__ */ new Map();
3434
+ this.name = options.name;
3435
+ this.defaultTtl = options.ttl || 3600;
3436
+ this.maxSize = options.max || 1e3;
3437
+ this.prefix = options.prefix || "";
3438
+ }
3439
+ getFullKey(key) {
3440
+ return this.prefix ? `${this.prefix}:${this.name}:${key}` : `${this.name}:${key}`;
3441
+ }
3442
+ isExpired(entry) {
3443
+ if (entry.expireAt === null) return false;
3444
+ return Date.now() > entry.expireAt;
3445
+ }
3446
+ cleanup() {
3447
+ for (const [key, entry] of this.store.entries()) {
3448
+ if (this.isExpired(entry)) {
3449
+ this.store.delete(key);
3450
+ }
3451
+ }
3452
+ }
3453
+ async get(key) {
3454
+ const fullKey = this.getFullKey(key);
3455
+ const entry = this.store.get(fullKey);
3456
+ if (!entry) return void 0;
3457
+ if (this.isExpired(entry)) {
3458
+ this.store.delete(fullKey);
3459
+ return void 0;
3460
+ }
3461
+ return entry.value;
3462
+ }
3463
+ async set(key, value, ttl) {
3464
+ const fullKey = this.getFullKey(key);
3465
+ const ttlSeconds = ttl ?? this.defaultTtl;
3466
+ if (this.store.size >= this.maxSize) {
3467
+ this.cleanup();
3468
+ if (this.store.size >= this.maxSize) {
3469
+ const firstKey = this.store.keys().next().value;
3470
+ if (firstKey) this.store.delete(firstKey);
3471
+ }
3472
+ }
3473
+ this.store.set(fullKey, {
3474
+ value,
3475
+ expireAt: ttlSeconds > 0 ? Date.now() + ttlSeconds * 1e3 : null
3476
+ });
3477
+ }
3478
+ async del(key) {
3479
+ const fullKey = this.getFullKey(key);
3480
+ this.store.delete(fullKey);
3481
+ }
3482
+ async has(key) {
3483
+ const value = await this.get(key);
3484
+ return value !== void 0;
3485
+ }
3486
+ async reset() {
3487
+ const prefix = this.getFullKey("");
3488
+ for (const key of this.store.keys()) {
3489
+ if (key.startsWith(prefix)) {
3490
+ this.store.delete(key);
3491
+ }
3492
+ }
3493
+ }
3494
+ async keys() {
3495
+ this.cleanup();
3496
+ const prefix = this.getFullKey("");
3497
+ const result = [];
3498
+ for (const key of this.store.keys()) {
3499
+ if (key.startsWith(prefix)) {
3500
+ result.push(key.slice(prefix.length));
3501
+ }
3502
+ }
3503
+ return result;
3504
+ }
3505
+ /** Get cache info for admin dashboard */
3506
+ getInfo() {
3507
+ return {
3508
+ name: this.name,
3509
+ ttl: this.defaultTtl,
3510
+ maxSize: this.maxSize
3511
+ };
3512
+ }
3513
+ };
3514
+
3515
+ // src/infrastructure/cache/cache-manager.ts
3516
+ var CacheManagerImpl = class {
3517
+ constructor(options = {}) {
3518
+ this.caches = /* @__PURE__ */ new Map();
3519
+ this.options = {
3520
+ defaultTtl: options.defaultTtl || 3600,
3521
+ prefix: options.prefix || ""
3522
+ };
3523
+ }
3524
+ create(options) {
3525
+ const existing = this.caches.get(options.name);
3526
+ if (existing) {
3527
+ return existing;
3528
+ }
3529
+ const cache = new MemoryCache({
3530
+ ...options,
3531
+ ttl: options.ttl || this.options.defaultTtl,
3532
+ prefix: this.options.prefix
3533
+ });
3534
+ this.caches.set(options.name, cache);
3535
+ return cache;
3536
+ }
3537
+ get(name) {
3538
+ return this.caches.get(name);
3539
+ }
3540
+ async flushAll() {
3541
+ const promises = [];
3542
+ for (const cache of this.caches.values()) {
3543
+ promises.push(cache.reset());
3544
+ }
3545
+ await Promise.all(promises);
3546
+ }
3547
+ /** Get all cache names */
3548
+ getAllCaches() {
3549
+ return Array.from(this.caches.keys());
3550
+ }
3551
+ /** Get stats for all caches (for admin dashboard) */
3552
+ async getStats() {
3553
+ const stats = [];
3554
+ for (const [name, cache] of this.caches.entries()) {
3555
+ const keys = await cache.keys();
3556
+ stats.push({
3557
+ name,
3558
+ itemCount: keys.length,
3559
+ ttl: cache.getInfo().ttl
3560
+ });
3561
+ }
3562
+ return stats;
3563
+ }
3564
+ /** Clear a specific cache by name */
3565
+ async clearCache(name) {
3566
+ const cache = this.caches.get(name);
3567
+ if (cache) {
3568
+ await cache.reset();
3569
+ return true;
3570
+ }
3571
+ return false;
3572
+ }
3573
+ };
3574
+ var globalForCache = globalThis;
3575
+ var cacheManager = globalForCache.coreCacheManager ?? new CacheManagerImpl();
3576
+ if (process.env.NODE_ENV !== "production") {
3577
+ globalForCache.coreCacheManager = cacheManager;
3578
+ }
3579
+
3580
+ // src/rbac/permission-service.ts
3581
+ init_utils();
3582
+ async function getUserPermissionsFromDB(db, userId) {
3583
+ try {
3584
+ const userRoles = await db.userRole.findMany({
3585
+ where: { userId },
3586
+ select: {
3587
+ roleCode: true,
3588
+ role: {
3589
+ select: {
3590
+ rolePermissions: {
3591
+ select: {
3592
+ resourceCode: true,
3593
+ actionCode: true
3594
+ }
3595
+ }
3596
+ }
3597
+ }
3598
+ }
3599
+ });
3600
+ if (userRoles.length === 0) {
3601
+ return [];
3602
+ }
3603
+ const allPermissions = userRoles.flatMap(
3604
+ (ur) => ur.role.rolePermissions.map((rp) => ({
3605
+ resourceCode: rp.resourceCode,
3606
+ actionCode: rp.actionCode
3607
+ }))
3608
+ );
3609
+ const uniquePermissions = Array.from(
3610
+ new Map(
3611
+ allPermissions.map((p) => [
3612
+ `${p.resourceCode}:${p.actionCode}`,
3613
+ {
3614
+ resourceCode: p.resourceCode,
3615
+ actionCode: p.actionCode
3616
+ }
3617
+ ])
3618
+ ).values()
3619
+ );
3620
+ return uniquePermissions;
3621
+ } catch (error) {
3622
+ logger.error("Error fetching user permissions from DB", error);
3623
+ return [];
3624
+ }
3625
+ }
3626
+ async function getCachedUserPermissions(db, userId, opts) {
3627
+ const force = opts?.forceRefresh === true;
3628
+ if (!force) {
3629
+ const cached = await getFromCache(userId);
3630
+ if (cached) return cached;
3631
+ }
3632
+ const pendingQuery = pendingQueries.get(userId);
3633
+ if (pendingQuery) {
3634
+ return pendingQuery;
3635
+ }
3636
+ const queryPromise = getUserPermissionsFromDB(db, userId).then(async (perms) => {
3637
+ await setToCache(userId, perms);
3638
+ pendingQueries.delete(userId);
3639
+ return perms;
3640
+ }).catch((error) => {
3641
+ pendingQueries.delete(userId);
3642
+ throw error;
3643
+ });
3644
+ pendingQueries.set(userId, queryPromise);
3645
+ return queryPromise;
3646
+ }
3647
+
3648
+ // src/rbac/role-service.ts
3649
+ async function getRolesData(db, params = {}) {
3650
+ const { page = 1, pageSize = 10, search, status } = params;
3651
+ const whereConditions = [];
3652
+ if (search) {
3653
+ whereConditions.push({
3654
+ OR: [
3655
+ { name: { contains: search, mode: "insensitive" } },
3656
+ { code: { contains: search, mode: "insensitive" } },
3657
+ { description: { contains: search, mode: "insensitive" } }
3658
+ ]
3659
+ });
3660
+ }
3661
+ if (status && status !== "all") {
3662
+ whereConditions.push({ status });
3663
+ }
3664
+ const where = whereConditions.length > 0 ? { AND: whereConditions } : {};
3665
+ const [total, items] = await Promise.all([
3666
+ db.role.count({ where }),
3667
+ db.role.findMany({
3668
+ where,
3669
+ orderBy: { createdAt: "desc" },
3670
+ skip: (page - 1) * pageSize,
3671
+ take: pageSize,
3672
+ include: {
3673
+ userRoles: {
3674
+ include: {
3675
+ user: {
3676
+ select: {
3677
+ id: true,
3678
+ name: true,
3679
+ email: true,
3680
+ image: true,
3681
+ isActive: true
3682
+ }
3683
+ }
3684
+ }
3685
+ },
3686
+ rolePermissions: {
3687
+ include: {
3688
+ resource: {
3689
+ select: {
3690
+ code: true,
3691
+ name: true,
3692
+ icon: true
3693
+ }
3694
+ },
3695
+ action: {
3696
+ select: {
3697
+ code: true,
3698
+ name: true
3699
+ }
3700
+ }
3701
+ }
3702
+ }
3703
+ }
3704
+ })
3705
+ ]);
3706
+ const transformedItems = items.map((role) => ({
3707
+ id: role.id,
3708
+ name: role.name,
3709
+ code: role.code,
3710
+ description: role.description || void 0,
3711
+ status: role.status,
3712
+ // Transform rolePermissions to array of "action:resource" strings
3713
+ permissions: role.rolePermissions.map(
3714
+ (rp) => `${rp.actionCode}:${rp.resourceCode}`
3715
+ ),
3716
+ usersCount: role.userRoles.length,
3717
+ users: role.userRoles.map((ur) => ({
3718
+ id: ur.user.id,
3719
+ name: ur.user.name,
3720
+ email: ur.user.email,
3721
+ image: ur.user.image,
3722
+ isActive: ur.user.isActive
3723
+ })),
3724
+ createdAt: role.createdAt.toISOString(),
3725
+ updatedAt: role.updatedAt.toISOString(),
3726
+ createdBy: role.createdBy || void 0,
3727
+ updatedBy: role.updatedBy || void 0
3728
+ }));
3729
+ return { total, page, pageSize, items: transformedItems };
3730
+ }
3731
+
3732
+ // src/rbac/resource-service.ts
3733
+ async function getResourcesData(db, params = {}) {
3734
+ const { page = 1, pageSize = 10, search, status, group, type } = params;
3735
+ const where = {
3736
+ AND: [
3737
+ search ? {
3738
+ OR: [
3739
+ { code: { contains: search, mode: "insensitive" } },
3740
+ { name: { contains: search, mode: "insensitive" } },
3741
+ { description: { contains: search, mode: "insensitive" } },
3742
+ { path: { contains: search, mode: "insensitive" } }
3743
+ ]
3744
+ } : {},
3745
+ status && status !== "all" ? { status: { equals: status, mode: "insensitive" } } : {},
3746
+ group && group !== "all" ? { group } : {},
3747
+ type && type !== "all" ? { type } : {}
3748
+ ]
3749
+ };
3750
+ const [total, items] = await Promise.all([
3751
+ db.resource.count({ where }),
3752
+ db.resource.findMany({
3753
+ where,
3754
+ orderBy: [{ order: "asc" }, { updatedAt: "desc" }],
3755
+ skip: (page - 1) * pageSize,
3756
+ take: pageSize
3757
+ })
3758
+ ]);
3759
+ const transformedItems = items.map((item) => ({
3760
+ id: item.id,
3761
+ code: item.code,
3762
+ name: item.name,
3763
+ group: item.group || void 0,
3764
+ description: item.description || void 0,
3765
+ status: item.status,
3766
+ parentCode: item.parentCode || void 0,
3767
+ order: item.order || void 0,
3768
+ type: item.type || void 0,
3769
+ icon: item.icon || void 0,
3770
+ path: item.path || void 0,
3771
+ config: item.config || void 0,
3772
+ createdAt: item.createdAt.toISOString(),
3773
+ updatedAt: item.updatedAt.toISOString()
3774
+ }));
3775
+ return { total, page, pageSize, items: transformedItems };
3776
+ }
3777
+ async function getResourcesForPermissionMatrix(db) {
3778
+ return await db.resource.findMany({
3779
+ where: {
3780
+ status: "active"
3781
+ },
3782
+ orderBy: [{ group: "asc" }, { order: "asc" }, { name: "asc" }],
3783
+ select: {
3784
+ id: true,
3785
+ code: true,
3786
+ name: true,
3787
+ group: true,
3788
+ description: true,
3789
+ icon: true,
3790
+ order: true,
3791
+ config: true
3792
+ }
3793
+ });
3794
+ }
3795
+ async function getActionsForPermissionMatrix(db) {
3796
+ return await db.action.findMany({
3797
+ where: {
3798
+ status: "active"
3799
+ },
3800
+ orderBy: {
3801
+ code: "asc"
3802
+ },
3803
+ select: {
3804
+ id: true,
3805
+ code: true,
3806
+ name: true,
3807
+ description: true,
3808
+ isDefault: true
3809
+ }
3810
+ });
3811
+ }
3812
+
3813
+ // src/rbac/resource-validator.ts
3814
+ var resourceCache = cacheManager.create({
3815
+ name: "resource-codes",
3816
+ ttl: 3600,
3817
+ // 1 hour - resource codes rarely change
3818
+ max: 1e3
3819
+ });
3820
+ async function isValidResourceCode(db, resourceCode) {
3821
+ const cacheKey = `valid:${resourceCode}`;
3822
+ const cached = await resourceCache.get(cacheKey);
3823
+ if (cached !== void 0) {
3824
+ return cached;
3825
+ }
3826
+ const resource = await db.resource.findUnique({
3827
+ where: { code: resourceCode }
3828
+ });
3829
+ const isValid = resource !== null;
3830
+ await resourceCache.set(cacheKey, isValid);
3831
+ return isValid;
3832
+ }
3833
+ function getPermissionResourceCode(config, entityParam) {
3834
+ if (config?.permissionResource) {
3835
+ return config.permissionResource;
3836
+ }
3837
+ if (config?.name) {
3838
+ return config.name;
3839
+ }
3840
+ return entityParam;
3841
+ }
3842
+ async function validatePermissionResource(db, config, entityParam) {
3843
+ const resourceCode = getPermissionResourceCode(config, entityParam);
3844
+ const isValid = await isValidResourceCode(db, resourceCode);
3845
+ return { resourceCode, isValid };
3846
+ }
3847
+ async function preloadResourceCodes(db) {
3848
+ const resources = await db.resource.findMany({
3849
+ select: { code: true }
3850
+ });
3851
+ for (const resource of resources) {
3852
+ await resourceCache.set(`valid:${resource.code}`, true);
3853
+ }
3854
+ }
3855
+ async function clearResourceCache() {
3856
+ await resourceCache.reset();
3857
+ }
3858
+
3859
+ // src/rbac/pages/role-list-page.tsx
3860
+ init_ui();
3861
+
3862
+ // src/rbac/components/roles/role-stats-cards.tsx
3863
+ init_compact_stat_bar();
3864
+ var RoleStatsCards = memo(function RoleStatsCards2({
3865
+ totalRoles,
3866
+ activeRoles,
3867
+ totalPermissions,
3868
+ totalUsers
3869
+ }) {
3870
+ const items = [
3871
+ { id: "total", label: "T\u1ED5ng vai tr\xF2", value: totalRoles || 0, icon: Shield, colorTheme: "dark" },
3872
+ { id: "active", label: "Ho\u1EA1t \u0111\u1ED9ng", value: activeRoles || 0, icon: ShieldCheck, colorTheme: "green" },
3873
+ { id: "perms", label: "T\u1ED5ng quy\u1EC1n h\u1EA1n", value: totalPermissions || 0, icon: Key, colorTheme: "purple" },
3874
+ { id: "users", label: "T\u1ED5ng ng\u01B0\u1EDDi d\xF9ng", value: totalUsers || 0, icon: Users, colorTheme: "orange" }
3875
+ ];
3876
+ return /* @__PURE__ */ jsx(CompactStatBar, { items });
3877
+ });
3878
+
3879
+ // src/rbac/components/roles/role-toolbar.tsx
3880
+ init_ui();
3881
+ var RoleToolbar = memo(function RoleToolbar2({
3882
+ dictionary,
3883
+ totalRows,
3884
+ searchTerm,
3885
+ statusFilter,
3886
+ onSearchChange,
3887
+ onStatusFilterChange,
3888
+ lang,
3889
+ canCreate,
3890
+ canImport,
3891
+ canExport
3892
+ }) {
3893
+ const router = useRouter();
3894
+ const [localSearchTerm, setLocalSearchTerm] = useState(searchTerm);
3895
+ useEffect(() => {
3896
+ setLocalSearchTerm(searchTerm);
3897
+ }, [searchTerm]);
3898
+ useEffect(() => {
3899
+ const handler = setTimeout(() => {
3900
+ if (localSearchTerm !== searchTerm) {
3901
+ onSearchChange(localSearchTerm);
3902
+ }
3903
+ }, 500);
3904
+ return () => {
3905
+ clearTimeout(handler);
3906
+ };
3907
+ }, [localSearchTerm, onSearchChange, searchTerm]);
3908
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
3909
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
3910
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" }),
3911
+ /* @__PURE__ */ jsx(
3912
+ Input,
3913
+ {
3914
+ placeholder: "T\xECm ki\u1EBFm vai tr\xF2...",
3915
+ value: localSearchTerm,
3916
+ onChange: (e) => setLocalSearchTerm(e.target.value),
3917
+ className: "h-9 w-[220px] lg:w-[280px] pl-9 text-[13px] bg-[#ffffff] dark:bg-[#181d26] border-[#dddddd] dark:border-[#333840] hover:bg-slate-50 transition-colors shadow-sm rounded-[6px] focus-visible:ring-1 focus-visible:ring-primary"
3918
+ }
3919
+ ),
3920
+ localSearchTerm && /* @__PURE__ */ jsx(
3921
+ Button,
3922
+ {
3923
+ variant: "ghost",
3924
+ size: "sm",
3925
+ className: "absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 p-0 rounded-md hover:bg-muted",
3926
+ onClick: () => setLocalSearchTerm(""),
3927
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
3928
+ }
3929
+ )
3930
+ ] }),
3931
+ /* @__PURE__ */ jsxs(Select, { value: statusFilter, onValueChange: onStatusFilterChange, children: [
3932
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-9 w-[160px] text-[13px] bg-[#ffffff] dark:bg-[#181d26] border-[#dddddd] dark:border-[#333840] hover:bg-slate-50 transition-colors shadow-sm rounded-[6px] focus-visible:ring-primary", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Tr\u1EA1ng th\xE1i" }) }),
3933
+ /* @__PURE__ */ jsxs(SelectContent, { className: "rounded-lg", children: [
3934
+ /* @__PURE__ */ jsx(SelectItem, { value: "all", children: "T\u1EA5t c\u1EA3" }),
3935
+ /* @__PURE__ */ jsx(SelectItem, { value: "active", children: "Ho\u1EA1t \u0111\u1ED9ng" }),
3936
+ /* @__PURE__ */ jsx(SelectItem, { value: "inactive", children: "Kh\xF4ng ho\u1EA1t \u0111\u1ED9ng" })
3937
+ ] })
3938
+ ] }),
3939
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
3940
+ canImport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-9 px-3 rounded-[6px] shadow-sm bg-[#ffffff] dark:bg-[#181d26] border-[#dddddd] dark:border-[#333840] hover:bg-slate-50", children: [
3941
+ /* @__PURE__ */ jsx(Upload, { className: "h-4 w-4 lg:mr-2" }),
3942
+ /* @__PURE__ */ jsx("span", { className: "hidden lg:inline text-[13px]", children: "Nh\u1EADp" })
3943
+ ] }),
3944
+ canExport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-9 px-3 rounded-[6px] shadow-sm bg-[#ffffff] dark:bg-[#181d26] border-[#dddddd] dark:border-[#333840] hover:bg-slate-50", children: [
3945
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 lg:mr-2" }),
3946
+ /* @__PURE__ */ jsx("span", { className: "hidden lg:inline text-[13px]", children: "Xu\u1EA5t" })
3947
+ ] }),
3948
+ canCreate && /* @__PURE__ */ jsxs(
3949
+ Button,
3950
+ {
3951
+ onClick: () => router.push(`/${lang}/roles/new`),
3952
+ size: "sm",
3953
+ className: "h-9 px-4 text-[13px] bg-primary hover:bg-primary/90 text-primary-foreground shadow-sm rounded-[6px] font-medium border-0",
3954
+ children: [
3955
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
3956
+ /* @__PURE__ */ jsx("span", { children: "Th\xEAm m\u1EDBi" })
3957
+ ]
3958
+ }
3959
+ )
3960
+ ] })
3961
+ ] });
3962
+ });
3963
+
3964
+ // src/rbac/components/roles/role-card.tsx
3965
+ init_ui();
3966
+ var roleColors = {
3967
+ admin: "bg-red-500",
3968
+ finance_manager: "bg-blue-500",
3969
+ purchasing_staff: "bg-green-500",
3970
+ kitchen_manager: "bg-orange-500",
3971
+ warehouse_staff: "bg-purple-500",
3972
+ supplier: "bg-gray-500"
3973
+ };
3974
+ var RoleCard = memo(function RoleCard2({
3975
+ role,
3976
+ lang,
3977
+ canUpdate,
3978
+ canCreate,
3979
+ canDelete,
3980
+ onDuplicate,
3981
+ onDelete
3982
+ }) {
3983
+ const router = useRouter();
3984
+ const permissionsCount = role.permissions.length;
3985
+ const roleColor = roleColors[role.code] || "bg-indigo-500";
3986
+ const handleEdit = useCallback(() => {
3987
+ router.push(`/${lang}/roles/${role.id}/edit`);
3988
+ }, [router, lang, role.id]);
3989
+ const handleDuplicate = useCallback(() => {
3990
+ onDuplicate(role);
3991
+ }, [onDuplicate, role]);
3992
+ const handleDelete = useCallback(() => {
3993
+ onDelete(role);
3994
+ }, [onDelete, role]);
3995
+ return /* @__PURE__ */ jsxs(Card, { className: "group relative transition-all duration-300 border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 rounded-[12px] shadow-sm hover:shadow-md hover:border-primary/40 overflow-hidden", children: [
3996
+ /* @__PURE__ */ jsx(CardHeader, { className: "p-4 pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
3997
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
3998
+ /* @__PURE__ */ jsx("div", { className: "relative flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: `w-3 h-3 rounded-full ${roleColor} ring-4 ring-slate-50 dark:ring-slate-800/50` }) }),
3999
+ /* @__PURE__ */ jsxs("div", { children: [
4000
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-[15px] font-bold text-slate-900 dark:text-slate-100 leading-tight", children: role.name }),
4001
+ /* @__PURE__ */ jsx(CardDescription, { className: "text-[11px] font-mono text-slate-500 mt-0.5", children: role.code })
4002
+ ] })
4003
+ ] }),
4004
+ role.status === "active" ? /* @__PURE__ */ jsx(
4005
+ Badge,
4006
+ {
4007
+ variant: "outline",
4008
+ className: "bg-emerald-50 text-emerald-600 border-emerald-200 dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20 text-[10px] px-2 py-0 h-5 font-semibold",
4009
+ children: "Ho\u1EA1t \u0111\u1ED9ng"
4010
+ }
4011
+ ) : /* @__PURE__ */ jsx(
4012
+ Badge,
4013
+ {
4014
+ variant: "outline",
4015
+ className: "bg-slate-100 text-slate-500 border-slate-200 dark:bg-slate-800 dark:text-slate-400 dark:border-slate-700 text-[10px] px-2 py-0 h-5 font-semibold",
4016
+ children: "Kh\xF3a"
4017
+ }
4018
+ )
4019
+ ] }) }),
4020
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-4 pt-0 space-y-3", children: [
4021
+ /* @__PURE__ */ jsx("p", { className: "text-[13px] text-slate-500 dark:text-slate-400 line-clamp-2 min-h-[2.5rem] leading-relaxed", children: role.description || "Ch\u01B0a c\xF3 m\xF4 t\u1EA3 chi ti\u1EBFt cho vai tr\xF2 n\xE0y." }),
4022
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between bg-slate-50 dark:bg-slate-800/50 rounded-lg p-2.5 border border-slate-100 dark:border-slate-800", children: [
4023
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center flex-1 border-r border-slate-200 dark:border-slate-700", children: [
4024
+ /* @__PURE__ */ jsx("span", { className: "text-[16px] font-black text-primary leading-none mb-1", children: permissionsCount }),
4025
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-slate-500 font-bold uppercase tracking-wider", children: "Quy\u1EC1n h\u1EA1n" })
4026
+ ] }),
4027
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center flex-1", children: [
4028
+ /* @__PURE__ */ jsx("span", { className: "text-[16px] font-black text-emerald-600 dark:text-emerald-500 leading-none mb-1", children: role.usersCount }),
4029
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-slate-500 font-bold uppercase tracking-wider", children: "Ng\u01B0\u1EDDi d\xF9ng" })
4030
+ ] })
4031
+ ] }),
4032
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-2", children: [
4033
+ canUpdate && /* @__PURE__ */ jsxs(
4034
+ Button,
4035
+ {
4036
+ variant: "outline",
4037
+ size: "sm",
4038
+ className: "flex-1 h-8 text-[12px] font-medium bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800 hover:text-slate-900 dark:hover:text-slate-100 transition-colors rounded-[8px] shadow-sm",
4039
+ onClick: handleEdit,
4040
+ children: [
4041
+ /* @__PURE__ */ jsx(Edit, { className: "mr-1.5 h-3.5 w-3.5 text-slate-400" }),
4042
+ "S\u1EEDa"
4043
+ ]
4044
+ }
4045
+ ),
4046
+ canCreate && /* @__PURE__ */ jsxs(
4047
+ Button,
4048
+ {
4049
+ variant: "outline",
4050
+ size: "sm",
4051
+ className: "flex-1 h-8 text-[12px] font-medium bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800 hover:text-slate-900 dark:hover:text-slate-100 transition-colors rounded-[8px] shadow-sm",
4052
+ onClick: handleDuplicate,
4053
+ children: [
4054
+ /* @__PURE__ */ jsx(Copy, { className: "mr-1.5 h-3.5 w-3.5 text-slate-400" }),
4055
+ "Ch\xE9p"
4056
+ ]
4057
+ }
4058
+ ),
4059
+ canDelete && /* @__PURE__ */ jsxs(
4060
+ Button,
4061
+ {
4062
+ variant: "outline",
4063
+ size: "sm",
4064
+ className: "flex-1 h-8 text-[12px] font-medium border-slate-200 dark:border-slate-800 text-red-600 dark:text-red-500 hover:bg-red-50 dark:hover:bg-red-500/10 hover:text-red-700 dark:hover:text-red-400 transition-colors bg-white dark:bg-slate-900 rounded-[8px] shadow-sm",
4065
+ onClick: handleDelete,
4066
+ children: [
4067
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-3.5 w-3.5" }),
4068
+ "X\xF3a"
4069
+ ]
4070
+ }
4071
+ )
4072
+ ] })
4073
+ ] })
4074
+ ] });
4075
+ });
4076
+ var fetcher = (url) => fetch(url).then((res) => res.json());
4077
+ function useRolesData(initialData) {
4078
+ const [page, setPage] = useState(1);
4079
+ const [pageSize, setPageSize] = useState(20);
4080
+ const [searchTerm, setSearchTerm] = useState("");
4081
+ const [statusFilter, setStatusFilter] = useState("all");
4082
+ const queryParams = useMemo(() => {
4083
+ const params = new URLSearchParams({
4084
+ page: page.toString(),
4085
+ pageSize: pageSize.toString()
4086
+ });
4087
+ if (searchTerm) params.set("search", searchTerm);
4088
+ if (statusFilter !== "all") params.set("status", statusFilter);
4089
+ return params.toString();
4090
+ }, [page, pageSize, searchTerm, statusFilter]);
4091
+ const {
4092
+ data: response,
4093
+ error,
4094
+ isLoading,
4095
+ mutate
4096
+ } = useSWR(`/api/roles?${queryParams}`, fetcher, {
4097
+ fallbackData: initialData,
4098
+ revalidateOnFocus: false,
4099
+ revalidateOnReconnect: false,
4100
+ keepPreviousData: true
4101
+ });
4102
+ const roles = response?.items || [];
4103
+ const totalRows = response?.total || 0;
4104
+ const activeRolesCount = useMemo(
4105
+ () => roles.filter((r) => r.status === "active").length,
4106
+ [roles]
4107
+ );
4108
+ return {
4109
+ roles,
4110
+ totalRows,
4111
+ activeRolesCount,
4112
+ page,
4113
+ pageSize,
4114
+ searchTerm,
4115
+ statusFilter,
4116
+ setPage,
4117
+ setPageSize,
4118
+ setSearchTerm,
4119
+ setStatusFilter,
4120
+ error,
4121
+ isLoading,
4122
+ mutate
4123
+ };
4124
+ }
4125
+
4126
+ // src/rbac/hooks/use-role-operations.ts
4127
+ init_tab_content_cache();
4128
+ init_tab_navigation_provider();
4129
+ function useSafeSession() {
4130
+ try {
4131
+ return useSession();
4132
+ } catch (error) {
4133
+ console.warn("[useSafeSession] Context error caught. Fallback to unauthenticated state.");
4134
+ return { data: null, status: "unauthenticated", update: async () => null };
4135
+ }
4136
+ }
4137
+ function useRoleOperations(mutate) {
4138
+ const router = useRouter();
4139
+ const { update } = useSafeSession();
4140
+ const { clearAllCache } = useTabContentCache();
4141
+ const { clearTabs } = useTabNavigation();
4142
+ const afterRbacChange = useCallback(async () => {
4143
+ try {
4144
+ clearAllCache();
4145
+ clearTabs();
4146
+ if (typeof window !== "undefined") {
4147
+ sessionStorage.removeItem("tab-content-cache");
4148
+ sessionStorage.removeItem("tab-navigation-state");
4149
+ }
4150
+ } catch {
4151
+ }
4152
+ try {
4153
+ await update();
4154
+ } catch {
4155
+ }
4156
+ router.refresh();
4157
+ }, [router, update, clearAllCache, clearTabs]);
4158
+ const handleCreateRole = useCallback(
4159
+ async (roleData) => {
4160
+ try {
4161
+ const res = await fetch("/api/roles", {
4162
+ method: "POST",
4163
+ headers: { "Content-Type": "application/json" },
4164
+ body: JSON.stringify(roleData)
4165
+ });
4166
+ if (!res.ok) {
4167
+ const errorData = await res.json();
4168
+ throw new Error(errorData.error || "Failed to create role");
4169
+ }
4170
+ toast.success("Th\xE0nh c\xF4ng", {
4171
+ description: "\u0110\xE3 t\u1EA1o vai tr\xF2 m\u1EDBi th\xE0nh c\xF4ng"
4172
+ });
4173
+ mutate();
4174
+ await afterRbacChange();
4175
+ return true;
4176
+ } catch (error) {
4177
+ toast.error("L\u1ED7i", {
4178
+ description: error.message
4179
+ });
4180
+ return false;
4181
+ }
4182
+ },
4183
+ [mutate, afterRbacChange]
4184
+ );
4185
+ const handleEditRole = useCallback(
4186
+ async (roleId, roleData) => {
4187
+ try {
4188
+ const res = await fetch(`/api/roles/${roleId}`, {
4189
+ method: "PUT",
4190
+ headers: { "Content-Type": "application/json" },
4191
+ body: JSON.stringify(roleData)
4192
+ });
4193
+ if (!res.ok) {
4194
+ const errorData = await res.json();
4195
+ throw new Error(errorData.error || "Failed to update role");
4196
+ }
4197
+ toast.success("Th\xE0nh c\xF4ng", {
4198
+ description: "\u0110\xE3 c\u1EADp nh\u1EADt vai tr\xF2 th\xE0nh c\xF4ng"
4199
+ });
4200
+ mutate();
4201
+ await afterRbacChange();
4202
+ return true;
4203
+ } catch (error) {
4204
+ toast.error("L\u1ED7i", {
4205
+ description: error.message
4206
+ });
4207
+ return false;
4208
+ }
4209
+ },
4210
+ [mutate, afterRbacChange]
4211
+ );
4212
+ const handleDeleteRole = useCallback(
4213
+ async (roleId) => {
4214
+ try {
4215
+ const res = await fetch(`/api/roles/${roleId}`, {
4216
+ method: "DELETE"
4217
+ });
4218
+ if (!res.ok) {
4219
+ const errorData = await res.json();
4220
+ throw new Error(errorData.error || "Failed to delete role");
4221
+ }
4222
+ toast.success("Th\xE0nh c\xF4ng", {
4223
+ description: "\u0110\xE3 x\xF3a vai tr\xF2 th\xE0nh c\xF4ng"
4224
+ });
4225
+ mutate();
4226
+ await afterRbacChange();
4227
+ return true;
4228
+ } catch (error) {
4229
+ toast.error("L\u1ED7i", {
4230
+ description: error.message
4231
+ });
4232
+ return false;
4233
+ }
4234
+ },
4235
+ [mutate, afterRbacChange]
4236
+ );
4237
+ const handleDuplicateRole = useCallback(
4238
+ async (role) => {
4239
+ const duplicatedRoleData = {
4240
+ name: `${role.name} (Copy)`,
4241
+ code: `${role.code}_copy_${Date.now()}`,
4242
+ description: role.description,
4243
+ status: role.status,
4244
+ permissions: role.permissions
4245
+ };
4246
+ return handleCreateRole(duplicatedRoleData);
4247
+ },
4248
+ [handleCreateRole]
4249
+ );
4250
+ return {
4251
+ handleCreateRole,
4252
+ handleEditRole,
4253
+ handleDeleteRole,
4254
+ handleDuplicateRole
4255
+ };
4256
+ }
4257
+
4258
+ // src/rbac/lib/permission-helpers.ts
4259
+ function getPermissionDescription(permission) {
4260
+ const descriptions = {
4261
+ "dashboard:view": "Xem b\u1EA3ng \u0111i\u1EC1u khi\u1EC3n",
4262
+ "users:view": "Xem danh s\xE1ch ng\u01B0\u1EDDi d\xF9ng",
4263
+ "users:create": "T\u1EA1o ng\u01B0\u1EDDi d\xF9ng m\u1EDBi",
4264
+ "users:update": "C\u1EADp nh\u1EADt th\xF4ng tin ng\u01B0\u1EDDi d\xF9ng",
4265
+ "users:delete": "X\xF3a ng\u01B0\u1EDDi d\xF9ng",
4266
+ "roles:view": "Xem danh s\xE1ch vai tr\xF2",
4267
+ "roles:create": "T\u1EA1o vai tr\xF2 m\u1EDBi",
4268
+ "roles:update": "C\u1EADp nh\u1EADt vai tr\xF2",
4269
+ "roles:delete": "X\xF3a vai tr\xF2",
4270
+ "reports:view": "Xem b\xE1o c\xE1o",
4271
+ "reconciliation:view": "Xem \u0111\u1ED1i so\xE1t",
4272
+ "reconciliation:manage": "Qu\u1EA3n l\xFD \u0111\u1ED1i so\xE1t",
4273
+ "payment:approve": "Duy\u1EC7t thanh to\xE1n",
4274
+ "supplier-pricing:view": "Xem gi\xE1 nh\xE0 cung c\u1EA5p",
4275
+ "supplier-pricing:approve": "Duy\u1EC7t gi\xE1 nh\xE0 cung c\u1EA5p",
4276
+ "purchase-request:view": "Xem y\xEAu c\u1EA7u mua h\xE0ng",
4277
+ "purchase-request:create": "T\u1EA1o y\xEAu c\u1EA7u mua h\xE0ng",
4278
+ "purchase-request:update": "C\u1EADp nh\u1EADt y\xEAu c\u1EA7u mua h\xE0ng",
4279
+ "purchase-request:approve": "Duy\u1EC7t y\xEAu c\u1EA7u mua h\xE0ng",
4280
+ "purchase-order:view": "Xem \u0111\u01A1n h\xE0ng mua",
4281
+ "purchase-order:create": "T\u1EA1o \u0111\u01A1n h\xE0ng mua",
4282
+ "purchase-order:update": "C\u1EADp nh\u1EADt \u0111\u01A1n h\xE0ng mua",
4283
+ "purchase-order:approve": "Duy\u1EC7t \u0111\u01A1n h\xE0ng mua",
4284
+ "supplier:view": "Xem nh\xE0 cung c\u1EA5p",
4285
+ "supplier-pricing:update": "C\u1EADp nh\u1EADt gi\xE1 nh\xE0 cung c\u1EA5p",
4286
+ "material:view": "Xem nguy\xEAn v\u1EADt li\u1EC7u",
4287
+ "material-category:view": "Xem nh\xF3m nguy\xEAn v\u1EADt li\u1EC7u",
4288
+ "warehouse:view": "Xem kho",
4289
+ "goods-receipt:view": "Xem phi\u1EBFu nh\u1EADp kho",
4290
+ "goods-receipt:create": "T\u1EA1o phi\u1EBFu nh\u1EADp kho",
4291
+ "goods-receipt:update": "C\u1EADp nh\u1EADt phi\u1EBFu nh\u1EADp kho"
4292
+ };
4293
+ return descriptions[permission] || `Quy\u1EC1n ${permission}`;
4294
+ }
4295
+ function getUsersWithPermission(permission, roles) {
4296
+ const usersWithPermission = [];
4297
+ roles.forEach((role) => {
4298
+ if (role.permissions.includes(permission)) {
4299
+ usersWithPermission.push(...role.users);
4300
+ }
4301
+ });
4302
+ return Array.from(
4303
+ new Map(usersWithPermission.map((u) => [u.id, u])).values()
4304
+ );
4305
+ }
4306
+ function RoleListPage({
4307
+ dictionary,
4308
+ permissions,
4309
+ lang,
4310
+ initialData,
4311
+ resources,
4312
+ actions
4313
+ }) {
4314
+ const canCreate = permissions.create;
4315
+ const canUpdate = permissions.update;
4316
+ const canDelete = permissions.delete;
4317
+ const canImport = permissions.import;
4318
+ const canExport = permissions.export;
4319
+ const {
4320
+ roles,
4321
+ totalRows,
4322
+ activeRolesCount,
4323
+ searchTerm,
4324
+ statusFilter,
4325
+ setSearchTerm,
4326
+ setStatusFilter,
4327
+ error,
4328
+ isLoading,
4329
+ mutate
4330
+ } = useRolesData(initialData);
4331
+ const {
4332
+ handleDeleteRole,
4333
+ handleDuplicateRole
4334
+ } = useRoleOperations(mutate);
4335
+ const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
4336
+ const [roleToDelete, setRoleToDelete] = useState(null);
4337
+ const [isPermissionDetailOpen, setIsPermissionDetailOpen] = useState(false);
4338
+ const [selectedPermission, setSelectedPermission] = useState(
4339
+ null
4340
+ );
4341
+ const permissionMatrix = useMemo(() => {
4342
+ return resources.map((resource) => {
4343
+ let allowedActions = [];
4344
+ const defaultActions = actions.filter((a) => a.isDefault).map((a) => a.code);
4345
+ const effectiveDefaultActions = defaultActions.length > 0 ? defaultActions : ["view", "create", "update", "delete"];
4346
+ if (resource.config) {
4347
+ try {
4348
+ const config = typeof resource.config === "string" ? JSON.parse(resource.config) : resource.config;
4349
+ if (config.actions && Array.isArray(config.actions)) {
4350
+ const allowedCodes = config.actions;
4351
+ allowedActions = actions.map((a) => a.code).filter((code) => allowedCodes.includes(code));
4352
+ } else {
4353
+ allowedActions = actions.map((a) => a.code).filter((code) => effectiveDefaultActions.includes(code));
4354
+ }
4355
+ } catch (e) {
4356
+ console.warn("Failed to parse resource config", e);
4357
+ allowedActions = actions.map((a) => a.code).filter((code) => effectiveDefaultActions.includes(code));
4358
+ }
4359
+ } else {
4360
+ allowedActions = actions.map((a) => a.code).filter((code) => effectiveDefaultActions.includes(code));
4361
+ }
4362
+ return {
4363
+ resource: resource.code,
4364
+ name: resource.name,
4365
+ icon: resource.icon || "\u{1F4C4}",
4366
+ actions: allowedActions
4367
+ };
4368
+ });
4369
+ }, [resources, actions]);
4370
+ const totalPermissions = useMemo(
4371
+ () => permissionMatrix.flatMap((r) => r.actions).length,
4372
+ [permissionMatrix]
4373
+ );
4374
+ const totalUsers = useMemo(
4375
+ () => roles.reduce((sum, role) => sum + role.usersCount, 0),
4376
+ [roles]
4377
+ );
4378
+ const openDeleteDialog = useCallback((role) => {
4379
+ setRoleToDelete(role);
4380
+ setIsDeleteDialogOpen(true);
4381
+ }, []);
4382
+ const handleDelete = useCallback(async () => {
4383
+ if (!roleToDelete) return;
4384
+ const success = await handleDeleteRole(roleToDelete.id);
4385
+ if (success) {
4386
+ setIsDeleteDialogOpen(false);
4387
+ setRoleToDelete(null);
4388
+ }
4389
+ }, [roleToDelete, handleDeleteRole]);
4390
+ const getUsersForPermission = useCallback(
4391
+ (permission) => {
4392
+ return getUsersWithPermission(permission, roles);
4393
+ },
4394
+ [roles]
4395
+ );
4396
+ if (isLoading) {
4397
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-96", children: /* @__PURE__ */ jsx(Loader2, { className: "h-8 w-8 animate-spin text-muted-foreground" }) });
4398
+ }
4399
+ if (error) {
4400
+ return /* @__PURE__ */ jsxs("div", { className: "text-red-500", children: [
4401
+ "Kh\xF4ng th\u1EC3 t\u1EA3i d\u1EEF li\u1EC7u: ",
4402
+ error.message
4403
+ ] });
4404
+ }
4405
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4406
+ /* @__PURE__ */ jsx(
4407
+ RoleStatsCards,
4408
+ {
4409
+ totalRoles: totalRows,
4410
+ activeRoles: activeRolesCount,
4411
+ totalPermissions,
4412
+ totalUsers
4413
+ }
4414
+ ),
4415
+ /* @__PURE__ */ jsx(
4416
+ RoleToolbar,
4417
+ {
4418
+ dictionary,
4419
+ totalRows,
4420
+ searchTerm,
4421
+ statusFilter,
4422
+ onSearchChange: setSearchTerm,
4423
+ onStatusFilterChange: setStatusFilter,
4424
+ lang,
4425
+ canCreate,
4426
+ canImport,
4427
+ canExport
4428
+ }
4429
+ ),
4430
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: [
4431
+ roles.length === 0 && !isLoading ? /* @__PURE__ */ jsx("div", { className: "col-span-full text-center py-8", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: roles.length === 0 ? "Kh\xF4ng c\xF3 d\u1EEF li\u1EC7u roles" : "Kh\xF4ng t\xECm th\u1EA5y roles ph\xF9 h\u1EE3p v\u1EDBi b\u1ED9 l\u1ECDc" }) }) : null,
4432
+ roles.map((role) => /* @__PURE__ */ jsx(
4433
+ RoleCard,
4434
+ {
4435
+ role,
4436
+ lang,
4437
+ canUpdate,
4438
+ canCreate,
4439
+ canDelete,
4440
+ onDuplicate: handleDuplicateRole,
4441
+ onDelete: openDeleteDialog
4442
+ },
4443
+ role.id
4444
+ ))
4445
+ ] }),
4446
+ /* @__PURE__ */ jsx(
4447
+ AlertDialog,
4448
+ {
4449
+ open: isDeleteDialogOpen,
4450
+ onOpenChange: setIsDeleteDialogOpen,
4451
+ children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
4452
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
4453
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: "X\xE1c nh\u1EADn x\xF3a vai tr\xF2" }),
4454
+ /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [
4455
+ 'B\u1EA1n c\xF3 ch\u1EAFc ch\u1EAFn mu\u1ED1n x\xF3a vai tr\xF2 "',
4456
+ roleToDelete?.name,
4457
+ '"? H\xE0nh \u0111\u1ED9ng n\xE0y kh\xF4ng th\u1EC3 ho\xE0n t\xE1c.'
4458
+ ] })
4459
+ ] }),
4460
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
4461
+ /* @__PURE__ */ jsx(AlertDialogCancel, { onClick: () => setRoleToDelete(null), children: "H\u1EE7y" }),
4462
+ /* @__PURE__ */ jsx(AlertDialogAction, { onClick: handleDelete, children: "X\xF3a" })
4463
+ ] })
4464
+ ] })
4465
+ }
4466
+ ),
4467
+ /* @__PURE__ */ jsx(
4468
+ Dialog,
4469
+ {
4470
+ open: isPermissionDetailOpen,
4471
+ onOpenChange: setIsPermissionDetailOpen,
4472
+ children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-2xl", children: [
4473
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
4474
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center space-x-2", children: [
4475
+ /* @__PURE__ */ jsx(KeyRound, { className: "h-5 w-5" }),
4476
+ /* @__PURE__ */ jsx("span", { children: "Chi ti\u1EBFt Quy\u1EC1n h\u1EA1n" })
4477
+ ] }),
4478
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Xem danh s\xE1ch ng\u01B0\u1EDDi d\xF9ng \u0111\u01B0\u1EE3c g\xE1n quy\u1EC1n h\u1EA1n n\xE0y" })
4479
+ ] }),
4480
+ selectedPermission && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4481
+ /* @__PURE__ */ jsxs("div", { className: "p-4 bg-muted/50 rounded-lg", children: [
4482
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 mb-2", children: [
4483
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-sm", children: selectedPermission.split(":")[0] }),
4484
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: ":" }),
4485
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-sm", children: selectedPermission.split(":")[1] })
4486
+ ] }),
4487
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: getPermissionDescription(selectedPermission) })
4488
+ ] }),
4489
+ /* @__PURE__ */ jsxs("div", { children: [
4490
+ /* @__PURE__ */ jsxs("h4", { className: "font-medium mb-3", children: [
4491
+ "Ng\u01B0\u1EDDi d\xF9ng c\xF3 quy\u1EC1n n\xE0y (",
4492
+ getUsersForPermission(selectedPermission).length,
4493
+ ")"
4494
+ ] }),
4495
+ /* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-60 overflow-y-auto", children: getUsersForPermission(selectedPermission).length > 0 ? getUsersForPermission(selectedPermission).map((user) => /* @__PURE__ */ jsxs(
4496
+ "div",
4497
+ {
4498
+ className: "flex items-center space-x-3 p-3 bg-muted/30 rounded-lg",
4499
+ children: [
4500
+ /* @__PURE__ */ jsxs(Avatar, { className: "h-10 w-10", children: [
4501
+ /* @__PURE__ */ jsx(
4502
+ AvatarImage,
4503
+ {
4504
+ src: user.image || void 0,
4505
+ alt: user.name || ""
4506
+ }
4507
+ ),
4508
+ /* @__PURE__ */ jsx(AvatarFallback, { children: (user.name || "U").split(" ").map((n) => n[0]).join("") })
4509
+ ] }),
4510
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
4511
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: user.name }),
4512
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: user.jobTitle || "N/A" }),
4513
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: user.email })
4514
+ ] }),
4515
+ /* @__PURE__ */ jsx("div", { className: "flex items-center space-x-2", children: user.isActive ? /* @__PURE__ */ jsxs(Badge, { variant: "default", className: "text-xs", children: [
4516
+ /* @__PURE__ */ jsx(UserCheck, { className: "h-3 w-3 mr-1" }),
4517
+ "Active"
4518
+ ] }) : /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "text-xs", children: [
4519
+ /* @__PURE__ */ jsx(UserX, { className: "h-3 w-3 mr-1" }),
4520
+ "Inactive"
4521
+ ] }) })
4522
+ ]
4523
+ },
4524
+ user.id
4525
+ )) : /* @__PURE__ */ jsxs("div", { className: "text-center p-6 text-muted-foreground", children: [
4526
+ /* @__PURE__ */ jsx(UserX, { className: "h-12 w-12 mx-auto mb-3 opacity-50" }),
4527
+ /* @__PURE__ */ jsx("p", { children: "Kh\xF4ng c\xF3 ng\u01B0\u1EDDi d\xF9ng n\xE0o c\xF3 quy\u1EC1n n\xE0y" })
4528
+ ] }) })
4529
+ ] })
4530
+ ] }),
4531
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { onClick: () => setIsPermissionDetailOpen(false), children: "\u0110\xF3ng" }) })
4532
+ ] })
4533
+ }
4534
+ )
4535
+ ] });
4536
+ }
4537
+
4538
+ // src/rbac/index.ts
4539
+ var CRUD_ACTIONS = {
4540
+ create: "create",
4541
+ view: "view",
4542
+ update: "update",
4543
+ delete: "delete",
4544
+ export: "export",
4545
+ import: "import",
4546
+ approve: "approve",
4547
+ reject: "reject"
4548
+ };
4549
+ function getActionCode(operation) {
4550
+ return CRUD_ACTIONS[operation];
4551
+ }
4552
+ function getAllCrudActionCodes() {
4553
+ return Object.values(CRUD_ACTIONS);
4554
+ }
4555
+ function isCrudAction(actionCode) {
4556
+ return Object.values(CRUD_ACTIONS).includes(actionCode);
4557
+ }
4558
+ var DEFAULT_PERMISSIONS_CACHE_TTL_SECONDS = 5 * 60;
4559
+ var PERMISSIONS_TTL_SECONDS = (() => {
4560
+ const ttlEnv = process.env.PERMISSIONS_CACHE_TTL_MS;
4561
+ if (!ttlEnv) {
4562
+ return DEFAULT_PERMISSIONS_CACHE_TTL_SECONDS;
4563
+ }
4564
+ const parsedTtlMs = Number.parseInt(ttlEnv, 10);
4565
+ if (Number.isNaN(parsedTtlMs) || parsedTtlMs <= 0) {
4566
+ logger.warn(
4567
+ `Invalid PERMISSIONS_CACHE_TTL_MS="${ttlEnv}". Falling back to default ${DEFAULT_PERMISSIONS_CACHE_TTL_SECONDS}s`
4568
+ );
4569
+ return DEFAULT_PERMISSIONS_CACHE_TTL_SECONDS;
4570
+ }
4571
+ return Math.floor(parsedTtlMs / 1e3);
4572
+ })();
4573
+ var permissionCache = cacheManager.create({
4574
+ name: "rbac-permissions",
4575
+ ttl: PERMISSIONS_TTL_SECONDS,
4576
+ max: 1e4
4577
+ });
4578
+ async function getFromCache(userId) {
4579
+ return permissionCache.get(userId);
4580
+ }
4581
+ async function setToCache(userId, data) {
4582
+ await permissionCache.set(userId, data);
4583
+ }
4584
+ var pendingQueries = /* @__PURE__ */ new Map();
4585
+ async function clearAllPermissionsCache() {
4586
+ await permissionCache.reset();
4587
+ pendingQueries.clear();
4588
+ }
4589
+ async function clearUserPermissionsCache(userId) {
4590
+ await permissionCache.del(userId);
4591
+ pendingQueries.delete(userId);
4592
+ }
4593
+ async function invalidateUserPermissions(userId) {
4594
+ await permissionCache.del(userId);
4595
+ pendingQueries.delete(userId);
4596
+ }
4597
+ function getUserPermissions(session) {
4598
+ if (!session?.user) return [];
4599
+ const user = session.user;
4600
+ if (!user.permissions) {
4601
+ return [];
4602
+ }
4603
+ return user.permissions;
4604
+ }
4605
+ var BYPASS_AUTH = process.env.BYPASS_AUTH === "true" || process.env.BYPASS_AUTH === "1";
4606
+ var ADMIN_ROLE_CODES = ["admin", "SUPER_ADMIN"];
4607
+ function getCrudPermissionsFromSession(session, entity) {
4608
+ if (BYPASS_AUTH) {
4609
+ return {
4610
+ create: true,
4611
+ view: true,
4612
+ update: true,
4613
+ delete: true,
4614
+ export: true,
4615
+ import: true,
4616
+ approve: true,
4617
+ reject: true
4618
+ };
4619
+ }
4620
+ if (!session?.user) {
4621
+ return {
4622
+ create: false,
4623
+ view: false,
4624
+ update: false,
4625
+ delete: false,
4626
+ export: false,
4627
+ import: false,
4628
+ approve: false,
4629
+ reject: false
4630
+ };
4631
+ }
4632
+ const user = session.user;
4633
+ if (!user.id) {
4634
+ return {
4635
+ create: false,
4636
+ view: false,
4637
+ update: false,
4638
+ delete: false,
4639
+ export: false,
4640
+ import: false,
4641
+ approve: false,
4642
+ reject: false
4643
+ };
4644
+ }
4645
+ const isAdmin = user.roles?.some((role) => ADMIN_ROLE_CODES.includes(role));
4646
+ if (isAdmin) {
4647
+ return {
4648
+ create: true,
4649
+ view: true,
4650
+ update: true,
4651
+ delete: true,
4652
+ export: true,
4653
+ import: true,
4654
+ approve: true,
4655
+ reject: true
4656
+ };
4657
+ }
4658
+ const permissions = user.permissions || [];
4659
+ const permissionKeys = new Set(
4660
+ permissions.map((p) => `${p.resourceCode}:${p.actionCode}`)
4661
+ );
4662
+ const hasPermission2 = (action) => {
4663
+ const key = `${entity}:${action}`;
4664
+ return permissionKeys.has(key);
4665
+ };
4666
+ return {
4667
+ create: hasPermission2(getActionCode("create")),
4668
+ view: hasPermission2(getActionCode("view")),
4669
+ update: hasPermission2(getActionCode("update")),
4670
+ delete: hasPermission2(getActionCode("delete")),
4671
+ export: hasPermission2(getActionCode("export")),
4672
+ import: hasPermission2(getActionCode("import")),
4673
+ approve: hasPermission2(getActionCode("approve")),
4674
+ reject: hasPermission2(getActionCode("reject"))
4675
+ };
4676
+ }
4677
+ function checkPermission(session, resourceCode, actionCode) {
4678
+ if (BYPASS_AUTH) {
4679
+ return true;
4680
+ }
4681
+ if (!session?.user) return false;
4682
+ const user = session.user;
4683
+ if (!user.permissions || user.permissions.length === 0) {
4684
+ return false;
4685
+ }
4686
+ if (user.roles?.some((role) => ADMIN_ROLE_CODES.includes(role))) {
4687
+ return true;
4688
+ }
4689
+ return user.permissions.some(
4690
+ (p) => p.resourceCode === resourceCode && p.actionCode === actionCode
4691
+ );
4692
+ }
4693
+ function hasPermission(session, resourceCode, actionCode) {
4694
+ return checkPermission(session, resourceCode, actionCode);
4695
+ }
4696
+ function requirePermission(session, resourceCode, actionCode) {
4697
+ if (!checkPermission(session, resourceCode, actionCode)) {
4698
+ throw new Error(
4699
+ `Unauthorized: User does not have permission ${actionCode} on ${resourceCode}`
4700
+ );
4701
+ }
4702
+ }
4703
+ function hasRole(session, roleCode) {
4704
+ if (!session?.user) return false;
4705
+ const user = session.user;
4706
+ if (!user.roles) {
4707
+ return false;
4708
+ }
4709
+ return user.roles.includes(roleCode);
4710
+ }
4711
+ function hasAnyRole(session, roleCodes) {
4712
+ if (!session?.user) return false;
4713
+ const user = session.user;
4714
+ if (!user.roles) {
4715
+ return false;
4716
+ }
4717
+ return roleCodes.some((role) => user.roles.includes(role));
4718
+ }
4719
+
4720
+ export { CRUD_ACTIONS, RoleListPage, checkPermission, clearAllPermissionsCache, clearResourceCache, clearUserPermissionsCache, getActionCode, getActionsForPermissionMatrix, getAllCrudActionCodes, getCachedUserPermissions, getCrudPermissionsFromSession, getFromCache, getPermissionResourceCode, getResourcesData, getResourcesForPermissionMatrix, getRolesData, getUserPermissions, getUserPermissionsFromDB, hasAnyRole, hasPermission, hasRole, invalidateUserPermissions, isCrudAction, isValidResourceCode, pendingQueries, preloadResourceCodes, requirePermission, setToCache, validatePermissionResource };
4721
+ //# sourceMappingURL=index.mjs.map
4722
+ //# sourceMappingURL=index.mjs.map