@apotech-os/ui-sdk 0.10.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,11 +3,6 @@
3
3
  var clsx = require('clsx');
4
4
  var tailwindMerge = require('tailwind-merge');
5
5
  var React = require('react');
6
- var dialog = require('@base-ui/react/dialog');
7
- var menu = require('@base-ui/react/menu');
8
- var popover = require('@base-ui/react/popover');
9
- var _switch = require('@base-ui/react/switch');
10
- var tabs = require('@base-ui/react/tabs');
11
6
  var classVarianceAuthority = require('class-variance-authority');
12
7
  var jsxRuntime = require('react/jsx-runtime');
13
8
 
@@ -315,12 +310,6 @@ function downloadCsv(rows, filename) {
315
310
  const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: "text/csv;charset=utf-8" });
316
311
  downloadBlob(blob, filename);
317
312
  }
318
- function triggerProps(trigger) {
319
- if (React__namespace.isValidElement(trigger)) {
320
- return { render: trigger, nativeButton: trigger.type === "button" || trigger.type === Button };
321
- }
322
- return { render: /* @__PURE__ */ jsxRuntime.jsx("span", { children: trigger }), nativeButton: false };
323
- }
324
313
  var buttonVariants = classVarianceAuthority.cva(
325
314
  "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",
326
315
  {
@@ -384,18 +373,9 @@ function CardHeader({ className, ...props }) {
384
373
  function CardTitle({ className, ...props }) {
385
374
  return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props });
386
375
  }
387
- function CardDescription({
388
- className,
389
- ...props
390
- }) {
391
- return /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm text-muted-foreground", className), ...props });
392
- }
393
376
  function CardContent({ className, ...props }) {
394
377
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-6 pt-0", className), ...props });
395
378
  }
396
- function CardFooter({ className, ...props }) {
397
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center p-6 pt-0", className), ...props });
398
- }
399
379
  var Input = React__namespace.forwardRef(({ className, type, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
400
380
  "input",
401
381
  {
@@ -416,13 +396,7 @@ function TableHeader({
416
396
  className,
417
397
  ...props
418
398
  }) {
419
- return /* @__PURE__ */ jsxRuntime.jsx(
420
- "thead",
421
- {
422
- className: cn("[&_tr]:border-b [&_tr]:hover:bg-transparent", className),
423
- ...props
424
- }
425
- );
399
+ return /* @__PURE__ */ jsxRuntime.jsx("thead", { className: cn("[&_tr]:border-b", className), ...props });
426
400
  }
427
401
  function TableBody({ className, ...props }) {
428
402
  return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: cn("[&_tr:last-child]:border-0", className), ...props });
@@ -444,7 +418,7 @@ function TableHead({ className, ...props }) {
444
418
  "th",
445
419
  {
446
420
  className: cn(
447
- "h-10 px-4 text-left align-middle text-xs font-medium uppercase tracking-wide text-muted-foreground",
421
+ "h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground",
448
422
  className
449
423
  ),
450
424
  ...props
@@ -469,43 +443,42 @@ var Select = React__namespace.forwardRef(
469
443
  )
470
444
  );
471
445
  Select.displayName = "Select";
446
+ var TabsContext = React__namespace.createContext(null);
447
+ function useTabsContext() {
448
+ const ctx = React__namespace.useContext(TabsContext);
449
+ if (!ctx) throw new Error("Tabs sub-component must be used within <Tabs>");
450
+ return ctx;
451
+ }
472
452
  function Tabs({ defaultValue, value, onValueChange, className, children }) {
473
- return /* @__PURE__ */ jsxRuntime.jsx(
474
- tabs.Tabs.Root,
475
- {
476
- className,
477
- defaultValue,
478
- value,
479
- onValueChange: (next) => onValueChange?.(String(next)),
480
- children
481
- }
482
- );
453
+ const [internal, setInternal] = React__namespace.useState(defaultValue ?? "");
454
+ const current = value ?? internal;
455
+ const setValue = (v) => {
456
+ setInternal(v);
457
+ onValueChange?.(v);
458
+ };
459
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, setValue }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children }) });
483
460
  }
484
461
  function TabsList({
485
462
  className,
486
463
  children
487
464
  }) {
488
- return /* @__PURE__ */ jsxRuntime.jsx(
489
- tabs.Tabs.List,
490
- {
491
- className: cn("inline-flex items-center gap-1 rounded-lg bg-muted p-1", className),
492
- children
493
- }
494
- );
465
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("inline-flex items-center gap-1 rounded-lg bg-muted p-1", className), children });
495
466
  }
496
467
  function TabsTrigger({
497
468
  value,
498
469
  className,
499
470
  children
500
471
  }) {
472
+ const { value: current, setValue } = useTabsContext();
473
+ const active = current === value;
501
474
  return /* @__PURE__ */ jsxRuntime.jsx(
502
- tabs.Tabs.Tab,
475
+ "button",
503
476
  {
504
- value,
477
+ type: "button",
478
+ onClick: () => setValue(value),
505
479
  className: cn(
506
480
  "rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
507
- "text-muted-foreground hover:text-foreground",
508
- "data-[active]:bg-card data-[active]:text-foreground data-[active]:shadow-sm",
481
+ active ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
509
482
  className
510
483
  ),
511
484
  children
@@ -517,25 +490,38 @@ function TabsContent({
517
490
  className,
518
491
  children
519
492
  }) {
520
- return /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs.Panel, { value, className, children });
493
+ const { value: current } = useTabsContext();
494
+ if (current !== value) return null;
495
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children });
521
496
  }
522
497
  function Modal({ open, onClose, title, children, className }) {
523
- return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Root, { open, onOpenChange: (next) => !next && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.Dialog.Portal, { children: [
524
- /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Backdrop, { "aria-label": "Close", className: "fixed inset-0 z-50 bg-foreground/40" }),
498
+ if (!open) return null;
499
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
500
+ /* @__PURE__ */ jsxRuntime.jsx(
501
+ "button",
502
+ {
503
+ type: "button",
504
+ "aria-label": "Close",
505
+ className: "absolute inset-0 cursor-default bg-foreground/40",
506
+ onClick: onClose
507
+ }
508
+ ),
525
509
  /* @__PURE__ */ jsxRuntime.jsxs(
526
- dialog.Dialog.Popup,
510
+ "div",
527
511
  {
512
+ role: "dialog",
513
+ "aria-modal": true,
528
514
  className: cn(
529
- "fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-xl border bg-card p-5 shadow-lg",
515
+ "relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg",
530
516
  className
531
517
  ),
532
518
  children: [
533
- title && /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Title, { className: "mb-3 text-base font-semibold", children: title }),
519
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mb-3 text-base font-semibold", children: title }),
534
520
  children
535
521
  ]
536
522
  }
537
523
  )
538
- ] }) });
524
+ ] });
539
525
  }
540
526
  var spinnerSizes = { sm: "size-4", md: "size-6", lg: "size-8" };
541
527
  function Spinner({ className, size = "md" }) {
@@ -585,19 +571,28 @@ function Switch({
585
571
  ...props
586
572
  }) {
587
573
  return /* @__PURE__ */ jsxRuntime.jsx(
588
- _switch.Switch.Root,
574
+ "button",
589
575
  {
590
- checked,
591
- onCheckedChange: (next) => onCheckedChange?.(next),
576
+ type: "button",
577
+ role: "switch",
578
+ "aria-checked": checked,
592
579
  disabled,
580
+ onClick: () => onCheckedChange?.(!checked),
593
581
  className: cn(
594
- // `data-[disabled]`, not `disabled:` the root is a span, so `:disabled`
595
- // never matches it and the dimming would silently stop happening.
596
- "relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full bg-input transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[checked]:bg-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
582
+ "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",
583
+ checked ? "bg-primary" : "bg-input",
597
584
  className
598
585
  ),
599
586
  ...props,
600
- children: /* @__PURE__ */ jsxRuntime.jsx(_switch.Switch.Thumb, { className: "inline-block size-4 translate-x-0.5 rounded-full bg-white shadow transition-transform data-[checked]:translate-x-4" })
587
+ children: /* @__PURE__ */ jsxRuntime.jsx(
588
+ "span",
589
+ {
590
+ className: cn(
591
+ "inline-block size-4 transform rounded-full bg-white shadow transition-transform",
592
+ checked ? "translate-x-4" : "translate-x-0.5"
593
+ )
594
+ }
595
+ )
601
596
  }
602
597
  );
603
598
  }
@@ -726,26 +721,47 @@ function SidePanel({
726
721
  children,
727
722
  className
728
723
  }) {
729
- return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Root, { open, onOpenChange: (next) => !next && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.Dialog.Portal, { children: [
730
- /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Backdrop, { "aria-label": "Fermer", className: "fixed inset-0 z-50 bg-foreground/40" }),
724
+ React__namespace.useEffect(() => {
725
+ if (!open) return;
726
+ const onKeyDown = (e) => {
727
+ if (e.key === "Escape") onClose();
728
+ };
729
+ window.addEventListener("keydown", onKeyDown);
730
+ return () => window.removeEventListener("keydown", onKeyDown);
731
+ }, [open, onClose]);
732
+ if (!open) return null;
733
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", children: [
734
+ /* @__PURE__ */ jsxRuntime.jsx(
735
+ "button",
736
+ {
737
+ type: "button",
738
+ "aria-label": "Fermer",
739
+ className: "absolute inset-0 cursor-default bg-foreground/40",
740
+ onClick: onClose
741
+ }
742
+ ),
731
743
  /* @__PURE__ */ jsxRuntime.jsxs(
732
- dialog.Dialog.Popup,
744
+ "aside",
733
745
  {
746
+ role: "dialog",
747
+ "aria-modal": true,
734
748
  className: cn(
735
- "fixed inset-y-0 right-0 z-50 flex w-full max-w-lg flex-col border-l bg-card shadow-xl",
749
+ "absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl",
736
750
  className
737
751
  ),
738
752
  children: [
739
753
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex shrink-0 items-start gap-3 border-b px-5 py-4", children: [
740
754
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
741
- title && /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Title, { className: "text-base font-semibold", children: title }),
742
- description && /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Description, { className: "mt-0.5 text-xs text-muted-foreground", children: description })
755
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-base font-semibold", children: title }),
756
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description })
743
757
  ] }),
744
758
  /* @__PURE__ */ jsxRuntime.jsx(
745
- dialog.Dialog.Close,
759
+ "button",
746
760
  {
761
+ type: "button",
747
762
  "aria-label": "Fermer",
748
763
  className: "-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
764
+ onClick: onClose,
749
765
  children: /* @__PURE__ */ jsxRuntime.jsx(IconX, { className: "size-4" })
750
766
  }
751
767
  )
@@ -754,7 +770,7 @@ function SidePanel({
754
770
  ]
755
771
  }
756
772
  )
757
- ] }) });
773
+ ] });
758
774
  }
759
775
  var COPY_FEEDBACK_MS = 2e3;
760
776
  function CopyButton({
@@ -797,110 +813,68 @@ function Popover({
797
813
  align = "start",
798
814
  className
799
815
  }) {
800
- return (
801
- // The callback is re-wrapped so Base UI's event-details argument stops at the
802
- // SDK boundary: the engine is an implementation detail, not part of the API.
803
- /* @__PURE__ */ jsxRuntime.jsxs(popover.Popover.Root, { open, onOpenChange: (next) => onOpenChange(next), children: [
804
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block", children: /* @__PURE__ */ jsxRuntime.jsx(popover.Popover.Trigger, { ...triggerProps(trigger) }) }),
805
- /* @__PURE__ */ jsxRuntime.jsx(popover.Popover.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(popover.Popover.Positioner, { side: "bottom", align, sideOffset: 4, className: "z-50", children: /* @__PURE__ */ jsxRuntime.jsx(
806
- popover.Popover.Popup,
807
- {
808
- className: cn("min-w-48 rounded-md border bg-card p-2 shadow-lg", className),
809
- children
810
- }
811
- ) }) })
812
- ] })
813
- );
814
- }
815
- function DropdownMenu({ trigger, items, align = "end", className }) {
816
- return /* @__PURE__ */ jsxRuntime.jsxs(menu.Menu.Root, { children: [
817
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block", children: /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Trigger, { ...triggerProps(trigger) }) }),
818
- /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Positioner, { side: "bottom", align, sideOffset: 4, className: "z-50", children: /* @__PURE__ */ jsxRuntime.jsx(
819
- menu.Menu.Popup,
820
- {
821
- className: cn(
822
- "flex min-w-48 flex-col rounded-md border bg-card p-1 shadow-lg",
823
- className
824
- ),
825
- children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
826
- menu.Menu.Item,
827
- {
828
- disabled: item.disabled,
829
- onClick: item.onSelect,
830
- className: cn(
831
- "cursor-pointer rounded px-2 py-1.5 text-left text-sm outline-none data-[highlighted]:bg-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
832
- item.destructive && "text-destructive"
833
- ),
834
- children: item.label
835
- },
836
- i
837
- ))
838
- }
839
- ) }) })
840
- ] });
841
- }
842
- var ToastContext = React.createContext(null);
843
- function useToast() {
844
- const toast = React.useContext(ToastContext);
845
- if (!toast) throw new Error("useToast must be used within ToastProvider");
846
- return toast;
847
- }
848
- var TOAST_TTL_MS = 4e3;
849
- var TONE = {
850
- success: "border-l-status-success",
851
- error: "border-l-status-blocked",
852
- info: "border-l-status-info"
853
- };
854
- function ToastProvider({ children }) {
855
- const [toasts, setToasts] = React.useState([]);
856
- const nextId = React.useRef(0);
857
- const toast = React.useCallback((input) => {
858
- const id = nextId.current++;
859
- setToasts((prev) => [...prev, { id, ...input }]);
860
- setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), TOAST_TTL_MS);
861
- }, []);
862
- return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: toast, children: [
863
- children,
864
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none fixed bottom-4 right-4 z-[60] flex w-80 flex-col gap-2", children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
816
+ const root = React__namespace.useRef(null);
817
+ React__namespace.useEffect(() => {
818
+ if (!open) return;
819
+ const onPointerDown = (e) => {
820
+ if (!root.current?.contains(e.target)) onOpenChange(false);
821
+ };
822
+ const onKeyDown = (e) => {
823
+ if (e.key === "Escape") onOpenChange(false);
824
+ };
825
+ document.addEventListener("mousedown", onPointerDown);
826
+ document.addEventListener("keydown", onKeyDown);
827
+ return () => {
828
+ document.removeEventListener("mousedown", onPointerDown);
829
+ document.removeEventListener("keydown", onKeyDown);
830
+ };
831
+ }, [open, onOpenChange]);
832
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: root, className: "relative inline-block", children: [
833
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-expanded": open, onClick: () => onOpenChange(!open), children: trigger }),
834
+ open && /* @__PURE__ */ jsxRuntime.jsx(
865
835
  "div",
866
836
  {
867
- role: "status",
868
837
  className: cn(
869
- "pointer-events-auto rounded-lg border border-l-4 bg-card px-4 py-3 text-foreground shadow-md",
870
- TONE[t.variant ?? "success"]
871
- ),
872
- children: [
873
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: t.title }),
874
- t.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 break-all text-xs text-muted-foreground", children: t.description })
875
- ]
876
- },
877
- t.id
878
- )) })
879
- ] });
880
- }
881
- var SIDES = {
882
- top: "bottom-full left-1/2 -translate-x-1/2 mb-1.5",
883
- right: "left-full top-1/2 -translate-y-1/2 ml-1.5",
884
- bottom: "top-full left-1/2 -translate-x-1/2 mt-1.5",
885
- left: "right-full top-1/2 -translate-y-1/2 mr-1.5"
886
- };
887
- function Tooltip({ label, children, side = "top", className }) {
888
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "group/tt relative inline-flex", children: [
889
- children,
890
- /* @__PURE__ */ jsxRuntime.jsx(
891
- "span",
892
- {
893
- role: "tooltip",
894
- className: cn(
895
- "pointer-events-none absolute z-50 whitespace-nowrap rounded-md bg-foreground px-2 py-1 text-xs font-medium text-background opacity-0 shadow-md transition-opacity group-hover/tt:opacity-100",
896
- SIDES[side],
838
+ "absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg",
839
+ align === "end" ? "right-0" : "left-0",
897
840
  className
898
841
  ),
899
- children: label
842
+ children
900
843
  }
901
844
  )
902
845
  ] });
903
846
  }
847
+ function DropdownMenu({ trigger, items, align = "end", className }) {
848
+ const [open, setOpen] = React__namespace.useState(false);
849
+ return /* @__PURE__ */ jsxRuntime.jsx(
850
+ Popover,
851
+ {
852
+ open,
853
+ onOpenChange: setOpen,
854
+ trigger,
855
+ align,
856
+ className: cn("p-1", className),
857
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { role: "menu", className: "flex flex-col", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
858
+ "button",
859
+ {
860
+ type: "button",
861
+ role: "menuitem",
862
+ disabled: item.disabled,
863
+ className: cn(
864
+ "cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50",
865
+ item.destructive && "text-destructive"
866
+ ),
867
+ onClick: () => {
868
+ setOpen(false);
869
+ item.onSelect();
870
+ },
871
+ children: item.label
872
+ },
873
+ i
874
+ )) })
875
+ }
876
+ );
877
+ }
904
878
 
905
879
  exports.AppApiProvider = AppApiProvider;
906
880
  exports.AppContextProvider = AppContextProvider;
@@ -909,8 +883,6 @@ exports.Badge = Badge;
909
883
  exports.Button = Button;
910
884
  exports.Card = Card;
911
885
  exports.CardContent = CardContent;
912
- exports.CardDescription = CardDescription;
913
- exports.CardFooter = CardFooter;
914
886
  exports.CardHeader = CardHeader;
915
887
  exports.CardTitle = CardTitle;
916
888
  exports.Checkbox = Checkbox;
@@ -936,10 +908,6 @@ exports.TabsContent = TabsContent;
936
908
  exports.TabsList = TabsList;
937
909
  exports.TabsTrigger = TabsTrigger;
938
910
  exports.Textarea = Textarea;
939
- exports.ToastProvider = ToastProvider;
940
- exports.Tooltip = Tooltip;
941
- exports.badgeVariants = badgeVariants;
942
- exports.buttonVariants = buttonVariants;
943
911
  exports.cn = cn;
944
912
  exports.copyToClipboard = copyToClipboard;
945
913
  exports.downloadBlob = downloadBlob;
@@ -950,6 +918,5 @@ exports.useAppContext = useAppContext;
950
918
  exports.useAppRun = useAppRun;
951
919
  exports.useAppRuns = useAppRuns;
952
920
  exports.useAppSettings = useAppSettings;
953
- exports.useToast = useToast;
954
921
  //# sourceMappingURL=index.cjs.map
955
922
  //# sourceMappingURL=index.cjs.map