@arqel-dev/ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/ArqelEditPage-7OFWPULE.js +12 -0
  2. package/dist/{ArqelEditPage-RRYFYOTC.js.map → ArqelEditPage-7OFWPULE.js.map} +1 -1
  3. package/dist/ArqelIndexPage-ZAVCCM6V.js +14 -0
  4. package/dist/{ArqelIndexPage-J2EUV2PI.js.map → ArqelIndexPage-ZAVCCM6V.js.map} +1 -1
  5. package/dist/ArqelNotificationsPage-MBJBYFHW.js +6 -0
  6. package/dist/ArqelNotificationsPage-MBJBYFHW.js.map +1 -0
  7. package/dist/{UserMenu-B5XbC_Gy.d.ts → UserMenu-QlwvvZRU.d.ts} +2 -1
  8. package/dist/action.js +2 -1
  9. package/dist/{chunk-SK6H7ARE.js → chunk-3E66JNQO.js} +3 -18
  10. package/dist/chunk-3E66JNQO.js.map +1 -0
  11. package/dist/chunk-53J74IYR.js +22 -0
  12. package/dist/chunk-53J74IYR.js.map +1 -0
  13. package/dist/chunk-6YGRTXEL.js +87 -0
  14. package/dist/chunk-6YGRTXEL.js.map +1 -0
  15. package/dist/{chunk-SLLTFOOS.js → chunk-7NGUPQON.js} +5 -192
  16. package/dist/chunk-7NGUPQON.js.map +1 -0
  17. package/dist/chunk-CH7YLELO.js +137 -0
  18. package/dist/chunk-CH7YLELO.js.map +1 -0
  19. package/dist/{chunk-K7QY56XN.js → chunk-D2MUCHFN.js} +5 -119
  20. package/dist/chunk-D2MUCHFN.js.map +1 -0
  21. package/dist/chunk-DO3PRGVV.js +198 -0
  22. package/dist/chunk-DO3PRGVV.js.map +1 -0
  23. package/dist/{chunk-X4ZFKOPX.js → chunk-DOQUHQND.js} +4 -4
  24. package/dist/{chunk-X4ZFKOPX.js.map → chunk-DOQUHQND.js.map} +1 -1
  25. package/dist/{chunk-X2X6YDOX.js → chunk-EXA6DWLB.js} +11 -3
  26. package/dist/chunk-EXA6DWLB.js.map +1 -0
  27. package/dist/{chunk-S5UNPCMQ.js → chunk-JKD6SE75.js} +3 -269
  28. package/dist/chunk-JKD6SE75.js.map +1 -0
  29. package/dist/{chunk-EG2DASKR.js → chunk-KGAY2AZH.js} +4 -3
  30. package/dist/chunk-KGAY2AZH.js.map +1 -0
  31. package/dist/chunk-U4MPY2XT.js +91 -0
  32. package/dist/chunk-U4MPY2XT.js.map +1 -0
  33. package/dist/chunk-WKIYS2FQ.js +509 -0
  34. package/dist/chunk-WKIYS2FQ.js.map +1 -0
  35. package/dist/chunk-XK2P6CSK.js +8 -0
  36. package/dist/chunk-XK2P6CSK.js.map +1 -0
  37. package/dist/chunk-YEPQWAD6.js +275 -0
  38. package/dist/chunk-YEPQWAD6.js.map +1 -0
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.js +11 -7
  41. package/dist/pages.d.ts +26 -1
  42. package/dist/pages.js +14 -8
  43. package/dist/pages.js.map +1 -1
  44. package/dist/primitives.js +3 -2
  45. package/dist/resource.js +3 -2
  46. package/dist/shell.d.ts +37 -3
  47. package/dist/shell.js +166 -7
  48. package/dist/shell.js.map +1 -1
  49. package/dist/table.js +2 -1
  50. package/dist/utility.js +2 -1
  51. package/dist/utils.d.ts +16 -1
  52. package/dist/utils.js +1 -0
  53. package/package.json +6 -6
  54. package/dist/ArqelEditPage-RRYFYOTC.js +0 -8
  55. package/dist/ArqelIndexPage-J2EUV2PI.js +0 -12
  56. package/dist/chunk-EG2DASKR.js.map +0 -1
  57. package/dist/chunk-K7QY56XN.js.map +0 -1
  58. package/dist/chunk-R4BOUU6Y.js +0 -55
  59. package/dist/chunk-R4BOUU6Y.js.map +0 -1
  60. package/dist/chunk-S5UNPCMQ.js.map +0 -1
  61. package/dist/chunk-SK6H7ARE.js.map +0 -1
  62. package/dist/chunk-SLLTFOOS.js.map +0 -1
  63. package/dist/chunk-X2X6YDOX.js.map +0 -1
  64. package/dist/chunk-YQ6KXR3U.js +0 -55
  65. package/dist/chunk-YQ6KXR3U.js.map +0 -1
package/dist/shell.js CHANGED
@@ -1,14 +1,173 @@
1
- export { AppShell, Footer, MainContent, Sidebar, Topbar, UserMenu } from './chunk-X2X6YDOX.js';
1
+ import { isSameOriginRelativeUrl } from './chunk-XK2P6CSK.js';
2
+ export { AppShell, Footer, MainContent, Sidebar, Topbar, UserMenu } from './chunk-EXA6DWLB.js';
2
3
  import './chunk-HNUUZEOL.js';
3
- import './chunk-R4BOUU6Y.js';
4
+ import { Badge } from './chunk-U4MPY2XT.js';
4
5
  import './chunk-RMPOR2YZ.js';
5
- import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-VKZY6J6G.js';
6
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from './chunk-VKZY6J6G.js';
6
7
  import { Button } from './chunk-H23VX3RR.js';
7
- import './chunk-B7ULUJVO.js';
8
+ import { cn } from './chunk-B7ULUJVO.js';
8
9
  import { useArqelTranslations } from '@arqel-dev/react/utils';
9
- import { router } from '@inertiajs/react';
10
- import { jsxs, jsx } from 'react/jsx-runtime';
10
+ import { Link, usePage, router } from '@inertiajs/react';
11
+ import { Bell, User, Mail, AlertTriangle, Info, Check } from 'lucide-react';
12
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
13
 
14
+ var NOTIFICATION_ICONS = {
15
+ bell: Bell,
16
+ check: Check,
17
+ info: Info,
18
+ alert: AlertTriangle,
19
+ mail: Mail,
20
+ user: User
21
+ };
22
+ function readTitle(item) {
23
+ const title = item.data["title"];
24
+ if (typeof title === "string" && title.trim()) return title;
25
+ return item.type;
26
+ }
27
+ function readBody(item) {
28
+ const body = item.data["body"] ?? item.data["message"];
29
+ return typeof body === "string" && body.trim() ? body : void 0;
30
+ }
31
+ function readActionUrl(item) {
32
+ const url = item.data["action_url"];
33
+ return typeof url === "string" && isSameOriginRelativeUrl(url) ? url : void 0;
34
+ }
35
+ function readIcon(item) {
36
+ const icon = item.data["icon"];
37
+ if (typeof icon === "string" && icon in NOTIFICATION_ICONS) {
38
+ return NOTIFICATION_ICONS[icon] ?? Bell;
39
+ }
40
+ return Bell;
41
+ }
42
+ function NotificationList({
43
+ items,
44
+ emptyLabel,
45
+ onItemClick
46
+ }) {
47
+ if (items.length === 0) {
48
+ return /* @__PURE__ */ jsx("div", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: emptyLabel });
49
+ }
50
+ return /* @__PURE__ */ jsx("div", { className: "flex max-h-80 flex-col gap-0.5 overflow-y-auto", children: items.map((item) => {
51
+ const title = readTitle(item);
52
+ const body = readBody(item);
53
+ const actionUrl = readActionUrl(item);
54
+ const unread = item.read_at === null;
55
+ const Icon = readIcon(item);
56
+ const itemContent = /* @__PURE__ */ jsxs(Fragment, { children: [
57
+ /* @__PURE__ */ jsx(
58
+ "span",
59
+ {
60
+ "aria-hidden": "true",
61
+ className: cn(
62
+ "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full",
63
+ unread ? "bg-primary" : "bg-transparent"
64
+ )
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }),
68
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
69
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: title }),
70
+ body && /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: body })
71
+ ] })
72
+ ] });
73
+ const itemClassName = cn(
74
+ "flex w-full items-start gap-2 rounded-sm px-2 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground",
75
+ unread && "bg-accent/50"
76
+ );
77
+ return actionUrl ? /* @__PURE__ */ jsx(
78
+ Link,
79
+ {
80
+ href: actionUrl,
81
+ onClick: () => onItemClick(item),
82
+ className: itemClassName,
83
+ children: itemContent
84
+ },
85
+ item.id
86
+ ) : /* @__PURE__ */ jsx(
87
+ "button",
88
+ {
89
+ type: "button",
90
+ onClick: () => onItemClick(item),
91
+ className: itemClassName,
92
+ children: itemContent
93
+ },
94
+ item.id
95
+ );
96
+ }) });
97
+ }
98
+ function markRead(id) {
99
+ router.post(
100
+ `/admin/notifications/${id}/read`,
101
+ {},
102
+ { preserveScroll: true, only: ["notifications"] }
103
+ );
104
+ }
105
+ function markAllRead() {
106
+ router.post(
107
+ "/admin/notifications/read-all",
108
+ {},
109
+ { preserveScroll: true, only: ["notifications"] }
110
+ );
111
+ }
112
+ function NotificationBell({ className }) {
113
+ const t = useArqelTranslations();
114
+ const { notifications } = usePage().props;
115
+ const unreadCount = notifications?.unread_count ?? 0;
116
+ const recent = notifications?.recent ?? [];
117
+ const handleItemClick = (item) => {
118
+ if (item.read_at === null) markRead(item.id);
119
+ };
120
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
121
+ /* @__PURE__ */ jsxs(
122
+ DropdownMenuTrigger,
123
+ {
124
+ "aria-label": t("arqel.notifications.title", "Notifications"),
125
+ className: cn(
126
+ "relative inline-flex h-9 w-9 items-center justify-center rounded-md hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
127
+ className
128
+ ),
129
+ children: [
130
+ /* @__PURE__ */ jsx(Bell, { "aria-hidden": "true", className: "h-4 w-4 text-muted-foreground" }),
131
+ unreadCount > 0 && /* @__PURE__ */ jsx(
132
+ Badge,
133
+ {
134
+ variant: "destructive",
135
+ className: "absolute -right-1 -top-1 h-4 min-w-4 justify-center px-1 text-[10px] leading-none",
136
+ children: unreadCount
137
+ }
138
+ )
139
+ ]
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-80", children: [
143
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-1.5", children: [
144
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "p-0 font-medium", children: t("arqel.notifications.title", "Notifications") }),
145
+ unreadCount > 0 && /* @__PURE__ */ jsx(
146
+ DropdownMenuItem,
147
+ {
148
+ className: "w-auto justify-end p-0 text-xs text-muted-foreground hover:text-foreground",
149
+ onSelect: (event) => {
150
+ event.preventDefault();
151
+ markAllRead();
152
+ },
153
+ children: t("arqel.notifications.mark_all_read", "Mark all as read")
154
+ }
155
+ )
156
+ ] }),
157
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
158
+ /* @__PURE__ */ jsx(
159
+ NotificationList,
160
+ {
161
+ items: recent,
162
+ emptyLabel: t("arqel.notifications.empty", "No notifications"),
163
+ onItemClick: handleItemClick
164
+ }
165
+ ),
166
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
167
+ /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, className: "justify-center text-sm", children: /* @__PURE__ */ jsx(Link, { href: "/admin/notifications", children: t("arqel.notifications.view_all", "View all") }) })
168
+ ] })
169
+ ] });
170
+ }
12
171
  var DEFAULT_SWITCH_URL = (id) => `/admin/tenants/${id}/switch`;
13
172
  function TenantSwitcher({
14
173
  current,
@@ -54,6 +213,6 @@ function TenantSwitcher({
54
213
  ] });
55
214
  }
56
215
 
57
- export { TenantSwitcher };
216
+ export { NotificationBell, NotificationList, TenantSwitcher };
58
217
  //# sourceMappingURL=shell.js.map
59
218
  //# sourceMappingURL=shell.js.map
package/dist/shell.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/TenantSwitcher.tsx"],"names":[],"mappings":";;;;;;;;;;;AAkCA,IAAM,kBAAA,GAAqB,CAAC,EAAA,KAAgC,CAAA,eAAA,EAAkB,EAAE,CAAA,OAAA,CAAA;AAEzE,SAAS,cAAA,CAAe;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAC1C,EAAA,MAAM,IAAI,oBAAA,EAAqB;AAC/B,EAAA,IAAI,CAAC,OAAA,IAAW,SAAA,CAAU,MAAA,IAAU,GAAG,OAAO,IAAA;AAE9C,EAAA,MAAM,WAAW,SAAA,IAAa,kBAAA;AAC9B,EAAA,MAAM,WAAW,CAAC,MAAA,KAChB,OAAO,IAAA,EAAM,IAAA,KACT,MAAA,CAAO,IAAA,GACP,EAAE,sBAAA,EAAwB,CAAA,OAAA,EAAU,OAAO,EAAE,CAAA,CAAA,EAAI,EAAE,EAAA,EAAI,MAAA,CAAO,IAAI,CAAA;AACxE,EAAA,MAAM,YAAA,GAAe,SAAS,OAAO,CAAA;AAErC,EAAA,4BACG,YAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,SAAO,IAAA,EAC1B,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,OAAA;AAAA,QACR,IAAA,EAAK,IAAA;AAAA,QACL,aAAA,EAAY,yBAAA;AAAA,QACZ,YAAA,EAAY,CAAA,CAAE,0BAAA,EAA4B,CAAA,wBAAA,EAA2B,YAAY,CAAA,CAAA,CAAA,EAAK;AAAA,UACpF,MAAA,EAAQ;AAAA,SACT,CAAA;AAAA,QAEA,QAAA,EAAA;AAAA;AAAA,KACH,EACF,CAAA;AAAA,wBACC,mBAAA,EAAA,EAAoB,KAAA,EAAM,OACxB,QAAA,EAAA,SAAA,CAAU,GAAA,CAAI,CAAC,MAAA,KAAW;AACzB,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,EAAA,KAAO,OAAA,CAAQ,EAAA;AACxC,MAAA,uBACE,IAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UAEC,aAAA,EAAa,CAAA,uBAAA,EAA0B,MAAA,CAAO,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAAA,UACxD,QAAA,EAAU,SAAA;AAAA,UACV,UAAU,MAAM;AACd,YAAA,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA,EAAG,EAAC,EAAG,EAAE,cAAA,EAAgB,IAAA,EAAM,CAAA;AAAA,UAC/D,CAAA;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,QAAA,CAAS,MAAM,CAAA;AAAA,YACf,YAAY,SAAA,GAAO;AAAA;AAAA,SAAA;AAAA,QARf,MAAA,CAAO,OAAO,EAAE;AAAA,OASvB;AAAA,IAEJ,CAAC,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ","file":"shell.js","sourcesContent":["/**\n * `<TenantSwitcher>` — dropdown that lists tenants the user can\n * access and dispatches `POST /admin/tenants/{id}/switch` via\n * Inertia router. Renders nothing when there is no current tenant\n * or the user only has access to one tenant.\n *\n * Mounts in the `tenantSwitcher` slot of `<Topbar>`. The current\n * tenant is read from `props.tenant.current` shared by the\n * server-side `HandleArqelInertiaRequests`; available tenants\n * come from the same payload.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { TenantSummary } from '@arqel-dev/types/tenant';\nimport { router } from '@inertiajs/react';\nimport type { JSX } from 'react';\nimport { Button } from '../action/Button.js';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../shadcn/ui/dropdown-menu.js';\n\nexport interface TenantSwitcherProps {\n current: TenantSummary | null;\n available: ReadonlyArray<TenantSummary>;\n /**\n * Path template for switching; defaults to\n * `/admin/tenants/{id}/switch`.\n */\n switchUrl?: (tenantId: string | number) => string;\n}\n\nconst DEFAULT_SWITCH_URL = (id: string | number): string => `/admin/tenants/${id}/switch`;\n\nexport function TenantSwitcher({\n current,\n available,\n switchUrl,\n}: TenantSwitcherProps): JSX.Element | null {\n const t = useArqelTranslations();\n if (!current || available.length <= 1) return null;\n\n const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;\n const labelFor = (tenant: TenantSummary): string =>\n tenant.name?.trim()\n ? tenant.name\n : t('arqel.tenant.unnamed', `Tenant ${tenant.id}`, { id: tenant.id });\n const currentLabel = labelFor(current);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"tenant-switcher-trigger\"\n aria-label={t('arqel.aria.tenant_switch', `Switch tenant (current: ${currentLabel})`, {\n tenant: currentLabel,\n })}\n >\n {currentLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {available.map((tenant) => {\n const isCurrent = tenant.id === current.id;\n return (\n <DropdownMenuItem\n key={String(tenant.id)}\n data-testid={`tenant-switcher-option-${String(tenant.id)}`}\n disabled={isCurrent}\n onSelect={() => {\n router.post(buildUrl(tenant.id), {}, { preserveScroll: true });\n }}\n >\n {labelFor(tenant)}\n {isCurrent ? ' ✓' : ''}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/NotificationList.tsx","../src/shell/NotificationBell.tsx","../src/shell/TenantSwitcher.tsx"],"names":["jsxs","jsx","Bell","Link","useArqelTranslations","router"],"mappings":"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","file":"shell.js","sourcesContent":["/**\n * `<NotificationList>` — renders the `recent` notifications inside the\n * `<NotificationBell>` dropdown content.\n *\n * Extracted from `NotificationBell` so it can be exercised directly in\n * tests without depending on Radix `DropdownMenu` mounting its portal\n * content in jsdom.\n */\n\nimport type { NotificationItem } from '@arqel-dev/types/inertia';\nimport { Link } from '@inertiajs/react';\nimport { AlertTriangle, Bell, Check, Info, type LucideIcon, Mail, User } from 'lucide-react';\nimport type { JSX } from 'react';\nimport { cn } from '../utils/cn.js';\nimport { isSameOriginRelativeUrl } from '../utils/url.js';\n\nexport interface NotificationListProps {\n items: ReadonlyArray<NotificationItem>;\n emptyLabel: string;\n onItemClick: (item: NotificationItem) => void;\n}\n\n/**\n * Allowlist of `data.icon` values accepted from notification payloads.\n *\n * Only these lucide-react icons may be rendered — no dynamic/arbitrary\n * lookup into the lucide namespace, to keep the bundle small and avoid\n * exposing an unbounded icon surface to server-controlled data.\n *\n * Supported keys: `bell` (default), `check`, `info`, `alert`, `mail`, `user`.\n */\nconst NOTIFICATION_ICONS: Record<string, LucideIcon> = {\n bell: Bell,\n check: Check,\n info: Info,\n alert: AlertTriangle,\n mail: Mail,\n user: User,\n};\n\nfunction readTitle(item: NotificationItem): string {\n const title = item.data['title'];\n if (typeof title === 'string' && title.trim()) return title;\n return item.type;\n}\n\nfunction readBody(item: NotificationItem): string | undefined {\n const body = item.data['body'] ?? item.data['message'];\n return typeof body === 'string' && body.trim() ? body : undefined;\n}\n\n/**\n * Only same-origin relative URLs (`/foo`, never `//evil.com`,\n * `https://…`, or `javascript:…`) unlock a navigable `Link` — mirrors\n * the `data.icon` allowlist below: server-controlled notification\n * payloads get a narrow, safe subset of behavior, never arbitrary\n * navigation. Anything else renders the item as a non-navigable button.\n */\nfunction readActionUrl(item: NotificationItem): string | undefined {\n const url = item.data['action_url'];\n return typeof url === 'string' && isSameOriginRelativeUrl(url) ? url : undefined;\n}\n\nfunction readIcon(item: NotificationItem): LucideIcon {\n const icon = item.data['icon'];\n if (typeof icon === 'string' && icon in NOTIFICATION_ICONS) {\n return NOTIFICATION_ICONS[icon] ?? Bell;\n }\n return Bell;\n}\n\nexport function NotificationList({\n items,\n emptyLabel,\n onItemClick,\n}: NotificationListProps): JSX.Element {\n if (items.length === 0) {\n return <div className=\"px-2 py-4 text-center text-sm text-muted-foreground\">{emptyLabel}</div>;\n }\n\n return (\n <div className=\"flex max-h-80 flex-col gap-0.5 overflow-y-auto\">\n {items.map((item) => {\n const title = readTitle(item);\n const body = readBody(item);\n const actionUrl = readActionUrl(item);\n const unread = item.read_at === null;\n const Icon = readIcon(item);\n\n const itemContent = (\n <>\n <span\n aria-hidden=\"true\"\n className={cn(\n 'mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full',\n unread ? 'bg-primary' : 'bg-transparent',\n )}\n />\n <Icon aria-hidden=\"true\" className=\"mt-0.5 h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate font-medium\">{title}</span>\n {body && <span className=\"truncate text-xs text-muted-foreground\">{body}</span>}\n </span>\n </>\n );\n const itemClassName = cn(\n 'flex w-full items-start gap-2 rounded-sm px-2 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground',\n unread && 'bg-accent/50',\n );\n\n // The item's root must be either a `Link` (navigable) or a\n // `button` (action-only) — never one nested inside the other,\n // which produces invalid `<a>`-inside-`<button>` HTML.\n return actionUrl ? (\n <Link\n key={item.id}\n href={actionUrl}\n onClick={() => onItemClick(item)}\n className={itemClassName}\n >\n {itemContent}\n </Link>\n ) : (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onItemClick(item)}\n className={itemClassName}\n >\n {itemContent}\n </button>\n );\n })}\n </div>\n );\n}\n","/**\n * `<NotificationBell>` — database-notifications trigger for the Topbar\n * `notifications` slot.\n *\n * Reads the shared `notifications` prop (`NotificationPayload | null`,\n * see `HandleArqelInertiaRequests`) via `usePage()`. Mounts a bell icon\n * with an unread-count `Badge` (shown only when `unread_count > 0`) and\n * a `DropdownMenu` listing the `recent` notifications. Marking a single\n * notification read, or all of them, does a scoped Inertia partial\n * reload (`only: ['notifications']`) — no full page reload.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { NotificationItem, NotificationPayload } from '@arqel-dev/types/inertia';\nimport { Link, router, usePage } from '@inertiajs/react';\nimport { Bell } from 'lucide-react';\nimport type { JSX } from 'react';\nimport { Badge } from '../shadcn/ui/badge.js';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../shadcn/ui/dropdown-menu.js';\nimport { cn } from '../utils/cn.js';\nimport { NotificationList } from './NotificationList.js';\n\nexport interface NotificationBellProps {\n className?: string;\n}\n\ninterface NotificationBellPageProps {\n notifications: NotificationPayload | null;\n [key: string]: unknown;\n}\n\nfunction markRead(id: string): void {\n router.post(\n `/admin/notifications/${id}/read`,\n {},\n { preserveScroll: true, only: ['notifications'] },\n );\n}\n\nfunction markAllRead(): void {\n router.post(\n '/admin/notifications/read-all',\n {},\n { preserveScroll: true, only: ['notifications'] },\n );\n}\n\nexport function NotificationBell({ className }: NotificationBellProps): JSX.Element {\n const t = useArqelTranslations();\n const { notifications } = usePage<NotificationBellPageProps>().props;\n\n const unreadCount = notifications?.unread_count ?? 0;\n const recent = notifications?.recent ?? [];\n\n const handleItemClick = (item: NotificationItem): void => {\n if (item.read_at === null) markRead(item.id);\n };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={t('arqel.notifications.title', 'Notifications')}\n className={cn(\n 'relative inline-flex h-9 w-9 items-center justify-center rounded-md hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n >\n <Bell aria-hidden=\"true\" className=\"h-4 w-4 text-muted-foreground\" />\n {unreadCount > 0 && (\n <Badge\n variant=\"destructive\"\n className=\"absolute -right-1 -top-1 h-4 min-w-4 justify-center px-1 text-[10px] leading-none\"\n >\n {unreadCount}\n </Badge>\n )}\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-80\">\n <div className=\"flex items-center justify-between px-2 py-1.5\">\n <DropdownMenuLabel className=\"p-0 font-medium\">\n {t('arqel.notifications.title', 'Notifications')}\n </DropdownMenuLabel>\n {unreadCount > 0 && (\n <DropdownMenuItem\n className=\"w-auto justify-end p-0 text-xs text-muted-foreground hover:text-foreground\"\n onSelect={(event) => {\n event.preventDefault();\n markAllRead();\n }}\n >\n {t('arqel.notifications.mark_all_read', 'Mark all as read')}\n </DropdownMenuItem>\n )}\n </div>\n\n <DropdownMenuSeparator />\n\n <NotificationList\n items={recent}\n emptyLabel={t('arqel.notifications.empty', 'No notifications')}\n onItemClick={handleItemClick}\n />\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild className=\"justify-center text-sm\">\n <Link href=\"/admin/notifications\">{t('arqel.notifications.view_all', 'View all')}</Link>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","/**\n * `<TenantSwitcher>` — dropdown that lists tenants the user can\n * access and dispatches `POST /admin/tenants/{id}/switch` via\n * Inertia router. Renders nothing when there is no current tenant\n * or the user only has access to one tenant.\n *\n * Mounts in the `tenantSwitcher` slot of `<Topbar>`. The current\n * tenant is read from `props.tenant.current` shared by the\n * server-side `HandleArqelInertiaRequests`; available tenants\n * come from the same payload.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { TenantSummary } from '@arqel-dev/types/tenant';\nimport { router } from '@inertiajs/react';\nimport type { JSX } from 'react';\nimport { Button } from '../action/Button.js';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../shadcn/ui/dropdown-menu.js';\n\nexport interface TenantSwitcherProps {\n current: TenantSummary | null;\n available: ReadonlyArray<TenantSummary>;\n /**\n * Path template for switching; defaults to\n * `/admin/tenants/{id}/switch`.\n */\n switchUrl?: (tenantId: string | number) => string;\n}\n\nconst DEFAULT_SWITCH_URL = (id: string | number): string => `/admin/tenants/${id}/switch`;\n\nexport function TenantSwitcher({\n current,\n available,\n switchUrl,\n}: TenantSwitcherProps): JSX.Element | null {\n const t = useArqelTranslations();\n if (!current || available.length <= 1) return null;\n\n const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;\n const labelFor = (tenant: TenantSummary): string =>\n tenant.name?.trim()\n ? tenant.name\n : t('arqel.tenant.unnamed', `Tenant ${tenant.id}`, { id: tenant.id });\n const currentLabel = labelFor(current);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n data-testid=\"tenant-switcher-trigger\"\n aria-label={t('arqel.aria.tenant_switch', `Switch tenant (current: ${currentLabel})`, {\n tenant: currentLabel,\n })}\n >\n {currentLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {available.map((tenant) => {\n const isCurrent = tenant.id === current.id;\n return (\n <DropdownMenuItem\n key={String(tenant.id)}\n data-testid={`tenant-switcher-option-${String(tenant.id)}`}\n disabled={isCurrent}\n onSelect={() => {\n router.post(buildUrl(tenant.id), {}, { preserveScroll: true });\n }}\n >\n {labelFor(tenant)}\n {isCurrent ? ' ✓' : ''}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"]}
package/dist/table.js CHANGED
@@ -1,4 +1,5 @@
1
- export { DataTable, TableCell, TableFilters, TablePagination, TableToolbar } from './chunk-S5UNPCMQ.js';
1
+ export { TableFilters, TablePagination, TableToolbar } from './chunk-YEPQWAD6.js';
2
+ export { DataTable, TableCell } from './chunk-JKD6SE75.js';
2
3
  import './chunk-RMPOR2YZ.js';
3
4
  import './chunk-H23VX3RR.js';
4
5
  import './chunk-B7ULUJVO.js';
package/dist/utility.js CHANGED
@@ -1,4 +1,5 @@
1
- export { Breadcrumbs, EmptyState, ErrorState, LoadingSkeleton } from './chunk-SK6H7ARE.js';
1
+ export { Breadcrumbs, EmptyState, LoadingSkeleton } from './chunk-3E66JNQO.js';
2
+ export { ErrorState } from './chunk-53J74IYR.js';
2
3
  export { PageHeader } from './chunk-MXUXMHOK.js';
3
4
  import './chunk-B7ULUJVO.js';
4
5
  //# sourceMappingURL=utility.js.map
package/dist/utils.d.ts CHANGED
@@ -15,4 +15,19 @@ import 'clsx';
15
15
  type LucideIconComponent = (typeof icons)[keyof typeof icons];
16
16
  declare function resolveLucideIcon(name: string | null | undefined): LucideIconComponent | undefined;
17
17
 
18
- export { type LucideIconComponent, resolveLucideIcon };
18
+ /**
19
+ * Guard for server-controlled URLs (e.g. notification `data.action_url`)
20
+ * that must never be rendered as a navigable `Link` unless they are
21
+ * relative to the current origin.
22
+ *
23
+ * Accepts only strings starting with a single `/` — `//evil.com` (a
24
+ * protocol-relative URL) and any absolute URL (`https://…`,
25
+ * `javascript:…`) are rejected. This mirrors the allowlist approach
26
+ * already used for `data.icon` in `NotificationList`: untrusted payload
27
+ * data only unlocks a narrow, safe subset of behavior, never arbitrary
28
+ * navigation — closing an open-redirect/phishing vector where a
29
+ * malicious `data.action_url` could send the user off-site.
30
+ */
31
+ declare function isSameOriginRelativeUrl(url: string): boolean;
32
+
33
+ export { type LucideIconComponent, isSameOriginRelativeUrl, resolveLucideIcon };
package/dist/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { isSameOriginRelativeUrl } from './chunk-XK2P6CSK.js';
1
2
  export { resolveLucideIcon } from './chunk-RMPOR2YZ.js';
2
3
  export { cn } from './chunk-B7ULUJVO.js';
3
4
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arqel-dev/ui",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Structural React components (AppShell, DataTable, FormRenderer, etc.) for Arqel admin panels.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://arqel.dev",
@@ -92,7 +92,7 @@
92
92
  "clsx": "^2.1.1",
93
93
  "radix-ui": "^1.4.3",
94
94
  "tailwind-merge": "^2.5.5",
95
- "@arqel-dev/types": "0.16.0"
95
+ "@arqel-dev/types": "0.18.0"
96
96
  },
97
97
  "peerDependencies": {
98
98
  "@inertiajs/react": "^3.0.0",
@@ -102,8 +102,8 @@
102
102
  "react-dom": "^19.2.0",
103
103
  "recharts": "^2.15.0",
104
104
  "tailwindcss": "^4.0.0",
105
- "@arqel-dev/hooks": "0.16.0",
106
- "@arqel-dev/react": "0.16.0"
105
+ "@arqel-dev/hooks": "0.18.0",
106
+ "@arqel-dev/react": "0.18.0"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@base-ui-components/react": "^1.0.0-alpha.0",
@@ -125,8 +125,8 @@
125
125
  "tsup": "^8.5.0",
126
126
  "typescript": "^5.6.3",
127
127
  "vitest": "^4.1.0",
128
- "@arqel-dev/hooks": "0.16.0",
129
- "@arqel-dev/react": "0.16.0"
128
+ "@arqel-dev/hooks": "0.18.0",
129
+ "@arqel-dev/react": "0.18.0"
130
130
  },
131
131
  "publishConfig": {
132
132
  "access": "public"
@@ -1,8 +0,0 @@
1
- export { ArqelEditPage as default } from './chunk-YQ6KXR3U.js';
2
- import './chunk-MXUXMHOK.js';
3
- import './chunk-MZMYV43C.js';
4
- import './chunk-CMNZLA32.js';
5
- import './chunk-H23VX3RR.js';
6
- import './chunk-B7ULUJVO.js';
7
- //# sourceMappingURL=ArqelEditPage-RRYFYOTC.js.map
8
- //# sourceMappingURL=ArqelEditPage-RRYFYOTC.js.map
@@ -1,12 +0,0 @@
1
- export { ArqelIndexPage as default } from './chunk-X4ZFKOPX.js';
2
- import './chunk-EG2DASKR.js';
3
- import './chunk-S5UNPCMQ.js';
4
- import './chunk-RMPOR2YZ.js';
5
- import './chunk-SLLTFOOS.js';
6
- import './chunk-VKZY6J6G.js';
7
- import './chunk-MZMYV43C.js';
8
- import './chunk-CMNZLA32.js';
9
- import './chunk-H23VX3RR.js';
10
- import './chunk-B7ULUJVO.js';
11
- //# sourceMappingURL=ArqelIndexPage-J2EUV2PI.js.map
12
- //# sourceMappingURL=ArqelIndexPage-J2EUV2PI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/resource/ResourceIndex.tsx"],"names":[],"mappings":"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","file":"chunk-EG2DASKR.js","sourcesContent":["/**\n * `<ResourceIndex>` — page-level wrapper for index/listing routes.\n *\n * Wires `ResourceIndexProps` (server payload) into the table stack:\n * header (title + toolbar actions + create button)\n * → TableToolbar (search + filters + bulk bar)\n * → DataTable (with selection, sorting, row actions)\n * → TablePagination\n *\n * The component is presentational — selection / sort / page transitions\n * are lifted to props so the same shell can be reused by ResourceIndex\n * (Inertia-driven) and dashboard widgets (memory-driven).\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { RecordType, ResourceIndexProps as ServerProps } from '@arqel-dev/types/resources';\nimport type { SortDirection, TableSort } from '@arqel-dev/types/tables';\nimport type { ReactNode } from 'react';\nimport { DataTable } from '../table/DataTable.js';\nimport { TableFilters } from '../table/TableFilters.js';\nimport { TablePagination } from '../table/TablePagination.js';\nimport { TableToolbar } from '../table/TableToolbar.js';\nimport { cn } from '../utils/cn.js';\n\ntype RowId = string | number;\n\nexport interface ResourceIndexUIProps<TRecord extends RecordType = RecordType>\n extends ServerProps<TRecord> {\n selectedIds?: ReadonlyArray<RowId>;\n onSelectionChange?: (ids: RowId[]) => void;\n onSortChange?: (column: string, direction: SortDirection) => void;\n onPageChange?: (page: number) => void;\n onPerPageChange?: (perPage: number) => void;\n onSearchChange?: (search: string) => void;\n onFilterChange?: (name: string, value: unknown) => void;\n onClearFilters?: () => void;\n\n filterValues?: Record<string, unknown>;\n\n searchSlot?: ReactNode;\n toolbarActions?: ReactNode;\n rowActions?: (record: TRecord) => ReactNode;\n bulkActions?: ReactNode;\n emptyState?: ReactNode;\n\n loading?: boolean;\n className?: string;\n}\n\nexport function ResourceIndex<TRecord extends RecordType = RecordType>({\n resource,\n records,\n pagination,\n columns,\n filters,\n search,\n sort,\n selectedIds = [],\n filterValues = {},\n onSelectionChange,\n onSortChange,\n onPageChange,\n onPerPageChange,\n onSearchChange,\n onFilterChange,\n onClearFilters,\n searchSlot,\n toolbarActions,\n rowActions,\n bulkActions,\n emptyState,\n loading = false,\n className,\n}: ResourceIndexUIProps<TRecord>) {\n const t = useArqelTranslations();\n const enableSelection = Boolean(onSelectionChange);\n\n const renderSearch = (): ReactNode => {\n if (searchSlot) return searchSlot;\n if (!onSearchChange) return null;\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {t('table.search.label', 'Search')}\n <input\n type=\"search\"\n placeholder={t(\n 'table.search.placeholder_for',\n `Search ${resource.pluralLabel.toLowerCase()}…`,\n { resource: resource.pluralLabel.toLowerCase() },\n )}\n // 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.\n className=\"h-11 w-64 rounded-sm border border-[var(--input)] bg-background px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring md:h-9\"\n value={search ?? ''}\n onChange={(e) => onSearchChange(e.target.value)}\n />\n </label>\n );\n };\n\n const normalisedSort: TableSort | null = sort?.column\n ? {\n column: sort.column,\n direction: sort.direction === 'desc' ? 'desc' : 'asc',\n }\n : null;\n\n return (\n <section\n className={cn(\n 'flex min-w-0 flex-col rounded-md border border-border bg-background',\n className,\n )}\n aria-label={resource.pluralLabel}\n >\n <header className=\"flex flex-wrap items-center gap-3 border-b border-border px-4 py-3\">\n <h1 className=\"text-lg font-semibold\">{resource.pluralLabel}</h1>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">{toolbarActions}</div>\n </header>\n\n <TableToolbar\n search={renderSearch()}\n filters={\n filters.length > 0 ? (\n <TableFilters\n filters={filters}\n values={filterValues}\n onChange={(name, value) => onFilterChange?.(name, value)}\n onClearAll={onClearFilters}\n />\n ) : null\n }\n selectedCount={selectedIds.length}\n bulkActions={bulkActions}\n onClearSelection={onSelectionChange ? () => onSelectionChange([]) : undefined}\n />\n\n <DataTable\n columns={columns}\n records={records as unknown as Array<{ id: RowId } & TRecord>}\n enableSelection={enableSelection}\n selectedIds={selectedIds}\n onSelectionChange={onSelectionChange}\n sort={normalisedSort}\n onSortChange={onSortChange}\n rowActions={rowActions ? (record) => rowActions(record as TRecord) : undefined}\n loading={loading}\n emptyState={emptyState}\n />\n\n {pagination && (\n <TablePagination\n meta={pagination}\n onPageChange={(page) => onPageChange?.(page)}\n onPerPageChange={onPerPageChange}\n />\n )}\n </section>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shadcn/ui/alert.tsx","../src/shadcn/ui/badge.tsx","../src/shadcn/ui/card.tsx","../src/shadcn/ui/checkbox.tsx","../src/shadcn/ui/label.tsx","../src/shadcn/ui/field.tsx","../src/shadcn/ui/select.tsx","../src/shadcn/ui/textarea.tsx"],"names":["cva","jsx","CheckboxPrimitive","LabelPrimitive","SelectPrimitive","jsxs","CheckIcon"],"mappings":"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","file":"chunk-K7QY56XN.js","sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/utils/cn\"\n\nconst alertVariants = cva(\n \"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\",\n {\n variants: {\n variant: {\n default: \"bg-card text-card-foreground\",\n destructive:\n \"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Alert({\n className,\n variant,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof alertVariants>) {\n return (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction AlertTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-title\"\n className={cn(\n \"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDescription({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-description\"\n className={cn(\n \"col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Alert, AlertTitle, AlertDescription }\n","import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nconst badgeVariants = cva(\n \"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\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90\",\n outline:\n \"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n ghost: \"[a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 [a&]:hover:underline\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot.Root : \"span\"\n\n return (\n <Comp\n data-slot=\"badge\"\n data-variant={variant}\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nexport { Badge, badgeVariants }\n","import * as React from \"react\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@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\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n","import * as React from \"react\"\nimport { CheckIcon } from \"lucide-react\"\nimport { Checkbox as CheckboxPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Checkbox({\n className,\n ...props\n}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {\n return (\n <CheckboxPrimitive.Root\n data-slot=\"checkbox\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"grid place-content-center text-current transition-none\"\n >\n <CheckIcon className=\"size-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n )\n}\n\nexport { Checkbox }\n","import * as React from \"react\"\nimport { Label as LabelPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Label({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Label }\n","import { useMemo } from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/utils/cn\"\nimport { Label } from \"@/shadcn/ui/label\"\nimport { Separator } from \"@/shadcn/ui/separator\"\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<\"fieldset\">) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n \"flex flex-col gap-6\",\n \"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLegend({\n className,\n variant = \"legend\",\n ...props\n}: React.ComponentProps<\"legend\"> & { variant?: \"legend\" | \"label\" }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n \"mb-3 font-medium\",\n \"data-[variant=legend]:text-base\",\n \"data-[variant=label]:text-sm\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst fieldVariants = cva(\n \"group/field flex w-full gap-3 data-[invalid=true]:text-destructive\",\n {\n variants: {\n orientation: {\n vertical: [\"flex-col [&>*]:w-full [&>.sr-only]:w-auto\"],\n horizontal: [\n \"flex-row items-center\",\n \"[&>[data-slot=field-label]]:flex-auto\",\n \"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n ],\n responsive: [\n \"flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto\",\n \"@md/field-group:[&>[data-slot=field-label]]:flex-auto\",\n \"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n ],\n },\n },\n defaultVariants: {\n orientation: \"vertical\",\n },\n }\n)\n\nfunction Field({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof fieldVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"field\"\n data-orientation={orientation}\n className={cn(fieldVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n \"group/field-content flex flex-1 flex-col gap-1.5 leading-snug\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldLabel({\n className,\n ...props\n}: React.ComponentProps<typeof Label>) {\n return (\n <Label\n data-slot=\"field-label\"\n className={cn(\n \"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50\",\n \"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\",\n \"has-data-[state=checked]:border-primary has-data-[state=checked]:bg-primary/5 dark:has-data-[state=checked]:bg-primary/10\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-label\"\n className={cn(\n \"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"field-description\"\n className={cn(\n \"text-sm leading-normal font-normal text-muted-foreground group-has-[[data-orientation=horizontal]]/field:text-balance\",\n \"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5\",\n \"[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n children?: React.ReactNode\n}) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn(\n \"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2\",\n className\n )}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"relative mx-auto block w-fit bg-background px-2 text-muted-foreground\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n )\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<\"div\"> & {\n errors?: Array<{ message?: string } | undefined>\n}) {\n const content = useMemo(() => {\n if (children) {\n return children\n }\n\n if (!errors?.length) {\n return null\n }\n\n const uniqueErrors = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ]\n\n if (uniqueErrors?.length == 1) {\n return uniqueErrors[0]?.message\n }\n\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {uniqueErrors.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>\n )}\n </ul>\n )\n }, [children, errors])\n\n if (!content) {\n return null\n }\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn(\"text-sm font-normal text-destructive\", className)}\n {...props}\n >\n {content}\n </div>\n )\n}\n\nexport {\n Field,\n FieldLabel,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldContent,\n FieldTitle,\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\nimport { Select as SelectPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Select({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />\n}\n\nfunction SelectValue({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n className,\n size = \"default\",\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n size?: \"sm\" | \"default\"\n}) {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n data-size={size}\n className={cn(\n \"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\",\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n}\n\nfunction SelectContent({\n className,\n children,\n position = \"item-aligned\",\n align = \"center\",\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"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\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n align={align}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n )\n}\n\nfunction SelectLabel({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"px-2 py-1.5 text-xs text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n >\n <span\n data-slot=\"select-item-indicator\"\n className=\"absolute right-2 flex size-3.5 items-center justify-center\"\n >\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\nfunction SelectSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"pointer-events-none -mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectScrollUpButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUpIcon className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n )\n}\n\nfunction SelectScrollDownButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDownIcon className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n )\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n}\n","import * as React from \"react\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Textarea({ className, ...props }: React.ComponentProps<\"textarea\">) {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Textarea }\n"]}
@@ -1,55 +0,0 @@
1
- import { cn } from './chunk-B7ULUJVO.js';
2
- import 'react';
3
- import { Separator as Separator$1 } from 'radix-ui';
4
- import { jsx } from 'react/jsx-runtime';
5
-
6
- function Separator({
7
- className,
8
- orientation = "horizontal",
9
- decorative = true,
10
- ...props
11
- }) {
12
- return /* @__PURE__ */ jsx(
13
- Separator$1.Root,
14
- {
15
- "data-slot": "separator",
16
- decorative,
17
- orientation,
18
- className: cn(
19
- "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
20
- className
21
- ),
22
- ...props
23
- }
24
- );
25
- }
26
- function Input({ className, type, ...props }) {
27
- return /* @__PURE__ */ jsx(
28
- "input",
29
- {
30
- type,
31
- "data-slot": "input",
32
- className: cn(
33
- "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",
34
- "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
35
- "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
36
- className
37
- ),
38
- ...props
39
- }
40
- );
41
- }
42
- function Skeleton({ className, ...props }) {
43
- return /* @__PURE__ */ jsx(
44
- "div",
45
- {
46
- "data-slot": "skeleton",
47
- className: cn("animate-pulse rounded-md bg-accent", className),
48
- ...props
49
- }
50
- );
51
- }
52
-
53
- export { Input, Separator, Skeleton };
54
- //# sourceMappingURL=chunk-R4BOUU6Y.js.map
55
- //# sourceMappingURL=chunk-R4BOUU6Y.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shadcn/ui/separator.tsx","../src/shadcn/ui/input.tsx","../src/shadcn/ui/skeleton.tsx"],"names":["SeparatorPrimitive","jsx"],"mappings":";;;;;AAOA,SAAS,SAAA,CAAU;AAAA,EACjB,SAAA;AAAA,EACA,WAAA,GAAc,YAAA;AAAA,EACd,UAAA,GAAa,IAAA;AAAA,EACb,GAAG;AACL,CAAA,EAAyD;AACvD,EAAA,uBACE,GAAA;AAAA,IAACA,WAAA,CAAmB,IAAA;AAAA,IAAnB;AAAA,MACC,WAAA,EAAU,WAAA;AAAA,MACV,UAAA;AAAA,MACA,WAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,gKAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;ACrBA,SAAS,MAAM,EAAE,SAAA,EAAW,IAAA,EAAM,GAAG,OAAM,EAAkC;AAC3E,EAAA,uBACEC,GAAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,WAAA,EAAU,OAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,4bAAA;AAAA,QACA,+EAAA;AAAA,QACA,wGAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AChBA,SAAS,QAAA,CAAS,EAAE,SAAA,EAAW,GAAG,OAAM,EAAgC;AACtE,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,UAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,oCAAA,EAAsC,SAAS,CAAA;AAAA,MAC5D,GAAG;AAAA;AAAA,GACN;AAEJ","file":"chunk-R4BOUU6Y.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Separator as SeparatorPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Separator({\n className,\n orientation = \"horizontal\",\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Separator }\n","import * as React from \"react\"\n\nimport { cn } from \"@/utils/cn\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(\n \"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\",\n \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Input }\n","import { cn } from \"@/utils/cn\"\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"skeleton\"\n className={cn(\"animate-pulse rounded-md bg-accent\", className)}\n {...props}\n />\n )\n}\n\nexport { Skeleton }\n"]}