History

feat: shadcn/ui monorepo setup with all components

- packages/ui (@executor/ui): shared UI package with shadcn components - 56 components installed (button, card, dialog, sidebar, etc.) - lib/utils.ts with cn() helper - globals.css with light/dark theme (oklch colors, auto detection) - DM Sans + Instrument Serif + JetBrains Mono fonts - components.json in both packages/ui and apps/web for CLI support - Tailwind v4 with @source directives for cross-package class scanning - Fixed source namespace detection (use last tag, filter by 'openapi' presence) - apps/web imports globals.css from @executor/ui/globals.css

Rhys Sullivan committed 7 months ago

Commit e2587321 parent cb0197f69 files · +7139 −9Browse files

Unified · Split

69 files
  1. apps/web/components.json +20 −0
  2. apps/web/package.json +1 −0
  3. apps/web/src/main.tsx +1 −1
  4. apps/web/src/pages/sources.tsx +4 −4
  5. apps/web/src/shell.tsx +3 −2
  6. bun.lock +306 −0
  7. package.json +1 −0
  8. packages/ui/components.json +20 −0
  9. packages/ui/package.json +42 −0
  10. packages/ui/src/components/accordion.tsx +64 −0
  11. packages/ui/src/components/alert-dialog.tsx +196 −0
  12. packages/ui/src/components/alert.tsx +66 −0
  13. packages/ui/src/components/aspect-ratio.tsx +11 −0
  14. packages/ui/src/components/avatar.tsx +107 −0
  15. packages/ui/src/components/badge.tsx +48 −0
  16. packages/ui/src/components/breadcrumb.tsx +109 −0
  17. packages/ui/src/components/button-group.tsx +83 −0
  18. packages/ui/src/components/button.tsx +64 −0
  19. packages/ui/src/components/calendar.tsx +218 −0
  20. packages/ui/src/components/card.tsx +92 −0
  21. packages/ui/src/components/carousel.tsx +241 −0
  22. packages/ui/src/components/chart.tsx +372 −0
  23. packages/ui/src/components/checkbox.tsx +32 −0
  24. packages/ui/src/components/collapsible.tsx +31 −0
  25. packages/ui/src/components/combobox.tsx +310 −0
  26. packages/ui/src/components/command.tsx +184 −0
  27. packages/ui/src/components/context-menu.tsx +252 −0
  28. packages/ui/src/components/dialog.tsx +156 −0
  29. packages/ui/src/components/direction.tsx +22 −0
  30. packages/ui/src/components/drawer.tsx +133 −0
  31. packages/ui/src/components/dropdown-menu.tsx +257 −0
  32. packages/ui/src/components/empty.tsx +104 −0
  33. packages/ui/src/components/field.tsx +248 −0
  34. packages/ui/src/components/form.tsx +165 −0
  35. packages/ui/src/components/hover-card.tsx +42 −0
  36. packages/ui/src/components/input-group.tsx +168 −0
  37. packages/ui/src/components/input-otp.tsx +77 −0
  38. packages/ui/src/components/input.tsx +21 −0
  39. packages/ui/src/components/item.tsx +193 −0
  40. packages/ui/src/components/kbd.tsx +28 −0
  41. packages/ui/src/components/label.tsx +22 −0
  42. packages/ui/src/components/menubar.tsx +276 −0
  43. packages/ui/src/components/native-select.tsx +53 −0
  44. packages/ui/src/components/navigation-menu.tsx +168 −0
  45. packages/ui/src/components/pagination.tsx +127 −0
  46. packages/ui/src/components/popover.tsx +87 −0
  47. packages/ui/src/components/progress.tsx +31 −0
  48. packages/ui/src/components/radio-group.tsx +43 −0
  49. packages/ui/src/components/resizable.tsx +53 −0
  50. packages/ui/src/components/scroll-area.tsx +56 −0
  51. packages/ui/src/components/select.tsx +190 −0
  52. packages/ui/src/components/separator.tsx +26 −0
  53. packages/ui/src/components/sheet.tsx +143 −0
  54. packages/ui/src/components/sidebar.tsx +724 −0
  55. packages/ui/src/components/skeleton.tsx +13 −0
  56. packages/ui/src/components/slider.tsx +61 −0
  57. packages/ui/src/components/sonner.tsx +40 −0
  58. packages/ui/src/components/spinner.tsx +16 −0
  59. packages/ui/src/components/switch.tsx +33 −0
  60. packages/ui/src/components/table.tsx +116 −0
  61. packages/ui/src/components/tabs.tsx +89 −0
  62. packages/ui/src/components/textarea.tsx +18 −0
  63. packages/ui/src/components/toggle-group.tsx +83 −0
  64. packages/ui/src/components/toggle.tsx +47 −0
  65. packages/ui/src/components/tooltip.tsx +55 −0
  66. packages/ui/src/hooks/use-mobile.ts +19 −0
  67. packages/ui/src/lib/utils.ts +6 −0
  68. packages/ui/src/styles/globals.css +27 −2
  69. packages/ui/tsconfig.json +25 −0
apps/web/components.json+20−0
@@ -0,0 +1,20 @@
1{
2 "$schema": "https://ui.shadcn.com/schema.json",
3 "style": "new-york",
4 "rsc": false,
5 "tsx": true,
6 "tailwind": {
7 "config": "",
8 "css": "../../packages/ui/src/styles/globals.css",
9 "baseColor": "neutral",
10 "cssVariables": true
11 },
12 "iconLibrary": "lucide",
13 "aliases": {
14 "components": "@/components",
15 "hooks": "@/hooks",
16 "lib": "@/lib",
17 "utils": "@executor/ui/lib/utils",
18 "ui": "@executor/ui/components"
19 }
20}
apps/web/package.json+1−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
5 "type": "module",5 "type": "module",
6 "dependencies": {6 "dependencies": {
7 "@executor/plugin-openapi": "workspace:*",7 "@executor/plugin-openapi": "workspace:*",
8 "@executor/ui": "workspace:*",
8 "tailwindcss": "^4.1.10",9 "tailwindcss": "^4.1.10",
9 "@executor/react": "workspace:*",10 "@executor/react": "workspace:*",
10 "@executor/server": "workspace:*",11 "@executor/server": "workspace:*",
apps/web/src/main.tsx+1−1
@@ -1,6 +1,6 @@
1import React from "react";1import React from "react";
2import { createRoot } from "react-dom/client";2import { createRoot } from "react-dom/client";
3import "./styles.css";3import "@executor/ui/globals.css";
4import { App } from "./App";4import { App } from "./App";
5 5
6const root = createRoot(document.getElementById("root")!);6const root = createRoot(document.getElementById("root")!);
apps/web/src/pages/sources.tsx+4−4
@@ -22,10 +22,10 @@ export function SourcesPage() { · 21 unmodified lines
22 if (tools._tag !== "Success") return [];22 if (tools._tag !== "Success") return [];
23 const namespaces = new Map<string, number>();23 const namespaces = new Map<string, number>();
24 for (const tool of tools.value) {24 for (const tool of tools.value) {
25 const ns = tool.tags.find(25 if (!tool.tags.includes("openapi")) continue;
26 (t) => t !== "openapi" && !sourcePlugins.some((p) => p.key === t),26 // Namespace is the last tag (after op tags and "openapi")
27 );27 const ns = tool.tags[tool.tags.length - 1];
28 if (ns) {28 if (ns && ns !== "openapi") {
29 namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1);29 namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1);
30 }30 }
31 }31 }
apps/web/src/shell.tsx+3−2
@@ -34,8 +34,9 @@ function SourceList() { · 33 unmodified lines
34 if (tools._tag !== "Success") return [];34 if (tools._tag !== "Success") return [];
35 const namespaces = new Map<string, number>();35 const namespaces = new Map<string, number>();
36 for (const tool of tools.value) {36 for (const tool of tools.value) {
37 const ns = tool.tags.find((t) => t !== "openapi");37 if (!tool.tags.includes("openapi")) continue;
38 if (ns && ns !== tool.tags[0]) {38 const ns = tool.tags[tool.tags.length - 1];
39 if (ns && ns !== "openapi") {
39 namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1);40 namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1);
40 }41 }
41 }42 }
bun.lock+306−0
@@ -34,6 +34,7 @@ · 33 unmodified lines
34 "@executor/plugin-openapi": "workspace:*",34 "@executor/plugin-openapi": "workspace:*",
35 "@executor/react": "workspace:*",35 "@executor/react": "workspace:*",
36 "@executor/server": "workspace:*",36 "@executor/server": "workspace:*",
37 "@executor/ui": "workspace:*",
37 "@tanstack/react-router": "^1.168.10",38 "@tanstack/react-router": "^1.168.10",
38 "react": "^19.1.0",39 "react": "^19.1.0",
39 "react-dom": "^19.1.0",40 "react-dom": "^19.1.0",
@@ -190,6 +191,37 @@ · 150 unmodified lines
190 "react",191 "react",
191 ],192 ],
192 },193 },
194 "packages/ui": {
195 "name": "@executor/ui",
196 "version": "0.0.0",
197 "dependencies": {
198 "@base-ui/react": "^1.3.0",
199 "@hookform/resolvers": "^5.2.2",
200 "class-variance-authority": "^0.7.1",
201 "clsx": "^2.1.1",
202 "cmdk": "^1.1.1",
203 "date-fns": "^4.1.0",
204 "embla-carousel-react": "^8.6.0",
205 "input-otp": "^1.4.2",
206 "lucide-react": "^1.7.0",
207 "next-themes": "^0.4.6",
208 "radix-ui": "^1.4.3",
209 "react": "^19.1.0",
210 "react-day-picker": "^9.14.0",
211 "react-hook-form": "^7.72.0",
212 "react-resizable-panels": "^4",
213 "recharts": "3.8.0",
214 "sonner": "^2.0.7",
215 "tailwind-merge": "^3.3.0",
216 "vaul": "^1.1.2",
217 "zod": "^4.3.6",
218 },
219 "devDependencies": {
220 "@types/react": "^19.1.0",
221 "tailwindcss": "^4.1.10",
222 "typescript": "^5.9.3",
223 },
224 },
193 },225 },
194 "catalog": {226 "catalog": {
195 "@effect/cluster": "^0.58.0",227 "@effect/cluster": "^0.58.0",
@@ -243,12 +275,20 @@ · 47 unmodified lines
243 275
244 "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],276 "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
245 277
278 "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="],
279
246 "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],280 "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
247 281
248 "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],282 "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
249 283
250 "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],284 "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
251 285
286 "@base-ui/react": ["@base-ui/react@1.3.0", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@base-ui/utils": "0.2.6", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "tabbable": "^6.4.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA=="],
287
288 "@base-ui/utils": ["@base-ui/utils@0.2.6", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw=="],
289
290 "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="],
291
252 "@effect-atom/atom": ["@effect-atom/atom@0.5.3", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "effect": "^3.19.15" } }, "sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA=="],292 "@effect-atom/atom": ["@effect-atom/atom@0.5.3", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "effect": "^3.19.15" } }, "sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA=="],
253 293
254 "@effect-atom/atom-react": ["@effect-atom/atom-react@0.5.0", "", { "dependencies": { "@effect-atom/atom": "^0.5.0" }, "peerDependencies": { "effect": "^3.19", "react": ">=18 <20", "scheduler": "*" } }, "sha512-aFfjWi4rEJCqfM12Oi36/EKaDm/W6n4/N6yM5vL0t/QozKhJhK05rQL/GY4XMxlH2eqkQ4ih8jBQa3Yyp0Fiqw=="],294 "@effect-atom/atom-react": ["@effect-atom/atom-react@0.5.0", "", { "dependencies": { "@effect-atom/atom": "^0.5.0" }, "peerDependencies": { "effect": "^3.19", "react": ">=18 <20", "scheduler": "*" } }, "sha512-aFfjWi4rEJCqfM12Oi36/EKaDm/W6n4/N6yM5vL0t/QozKhJhK05rQL/GY4XMxlH2eqkQ4ih8jBQa3Yyp0Fiqw=="],
@@ -343,8 +383,20 @@ · 88 unmodified lines
343 383
344 "@executor/server": ["@executor/server@workspace:apps/server"],384 "@executor/server": ["@executor/server@workspace:apps/server"],
345 385
386 "@executor/ui": ["@executor/ui@workspace:packages/ui"],
387
346 "@executor/web": ["@executor/web@workspace:apps/web"],388 "@executor/web": ["@executor/web@workspace:apps/web"],
347 389
390 "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
391
392 "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="],
393
394 "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="],
395
396 "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="],
397
398 "@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="],
399
348 "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="],400 "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="],
349 401
350 "@jitl/quickjs-wasmfile-debug-asyncify": ["@jitl/quickjs-wasmfile-debug-asyncify@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w=="],402 "@jitl/quickjs-wasmfile-debug-asyncify": ["@jitl/quickjs-wasmfile-debug-asyncify@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w=="],
@@ -469,6 +521,128 @@ · 118 unmodified lines
469 521
470 "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],522 "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
471 523
524 "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
525
526 "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
527
528 "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="],
529
530 "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
531
532 "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
533
534 "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
535
536 "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="],
537
538 "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
539
540 "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
541
542 "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
543
544 "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
545
546 "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
547
548 "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
549
550 "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="],
551
552 "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
553
554 "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
555
556 "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
557
558 "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="],
559
560 "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
561
562 "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
563
564 "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="],
565
566 "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="],
567
568 "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
569
570 "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
571
572 "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
573
574 "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="],
575
576 "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="],
577
578 "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="],
579
580 "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="],
581
582 "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="],
583
584 "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
585
586 "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
587
588 "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
589
590 "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
591
592 "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
593
594 "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
595
596 "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
597
598 "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
599
600 "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
601
602 "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
603
604 "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="],
605
606 "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
607
608 "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
609
610 "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
611
612 "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="],
613
614 "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="],
615
616 "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="],
617
618 "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="],
619
620 "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
621
622 "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
623
624 "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
625
626 "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
627
628 "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
629
630 "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="],
631
632 "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
633
634 "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
635
636 "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="],
637
638 "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
639
640 "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
641
642 "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
643
644 "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="],
645
472 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],646 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
473 647
474 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="],648 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="],
@@ -523,6 +697,10 @@ · 48 unmodified lines
523 697
524 "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],698 "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
525 699
700 "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
701
702 "@tabby_ai/hijri-converter": ["@tabby_ai/hijri-converter@1.0.5", "", {}, "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ=="],
703
526 "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="],704 "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="],
527 705
528 "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="],706 "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="],
@@ -585,6 +763,24 @@ · 56 unmodified lines
585 763
586 "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],764 "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
587 765
766 "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
767
768 "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
769
770 "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
771
772 "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
773
774 "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
775
776 "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
777
778 "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="],
779
780 "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
781
782 "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
783
588 "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],784 "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
589 785
590 "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],786 "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -597,6 +793,8 @@ · 6 unmodified lines
597 793
598 "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],794 "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
599 795
796 "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
797
600 "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],798 "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
601 799
602 "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],800 "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
@@ -621,6 +819,8 @@ · 18 unmodified lines
621 819
622 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],820 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
623 821
822 "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
823
624 "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],824 "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
625 825
626 "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="],826 "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="],
@@ -639,32 +839,78 @@ · 12 unmodified lines
639 839
640 "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],840 "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
641 841
842 "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
843
844 "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
845
846 "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="],
847
642 "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],848 "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
643 849
644 "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],850 "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],
645 851
646 "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],852 "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
647 853
854 "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
855
856 "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
857
858 "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
859
860 "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="],
861
862 "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
863
864 "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
865
866 "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
867
868 "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
869
870 "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
871
872 "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
873
874 "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
875
876 "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
877
878 "date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="],
879
648 "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],880 "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
649 881
882 "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
883
650 "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],884 "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
651 885
652 "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],886 "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
653 887
888 "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
889
654 "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="],890 "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="],
655 891
656 "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="],892 "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="],
657 893
894 "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="],
895
896 "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="],
897
898 "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="],
899
658 "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="],900 "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="],
659 901
660 "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],902 "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
661 903
904 "es-toolkit": ["es-toolkit@1.45.1", "", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="],
905
662 "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],906 "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
663 907
664 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],908 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
665 909
666 "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],910 "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
667 911
912 "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
913
668 "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],914 "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
669 915
670 "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],916 "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
@@ -681,8 +927,16 @@ · 10 unmodified lines
681 927
682 "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],928 "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
683 929
930 "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
931
684 "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],932 "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
685 933
934 "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
935
936 "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="],
937
938 "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
939
686 "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],940 "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
687 941
688 "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],942 "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
@@ -731,6 +985,8 @@ · 42 unmodified lines
731 985
732 "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],986 "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
733 987
988 "lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="],
989
734 "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],990 "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
735 991
736 "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],992 "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
@@ -745,6 +1001,8 @@ · 8 unmodified lines
745 1001
746 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],1002 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
747 1003
1004 "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="],
1005
748 "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],1006 "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
749 1007
750 "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],1008 "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
@@ -771,14 +1029,40 @@ · 20 unmodified lines
771 1029
772 "quickjs-emscripten-core": ["quickjs-emscripten-core@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ=="],1030 "quickjs-emscripten-core": ["quickjs-emscripten-core@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ=="],
773 1031
1032 "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
1033
774 "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],1034 "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
775 1035
1036 "react-day-picker": ["react-day-picker@9.14.0", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "@tabby_ai/hijri-converter": "1.0.5", "date-fns": "^4.1.0", "date-fns-jalali": "4.1.0-0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA=="],
1037
776 "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],1038 "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
777 1039
1040 "react-hook-form": ["react-hook-form@7.72.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-V4v6jubaf6JAurEaVnT9aUPKFbNtDgohj5CIgVGyPHvT9wRx5OZHVjz31GsxnPNI278XMu+ruFz+wGOscHaLKw=="],
1041
1042 "react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="],
1043
1044 "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="],
1045
778 "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],1046 "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
779 1047
1048 "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
1049
1050 "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
1051
1052 "react-resizable-panels": ["react-resizable-panels@4.8.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-2uEABkewb3ky/ZgIlAUxWa1W/LjsK494fdV1QsXxst7CDRHCzo7h22tWWu3NNaBjmiuriOCt3CvhipnaYcpoIw=="],
1053
1054 "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
1055
1056 "recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="],
1057
1058 "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
1059
1060 "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
1061
780 "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],1062 "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
781 1063
1064 "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
1065
782 "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],1066 "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
783 1067
784 "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],1068 "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
@@ -791,6 +1075,8 @@ · 6 unmodified lines
791 1075
792 "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],1076 "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
793 1077
1078 "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
1079
794 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],1080 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
795 1081
796 "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],1082 "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
@@ -799,10 +1085,16 @@ · 2 unmodified lines
799 1085
800 "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],1086 "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
801 1087
1088 "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="],
1089
1090 "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
1091
802 "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="],1092 "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="],
803 1093
804 "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],1094 "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
805 1095
1096 "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
1097
806 "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],1098 "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
807 1099
808 "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],1100 "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
@@ -815,6 +1107,8 @@ · 6 unmodified lines
815 1107
816 "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="],1108 "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="],
817 1109
1110 "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
1111
818 "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="],1112 "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="],
819 1113
820 "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],1114 "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
@@ -825,10 +1119,18 @@ · 4 unmodified lines
825 1119
826 "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],1120 "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
827 1121
1122 "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
1123
1124 "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
1125
828 "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],1126 "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
829 1127
830 "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],1128 "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
831 1129
1130 "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="],
1131
1132 "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
1133
832 "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],1134 "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
833 1135
834 "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],1136 "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
@@ -843,10 +1145,14 @@ · 8 unmodified lines
843 1145
844 "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="],1146 "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="],
845 1147
1148 "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
1149
846 "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],1150 "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
847 1151
848 "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="],1152 "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="],
849 1153
1154 "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="],
1155
850 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],1156 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
851 1157
852 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],1158 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
package.json+1−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
5 "packageManager": "bun@1.2.22",5 "packageManager": "bun@1.2.22",
6 "workspaces": [6 "workspaces": [
7 "packages/*/*",7 "packages/*/*",
8 "packages/ui",
8 "apps/*"9 "apps/*"
9 ],10 ],
10 "catalog": {11 "catalog": {
packages/ui/components.json+20−0
@@ -0,0 +1,20 @@
1{
2 "$schema": "https://ui.shadcn.com/schema.json",
3 "style": "new-york",
4 "rsc": false,
5 "tsx": true,
6 "tailwind": {
7 "config": "",
8 "css": "src/styles/globals.css",
9 "baseColor": "neutral",
10 "cssVariables": true
11 },
12 "iconLibrary": "lucide",
13 "aliases": {
14 "components": "@executor/ui/components",
15 "utils": "@executor/ui/lib/utils",
16 "hooks": "@executor/ui/hooks",
17 "lib": "@executor/ui/lib",
18 "ui": "@executor/ui/components"
19 }
20}
packages/ui/package.json+42−0
@@ -0,0 +1,42 @@
1{
2 "name": "@executor/ui",
3 "version": "0.0.0",
4 "private": true,
5 "type": "module",
6 "exports": {
7 "./components/*": "./src/components/*.tsx",
8 "./hooks/*": "./src/hooks/*.ts",
9 "./lib/*": "./src/lib/*.ts",
10 "./globals.css": "./src/styles/globals.css"
11 },
12 "dependencies": {
13 "@base-ui/react": "^1.3.0",
14 "@hookform/resolvers": "^5.2.2",
15 "class-variance-authority": "^0.7.1",
16 "clsx": "^2.1.1",
17 "cmdk": "^1.1.1",
18 "date-fns": "^4.1.0",
19 "embla-carousel-react": "^8.6.0",
20 "input-otp": "^1.4.2",
21 "lucide-react": "^1.7.0",
22 "next-themes": "^0.4.6",
23 "radix-ui": "^1.4.3",
24 "react": "^19.1.0",
25 "react-day-picker": "^9.14.0",
26 "react-hook-form": "^7.72.0",
27 "react-resizable-panels": "^4",
28 "recharts": "3.8.0",
29 "sonner": "^2.0.7",
30 "tailwind-merge": "^3.3.0",
31 "vaul": "^1.1.2",
32 "zod": "^4.3.6"
33 },
34 "devDependencies": {
35 "@types/react": "^19.1.0",
36 "typescript": "^5.9.3",
37 "tailwindcss": "^4.1.10"
38 },
39 "scripts": {
40 "typecheck": "tsc --noEmit"
41 }
42}
packages/ui/src/components/accordion.tsx+64−0
@@ -0,0 +1,64 @@
1import * as React from "react"
2import { ChevronDownIcon } from "lucide-react"
3import { Accordion as AccordionPrimitive } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7function Accordion({
8 ...props
9}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
10 return <AccordionPrimitive.Root data-slot="accordion" {...props} />
11}
12
13function AccordionItem({
14 className,
15 ...props
16}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
17 return (
18 <AccordionPrimitive.Item
19 data-slot="accordion-item"
20 className={cn("border-b last:border-b-0", className)}
21 {...props}
22 />
23 )
24}
25
26function AccordionTrigger({
27 className,
28 children,
29 ...props
30}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
31 return (
32 <AccordionPrimitive.Header className="flex">
33 <AccordionPrimitive.Trigger
34 data-slot="accordion-trigger"
35 className={cn(
36 "flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
37 className
38 )}
39 {...props}
40 >
41 {children}
42 <ChevronDownIcon className="pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" />
43 </AccordionPrimitive.Trigger>
44 </AccordionPrimitive.Header>
45 )
46}
47
48function AccordionContent({
49 className,
50 children,
51 ...props
52}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
53 return (
54 <AccordionPrimitive.Content
55 data-slot="accordion-content"
56 className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
57 {...props}
58 >
59 <div className={cn("pt-0 pb-4", className)}>{children}</div>
60 </AccordionPrimitive.Content>
61 )
62}
63
64export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
packages/ui/src/components/alert-dialog.tsx+196−0
@@ -0,0 +1,196 @@
1"use client"
2
3import * as React from "react"
4import { AlertDialog as AlertDialogPrimitive } from "radix-ui"
5
6import { cn } from "@executor/ui/lib/utils"
7import { Button } from "@executor/ui/components/button"
8
9function AlertDialog({
10 ...props
11}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
12 return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
13}
14
15function AlertDialogTrigger({
16 ...props
17}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
18 return (
19 <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
20 )
21}
22
23function AlertDialogPortal({
24 ...props
25}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
26 return (
27 <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
28 )
29}
30
31function AlertDialogOverlay({
32 className,
33 ...props
34}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
35 return (
36 <AlertDialogPrimitive.Overlay
37 data-slot="alert-dialog-overlay"
38 className={cn(
39 "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
40 className
41 )}
42 {...props}
43 />
44 )
45}
46
47function AlertDialogContent({
48 className,
49 size = "default",
50 ...props
51}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
52 size?: "default" | "sm"
53}) {
54 return (
55 <AlertDialogPortal>
56 <AlertDialogOverlay />
57 <AlertDialogPrimitive.Content
58 data-slot="alert-dialog-content"
59 data-size={size}
60 className={cn(
61 "group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg",
62 className
63 )}
64 {...props}
65 />
66 </AlertDialogPortal>
67 )
68}
69
70function AlertDialogHeader({
71 className,
72 ...props
73}: React.ComponentProps<"div">) {
74 return (
75 <div
76 data-slot="alert-dialog-header"
77 className={cn(
78 "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
79 className
80 )}
81 {...props}
82 />
83 )
84}
85
86function AlertDialogFooter({
87 className,
88 ...props
89}: React.ComponentProps<"div">) {
90 return (
91 <div
92 data-slot="alert-dialog-footer"
93 className={cn(
94 "flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
95 className
96 )}
97 {...props}
98 />
99 )
100}
101
102function AlertDialogTitle({
103 className,
104 ...props
105}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
106 return (
107 <AlertDialogPrimitive.Title
108 data-slot="alert-dialog-title"
109 className={cn(
110 "text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
111 className
112 )}
113 {...props}
114 />
115 )
116}
117
118function AlertDialogDescription({
119 className,
120 ...props
121}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
122 return (
123 <AlertDialogPrimitive.Description
124 data-slot="alert-dialog-description"
125 className={cn("text-sm text-muted-foreground", className)}
126 {...props}
127 />
128 )
129}
130
131function AlertDialogMedia({
132 className,
133 ...props
134}: React.ComponentProps<"div">) {
135 return (
136 <div
137 data-slot="alert-dialog-media"
138 className={cn(
139 "mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
140 className
141 )}
142 {...props}
143 />
144 )
145}
146
147function AlertDialogAction({
148 className,
149 variant = "default",
150 size = "default",
151 ...props
152}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
153 Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
154 return (
155 <Button variant={variant} size={size} asChild>
156 <AlertDialogPrimitive.Action
157 data-slot="alert-dialog-action"
158 className={cn(className)}
159 {...props}
160 />
161 </Button>
162 )
163}
164
165function AlertDialogCancel({
166 className,
167 variant = "outline",
168 size = "default",
169 ...props
170}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
171 Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
172 return (
173 <Button variant={variant} size={size} asChild>
174 <AlertDialogPrimitive.Cancel
175 data-slot="alert-dialog-cancel"
176 className={cn(className)}
177 {...props}
178 />
179 </Button>
180 )
181}
182
183export {
184 AlertDialog,
185 AlertDialogAction,
186 AlertDialogCancel,
187 AlertDialogContent,
188 AlertDialogDescription,
189 AlertDialogFooter,
190 AlertDialogHeader,
191 AlertDialogMedia,
192 AlertDialogOverlay,
193 AlertDialogPortal,
194 AlertDialogTitle,
195 AlertDialogTrigger,
196}
packages/ui/src/components/alert.tsx+66−0
@@ -0,0 +1,66 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3
4import { cn } from "@executor/ui/lib/utils"
5
6const alertVariants = cva(
7 "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8 {
9 variants: {
10 variant: {
11 default: "bg-card text-card-foreground",
12 destructive:
13 "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current",
14 },
15 },
16 defaultVariants: {
17 variant: "default",
18 },
19 }
20)
21
22function Alert({
23 className,
24 variant,
25 ...props
26}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27 return (
28 <div
29 data-slot="alert"
30 role="alert"
31 className={cn(alertVariants({ variant }), className)}
32 {...props}
33 />
34 )
35}
36
37function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38 return (
39 <div
40 data-slot="alert-title"
41 className={cn(
42 "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43 className
44 )}
45 {...props}
46 />
47 )
48}
49
50function AlertDescription({
51 className,
52 ...props
53}: React.ComponentProps<"div">) {
54 return (
55 <div
56 data-slot="alert-description"
57 className={cn(
58 "col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed",
59 className
60 )}
61 {...props}
62 />
63 )
64}
65
66export { Alert, AlertTitle, AlertDescription }
packages/ui/src/components/aspect-ratio.tsx+11−0
@@ -0,0 +1,11 @@
1"use client"
2
3import { AspectRatio as AspectRatioPrimitive } from "radix-ui"
4
5function AspectRatio({
6 ...props
7}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
8 return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
9}
10
11export { AspectRatio }
packages/ui/src/components/avatar.tsx+107−0
@@ -0,0 +1,107 @@
1import * as React from "react"
2import { Avatar as AvatarPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Avatar({
7 className,
8 size = "default",
9 ...props
10}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
11 size?: "default" | "sm" | "lg"
12}) {
13 return (
14 <AvatarPrimitive.Root
15 data-slot="avatar"
16 data-size={size}
17 className={cn(
18 "group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
19 className
20 )}
21 {...props}
22 />
23 )
24}
25
26function AvatarImage({
27 className,
28 ...props
29}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
30 return (
31 <AvatarPrimitive.Image
32 data-slot="avatar-image"
33 className={cn("aspect-square size-full", className)}
34 {...props}
35 />
36 )
37}
38
39function AvatarFallback({
40 className,
41 ...props
42}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
43 return (
44 <AvatarPrimitive.Fallback
45 data-slot="avatar-fallback"
46 className={cn(
47 "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
48 className
49 )}
50 {...props}
51 />
52 )
53}
54
55function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
56 return (
57 <span
58 data-slot="avatar-badge"
59 className={cn(
60 "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none",
61 "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
62 "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
63 "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
64 className
65 )}
66 {...props}
67 />
68 )
69}
70
71function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
72 return (
73 <div
74 data-slot="avatar-group"
75 className={cn(
76 "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
77 className
78 )}
79 {...props}
80 />
81 )
82}
83
84function AvatarGroupCount({
85 className,
86 ...props
87}: React.ComponentProps<"div">) {
88 return (
89 <div
90 data-slot="avatar-group-count"
91 className={cn(
92 "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
93 className
94 )}
95 {...props}
96 />
97 )
98}
99
100export {
101 Avatar,
102 AvatarImage,
103 AvatarFallback,
104 AvatarBadge,
105 AvatarGroup,
106 AvatarGroupCount,
107}
packages/ui/src/components/badge.tsx+48−0
@@ -0,0 +1,48 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3import { Slot } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7const badgeVariants = cva(
8 "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
9 {
10 variants: {
11 variant: {
12 default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
13 secondary:
14 "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
15 destructive:
16 "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90",
17 outline:
18 "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
19 ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20 link: "text-primary underline-offset-4 [a&]:hover:underline",
21 },
22 },
23 defaultVariants: {
24 variant: "default",
25 },
26 }
27)
28
29function Badge({
30 className,
31 variant = "default",
32 asChild = false,
33 ...props
34}: React.ComponentProps<"span"> &
35 VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
36 const Comp = asChild ? Slot.Root : "span"
37
38 return (
39 <Comp
40 data-slot="badge"
41 data-variant={variant}
42 className={cn(badgeVariants({ variant }), className)}
43 {...props}
44 />
45 )
46}
47
48export { Badge, badgeVariants }
packages/ui/src/components/breadcrumb.tsx+109−0
@@ -0,0 +1,109 @@
1import * as React from "react"
2import { ChevronRight, MoreHorizontal } from "lucide-react"
3import { Slot } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
8 return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
9}
10
11function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
12 return (
13 <ol
14 data-slot="breadcrumb-list"
15 className={cn(
16 "flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5",
17 className
18 )}
19 {...props}
20 />
21 )
22}
23
24function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
25 return (
26 <li
27 data-slot="breadcrumb-item"
28 className={cn("inline-flex items-center gap-1.5", className)}
29 {...props}
30 />
31 )
32}
33
34function BreadcrumbLink({
35 asChild,
36 className,
37 ...props
38}: React.ComponentProps<"a"> & {
39 asChild?: boolean
40}) {
41 const Comp = asChild ? Slot.Root : "a"
42
43 return (
44 <Comp
45 data-slot="breadcrumb-link"
46 className={cn("transition-colors hover:text-foreground", className)}
47 {...props}
48 />
49 )
50}
51
52function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
53 return (
54 <span
55 data-slot="breadcrumb-page"
56 role="link"
57 aria-disabled="true"
58 aria-current="page"
59 className={cn("font-normal text-foreground", className)}
60 {...props}
61 />
62 )
63}
64
65function BreadcrumbSeparator({
66 children,
67 className,
68 ...props
69}: React.ComponentProps<"li">) {
70 return (
71 <li
72 data-slot="breadcrumb-separator"
73 role="presentation"
74 aria-hidden="true"
75 className={cn("[&>svg]:size-3.5", className)}
76 {...props}
77 >
78 {children ?? <ChevronRight />}
79 </li>
80 )
81}
82
83function BreadcrumbEllipsis({
84 className,
85 ...props
86}: React.ComponentProps<"span">) {
87 return (
88 <span
89 data-slot="breadcrumb-ellipsis"
90 role="presentation"
91 aria-hidden="true"
92 className={cn("flex size-9 items-center justify-center", className)}
93 {...props}
94 >
95 <MoreHorizontal className="size-4" />
96 <span className="sr-only">More</span>
97 </span>
98 )
99}
100
101export {
102 Breadcrumb,
103 BreadcrumbList,
104 BreadcrumbItem,
105 BreadcrumbLink,
106 BreadcrumbPage,
107 BreadcrumbSeparator,
108 BreadcrumbEllipsis,
109}
packages/ui/src/components/button-group.tsx+83−0
@@ -0,0 +1,83 @@
1import { cva, type VariantProps } from "class-variance-authority"
2import { Slot } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5import { Separator } from "@executor/ui/components/separator"
6
7const buttonGroupVariants = cva(
8 "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
9 {
10 variants: {
11 orientation: {
12 horizontal:
13 "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
14 vertical:
15 "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
16 },
17 },
18 defaultVariants: {
19 orientation: "horizontal",
20 },
21 }
22)
23
24function ButtonGroup({
25 className,
26 orientation,
27 ...props
28}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
29 return (
30 <div
31 role="group"
32 data-slot="button-group"
33 data-orientation={orientation}
34 className={cn(buttonGroupVariants({ orientation }), className)}
35 {...props}
36 />
37 )
38}
39
40function ButtonGroupText({
41 className,
42 asChild = false,
43 ...props
44}: React.ComponentProps<"div"> & {
45 asChild?: boolean
46}) {
47 const Comp = asChild ? Slot.Root : "div"
48
49 return (
50 <Comp
51 className={cn(
52 "flex items-center gap-2 rounded-md border bg-muted px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
53 className
54 )}
55 {...props}
56 />
57 )
58}
59
60function ButtonGroupSeparator({
61 className,
62 orientation = "vertical",
63 ...props
64}: React.ComponentProps<typeof Separator>) {
65 return (
66 <Separator
67 data-slot="button-group-separator"
68 orientation={orientation}
69 className={cn(
70 "relative m-0! self-stretch bg-input data-[orientation=vertical]:h-auto",
71 className
72 )}
73 {...props}
74 />
75 )
76}
77
78export {
79 ButtonGroup,
80 ButtonGroupSeparator,
81 ButtonGroupText,
82 buttonGroupVariants,
83}
packages/ui/src/components/button.tsx+64−0
@@ -0,0 +1,64 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3import { Slot } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7const buttonVariants = cva(
8 "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
9 {
10 variants: {
11 variant: {
12 default: "bg-primary text-primary-foreground hover:bg-primary/90",
13 destructive:
14 "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
15 outline:
16 "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
17 secondary:
18 "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19 ghost:
20 "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21 link: "text-primary underline-offset-4 hover:underline",
22 },
23 size: {
24 default: "h-9 px-4 py-2 has-[>svg]:px-3",
25 xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
26 sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
27 lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28 icon: "size-9",
29 "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
30 "icon-sm": "size-8",
31 "icon-lg": "size-10",
32 },
33 },
34 defaultVariants: {
35 variant: "default",
36 size: "default",
37 },
38 }
39)
40
41function Button({
42 className,
43 variant = "default",
44 size = "default",
45 asChild = false,
46 ...props
47}: React.ComponentProps<"button"> &
48 VariantProps<typeof buttonVariants> & {
49 asChild?: boolean
50 }) {
51 const Comp = asChild ? Slot.Root : "button"
52
53 return (
54 <Comp
55 data-slot="button"
56 data-variant={variant}
57 data-size={size}
58 className={cn(buttonVariants({ variant, size, className }))}
59 {...props}
60 />
61 )
62}
63
64export { Button, buttonVariants }
packages/ui/src/components/calendar.tsx+218−0
@@ -0,0 +1,218 @@
1import * as React from "react"
2import {
3 ChevronDownIcon,
4 ChevronLeftIcon,
5 ChevronRightIcon,
6} from "lucide-react"
7import {
8 DayPicker,
9 getDefaultClassNames,
10 type DayButton,
11} from "react-day-picker"
12
13import { cn } from "@executor/ui/lib/utils"
14import { Button, buttonVariants } from "@executor/ui/components/button"
15
16function Calendar({
17 className,
18 classNames,
19 showOutsideDays = true,
20 captionLayout = "label",
21 buttonVariant = "ghost",
22 formatters,
23 components,
24 ...props
25}: React.ComponentProps<typeof DayPicker> & {
26 buttonVariant?: React.ComponentProps<typeof Button>["variant"]
27}) {
28 const defaultClassNames = getDefaultClassNames()
29
30 return (
31 <DayPicker
32 showOutsideDays={showOutsideDays}
33 className={cn(
34 "group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
35 String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
36 String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
37 className
38 )}
39 captionLayout={captionLayout}
40 formatters={{
41 formatMonthDropdown: (date) =>
42 date.toLocaleString("default", { month: "short" }),
43 ...formatters,
44 }}
45 classNames={{
46 root: cn("w-fit", defaultClassNames.root),
47 months: cn(
48 "relative flex flex-col gap-4 md:flex-row",
49 defaultClassNames.months
50 ),
51 month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
52 nav: cn(
53 "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
54 defaultClassNames.nav
55 ),
56 button_previous: cn(
57 buttonVariants({ variant: buttonVariant }),
58 "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
59 defaultClassNames.button_previous
60 ),
61 button_next: cn(
62 buttonVariants({ variant: buttonVariant }),
63 "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
64 defaultClassNames.button_next
65 ),
66 month_caption: cn(
67 "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
68 defaultClassNames.month_caption
69 ),
70 dropdowns: cn(
71 "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
72 defaultClassNames.dropdowns
73 ),
74 dropdown_root: cn(
75 "relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
76 defaultClassNames.dropdown_root
77 ),
78 dropdown: cn(
79 "absolute inset-0 bg-popover opacity-0",
80 defaultClassNames.dropdown
81 ),
82 caption_label: cn(
83 "font-medium select-none",
84 captionLayout === "label"
85 ? "text-sm"
86 : "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
87 defaultClassNames.caption_label
88 ),
89 table: "w-full border-collapse",
90 weekdays: cn("flex", defaultClassNames.weekdays),
91 weekday: cn(
92 "flex-1 rounded-md text-[0.8rem] font-normal text-muted-foreground select-none",
93 defaultClassNames.weekday
94 ),
95 week: cn("mt-2 flex w-full", defaultClassNames.week),
96 week_number_header: cn(
97 "w-(--cell-size) select-none",
98 defaultClassNames.week_number_header
99 ),
100 week_number: cn(
101 "text-[0.8rem] text-muted-foreground select-none",
102 defaultClassNames.week_number
103 ),
104 day: cn(
105 "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
106 props.showWeekNumber
107 ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
108 : "[&:first-child[data-selected=true]_button]:rounded-l-md",
109 defaultClassNames.day
110 ),
111 range_start: cn(
112 "rounded-l-md bg-accent",
113 defaultClassNames.range_start
114 ),
115 range_middle: cn("rounded-none", defaultClassNames.range_middle),
116 range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
117 today: cn(
118 "rounded-md bg-accent text-accent-foreground data-[selected=true]:rounded-none",
119 defaultClassNames.today
120 ),
121 outside: cn(
122 "text-muted-foreground aria-selected:text-muted-foreground",
123 defaultClassNames.outside
124 ),
125 disabled: cn(
126 "text-muted-foreground opacity-50",
127 defaultClassNames.disabled
128 ),
129 hidden: cn("invisible", defaultClassNames.hidden),
130 ...classNames,
131 }}
132 components={{
133 Root: ({ className, rootRef, ...props }) => {
134 return (
135 <div
136 data-slot="calendar"
137 ref={rootRef}
138 className={cn(className)}
139 {...props}
140 />
141 )
142 },
143 Chevron: ({ className, orientation, ...props }) => {
144 if (orientation === "left") {
145 return (
146 <ChevronLeftIcon className={cn("size-4", className)} {...props} />
147 )
148 }
149
150 if (orientation === "right") {
151 return (
152 <ChevronRightIcon
153 className={cn("size-4", className)}
154 {...props}
155 />
156 )
157 }
158
159 return (
160 <ChevronDownIcon className={cn("size-4", className)} {...props} />
161 )
162 },
163 DayButton: CalendarDayButton,
164 WeekNumber: ({ children, ...props }) => {
165 return (
166 <td {...props}>
167 <div className="flex size-(--cell-size) items-center justify-center text-center">
168 {children}
169 </div>
170 </td>
171 )
172 },
173 ...components,
174 }}
175 {...props}
176 />
177 )
178}
179
180function CalendarDayButton({
181 className,
182 day,
183 modifiers,
184 ...props
185}: React.ComponentProps<typeof DayButton>) {
186 const defaultClassNames = getDefaultClassNames()
187
188 const ref = React.useRef<HTMLButtonElement>(null)
189 React.useEffect(() => {
190 if (modifiers.focused) ref.current?.focus()
191 }, [modifiers.focused])
192
193 return (
194 <Button
195 ref={ref}
196 variant="ghost"
197 size="icon"
198 data-day={day.date.toLocaleDateString()}
199 data-selected-single={
200 modifiers.selected &&
201 !modifiers.range_start &&
202 !modifiers.range_end &&
203 !modifiers.range_middle
204 }
205 data-range-start={modifiers.range_start}
206 data-range-end={modifiers.range_end}
207 data-range-middle={modifiers.range_middle}
208 className={cn(
209 "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground [&>span]:text-xs [&>span]:opacity-70",
210 defaultClassNames.day,
211 className
212 )}
213 {...props}
214 />
215 )
216}
217
218export { Calendar, CalendarDayButton }
packages/ui/src/components/card.tsx+92−0
@@ -0,0 +1,92 @@
1import * as React from "react"
2
3import { cn } from "@executor/ui/lib/utils"
4
5function Card({ className, ...props }: React.ComponentProps<"div">) {
6 return (
7 <div
8 data-slot="card"
9 className={cn(
10 "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
11 className
12 )}
13 {...props}
14 />
15 )
16}
17
18function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19 return (
20 <div
21 data-slot="card-header"
22 className={cn(
23 "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24 className
25 )}
26 {...props}
27 />
28 )
29}
30
31function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32 return (
33 <div
34 data-slot="card-title"
35 className={cn("leading-none font-semibold", className)}
36 {...props}
37 />
38 )
39}
40
41function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42 return (
43 <div
44 data-slot="card-description"
45 className={cn("text-sm text-muted-foreground", className)}
46 {...props}
47 />
48 )
49}
50
51function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52 return (
53 <div
54 data-slot="card-action"
55 className={cn(
56 "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57 className
58 )}
59 {...props}
60 />
61 )
62}
63
64function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65 return (
66 <div
67 data-slot="card-content"
68 className={cn("px-6", className)}
69 {...props}
70 />
71 )
72}
73
74function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75 return (
76 <div
77 data-slot="card-footer"
78 className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
79 {...props}
80 />
81 )
82}
83
84export {
85 Card,
86 CardHeader,
87 CardFooter,
88 CardTitle,
89 CardAction,
90 CardDescription,
91 CardContent,
92}
packages/ui/src/components/carousel.tsx+241−0
@@ -0,0 +1,241 @@
1"use client"
2
3import * as React from "react"
4import useEmblaCarousel, {
5 type UseEmblaCarouselType,
6} from "embla-carousel-react"
7import { ArrowLeft, ArrowRight } from "lucide-react"
8
9import { cn } from "@executor/ui/lib/utils"
10import { Button } from "@executor/ui/components/button"
11
12type CarouselApi = UseEmblaCarouselType[1]
13type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
14type CarouselOptions = UseCarouselParameters[0]
15type CarouselPlugin = UseCarouselParameters[1]
16
17type CarouselProps = {
18 opts?: CarouselOptions
19 plugins?: CarouselPlugin
20 orientation?: "horizontal" | "vertical"
21 setApi?: (api: CarouselApi) => void
22}
23
24type CarouselContextProps = {
25 carouselRef: ReturnType<typeof useEmblaCarousel>[0]
26 api: ReturnType<typeof useEmblaCarousel>[1]
27 scrollPrev: () => void
28 scrollNext: () => void
29 canScrollPrev: boolean
30 canScrollNext: boolean
31} & CarouselProps
32
33const CarouselContext = React.createContext<CarouselContextProps | null>(null)
34
35function useCarousel() {
36 const context = React.useContext(CarouselContext)
37
38 if (!context) {
39 throw new Error("useCarousel must be used within a <Carousel />")
40 }
41
42 return context
43}
44
45function Carousel({
46 orientation = "horizontal",
47 opts,
48 setApi,
49 plugins,
50 className,
51 children,
52 ...props
53}: React.ComponentProps<"div"> & CarouselProps) {
54 const [carouselRef, api] = useEmblaCarousel(
55 {
56 ...opts,
57 axis: orientation === "horizontal" ? "x" : "y",
58 },
59 plugins
60 )
61 const [canScrollPrev, setCanScrollPrev] = React.useState(false)
62 const [canScrollNext, setCanScrollNext] = React.useState(false)
63
64 const onSelect = React.useCallback((api: CarouselApi) => {
65 if (!api) return
66 setCanScrollPrev(api.canScrollPrev())
67 setCanScrollNext(api.canScrollNext())
68 }, [])
69
70 const scrollPrev = React.useCallback(() => {
71 api?.scrollPrev()
72 }, [api])
73
74 const scrollNext = React.useCallback(() => {
75 api?.scrollNext()
76 }, [api])
77
78 const handleKeyDown = React.useCallback(
79 (event: React.KeyboardEvent<HTMLDivElement>) => {
80 if (event.key === "ArrowLeft") {
81 event.preventDefault()
82 scrollPrev()
83 } else if (event.key === "ArrowRight") {
84 event.preventDefault()
85 scrollNext()
86 }
87 },
88 [scrollPrev, scrollNext]
89 )
90
91 React.useEffect(() => {
92 if (!api || !setApi) return
93 setApi(api)
94 }, [api, setApi])
95
96 React.useEffect(() => {
97 if (!api) return
98 onSelect(api)
99 api.on("reInit", onSelect)
100 api.on("select", onSelect)
101
102 return () => {
103 api?.off("select", onSelect)
104 }
105 }, [api, onSelect])
106
107 return (
108 <CarouselContext.Provider
109 value={{
110 carouselRef,
111 api: api,
112 opts,
113 orientation:
114 orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
115 scrollPrev,
116 scrollNext,
117 canScrollPrev,
118 canScrollNext,
119 }}
120 >
121 <div
122 onKeyDownCapture={handleKeyDown}
123 className={cn("relative", className)}
124 role="region"
125 aria-roledescription="carousel"
126 data-slot="carousel"
127 {...props}
128 >
129 {children}
130 </div>
131 </CarouselContext.Provider>
132 )
133}
134
135function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
136 const { carouselRef, orientation } = useCarousel()
137
138 return (
139 <div
140 ref={carouselRef}
141 className="overflow-hidden"
142 data-slot="carousel-content"
143 >
144 <div
145 className={cn(
146 "flex",
147 orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
148 className
149 )}
150 {...props}
151 />
152 </div>
153 )
154}
155
156function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
157 const { orientation } = useCarousel()
158
159 return (
160 <div
161 role="group"
162 aria-roledescription="slide"
163 data-slot="carousel-item"
164 className={cn(
165 "min-w-0 shrink-0 grow-0 basis-full",
166 orientation === "horizontal" ? "pl-4" : "pt-4",
167 className
168 )}
169 {...props}
170 />
171 )
172}
173
174function CarouselPrevious({
175 className,
176 variant = "outline",
177 size = "icon",
178 ...props
179}: React.ComponentProps<typeof Button>) {
180 const { orientation, scrollPrev, canScrollPrev } = useCarousel()
181
182 return (
183 <Button
184 data-slot="carousel-previous"
185 variant={variant}
186 size={size}
187 className={cn(
188 "absolute size-8 rounded-full",
189 orientation === "horizontal"
190 ? "top-1/2 -left-12 -translate-y-1/2"
191 : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
192 className
193 )}
194 disabled={!canScrollPrev}
195 onClick={scrollPrev}
196 {...props}
197 >
198 <ArrowLeft />
199 <span className="sr-only">Previous slide</span>
200 </Button>
201 )
202}
203
204function CarouselNext({
205 className,
206 variant = "outline",
207 size = "icon",
208 ...props
209}: React.ComponentProps<typeof Button>) {
210 const { orientation, scrollNext, canScrollNext } = useCarousel()
211
212 return (
213 <Button
214 data-slot="carousel-next"
215 variant={variant}
216 size={size}
217 className={cn(
218 "absolute size-8 rounded-full",
219 orientation === "horizontal"
220 ? "top-1/2 -right-12 -translate-y-1/2"
221 : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
222 className
223 )}
224 disabled={!canScrollNext}
225 onClick={scrollNext}
226 {...props}
227 >
228 <ArrowRight />
229 <span className="sr-only">Next slide</span>
230 </Button>
231 )
232}
233
234export {
235 type CarouselApi,
236 Carousel,
237 CarouselContent,
238 CarouselItem,
239 CarouselPrevious,
240 CarouselNext,
241}
packages/ui/src/components/chart.tsx+372−0
@@ -0,0 +1,372 @@
1import * as React from "react"
2import * as RechartsPrimitive from "recharts"
3import type { TooltipValueType } from "recharts"
4
5import { cn } from "@executor/ui/lib/utils"
6
7// Format: { THEME_NAME: CSS_SELECTOR }
8const THEMES = { light: "", dark: ".dark" } as const
9
10const INITIAL_DIMENSION = { width: 320, height: 200 } as const
11type TooltipNameType = number | string
12
13export type ChartConfig = Record<
14 string,
15 {
16 label?: React.ReactNode
17 icon?: React.ComponentType
18 } & (
19 | { color?: string; theme?: never }
20 | { color?: never; theme: Record<keyof typeof THEMES, string> }
21 )
22>
23
24type ChartContextProps = {
25 config: ChartConfig
26}
27
28const ChartContext = React.createContext<ChartContextProps | null>(null)
29
30function useChart() {
31 const context = React.useContext(ChartContext)
32
33 if (!context) {
34 throw new Error("useChart must be used within a <ChartContainer />")
35 }
36
37 return context
38}
39
40function ChartContainer({
41 id,
42 className,
43 children,
44 config,
45 initialDimension = INITIAL_DIMENSION,
46 ...props
47}: React.ComponentProps<"div"> & {
48 config: ChartConfig
49 children: React.ComponentProps<
50 typeof RechartsPrimitive.ResponsiveContainer
51 >["children"]
52 initialDimension?: {
53 width: number
54 height: number
55 }
56}) {
57 const uniqueId = React.useId()
58 const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`
59
60 return (
61 <ChartContext.Provider value={{ config }}>
62 <div
63 data-slot="chart"
64 data-chart={chartId}
65 className={cn(
66 "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
67 className
68 )}
69 {...props}
70 >
71 <ChartStyle id={chartId} config={config} />
72 <RechartsPrimitive.ResponsiveContainer
73 initialDimension={initialDimension}
74 >
75 {children}
76 </RechartsPrimitive.ResponsiveContainer>
77 </div>
78 </ChartContext.Provider>
79 )
80}
81
82const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
83 const colorConfig = Object.entries(config).filter(
84 ([, config]) => config.theme ?? config.color
85 )
86
87 if (!colorConfig.length) {
88 return null
89 }
90
91 return (
92 <style
93 dangerouslySetInnerHTML={{
94 __html: Object.entries(THEMES)
95 .map(
96 ([theme, prefix]) => `
97${prefix} [data-chart=${id}] {
98${colorConfig
99 .map(([key, itemConfig]) => {
100 const color =
101 itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
102 itemConfig.color
103 return color ? ` --color-${key}: ${color};` : null
104 })
105 .join("\n")}
106}
107`
108 )
109 .join("\n"),
110 }}
111 />
112 )
113}
114
115const ChartTooltip = RechartsPrimitive.Tooltip
116
117function ChartTooltipContent({
118 active,
119 payload,
120 className,
121 indicator = "dot",
122 hideLabel = false,
123 hideIndicator = false,
124 label,
125 labelFormatter,
126 labelClassName,
127 formatter,
128 color,
129 nameKey,
130 labelKey,
131}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
132 React.ComponentProps<"div"> & {
133 hideLabel?: boolean
134 hideIndicator?: boolean
135 indicator?: "line" | "dot" | "dashed"
136 nameKey?: string
137 labelKey?: string
138 } & Omit<
139 RechartsPrimitive.DefaultTooltipContentProps<
140 TooltipValueType,
141 TooltipNameType
142 >,
143 "accessibilityLayer"
144 >) {
145 const { config } = useChart()
146
147 const tooltipLabel = React.useMemo(() => {
148 if (hideLabel || !payload?.length) {
149 return null
150 }
151
152 const [item] = payload
153 const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`
154 const itemConfig = getPayloadConfigFromPayload(config, item, key)
155 const value =
156 !labelKey && typeof label === "string"
157 ? (config[label]?.label ?? label)
158 : itemConfig?.label
159
160 if (labelFormatter) {
161 return (
162 <div className={cn("font-medium", labelClassName)}>
163 {labelFormatter(value, payload)}
164 </div>
165 )
166 }
167
168 if (!value) {
169 return null
170 }
171
172 return <div className={cn("font-medium", labelClassName)}>{value}</div>
173 }, [
174 label,
175 labelFormatter,
176 payload,
177 hideLabel,
178 labelClassName,
179 config,
180 labelKey,
181 ])
182
183 if (!active || !payload?.length) {
184 return null
185 }
186
187 const nestLabel = payload.length === 1 && indicator !== "dot"
188
189 return (
190 <div
191 className={cn(
192 "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
193 className
194 )}
195 >
196 {!nestLabel ? tooltipLabel : null}
197 <div className="grid gap-1.5">
198 {payload
199 .filter((item) => item.type !== "none")
200 .map((item, index) => {
201 const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
202 const itemConfig = getPayloadConfigFromPayload(config, item, key)
203 const indicatorColor = color ?? item.payload?.fill ?? item.color
204
205 return (
206 <div
207 key={index}
208 className={cn(
209 "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
210 indicator === "dot" && "items-center"
211 )}
212 >
213 {formatter && item?.value !== undefined && item.name ? (
214 formatter(item.value, item.name, item, index, item.payload)
215 ) : (
216 <>
217 {itemConfig?.icon ? (
218 <itemConfig.icon />
219 ) : (
220 !hideIndicator && (
221 <div
222 className={cn(
223 "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
224 {
225 "h-2.5 w-2.5": indicator === "dot",
226 "w-1": indicator === "line",
227 "w-0 border-[1.5px] border-dashed bg-transparent":
228 indicator === "dashed",
229 "my-0.5": nestLabel && indicator === "dashed",
230 }
231 )}
232 style={
233 {
234 "--color-bg": indicatorColor,
235 "--color-border": indicatorColor,
236 } as React.CSSProperties
237 }
238 />
239 )
240 )}
241 <div
242 className={cn(
243 "flex flex-1 justify-between leading-none",
244 nestLabel ? "items-end" : "items-center"
245 )}
246 >
247 <div className="grid gap-1.5">
248 {nestLabel ? tooltipLabel : null}
249 <span className="text-muted-foreground">
250 {itemConfig?.label ?? item.name}
251 </span>
252 </div>
253 {item.value != null && (
254 <span className="font-mono font-medium text-foreground tabular-nums">
255 {typeof item.value === "number"
256 ? item.value.toLocaleString()
257 : String(item.value)}
258 </span>
259 )}
260 </div>
261 </>
262 )}
263 </div>
264 )
265 })}
266 </div>
267 </div>
268 )
269}
270
271const ChartLegend = RechartsPrimitive.Legend
272
273function ChartLegendContent({
274 className,
275 hideIcon = false,
276 payload,
277 verticalAlign = "bottom",
278 nameKey,
279}: React.ComponentProps<"div"> & {
280 hideIcon?: boolean
281 nameKey?: string
282} & RechartsPrimitive.DefaultLegendContentProps) {
283 const { config } = useChart()
284
285 if (!payload?.length) {
286 return null
287 }
288
289 return (
290 <div
291 className={cn(
292 "flex items-center justify-center gap-4",
293 verticalAlign === "top" ? "pb-3" : "pt-3",
294 className
295 )}
296 >
297 {payload
298 .filter((item) => item.type !== "none")
299 .map((item, index) => {
300 const key = `${nameKey ?? item.dataKey ?? "value"}`
301 const itemConfig = getPayloadConfigFromPayload(config, item, key)
302
303 return (
304 <div
305 key={index}
306 className={cn(
307 "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
308 )}
309 >
310 {itemConfig?.icon && !hideIcon ? (
311 <itemConfig.icon />
312 ) : (
313 <div
314 className="h-2 w-2 shrink-0 rounded-[2px]"
315 style={{
316 backgroundColor: item.color,
317 }}
318 />
319 )}
320 {itemConfig?.label}
321 </div>
322 )
323 })}
324 </div>
325 )
326}
327
328// Helper to extract item config from a payload.
329function getPayloadConfigFromPayload(
330 config: ChartConfig,
331 payload: unknown,
332 key: string
333) {
334 if (typeof payload !== "object" || payload === null) {
335 return undefined
336 }
337
338 const payloadPayload =
339 "payload" in payload &&
340 typeof payload.payload === "object" &&
341 payload.payload !== null
342 ? payload.payload
343 : undefined
344
345 let configLabelKey: string = key
346
347 if (
348 key in payload &&
349 typeof payload[key as keyof typeof payload] === "string"
350 ) {
351 configLabelKey = payload[key as keyof typeof payload] as string
352 } else if (
353 payloadPayload &&
354 key in payloadPayload &&
355 typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
356 ) {
357 configLabelKey = payloadPayload[
358 key as keyof typeof payloadPayload
359 ] as string
360 }
361
362 return configLabelKey in config ? config[configLabelKey] : config[key]
363}
364
365export {
366 ChartContainer,
367 ChartTooltip,
368 ChartTooltipContent,
369 ChartLegend,
370 ChartLegendContent,
371 ChartStyle,
372}
packages/ui/src/components/checkbox.tsx+32−0
@@ -0,0 +1,32 @@
1"use client"
2
3import * as React from "react"
4import { CheckIcon } from "lucide-react"
5import { Checkbox as CheckboxPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function Checkbox({
10 className,
11 ...props
12}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13 return (
14 <CheckboxPrimitive.Root
15 data-slot="checkbox"
16 className={cn(
17 "peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
18 className
19 )}
20 {...props}
21 >
22 <CheckboxPrimitive.Indicator
23 data-slot="checkbox-indicator"
24 className="grid place-content-center text-current transition-none"
25 >
26 <CheckIcon className="size-3.5" />
27 </CheckboxPrimitive.Indicator>
28 </CheckboxPrimitive.Root>
29 )
30}
31
32export { Checkbox }
packages/ui/src/components/collapsible.tsx+31−0
@@ -0,0 +1,31 @@
1import { Collapsible as CollapsiblePrimitive } from "radix-ui"
2
3function Collapsible({
4 ...props
5}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
6 return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
7}
8
9function CollapsibleTrigger({
10 ...props
11}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
12 return (
13 <CollapsiblePrimitive.CollapsibleTrigger
14 data-slot="collapsible-trigger"
15 {...props}
16 />
17 )
18}
19
20function CollapsibleContent({
21 ...props
22}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
23 return (
24 <CollapsiblePrimitive.CollapsibleContent
25 data-slot="collapsible-content"
26 {...props}
27 />
28 )
29}
30
31export { Collapsible, CollapsibleTrigger, CollapsibleContent }
packages/ui/src/components/combobox.tsx+310−0
@@ -0,0 +1,310 @@
1"use client"
2
3import * as React from "react"
4import { Combobox as ComboboxPrimitive } from "@base-ui/react"
5import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react"
6
7import { cn } from "@executor/ui/lib/utils"
8import { Button } from "@executor/ui/components/button"
9import {
10 InputGroup,
11 InputGroupAddon,
12 InputGroupButton,
13 InputGroupInput,
14} from "@executor/ui/components/input-group"
15
16const Combobox = ComboboxPrimitive.Root
17
18function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) {
19 return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />
20}
21
22function ComboboxTrigger({
23 className,
24 children,
25 ...props
26}: ComboboxPrimitive.Trigger.Props) {
27 return (
28 <ComboboxPrimitive.Trigger
29 data-slot="combobox-trigger"
30 className={cn("[&_svg:not([class*='size-'])]:size-4", className)}
31 {...props}
32 >
33 {children}
34 <ChevronDownIcon
35 data-slot="combobox-trigger-icon"
36 className="pointer-events-none size-4 text-muted-foreground"
37 />
38 </ComboboxPrimitive.Trigger>
39 )
40}
41
42function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
43 return (
44 <ComboboxPrimitive.Clear
45 data-slot="combobox-clear"
46 render={<InputGroupButton variant="ghost" size="icon-xs" />}
47 className={cn(className)}
48 {...props}
49 >
50 <XIcon className="pointer-events-none" />
51 </ComboboxPrimitive.Clear>
52 )
53}
54
55function ComboboxInput({
56 className,
57 children,
58 disabled = false,
59 showTrigger = true,
60 showClear = false,
61 ...props
62}: ComboboxPrimitive.Input.Props & {
63 showTrigger?: boolean
64 showClear?: boolean
65}) {
66 return (
67 <InputGroup className={cn("w-auto", className)}>
68 <ComboboxPrimitive.Input
69 render={<InputGroupInput disabled={disabled} />}
70 {...props}
71 />
72 <InputGroupAddon align="inline-end">
73 {showTrigger && (
74 <InputGroupButton
75 size="icon-xs"
76 variant="ghost"
77 asChild
78 data-slot="input-group-button"
79 className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
80 disabled={disabled}
81 >
82 <ComboboxTrigger />
83 </InputGroupButton>
84 )}
85 {showClear && <ComboboxClear disabled={disabled} />}
86 </InputGroupAddon>
87 {children}
88 </InputGroup>
89 )
90}
91
92function ComboboxContent({
93 className,
94 side = "bottom",
95 sideOffset = 6,
96 align = "start",
97 alignOffset = 0,
98 anchor,
99 ...props
100}: ComboboxPrimitive.Popup.Props &
101 Pick<
102 ComboboxPrimitive.Positioner.Props,
103 "side" | "align" | "sideOffset" | "alignOffset" | "anchor"
104 >) {
105 return (
106 <ComboboxPrimitive.Portal>
107 <ComboboxPrimitive.Positioner
108 side={side}
109 sideOffset={sideOffset}
110 align={align}
111 alignOffset={alignOffset}
112 anchor={anchor}
113 className="isolate z-50"
114 >
115 <ComboboxPrimitive.Popup
116 data-slot="combobox-content"
117 data-chips={!!anchor}
118 className={cn(
119 "group/combobox-content relative max-h-96 w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) 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 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
120 className
121 )}
122 {...props}
123 />
124 </ComboboxPrimitive.Positioner>
125 </ComboboxPrimitive.Portal>
126 )
127}
128
129function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
130 return (
131 <ComboboxPrimitive.List
132 data-slot="combobox-list"
133 className={cn(
134 "max-h-[min(calc(--spacing(96)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto p-1 data-empty:p-0",
135 className
136 )}
137 {...props}
138 />
139 )
140}
141
142function ComboboxItem({
143 className,
144 children,
145 ...props
146}: ComboboxPrimitive.Item.Props) {
147 return (
148 <ComboboxPrimitive.Item
149 data-slot="combobox-item"
150 className={cn(
151 "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
152 className
153 )}
154 {...props}
155 >
156 {children}
157 <ComboboxPrimitive.ItemIndicator
158 data-slot="combobox-item-indicator"
159 render={
160 <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
161 }
162 >
163 <CheckIcon className="pointer-events-none size-4 pointer-coarse:size-5" />
164 </ComboboxPrimitive.ItemIndicator>
165 </ComboboxPrimitive.Item>
166 )
167}
168
169function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
170 return (
171 <ComboboxPrimitive.Group
172 data-slot="combobox-group"
173 className={cn(className)}
174 {...props}
175 />
176 )
177}
178
179function ComboboxLabel({
180 className,
181 ...props
182}: ComboboxPrimitive.GroupLabel.Props) {
183 return (
184 <ComboboxPrimitive.GroupLabel
185 data-slot="combobox-label"
186 className={cn(
187 "px-2 py-1.5 text-xs text-muted-foreground pointer-coarse:px-3 pointer-coarse:py-2 pointer-coarse:text-sm",
188 className
189 )}
190 {...props}
191 />
192 )
193}
194
195function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
196 return (
197 <ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />
198 )
199}
200
201function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
202 return (
203 <ComboboxPrimitive.Empty
204 data-slot="combobox-empty"
205 className={cn(
206 "hidden w-full justify-center py-2 text-center text-sm text-muted-foreground group-data-empty/combobox-content:flex",
207 className
208 )}
209 {...props}
210 />
211 )
212}
213
214function ComboboxSeparator({
215 className,
216 ...props
217}: ComboboxPrimitive.Separator.Props) {
218 return (
219 <ComboboxPrimitive.Separator
220 data-slot="combobox-separator"
221 className={cn("-mx-1 my-1 h-px bg-border", className)}
222 {...props}
223 />
224 )
225}
226
227function ComboboxChips({
228 className,
229 ...props
230}: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
231 ComboboxPrimitive.Chips.Props) {
232 return (
233 <ComboboxPrimitive.Chips
234 data-slot="combobox-chips"
235 className={cn(
236 "flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent bg-clip-padding px-2.5 py-1.5 text-sm shadow-xs transition-[color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 has-aria-invalid:border-destructive has-aria-invalid:ring-[3px] has-aria-invalid:ring-destructive/20 has-data-[slot=combobox-chip]:px-1.5 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40",
237 className
238 )}
239 {...props}
240 />
241 )
242}
243
244function ComboboxChip({
245 className,
246 children,
247 showRemove = true,
248 ...props
249}: ComboboxPrimitive.Chip.Props & {
250 showRemove?: boolean
251}) {
252 return (
253 <ComboboxPrimitive.Chip
254 data-slot="combobox-chip"
255 className={cn(
256 "flex h-[calc(--spacing(5.5))] w-fit items-center justify-center gap-1 rounded-sm bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0",
257 className
258 )}
259 {...props}
260 >
261 {children}
262 {showRemove && (
263 <ComboboxPrimitive.ChipRemove
264 render={<Button variant="ghost" size="icon-xs" />}
265 className="-ml-1 opacity-50 hover:opacity-100"
266 data-slot="combobox-chip-remove"
267 >
268 <XIcon className="pointer-events-none" />
269 </ComboboxPrimitive.ChipRemove>
270 )}
271 </ComboboxPrimitive.Chip>
272 )
273}
274
275function ComboboxChipsInput({
276 className,
277 children,
278 ...props
279}: ComboboxPrimitive.Input.Props) {
280 return (
281 <ComboboxPrimitive.Input
282 data-slot="combobox-chip-input"
283 className={cn("min-w-16 flex-1 outline-none", className)}
284 {...props}
285 />
286 )
287}
288
289function useComboboxAnchor() {
290 return React.useRef<HTMLDivElement | null>(null)
291}
292
293export {
294 Combobox,
295 ComboboxInput,
296 ComboboxContent,
297 ComboboxList,
298 ComboboxItem,
299 ComboboxGroup,
300 ComboboxLabel,
301 ComboboxCollection,
302 ComboboxEmpty,
303 ComboboxSeparator,
304 ComboboxChips,
305 ComboboxChip,
306 ComboboxChipsInput,
307 ComboboxTrigger,
308 ComboboxValue,
309 useComboboxAnchor,
310}
packages/ui/src/components/command.tsx+184−0
@@ -0,0 +1,184 @@
1"use client"
2
3import * as React from "react"
4import { Command as CommandPrimitive } from "cmdk"
5import { SearchIcon } from "lucide-react"
6
7import { cn } from "@executor/ui/lib/utils"
8import {
9 Dialog,
10 DialogContent,
11 DialogDescription,
12 DialogHeader,
13 DialogTitle,
14} from "@executor/ui/components/dialog"
15
16function Command({
17 className,
18 ...props
19}: React.ComponentProps<typeof CommandPrimitive>) {
20 return (
21 <CommandPrimitive
22 data-slot="command"
23 className={cn(
24 "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
25 className
26 )}
27 {...props}
28 />
29 )
30}
31
32function CommandDialog({
33 title = "Command Palette",
34 description = "Search for a command to run...",
35 children,
36 className,
37 showCloseButton = true,
38 ...props
39}: React.ComponentProps<typeof Dialog> & {
40 title?: string
41 description?: string
42 className?: string
43 showCloseButton?: boolean
44}) {
45 return (
46 <Dialog {...props}>
47 <DialogHeader className="sr-only">
48 <DialogTitle>{title}</DialogTitle>
49 <DialogDescription>{description}</DialogDescription>
50 </DialogHeader>
51 <DialogContent
52 className={cn("overflow-hidden p-0", className)}
53 showCloseButton={showCloseButton}
54 >
55 <Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
56 {children}
57 </Command>
58 </DialogContent>
59 </Dialog>
60 )
61}
62
63function CommandInput({
64 className,
65 ...props
66}: React.ComponentProps<typeof CommandPrimitive.Input>) {
67 return (
68 <div
69 data-slot="command-input-wrapper"
70 className="flex h-9 items-center gap-2 border-b px-3"
71 >
72 <SearchIcon className="size-4 shrink-0 opacity-50" />
73 <CommandPrimitive.Input
74 data-slot="command-input"
75 className={cn(
76 "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
77 className
78 )}
79 {...props}
80 />
81 </div>
82 )
83}
84
85function CommandList({
86 className,
87 ...props
88}: React.ComponentProps<typeof CommandPrimitive.List>) {
89 return (
90 <CommandPrimitive.List
91 data-slot="command-list"
92 className={cn(
93 "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
94 className
95 )}
96 {...props}
97 />
98 )
99}
100
101function CommandEmpty({
102 ...props
103}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
104 return (
105 <CommandPrimitive.Empty
106 data-slot="command-empty"
107 className="py-6 text-center text-sm"
108 {...props}
109 />
110 )
111}
112
113function CommandGroup({
114 className,
115 ...props
116}: React.ComponentProps<typeof CommandPrimitive.Group>) {
117 return (
118 <CommandPrimitive.Group
119 data-slot="command-group"
120 className={cn(
121 "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
122 className
123 )}
124 {...props}
125 />
126 )
127}
128
129function CommandSeparator({
130 className,
131 ...props
132}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
133 return (
134 <CommandPrimitive.Separator
135 data-slot="command-separator"
136 className={cn("-mx-1 h-px bg-border", className)}
137 {...props}
138 />
139 )
140}
141
142function CommandItem({
143 className,
144 ...props
145}: React.ComponentProps<typeof CommandPrimitive.Item>) {
146 return (
147 <CommandPrimitive.Item
148 data-slot="command-item"
149 className={cn(
150 "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
151 className
152 )}
153 {...props}
154 />
155 )
156}
157
158function CommandShortcut({
159 className,
160 ...props
161}: React.ComponentProps<"span">) {
162 return (
163 <span
164 data-slot="command-shortcut"
165 className={cn(
166 "ml-auto text-xs tracking-widest text-muted-foreground",
167 className
168 )}
169 {...props}
170 />
171 )
172}
173
174export {
175 Command,
176 CommandDialog,
177 CommandInput,
178 CommandList,
179 CommandEmpty,
180 CommandGroup,
181 CommandItem,
182 CommandShortcut,
183 CommandSeparator,
184}
packages/ui/src/components/context-menu.tsx+252−0
@@ -0,0 +1,252 @@
1"use client"
2
3import * as React from "react"
4import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
5import { ContextMenu as ContextMenuPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function ContextMenu({
10 ...props
11}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
12 return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
13}
14
15function ContextMenuTrigger({
16 ...props
17}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
18 return (
19 <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
20 )
21}
22
23function ContextMenuGroup({
24 ...props
25}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
26 return (
27 <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
28 )
29}
30
31function ContextMenuPortal({
32 ...props
33}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
34 return (
35 <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
36 )
37}
38
39function ContextMenuSub({
40 ...props
41}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
42 return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />
43}
44
45function ContextMenuRadioGroup({
46 ...props
47}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
48 return (
49 <ContextMenuPrimitive.RadioGroup
50 data-slot="context-menu-radio-group"
51 {...props}
52 />
53 )
54}
55
56function ContextMenuSubTrigger({
57 className,
58 inset,
59 children,
60 ...props
61}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
62 inset?: boolean
63}) {
64 return (
65 <ContextMenuPrimitive.SubTrigger
66 data-slot="context-menu-sub-trigger"
67 data-inset={inset}
68 className={cn(
69 "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
70 className
71 )}
72 {...props}
73 >
74 {children}
75 <ChevronRightIcon className="ml-auto" />
76 </ContextMenuPrimitive.SubTrigger>
77 )
78}
79
80function ContextMenuSubContent({
81 className,
82 ...props
83}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
84 return (
85 <ContextMenuPrimitive.SubContent
86 data-slot="context-menu-sub-content"
87 className={cn(
88 "z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
89 className
90 )}
91 {...props}
92 />
93 )
94}
95
96function ContextMenuContent({
97 className,
98 ...props
99}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
100 return (
101 <ContextMenuPrimitive.Portal>
102 <ContextMenuPrimitive.Content
103 data-slot="context-menu-content"
104 className={cn(
105 "z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
106 className
107 )}
108 {...props}
109 />
110 </ContextMenuPrimitive.Portal>
111 )
112}
113
114function ContextMenuItem({
115 className,
116 inset,
117 variant = "default",
118 ...props
119}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
120 inset?: boolean
121 variant?: "default" | "destructive"
122}) {
123 return (
124 <ContextMenuPrimitive.Item
125 data-slot="context-menu-item"
126 data-inset={inset}
127 data-variant={variant}
128 className={cn(
129 "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
130 className
131 )}
132 {...props}
133 />
134 )
135}
136
137function ContextMenuCheckboxItem({
138 className,
139 children,
140 checked,
141 ...props
142}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
143 return (
144 <ContextMenuPrimitive.CheckboxItem
145 data-slot="context-menu-checkbox-item"
146 className={cn(
147 "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
148 className
149 )}
150 checked={checked}
151 {...props}
152 >
153 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
154 <ContextMenuPrimitive.ItemIndicator>
155 <CheckIcon className="size-4" />
156 </ContextMenuPrimitive.ItemIndicator>
157 </span>
158 {children}
159 </ContextMenuPrimitive.CheckboxItem>
160 )
161}
162
163function ContextMenuRadioItem({
164 className,
165 children,
166 ...props
167}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
168 return (
169 <ContextMenuPrimitive.RadioItem
170 data-slot="context-menu-radio-item"
171 className={cn(
172 "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
173 className
174 )}
175 {...props}
176 >
177 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
178 <ContextMenuPrimitive.ItemIndicator>
179 <CircleIcon className="size-2 fill-current" />
180 </ContextMenuPrimitive.ItemIndicator>
181 </span>
182 {children}
183 </ContextMenuPrimitive.RadioItem>
184 )
185}
186
187function ContextMenuLabel({
188 className,
189 inset,
190 ...props
191}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
192 inset?: boolean
193}) {
194 return (
195 <ContextMenuPrimitive.Label
196 data-slot="context-menu-label"
197 data-inset={inset}
198 className={cn(
199 "px-2 py-1.5 text-sm font-medium text-foreground data-[inset]:pl-8",
200 className
201 )}
202 {...props}
203 />
204 )
205}
206
207function ContextMenuSeparator({
208 className,
209 ...props
210}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
211 return (
212 <ContextMenuPrimitive.Separator
213 data-slot="context-menu-separator"
214 className={cn("-mx-1 my-1 h-px bg-border", className)}
215 {...props}
216 />
217 )
218}
219
220function ContextMenuShortcut({
221 className,
222 ...props
223}: React.ComponentProps<"span">) {
224 return (
225 <span
226 data-slot="context-menu-shortcut"
227 className={cn(
228 "ml-auto text-xs tracking-widest text-muted-foreground",
229 className
230 )}
231 {...props}
232 />
233 )
234}
235
236export {
237 ContextMenu,
238 ContextMenuTrigger,
239 ContextMenuContent,
240 ContextMenuItem,
241 ContextMenuCheckboxItem,
242 ContextMenuRadioItem,
243 ContextMenuLabel,
244 ContextMenuSeparator,
245 ContextMenuShortcut,
246 ContextMenuGroup,
247 ContextMenuPortal,
248 ContextMenuSub,
249 ContextMenuSubContent,
250 ContextMenuSubTrigger,
251 ContextMenuRadioGroup,
252}
packages/ui/src/components/dialog.tsx+156−0
@@ -0,0 +1,156 @@
1import * as React from "react"
2import { XIcon } from "lucide-react"
3import { Dialog as DialogPrimitive } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6import { Button } from "@executor/ui/components/button"
7
8function Dialog({
9 ...props
10}: React.ComponentProps<typeof DialogPrimitive.Root>) {
11 return <DialogPrimitive.Root data-slot="dialog" {...props} />
12}
13
14function DialogTrigger({
15 ...props
16}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
17 return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
18}
19
20function DialogPortal({
21 ...props
22}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
23 return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
24}
25
26function DialogClose({
27 ...props
28}: React.ComponentProps<typeof DialogPrimitive.Close>) {
29 return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
30}
31
32function DialogOverlay({
33 className,
34 ...props
35}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
36 return (
37 <DialogPrimitive.Overlay
38 data-slot="dialog-overlay"
39 className={cn(
40 "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
41 className
42 )}
43 {...props}
44 />
45 )
46}
47
48function DialogContent({
49 className,
50 children,
51 showCloseButton = true,
52 ...props
53}: React.ComponentProps<typeof DialogPrimitive.Content> & {
54 showCloseButton?: boolean
55}) {
56 return (
57 <DialogPortal data-slot="dialog-portal">
58 <DialogOverlay />
59 <DialogPrimitive.Content
60 data-slot="dialog-content"
61 className={cn(
62 "fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
63 className
64 )}
65 {...props}
66 >
67 {children}
68 {showCloseButton && (
69 <DialogPrimitive.Close
70 data-slot="dialog-close"
71 className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
72 >
73 <XIcon />
74 <span className="sr-only">Close</span>
75 </DialogPrimitive.Close>
76 )}
77 </DialogPrimitive.Content>
78 </DialogPortal>
79 )
80}
81
82function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
83 return (
84 <div
85 data-slot="dialog-header"
86 className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
87 {...props}
88 />
89 )
90}
91
92function DialogFooter({
93 className,
94 showCloseButton = false,
95 children,
96 ...props
97}: React.ComponentProps<"div"> & {
98 showCloseButton?: boolean
99}) {
100 return (
101 <div
102 data-slot="dialog-footer"
103 className={cn(
104 "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
105 className
106 )}
107 {...props}
108 >
109 {children}
110 {showCloseButton && (
111 <DialogPrimitive.Close asChild>
112 <Button variant="outline">Close</Button>
113 </DialogPrimitive.Close>
114 )}
115 </div>
116 )
117}
118
119function DialogTitle({
120 className,
121 ...props
122}: React.ComponentProps<typeof DialogPrimitive.Title>) {
123 return (
124 <DialogPrimitive.Title
125 data-slot="dialog-title"
126 className={cn("text-lg leading-none font-semibold", className)}
127 {...props}
128 />
129 )
130}
131
132function DialogDescription({
133 className,
134 ...props
135}: React.ComponentProps<typeof DialogPrimitive.Description>) {
136 return (
137 <DialogPrimitive.Description
138 data-slot="dialog-description"
139 className={cn("text-sm text-muted-foreground", className)}
140 {...props}
141 />
142 )
143}
144
145export {
146 Dialog,
147 DialogClose,
148 DialogContent,
149 DialogDescription,
150 DialogFooter,
151 DialogHeader,
152 DialogOverlay,
153 DialogPortal,
154 DialogTitle,
155 DialogTrigger,
156}
packages/ui/src/components/direction.tsx+22−0
@@ -0,0 +1,22 @@
1"use client"
2
3import * as React from "react"
4import { Direction } from "radix-ui"
5
6function DirectionProvider({
7 dir,
8 direction,
9 children,
10}: React.ComponentProps<typeof Direction.DirectionProvider> & {
11 direction?: React.ComponentProps<typeof Direction.DirectionProvider>["dir"]
12}) {
13 return (
14 <Direction.DirectionProvider dir={direction ?? dir}>
15 {children}
16 </Direction.DirectionProvider>
17 )
18}
19
20const useDirection = Direction.useDirection
21
22export { DirectionProvider, useDirection }
packages/ui/src/components/drawer.tsx+133−0
@@ -0,0 +1,133 @@
1import * as React from "react"
2import { Drawer as DrawerPrimitive } from "vaul"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Drawer({
7 ...props
8}: React.ComponentProps<typeof DrawerPrimitive.Root>) {
9 return <DrawerPrimitive.Root data-slot="drawer" {...props} />
10}
11
12function DrawerTrigger({
13 ...props
14}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
15 return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />
16}
17
18function DrawerPortal({
19 ...props
20}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
21 return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />
22}
23
24function DrawerClose({
25 ...props
26}: React.ComponentProps<typeof DrawerPrimitive.Close>) {
27 return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />
28}
29
30function DrawerOverlay({
31 className,
32 ...props
33}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
34 return (
35 <DrawerPrimitive.Overlay
36 data-slot="drawer-overlay"
37 className={cn(
38 "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
39 className
40 )}
41 {...props}
42 />
43 )
44}
45
46function DrawerContent({
47 className,
48 children,
49 ...props
50}: React.ComponentProps<typeof DrawerPrimitive.Content>) {
51 return (
52 <DrawerPortal data-slot="drawer-portal">
53 <DrawerOverlay />
54 <DrawerPrimitive.Content
55 data-slot="drawer-content"
56 className={cn(
57 "group/drawer-content fixed z-50 flex h-auto flex-col bg-background",
58 "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
59 "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
60 "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
61 "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
62 className
63 )}
64 {...props}
65 >
66 <div className="mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-muted group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
67 {children}
68 </DrawerPrimitive.Content>
69 </DrawerPortal>
70 )
71}
72
73function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
74 return (
75 <div
76 data-slot="drawer-header"
77 className={cn(
78 "flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left",
79 className
80 )}
81 {...props}
82 />
83 )
84}
85
86function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
87 return (
88 <div
89 data-slot="drawer-footer"
90 className={cn("mt-auto flex flex-col gap-2 p-4", className)}
91 {...props}
92 />
93 )
94}
95
96function DrawerTitle({
97 className,
98 ...props
99}: React.ComponentProps<typeof DrawerPrimitive.Title>) {
100 return (
101 <DrawerPrimitive.Title
102 data-slot="drawer-title"
103 className={cn("font-semibold text-foreground", className)}
104 {...props}
105 />
106 )
107}
108
109function DrawerDescription({
110 className,
111 ...props
112}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
113 return (
114 <DrawerPrimitive.Description
115 data-slot="drawer-description"
116 className={cn("text-sm text-muted-foreground", className)}
117 {...props}
118 />
119 )
120}
121
122export {
123 Drawer,
124 DrawerPortal,
125 DrawerOverlay,
126 DrawerTrigger,
127 DrawerClose,
128 DrawerContent,
129 DrawerHeader,
130 DrawerFooter,
131 DrawerTitle,
132 DrawerDescription,
133}
packages/ui/src/components/dropdown-menu.tsx+257−0
@@ -0,0 +1,257 @@
1"use client"
2
3import * as React from "react"
4import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
5import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function DropdownMenu({
10 ...props
11}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12 return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
13}
14
15function DropdownMenuPortal({
16 ...props
17}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18 return (
19 <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
20 )
21}
22
23function DropdownMenuTrigger({
24 ...props
25}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
26 return (
27 <DropdownMenuPrimitive.Trigger
28 data-slot="dropdown-menu-trigger"
29 {...props}
30 />
31 )
32}
33
34function DropdownMenuContent({
35 className,
36 sideOffset = 4,
37 ...props
38}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39 return (
40 <DropdownMenuPrimitive.Portal>
41 <DropdownMenuPrimitive.Content
42 data-slot="dropdown-menu-content"
43 sideOffset={sideOffset}
44 className={cn(
45 "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
46 className
47 )}
48 {...props}
49 />
50 </DropdownMenuPrimitive.Portal>
51 )
52}
53
54function DropdownMenuGroup({
55 ...props
56}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
57 return (
58 <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
59 )
60}
61
62function DropdownMenuItem({
63 className,
64 inset,
65 variant = "default",
66 ...props
67}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
68 inset?: boolean
69 variant?: "default" | "destructive"
70}) {
71 return (
72 <DropdownMenuPrimitive.Item
73 data-slot="dropdown-menu-item"
74 data-inset={inset}
75 data-variant={variant}
76 className={cn(
77 "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
78 className
79 )}
80 {...props}
81 />
82 )
83}
84
85function DropdownMenuCheckboxItem({
86 className,
87 children,
88 checked,
89 ...props
90}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
91 return (
92 <DropdownMenuPrimitive.CheckboxItem
93 data-slot="dropdown-menu-checkbox-item"
94 className={cn(
95 "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
96 className
97 )}
98 checked={checked}
99 {...props}
100 >
101 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
102 <DropdownMenuPrimitive.ItemIndicator>
103 <CheckIcon className="size-4" />
104 </DropdownMenuPrimitive.ItemIndicator>
105 </span>
106 {children}
107 </DropdownMenuPrimitive.CheckboxItem>
108 )
109}
110
111function DropdownMenuRadioGroup({
112 ...props
113}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
114 return (
115 <DropdownMenuPrimitive.RadioGroup
116 data-slot="dropdown-menu-radio-group"
117 {...props}
118 />
119 )
120}
121
122function DropdownMenuRadioItem({
123 className,
124 children,
125 ...props
126}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
127 return (
128 <DropdownMenuPrimitive.RadioItem
129 data-slot="dropdown-menu-radio-item"
130 className={cn(
131 "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132 className
133 )}
134 {...props}
135 >
136 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
137 <DropdownMenuPrimitive.ItemIndicator>
138 <CircleIcon className="size-2 fill-current" />
139 </DropdownMenuPrimitive.ItemIndicator>
140 </span>
141 {children}
142 </DropdownMenuPrimitive.RadioItem>
143 )
144}
145
146function DropdownMenuLabel({
147 className,
148 inset,
149 ...props
150}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
151 inset?: boolean
152}) {
153 return (
154 <DropdownMenuPrimitive.Label
155 data-slot="dropdown-menu-label"
156 data-inset={inset}
157 className={cn(
158 "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
159 className
160 )}
161 {...props}
162 />
163 )
164}
165
166function DropdownMenuSeparator({
167 className,
168 ...props
169}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
170 return (
171 <DropdownMenuPrimitive.Separator
172 data-slot="dropdown-menu-separator"
173 className={cn("-mx-1 my-1 h-px bg-border", className)}
174 {...props}
175 />
176 )
177}
178
179function DropdownMenuShortcut({
180 className,
181 ...props
182}: React.ComponentProps<"span">) {
183 return (
184 <span
185 data-slot="dropdown-menu-shortcut"
186 className={cn(
187 "ml-auto text-xs tracking-widest text-muted-foreground",
188 className
189 )}
190 {...props}
191 />
192 )
193}
194
195function DropdownMenuSub({
196 ...props
197}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
198 return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
199}
200
201function DropdownMenuSubTrigger({
202 className,
203 inset,
204 children,
205 ...props
206}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
207 inset?: boolean
208}) {
209 return (
210 <DropdownMenuPrimitive.SubTrigger
211 data-slot="dropdown-menu-sub-trigger"
212 data-inset={inset}
213 className={cn(
214 "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
215 className
216 )}
217 {...props}
218 >
219 {children}
220 <ChevronRightIcon className="ml-auto size-4" />
221 </DropdownMenuPrimitive.SubTrigger>
222 )
223}
224
225function DropdownMenuSubContent({
226 className,
227 ...props
228}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
229 return (
230 <DropdownMenuPrimitive.SubContent
231 data-slot="dropdown-menu-sub-content"
232 className={cn(
233 "z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
234 className
235 )}
236 {...props}
237 />
238 )
239}
240
241export {
242 DropdownMenu,
243 DropdownMenuPortal,
244 DropdownMenuTrigger,
245 DropdownMenuContent,
246 DropdownMenuGroup,
247 DropdownMenuLabel,
248 DropdownMenuItem,
249 DropdownMenuCheckboxItem,
250 DropdownMenuRadioGroup,
251 DropdownMenuRadioItem,
252 DropdownMenuSeparator,
253 DropdownMenuShortcut,
254 DropdownMenuSub,
255 DropdownMenuSubTrigger,
256 DropdownMenuSubContent,
257}
packages/ui/src/components/empty.tsx+104−0
@@ -0,0 +1,104 @@
1import { cva, type VariantProps } from "class-variance-authority"
2
3import { cn } from "@executor/ui/lib/utils"
4
5function Empty({ className, ...props }: React.ComponentProps<"div">) {
6 return (
7 <div
8 data-slot="empty"
9 className={cn(
10 "flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12",
11 className
12 )}
13 {...props}
14 />
15 )
16}
17
18function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) {
19 return (
20 <div
21 data-slot="empty-header"
22 className={cn(
23 "flex max-w-sm flex-col items-center gap-2 text-center",
24 className
25 )}
26 {...props}
27 />
28 )
29}
30
31const emptyMediaVariants = cva(
32 "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
33 {
34 variants: {
35 variant: {
36 default: "bg-transparent",
37 icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
38 },
39 },
40 defaultVariants: {
41 variant: "default",
42 },
43 }
44)
45
46function EmptyMedia({
47 className,
48 variant = "default",
49 ...props
50}: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) {
51 return (
52 <div
53 data-slot="empty-icon"
54 data-variant={variant}
55 className={cn(emptyMediaVariants({ variant, className }))}
56 {...props}
57 />
58 )
59}
60
61function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
62 return (
63 <div
64 data-slot="empty-title"
65 className={cn("text-lg font-medium tracking-tight", className)}
66 {...props}
67 />
68 )
69}
70
71function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
72 return (
73 <div
74 data-slot="empty-description"
75 className={cn(
76 "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
77 className
78 )}
79 {...props}
80 />
81 )
82}
83
84function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
85 return (
86 <div
87 data-slot="empty-content"
88 className={cn(
89 "flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance",
90 className
91 )}
92 {...props}
93 />
94 )
95}
96
97export {
98 Empty,
99 EmptyHeader,
100 EmptyTitle,
101 EmptyDescription,
102 EmptyContent,
103 EmptyMedia,
104}
packages/ui/src/components/field.tsx+248−0
@@ -0,0 +1,248 @@
1"use client"
2
3import { useMemo } from "react"
4import { cva, type VariantProps } from "class-variance-authority"
5
6import { cn } from "@executor/ui/lib/utils"
7import { Label } from "@executor/ui/components/label"
8import { Separator } from "@executor/ui/components/separator"
9
10function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
11 return (
12 <fieldset
13 data-slot="field-set"
14 className={cn(
15 "flex flex-col gap-6",
16 "has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
17 className
18 )}
19 {...props}
20 />
21 )
22}
23
24function FieldLegend({
25 className,
26 variant = "legend",
27 ...props
28}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
29 return (
30 <legend
31 data-slot="field-legend"
32 data-variant={variant}
33 className={cn(
34 "mb-3 font-medium",
35 "data-[variant=legend]:text-base",
36 "data-[variant=label]:text-sm",
37 className
38 )}
39 {...props}
40 />
41 )
42}
43
44function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
45 return (
46 <div
47 data-slot="field-group"
48 className={cn(
49 "group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4",
50 className
51 )}
52 {...props}
53 />
54 )
55}
56
57const fieldVariants = cva(
58 "group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
59 {
60 variants: {
61 orientation: {
62 vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
63 horizontal: [
64 "flex-row items-center",
65 "[&>[data-slot=field-label]]:flex-auto",
66 "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
67 ],
68 responsive: [
69 "flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto",
70 "@md/field-group:[&>[data-slot=field-label]]:flex-auto",
71 "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
72 ],
73 },
74 },
75 defaultVariants: {
76 orientation: "vertical",
77 },
78 }
79)
80
81function Field({
82 className,
83 orientation = "vertical",
84 ...props
85}: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
86 return (
87 <div
88 role="group"
89 data-slot="field"
90 data-orientation={orientation}
91 className={cn(fieldVariants({ orientation }), className)}
92 {...props}
93 />
94 )
95}
96
97function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
98 return (
99 <div
100 data-slot="field-content"
101 className={cn(
102 "group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
103 className
104 )}
105 {...props}
106 />
107 )
108}
109
110function FieldLabel({
111 className,
112 ...props
113}: React.ComponentProps<typeof Label>) {
114 return (
115 <Label
116 data-slot="field-label"
117 className={cn(
118 "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
119 "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4",
120 "has-data-[state=checked]:border-primary has-data-[state=checked]:bg-primary/5 dark:has-data-[state=checked]:bg-primary/10",
121 className
122 )}
123 {...props}
124 />
125 )
126}
127
128function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
129 return (
130 <div
131 data-slot="field-label"
132 className={cn(
133 "flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
134 className
135 )}
136 {...props}
137 />
138 )
139}
140
141function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
142 return (
143 <p
144 data-slot="field-description"
145 className={cn(
146 "text-sm leading-normal font-normal text-muted-foreground group-has-[[data-orientation=horizontal]]/field:text-balance",
147 "last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
148 "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
149 className
150 )}
151 {...props}
152 />
153 )
154}
155
156function FieldSeparator({
157 children,
158 className,
159 ...props
160}: React.ComponentProps<"div"> & {
161 children?: React.ReactNode
162}) {
163 return (
164 <div
165 data-slot="field-separator"
166 data-content={!!children}
167 className={cn(
168 "relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
169 className
170 )}
171 {...props}
172 >
173 <Separator className="absolute inset-0 top-1/2" />
174 {children && (
175 <span
176 className="relative mx-auto block w-fit bg-background px-2 text-muted-foreground"
177 data-slot="field-separator-content"
178 >
179 {children}
180 </span>
181 )}
182 </div>
183 )
184}
185
186function FieldError({
187 className,
188 children,
189 errors,
190 ...props
191}: React.ComponentProps<"div"> & {
192 errors?: Array<{ message?: string } | undefined>
193}) {
194 const content = useMemo(() => {
195 if (children) {
196 return children
197 }
198
199 if (!errors?.length) {
200 return null
201 }
202
203 const uniqueErrors = [
204 ...new Map(errors.map((error) => [error?.message, error])).values(),
205 ]
206
207 if (uniqueErrors?.length == 1) {
208 return uniqueErrors[0]?.message
209 }
210
211 return (
212 <ul className="ml-4 flex list-disc flex-col gap-1">
213 {uniqueErrors.map(
214 (error, index) =>
215 error?.message && <li key={index}>{error.message}</li>
216 )}
217 </ul>
218 )
219 }, [children, errors])
220
221 if (!content) {
222 return null
223 }
224
225 return (
226 <div
227 role="alert"
228 data-slot="field-error"
229 className={cn("text-sm font-normal text-destructive", className)}
230 {...props}
231 >
232 {content}
233 </div>
234 )
235}
236
237export {
238 Field,
239 FieldLabel,
240 FieldDescription,
241 FieldError,
242 FieldGroup,
243 FieldLegend,
244 FieldSeparator,
245 FieldSet,
246 FieldContent,
247 FieldTitle,
248}
packages/ui/src/components/form.tsx+165−0
@@ -0,0 +1,165 @@
1import * as React from "react"
2import type { Label as LabelPrimitive } from "radix-ui"
3import { Slot } from "radix-ui"
4import {
5 Controller,
6 FormProvider,
7 useFormContext,
8 useFormState,
9 type ControllerProps,
10 type FieldPath,
11 type FieldValues,
12} from "react-hook-form"
13
14import { cn } from "@executor/ui/lib/utils"
15import { Label } from "@executor/ui/components/label"
16
17const Form = FormProvider
18
19type FormFieldContextValue<
20 TFieldValues extends FieldValues = FieldValues,
21 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
22> = {
23 name: TName
24}
25
26const FormFieldContext = React.createContext<FormFieldContextValue>(
27 {} as FormFieldContextValue
28)
29
30const FormField = <
31 TFieldValues extends FieldValues = FieldValues,
32 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
33>({
34 ...props
35}: ControllerProps<TFieldValues, TName>) => {
36 return (
37 <FormFieldContext.Provider value={{ name: props.name }}>
38 <Controller {...props} />
39 </FormFieldContext.Provider>
40 )
41}
42
43const useFormField = () => {
44 const fieldContext = React.useContext(FormFieldContext)
45 const itemContext = React.useContext(FormItemContext)
46 const { getFieldState } = useFormContext()
47 const formState = useFormState({ name: fieldContext.name })
48 const fieldState = getFieldState(fieldContext.name, formState)
49
50 if (!fieldContext) {
51 throw new Error("useFormField should be used within <FormField>")
52 }
53
54 const { id } = itemContext
55
56 return {
57 id,
58 name: fieldContext.name,
59 formItemId: `${id}-form-item`,
60 formDescriptionId: `${id}-form-item-description`,
61 formMessageId: `${id}-form-item-message`,
62 ...fieldState,
63 }
64}
65
66type FormItemContextValue = {
67 id: string
68}
69
70const FormItemContext = React.createContext<FormItemContextValue>(
71 {} as FormItemContextValue
72)
73
74function FormItem({ className, ...props }: React.ComponentProps<"div">) {
75 const id = React.useId()
76
77 return (
78 <FormItemContext.Provider value={{ id }}>
79 <div
80 data-slot="form-item"
81 className={cn("grid gap-2", className)}
82 {...props}
83 />
84 </FormItemContext.Provider>
85 )
86}
87
88function FormLabel({
89 className,
90 ...props
91}: React.ComponentProps<typeof LabelPrimitive.Root>) {
92 const { error, formItemId } = useFormField()
93
94 return (
95 <Label
96 data-slot="form-label"
97 data-error={!!error}
98 className={cn("data-[error=true]:text-destructive", className)}
99 htmlFor={formItemId}
100 {...props}
101 />
102 )
103}
104
105function FormControl({ ...props }: React.ComponentProps<typeof Slot.Root>) {
106 const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
107
108 return (
109 <Slot.Root
110 data-slot="form-control"
111 id={formItemId}
112 aria-describedby={
113 !error
114 ? `${formDescriptionId}`
115 : `${formDescriptionId} ${formMessageId}`
116 }
117 aria-invalid={!!error}
118 {...props}
119 />
120 )
121}
122
123function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
124 const { formDescriptionId } = useFormField()
125
126 return (
127 <p
128 data-slot="form-description"
129 id={formDescriptionId}
130 className={cn("text-sm text-muted-foreground", className)}
131 {...props}
132 />
133 )
134}
135
136function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
137 const { error, formMessageId } = useFormField()
138 const body = error ? String(error?.message ?? "") : props.children
139
140 if (!body) {
141 return null
142 }
143
144 return (
145 <p
146 data-slot="form-message"
147 id={formMessageId}
148 className={cn("text-sm text-destructive", className)}
149 {...props}
150 >
151 {body}
152 </p>
153 )
154}
155
156export {
157 useFormField,
158 Form,
159 FormItem,
160 FormLabel,
161 FormControl,
162 FormDescription,
163 FormMessage,
164 FormField,
165}
packages/ui/src/components/hover-card.tsx+42−0
@@ -0,0 +1,42 @@
1import * as React from "react"
2import { HoverCard as HoverCardPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function HoverCard({
7 ...props
8}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
9 return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
10}
11
12function HoverCardTrigger({
13 ...props
14}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
15 return (
16 <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
17 )
18}
19
20function HoverCardContent({
21 className,
22 align = "center",
23 sideOffset = 4,
24 ...props
25}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
26 return (
27 <HoverCardPrimitive.Portal data-slot="hover-card-portal">
28 <HoverCardPrimitive.Content
29 data-slot="hover-card-content"
30 align={align}
31 sideOffset={sideOffset}
32 className={cn(
33 "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
34 className
35 )}
36 {...props}
37 />
38 </HoverCardPrimitive.Portal>
39 )
40}
41
42export { HoverCard, HoverCardTrigger, HoverCardContent }
packages/ui/src/components/input-group.tsx+168−0
@@ -0,0 +1,168 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3
4import { cn } from "@executor/ui/lib/utils"
5import { Button } from "@executor/ui/components/button"
6import { Input } from "@executor/ui/components/input"
7import { Textarea } from "@executor/ui/components/textarea"
8
9function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
10 return (
11 <div
12 data-slot="input-group"
13 role="group"
14 className={cn(
15 "group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30",
16 "h-9 min-w-0 has-[>textarea]:h-auto",
17
18 // Variants based on alignment.
19 "has-[>[data-align=inline-start]]:[&>input]:pl-2",
20 "has-[>[data-align=inline-end]]:[&>input]:pr-2",
21 "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
22 "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
23
24 // Focus state.
25 "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",
26
27 // Error state.
28 "has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
29
30 className
31 )}
32 {...props}
33 />
34 )
35}
36
37const inputGroupAddonVariants = cva(
38 "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
39 {
40 variants: {
41 align: {
42 "inline-start":
43 "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
44 "inline-end":
45 "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
46 "block-start":
47 "order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",
48 "block-end":
49 "order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3",
50 },
51 },
52 defaultVariants: {
53 align: "inline-start",
54 },
55 }
56)
57
58function InputGroupAddon({
59 className,
60 align = "inline-start",
61 ...props
62}: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
63 return (
64 <div
65 role="group"
66 data-slot="input-group-addon"
67 data-align={align}
68 className={cn(inputGroupAddonVariants({ align }), className)}
69 onClick={(e) => {
70 if ((e.target as HTMLElement).closest("button")) {
71 return
72 }
73 e.currentTarget.parentElement?.querySelector("input")?.focus()
74 }}
75 {...props}
76 />
77 )
78}
79
80const inputGroupButtonVariants = cva(
81 "flex items-center gap-2 text-sm shadow-none",
82 {
83 variants: {
84 size: {
85 xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
86 sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
87 "icon-xs":
88 "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
89 "icon-sm": "size-8 p-0 has-[>svg]:p-0",
90 },
91 },
92 defaultVariants: {
93 size: "xs",
94 },
95 }
96)
97
98function InputGroupButton({
99 className,
100 type = "button",
101 variant = "ghost",
102 size = "xs",
103 ...props
104}: Omit<React.ComponentProps<typeof Button>, "size"> &
105 VariantProps<typeof inputGroupButtonVariants>) {
106 return (
107 <Button
108 type={type}
109 data-size={size}
110 variant={variant}
111 className={cn(inputGroupButtonVariants({ size }), className)}
112 {...props}
113 />
114 )
115}
116
117function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
118 return (
119 <span
120 className={cn(
121 "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
122 className
123 )}
124 {...props}
125 />
126 )
127}
128
129function InputGroupInput({
130 className,
131 ...props
132}: React.ComponentProps<"input">) {
133 return (
134 <Input
135 data-slot="input-group-control"
136 className={cn(
137 "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
138 className
139 )}
140 {...props}
141 />
142 )
143}
144
145function InputGroupTextarea({
146 className,
147 ...props
148}: React.ComponentProps<"textarea">) {
149 return (
150 <Textarea
151 data-slot="input-group-control"
152 className={cn(
153 "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
154 className
155 )}
156 {...props}
157 />
158 )
159}
160
161export {
162 InputGroup,
163 InputGroupAddon,
164 InputGroupButton,
165 InputGroupText,
166 InputGroupInput,
167 InputGroupTextarea,
168}
packages/ui/src/components/input-otp.tsx+77−0
@@ -0,0 +1,77 @@
1"use client"
2
3import * as React from "react"
4import { OTPInput, OTPInputContext } from "input-otp"
5import { MinusIcon } from "lucide-react"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function InputOTP({
10 className,
11 containerClassName,
12 ...props
13}: React.ComponentProps<typeof OTPInput> & {
14 containerClassName?: string
15}) {
16 return (
17 <OTPInput
18 data-slot="input-otp"
19 containerClassName={cn(
20 "flex items-center gap-2 has-disabled:opacity-50",
21 containerClassName
22 )}
23 className={cn("disabled:cursor-not-allowed", className)}
24 {...props}
25 />
26 )
27}
28
29function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
30 return (
31 <div
32 data-slot="input-otp-group"
33 className={cn("flex items-center", className)}
34 {...props}
35 />
36 )
37}
38
39function InputOTPSlot({
40 index,
41 className,
42 ...props
43}: React.ComponentProps<"div"> & {
44 index: number
45}) {
46 const inputOTPContext = React.useContext(OTPInputContext)
47 const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
48
49 return (
50 <div
51 data-slot="input-otp-slot"
52 data-active={isActive}
53 className={cn(
54 "relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[3px] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
55 className
56 )}
57 {...props}
58 >
59 {char}
60 {hasFakeCaret && (
61 <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
62 <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
63 </div>
64 )}
65 </div>
66 )
67}
68
69function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
70 return (
71 <div data-slot="input-otp-separator" role="separator" {...props}>
72 <MinusIcon />
73 </div>
74 )
75}
76
77export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
packages/ui/src/components/input.tsx+21−0
@@ -0,0 +1,21 @@
1import * as React from "react"
2
3import { cn } from "@executor/ui/lib/utils"
4
5function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6 return (
7 <input
8 type={type}
9 data-slot="input"
10 className={cn(
11 "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
12 "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
13 "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
14 className
15 )}
16 {...props}
17 />
18 )
19}
20
21export { Input }
packages/ui/src/components/item.tsx+193−0
@@ -0,0 +1,193 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3import { Slot } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6import { Separator } from "@executor/ui/components/separator"
7
8function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
9 return (
10 <div
11 role="list"
12 data-slot="item-group"
13 className={cn("group/item-group flex flex-col", className)}
14 {...props}
15 />
16 )
17}
18
19function ItemSeparator({
20 className,
21 ...props
22}: React.ComponentProps<typeof Separator>) {
23 return (
24 <Separator
25 data-slot="item-separator"
26 orientation="horizontal"
27 className={cn("my-0", className)}
28 {...props}
29 />
30 )
31}
32
33const itemVariants = cva(
34 "group/item flex flex-wrap items-center rounded-md border border-transparent text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-accent/50",
35 {
36 variants: {
37 variant: {
38 default: "bg-transparent",
39 outline: "border-border",
40 muted: "bg-muted/50",
41 },
42 size: {
43 default: "gap-4 p-4",
44 sm: "gap-2.5 px-4 py-3",
45 },
46 },
47 defaultVariants: {
48 variant: "default",
49 size: "default",
50 },
51 }
52)
53
54function Item({
55 className,
56 variant = "default",
57 size = "default",
58 asChild = false,
59 ...props
60}: React.ComponentProps<"div"> &
61 VariantProps<typeof itemVariants> & { asChild?: boolean }) {
62 const Comp = asChild ? Slot.Root : "div"
63 return (
64 <Comp
65 data-slot="item"
66 data-variant={variant}
67 data-size={size}
68 className={cn(itemVariants({ variant, size, className }))}
69 {...props}
70 />
71 )
72}
73
74const itemMediaVariants = cva(
75 "flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none",
76 {
77 variants: {
78 variant: {
79 default: "bg-transparent",
80 icon: "size-8 rounded-sm border bg-muted [&_svg:not([class*='size-'])]:size-4",
81 image:
82 "size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover",
83 },
84 },
85 defaultVariants: {
86 variant: "default",
87 },
88 }
89)
90
91function ItemMedia({
92 className,
93 variant = "default",
94 ...props
95}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
96 return (
97 <div
98 data-slot="item-media"
99 data-variant={variant}
100 className={cn(itemMediaVariants({ variant, className }))}
101 {...props}
102 />
103 )
104}
105
106function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
107 return (
108 <div
109 data-slot="item-content"
110 className={cn(
111 "flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none",
112 className
113 )}
114 {...props}
115 />
116 )
117}
118
119function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
120 return (
121 <div
122 data-slot="item-title"
123 className={cn(
124 "flex w-fit items-center gap-2 text-sm leading-snug font-medium",
125 className
126 )}
127 {...props}
128 />
129 )
130}
131
132function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
133 return (
134 <p
135 data-slot="item-description"
136 className={cn(
137 "line-clamp-2 text-sm leading-normal font-normal text-balance text-muted-foreground",
138 "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
139 className
140 )}
141 {...props}
142 />
143 )
144}
145
146function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
147 return (
148 <div
149 data-slot="item-actions"
150 className={cn("flex items-center gap-2", className)}
151 {...props}
152 />
153 )
154}
155
156function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
157 return (
158 <div
159 data-slot="item-header"
160 className={cn(
161 "flex basis-full items-center justify-between gap-2",
162 className
163 )}
164 {...props}
165 />
166 )
167}
168
169function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
170 return (
171 <div
172 data-slot="item-footer"
173 className={cn(
174 "flex basis-full items-center justify-between gap-2",
175 className
176 )}
177 {...props}
178 />
179 )
180}
181
182export {
183 Item,
184 ItemMedia,
185 ItemContent,
186 ItemActions,
187 ItemGroup,
188 ItemSeparator,
189 ItemTitle,
190 ItemDescription,
191 ItemHeader,
192 ItemFooter,
193}
packages/ui/src/components/kbd.tsx+28−0
@@ -0,0 +1,28 @@
1import { cn } from "@executor/ui/lib/utils"
2
3function Kbd({ className, ...props }: React.ComponentProps<"kbd">) {
4 return (
5 <kbd
6 data-slot="kbd"
7 className={cn(
8 "pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none",
9 "[&_svg:not([class*='size-'])]:size-3",
10 "[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10",
11 className
12 )}
13 {...props}
14 />
15 )
16}
17
18function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
19 return (
20 <kbd
21 data-slot="kbd-group"
22 className={cn("inline-flex items-center gap-1", className)}
23 {...props}
24 />
25 )
26}
27
28export { Kbd, KbdGroup }
packages/ui/src/components/label.tsx+22−0
@@ -0,0 +1,22 @@
1import * as React from "react"
2import { Label as LabelPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Label({
7 className,
8 ...props
9}: React.ComponentProps<typeof LabelPrimitive.Root>) {
10 return (
11 <LabelPrimitive.Root
12 data-slot="label"
13 className={cn(
14 "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
15 className
16 )}
17 {...props}
18 />
19 )
20}
21
22export { Label }
packages/ui/src/components/menubar.tsx+276−0
@@ -0,0 +1,276 @@
1"use client"
2
3import * as React from "react"
4import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
5import { Menubar as MenubarPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function Menubar({
10 className,
11 ...props
12}: React.ComponentProps<typeof MenubarPrimitive.Root>) {
13 return (
14 <MenubarPrimitive.Root
15 data-slot="menubar"
16 className={cn(
17 "flex h-9 items-center gap-1 rounded-md border bg-background p-1 shadow-xs",
18 className
19 )}
20 {...props}
21 />
22 )
23}
24
25function MenubarMenu({
26 ...props
27}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
28 return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />
29}
30
31function MenubarGroup({
32 ...props
33}: React.ComponentProps<typeof MenubarPrimitive.Group>) {
34 return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />
35}
36
37function MenubarPortal({
38 ...props
39}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
40 return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />
41}
42
43function MenubarRadioGroup({
44 ...props
45}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
46 return (
47 <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
48 )
49}
50
51function MenubarTrigger({
52 className,
53 ...props
54}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
55 return (
56 <MenubarPrimitive.Trigger
57 data-slot="menubar-trigger"
58 className={cn(
59 "flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
60 className
61 )}
62 {...props}
63 />
64 )
65}
66
67function MenubarContent({
68 className,
69 align = "start",
70 alignOffset = -4,
71 sideOffset = 8,
72 ...props
73}: React.ComponentProps<typeof MenubarPrimitive.Content>) {
74 return (
75 <MenubarPortal>
76 <MenubarPrimitive.Content
77 data-slot="menubar-content"
78 align={align}
79 alignOffset={alignOffset}
80 sideOffset={sideOffset}
81 className={cn(
82 "z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
83 className
84 )}
85 {...props}
86 />
87 </MenubarPortal>
88 )
89}
90
91function MenubarItem({
92 className,
93 inset,
94 variant = "default",
95 ...props
96}: React.ComponentProps<typeof MenubarPrimitive.Item> & {
97 inset?: boolean
98 variant?: "default" | "destructive"
99}) {
100 return (
101 <MenubarPrimitive.Item
102 data-slot="menubar-item"
103 data-inset={inset}
104 data-variant={variant}
105 className={cn(
106 "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
107 className
108 )}
109 {...props}
110 />
111 )
112}
113
114function MenubarCheckboxItem({
115 className,
116 children,
117 checked,
118 ...props
119}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
120 return (
121 <MenubarPrimitive.CheckboxItem
122 data-slot="menubar-checkbox-item"
123 className={cn(
124 "relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
125 className
126 )}
127 checked={checked}
128 {...props}
129 >
130 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
131 <MenubarPrimitive.ItemIndicator>
132 <CheckIcon className="size-4" />
133 </MenubarPrimitive.ItemIndicator>
134 </span>
135 {children}
136 </MenubarPrimitive.CheckboxItem>
137 )
138}
139
140function MenubarRadioItem({
141 className,
142 children,
143 ...props
144}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {
145 return (
146 <MenubarPrimitive.RadioItem
147 data-slot="menubar-radio-item"
148 className={cn(
149 "relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
150 className
151 )}
152 {...props}
153 >
154 <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
155 <MenubarPrimitive.ItemIndicator>
156 <CircleIcon className="size-2 fill-current" />
157 </MenubarPrimitive.ItemIndicator>
158 </span>
159 {children}
160 </MenubarPrimitive.RadioItem>
161 )
162}
163
164function MenubarLabel({
165 className,
166 inset,
167 ...props
168}: React.ComponentProps<typeof MenubarPrimitive.Label> & {
169 inset?: boolean
170}) {
171 return (
172 <MenubarPrimitive.Label
173 data-slot="menubar-label"
174 data-inset={inset}
175 className={cn(
176 "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
177 className
178 )}
179 {...props}
180 />
181 )
182}
183
184function MenubarSeparator({
185 className,
186 ...props
187}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
188 return (
189 <MenubarPrimitive.Separator
190 data-slot="menubar-separator"
191 className={cn("-mx-1 my-1 h-px bg-border", className)}
192 {...props}
193 />
194 )
195}
196
197function MenubarShortcut({
198 className,
199 ...props
200}: React.ComponentProps<"span">) {
201 return (
202 <span
203 data-slot="menubar-shortcut"
204 className={cn(
205 "ml-auto text-xs tracking-widest text-muted-foreground",
206 className
207 )}
208 {...props}
209 />
210 )
211}
212
213function MenubarSub({
214 ...props
215}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
216 return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />
217}
218
219function MenubarSubTrigger({
220 className,
221 inset,
222 children,
223 ...props
224}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
225 inset?: boolean
226}) {
227 return (
228 <MenubarPrimitive.SubTrigger
229 data-slot="menubar-sub-trigger"
230 data-inset={inset}
231 className={cn(
232 "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
233 className
234 )}
235 {...props}
236 >
237 {children}
238 <ChevronRightIcon className="ml-auto h-4 w-4" />
239 </MenubarPrimitive.SubTrigger>
240 )
241}
242
243function MenubarSubContent({
244 className,
245 ...props
246}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
247 return (
248 <MenubarPrimitive.SubContent
249 data-slot="menubar-sub-content"
250 className={cn(
251 "z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
252 className
253 )}
254 {...props}
255 />
256 )
257}
258
259export {
260 Menubar,
261 MenubarPortal,
262 MenubarMenu,
263 MenubarTrigger,
264 MenubarContent,
265 MenubarGroup,
266 MenubarSeparator,
267 MenubarLabel,
268 MenubarItem,
269 MenubarShortcut,
270 MenubarCheckboxItem,
271 MenubarRadioGroup,
272 MenubarRadioItem,
273 MenubarSub,
274 MenubarSubTrigger,
275 MenubarSubContent,
276}
packages/ui/src/components/native-select.tsx+53−0
@@ -0,0 +1,53 @@
1import * as React from "react"
2import { ChevronDownIcon } from "lucide-react"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function NativeSelect({
7 className,
8 size = "default",
9 ...props
10}: Omit<React.ComponentProps<"select">, "size"> & { size?: "sm" | "default" }) {
11 return (
12 <div
13 className="group/native-select relative w-fit has-[select:disabled]:opacity-50"
14 data-slot="native-select-wrapper"
15 >
16 <select
17 data-slot="native-select"
18 data-size={size}
19 className={cn(
20 "h-9 w-full min-w-0 appearance-none rounded-md border border-input bg-transparent px-3 py-2 pr-9 text-sm shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed data-[size=sm]:h-8 data-[size=sm]:py-1 dark:bg-input/30 dark:hover:bg-input/50",
21 "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
22 "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
23 className
24 )}
25 {...props}
26 />
27 <ChevronDownIcon
28 className="pointer-events-none absolute top-1/2 right-3.5 size-4 -translate-y-1/2 text-muted-foreground opacity-50 select-none"
29 aria-hidden="true"
30 data-slot="native-select-icon"
31 />
32 </div>
33 )
34}
35
36function NativeSelectOption({ ...props }: React.ComponentProps<"option">) {
37 return <option data-slot="native-select-option" {...props} />
38}
39
40function NativeSelectOptGroup({
41 className,
42 ...props
43}: React.ComponentProps<"optgroup">) {
44 return (
45 <optgroup
46 data-slot="native-select-optgroup"
47 className={cn(className)}
48 {...props}
49 />
50 )
51}
52
53export { NativeSelect, NativeSelectOptGroup, NativeSelectOption }
packages/ui/src/components/navigation-menu.tsx+168−0
@@ -0,0 +1,168 @@
1import * as React from "react"
2import { cva } from "class-variance-authority"
3import { ChevronDownIcon } from "lucide-react"
4import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"
5
6import { cn } from "@executor/ui/lib/utils"
7
8function NavigationMenu({
9 className,
10 children,
11 viewport = true,
12 ...props
13}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
14 viewport?: boolean
15}) {
16 return (
17 <NavigationMenuPrimitive.Root
18 data-slot="navigation-menu"
19 data-viewport={viewport}
20 className={cn(
21 "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
22 className
23 )}
24 {...props}
25 >
26 {children}
27 {viewport && <NavigationMenuViewport />}
28 </NavigationMenuPrimitive.Root>
29 )
30}
31
32function NavigationMenuList({
33 className,
34 ...props
35}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
36 return (
37 <NavigationMenuPrimitive.List
38 data-slot="navigation-menu-list"
39 className={cn(
40 "group flex flex-1 list-none items-center justify-center gap-1",
41 className
42 )}
43 {...props}
44 />
45 )
46}
47
48function NavigationMenuItem({
49 className,
50 ...props
51}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
52 return (
53 <NavigationMenuPrimitive.Item
54 data-slot="navigation-menu-item"
55 className={cn("relative", className)}
56 {...props}
57 />
58 )
59}
60
61const navigationMenuTriggerStyle = cva(
62 "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-[color,box-shadow] outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-accent/50 data-[state=open]:text-accent-foreground data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent"
63)
64
65function NavigationMenuTrigger({
66 className,
67 children,
68 ...props
69}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
70 return (
71 <NavigationMenuPrimitive.Trigger
72 data-slot="navigation-menu-trigger"
73 className={cn(navigationMenuTriggerStyle(), "group", className)}
74 {...props}
75 >
76 {children}{" "}
77 <ChevronDownIcon
78 className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
79 aria-hidden="true"
80 />
81 </NavigationMenuPrimitive.Trigger>
82 )
83}
84
85function NavigationMenuContent({
86 className,
87 ...props
88}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
89 return (
90 <NavigationMenuPrimitive.Content
91 data-slot="navigation-menu-content"
92 className={cn(
93 "top-0 left-0 w-full p-2 pr-2.5 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out md:absolute md:w-auto",
94 "group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95",
95 className
96 )}
97 {...props}
98 />
99 )
100}
101
102function NavigationMenuViewport({
103 className,
104 ...props
105}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
106 return (
107 <div
108 className={cn(
109 "absolute top-full left-0 isolate z-50 flex justify-center"
110 )}
111 >
112 <NavigationMenuPrimitive.Viewport
113 data-slot="navigation-menu-viewport"
114 className={cn(
115 "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
116 className
117 )}
118 {...props}
119 />
120 </div>
121 )
122}
123
124function NavigationMenuLink({
125 className,
126 ...props
127}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
128 return (
129 <NavigationMenuPrimitive.Link
130 data-slot="navigation-menu-link"
131 className={cn(
132 "flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground data-[active=true]:hover:bg-accent data-[active=true]:focus:bg-accent [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
133 className
134 )}
135 {...props}
136 />
137 )
138}
139
140function NavigationMenuIndicator({
141 className,
142 ...props
143}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
144 return (
145 <NavigationMenuPrimitive.Indicator
146 data-slot="navigation-menu-indicator"
147 className={cn(
148 "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",
149 className
150 )}
151 {...props}
152 >
153 <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
154 </NavigationMenuPrimitive.Indicator>
155 )
156}
157
158export {
159 NavigationMenu,
160 NavigationMenuList,
161 NavigationMenuItem,
162 NavigationMenuContent,
163 NavigationMenuTrigger,
164 NavigationMenuLink,
165 NavigationMenuIndicator,
166 NavigationMenuViewport,
167 navigationMenuTriggerStyle,
168}
packages/ui/src/components/pagination.tsx+127−0
@@ -0,0 +1,127 @@
1import * as React from "react"
2import {
3 ChevronLeftIcon,
4 ChevronRightIcon,
5 MoreHorizontalIcon,
6} from "lucide-react"
7
8import { cn } from "@executor/ui/lib/utils"
9import { buttonVariants, type Button } from "@executor/ui/components/button"
10
11function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
12 return (
13 <nav
14 role="navigation"
15 aria-label="pagination"
16 data-slot="pagination"
17 className={cn("mx-auto flex w-full justify-center", className)}
18 {...props}
19 />
20 )
21}
22
23function PaginationContent({
24 className,
25 ...props
26}: React.ComponentProps<"ul">) {
27 return (
28 <ul
29 data-slot="pagination-content"
30 className={cn("flex flex-row items-center gap-1", className)}
31 {...props}
32 />
33 )
34}
35
36function PaginationItem({ ...props }: React.ComponentProps<"li">) {
37 return <li data-slot="pagination-item" {...props} />
38}
39
40type PaginationLinkProps = {
41 isActive?: boolean
42} & Pick<React.ComponentProps<typeof Button>, "size"> &
43 React.ComponentProps<"a">
44
45function PaginationLink({
46 className,
47 isActive,
48 size = "icon",
49 ...props
50}: PaginationLinkProps) {
51 return (
52 <a
53 aria-current={isActive ? "page" : undefined}
54 data-slot="pagination-link"
55 data-active={isActive}
56 className={cn(
57 buttonVariants({
58 variant: isActive ? "outline" : "ghost",
59 size,
60 }),
61 className
62 )}
63 {...props}
64 />
65 )
66}
67
68function PaginationPrevious({
69 className,
70 ...props
71}: React.ComponentProps<typeof PaginationLink>) {
72 return (
73 <PaginationLink
74 aria-label="Go to previous page"
75 size="default"
76 className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
77 {...props}
78 >
79 <ChevronLeftIcon />
80 <span className="hidden sm:block">Previous</span>
81 </PaginationLink>
82 )
83}
84
85function PaginationNext({
86 className,
87 ...props
88}: React.ComponentProps<typeof PaginationLink>) {
89 return (
90 <PaginationLink
91 aria-label="Go to next page"
92 size="default"
93 className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
94 {...props}
95 >
96 <span className="hidden sm:block">Next</span>
97 <ChevronRightIcon />
98 </PaginationLink>
99 )
100}
101
102function PaginationEllipsis({
103 className,
104 ...props
105}: React.ComponentProps<"span">) {
106 return (
107 <span
108 aria-hidden
109 data-slot="pagination-ellipsis"
110 className={cn("flex size-9 items-center justify-center", className)}
111 {...props}
112 >
113 <MoreHorizontalIcon className="size-4" />
114 <span className="sr-only">More pages</span>
115 </span>
116 )
117}
118
119export {
120 Pagination,
121 PaginationContent,
122 PaginationLink,
123 PaginationItem,
124 PaginationPrevious,
125 PaginationNext,
126 PaginationEllipsis,
127}
packages/ui/src/components/popover.tsx+87−0
@@ -0,0 +1,87 @@
1import * as React from "react"
2import { Popover as PopoverPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Popover({
7 ...props
8}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
9 return <PopoverPrimitive.Root data-slot="popover" {...props} />
10}
11
12function PopoverTrigger({
13 ...props
14}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
15 return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
16}
17
18function PopoverContent({
19 className,
20 align = "center",
21 sideOffset = 4,
22 ...props
23}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
24 return (
25 <PopoverPrimitive.Portal>
26 <PopoverPrimitive.Content
27 data-slot="popover-content"
28 align={align}
29 sideOffset={sideOffset}
30 className={cn(
31 "z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
32 className
33 )}
34 {...props}
35 />
36 </PopoverPrimitive.Portal>
37 )
38}
39
40function PopoverAnchor({
41 ...props
42}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
43 return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
44}
45
46function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
47 return (
48 <div
49 data-slot="popover-header"
50 className={cn("flex flex-col gap-1 text-sm", className)}
51 {...props}
52 />
53 )
54}
55
56function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) {
57 return (
58 <div
59 data-slot="popover-title"
60 className={cn("font-medium", className)}
61 {...props}
62 />
63 )
64}
65
66function PopoverDescription({
67 className,
68 ...props
69}: React.ComponentProps<"p">) {
70 return (
71 <p
72 data-slot="popover-description"
73 className={cn("text-muted-foreground", className)}
74 {...props}
75 />
76 )
77}
78
79export {
80 Popover,
81 PopoverTrigger,
82 PopoverContent,
83 PopoverAnchor,
84 PopoverHeader,
85 PopoverTitle,
86 PopoverDescription,
87}
packages/ui/src/components/progress.tsx+31−0
@@ -0,0 +1,31 @@
1"use client"
2
3import * as React from "react"
4import { Progress as ProgressPrimitive } from "radix-ui"
5
6import { cn } from "@executor/ui/lib/utils"
7
8function Progress({
9 className,
10 value,
11 ...props
12}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13 return (
14 <ProgressPrimitive.Root
15 data-slot="progress"
16 className={cn(
17 "relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
18 className
19 )}
20 {...props}
21 >
22 <ProgressPrimitive.Indicator
23 data-slot="progress-indicator"
24 className="h-full w-full flex-1 bg-primary transition-all"
25 style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26 />
27 </ProgressPrimitive.Root>
28 )
29}
30
31export { Progress }
packages/ui/src/components/radio-group.tsx+43−0
@@ -0,0 +1,43 @@
1import * as React from "react"
2import { CircleIcon } from "lucide-react"
3import { RadioGroup as RadioGroupPrimitive } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7function RadioGroup({
8 className,
9 ...props
10}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
11 return (
12 <RadioGroupPrimitive.Root
13 data-slot="radio-group"
14 className={cn("grid gap-3", className)}
15 {...props}
16 />
17 )
18}
19
20function RadioGroupItem({
21 className,
22 ...props
23}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
24 return (
25 <RadioGroupPrimitive.Item
26 data-slot="radio-group-item"
27 className={cn(
28 "aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
29 className
30 )}
31 {...props}
32 >
33 <RadioGroupPrimitive.Indicator
34 data-slot="radio-group-indicator"
35 className="relative flex items-center justify-center"
36 >
37 <CircleIcon className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 fill-primary" />
38 </RadioGroupPrimitive.Indicator>
39 </RadioGroupPrimitive.Item>
40 )
41}
42
43export { RadioGroup, RadioGroupItem }
packages/ui/src/components/resizable.tsx+53−0
@@ -0,0 +1,53 @@
1"use client"
2
3import { GripVerticalIcon } from "lucide-react"
4import * as ResizablePrimitive from "react-resizable-panels"
5
6import { cn } from "@executor/ui/lib/utils"
7
8function ResizablePanelGroup({
9 className,
10 ...props
11}: ResizablePrimitive.GroupProps) {
12 return (
13 <ResizablePrimitive.Group
14 data-slot="resizable-panel-group"
15 className={cn(
16 "flex h-full w-full aria-[orientation=vertical]:flex-col",
17 className
18 )}
19 {...props}
20 />
21 )
22}
23
24function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
25 return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
26}
27
28function ResizableHandle({
29 withHandle,
30 className,
31 ...props
32}: ResizablePrimitive.SeparatorProps & {
33 withHandle?: boolean
34}) {
35 return (
36 <ResizablePrimitive.Separator
37 data-slot="resizable-handle"
38 className={cn(
39 "relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
40 className
41 )}
42 {...props}
43 >
44 {withHandle && (
45 <div className="z-10 flex h-4 w-3 items-center justify-center rounded-xs border bg-border">
46 <GripVerticalIcon className="size-2.5" />
47 </div>
48 )}
49 </ResizablePrimitive.Separator>
50 )
51}
52
53export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
packages/ui/src/components/scroll-area.tsx+56−0
@@ -0,0 +1,56 @@
1import * as React from "react"
2import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function ScrollArea({
7 className,
8 children,
9 ...props
10}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
11 return (
12 <ScrollAreaPrimitive.Root
13 data-slot="scroll-area"
14 className={cn("relative", className)}
15 {...props}
16 >
17 <ScrollAreaPrimitive.Viewport
18 data-slot="scroll-area-viewport"
19 className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
20 >
21 {children}
22 </ScrollAreaPrimitive.Viewport>
23 <ScrollBar />
24 <ScrollAreaPrimitive.Corner />
25 </ScrollAreaPrimitive.Root>
26 )
27}
28
29function ScrollBar({
30 className,
31 orientation = "vertical",
32 ...props
33}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
34 return (
35 <ScrollAreaPrimitive.ScrollAreaScrollbar
36 data-slot="scroll-area-scrollbar"
37 orientation={orientation}
38 className={cn(
39 "flex touch-none p-px transition-colors select-none",
40 orientation === "vertical" &&
41 "h-full w-2.5 border-l border-l-transparent",
42 orientation === "horizontal" &&
43 "h-2.5 flex-col border-t border-t-transparent",
44 className
45 )}
46 {...props}
47 >
48 <ScrollAreaPrimitive.ScrollAreaThumb
49 data-slot="scroll-area-thumb"
50 className="relative flex-1 rounded-full bg-border"
51 />
52 </ScrollAreaPrimitive.ScrollAreaScrollbar>
53 )
54}
55
56export { ScrollArea, ScrollBar }
packages/ui/src/components/select.tsx+190−0
@@ -0,0 +1,190 @@
1"use client"
2
3import * as React from "react"
4import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
5import { Select as SelectPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function Select({
10 ...props
11}: React.ComponentProps<typeof SelectPrimitive.Root>) {
12 return <SelectPrimitive.Root data-slot="select" {...props} />
13}
14
15function SelectGroup({
16 ...props
17}: React.ComponentProps<typeof SelectPrimitive.Group>) {
18 return <SelectPrimitive.Group data-slot="select-group" {...props} />
19}
20
21function SelectValue({
22 ...props
23}: React.ComponentProps<typeof SelectPrimitive.Value>) {
24 return <SelectPrimitive.Value data-slot="select-value" {...props} />
25}
26
27function SelectTrigger({
28 className,
29 size = "default",
30 children,
31 ...props
32}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
33 size?: "sm" | "default"
34}) {
35 return (
36 <SelectPrimitive.Trigger
37 data-slot="select-trigger"
38 data-size={size}
39 className={cn(
40 "flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
41 className
42 )}
43 {...props}
44 >
45 {children}
46 <SelectPrimitive.Icon asChild>
47 <ChevronDownIcon className="size-4 opacity-50" />
48 </SelectPrimitive.Icon>
49 </SelectPrimitive.Trigger>
50 )
51}
52
53function SelectContent({
54 className,
55 children,
56 position = "item-aligned",
57 align = "center",
58 ...props
59}: React.ComponentProps<typeof SelectPrimitive.Content>) {
60 return (
61 <SelectPrimitive.Portal>
62 <SelectPrimitive.Content
63 data-slot="select-content"
64 className={cn(
65 "relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
66 position === "popper" &&
67 "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
68 className
69 )}
70 position={position}
71 align={align}
72 {...props}
73 >
74 <SelectScrollUpButton />
75 <SelectPrimitive.Viewport
76 className={cn(
77 "p-1",
78 position === "popper" &&
79 "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
80 )}
81 >
82 {children}
83 </SelectPrimitive.Viewport>
84 <SelectScrollDownButton />
85 </SelectPrimitive.Content>
86 </SelectPrimitive.Portal>
87 )
88}
89
90function SelectLabel({
91 className,
92 ...props
93}: React.ComponentProps<typeof SelectPrimitive.Label>) {
94 return (
95 <SelectPrimitive.Label
96 data-slot="select-label"
97 className={cn("px-2 py-1.5 text-xs text-muted-foreground", className)}
98 {...props}
99 />
100 )
101}
102
103function SelectItem({
104 className,
105 children,
106 ...props
107}: React.ComponentProps<typeof SelectPrimitive.Item>) {
108 return (
109 <SelectPrimitive.Item
110 data-slot="select-item"
111 className={cn(
112 "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
113 className
114 )}
115 {...props}
116 >
117 <span
118 data-slot="select-item-indicator"
119 className="absolute right-2 flex size-3.5 items-center justify-center"
120 >
121 <SelectPrimitive.ItemIndicator>
122 <CheckIcon className="size-4" />
123 </SelectPrimitive.ItemIndicator>
124 </span>
125 <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
126 </SelectPrimitive.Item>
127 )
128}
129
130function SelectSeparator({
131 className,
132 ...props
133}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
134 return (
135 <SelectPrimitive.Separator
136 data-slot="select-separator"
137 className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
138 {...props}
139 />
140 )
141}
142
143function SelectScrollUpButton({
144 className,
145 ...props
146}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
147 return (
148 <SelectPrimitive.ScrollUpButton
149 data-slot="select-scroll-up-button"
150 className={cn(
151 "flex cursor-default items-center justify-center py-1",
152 className
153 )}
154 {...props}
155 >
156 <ChevronUpIcon className="size-4" />
157 </SelectPrimitive.ScrollUpButton>
158 )
159}
160
161function SelectScrollDownButton({
162 className,
163 ...props
164}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
165 return (
166 <SelectPrimitive.ScrollDownButton
167 data-slot="select-scroll-down-button"
168 className={cn(
169 "flex cursor-default items-center justify-center py-1",
170 className
171 )}
172 {...props}
173 >
174 <ChevronDownIcon className="size-4" />
175 </SelectPrimitive.ScrollDownButton>
176 )
177}
178
179export {
180 Select,
181 SelectContent,
182 SelectGroup,
183 SelectItem,
184 SelectLabel,
185 SelectScrollDownButton,
186 SelectScrollUpButton,
187 SelectSeparator,
188 SelectTrigger,
189 SelectValue,
190}
packages/ui/src/components/separator.tsx+26−0
@@ -0,0 +1,26 @@
1import * as React from "react"
2import { Separator as SeparatorPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Separator({
7 className,
8 orientation = "horizontal",
9 decorative = true,
10 ...props
11}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
12 return (
13 <SeparatorPrimitive.Root
14 data-slot="separator"
15 decorative={decorative}
16 orientation={orientation}
17 className={cn(
18 "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
19 className
20 )}
21 {...props}
22 />
23 )
24}
25
26export { Separator }
packages/ui/src/components/sheet.tsx+143−0
@@ -0,0 +1,143 @@
1"use client"
2
3import * as React from "react"
4import { XIcon } from "lucide-react"
5import { Dialog as SheetPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
10 return <SheetPrimitive.Root data-slot="sheet" {...props} />
11}
12
13function SheetTrigger({
14 ...props
15}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
16 return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
17}
18
19function SheetClose({
20 ...props
21}: React.ComponentProps<typeof SheetPrimitive.Close>) {
22 return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
23}
24
25function SheetPortal({
26 ...props
27}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
28 return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
29}
30
31function SheetOverlay({
32 className,
33 ...props
34}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
35 return (
36 <SheetPrimitive.Overlay
37 data-slot="sheet-overlay"
38 className={cn(
39 "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
40 className
41 )}
42 {...props}
43 />
44 )
45}
46
47function SheetContent({
48 className,
49 children,
50 side = "right",
51 showCloseButton = true,
52 ...props
53}: React.ComponentProps<typeof SheetPrimitive.Content> & {
54 side?: "top" | "right" | "bottom" | "left"
55 showCloseButton?: boolean
56}) {
57 return (
58 <SheetPortal>
59 <SheetOverlay />
60 <SheetPrimitive.Content
61 data-slot="sheet-content"
62 className={cn(
63 "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
64 side === "right" &&
65 "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
66 side === "left" &&
67 "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
68 side === "top" &&
69 "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
70 side === "bottom" &&
71 "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
72 className
73 )}
74 {...props}
75 >
76 {children}
77 {showCloseButton && (
78 <SheetPrimitive.Close className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary">
79 <XIcon className="size-4" />
80 <span className="sr-only">Close</span>
81 </SheetPrimitive.Close>
82 )}
83 </SheetPrimitive.Content>
84 </SheetPortal>
85 )
86}
87
88function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
89 return (
90 <div
91 data-slot="sheet-header"
92 className={cn("flex flex-col gap-1.5 p-4", className)}
93 {...props}
94 />
95 )
96}
97
98function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
99 return (
100 <div
101 data-slot="sheet-footer"
102 className={cn("mt-auto flex flex-col gap-2 p-4", className)}
103 {...props}
104 />
105 )
106}
107
108function SheetTitle({
109 className,
110 ...props
111}: React.ComponentProps<typeof SheetPrimitive.Title>) {
112 return (
113 <SheetPrimitive.Title
114 data-slot="sheet-title"
115 className={cn("font-semibold text-foreground", className)}
116 {...props}
117 />
118 )
119}
120
121function SheetDescription({
122 className,
123 ...props
124}: React.ComponentProps<typeof SheetPrimitive.Description>) {
125 return (
126 <SheetPrimitive.Description
127 data-slot="sheet-description"
128 className={cn("text-sm text-muted-foreground", className)}
129 {...props}
130 />
131 )
132}
133
134export {
135 Sheet,
136 SheetTrigger,
137 SheetClose,
138 SheetContent,
139 SheetHeader,
140 SheetFooter,
141 SheetTitle,
142 SheetDescription,
143}
packages/ui/src/components/sidebar.tsx+724−0
@@ -0,0 +1,724 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3import { PanelLeftIcon } from "lucide-react"
4import { Slot } from "radix-ui"
5
6import { useIsMobile } from "@executor/ui/hooks/use-mobile"
7import { cn } from "@executor/ui/lib/utils"
8import { Button } from "@executor/ui/components/button"
9import { Input } from "@executor/ui/components/input"
10import { Separator } from "@executor/ui/components/separator"
11import {
12 Sheet,
13 SheetContent,
14 SheetDescription,
15 SheetHeader,
16 SheetTitle,
17} from "@executor/ui/components/sheet"
18import { Skeleton } from "@executor/ui/components/skeleton"
19import {
20 Tooltip,
21 TooltipContent,
22 TooltipProvider,
23 TooltipTrigger,
24} from "@executor/ui/components/tooltip"
25
26const SIDEBAR_COOKIE_NAME = "sidebar_state"
27const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
28const SIDEBAR_WIDTH = "16rem"
29const SIDEBAR_WIDTH_MOBILE = "18rem"
30const SIDEBAR_WIDTH_ICON = "3rem"
31const SIDEBAR_KEYBOARD_SHORTCUT = "b"
32
33type SidebarContextProps = {
34 state: "expanded" | "collapsed"
35 open: boolean
36 setOpen: (open: boolean) => void
37 openMobile: boolean
38 setOpenMobile: (open: boolean) => void
39 isMobile: boolean
40 toggleSidebar: () => void
41}
42
43const SidebarContext = React.createContext<SidebarContextProps | null>(null)
44
45function useSidebar() {
46 const context = React.useContext(SidebarContext)
47 if (!context) {
48 throw new Error("useSidebar must be used within a SidebarProvider.")
49 }
50
51 return context
52}
53
54function SidebarProvider({
55 defaultOpen = true,
56 open: openProp,
57 onOpenChange: setOpenProp,
58 className,
59 style,
60 children,
61 ...props
62}: React.ComponentProps<"div"> & {
63 defaultOpen?: boolean
64 open?: boolean
65 onOpenChange?: (open: boolean) => void
66}) {
67 const isMobile = useIsMobile()
68 const [openMobile, setOpenMobile] = React.useState(false)
69
70 // This is the internal state of the sidebar.
71 // We use openProp and setOpenProp for control from outside the component.
72 const [_open, _setOpen] = React.useState(defaultOpen)
73 const open = openProp ?? _open
74 const setOpen = React.useCallback(
75 (value: boolean | ((value: boolean) => boolean)) => {
76 const openState = typeof value === "function" ? value(open) : value
77 if (setOpenProp) {
78 setOpenProp(openState)
79 } else {
80 _setOpen(openState)
81 }
82
83 // This sets the cookie to keep the sidebar state.
84 document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
85 },
86 [setOpenProp, open]
87 )
88
89 // Helper to toggle the sidebar.
90 const toggleSidebar = React.useCallback(() => {
91 return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
92 }, [isMobile, setOpen, setOpenMobile])
93
94 // Adds a keyboard shortcut to toggle the sidebar.
95 React.useEffect(() => {
96 const handleKeyDown = (event: KeyboardEvent) => {
97 if (
98 event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
99 (event.metaKey || event.ctrlKey)
100 ) {
101 event.preventDefault()
102 toggleSidebar()
103 }
104 }
105
106 window.addEventListener("keydown", handleKeyDown)
107 return () => window.removeEventListener("keydown", handleKeyDown)
108 }, [toggleSidebar])
109
110 // We add a state so that we can do data-state="expanded" or "collapsed".
111 // This makes it easier to style the sidebar with Tailwind classes.
112 const state = open ? "expanded" : "collapsed"
113
114 const contextValue = React.useMemo<SidebarContextProps>(
115 () => ({
116 state,
117 open,
118 setOpen,
119 isMobile,
120 openMobile,
121 setOpenMobile,
122 toggleSidebar,
123 }),
124 [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
125 )
126
127 return (
128 <SidebarContext.Provider value={contextValue}>
129 <TooltipProvider delayDuration={0}>
130 <div
131 data-slot="sidebar-wrapper"
132 style={
133 {
134 "--sidebar-width": SIDEBAR_WIDTH,
135 "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
136 ...style,
137 } as React.CSSProperties
138 }
139 className={cn(
140 "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar",
141 className
142 )}
143 {...props}
144 >
145 {children}
146 </div>
147 </TooltipProvider>
148 </SidebarContext.Provider>
149 )
150}
151
152function Sidebar({
153 side = "left",
154 variant = "sidebar",
155 collapsible = "offcanvas",
156 className,
157 children,
158 ...props
159}: React.ComponentProps<"div"> & {
160 side?: "left" | "right"
161 variant?: "sidebar" | "floating" | "inset"
162 collapsible?: "offcanvas" | "icon" | "none"
163}) {
164 const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
165
166 if (collapsible === "none") {
167 return (
168 <div
169 data-slot="sidebar"
170 className={cn(
171 "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
172 className
173 )}
174 {...props}
175 >
176 {children}
177 </div>
178 )
179 }
180
181 if (isMobile) {
182 return (
183 <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
184 <SheetContent
185 data-sidebar="sidebar"
186 data-slot="sidebar"
187 data-mobile="true"
188 className="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
189 style={
190 {
191 "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
192 } as React.CSSProperties
193 }
194 side={side}
195 >
196 <SheetHeader className="sr-only">
197 <SheetTitle>Sidebar</SheetTitle>
198 <SheetDescription>Displays the mobile sidebar.</SheetDescription>
199 </SheetHeader>
200 <div className="flex h-full w-full flex-col">{children}</div>
201 </SheetContent>
202 </Sheet>
203 )
204 }
205
206 return (
207 <div
208 className="group peer hidden text-sidebar-foreground md:block"
209 data-state={state}
210 data-collapsible={state === "collapsed" ? collapsible : ""}
211 data-variant={variant}
212 data-side={side}
213 data-slot="sidebar"
214 >
215 {/* This is what handles the sidebar gap on desktop */}
216 <div
217 data-slot="sidebar-gap"
218 className={cn(
219 "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
220 "group-data-[collapsible=offcanvas]:w-0",
221 "group-data-[side=right]:rotate-180",
222 variant === "floating" || variant === "inset"
223 ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
224 : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
225 )}
226 />
227 <div
228 data-slot="sidebar-container"
229 className={cn(
230 "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
231 side === "left"
232 ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
233 : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
234 // Adjust the padding for floating and inset variants.
235 variant === "floating" || variant === "inset"
236 ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
237 : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
238 className
239 )}
240 {...props}
241 >
242 <div
243 data-sidebar="sidebar"
244 data-slot="sidebar-inner"
245 className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm"
246 >
247 {children}
248 </div>
249 </div>
250 </div>
251 )
252}
253
254function SidebarTrigger({
255 className,
256 onClick,
257 ...props
258}: React.ComponentProps<typeof Button>) {
259 const { toggleSidebar } = useSidebar()
260
261 return (
262 <Button
263 data-sidebar="trigger"
264 data-slot="sidebar-trigger"
265 variant="ghost"
266 size="icon"
267 className={cn("size-7", className)}
268 onClick={(event) => {
269 onClick?.(event)
270 toggleSidebar()
271 }}
272 {...props}
273 >
274 <PanelLeftIcon />
275 <span className="sr-only">Toggle Sidebar</span>
276 </Button>
277 )
278}
279
280function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
281 const { toggleSidebar } = useSidebar()
282
283 return (
284 <button
285 data-sidebar="rail"
286 data-slot="sidebar-rail"
287 aria-label="Toggle Sidebar"
288 tabIndex={-1}
289 onClick={toggleSidebar}
290 title="Toggle Sidebar"
291 className={cn(
292 "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex",
293 "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
294 "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
295 "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
296 "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
297 "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
298 className
299 )}
300 {...props}
301 />
302 )
303}
304
305function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
306 return (
307 <main
308 data-slot="sidebar-inset"
309 className={cn(
310 "relative flex w-full flex-1 flex-col bg-background",
311 "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
312 className
313 )}
314 {...props}
315 />
316 )
317}
318
319function SidebarInput({
320 className,
321 ...props
322}: React.ComponentProps<typeof Input>) {
323 return (
324 <Input
325 data-slot="sidebar-input"
326 data-sidebar="input"
327 className={cn("h-8 w-full bg-background shadow-none", className)}
328 {...props}
329 />
330 )
331}
332
333function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
334 return (
335 <div
336 data-slot="sidebar-header"
337 data-sidebar="header"
338 className={cn("flex flex-col gap-2 p-2", className)}
339 {...props}
340 />
341 )
342}
343
344function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
345 return (
346 <div
347 data-slot="sidebar-footer"
348 data-sidebar="footer"
349 className={cn("flex flex-col gap-2 p-2", className)}
350 {...props}
351 />
352 )
353}
354
355function SidebarSeparator({
356 className,
357 ...props
358}: React.ComponentProps<typeof Separator>) {
359 return (
360 <Separator
361 data-slot="sidebar-separator"
362 data-sidebar="separator"
363 className={cn("mx-2 w-auto bg-sidebar-border", className)}
364 {...props}
365 />
366 )
367}
368
369function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
370 return (
371 <div
372 data-slot="sidebar-content"
373 data-sidebar="content"
374 className={cn(
375 "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
376 className
377 )}
378 {...props}
379 />
380 )
381}
382
383function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
384 return (
385 <div
386 data-slot="sidebar-group"
387 data-sidebar="group"
388 className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
389 {...props}
390 />
391 )
392}
393
394function SidebarGroupLabel({
395 className,
396 asChild = false,
397 ...props
398}: React.ComponentProps<"div"> & { asChild?: boolean }) {
399 const Comp = asChild ? Slot.Root : "div"
400
401 return (
402 <Comp
403 data-slot="sidebar-group-label"
404 data-sidebar="group-label"
405 className={cn(
406 "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
407 "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
408 className
409 )}
410 {...props}
411 />
412 )
413}
414
415function SidebarGroupAction({
416 className,
417 asChild = false,
418 ...props
419}: React.ComponentProps<"button"> & { asChild?: boolean }) {
420 const Comp = asChild ? Slot.Root : "button"
421
422 return (
423 <Comp
424 data-slot="sidebar-group-action"
425 data-sidebar="group-action"
426 className={cn(
427 "absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
428 // Increases the hit area of the button on mobile.
429 "after:absolute after:-inset-2 md:after:hidden",
430 "group-data-[collapsible=icon]:hidden",
431 className
432 )}
433 {...props}
434 />
435 )
436}
437
438function SidebarGroupContent({
439 className,
440 ...props
441}: React.ComponentProps<"div">) {
442 return (
443 <div
444 data-slot="sidebar-group-content"
445 data-sidebar="group-content"
446 className={cn("w-full text-sm", className)}
447 {...props}
448 />
449 )
450}
451
452function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
453 return (
454 <ul
455 data-slot="sidebar-menu"
456 data-sidebar="menu"
457 className={cn("flex w-full min-w-0 flex-col gap-1", className)}
458 {...props}
459 />
460 )
461}
462
463function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
464 return (
465 <li
466 data-slot="sidebar-menu-item"
467 data-sidebar="menu-item"
468 className={cn("group/menu-item relative", className)}
469 {...props}
470 />
471 )
472}
473
474const sidebarMenuButtonVariants = cva(
475 "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! 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 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
476 {
477 variants: {
478 variant: {
479 default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
480 outline:
481 "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))]",
482 },
483 size: {
484 default: "h-8 text-sm",
485 sm: "h-7 text-xs",
486 lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
487 },
488 },
489 defaultVariants: {
490 variant: "default",
491 size: "default",
492 },
493 }
494)
495
496function SidebarMenuButton({
497 asChild = false,
498 isActive = false,
499 variant = "default",
500 size = "default",
501 tooltip,
502 className,
503 ...props
504}: React.ComponentProps<"button"> & {
505 asChild?: boolean
506 isActive?: boolean
507 tooltip?: string | React.ComponentProps<typeof TooltipContent>
508} & VariantProps<typeof sidebarMenuButtonVariants>) {
509 const Comp = asChild ? Slot.Root : "button"
510 const { isMobile, state } = useSidebar()
511
512 const button = (
513 <Comp
514 data-slot="sidebar-menu-button"
515 data-sidebar="menu-button"
516 data-size={size}
517 data-active={isActive}
518 className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
519 {...props}
520 />
521 )
522
523 if (!tooltip) {
524 return button
525 }
526
527 if (typeof tooltip === "string") {
528 tooltip = {
529 children: tooltip,
530 }
531 }
532
533 return (
534 <Tooltip>
535 <TooltipTrigger asChild>{button}</TooltipTrigger>
536 <TooltipContent
537 side="right"
538 align="center"
539 hidden={state !== "collapsed" || isMobile}
540 {...tooltip}
541 />
542 </Tooltip>
543 )
544}
545
546function SidebarMenuAction({
547 className,
548 asChild = false,
549 showOnHover = false,
550 ...props
551}: React.ComponentProps<"button"> & {
552 asChild?: boolean
553 showOnHover?: boolean
554}) {
555 const Comp = asChild ? Slot.Root : "button"
556
557 return (
558 <Comp
559 data-slot="sidebar-menu-action"
560 data-sidebar="menu-action"
561 className={cn(
562 "absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
563 // Increases the hit area of the button on mobile.
564 "after:absolute after:-inset-2 md:after:hidden",
565 "peer-data-[size=sm]/menu-button:top-1",
566 "peer-data-[size=default]/menu-button:top-1.5",
567 "peer-data-[size=lg]/menu-button:top-2.5",
568 "group-data-[collapsible=icon]:hidden",
569 showOnHover &&
570 "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground data-[state=open]:opacity-100 md:opacity-0",
571 className
572 )}
573 {...props}
574 />
575 )
576}
577
578function SidebarMenuBadge({
579 className,
580 ...props
581}: React.ComponentProps<"div">) {
582 return (
583 <div
584 data-slot="sidebar-menu-badge"
585 data-sidebar="menu-badge"
586 className={cn(
587 "pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none",
588 "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
589 "peer-data-[size=sm]/menu-button:top-1",
590 "peer-data-[size=default]/menu-button:top-1.5",
591 "peer-data-[size=lg]/menu-button:top-2.5",
592 "group-data-[collapsible=icon]:hidden",
593 className
594 )}
595 {...props}
596 />
597 )
598}
599
600function SidebarMenuSkeleton({
601 className,
602 showIcon = false,
603 ...props
604}: React.ComponentProps<"div"> & {
605 showIcon?: boolean
606}) {
607 // Random width between 50 to 90%.
608 const width = React.useMemo(() => {
609 return `${Math.floor(Math.random() * 40) + 50}%`
610 }, [])
611
612 return (
613 <div
614 data-slot="sidebar-menu-skeleton"
615 data-sidebar="menu-skeleton"
616 className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
617 {...props}
618 >
619 {showIcon && (
620 <Skeleton
621 className="size-4 rounded-md"
622 data-sidebar="menu-skeleton-icon"
623 />
624 )}
625 <Skeleton
626 className="h-4 max-w-(--skeleton-width) flex-1"
627 data-sidebar="menu-skeleton-text"
628 style={
629 {
630 "--skeleton-width": width,
631 } as React.CSSProperties
632 }
633 />
634 </div>
635 )
636}
637
638function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
639 return (
640 <ul
641 data-slot="sidebar-menu-sub"
642 data-sidebar="menu-sub"
643 className={cn(
644 "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",
645 "group-data-[collapsible=icon]:hidden",
646 className
647 )}
648 {...props}
649 />
650 )
651}
652
653function SidebarMenuSubItem({
654 className,
655 ...props
656}: React.ComponentProps<"li">) {
657 return (
658 <li
659 data-slot="sidebar-menu-sub-item"
660 data-sidebar="menu-sub-item"
661 className={cn("group/menu-sub-item relative", className)}
662 {...props}
663 />
664 )
665}
666
667function SidebarMenuSubButton({
668 asChild = false,
669 size = "md",
670 isActive = false,
671 className,
672 ...props
673}: React.ComponentProps<"a"> & {
674 asChild?: boolean
675 size?: "sm" | "md"
676 isActive?: boolean
677}) {
678 const Comp = asChild ? Slot.Root : "a"
679
680 return (
681 <Comp
682 data-slot="sidebar-menu-sub-button"
683 data-sidebar="menu-sub-button"
684 data-size={size}
685 data-active={isActive}
686 className={cn(
687 "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden 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 [&>svg]:text-sidebar-accent-foreground",
688 "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
689 size === "sm" && "text-xs",
690 size === "md" && "text-sm",
691 "group-data-[collapsible=icon]:hidden",
692 className
693 )}
694 {...props}
695 />
696 )
697}
698
699export {
700 Sidebar,
701 SidebarContent,
702 SidebarFooter,
703 SidebarGroup,
704 SidebarGroupAction,
705 SidebarGroupContent,
706 SidebarGroupLabel,
707 SidebarHeader,
708 SidebarInput,
709 SidebarInset,
710 SidebarMenu,
711 SidebarMenuAction,
712 SidebarMenuBadge,
713 SidebarMenuButton,
714 SidebarMenuItem,
715 SidebarMenuSkeleton,
716 SidebarMenuSub,
717 SidebarMenuSubButton,
718 SidebarMenuSubItem,
719 SidebarProvider,
720 SidebarRail,
721 SidebarSeparator,
722 SidebarTrigger,
723 useSidebar,
724}
packages/ui/src/components/skeleton.tsx+13−0
@@ -0,0 +1,13 @@
1import { cn } from "@executor/ui/lib/utils"
2
3function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
4 return (
5 <div
6 data-slot="skeleton"
7 className={cn("animate-pulse rounded-md bg-accent", className)}
8 {...props}
9 />
10 )
11}
12
13export { Skeleton }
packages/ui/src/components/slider.tsx+61−0
@@ -0,0 +1,61 @@
1import * as React from "react"
2import { Slider as SliderPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Slider({
7 className,
8 defaultValue,
9 value,
10 min = 0,
11 max = 100,
12 ...props
13}: React.ComponentProps<typeof SliderPrimitive.Root>) {
14 const _values = React.useMemo(
15 () =>
16 Array.isArray(value)
17 ? value
18 : Array.isArray(defaultValue)
19 ? defaultValue
20 : [min, max],
21 [value, defaultValue, min, max]
22 )
23
24 return (
25 <SliderPrimitive.Root
26 data-slot="slider"
27 defaultValue={defaultValue}
28 value={value}
29 min={min}
30 max={max}
31 className={cn(
32 "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
33 className
34 )}
35 {...props}
36 >
37 <SliderPrimitive.Track
38 data-slot="slider-track"
39 className={cn(
40 "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
41 )}
42 >
43 <SliderPrimitive.Range
44 data-slot="slider-range"
45 className={cn(
46 "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
47 )}
48 />
49 </SliderPrimitive.Track>
50 {Array.from({ length: _values.length }, (_, index) => (
51 <SliderPrimitive.Thumb
52 data-slot="slider-thumb"
53 key={index}
54 className="block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
55 />
56 ))}
57 </SliderPrimitive.Root>
58 )
59}
60
61export { Slider }
packages/ui/src/components/sonner.tsx+40−0
@@ -0,0 +1,40 @@
1"use client"
2
3import {
4 CircleCheckIcon,
5 InfoIcon,
6 Loader2Icon,
7 OctagonXIcon,
8 TriangleAlertIcon,
9} from "lucide-react"
10import { useTheme } from "next-themes"
11import { Toaster as Sonner, type ToasterProps } from "sonner"
12
13const Toaster = ({ ...props }: ToasterProps) => {
14 const { theme = "system" } = useTheme()
15
16 return (
17 <Sonner
18 theme={theme as ToasterProps["theme"]}
19 className="toaster group"
20 icons={{
21 success: <CircleCheckIcon className="size-4" />,
22 info: <InfoIcon className="size-4" />,
23 warning: <TriangleAlertIcon className="size-4" />,
24 error: <OctagonXIcon className="size-4" />,
25 loading: <Loader2Icon className="size-4 animate-spin" />,
26 }}
27 style={
28 {
29 "--normal-bg": "var(--popover)",
30 "--normal-text": "var(--popover-foreground)",
31 "--normal-border": "var(--border)",
32 "--border-radius": "var(--radius)",
33 } as React.CSSProperties
34 }
35 {...props}
36 />
37 )
38}
39
40export { Toaster }
packages/ui/src/components/spinner.tsx+16−0
@@ -0,0 +1,16 @@
1import { Loader2Icon } from "lucide-react"
2
3import { cn } from "@executor/ui/lib/utils"
4
5function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
6 return (
7 <Loader2Icon
8 role="status"
9 aria-label="Loading"
10 className={cn("size-4 animate-spin", className)}
11 {...props}
12 />
13 )
14}
15
16export { Spinner }
packages/ui/src/components/switch.tsx+33−0
@@ -0,0 +1,33 @@
1import * as React from "react"
2import { Switch as SwitchPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function Switch({
7 className,
8 size = "default",
9 ...props
10}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
11 size?: "sm" | "default"
12}) {
13 return (
14 <SwitchPrimitive.Root
15 data-slot="switch"
16 data-size={size}
17 className={cn(
18 "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
19 className
20 )}
21 {...props}
22 >
23 <SwitchPrimitive.Thumb
24 data-slot="switch-thumb"
25 className={cn(
26 "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
27 )}
28 />
29 </SwitchPrimitive.Root>
30 )
31}
32
33export { Switch }
packages/ui/src/components/table.tsx+116−0
@@ -0,0 +1,116 @@
1"use client"
2
3import * as React from "react"
4
5import { cn } from "@executor/ui/lib/utils"
6
7function Table({ className, ...props }: React.ComponentProps<"table">) {
8 return (
9 <div
10 data-slot="table-container"
11 className="relative w-full overflow-x-auto"
12 >
13 <table
14 data-slot="table"
15 className={cn("w-full caption-bottom text-sm", className)}
16 {...props}
17 />
18 </div>
19 )
20}
21
22function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
23 return (
24 <thead
25 data-slot="table-header"
26 className={cn("[&_tr]:border-b", className)}
27 {...props}
28 />
29 )
30}
31
32function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
33 return (
34 <tbody
35 data-slot="table-body"
36 className={cn("[&_tr:last-child]:border-0", className)}
37 {...props}
38 />
39 )
40}
41
42function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
43 return (
44 <tfoot
45 data-slot="table-footer"
46 className={cn(
47 "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
48 className
49 )}
50 {...props}
51 />
52 )
53}
54
55function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
56 return (
57 <tr
58 data-slot="table-row"
59 className={cn(
60 "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
61 className
62 )}
63 {...props}
64 />
65 )
66}
67
68function TableHead({ className, ...props }: React.ComponentProps<"th">) {
69 return (
70 <th
71 data-slot="table-head"
72 className={cn(
73 "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
74 className
75 )}
76 {...props}
77 />
78 )
79}
80
81function TableCell({ className, ...props }: React.ComponentProps<"td">) {
82 return (
83 <td
84 data-slot="table-cell"
85 className={cn(
86 "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
87 className
88 )}
89 {...props}
90 />
91 )
92}
93
94function TableCaption({
95 className,
96 ...props
97}: React.ComponentProps<"caption">) {
98 return (
99 <caption
100 data-slot="table-caption"
101 className={cn("mt-4 text-sm text-muted-foreground", className)}
102 {...props}
103 />
104 )
105}
106
107export {
108 Table,
109 TableHeader,
110 TableBody,
111 TableFooter,
112 TableHead,
113 TableRow,
114 TableCell,
115 TableCaption,
116}
packages/ui/src/components/tabs.tsx+89−0
@@ -0,0 +1,89 @@
1import * as React from "react"
2import { cva, type VariantProps } from "class-variance-authority"
3import { Tabs as TabsPrimitive } from "radix-ui"
4
5import { cn } from "@executor/ui/lib/utils"
6
7function Tabs({
8 className,
9 orientation = "horizontal",
10 ...props
11}: React.ComponentProps<typeof TabsPrimitive.Root>) {
12 return (
13 <TabsPrimitive.Root
14 data-slot="tabs"
15 data-orientation={orientation}
16 orientation={orientation}
17 className={cn(
18 "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
19 className
20 )}
21 {...props}
22 />
23 )
24}
25
26const tabsListVariants = cva(
27 "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none",
28 {
29 variants: {
30 variant: {
31 default: "bg-muted",
32 line: "gap-1 bg-transparent",
33 },
34 },
35 defaultVariants: {
36 variant: "default",
37 },
38 }
39)
40
41function TabsList({
42 className,
43 variant = "default",
44 ...props
45}: React.ComponentProps<typeof TabsPrimitive.List> &
46 VariantProps<typeof tabsListVariants>) {
47 return (
48 <TabsPrimitive.List
49 data-slot="tabs-list"
50 data-variant={variant}
51 className={cn(tabsListVariants({ variant }), className)}
52 {...props}
53 />
54 )
55}
56
57function TabsTrigger({
58 className,
59 ...props
60}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
61 return (
62 <TabsPrimitive.Trigger
63 data-slot="tabs-trigger"
64 className={cn(
65 "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
66 "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
67 "data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground",
68 "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
69 className
70 )}
71 {...props}
72 />
73 )
74}
75
76function TabsContent({
77 className,
78 ...props
79}: React.ComponentProps<typeof TabsPrimitive.Content>) {
80 return (
81 <TabsPrimitive.Content
82 data-slot="tabs-content"
83 className={cn("flex-1 outline-none", className)}
84 {...props}
85 />
86 )
87}
88
89export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
packages/ui/src/components/textarea.tsx+18−0
@@ -0,0 +1,18 @@
1import * as React from "react"
2
3import { cn } from "@executor/ui/lib/utils"
4
5function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
6 return (
7 <textarea
8 data-slot="textarea"
9 className={cn(
10 "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
11 className
12 )}
13 {...props}
14 />
15 )
16}
17
18export { Textarea }
packages/ui/src/components/toggle-group.tsx+83−0
@@ -0,0 +1,83 @@
1"use client"
2
3import * as React from "react"
4import { type VariantProps } from "class-variance-authority"
5import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8import { toggleVariants } from "@executor/ui/components/toggle"
9
10const ToggleGroupContext = React.createContext<
11 VariantProps<typeof toggleVariants> & {
12 spacing?: number
13 }
14>({
15 size: "default",
16 variant: "default",
17 spacing: 0,
18})
19
20function ToggleGroup({
21 className,
22 variant,
23 size,
24 spacing = 0,
25 children,
26 ...props
27}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
28 VariantProps<typeof toggleVariants> & {
29 spacing?: number
30 }) {
31 return (
32 <ToggleGroupPrimitive.Root
33 data-slot="toggle-group"
34 data-variant={variant}
35 data-size={size}
36 data-spacing={spacing}
37 style={{ "--gap": spacing } as React.CSSProperties}
38 className={cn(
39 "group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs",
40 className
41 )}
42 {...props}
43 >
44 <ToggleGroupContext.Provider value={{ variant, size, spacing }}>
45 {children}
46 </ToggleGroupContext.Provider>
47 </ToggleGroupPrimitive.Root>
48 )
49}
50
51function ToggleGroupItem({
52 className,
53 children,
54 variant,
55 size,
56 ...props
57}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
58 VariantProps<typeof toggleVariants>) {
59 const context = React.useContext(ToggleGroupContext)
60
61 return (
62 <ToggleGroupPrimitive.Item
63 data-slot="toggle-group-item"
64 data-variant={context.variant || variant}
65 data-size={context.size || size}
66 data-spacing={context.spacing}
67 className={cn(
68 toggleVariants({
69 variant: context.variant || variant,
70 size: context.size || size,
71 }),
72 "w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10",
73 "data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l",
74 className
75 )}
76 {...props}
77 >
78 {children}
79 </ToggleGroupPrimitive.Item>
80 )
81}
82
83export { ToggleGroup, ToggleGroupItem }
packages/ui/src/components/toggle.tsx+47−0
@@ -0,0 +1,47 @@
1"use client"
2
3import * as React from "react"
4import { cva, type VariantProps } from "class-variance-authority"
5import { Toggle as TogglePrimitive } from "radix-ui"
6
7import { cn } from "@executor/ui/lib/utils"
8
9const toggleVariants = cva(
10 "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
11 {
12 variants: {
13 variant: {
14 default: "bg-transparent",
15 outline:
16 "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
17 },
18 size: {
19 default: "h-9 min-w-9 px-2",
20 sm: "h-8 min-w-8 px-1.5",
21 lg: "h-10 min-w-10 px-2.5",
22 },
23 },
24 defaultVariants: {
25 variant: "default",
26 size: "default",
27 },
28 }
29)
30
31function Toggle({
32 className,
33 variant,
34 size,
35 ...props
36}: React.ComponentProps<typeof TogglePrimitive.Root> &
37 VariantProps<typeof toggleVariants>) {
38 return (
39 <TogglePrimitive.Root
40 data-slot="toggle"
41 className={cn(toggleVariants({ variant, size, className }))}
42 {...props}
43 />
44 )
45}
46
47export { Toggle, toggleVariants }
packages/ui/src/components/tooltip.tsx+55−0
@@ -0,0 +1,55 @@
1import * as React from "react"
2import { Tooltip as TooltipPrimitive } from "radix-ui"
3
4import { cn } from "@executor/ui/lib/utils"
5
6function TooltipProvider({
7 delayDuration = 0,
8 ...props
9}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
10 return (
11 <TooltipPrimitive.Provider
12 data-slot="tooltip-provider"
13 delayDuration={delayDuration}
14 {...props}
15 />
16 )
17}
18
19function Tooltip({
20 ...props
21}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
22 return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
23}
24
25function TooltipTrigger({
26 ...props
27}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
28 return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
29}
30
31function TooltipContent({
32 className,
33 sideOffset = 0,
34 children,
35 ...props
36}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
37 return (
38 <TooltipPrimitive.Portal>
39 <TooltipPrimitive.Content
40 data-slot="tooltip-content"
41 sideOffset={sideOffset}
42 className={cn(
43 "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
44 className
45 )}
46 {...props}
47 >
48 {children}
49 <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
50 </TooltipPrimitive.Content>
51 </TooltipPrimitive.Portal>
52 )
53}
54
55export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
packages/ui/src/hooks/use-mobile.ts+19−0
@@ -0,0 +1,19 @@
1import * as React from "react"
2
3const MOBILE_BREAKPOINT = 768
4
5export function useIsMobile() {
6 const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
8 React.useEffect(() => {
9 const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10 const onChange = () => {
11 setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12 }
13 mql.addEventListener("change", onChange)
14 setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15 return () => mql.removeEventListener("change", onChange)
16 }, [])
17
18 return !!isMobile
19}
packages/ui/src/lib/utils.ts+6−0
@@ -0,0 +1,6 @@
1import { type ClassValue, clsx } from "clsx";
2import { twMerge } from "tailwind-merge";
3
4export function cn(...inputs: ClassValue[]) {
5 return twMerge(clsx(inputs));
6}
packages/ui/src/styles/globals.cssrenamed from apps/web/src/styles.css+27−2
@@ -1,7 +1,11 @@
1@import "tailwindcss";1@import "tailwindcss";
2 2
3@source "../../../packages/clients/react/src/**/*.{ts,tsx}";3@custom-variant dark (&:is(.dark *));
4@source "../../../packages/plugins/openapi/src/react/**/*.{ts,tsx}";4
5@source "../components/**/*.{ts,tsx}";
6@source "../../../../apps/web/src/**/*.{ts,tsx}";
7@source "../../../clients/react/src/**/*.{ts,tsx}";
8@source "../../../plugins/openapi/src/react/**/*.{ts,tsx}";
5 9
6@theme inline {10@theme inline {
7 --font-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif;11 --font-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif;
@@ -34,6 +38,11 @@ · 26 unmodified lines
34 --radius-md: calc(var(--radius) * 0.8);38 --radius-md: calc(var(--radius) * 0.8);
35 --radius-lg: var(--radius);39 --radius-lg: var(--radius);
36 --radius-xl: calc(var(--radius) * 1.4);40 --radius-xl: calc(var(--radius) * 1.4);
41 --color-sidebar-ring: var(--sidebar-ring);
42 --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
43 --color-sidebar-accent: var(--sidebar-accent);
44 --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
45 --color-sidebar-primary: var(--sidebar-primary);
37}46}
38 47
39/* ——— Light theme ——— */48/* ——— Light theme ——— */
@@ -65,6 +74,11 @@ · 25 unmodified lines
65 74
66 --scrollbar-thumb: oklch(0.78 0.005 260);75 --scrollbar-thumb: oklch(0.78 0.005 260);
67 --scrollbar-thumb-hover: oklch(0.68 0.005 260);76 --scrollbar-thumb-hover: oklch(0.68 0.005 260);
77 --sidebar-primary: hsl(240 5.9% 10%);
78 --sidebar-primary-foreground: hsl(0 0% 98%);
79 --sidebar-accent: hsl(240 4.8% 95.9%);
80 --sidebar-accent-foreground: hsl(240 5.9% 10%);
81 --sidebar-ring: hsl(217.2 91.2% 59.8%);
68}82}
69 83
70/* ——— Dark theme ——— */84/* ——— Dark theme ——— */
@@ -126,3 +140,14 @@ · 55 unmodified lines
126 background: var(--scrollbar-thumb-hover);140 background: var(--scrollbar-thumb-hover);
127 }141 }
128}142}
143
144.dark {
145 --sidebar: hsl(240 5.9% 10%);
146 --sidebar-foreground: hsl(240 4.8% 95.9%);
147 --sidebar-primary: hsl(224.3 76.3% 48%);
148 --sidebar-primary-foreground: hsl(0 0% 100%);
149 --sidebar-accent: hsl(240 3.7% 15.9%);
150 --sidebar-accent-foreground: hsl(240 4.8% 95.9%);
151 --sidebar-border: hsl(240 3.7% 15.9%);
152 --sidebar-ring: hsl(217.2 91.2% 59.8%);
153}
packages/ui/tsconfig.json+25−0
@@ -0,0 +1,25 @@
1{
2 "compilerOptions": {
3 "target": "ESNext",
4 "module": "ESNext",
5 "moduleResolution": "bundler",
6 "strict": true,
7 "esModuleInterop": true,
8 "skipLibCheck": true,
9 "outDir": "dist",
10 "rootDir": "src",
11 "declaration": true,
12 "declarationMap": true,
13 "sourceMap": true,
14 "jsx": "react-jsx",
15 "paths": {
16 "@executor/ui/*": ["./src/*"]
17 },
18 "plugins": [
19 {
20 "name": "@effect/language-service"
21 }
22 ]
23 },
24 "include": ["src"]
25}