@geomak/ui 5.9.0 → 6.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { colors_default } from './chunk-GKXP6OJJ.js';
2
2
  export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-GKXP6OJJ.js';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import React8, { createContext, useState, useEffect, useMemo, useCallback, useContext, useRef, useId, useLayoutEffect, useSyncExternalStore } from 'react';
4
+ import React8, { createContext, useState, useEffect, useMemo, useId, useCallback, useContext, useRef, useLayoutEffect, useSyncExternalStore } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
7
7
  import * as Dialog from '@radix-ui/react-dialog';
@@ -883,7 +883,8 @@ function Tooltip({
883
883
  title,
884
884
  placement = "top",
885
885
  delayDuration = 300,
886
- sideOffset = 8
886
+ sideOffset = 8,
887
+ className = ""
887
888
  }) {
888
889
  return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsxs(TooltipPrimitive.Root, { children: [
889
890
  /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "inline-flex", children }) }),
@@ -903,8 +904,9 @@ function Tooltip({
903
904
  // Out animation (always the same — just fade)
904
905
  "data-[state=closed]:animate-tooltip-out",
905
906
  // In animation — direction-aware
906
- ANIMATION[placement]
907
- ].join(" "),
907
+ ANIMATION[placement],
908
+ className
909
+ ].filter(Boolean).join(" "),
908
910
  children: [
909
911
  title,
910
912
  /* @__PURE__ */ jsx(
@@ -921,131 +923,225 @@ function Tooltip({
921
923
  ] }) });
922
924
  }
923
925
  var TooltipProvider = TooltipPrimitive.Provider;
926
+ var TabsContext = createContext(null);
927
+ function useTabsContext() {
928
+ const ctx = useContext(TabsContext);
929
+ if (!ctx) throw new Error("Tabs.List / Tabs.Trigger / Tabs.Panel must be rendered inside <Tabs>.");
930
+ return ctx;
931
+ }
932
+ var SIZE = {
933
+ sm: { trigger: "h-8 text-xs px-2.5", icon: "h-3.5 w-3.5", add: "h-8 w-8" },
934
+ md: { trigger: "h-10 text-sm px-3", icon: "h-4 w-4", add: "h-10 w-9" },
935
+ lg: { trigger: "h-12 text-sm px-4", icon: "h-[18px] w-[18px]", add: "h-12 w-10" }
936
+ };
937
+ var MARKER_TRANSITION = { duration: 0.26, ease: [0.16, 1, 0.3, 1] };
924
938
  function Tabs({
925
- tabs = [],
926
- onTabChange,
927
- onTabClose,
928
- isLazy,
929
- tabsClosable = true,
930
- defaultActiveTab
939
+ value,
940
+ defaultValue,
941
+ onValueChange,
942
+ variant = "underline",
943
+ size = "md",
944
+ orientation = "horizontal",
945
+ className = "",
946
+ style,
947
+ children
931
948
  }) {
932
- const [value, setValue] = useState(() => defaultActiveTab ?? tabs[0]?.key ?? "");
933
- useEffect(() => {
934
- if (defaultActiveTab) setValue(defaultActiveTab);
935
- }, [defaultActiveTab]);
936
- useEffect(() => {
937
- if (tabs.length === 0) {
938
- setValue("");
939
- return;
940
- }
941
- const exists = tabs.find((t) => t.key === value);
942
- if (!exists) {
943
- setValue(tabs[tabs.length - 1].key);
944
- }
945
- }, [tabs, value]);
946
- const handleValueChange = (newValue) => {
947
- const prev = tabs.find((t) => t.key === value);
948
- const next = tabs.find((t) => t.key === newValue);
949
- onTabChange?.(prev, next);
950
- setValue(newValue);
951
- };
952
- const toPreviousTab = () => {
953
- const idx = tabs.findIndex((t) => t.key === value);
954
- if (idx > 0) handleValueChange(tabs[idx - 1].key);
955
- };
956
- const toNextTab = () => {
957
- const idx = tabs.findIndex((t) => t.key === value);
958
- if (idx < tabs.length - 1) handleValueChange(tabs[idx + 1].key);
949
+ const isControlled = value !== void 0;
950
+ const [internal, setInternal] = useState(defaultValue);
951
+ const current = isControlled ? value : internal;
952
+ const reduced = !!useReducedMotion();
953
+ const indicatorId = useId();
954
+ const handle = (next) => {
955
+ if (!isControlled) setInternal(next);
956
+ onValueChange?.(next);
959
957
  };
960
- if (tabs.length === 0) return null;
961
- return /* @__PURE__ */ jsxs(
958
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { value: current, variant, size, orientation, indicatorId, reduced }, children: /* @__PURE__ */ jsx(
962
959
  TabsPrimitive.Root,
960
+ {
961
+ value: current,
962
+ onValueChange: handle,
963
+ orientation,
964
+ className: [
965
+ "flex min-w-0",
966
+ orientation === "vertical" ? "flex-row gap-4" : "flex-col gap-3",
967
+ className
968
+ ].filter(Boolean).join(" "),
969
+ style,
970
+ children
971
+ }
972
+ ) });
973
+ }
974
+ function TabsList({ children, "aria-label": ariaLabel, className = "" }) {
975
+ const { variant, orientation, reduced } = useTabsContext();
976
+ const horizontal = orientation === "horizontal";
977
+ const scrollRef = useRef(null);
978
+ const [edges, setEdges] = useState({ start: false, end: false });
979
+ const scrollable = variant !== "segmented";
980
+ useLayoutEffect(() => {
981
+ const el = scrollRef.current;
982
+ if (!el || !scrollable) return;
983
+ const update = () => {
984
+ if (horizontal) {
985
+ setEdges({
986
+ start: el.scrollLeft > 1,
987
+ end: el.scrollLeft + el.clientWidth < el.scrollWidth - 1
988
+ });
989
+ } else {
990
+ setEdges({
991
+ start: el.scrollTop > 1,
992
+ end: el.scrollTop + el.clientHeight < el.scrollHeight - 1
993
+ });
994
+ }
995
+ };
996
+ update();
997
+ el.addEventListener("scroll", update, { passive: true });
998
+ const ro = new ResizeObserver(update);
999
+ ro.observe(el);
1000
+ return () => {
1001
+ el.removeEventListener("scroll", update);
1002
+ ro.disconnect();
1003
+ };
1004
+ }, [horizontal, scrollable, children]);
1005
+ const nudge = useCallback((dir) => {
1006
+ const el = scrollRef.current;
1007
+ if (!el) return;
1008
+ const amount = (horizontal ? el.clientWidth : el.clientHeight) * 0.7 * dir;
1009
+ el.scrollBy({ [horizontal ? "left" : "top"]: amount, behavior: reduced ? "auto" : "smooth" });
1010
+ }, [horizontal, reduced]);
1011
+ const maskStyle = scrollable && (edges.start || edges.end) ? (() => {
1012
+ const dir = horizontal ? "to right" : "to bottom";
1013
+ const a = edges.start ? "transparent, black 36px" : "black";
1014
+ const b = edges.end ? "black calc(100% - 36px), transparent" : "black";
1015
+ const img = `linear-gradient(${dir}, ${a}, ${b})`;
1016
+ return { maskImage: img, WebkitMaskImage: img };
1017
+ })() : {};
1018
+ const trackClass = (() => {
1019
+ if (variant === "segmented") {
1020
+ return horizontal ? "inline-flex items-center gap-1 rounded-lg border border-border bg-surface-raised p-1 w-fit" : "inline-flex flex-col items-stretch gap-1 rounded-lg border border-border bg-surface-raised p-1 w-fit";
1021
+ }
1022
+ const hairline = horizontal ? "border-b border-border" : "border-r border-border";
1023
+ const align = variant === "enclosed" && horizontal ? "items-end" : "items-stretch";
1024
+ return `flex ${horizontal ? "flex-row" : "flex-col"} ${align} gap-1 ${hairline}`;
1025
+ })();
1026
+ const scrollClass = scrollable ? horizontal ? "overflow-x-auto overflow-y-hidden hidden-scrollbar" : "overflow-y-auto overflow-x-hidden hidden-scrollbar" : "";
1027
+ return /* @__PURE__ */ jsxs("div", { className: ["relative flex min-w-0", horizontal ? "flex-row items-stretch" : "flex-col items-stretch", className].filter(Boolean).join(" "), children: [
1028
+ scrollable && edges.start && /* @__PURE__ */ jsx(Chevron, { side: "start", orientation, onClick: () => nudge(-1) }),
1029
+ /* @__PURE__ */ jsx(
1030
+ TabsPrimitive.List,
1031
+ {
1032
+ ref: scrollRef,
1033
+ "aria-label": ariaLabel,
1034
+ className: [scrollClass, trackClass, "min-w-0 flex-1"].filter(Boolean).join(" "),
1035
+ style: maskStyle,
1036
+ children
1037
+ }
1038
+ ),
1039
+ scrollable && edges.end && /* @__PURE__ */ jsx(Chevron, { side: "end", orientation, onClick: () => nudge(1) })
1040
+ ] });
1041
+ }
1042
+ function Chevron({ side, orientation, onClick }) {
1043
+ const horizontal = orientation === "horizontal";
1044
+ const rotate = horizontal ? side === "start" ? "rotate-180" : "" : side === "start" ? "-rotate-90" : "rotate-90";
1045
+ const pos = horizontal ? side === "start" ? "left-0 top-1/2 -translate-y-1/2" : "right-0 top-1/2 -translate-y-1/2" : side === "start" ? "top-0 left-1/2 -translate-x-1/2" : "bottom-0 left-1/2 -translate-x-1/2";
1046
+ return /* @__PURE__ */ jsx(
1047
+ "button",
1048
+ {
1049
+ type: "button",
1050
+ "aria-label": side === "start" ? "Scroll tabs backward" : "Scroll tabs forward",
1051
+ onClick,
1052
+ className: `absolute z-20 ${pos} flex h-7 w-7 items-center justify-center rounded-full border border-border bg-surface text-foreground-secondary shadow-sm hover:text-foreground hover:bg-surface-raised transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent`,
1053
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: `h-4 w-4 ${rotate}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) })
1054
+ }
1055
+ );
1056
+ }
1057
+ function TabsTrigger({ value, icon, badge, closeable, onClose, disabled, className = "", children }) {
1058
+ const { value: active, variant, size, orientation, indicatorId, reduced } = useTabsContext();
1059
+ const isActive = active === value;
1060
+ const horizontal = orientation === "horizontal";
1061
+ const sz = SIZE[size];
1062
+ const base = "group/trigger relative inline-flex items-center justify-center whitespace-nowrap font-medium select-none transition-colors duration-150 focus:outline-none disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0";
1063
+ const variantCls = variant === "segmented" ? `rounded-md ${isActive ? "text-accent" : "text-foreground-secondary hover:text-foreground"} focus-visible:text-accent` : variant === "enclosed" ? `${horizontal ? "rounded-t-md border border-b-0 -mb-px" : "rounded-l-md border border-r-0 -mr-px"} ${isActive ? "bg-surface border-border text-foreground" : "border-transparent text-foreground-secondary hover:text-foreground hover:bg-surface-raised"} focus-visible:text-accent` : `${isActive ? "text-accent" : "text-foreground-secondary hover:text-foreground"} focus-visible:text-accent`;
1064
+ const trigger = /* @__PURE__ */ jsxs(
1065
+ TabsPrimitive.Trigger,
963
1066
  {
964
1067
  value,
965
- onValueChange: handleValueChange,
966
- className: "h-full max-w-full flex flex-col gap-2",
1068
+ disabled,
1069
+ className: [base, sz.trigger, closeable ? "pr-8" : "", variantCls, className].filter(Boolean).join(" "),
967
1070
  children: [
968
- /* @__PURE__ */ jsxs("div", { className: "bg-surface border border-border rounded-lg flex items-center justify-between flex-shrink-0 w-full p-1 overflow-hidden", children: [
969
- /* @__PURE__ */ jsx(
970
- "button",
971
- {
972
- type: "button",
973
- onClick: toPreviousTab,
974
- "aria-label": "Previous tab",
975
- className: "cursor-pointer rounded-lg transition-colors duration-150 hover:bg-surface-raised text-foreground-secondary hover:text-foreground rotate-180 flex-shrink-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
976
- children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-6 w-6", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) })
977
- }
978
- ),
979
- /* @__PURE__ */ jsx(
980
- TabsPrimitive.List,
981
- {
982
- "aria-label": "Tabs",
983
- className: "flex-1 flex items-center gap-1 overflow-x-auto overflow-y-hidden rounded-lg scroll-smooth snap-x snap-mandatory hidden-scrollbar",
984
- children: tabs.map((tab) => (
985
- // Trigger + close button are SIBLINGS, not nested.
986
- // Nesting a clickable element inside <button> is invalid
987
- // HTML and breaks keyboard activation of the inner one.
988
- // The wrapper carries `group` so the close button can
989
- // react to the trigger's `data-state=active` for styling.
990
- /* @__PURE__ */ jsxs(
991
- "div",
992
- {
993
- className: "snap-start snap-always relative flex items-center flex-1 min-w-[120px] max-w-[220px] flex-shrink-0 group",
994
- children: [
995
- /* @__PURE__ */ jsx(
996
- TabsPrimitive.Trigger,
997
- {
998
- value: tab.key,
999
- className: `w-full ${tabsClosable ? "pr-8" : "pr-3"} pl-3 py-2 rounded-3xl cursor-pointer transition-all duration-200 select-none h-10 text-left
1000
- text-foreground-secondary bg-surface-raised
1001
- hover:bg-surface hover:text-foreground
1002
- data-[state=active]:bg-accent data-[state=active]:text-accent-foreground
1003
- focus:outline-none focus-visible:ring-2 focus-visible:ring-accent`,
1004
- children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm block", children: tab.title })
1005
- }
1006
- ),
1007
- tabsClosable && /* @__PURE__ */ jsx(
1008
- "button",
1009
- {
1010
- type: "button",
1011
- "aria-label": `Close ${tab.title}`,
1012
- onClick: (e) => {
1013
- e.stopPropagation();
1014
- onTabClose?.(tab.key);
1015
- },
1016
- className: "absolute right-1.5 top-1/2 -translate-y-1/2 rounded p-0.5 text-foreground-secondary group-data-[state=active]:text-accent-foreground hover:bg-black/10 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
1017
- children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1018
- }
1019
- )
1020
- ]
1021
- },
1022
- tab.key
1023
- )
1024
- ))
1025
- }
1026
- ),
1027
- /* @__PURE__ */ jsx(
1028
- "button",
1029
- {
1030
- type: "button",
1031
- onClick: toNextTab,
1032
- "aria-label": "Next tab",
1033
- className: "cursor-pointer rounded-lg transition-colors duration-150 hover:bg-surface-raised text-foreground-secondary hover:text-foreground flex-shrink-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
1034
- children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-6 w-6", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) })
1035
- }
1036
- )
1071
+ variant === "segmented" && isActive && /* @__PURE__ */ jsx(
1072
+ motion.span,
1073
+ {
1074
+ layoutId: `${indicatorId}-seg`,
1075
+ className: "absolute inset-0 rounded-md bg-surface shadow-sm",
1076
+ transition: reduced ? { duration: 0 } : MARKER_TRANSITION,
1077
+ "aria-hidden": "true"
1078
+ }
1079
+ ),
1080
+ /* @__PURE__ */ jsxs("span", { className: "relative z-[1] inline-flex items-center gap-2 min-w-0", children: [
1081
+ icon && /* @__PURE__ */ jsx("span", { className: `flex-shrink-0 inline-flex items-center justify-center ${sz.icon}`, children: icon }),
1082
+ /* @__PURE__ */ jsx("span", { className: "truncate", children }),
1083
+ badge != null && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-border px-1 text-[11px] font-semibold leading-none text-foreground-secondary group-data-[state=active]/trigger:bg-accent group-data-[state=active]/trigger:text-accent-foreground transition-colors", children: badge })
1037
1084
  ] }),
1038
- /* @__PURE__ */ jsx("div", { className: "p-2 rounded-lg w-full flex-1 min-h-0 bg-surface border border-border overflow-hidden", children: isLazy ? (
1039
- // Mount only the active content
1040
- tabs.filter((t) => t.key === value).map((t) => /* @__PURE__ */ jsx(TabsPrimitive.Content, { value: t.key, className: "w-full h-full focus:outline-none", children: t.content }, t.key))
1041
- ) : (
1042
- // Pre-mount all, hide non-active via Radix
1043
- tabs.map((t) => /* @__PURE__ */ jsx(TabsPrimitive.Content, { value: t.key, className: "w-full h-full focus:outline-none", forceMount: true, children: /* @__PURE__ */ jsx("div", { className: `w-full h-full ${t.key === value ? "block" : "hidden"}`, children: t.content }) }, t.key))
1044
- ) })
1085
+ variant === "underline" && isActive && /* @__PURE__ */ jsx(
1086
+ motion.span,
1087
+ {
1088
+ layoutId: `${indicatorId}-line`,
1089
+ className: horizontal ? "absolute left-2 right-2 bottom-0 h-0.5 rounded-full bg-accent" : "absolute top-1.5 bottom-1.5 right-0 w-0.5 rounded-full bg-accent",
1090
+ transition: reduced ? { duration: 0 } : MARKER_TRANSITION,
1091
+ "aria-hidden": "true"
1092
+ }
1093
+ )
1045
1094
  ]
1046
1095
  }
1047
1096
  );
1097
+ if (!closeable) return trigger;
1098
+ return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex items-center flex-shrink-0", children: [
1099
+ trigger,
1100
+ /* @__PURE__ */ jsx(
1101
+ "button",
1102
+ {
1103
+ type: "button",
1104
+ "aria-label": "Close tab",
1105
+ onClick: (e) => {
1106
+ e.stopPropagation();
1107
+ onClose?.();
1108
+ },
1109
+ className: "absolute right-1.5 top-1/2 z-[2] -translate-y-1/2 inline-flex h-5 w-5 items-center justify-center rounded text-foreground-muted hover:text-status-error hover:bg-surface-raised transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent",
1110
+ children: /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
1111
+ }
1112
+ )
1113
+ ] });
1114
+ }
1115
+ function TabsAdd({ onClick, "aria-label": ariaLabel = "Add tab", className = "" }) {
1116
+ const { size } = useTabsContext();
1117
+ return /* @__PURE__ */ jsx(
1118
+ "button",
1119
+ {
1120
+ type: "button",
1121
+ onClick,
1122
+ "aria-label": ariaLabel,
1123
+ className: `flex-shrink-0 inline-flex items-center justify-center rounded-md text-foreground-muted hover:text-foreground hover:bg-surface-raised transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${SIZE[size].add} ${className}`.trim(),
1124
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 5v14M5 12h14" }) })
1125
+ }
1126
+ );
1127
+ }
1128
+ function TabsPanel({ value, keepMounted, className = "", style, children }) {
1129
+ return /* @__PURE__ */ jsx(
1130
+ TabsPrimitive.Content,
1131
+ {
1132
+ value,
1133
+ forceMount: keepMounted || void 0,
1134
+ className: ["min-w-0 flex-1 focus:outline-none data-[state=inactive]:hidden", className].filter(Boolean).join(" "),
1135
+ style,
1136
+ children
1137
+ }
1138
+ );
1048
1139
  }
1140
+ Tabs.List = TabsList;
1141
+ Tabs.Trigger = TabsTrigger;
1142
+ Tabs.Panel = TabsPanel;
1143
+ Tabs.Add = TabsAdd;
1144
+ var Tabs_default = Tabs;
1049
1145
  var isParent = (item) => Boolean(item.children && item.children.length > 0);
1050
1146
  function TreeNodeItem({
1051
1147
  item,
@@ -1137,9 +1233,11 @@ function Tree({
1137
1233
  nodes,
1138
1234
  onNodeClick,
1139
1235
  defaultExpandAll = false,
1140
- defaultExpandedKeys = []
1236
+ defaultExpandedKeys = [],
1237
+ className = "",
1238
+ style
1141
1239
  }) {
1142
- return /* @__PURE__ */ jsx("div", { className: "p-1 w-full", children: nodes.map((item) => /* @__PURE__ */ jsx(
1240
+ return /* @__PURE__ */ jsx("div", { className: `p-1 w-full ${className}`.trim(), style, children: nodes.map((item) => /* @__PURE__ */ jsx(
1143
1241
  TreeNodeItem,
1144
1242
  {
1145
1243
  item,
@@ -1406,7 +1504,8 @@ function LoadingSpinner({
1406
1504
  inline = false,
1407
1505
  spinnerColor,
1408
1506
  textColor,
1409
- backdropOpacity = 0.8
1507
+ backdropOpacity = 0.8,
1508
+ className = ""
1410
1509
  }) {
1411
1510
  const reduced = useReducedMotion();
1412
1511
  const letters = prompt ? Array.from(prompt) : [];
@@ -1441,7 +1540,7 @@ function LoadingSpinner({
1441
1540
  role: "status",
1442
1541
  "aria-live": "polite",
1443
1542
  "aria-label": prompt ?? "Loading",
1444
- className: "flex flex-col items-center justify-center gap-3",
1543
+ className: `flex flex-col items-center justify-center gap-3 ${className}`.trim(),
1445
1544
  children: content
1446
1545
  }
1447
1546
  );
@@ -1452,7 +1551,7 @@ function LoadingSpinner({
1452
1551
  role: "status",
1453
1552
  "aria-live": "polite",
1454
1553
  "aria-label": prompt ?? "Loading",
1455
- className: "fixed inset-0 z-[8000000] flex flex-col items-center justify-center gap-6 bg-background backdrop-blur-sm",
1554
+ className: `fixed inset-0 z-[8000000] flex flex-col items-center justify-center gap-6 bg-background backdrop-blur-sm ${className}`.trim(),
1456
1555
  style: { opacity: backdropOpacity },
1457
1556
  children: content
1458
1557
  }
@@ -1561,7 +1660,8 @@ function ScalableContainer({
1561
1660
  assignClassOnClick,
1562
1661
  expandIcon,
1563
1662
  collapseIcon,
1564
- togglePosition = "top-right"
1663
+ togglePosition = "top-right",
1664
+ className = ""
1565
1665
  }) {
1566
1666
  const containerRef = useRef(null);
1567
1667
  const [internalScaled, setInternalScaled] = useState(false);
@@ -1596,8 +1696,9 @@ function ScalableContainer({
1596
1696
  // OS-window aesthetic: subtle elevation at rest, lifted shadow
1597
1697
  // when expanded. No background colour change.
1598
1698
  isScaled ? "shadow-2xl" : "shadow-md",
1599
- "transition-shadow duration-300"
1600
- ].join(" "),
1699
+ "transition-shadow duration-300",
1700
+ className
1701
+ ].filter(Boolean).join(" "),
1601
1702
  children: [
1602
1703
  /* @__PURE__ */ jsx(Tooltip, { placement: "bottom", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
1603
1704
  "button",
@@ -1649,12 +1750,13 @@ function OpaqueGridCard({
1649
1750
  item,
1650
1751
  isRight = false,
1651
1752
  buttonText = "Open Application",
1652
- onOpen
1753
+ onOpen,
1754
+ className = ""
1653
1755
  }) {
1654
1756
  return /* @__PURE__ */ jsxs(
1655
1757
  "div",
1656
1758
  {
1657
- className: `flex flex-col w-[200px] h-[250px] rounded-lg items-center p-2 ${!isRight ? "opaque-carousel-card-left dark:opaque-carousel-card-dark-left" : "opaque-carousel-card-right dark:opaque-carousel-card-dark-right"}`,
1759
+ className: `flex flex-col w-[200px] h-[250px] rounded-lg items-center p-2 ${!isRight ? "opaque-carousel-card-left dark:opaque-carousel-card-dark-left" : "opaque-carousel-card-right dark:opaque-carousel-card-dark-right"} ${className}`.trim(),
1658
1760
  children: [
1659
1761
  /* @__PURE__ */ jsx(
1660
1762
  "div",
@@ -1696,10 +1798,10 @@ function OpaqueGridCard({
1696
1798
  }
1697
1799
  );
1698
1800
  }
1699
- function CatalogGrid({ items, buttonText, onOpen }) {
1700
- return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: items.map((item) => /* @__PURE__ */ jsx(GridCard, { item, buttonText, onOpen }, item.key)) });
1801
+ function CatalogGrid({ items, buttonText, onOpen, className = "" }) {
1802
+ return /* @__PURE__ */ jsx("div", { className: `flex flex-wrap gap-2 ${className}`.trim(), children: items.map((item) => /* @__PURE__ */ jsx(GridCard, { item, buttonText, onOpen }, item.key)) });
1701
1803
  }
1702
- function CatalogCarousel({ items, buttonText, onOpen }) {
1804
+ function CatalogCarousel({ items, buttonText, onOpen, className = "" }) {
1703
1805
  const [activeIndex, setActiveIndex] = useState(0);
1704
1806
  const [indexPool, setIndexPool] = useState([]);
1705
1807
  const cardRefs = useRef([]);
@@ -1736,7 +1838,7 @@ function CatalogCarousel({ items, buttonText, onOpen }) {
1736
1838
  }, [activeIndex, getIndexes, items.length]);
1737
1839
  const nextApp = () => setActiveIndex((prev) => prev + 1 === items.length ? 0 : prev + 1);
1738
1840
  const previousApp = () => setActiveIndex((prev) => prev - 1 === -1 ? items.length - 1 : prev - 1);
1739
- return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-full h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-10", children: [
1841
+ return /* @__PURE__ */ jsx("div", { className: `flex items-center justify-center w-full h-full ${className}`.trim(), children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-10", children: [
1740
1842
  /* @__PURE__ */ jsx(
1741
1843
  "button",
1742
1844
  {
@@ -1786,16 +1888,16 @@ function CatalogCarousel({ items, buttonText, onOpen }) {
1786
1888
  )
1787
1889
  ] }) });
1788
1890
  }
1789
- function Catalog({ display: display2 = "grid", items = [], buttonText, onOpen }) {
1790
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: display2 === "grid" ? /* @__PURE__ */ jsx(CatalogGrid, { items, buttonText, onOpen }) : /* @__PURE__ */ jsx(CatalogCarousel, { items, buttonText, onOpen }) });
1891
+ function Catalog({ display: display2 = "grid", items = [], buttonText, onOpen, className = "" }) {
1892
+ return /* @__PURE__ */ jsx("div", { className: `w-full h-full ${className}`.trim(), children: display2 === "grid" ? /* @__PURE__ */ jsx(CatalogGrid, { items, buttonText, onOpen }) : /* @__PURE__ */ jsx(CatalogCarousel, { items, buttonText, onOpen }) });
1791
1893
  }
1792
- function ContextMenu({ items, children }) {
1894
+ function ContextMenu({ items, children, className = "" }) {
1793
1895
  return /* @__PURE__ */ jsxs(ContextMenuPrimitive.Root, { children: [
1794
1896
  /* @__PURE__ */ jsx(ContextMenuPrimitive.Trigger, { asChild: true, children }),
1795
1897
  /* @__PURE__ */ jsx(ContextMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1796
1898
  ContextMenuPrimitive.Content,
1797
1899
  {
1798
- className: CONTENT_CLASSNAME,
1900
+ className: `${CONTENT_CLASSNAME} ${className}`.trim(),
1799
1901
  collisionPadding: 8,
1800
1902
  children: items.map((item) => renderItem(item))
1801
1903
  }
@@ -2980,9 +3082,9 @@ function TableSkeletonBody({
2980
3082
  i
2981
3083
  )) });
2982
3084
  }
2983
- function ThemeSwitch({ checked, onChange, label = "Toggle dark mode" }) {
3085
+ function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
2984
3086
  const id = useId();
2985
- return /* @__PURE__ */ jsx("label", { htmlFor: id, className: "flex items-center gap-2 cursor-pointer select-none", children: /* @__PURE__ */ jsx(
3087
+ return /* @__PURE__ */ jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsx(
2986
3088
  SwitchPrimitive.Root,
2987
3089
  {
2988
3090
  id,
@@ -4604,7 +4706,8 @@ function DatePicker({
4604
4706
  format = defaultFormat,
4605
4707
  weekStartsOn = 0,
4606
4708
  clearable = true,
4607
- size = "md"
4709
+ size = "md",
4710
+ className = ""
4608
4711
  }) {
4609
4712
  const errorId = useId();
4610
4713
  const hasError = errorMessage != null;
@@ -4685,7 +4788,7 @@ function DatePicker({
4685
4788
  }
4686
4789
  };
4687
4790
  const displayValue = value ? format(value) : "";
4688
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4791
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-1 ${className}`.trim(), children: [
4689
4792
  /* @__PURE__ */ jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`, children: [
4690
4793
  /* @__PURE__ */ jsx(
4691
4794
  FieldLabel,
@@ -4969,7 +5072,7 @@ function TextArea({
4969
5072
  }
4970
5073
  );
4971
5074
  }
4972
- var SIZE = {
5075
+ var SIZE2 = {
4973
5076
  sm: { h: "h-control-sm", text: "text-xs", pad: "px-2.5" },
4974
5077
  md: { h: "h-control-md", text: "text-sm", pad: "px-3.5" },
4975
5078
  lg: { h: "h-control-lg", text: "text-sm", pad: "px-4" }
@@ -4991,7 +5094,7 @@ function SegmentedControl({
4991
5094
  errorMessage,
4992
5095
  "aria-label": ariaLabel
4993
5096
  }) {
4994
- const sz = SIZE[size];
5097
+ const sz = SIZE2[size];
4995
5098
  const groupId = useId();
4996
5099
  const errorId = useId();
4997
5100
  const hasError = errorMessage != null;
@@ -6592,6 +6695,6 @@ function CreditCardForm({
6592
6695
  );
6593
6696
  }
6594
6697
 
6595
- export { AppShell, AutoComplete, Avatar, Box, Button, CARD_BRANDS, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ColorPicker, ContextMenu, CreditCardForm, DateRangePicker, Drawer, Dropdown, FadingBase, Field, FieldHelpIcon, FieldLabel, FileInput, Flex, Form, FormContext, FormField, FormStore, Grid2 as Grid, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, Modal, NotificationProvider, NumberInput, OpaqueGridCard, OtpInput, Password, Portal, RadioGroup, Rating, ScalableContainer, SearchInput_default as SearchInput, SegmentedControl, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Slider, Switch, Table, Tabs, TagsInput, DatePicker as Temporal, TextArea, TextInput, ThemeProvider, ThemeSwitch, TimePicker, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Typography, Wizard, cardNumberError, cvvError, detectBrand, expiryError, fieldShell, formatCardNumber, formatExpiry, isRequired, luhnValid, onlyDigits, patterns, runFieldRules, useFieldArray, useForm, useFormField, useFormStore, useNotification };
6698
+ export { AppShell, AutoComplete, Avatar, Box, Button, CARD_BRANDS, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ColorPicker, ContextMenu, CreditCardForm, DateRangePicker, Drawer, Dropdown, FadingBase, Field, FieldHelpIcon, FieldLabel, FileInput, Flex, Form, FormContext, FormField, FormStore, Grid2 as Grid, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, Modal, NotificationProvider, NumberInput, OpaqueGridCard, OtpInput, Password, Portal, RadioGroup, Rating, ScalableContainer, SearchInput_default as SearchInput, SegmentedControl, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Slider, Switch, Table, Tabs_default as Tabs, TagsInput, DatePicker as Temporal, TextArea, TextInput, ThemeProvider, ThemeSwitch, TimePicker, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Typography, Wizard, cardNumberError, cvvError, detectBrand, expiryError, fieldShell, formatCardNumber, formatExpiry, isRequired, luhnValid, onlyDigits, patterns, runFieldRules, useFieldArray, useForm, useFormField, useFormStore, useNotification };
6596
6699
  //# sourceMappingURL=index.js.map
6597
6700
  //# sourceMappingURL=index.js.map