@apotech-os/ui-sdk 0.2.0 → 0.5.0-rc.1

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.
package/dist/index.cjs CHANGED
@@ -37,6 +37,15 @@ function useAppContext() {
37
37
  if (!ctx) throw new Error("useAppContext must be used inside an app page mounted by the shell");
38
38
  return ctx;
39
39
  }
40
+ var AppInvokeError = class extends Error {
41
+ constructor(status, message, code, invocationId) {
42
+ super(message);
43
+ this.status = status;
44
+ this.code = code;
45
+ this.invocationId = invocationId;
46
+ this.name = "AppInvokeError";
47
+ }
48
+ };
40
49
  var AppApiCtx = React.createContext(null);
41
50
  var AppApiProvider = AppApiCtx.Provider;
42
51
  function useAppApi() {
@@ -44,6 +53,38 @@ function useAppApi() {
44
53
  if (!client) throw new Error("useAppApi must be used inside an app page mounted by the shell");
45
54
  return client;
46
55
  }
56
+
57
+ // src/utils.ts
58
+ async function copyToClipboard(text) {
59
+ if (!navigator?.clipboard || !window.isSecureContext) return false;
60
+ try {
61
+ await navigator.clipboard.writeText(text);
62
+ return true;
63
+ } catch {
64
+ return false;
65
+ }
66
+ }
67
+ function downloadBlob(blob, filename) {
68
+ const url = URL.createObjectURL(blob);
69
+ const a = document.createElement("a");
70
+ a.href = url;
71
+ a.download = filename;
72
+ document.body.appendChild(a);
73
+ a.click();
74
+ a.remove();
75
+ URL.revokeObjectURL(url);
76
+ }
77
+ function escapeCsvField(value) {
78
+ return /[",\r\n]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
79
+ }
80
+ function toCsv(rows) {
81
+ return rows.map((row) => row.map(escapeCsvField).join(",")).join("\r\n");
82
+ }
83
+ var BOM = "\uFEFF";
84
+ function downloadCsv(rows, filename) {
85
+ const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: "text/csv;charset=utf-8" });
86
+ downloadBlob(blob, filename);
87
+ }
47
88
  var buttonVariants = classVarianceAuthority.cva(
48
89
  "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
49
90
  {
@@ -110,25 +151,26 @@ function CardTitle({ className, ...props }) {
110
151
  function CardContent({ className, ...props }) {
111
152
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-6 pt-0", className), ...props });
112
153
  }
113
- var Input = React__namespace.forwardRef(
114
- ({ className, type, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
115
- "input",
116
- {
117
- type,
118
- className: cn(
119
- "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
120
- className
121
- ),
122
- ref,
123
- ...props
124
- }
125
- )
126
- );
154
+ var Input = React__namespace.forwardRef(({ className, type, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
155
+ "input",
156
+ {
157
+ type,
158
+ className: cn(
159
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
160
+ className
161
+ ),
162
+ ref,
163
+ ...props
164
+ }
165
+ ));
127
166
  Input.displayName = "Input";
128
167
  function Table({ className, ...props }) {
129
168
  return /* @__PURE__ */ jsxRuntime.jsx("table", { className: cn("w-full text-sm", className), ...props });
130
169
  }
131
- function TableHeader({ className, ...props }) {
170
+ function TableHeader({
171
+ className,
172
+ ...props
173
+ }) {
132
174
  return /* @__PURE__ */ jsxRuntime.jsx("thead", { className: cn("[&_tr]:border-b", className), ...props });
133
175
  }
134
176
  function TableBody({ className, ...props }) {
@@ -138,7 +180,10 @@ function TableRow({ className, ...props }) {
138
180
  return /* @__PURE__ */ jsxRuntime.jsx(
139
181
  "tr",
140
182
  {
141
- className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className),
183
+ className: cn(
184
+ "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
185
+ className
186
+ ),
142
187
  ...props
143
188
  }
144
189
  );
@@ -147,7 +192,10 @@ function TableHead({ className, ...props }) {
147
192
  return /* @__PURE__ */ jsxRuntime.jsx(
148
193
  "th",
149
194
  {
150
- className: cn("h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground", className),
195
+ className: cn(
196
+ "h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground",
197
+ className
198
+ ),
151
199
  ...props
152
200
  }
153
201
  );
@@ -185,7 +233,10 @@ function Tabs({ defaultValue, value, onValueChange, className, children }) {
185
233
  };
186
234
  return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, setValue }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children }) });
187
235
  }
188
- function TabsList({ className, children }) {
236
+ function TabsList({
237
+ className,
238
+ children
239
+ }) {
189
240
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("inline-flex items-center gap-1 rounded-lg bg-muted p-1", className), children });
190
241
  }
191
242
  function TabsTrigger({
@@ -235,7 +286,10 @@ function Modal({ open, onClose, title, children, className }) {
235
286
  {
236
287
  role: "dialog",
237
288
  "aria-modal": true,
238
- className: cn("relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg", className),
289
+ className: cn(
290
+ "relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg",
291
+ className
292
+ ),
239
293
  children: [
240
294
  title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mb-3 text-base font-semibold", children: title }),
241
295
  children
@@ -284,7 +338,13 @@ var Link = React__namespace.forwardRef(
284
338
  )
285
339
  );
286
340
  Link.displayName = "Link";
287
- function Switch({ checked = false, onCheckedChange, disabled, className, ...props }) {
341
+ function Switch({
342
+ checked = false,
343
+ onCheckedChange,
344
+ disabled,
345
+ className,
346
+ ...props
347
+ }) {
288
348
  return /* @__PURE__ */ jsxRuntime.jsx(
289
349
  "button",
290
350
  {
@@ -338,20 +398,278 @@ function DateRangePicker({ value, onChange, className, disabled }) {
338
398
  )
339
399
  ] });
340
400
  }
401
+ function IconX({ className }) {
402
+ return /* @__PURE__ */ jsxRuntime.jsx(
403
+ "svg",
404
+ {
405
+ className,
406
+ xmlns: "http://www.w3.org/2000/svg",
407
+ viewBox: "0 0 24 24",
408
+ fill: "none",
409
+ stroke: "currentColor",
410
+ strokeWidth: "2",
411
+ strokeLinecap: "round",
412
+ "aria-hidden": "true",
413
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" })
414
+ }
415
+ );
416
+ }
417
+ function IconCopy({ className }) {
418
+ return /* @__PURE__ */ jsxRuntime.jsxs(
419
+ "svg",
420
+ {
421
+ className,
422
+ xmlns: "http://www.w3.org/2000/svg",
423
+ viewBox: "0 0 24 24",
424
+ fill: "none",
425
+ stroke: "currentColor",
426
+ strokeWidth: "2",
427
+ strokeLinecap: "round",
428
+ strokeLinejoin: "round",
429
+ "aria-hidden": "true",
430
+ children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
432
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
433
+ ]
434
+ }
435
+ );
436
+ }
437
+ function IconCheck({ className }) {
438
+ return /* @__PURE__ */ jsxRuntime.jsx(
439
+ "svg",
440
+ {
441
+ className,
442
+ xmlns: "http://www.w3.org/2000/svg",
443
+ viewBox: "0 0 24 24",
444
+ fill: "none",
445
+ stroke: "currentColor",
446
+ strokeWidth: "2",
447
+ strokeLinecap: "round",
448
+ strokeLinejoin: "round",
449
+ "aria-hidden": "true",
450
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
451
+ }
452
+ );
453
+ }
454
+ var Textarea = React__namespace.forwardRef(
455
+ function Textarea2({ className, ...props }, ref) {
456
+ return /* @__PURE__ */ jsxRuntime.jsx(
457
+ "textarea",
458
+ {
459
+ ref,
460
+ className: cn(
461
+ "flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
462
+ className
463
+ ),
464
+ ...props
465
+ }
466
+ );
467
+ }
468
+ );
469
+ var Checkbox = React__namespace.forwardRef(
470
+ function Checkbox2({ className, label, onCheckedChange, ...props }, ref) {
471
+ const input = /* @__PURE__ */ jsxRuntime.jsx(
472
+ "input",
473
+ {
474
+ ref,
475
+ type: "checkbox",
476
+ className: cn(
477
+ "size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50",
478
+ className
479
+ ),
480
+ onChange: (e) => onCheckedChange?.(e.target.checked),
481
+ ...props
482
+ }
483
+ );
484
+ if (!label) return input;
485
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex cursor-pointer items-center gap-2 text-sm", children: [
486
+ input,
487
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
488
+ ] });
489
+ }
490
+ );
491
+ function SidePanel({
492
+ open,
493
+ onClose,
494
+ title,
495
+ description,
496
+ children,
497
+ className
498
+ }) {
499
+ React__namespace.useEffect(() => {
500
+ if (!open) return;
501
+ const onKeyDown = (e) => {
502
+ if (e.key === "Escape") onClose();
503
+ };
504
+ window.addEventListener("keydown", onKeyDown);
505
+ return () => window.removeEventListener("keydown", onKeyDown);
506
+ }, [open, onClose]);
507
+ if (!open) return null;
508
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", children: [
509
+ /* @__PURE__ */ jsxRuntime.jsx(
510
+ "button",
511
+ {
512
+ type: "button",
513
+ "aria-label": "Fermer",
514
+ className: "absolute inset-0 cursor-default bg-foreground/40",
515
+ onClick: onClose
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsxRuntime.jsxs(
519
+ "aside",
520
+ {
521
+ role: "dialog",
522
+ "aria-modal": true,
523
+ className: cn(
524
+ "absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl",
525
+ className
526
+ ),
527
+ children: [
528
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex shrink-0 items-start gap-3 border-b px-5 py-4", children: [
529
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
530
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-base font-semibold", children: title }),
531
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description })
532
+ ] }),
533
+ /* @__PURE__ */ jsxRuntime.jsx(
534
+ "button",
535
+ {
536
+ type: "button",
537
+ "aria-label": "Fermer",
538
+ className: "-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
539
+ onClick: onClose,
540
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconX, { className: "size-4" })
541
+ }
542
+ )
543
+ ] }),
544
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1 flex-col px-5 py-4", children })
545
+ ]
546
+ }
547
+ )
548
+ ] });
549
+ }
550
+ var COPY_FEEDBACK_MS = 2e3;
551
+ function CopyButton({
552
+ value,
553
+ label = "Copier",
554
+ copiedLabel = "Copi\xE9",
555
+ variant = "outline",
556
+ size = "sm",
557
+ className
558
+ }) {
559
+ const [state, setState] = React__namespace.useState("idle");
560
+ const timeout = React__namespace.useRef(void 0);
561
+ React__namespace.useEffect(() => () => clearTimeout(timeout.current), []);
562
+ async function copy() {
563
+ const ok = await copyToClipboard(value);
564
+ setState(ok ? "copied" : "error");
565
+ clearTimeout(timeout.current);
566
+ timeout.current = setTimeout(() => setState("idle"), COPY_FEEDBACK_MS);
567
+ }
568
+ return /* @__PURE__ */ jsxRuntime.jsxs(
569
+ Button,
570
+ {
571
+ type: "button",
572
+ variant,
573
+ size,
574
+ className,
575
+ onClick: () => void copy(),
576
+ children: [
577
+ state === "copied" ? /* @__PURE__ */ jsxRuntime.jsx(IconCheck, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(IconCopy, { className: "size-3.5" }),
578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-live": "polite", className: state === "error" ? "text-destructive" : void 0, children: state === "copied" ? copiedLabel : state === "error" ? "Copie impossible" : label })
579
+ ]
580
+ }
581
+ );
582
+ }
583
+ function Popover({
584
+ open,
585
+ onOpenChange,
586
+ trigger,
587
+ children,
588
+ align = "start",
589
+ className
590
+ }) {
591
+ const root = React__namespace.useRef(null);
592
+ React__namespace.useEffect(() => {
593
+ if (!open) return;
594
+ const onPointerDown = (e) => {
595
+ if (!root.current?.contains(e.target)) onOpenChange(false);
596
+ };
597
+ const onKeyDown = (e) => {
598
+ if (e.key === "Escape") onOpenChange(false);
599
+ };
600
+ document.addEventListener("mousedown", onPointerDown);
601
+ document.addEventListener("keydown", onKeyDown);
602
+ return () => {
603
+ document.removeEventListener("mousedown", onPointerDown);
604
+ document.removeEventListener("keydown", onKeyDown);
605
+ };
606
+ }, [open, onOpenChange]);
607
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: root, className: "relative inline-block", children: [
608
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-expanded": open, onClick: () => onOpenChange(!open), children: trigger }),
609
+ open && /* @__PURE__ */ jsxRuntime.jsx(
610
+ "div",
611
+ {
612
+ className: cn(
613
+ "absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg",
614
+ align === "end" ? "right-0" : "left-0",
615
+ className
616
+ ),
617
+ children
618
+ }
619
+ )
620
+ ] });
621
+ }
622
+ function DropdownMenu({ trigger, items, align = "end", className }) {
623
+ const [open, setOpen] = React__namespace.useState(false);
624
+ return /* @__PURE__ */ jsxRuntime.jsx(
625
+ Popover,
626
+ {
627
+ open,
628
+ onOpenChange: setOpen,
629
+ trigger,
630
+ align,
631
+ className: cn("p-1", className),
632
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { role: "menu", className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
633
+ "button",
634
+ {
635
+ type: "button",
636
+ role: "menuitem",
637
+ disabled: item.disabled,
638
+ className: cn(
639
+ "cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50",
640
+ item.destructive && "text-destructive"
641
+ ),
642
+ onClick: () => {
643
+ setOpen(false);
644
+ item.onSelect();
645
+ },
646
+ children: item.label
647
+ },
648
+ i
649
+ )) })
650
+ }
651
+ );
652
+ }
341
653
 
342
654
  exports.AppApiProvider = AppApiProvider;
343
655
  exports.AppContextProvider = AppContextProvider;
656
+ exports.AppInvokeError = AppInvokeError;
344
657
  exports.Badge = Badge;
345
658
  exports.Button = Button;
346
659
  exports.Card = Card;
347
660
  exports.CardContent = CardContent;
348
661
  exports.CardHeader = CardHeader;
349
662
  exports.CardTitle = CardTitle;
663
+ exports.Checkbox = Checkbox;
664
+ exports.CopyButton = CopyButton;
350
665
  exports.DateRangePicker = DateRangePicker;
666
+ exports.DropdownMenu = DropdownMenu;
351
667
  exports.Input = Input;
352
668
  exports.Link = Link;
353
669
  exports.Modal = Modal;
670
+ exports.Popover = Popover;
354
671
  exports.Select = Select;
672
+ exports.SidePanel = SidePanel;
355
673
  exports.Spinner = Spinner;
356
674
  exports.Switch = Switch;
357
675
  exports.Table = Table;
@@ -364,7 +682,12 @@ exports.Tabs = Tabs;
364
682
  exports.TabsContent = TabsContent;
365
683
  exports.TabsList = TabsList;
366
684
  exports.TabsTrigger = TabsTrigger;
685
+ exports.Textarea = Textarea;
367
686
  exports.cn = cn;
687
+ exports.copyToClipboard = copyToClipboard;
688
+ exports.downloadBlob = downloadBlob;
689
+ exports.downloadCsv = downloadCsv;
690
+ exports.toCsv = toCsv;
368
691
  exports.useAppApi = useAppApi;
369
692
  exports.useAppContext = useAppContext;
370
693
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/components.tsx"],"names":["twMerge","clsx","createContext","useContext","cva","React","jsx","jsxs"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext } from 'react';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />;\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLInputElement>>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n ),\n);\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', className)}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn('h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({ className, children }: { className?: string; children: React.ReactNode }) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active ? 'bg-card text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn('relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg', className)}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({ checked = false, onCheckedChange, disabled, className, ...props }: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/utils.ts","../src/components.tsx"],"names":["twMerge","clsx","createContext","useContext","cva","React","jsx","jsxs","Textarea","Checkbox"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext } from 'react';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PATCH request to a platform-data endpoint (e.g. update a record).\n */\n patch<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a DELETE request to a platform-data endpoint (e.g. delete a record).\n */\n delete<T>(path: string): Promise<T>;\n /**\n * Run one of this app's `uiInvoke` functions and get its return value back.\n *\n * This is the ONLY way a page can reach an integration: the action endpoint\n * requires an app token and refuses a browser session. The platform mints the\n * token server-side and runs the handler in-process.\n *\n * The function must be declared `trigger: { type: 'uiInvoke' }` in the\n * manifest, and the caller must hold its `minRole` (default EDITOR).\n *\n * Pass `idempotencyKey` for anything that must not run twice on a double\n * click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.\n *\n * Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored\n * message that is safe to show the user; every other failure is generic on\n * purpose (raw provider errors can leak tokens or PII).\n */\n invoke<TResult, TInput = Record<string, unknown>>(\n functionName: string,\n input?: TInput,\n opts?: { idempotencyKey?: string; signal?: AbortSignal },\n ): Promise<TResult>;\n}\n\n/** Thrown by AppApiClient.invoke. */\nexport class AppInvokeError extends Error {\n constructor(\n readonly status: number,\n message: string,\n readonly code?: string,\n readonly invocationId?: string,\n ) {\n super(message);\n this.name = 'AppInvokeError';\n }\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n","/**\n * Browser helpers for app pages.\n *\n * App bundles get react, react-dom and this SDK from the shell's import map and\n * bundle everything else themselves — so without these here, every app would\n * reimplement clipboard handling and CSV escaping, and get the edge cases wrong\n * in its own way.\n */\n\n/**\n * Copy text to the clipboard.\n *\n * Returns `false` instead of throwing when the clipboard is unavailable (non\n * secure context, permission refused) so the caller can render inline feedback.\n * No `document.execCommand('copy')` fallback: it is deprecated, and the shell\n * only ever runs on https or localhost, both secure contexts.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard || !window.isSecureContext) return false;\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */\nexport function downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Escape one CSV field per RFC 4180: quote it, and double any embedded quote,\n * whenever it contains a comma, a quote, or a line break. */\nfunction escapeCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value;\n}\n\n/** Serialize rows (header included) into an RFC 4180 CSV string. */\nexport function toCsv(rows: string[][]): string {\n return rows.map((row) => row.map(escapeCsvField).join(',')).join('\\r\\n');\n}\n\n/** UTF-8 byte order mark. */\nconst BOM = '\\uFEFF';\n\n/**\n * Serialize + download in one call.\n *\n * The BOM is the whole reason this helper exists: without it Excel on Windows\n * reads the file as latin-1 and mangles every accented character.\n */\nexport function downloadCsv(rows: string[][], filename: string): void {\n const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, filename);\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\nimport { copyToClipboard } from './utils';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return (\n <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />\n );\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<\n HTMLInputElement,\n React.InputHTMLAttributes<HTMLInputElement>\n>(({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn(\n 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn(\n 'h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn(\n 'relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg',\n className,\n )}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({\n checked = false,\n onCheckedChange,\n disabled,\n className,\n ...props\n}: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Icons\n//\n// Inline SVGs rather than a lucide-react dependency: the SDK is loaded through\n// the shell's import map as a single vendor chunk, so a dependency here inflates\n// every app page. Same precedent as Spinner above.\n// ---------------------------------------------------------------------------\n\nfunction IconX({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nfunction IconCopy({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\nfunction IconCheck({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {\n checked?: boolean;\n /** Preferred over onChange — receives the boolean directly. */\n onCheckedChange?: (checked: boolean) => void;\n label?: React.ReactNode;\n}\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox({ className, label, onCheckedChange, ...props }, ref) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(\n 'size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n onChange={(e) => onCheckedChange?.(e.target.checked)}\n {...props}\n />\n );\n if (!label) return input;\n return (\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm\">\n {input}\n <span>{label}</span>\n </label>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// SidePanel\n// ---------------------------------------------------------------------------\n\nexport interface SidePanelProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * Blocking slide-over — reach for it when a task has more fields than a `Modal`\n * can show without an inner scrollbar. Full height, so the body scrolls once and\n * a footer can stay pinned; `Modal` centres a box and does no height management.\n *\n * Children are laid out in a flex column filling the panel: put the scrollable\n * region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.\n *\n * NOTE: no focus management. Autofocus the primary action yourself.\n */\nexport function SidePanel({\n open,\n onClose,\n title,\n description,\n children,\n className,\n}: SidePanelProps) {\n // Escape closes. A panel that covers the viewport makes a missing keyboard\n // exit far more noticeable than it is on a centred Modal.\n React.useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, onClose]);\n\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50\">\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <aside\n role=\"dialog\"\n aria-modal\n className={cn(\n 'absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl',\n className,\n )}\n >\n <header className=\"flex shrink-0 items-start gap-3 border-b px-5 py-4\">\n <div className=\"min-w-0 flex-1\">\n {title && <h2 className=\"text-base font-semibold\">{title}</h2>}\n {description && <p className=\"mt-0.5 text-xs text-muted-foreground\">{description}</p>}\n </div>\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={onClose}\n >\n <IconX className=\"size-4\" />\n </button>\n </header>\n <div className=\"flex min-h-0 flex-1 flex-col px-5 py-4\">{children}</div>\n </aside>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CopyButton\n// ---------------------------------------------------------------------------\n\nexport interface CopyButtonProps {\n value: string;\n label?: string;\n copiedLabel?: string;\n variant?: ButtonProps['variant'];\n size?: ButtonProps['size'];\n className?: string;\n}\n\n/** How long the confirmation stays up before reverting. */\nconst COPY_FEEDBACK_MS = 2000;\n\n/**\n * Copy-to-clipboard button with inline feedback. On failure it says so rather\n * than silently doing nothing — keep the copyable text selectable so manual\n * copy stays the fallback.\n */\nexport function CopyButton({\n value,\n label = 'Copier',\n copiedLabel = 'Copié',\n variant = 'outline',\n size = 'sm',\n className,\n}: CopyButtonProps) {\n const [state, setState] = React.useState<'idle' | 'copied' | 'error'>('idle');\n const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Held in a ref and cleared on unmount: the panel can close mid-feedback.\n React.useEffect(() => () => clearTimeout(timeout.current), []);\n\n async function copy() {\n const ok = await copyToClipboard(value);\n setState(ok ? 'copied' : 'error');\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => setState('idle'), COPY_FEEDBACK_MS);\n }\n\n return (\n <Button\n type=\"button\"\n variant={variant}\n size={size}\n className={className}\n onClick={() => void copy()}\n >\n {state === 'copied' ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n <span aria-live=\"polite\" className={state === 'error' ? 'text-destructive' : undefined}>\n {state === 'copied' ? copiedLabel : state === 'error' ? 'Copie impossible' : label}\n </span>\n </Button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Popover\n// ---------------------------------------------------------------------------\n\nexport interface PopoverProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n trigger: React.ReactNode;\n children: React.ReactNode;\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click\n * and Escape, which is what a filter pill needs and a Modal is too heavy for. */\nexport function Popover({\n open,\n onOpenChange,\n trigger,\n children,\n align = 'start',\n className,\n}: PopoverProps) {\n const root = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n if (!root.current?.contains(e.target as Node)) onOpenChange(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onOpenChange(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <div ref={root} className=\"relative inline-block\">\n <button type=\"button\" aria-expanded={open} onClick={() => onOpenChange(!open)}>\n {trigger}\n </button>\n {open && (\n <div\n className={cn(\n 'absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg',\n align === 'end' ? 'right-0' : 'left-0',\n className,\n )}\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DropdownMenu\n// ---------------------------------------------------------------------------\n\nexport interface DropdownMenuItem {\n label: React.ReactNode;\n onSelect: () => void;\n disabled?: boolean;\n destructive?: boolean;\n}\n\nexport interface DropdownMenuProps {\n trigger: React.ReactNode;\n items: DropdownMenuItem[];\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Uncontrolled menu built on Popover. Selecting an item closes it. */\nexport function DropdownMenu({ trigger, items, align = 'end', className }: DropdownMenuProps) {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n align={align}\n className={cn('p-1', className)}\n >\n <div role=\"menu\" className=\"flex flex-col\">\n {items.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={cn(\n 'cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50',\n item.destructive && 'text-destructive',\n )}\n onClick={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.label}\n </button>\n ))}\n </div>\n </Popover>\n );\n}\n"]}