@inf-monkeys-tech/monkeys-design 0.4.32 → 0.4.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +226 -226
  3. package/dist/components/base/index.d.mts +2 -2
  4. package/dist/components/base/index.d.ts +2 -2
  5. package/dist/components/base/index.js +990 -28
  6. package/dist/components/base/index.js.map +1 -1
  7. package/dist/components/base/index.mjs +987 -30
  8. package/dist/components/base/index.mjs.map +1 -1
  9. package/dist/components/data-explorer/index.js.map +1 -1
  10. package/dist/components/data-explorer/index.mjs.map +1 -1
  11. package/dist/components/layout/index.js.map +1 -1
  12. package/dist/components/layout/index.mjs.map +1 -1
  13. package/dist/components/login/index.js.map +1 -1
  14. package/dist/components/login/index.mjs.map +1 -1
  15. package/dist/components/toolbar/index.js.map +1 -1
  16. package/dist/components/toolbar/index.mjs.map +1 -1
  17. package/dist/components/workbench/index.d.mts +193 -2
  18. package/dist/components/workbench/index.d.ts +193 -2
  19. package/dist/components/workbench/index.js +2164 -585
  20. package/dist/components/workbench/index.js.map +1 -1
  21. package/dist/components/workbench/index.mjs +2367 -813
  22. package/dist/components/workbench/index.mjs.map +1 -1
  23. package/dist/icons/oauth/index.js.map +1 -1
  24. package/dist/icons/oauth/index.mjs.map +1 -1
  25. package/dist/index.d.mts +3 -3
  26. package/dist/index.d.ts +3 -3
  27. package/dist/index.js +1958 -170
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +1950 -172
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/palette/index.js.map +1 -1
  32. package/dist/palette/index.mjs.map +1 -1
  33. package/dist/registry/index.js.map +1 -1
  34. package/dist/registry/index.mjs.map +1 -1
  35. package/dist/styles/artist-login.scss +374 -374
  36. package/dist/styles/global.scss +21 -21
  37. package/dist/styles/workflow-board.scss +440 -440
  38. package/dist/styles/workflow-nodes.css +340 -340
  39. package/dist/{theme-CvbotXXr.d.ts → theme-Clm5dVb0.d.mts} +10 -3
  40. package/dist/{theme-6RDum855.d.mts → theme-sIoU5-YC.d.ts} +10 -3
  41. package/dist/theme-system/index.d.mts +1 -1
  42. package/dist/theme-system/index.d.ts +1 -1
  43. package/dist/theme-system/index.js +842 -18
  44. package/dist/theme-system/index.js.map +1 -1
  45. package/dist/theme-system/index.mjs +843 -19
  46. package/dist/theme-system/index.mjs.map +1 -1
  47. package/dist/themes/artist/index.js.map +1 -1
  48. package/dist/themes/artist/index.mjs.map +1 -1
  49. package/dist/themes/bsd/index.js.map +1 -1
  50. package/dist/themes/bsd/index.mjs.map +1 -1
  51. package/dist/themes/concept/index.js.map +1 -1
  52. package/dist/themes/concept/index.mjs.map +1 -1
  53. package/dist/themes/default/index.js.map +1 -1
  54. package/dist/themes/default/index.mjs.map +1 -1
  55. package/dist/{types-BgEEUqSm.d.mts → types-Bn6PEDsX.d.mts} +163 -1
  56. package/dist/{types-BgEEUqSm.d.ts → types-Bn6PEDsX.d.ts} +163 -1
  57. package/package.json +139 -138
@@ -1,6 +1,7 @@
1
- import { forwardRef, useRef, useState, useEffect, useId, useMemo, createContext, useLayoutEffect, Children, isValidElement, useCallback, useContext } from 'react';
1
+ import { forwardRef, useRef, useState, useEffect, useId, useMemo, createContext, useContext, useLayoutEffect, Children, isValidElement, useCallback } from 'react';
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
- import '@radix-ui/react-context-menu';
3
+ import * as ContextMenu from '@radix-ui/react-context-menu';
4
+ import { useSensors, useSensor, PointerSensor, DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
4
5
 
5
6
  // src/components/workbench/WorkbenchResizableSidebar.tsx
6
7
 
@@ -707,7 +708,41 @@ var baseSlots = {
707
708
  tableEmptyActions: "mt-4 flex flex-wrap items-center justify-center gap-2",
708
709
  tableLoadingRow: "border-b border-border/60",
709
710
  tableLoadingCell: "px-3 py-2",
710
- tableLoadingSkeleton: "h-4 w-full rounded-md bg-muted/70"
711
+ tableLoadingSkeleton: "h-4 w-full rounded-md bg-muted/70",
712
+ layoutRoot: cn(
713
+ "grid min-w-0 overflow-hidden grid-rows-[auto_minmax(0,1fr)_auto] gap-3 rounded-lg border border-border/70 bg-background p-3 text-foreground",
714
+ motionBase
715
+ ),
716
+ layoutRootFull: "h-full min-h-0",
717
+ layoutHeader: "min-w-0",
718
+ layoutBody: "grid min-h-0 min-w-0 overflow-hidden gap-3",
719
+ layoutSidebar: "min-h-0 min-w-0 overflow-hidden",
720
+ layoutMain: "min-h-0 min-w-0 overflow-hidden",
721
+ layoutAside: "min-h-0 min-w-0 overflow-hidden",
722
+ layoutFooter: "min-w-0",
723
+ layoutPane: cn(
724
+ "h-full max-h-full min-h-0 min-w-0 overflow-hidden rounded-lg bg-background text-foreground",
725
+ motionBase
726
+ ),
727
+ layoutPaneScrollable: "overflow-auto",
728
+ layoutPaneBordered: "border border-border/70",
729
+ layoutPaneMuted: "bg-muted/25",
730
+ layoutPaneSoft: "bg-background/95 shadow-sm",
731
+ layoutPaneTransparent: "bg-transparent shadow-none",
732
+ layoutSplitRoot: "grid min-h-0 min-w-0 overflow-hidden",
733
+ layoutSplitHorizontal: "grid-flow-col",
734
+ layoutSplitVertical: "grid-flow-row",
735
+ layoutSplitPane: "min-h-0 min-w-0 overflow-hidden",
736
+ layoutSplitPrimary: "",
737
+ layoutSplitSecondary: "",
738
+ layoutResizeHandle: cn(
739
+ "group/resize relative z-10 flex shrink-0 items-center justify-center bg-transparent text-muted-foreground hover:bg-border/60 active:bg-border/70 focus-visible:bg-border/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
740
+ motionInteractive
741
+ ),
742
+ layoutResizeHandleHorizontal: "w-2 cursor-col-resize",
743
+ layoutResizeHandleVertical: "h-2 cursor-row-resize",
744
+ layoutResizeHandleDisabled: "cursor-default opacity-60",
745
+ layoutResizeHandleIndicator: "rounded-full bg-muted-foreground/45 group-hover/resize:bg-primary/70"
711
746
  };
712
747
  var densitySlots = {
713
748
  compact: {
@@ -781,7 +816,12 @@ var densitySlots = {
781
816
  tableCell: "px-2 py-1.5 text-xs",
782
817
  tableHeadLabel: "text-[11px]",
783
818
  tableHeadDescription: "text-[10px] leading-3",
784
- tableLoadingCell: "px-2 py-1.5"
819
+ tableLoadingCell: "px-2 py-1.5",
820
+ layoutRoot: "gap-2 p-2",
821
+ layoutBody: "gap-2",
822
+ layoutPane: "rounded-md text-xs",
823
+ layoutResizeHandleHorizontal: "w-1.5",
824
+ layoutResizeHandleVertical: "h-1.5"
785
825
  },
786
826
  default: {
787
827
  buttonBase: "h-9"
@@ -832,7 +872,12 @@ var densitySlots = {
832
872
  menuSubTrigger: "min-h-9 px-3 py-2",
833
873
  tableHead: "h-12 px-4 py-3",
834
874
  tableCell: "px-4 py-3",
835
- tableLoadingCell: "px-4 py-3"
875
+ tableLoadingCell: "px-4 py-3",
876
+ layoutRoot: "gap-4 p-4",
877
+ layoutBody: "gap-4",
878
+ layoutPane: "rounded-xl",
879
+ layoutResizeHandleHorizontal: "w-2.5",
880
+ layoutResizeHandleVertical: "h-2.5"
836
881
  }
837
882
  };
838
883
  var radiusSlots = {
@@ -876,7 +921,9 @@ var radiusSlots = {
876
921
  menuSubContent: "rounded-none",
877
922
  tableContainer: "rounded-none",
878
923
  tableEmptyIcon: "rounded-none",
879
- tableLoadingSkeleton: "rounded-none"
924
+ tableLoadingSkeleton: "rounded-none",
925
+ layoutRoot: "rounded-none",
926
+ layoutPane: "rounded-none"
880
927
  },
881
928
  sm: {
882
929
  buttonBase: "rounded-sm",
@@ -918,7 +965,9 @@ var radiusSlots = {
918
965
  menuSubContent: "rounded-sm",
919
966
  tableContainer: "rounded-sm",
920
967
  tableEmptyIcon: "rounded-sm",
921
- tableLoadingSkeleton: "rounded-sm"
968
+ tableLoadingSkeleton: "rounded-sm",
969
+ layoutRoot: "rounded-sm",
970
+ layoutPane: "rounded-sm"
922
971
  },
923
972
  md: {},
924
973
  lg: {
@@ -955,7 +1004,9 @@ var radiusSlots = {
955
1004
  menuSubContent: "rounded-lg",
956
1005
  tableContainer: "rounded-xl",
957
1006
  tableEmptyIcon: "rounded-xl",
958
- tableLoadingSkeleton: "rounded-lg"
1007
+ tableLoadingSkeleton: "rounded-lg",
1008
+ layoutRoot: "rounded-xl",
1009
+ layoutPane: "rounded-xl"
959
1010
  },
960
1011
  xl: {
961
1012
  buttonBase: "rounded-xl",
@@ -993,7 +1044,9 @@ var radiusSlots = {
993
1044
  menuSubContent: "rounded-xl",
994
1045
  tableContainer: "rounded-2xl",
995
1046
  tableEmptyIcon: "rounded-2xl",
996
- tableLoadingSkeleton: "rounded-xl"
1047
+ tableLoadingSkeleton: "rounded-xl",
1048
+ layoutRoot: "rounded-2xl",
1049
+ layoutPane: "rounded-2xl"
997
1050
  },
998
1051
  full: {
999
1052
  buttonBase: "rounded-full",
@@ -1035,7 +1088,9 @@ var radiusSlots = {
1035
1088
  menuSubContent: "rounded-2xl",
1036
1089
  tableContainer: "rounded-2xl",
1037
1090
  tableEmptyIcon: "rounded-full",
1038
- tableLoadingSkeleton: "rounded-full"
1091
+ tableLoadingSkeleton: "rounded-full",
1092
+ layoutRoot: "rounded-2xl",
1093
+ layoutPane: "rounded-2xl"
1039
1094
  }
1040
1095
  };
1041
1096
  var borderSlots = {
@@ -1077,7 +1132,10 @@ var borderSlots = {
1077
1132
  tableFooterBarAttached: "border-t border-transparent",
1078
1133
  tableRow: "border-transparent",
1079
1134
  tableEmptyRow: "border-transparent",
1080
- tableLoadingRow: "border-transparent"
1135
+ tableLoadingRow: "border-transparent",
1136
+ layoutRoot: "border-transparent",
1137
+ layoutPaneBordered: "border-transparent",
1138
+ layoutResizeHandle: "bg-transparent hover:bg-transparent active:bg-transparent focus-visible:bg-transparent"
1081
1139
  },
1082
1140
  subtle: {
1083
1141
  buttonDefault: "border-border/60",
@@ -1117,7 +1175,9 @@ var borderSlots = {
1117
1175
  tableFooterBarAttached: "border-t border-border/60",
1118
1176
  tableRow: "border-border/50",
1119
1177
  tableEmptyRow: "border-border/50",
1120
- tableLoadingRow: "border-border/50"
1178
+ tableLoadingRow: "border-border/50",
1179
+ layoutRoot: "border-border/60",
1180
+ layoutPaneBordered: "border-border/60"
1121
1181
  },
1122
1182
  solid: {},
1123
1183
  strong: {
@@ -1158,7 +1218,10 @@ var borderSlots = {
1158
1218
  tableFooterBarAttached: "border-t border-foreground/20",
1159
1219
  tableRow: "border-foreground/15",
1160
1220
  tableEmptyRow: "border-foreground/15",
1161
- tableLoadingRow: "border-foreground/15"
1221
+ tableLoadingRow: "border-foreground/15",
1222
+ layoutRoot: "border-foreground/20",
1223
+ layoutPaneBordered: "border-foreground/20",
1224
+ layoutResizeHandle: "hover:bg-foreground/15 active:bg-foreground/20 focus-visible:bg-foreground/15"
1162
1225
  }
1163
1226
  };
1164
1227
  var backgroundSlots = {
@@ -1200,7 +1263,11 @@ var backgroundSlots = {
1200
1263
  tableFooter: "bg-muted/35",
1201
1264
  tableFooterBar: "bg-muted/30 shadow-none",
1202
1265
  tableRowInteractive: "cursor-pointer hover:bg-muted/45",
1203
- tableLoadingSkeleton: "bg-muted"
1266
+ tableLoadingSkeleton: "bg-muted",
1267
+ layoutRoot: "bg-card",
1268
+ layoutPane: "bg-card",
1269
+ layoutPaneMuted: "bg-muted/35",
1270
+ layoutResizeHandle: "hover:bg-border/70 active:bg-border/80 focus-visible:bg-border/70"
1204
1271
  },
1205
1272
  soft: {
1206
1273
  buttonDefault: "bg-muted/30 hover:bg-muted/55",
@@ -1236,7 +1303,10 @@ var backgroundSlots = {
1236
1303
  tableFooter: "bg-muted/25",
1237
1304
  tableFooterBar: "bg-muted/25 shadow-none",
1238
1305
  tableRowInteractive: "cursor-pointer hover:bg-muted/35",
1239
- tableLoadingSkeleton: "bg-muted/65"
1306
+ tableLoadingSkeleton: "bg-muted/65",
1307
+ layoutRoot: "bg-background/95 shadow-sm",
1308
+ layoutPane: "bg-background/95 shadow-sm",
1309
+ layoutPaneSoft: "bg-background/95 shadow-md"
1240
1310
  },
1241
1311
  glass: {
1242
1312
  buttonBase: "backdrop-blur-md",
@@ -1297,7 +1367,13 @@ var backgroundSlots = {
1297
1367
  tableRow: "border-white/10",
1298
1368
  tableRowInteractive: "cursor-pointer hover:bg-white/[0.08]",
1299
1369
  tableHeadLabel: "text-foreground",
1300
- tableLoadingSkeleton: "bg-white/[0.16]"
1370
+ tableLoadingSkeleton: "bg-white/[0.16]",
1371
+ layoutRoot: "border-white/10 bg-white/[0.05] shadow-none backdrop-blur-md",
1372
+ layoutPane: "border-white/10 bg-white/[0.06] shadow-none backdrop-blur-md",
1373
+ layoutPaneMuted: "bg-white/[0.08]",
1374
+ layoutPaneSoft: "bg-white/[0.10] shadow-none backdrop-blur-md",
1375
+ layoutResizeHandle: "text-foreground/65 hover:bg-white/10 active:bg-white/15 focus-visible:bg-white/10",
1376
+ layoutResizeHandleIndicator: "bg-white/45 group-hover/resize:bg-white/75"
1301
1377
  },
1302
1378
  dark: {
1303
1379
  buttonBase: "border-white/15 text-white shadow-lg backdrop-blur",
@@ -1426,7 +1502,13 @@ var backgroundSlots = {
1426
1502
  menuSubTrigger: "text-white focus:bg-white/[0.10] focus:text-white data-[highlighted]:bg-white/[0.10] data-[highlighted]:text-white data-[state=open]:bg-white/[0.12]",
1427
1503
  menuSubTriggerIcon: "text-white/55",
1428
1504
  menuSubContent: "border-white/10 bg-slate-950 text-white shadow-2xl",
1429
- tableLoadingSkeleton: "bg-white/[0.14]"
1505
+ tableLoadingSkeleton: "bg-white/[0.14]",
1506
+ layoutRoot: "border-white/10 bg-slate-950 text-white shadow-none",
1507
+ layoutPane: "border-white/10 bg-slate-950 text-white shadow-none",
1508
+ layoutPaneMuted: "bg-white/[0.06]",
1509
+ layoutPaneSoft: "bg-white/[0.08] shadow-none",
1510
+ layoutResizeHandle: "text-white/65 hover:bg-white/10 active:bg-white/15 focus-visible:bg-white/10",
1511
+ layoutResizeHandleIndicator: "bg-white/45 group-hover/resize:bg-white/75"
1430
1512
  }
1431
1513
  };
1432
1514
  var presetDefaults = {
@@ -1579,6 +1661,16 @@ function getBaseButtonToneClassName(theme, tone = "default", active = false) {
1579
1661
  active && theme.slots.buttonActive
1580
1662
  );
1581
1663
  }
1664
+ function getBaseMenuItemToneClassName(theme, tone = "default") {
1665
+ return cn(
1666
+ tone === "default" && theme.slots.menuItemDefault,
1667
+ tone === "primary" && theme.slots.menuItemPrimary,
1668
+ tone === "success" && theme.slots.menuItemSuccess,
1669
+ tone === "warning" && theme.slots.menuItemWarning,
1670
+ tone === "danger" && theme.slots.menuItemDanger,
1671
+ tone === "muted" && theme.slots.menuItemMuted
1672
+ );
1673
+ }
1582
1674
  function LoadingIcon() {
1583
1675
  return /* @__PURE__ */ jsxs(
1584
1676
  "svg",
@@ -1799,6 +1891,198 @@ var BaseCheckbox = forwardRef(
1799
1891
  );
1800
1892
  }
1801
1893
  );
1894
+ function renderItemContent({
1895
+ label,
1896
+ icon,
1897
+ shortcut,
1898
+ children,
1899
+ classNames,
1900
+ inset,
1901
+ indicator
1902
+ }) {
1903
+ const resolvedLabel = children ?? label;
1904
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1905
+ indicator ? indicator : null,
1906
+ hasRenderableNode(icon) ? /* @__PURE__ */ jsx("span", { className: cn(classNames?.icon), children: icon }) : inset ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "h-4 w-4 shrink-0" }) : null,
1907
+ hasRenderableNode(resolvedLabel) ? /* @__PURE__ */ jsx("span", { className: cn(classNames?.label), children: resolvedLabel }) : null,
1908
+ hasRenderableNode(shortcut) ? /* @__PURE__ */ jsx("span", { className: cn(classNames?.shortcut), children: shortcut }) : null
1909
+ ] });
1910
+ }
1911
+ function BaseContextMenu({
1912
+ children,
1913
+ trigger,
1914
+ content,
1915
+ disabled = false,
1916
+ modal = true,
1917
+ dir,
1918
+ appearance,
1919
+ className,
1920
+ classNames,
1921
+ onOpenChange
1922
+ }) {
1923
+ const theme = resolveBaseAppearance(appearance);
1924
+ return /* @__PURE__ */ jsxs(
1925
+ ContextMenu.Root,
1926
+ {
1927
+ onOpenChange,
1928
+ modal,
1929
+ dir,
1930
+ children: [
1931
+ trigger ? /* @__PURE__ */ jsx(
1932
+ ContextMenu.Trigger,
1933
+ {
1934
+ disabled,
1935
+ className: cn(
1936
+ theme.slots.menuTrigger,
1937
+ disabled && theme.slots.menuItemDisabled,
1938
+ classNames?.trigger,
1939
+ className
1940
+ ),
1941
+ children: trigger
1942
+ }
1943
+ ) : null,
1944
+ content ? /* @__PURE__ */ jsx(BaseContextMenuContent, { appearance, className: classNames?.content, children: content }) : null,
1945
+ children
1946
+ ]
1947
+ }
1948
+ );
1949
+ }
1950
+ function BaseContextMenuTrigger({
1951
+ children,
1952
+ disabled = false,
1953
+ asChild = false,
1954
+ appearance,
1955
+ className,
1956
+ style,
1957
+ ...triggerProps
1958
+ }) {
1959
+ const theme = resolveBaseAppearance(appearance);
1960
+ return /* @__PURE__ */ jsx(
1961
+ ContextMenu.Trigger,
1962
+ {
1963
+ ...triggerProps,
1964
+ asChild,
1965
+ disabled,
1966
+ className: cn(
1967
+ !asChild && theme.slots.menuTrigger,
1968
+ disabled && !asChild && theme.slots.menuItemDisabled,
1969
+ className
1970
+ ),
1971
+ style,
1972
+ children
1973
+ }
1974
+ );
1975
+ }
1976
+ function BaseContextMenuContent({
1977
+ children,
1978
+ appearance,
1979
+ className,
1980
+ classNames,
1981
+ style,
1982
+ ...contentProps
1983
+ }) {
1984
+ const theme = resolveBaseAppearance(appearance);
1985
+ return /* @__PURE__ */ jsx(ContextMenu.Portal, { children: /* @__PURE__ */ jsx(
1986
+ ContextMenu.Content,
1987
+ {
1988
+ ...contentProps,
1989
+ className: cn(theme.slots.menuContent, classNames?.root, className),
1990
+ style: {
1991
+ ...theme.styles.menuContent,
1992
+ ...style
1993
+ },
1994
+ children
1995
+ }
1996
+ ) });
1997
+ }
1998
+ function BaseContextMenuLabel({
1999
+ children,
2000
+ appearance,
2001
+ className,
2002
+ style,
2003
+ ...labelProps
2004
+ }) {
2005
+ const theme = resolveBaseAppearance(appearance);
2006
+ return /* @__PURE__ */ jsx(
2007
+ ContextMenu.Label,
2008
+ {
2009
+ ...labelProps,
2010
+ className: cn(theme.slots.menuLabel, className),
2011
+ style,
2012
+ children
2013
+ }
2014
+ );
2015
+ }
2016
+ function BaseContextMenuSeparator({
2017
+ appearance,
2018
+ className,
2019
+ style,
2020
+ ...separatorProps
2021
+ }) {
2022
+ const theme = resolveBaseAppearance(appearance);
2023
+ return /* @__PURE__ */ jsx(
2024
+ ContextMenu.Separator,
2025
+ {
2026
+ ...separatorProps,
2027
+ className: cn(theme.slots.menuSeparator, className),
2028
+ style
2029
+ }
2030
+ );
2031
+ }
2032
+ function BaseContextMenuItem({
2033
+ children,
2034
+ label,
2035
+ icon,
2036
+ shortcut,
2037
+ tone,
2038
+ disabled = false,
2039
+ inset = false,
2040
+ appearance,
2041
+ className,
2042
+ classNames,
2043
+ style,
2044
+ onSelect,
2045
+ ...itemProps
2046
+ }) {
2047
+ const theme = resolveBaseAppearance(appearance);
2048
+ return /* @__PURE__ */ jsx(
2049
+ ContextMenu.Item,
2050
+ {
2051
+ ...itemProps,
2052
+ disabled,
2053
+ className: cn(
2054
+ theme.slots.menuItem,
2055
+ getBaseMenuItemToneClassName(theme, tone),
2056
+ disabled && theme.slots.menuItemDisabled,
2057
+ classNames?.root,
2058
+ className
2059
+ ),
2060
+ style: {
2061
+ ...theme.styles.menuItem,
2062
+ ...style
2063
+ },
2064
+ onSelect: (event) => {
2065
+ if (disabled) {
2066
+ event.preventDefault();
2067
+ return;
2068
+ }
2069
+ onSelect?.(event);
2070
+ },
2071
+ children: renderItemContent({
2072
+ children,
2073
+ label,
2074
+ icon,
2075
+ shortcut,
2076
+ inset,
2077
+ classNames: {
2078
+ icon: cn(theme.slots.menuItemIcon, classNames?.icon),
2079
+ label: cn(theme.slots.menuItemLabel, classNames?.label),
2080
+ shortcut: cn(theme.slots.menuItemShortcut, classNames?.shortcut)
2081
+ }
2082
+ })
2083
+ }
2084
+ );
2085
+ }
1802
2086
  var columnClassNames = {
1803
2087
  1: "grid-cols-1",
1804
2088
  2: "md:grid-cols-2",
@@ -1991,84 +2275,131 @@ var BaseInput = forwardRef(
1991
2275
  );
1992
2276
  }
1993
2277
  );
1994
- function findOption(options, value) {
1995
- if (value === void 0) return void 0;
1996
- return options.find((option) => option.value === value);
1997
- }
1998
- function getInitialValue(options, defaultValue) {
1999
- if (typeof defaultValue === "string") {
2000
- return defaultValue;
2001
- }
2002
- return "";
2278
+ function normalizeValues(values) {
2279
+ const nextValues = [];
2280
+ const seen = /* @__PURE__ */ new Set();
2281
+ values?.forEach((value) => {
2282
+ if (seen.has(value)) return;
2283
+ seen.add(value);
2284
+ nextValues.push(value);
2285
+ });
2286
+ return nextValues;
2003
2287
  }
2004
2288
  function getNextEnabledIndex(options, currentIndex, direction) {
2005
2289
  if (!options.length) return -1;
2290
+ const startIndex = currentIndex >= 0 ? currentIndex : 0;
2006
2291
  for (let offset = 1; offset <= options.length; offset += 1) {
2007
- const nextIndex = (currentIndex + offset * direction + options.length) % options.length;
2292
+ const nextIndex = (startIndex + offset * direction + options.length) % options.length;
2008
2293
  if (!options[nextIndex]?.disabled) {
2009
2294
  return nextIndex;
2010
2295
  }
2011
2296
  }
2012
2297
  return -1;
2013
2298
  }
2014
- var BaseSelect = forwardRef(
2015
- function BaseSelect2({
2299
+ function getFirstEnabledIndex(options) {
2300
+ return options.findIndex((option) => !option.disabled);
2301
+ }
2302
+ function getSafeTagCount(maxTagCount, total) {
2303
+ if (maxTagCount === void 0) return total;
2304
+ if (!Number.isFinite(maxTagCount)) return total;
2305
+ return Math.max(0, Math.min(total, Math.floor(maxTagCount)));
2306
+ }
2307
+ function getDefaultRemoveLabel(option) {
2308
+ return `Remove ${option.value}`;
2309
+ }
2310
+ forwardRef(
2311
+ function BaseMultiSelect2({
2016
2312
  options,
2017
- placeholder,
2313
+ value,
2314
+ defaultValue,
2315
+ name,
2316
+ placeholder = "Select options",
2018
2317
  icon,
2019
2318
  invalid = false,
2020
2319
  disabled = false,
2320
+ required = false,
2021
2321
  openForPreview = false,
2322
+ maxTagCount,
2323
+ removeLabel = getDefaultRemoveLabel,
2324
+ emptyLabel = "No options",
2022
2325
  appearance,
2023
2326
  className,
2024
2327
  classNames,
2025
2328
  style,
2026
- children,
2027
- value,
2028
- defaultValue,
2029
- onChange,
2030
- name,
2031
2329
  id,
2032
- required,
2033
2330
  "aria-invalid": nativeAriaInvalid,
2034
2331
  "aria-label": nativeAriaLabel,
2035
2332
  "aria-labelledby": nativeAriaLabelledBy,
2036
- ...selectProps
2333
+ onValueChange,
2334
+ ...rootProps
2037
2335
  }, ref) {
2038
2336
  const theme = resolveBaseAppearance(appearance);
2039
2337
  const generatedId = useId();
2040
- const selectId = id ?? generatedId;
2041
- const listboxId = `${selectId}-listbox`;
2338
+ const multiSelectId = id ?? generatedId;
2339
+ const controlId = `${multiSelectId}-control`;
2340
+ const listboxId = `${multiSelectId}-listbox`;
2042
2341
  const rootRef = useRef(null);
2043
- const selectRef = useRef(null);
2044
2342
  const optionList = options ?? [];
2045
- const isCustomSelect = optionList.length > 0;
2046
2343
  const forceOpen = openForPreview;
2047
2344
  const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
2048
2345
  const open = forceOpen || uncontrolledOpen;
2049
2346
  const [uncontrolledValue, setUncontrolledValue] = useState(
2050
- () => getInitialValue(optionList, defaultValue)
2347
+ () => normalizeValues(defaultValue)
2348
+ );
2349
+ const [activeIndex, setActiveIndex] = useState(
2350
+ () => getFirstEnabledIndex(optionList)
2051
2351
  );
2052
2352
  const isControlled = value !== void 0;
2053
- const selectedValue = String(isControlled ? value : uncontrolledValue);
2054
- const selectedOption = findOption(optionList, selectedValue);
2055
- const activeIndex = useMemo(() => {
2056
- const selectedIndex = optionList.findIndex(
2057
- (option) => option.value === selectedValue && !option.disabled
2058
- );
2059
- if (selectedIndex >= 0) return selectedIndex;
2060
- return optionList.findIndex((option) => !option.disabled);
2061
- }, [optionList, selectedValue]);
2062
- const visibleLabel = selectedOption?.label ?? placeholder;
2063
- const isPlaceholder = !selectedOption;
2064
- const setSelectRef = (node) => {
2065
- selectRef.current = node;
2353
+ const selectedValues = useMemo(
2354
+ () => normalizeValues(isControlled ? value : uncontrolledValue),
2355
+ [isControlled, uncontrolledValue, value]
2356
+ );
2357
+ const selectedValueSet = useMemo(
2358
+ () => new Set(selectedValues),
2359
+ [selectedValues]
2360
+ );
2361
+ const optionByValue = useMemo(() => {
2362
+ const map = /* @__PURE__ */ new Map();
2363
+ optionList.forEach((option) => {
2364
+ if (!map.has(option.value)) {
2365
+ map.set(option.value, option);
2366
+ }
2367
+ });
2368
+ return map;
2369
+ }, [optionList]);
2370
+ const selectedOptions = useMemo(
2371
+ () => selectedValues.map((selectedValue) => optionByValue.get(selectedValue)).filter(
2372
+ (option) => option !== void 0
2373
+ ),
2374
+ [optionByValue, selectedValues]
2375
+ );
2376
+ const firstEnabledIndex = useMemo(
2377
+ () => getFirstEnabledIndex(optionList),
2378
+ [optionList]
2379
+ );
2380
+ const resolvedActiveIndex = activeIndex >= 0 && !optionList[activeIndex]?.disabled ? activeIndex : firstEnabledIndex;
2381
+ const visibleTagCount = getSafeTagCount(
2382
+ maxTagCount,
2383
+ selectedOptions.length
2384
+ );
2385
+ const visibleOptions = selectedOptions.slice(0, visibleTagCount);
2386
+ const overflowCount = selectedOptions.length - visibleOptions.length;
2387
+ const isPlaceholder = selectedOptions.length === 0;
2388
+ const setRootRef = (node) => {
2389
+ rootRef.current = node;
2066
2390
  if (typeof ref === "function") {
2067
2391
  ref(node);
2068
2392
  } else if (ref) {
2069
2393
  ref.current = node;
2070
2394
  }
2071
2395
  };
2396
+ const setOpen = (nextOpen) => {
2397
+ if (disabled || forceOpen) return;
2398
+ setUncontrolledOpen(nextOpen);
2399
+ if (nextOpen) {
2400
+ setActiveIndex(resolvedActiveIndex);
2401
+ }
2402
+ };
2072
2403
  useEffect(() => {
2073
2404
  if (!open || forceOpen) return void 0;
2074
2405
  const handlePointerDown = (event) => {
@@ -2081,31 +2412,37 @@ var BaseSelect = forwardRef(
2081
2412
  document.removeEventListener("pointerdown", handlePointerDown);
2082
2413
  };
2083
2414
  }, [forceOpen, open]);
2084
- const notifyChange = (nextValue) => {
2085
- const selectElement = selectRef.current;
2086
- if (!selectElement) return;
2087
- const valueSetter = Object.getOwnPropertyDescriptor(
2088
- HTMLSelectElement.prototype,
2089
- "value"
2090
- )?.set;
2091
- valueSetter?.call(selectElement, nextValue);
2092
- selectElement.dispatchEvent(new Event("change", { bubbles: true }));
2093
- };
2094
- const commitValue = (nextValue, optionDisabled) => {
2095
- if (optionDisabled || disabled) return;
2096
- if (!isControlled) {
2097
- setUncontrolledValue(nextValue);
2415
+ useEffect(() => {
2416
+ if (resolvedActiveIndex >= 0 && resolvedActiveIndex !== activeIndex) {
2417
+ setActiveIndex(resolvedActiveIndex);
2098
2418
  }
2099
- notifyChange(nextValue);
2100
- if (!forceOpen) {
2101
- setUncontrolledOpen(false);
2419
+ }, [activeIndex, resolvedActiveIndex]);
2420
+ const commitValues = (nextValues) => {
2421
+ const normalizedValues = normalizeValues(nextValues);
2422
+ if (!isControlled) {
2423
+ setUncontrolledValue(normalizedValues);
2102
2424
  }
2425
+ onValueChange?.(normalizedValues);
2426
+ };
2427
+ const toggleOption = (option) => {
2428
+ if (!option || option.disabled || disabled) return;
2429
+ const nextValues = selectedValueSet.has(option.value) ? selectedValues.filter((selectedValue) => selectedValue !== option.value) : [...selectedValues, option.value];
2430
+ commitValues(nextValues);
2431
+ };
2432
+ const removeOption = (option) => {
2433
+ if (disabled) return;
2434
+ commitValues(
2435
+ selectedValues.filter((selectedValue) => selectedValue !== option.value)
2436
+ );
2103
2437
  };
2104
2438
  const focusOption = (direction) => {
2105
- const currentIndex = activeIndex >= 0 ? activeIndex : 0;
2106
- const nextIndex = getNextEnabledIndex(optionList, currentIndex, direction);
2439
+ const nextIndex = getNextEnabledIndex(
2440
+ optionList,
2441
+ resolvedActiveIndex,
2442
+ direction
2443
+ );
2107
2444
  if (nextIndex >= 0) {
2108
- commitValue(optionList[nextIndex].value, optionList[nextIndex].disabled);
2445
+ setActiveIndex(nextIndex);
2109
2446
  }
2110
2447
  };
2111
2448
  const handleKeyDown = (event) => {
@@ -2113,77 +2450,49 @@ var BaseSelect = forwardRef(
2113
2450
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
2114
2451
  event.preventDefault();
2115
2452
  if (!open) {
2116
- setUncontrolledOpen(true);
2453
+ setOpen(true);
2454
+ setActiveIndex(firstEnabledIndex);
2117
2455
  return;
2118
2456
  }
2119
2457
  focusOption(event.key === "ArrowDown" ? 1 : -1);
2120
2458
  return;
2121
2459
  }
2460
+ if (event.key === "Home") {
2461
+ event.preventDefault();
2462
+ setOpen(true);
2463
+ setActiveIndex(firstEnabledIndex);
2464
+ return;
2465
+ }
2466
+ if (event.key === "End") {
2467
+ event.preventDefault();
2468
+ setOpen(true);
2469
+ for (let index = optionList.length - 1; index >= 0; index -= 1) {
2470
+ if (!optionList[index]?.disabled) {
2471
+ setActiveIndex(index);
2472
+ break;
2473
+ }
2474
+ }
2475
+ return;
2476
+ }
2122
2477
  if (event.key === "Enter" || event.key === " ") {
2123
2478
  event.preventDefault();
2124
- if (!forceOpen) {
2125
- setUncontrolledOpen((current) => !current);
2479
+ if (!open) {
2480
+ setOpen(true);
2481
+ return;
2126
2482
  }
2483
+ toggleOption(optionList[resolvedActiveIndex]);
2127
2484
  return;
2128
2485
  }
2129
2486
  if (event.key === "Escape") {
2130
- setUncontrolledOpen(false);
2487
+ setOpen(false);
2131
2488
  }
2132
2489
  };
2133
- if (!isCustomSelect) {
2134
- return /* @__PURE__ */ jsxs(
2135
- "div",
2136
- {
2137
- className: cn(
2138
- theme.slots.controlWrapper,
2139
- invalid && theme.slots.controlInvalid,
2140
- disabled && theme.slots.controlDisabled,
2141
- classNames?.root,
2142
- className
2143
- ),
2144
- style: {
2145
- ...theme.styles.control,
2146
- ...invalid ? theme.styles.controlInvalid : void 0,
2147
- ...disabled ? theme.styles.controlDisabled : void 0,
2148
- ...style
2149
- },
2150
- children: [
2151
- hasRenderableNode(icon) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.controlIcon, classNames?.icon), children: icon }) : null,
2152
- /* @__PURE__ */ jsxs(
2153
- "select",
2154
- {
2155
- ...selectProps,
2156
- id,
2157
- ref,
2158
- name,
2159
- value,
2160
- defaultValue,
2161
- required,
2162
- disabled,
2163
- "aria-invalid": nativeAriaInvalid ?? (invalid || void 0),
2164
- "aria-label": nativeAriaLabel,
2165
- "aria-labelledby": nativeAriaLabelledBy,
2166
- onChange,
2167
- className: cn(
2168
- theme.slots.controlBase,
2169
- theme.slots.controlSelect,
2170
- classNames?.control
2171
- ),
2172
- children: [
2173
- hasRenderableNode(placeholder) ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }) : null,
2174
- children
2175
- ]
2176
- }
2177
- ),
2178
- /* @__PURE__ */ jsx("span", { className: theme.slots.selectChevron })
2179
- ]
2180
- }
2181
- );
2182
- }
2183
2490
  return /* @__PURE__ */ jsxs(
2184
2491
  "div",
2185
2492
  {
2186
- ref: rootRef,
2493
+ ...rootProps,
2494
+ id,
2495
+ ref: setRootRef,
2187
2496
  className: cn(
2188
2497
  theme.slots.controlWrapper,
2189
2498
  "overflow-visible",
@@ -2202,38 +2511,105 @@ var BaseSelect = forwardRef(
2202
2511
  children: [
2203
2512
  hasRenderableNode(icon) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.controlIcon, classNames?.icon), children: icon }) : null,
2204
2513
  /* @__PURE__ */ jsx(
2205
- "button",
2514
+ "div",
2206
2515
  {
2207
- type: "button",
2208
- id: `${selectId}-button`,
2209
- disabled,
2516
+ id: controlId,
2517
+ role: "combobox",
2518
+ tabIndex: disabled ? -1 : 0,
2210
2519
  "aria-haspopup": "listbox",
2211
2520
  "aria-expanded": open,
2212
2521
  "aria-controls": listboxId,
2522
+ "aria-disabled": disabled || void 0,
2523
+ "aria-required": required || void 0,
2213
2524
  "aria-invalid": nativeAriaInvalid ?? (invalid || void 0),
2214
2525
  "aria-label": nativeAriaLabel,
2215
2526
  "aria-labelledby": nativeAriaLabelledBy,
2216
2527
  className: cn(
2217
2528
  theme.slots.controlBase,
2218
- theme.slots.controlSelect,
2219
- "flex items-center text-left",
2529
+ "flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 py-1.5 pr-9 text-left",
2530
+ disabled && "!cursor-not-allowed",
2220
2531
  classNames?.control
2221
2532
  ),
2222
- onClick: () => {
2223
- if (!forceOpen) {
2224
- setUncontrolledOpen((current) => !current);
2225
- }
2226
- },
2533
+ onClick: () => setOpen(!open),
2227
2534
  onKeyDown: handleKeyDown,
2228
- children: /* @__PURE__ */ jsx(
2535
+ children: /* @__PURE__ */ jsxs(
2229
2536
  "span",
2230
2537
  {
2231
2538
  className: cn(
2232
- "min-w-0 flex-1 truncate",
2233
- isPlaceholder && theme.slots.selectPlaceholder,
2234
- isPlaceholder && classNames?.placeholder
2539
+ "flex min-w-0 flex-1 flex-wrap items-center gap-1.5",
2540
+ classNames?.tagList
2235
2541
  ),
2236
- children: visibleLabel
2542
+ children: [
2543
+ visibleOptions.map((option) => /* @__PURE__ */ jsxs(
2544
+ "span",
2545
+ {
2546
+ className: cn(
2547
+ "inline-flex max-w-full items-center gap-1 rounded-full border border-border/70 bg-muted/65 px-2 py-0.5 text-xs font-medium text-foreground",
2548
+ classNames?.tag
2549
+ ),
2550
+ children: [
2551
+ /* @__PURE__ */ jsx(
2552
+ "span",
2553
+ {
2554
+ className: cn(
2555
+ "max-w-40 truncate",
2556
+ classNames?.tagLabel
2557
+ ),
2558
+ children: option.label
2559
+ }
2560
+ ),
2561
+ /* @__PURE__ */ jsx(
2562
+ "button",
2563
+ {
2564
+ type: "button",
2565
+ "aria-label": removeLabel(option),
2566
+ disabled,
2567
+ className: cn(
2568
+ "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-background/80 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 disabled:!cursor-not-allowed",
2569
+ classNames?.tagRemove
2570
+ ),
2571
+ onClick: (event) => {
2572
+ event.preventDefault();
2573
+ event.stopPropagation();
2574
+ removeOption(option);
2575
+ },
2576
+ onMouseDown: (event) => {
2577
+ event.preventDefault();
2578
+ event.stopPropagation();
2579
+ },
2580
+ onKeyDown: (event) => event.stopPropagation(),
2581
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "x" })
2582
+ }
2583
+ )
2584
+ ]
2585
+ },
2586
+ option.value
2587
+ )),
2588
+ overflowCount > 0 ? /* @__PURE__ */ jsxs(
2589
+ "span",
2590
+ {
2591
+ className: cn(
2592
+ "inline-flex max-w-full items-center rounded-full border border-border/70 bg-muted/45 px-2 py-0.5 text-xs font-medium text-muted-foreground",
2593
+ classNames?.tag
2594
+ ),
2595
+ children: [
2596
+ "+",
2597
+ overflowCount
2598
+ ]
2599
+ }
2600
+ ) : null,
2601
+ isPlaceholder ? /* @__PURE__ */ jsx(
2602
+ "span",
2603
+ {
2604
+ className: cn(
2605
+ "min-w-0 truncate",
2606
+ theme.slots.selectPlaceholder,
2607
+ classNames?.placeholder
2608
+ ),
2609
+ children: placeholder
2610
+ }
2611
+ ) : null
2612
+ ]
2237
2613
  }
2238
2614
  )
2239
2615
  }
@@ -2243,50 +2619,34 @@ var BaseSelect = forwardRef(
2243
2619
  {
2244
2620
  className: cn(
2245
2621
  theme.slots.selectChevron,
2246
- open && "rotate-[225deg]"
2622
+ open && "rotate-[225deg]",
2623
+ classNames?.chevron
2247
2624
  )
2248
2625
  }
2249
2626
  ),
2250
- /* @__PURE__ */ jsxs(
2251
- "select",
2627
+ name ? selectedValues.map((selectedValue) => /* @__PURE__ */ jsx(
2628
+ "input",
2252
2629
  {
2253
- ...selectProps,
2254
- ref: setSelectRef,
2255
- id,
2630
+ type: "hidden",
2256
2631
  name,
2257
2632
  value: selectedValue,
2258
- required,
2259
- disabled,
2260
- "aria-hidden": "true",
2261
- tabIndex: -1,
2262
- className: theme.slots.selectNative,
2263
- onChange,
2264
- children: [
2265
- hasRenderableNode(placeholder) ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }) : null,
2266
- optionList.map((option) => /* @__PURE__ */ jsx(
2267
- "option",
2268
- {
2269
- value: option.value,
2270
- disabled: option.disabled,
2271
- children: typeof option.label === "string" ? option.label : option.value
2272
- },
2273
- option.value
2274
- ))
2275
- ]
2276
- }
2277
- ),
2633
+ className: classNames?.hiddenInput
2634
+ },
2635
+ selectedValue
2636
+ )) : null,
2278
2637
  open ? /* @__PURE__ */ jsx(
2279
2638
  "div",
2280
2639
  {
2281
2640
  id: listboxId,
2282
2641
  role: "listbox",
2283
- "aria-labelledby": `${selectId}-button`,
2642
+ "aria-multiselectable": "true",
2643
+ "aria-labelledby": controlId,
2284
2644
  className: cn(theme.slots.selectMenu, classNames?.menu),
2285
2645
  style: theme.styles.selectMenu,
2286
- children: optionList.map((option, index) => {
2287
- const selected = option.value === selectedValue;
2288
- const active = index === activeIndex;
2289
- return /* @__PURE__ */ jsx(
2646
+ children: optionList.length > 0 ? optionList.map((option, index) => {
2647
+ const selected = selectedValueSet.has(option.value);
2648
+ const active = index === resolvedActiveIndex;
2649
+ return /* @__PURE__ */ jsxs(
2290
2650
  "button",
2291
2651
  {
2292
2652
  type: "button",
@@ -2295,6 +2655,7 @@ var BaseSelect = forwardRef(
2295
2655
  disabled: option.disabled,
2296
2656
  className: cn(
2297
2657
  theme.slots.selectOption,
2658
+ "gap-2",
2298
2659
  active && theme.slots.selectOptionActive,
2299
2660
  selected && theme.slots.selectOptionSelected,
2300
2661
  option.disabled && theme.slots.selectOptionDisabled,
@@ -2305,13 +2666,50 @@ var BaseSelect = forwardRef(
2305
2666
  ...active ? theme.styles.selectOptionActive : void 0,
2306
2667
  ...selected ? theme.styles.selectOptionSelected : void 0
2307
2668
  },
2669
+ onMouseEnter: () => {
2670
+ if (!option.disabled) {
2671
+ setActiveIndex(index);
2672
+ }
2673
+ },
2308
2674
  onMouseDown: (event) => event.preventDefault(),
2309
- onClick: () => commitValue(option.value, option.disabled),
2310
- children: /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label })
2675
+ onClick: () => toggleOption(option),
2676
+ children: [
2677
+ /* @__PURE__ */ jsx(
2678
+ "span",
2679
+ {
2680
+ "aria-hidden": "true",
2681
+ className: cn(
2682
+ "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border border-border/70 text-[10px]",
2683
+ selected && "border-primary/40 bg-primary text-primary-foreground",
2684
+ classNames?.optionIndicator
2685
+ ),
2686
+ children: selected ? "\u2713" : null
2687
+ }
2688
+ ),
2689
+ /* @__PURE__ */ jsx(
2690
+ "span",
2691
+ {
2692
+ className: cn(
2693
+ "min-w-0 flex-1 truncate",
2694
+ classNames?.optionLabel
2695
+ ),
2696
+ children: option.label
2697
+ }
2698
+ )
2699
+ ]
2311
2700
  },
2312
2701
  option.value
2313
2702
  );
2314
- })
2703
+ }) : /* @__PURE__ */ jsx(
2704
+ "div",
2705
+ {
2706
+ className: cn(
2707
+ "px-2.5 py-2 text-sm text-muted-foreground",
2708
+ classNames?.empty
2709
+ ),
2710
+ children: emptyLabel
2711
+ }
2712
+ )
2315
2713
  }
2316
2714
  ) : null
2317
2715
  ]
@@ -2319,445 +2717,781 @@ var BaseSelect = forwardRef(
2319
2717
  );
2320
2718
  }
2321
2719
  );
2322
- function getInitialSegmentValue(options, defaultValue) {
2323
- if (defaultValue && options?.some((option) => option.value === defaultValue)) {
2324
- const defaultOption = options.find((option) => option.value === defaultValue);
2325
- if (!defaultOption?.disabled) {
2326
- return defaultValue;
2327
- }
2720
+ function findOption(options, value) {
2721
+ if (value === void 0) return void 0;
2722
+ return options.find((option) => option.value === value);
2723
+ }
2724
+ function getInitialValue(options, defaultValue) {
2725
+ if (typeof defaultValue === "string") {
2726
+ return defaultValue;
2328
2727
  }
2329
- return options?.find((option) => !option.disabled)?.value ?? options?.[0]?.value;
2728
+ return "";
2330
2729
  }
2331
- function BaseSegmentedControl({
2332
- options = [],
2333
- value,
2334
- defaultValue,
2335
- appearance,
2336
- className,
2337
- classNames,
2338
- style,
2339
- onValueChange,
2340
- ...controlProps
2341
- }) {
2342
- const theme = resolveBaseAppearance(appearance);
2343
- const [uncontrolledValue, setUncontrolledValue] = useState(
2344
- () => getInitialSegmentValue(options, defaultValue)
2345
- );
2346
- const isControlled = value !== void 0;
2347
- const selectedValue = isControlled ? value : uncontrolledValue;
2348
- const handleSelect = (nextValue, disabled) => {
2349
- if (disabled) return;
2350
- if (!isControlled) {
2351
- setUncontrolledValue(nextValue);
2352
- }
2353
- onValueChange?.(nextValue);
2354
- };
2355
- return /* @__PURE__ */ jsx(
2356
- "div",
2357
- {
2358
- ...controlProps,
2359
- role: "radiogroup",
2360
- className: cn(theme.slots.segmentedRoot, classNames?.root, className),
2361
- style: {
2362
- ...theme.styles.segmentedRoot,
2363
- ...style
2364
- },
2365
- children: options.map((option) => {
2366
- const selected = option.value === selectedValue;
2367
- return /* @__PURE__ */ jsxs(
2368
- "button",
2369
- {
2370
- type: "button",
2371
- role: "radio",
2372
- "aria-checked": selected,
2373
- disabled: option.disabled,
2374
- className: cn(
2375
- theme.slots.segmentedItem,
2376
- selected && theme.slots.segmentedItemActive,
2377
- option.disabled && theme.slots.segmentedItemDisabled,
2378
- classNames?.item
2379
- ),
2380
- style: theme.styles.segmentedItem,
2381
- onClick: () => handleSelect(option.value, option.disabled),
2382
- children: [
2383
- hasRenderableNode(option.icon) ? /* @__PURE__ */ jsx("span", { className: cn("inline-flex h-4 w-4 shrink-0", classNames?.icon), children: option.icon }) : null,
2384
- /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", classNames?.label), children: option.label })
2385
- ]
2386
- },
2387
- option.value
2388
- );
2389
- })
2730
+ function getNextEnabledIndex2(options, currentIndex, direction) {
2731
+ if (!options.length) return -1;
2732
+ for (let offset = 1; offset <= options.length; offset += 1) {
2733
+ const nextIndex = (currentIndex + offset * direction + options.length) % options.length;
2734
+ if (!options[nextIndex]?.disabled) {
2735
+ return nextIndex;
2390
2736
  }
2391
- );
2737
+ }
2738
+ return -1;
2392
2739
  }
2393
- forwardRef(
2394
- function BaseSwitch2({
2395
- label,
2396
- description,
2740
+ var BaseSelect = forwardRef(
2741
+ function BaseSelect2({
2742
+ options,
2743
+ placeholder,
2744
+ icon,
2745
+ invalid = false,
2397
2746
  disabled = false,
2747
+ openForPreview = false,
2398
2748
  appearance,
2399
2749
  className,
2400
2750
  classNames,
2401
2751
  style,
2402
- checked,
2403
- defaultChecked,
2752
+ children,
2753
+ value,
2754
+ defaultValue,
2404
2755
  onChange,
2405
- ...switchProps
2756
+ name,
2757
+ id,
2758
+ required,
2759
+ "aria-invalid": nativeAriaInvalid,
2760
+ "aria-label": nativeAriaLabel,
2761
+ "aria-labelledby": nativeAriaLabelledBy,
2762
+ ...selectProps
2406
2763
  }, ref) {
2407
2764
  const theme = resolveBaseAppearance(appearance);
2408
- const [uncontrolledChecked, setUncontrolledChecked] = useState(
2409
- defaultChecked ?? false
2765
+ const generatedId = useId();
2766
+ const selectId = id ?? generatedId;
2767
+ const listboxId = `${selectId}-listbox`;
2768
+ const rootRef = useRef(null);
2769
+ const selectRef = useRef(null);
2770
+ const optionList = options ?? [];
2771
+ const isCustomSelect = optionList.length > 0;
2772
+ const forceOpen = openForPreview;
2773
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
2774
+ const open = forceOpen || uncontrolledOpen;
2775
+ const [uncontrolledValue, setUncontrolledValue] = useState(
2776
+ () => getInitialValue(optionList, defaultValue)
2410
2777
  );
2411
- const isControlled = checked !== void 0;
2412
- const resolvedChecked = isControlled ? checked : uncontrolledChecked;
2413
- const handleChange = (event) => {
2414
- if (!isControlled) {
2415
- setUncontrolledChecked(event.currentTarget.checked);
2778
+ const isControlled = value !== void 0;
2779
+ const selectedValue = String(isControlled ? value : uncontrolledValue);
2780
+ const selectedOption = findOption(optionList, selectedValue);
2781
+ const activeIndex = useMemo(() => {
2782
+ const selectedIndex = optionList.findIndex(
2783
+ (option) => option.value === selectedValue && !option.disabled
2784
+ );
2785
+ if (selectedIndex >= 0) return selectedIndex;
2786
+ return optionList.findIndex((option) => !option.disabled);
2787
+ }, [optionList, selectedValue]);
2788
+ const visibleLabel = selectedOption?.label ?? placeholder;
2789
+ const isPlaceholder = !selectedOption;
2790
+ const setSelectRef = (node) => {
2791
+ selectRef.current = node;
2792
+ if (typeof ref === "function") {
2793
+ ref(node);
2794
+ } else if (ref) {
2795
+ ref.current = node;
2416
2796
  }
2417
- onChange?.(event);
2418
2797
  };
2419
- return /* @__PURE__ */ jsxs(
2420
- "label",
2421
- {
2422
- className: cn(
2423
- theme.slots.switchRoot,
2424
- disabled && theme.slots.switchDisabled,
2425
- classNames?.root,
2426
- className
2427
- ),
2428
- style: {
2429
- ...theme.styles.switchRoot,
2430
- ...style
2431
- },
2432
- children: [
2433
- /* @__PURE__ */ jsxs(
2434
- "span",
2435
- {
2436
- className: cn(
2437
- theme.slots.switchTrack,
2438
- resolvedChecked && theme.slots.switchChecked,
2439
- classNames?.track
2440
- ),
2441
- style: theme.styles.switchTrack,
2442
- children: [
2443
- /* @__PURE__ */ jsx(
2444
- "input",
2445
- {
2446
- ...switchProps,
2447
- ref,
2448
- type: "checkbox",
2449
- disabled,
2450
- checked,
2451
- defaultChecked,
2452
- onChange: handleChange,
2453
- className: cn(theme.slots.switchInput, classNames?.input)
2454
- }
2455
- ),
2456
- /* @__PURE__ */ jsx(
2457
- "span",
2458
- {
2459
- className: cn(
2460
- theme.slots.switchThumb,
2461
- resolvedChecked && "translate-x-5",
2462
- classNames?.thumb
2463
- ),
2464
- style: theme.styles.switchThumb
2465
- }
2466
- )
2467
- ]
2468
- }
2798
+ useEffect(() => {
2799
+ if (!open || forceOpen) return void 0;
2800
+ const handlePointerDown = (event) => {
2801
+ if (!rootRef.current?.contains(event.target)) {
2802
+ setUncontrolledOpen(false);
2803
+ }
2804
+ };
2805
+ document.addEventListener("pointerdown", handlePointerDown);
2806
+ return () => {
2807
+ document.removeEventListener("pointerdown", handlePointerDown);
2808
+ };
2809
+ }, [forceOpen, open]);
2810
+ const notifyChange = (nextValue) => {
2811
+ const selectElement = selectRef.current;
2812
+ if (!selectElement) return;
2813
+ const valueSetter = Object.getOwnPropertyDescriptor(
2814
+ HTMLSelectElement.prototype,
2815
+ "value"
2816
+ )?.set;
2817
+ valueSetter?.call(selectElement, nextValue);
2818
+ selectElement.dispatchEvent(new Event("change", { bubbles: true }));
2819
+ };
2820
+ const commitValue = (nextValue, optionDisabled) => {
2821
+ if (optionDisabled || disabled) return;
2822
+ if (!isControlled) {
2823
+ setUncontrolledValue(nextValue);
2824
+ }
2825
+ notifyChange(nextValue);
2826
+ if (!forceOpen) {
2827
+ setUncontrolledOpen(false);
2828
+ }
2829
+ };
2830
+ const focusOption = (direction) => {
2831
+ const currentIndex = activeIndex >= 0 ? activeIndex : 0;
2832
+ const nextIndex = getNextEnabledIndex2(optionList, currentIndex, direction);
2833
+ if (nextIndex >= 0) {
2834
+ commitValue(optionList[nextIndex].value, optionList[nextIndex].disabled);
2835
+ }
2836
+ };
2837
+ const handleKeyDown = (event) => {
2838
+ if (disabled) return;
2839
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
2840
+ event.preventDefault();
2841
+ if (!open) {
2842
+ setUncontrolledOpen(true);
2843
+ return;
2844
+ }
2845
+ focusOption(event.key === "ArrowDown" ? 1 : -1);
2846
+ return;
2847
+ }
2848
+ if (event.key === "Enter" || event.key === " ") {
2849
+ event.preventDefault();
2850
+ if (!forceOpen) {
2851
+ setUncontrolledOpen((current) => !current);
2852
+ }
2853
+ return;
2854
+ }
2855
+ if (event.key === "Escape") {
2856
+ setUncontrolledOpen(false);
2857
+ }
2858
+ };
2859
+ if (!isCustomSelect) {
2860
+ return /* @__PURE__ */ jsxs(
2861
+ "div",
2862
+ {
2863
+ className: cn(
2864
+ theme.slots.controlWrapper,
2865
+ invalid && theme.slots.controlInvalid,
2866
+ disabled && theme.slots.controlDisabled,
2867
+ classNames?.root,
2868
+ className
2469
2869
  ),
2470
- hasRenderableNode(label) || hasRenderableNode(description) ? /* @__PURE__ */ jsxs("span", { className: cn(theme.slots.switchContent, classNames?.content), children: [
2471
- hasRenderableNode(label) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.switchLabel, classNames?.label), children: label }) : null,
2472
- hasRenderableNode(description) ? /* @__PURE__ */ jsx(
2473
- "span",
2870
+ style: {
2871
+ ...theme.styles.control,
2872
+ ...invalid ? theme.styles.controlInvalid : void 0,
2873
+ ...disabled ? theme.styles.controlDisabled : void 0,
2874
+ ...style
2875
+ },
2876
+ children: [
2877
+ hasRenderableNode(icon) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.controlIcon, classNames?.icon), children: icon }) : null,
2878
+ /* @__PURE__ */ jsxs(
2879
+ "select",
2474
2880
  {
2881
+ ...selectProps,
2882
+ id,
2883
+ ref,
2884
+ name,
2885
+ value,
2886
+ defaultValue,
2887
+ required,
2888
+ disabled,
2889
+ "aria-invalid": nativeAriaInvalid ?? (invalid || void 0),
2890
+ "aria-label": nativeAriaLabel,
2891
+ "aria-labelledby": nativeAriaLabelledBy,
2892
+ onChange,
2475
2893
  className: cn(
2476
- theme.slots.switchDescription,
2477
- classNames?.description
2894
+ theme.slots.controlBase,
2895
+ theme.slots.controlSelect,
2896
+ classNames?.control
2478
2897
  ),
2479
- children: description
2898
+ children: [
2899
+ hasRenderableNode(placeholder) ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }) : null,
2900
+ children
2901
+ ]
2480
2902
  }
2481
- ) : null
2482
- ] }) : null
2483
- ]
2484
- }
2485
- );
2486
- }
2487
- );
2488
- var DATA_TRANSFER_COLUMN_TYPE = "application/x-monkeys-base-table-column";
2489
- var BaseTableContext = createContext(null);
2490
- function useBaseTableContext(appearance) {
2491
- const context = useContext(BaseTableContext);
2492
- if (context) {
2493
- return {
2494
- ...context,
2495
- theme: appearance ? resolveBaseAppearance(appearance) : context.theme,
2496
- appearance: appearance ?? context.appearance
2497
- };
2498
- }
2499
- const theme = resolveBaseAppearance(appearance);
2500
- return {
2501
- appearance,
2502
- theme,
2503
- setDraggingColumnId: () => {
2504
- }
2505
- };
2506
- }
2507
- function toCssSize(value) {
2508
- if (value === void 0) return void 0;
2509
- return typeof value === "number" ? `${value}px` : value;
2510
- }
2511
- function clampWidth2(value, minWidth, maxWidth) {
2512
- const min = minWidth ?? 48;
2513
- const max = maxWidth ?? Number.POSITIVE_INFINITY;
2514
- return Math.min(Math.max(value, min), max);
2515
- }
2516
- function getNextColumnOrder(order, columnId, targetColumnId) {
2517
- if (!order || columnId === targetColumnId) return void 0;
2518
- const fromIndex = order.indexOf(columnId);
2519
- const toIndex = order.indexOf(targetColumnId);
2520
- if (fromIndex < 0 || toIndex < 0) return void 0;
2521
- const next = [...order];
2522
- const [moved] = next.splice(fromIndex, 1);
2523
- next.splice(toIndex, 0, moved);
2524
- return next;
2525
- }
2526
- function sortAriaValue(direction) {
2527
- switch (direction) {
2528
- case "asc":
2529
- return "ascending";
2530
- case "desc":
2531
- return "descending";
2532
- default:
2533
- return void 0;
2534
- }
2535
- }
2536
- function SortIndicator({
2537
- direction,
2538
- className
2539
- }) {
2540
- return /* @__PURE__ */ jsx(
2541
- "span",
2542
- {
2543
- "aria-hidden": "true",
2544
- className: cn(
2545
- className,
2546
- direction === "desc" && "rotate-180",
2547
- (!direction || direction === "none") && "opacity-45"
2548
- ),
2549
- children: "\u25B2"
2550
- }
2551
- );
2552
- }
2553
- function DragHandleIcon() {
2554
- return /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "grid gap-0.5", children: [
2555
- /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" }),
2556
- /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" }),
2557
- /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" })
2558
- ] });
2559
- }
2560
- function BaseTableContainer({
2561
- appearance,
2562
- attachedFooter = false,
2563
- className,
2564
- classNames,
2565
- style,
2566
- ...containerProps
2567
- }) {
2568
- const theme = resolveBaseAppearance(appearance);
2569
- return /* @__PURE__ */ jsx(
2570
- "div",
2571
- {
2572
- ...containerProps,
2573
- "data-base-table-container": "",
2574
- "data-attached-footer": attachedFooter ? "" : void 0,
2575
- className: cn(
2576
- theme.slots.tableContainer,
2577
- attachedFooter && theme.slots.tableContainerFooterAttached,
2578
- classNames?.root,
2579
- className
2580
- ),
2581
- style: {
2582
- ...theme.styles.tableContainer,
2583
- ...attachedFooter ? theme.styles.tableContainerFooterAttached : void 0,
2584
- ...style
2585
- }
2903
+ ),
2904
+ /* @__PURE__ */ jsx("span", { className: theme.slots.selectChevron })
2905
+ ]
2906
+ }
2907
+ );
2586
2908
  }
2587
- );
2588
- }
2589
- function BaseTable({
2590
- appearance,
2591
- className,
2592
- classNames,
2593
- style,
2594
- columnOrder,
2595
- columnSizes,
2596
- columnDragEnabled = false,
2597
- columnResizeEnabled = false,
2598
- onColumnOrderChange,
2599
- onColumnSizeChange,
2600
- ...tableProps
2601
- }) {
2602
- const theme = resolveBaseAppearance(appearance);
2603
- const [draggingColumnId, setDraggingColumnId] = useState();
2604
- const contextValue = {
2605
- appearance,
2606
- theme,
2607
- columnOrder,
2608
- columnSizes,
2609
- columnDragEnabled,
2610
- columnResizeEnabled,
2611
- onColumnOrderChange,
2612
- onColumnSizeChange,
2613
- draggingColumnId,
2614
- setDraggingColumnId
2615
- };
2616
- return /* @__PURE__ */ jsx(BaseTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
2617
- "table",
2618
- {
2619
- ...tableProps,
2620
- className: cn(theme.slots.tableRoot, classNames?.root, className),
2621
- style: {
2622
- ...theme.styles.table,
2623
- ...style
2909
+ return /* @__PURE__ */ jsxs(
2910
+ "div",
2911
+ {
2912
+ ref: rootRef,
2913
+ className: cn(
2914
+ theme.slots.controlWrapper,
2915
+ "overflow-visible",
2916
+ open && "z-50",
2917
+ invalid && theme.slots.controlInvalid,
2918
+ disabled && theme.slots.controlDisabled,
2919
+ classNames?.root,
2920
+ className
2921
+ ),
2922
+ style: {
2923
+ ...theme.styles.control,
2924
+ ...invalid ? theme.styles.controlInvalid : void 0,
2925
+ ...disabled ? theme.styles.controlDisabled : void 0,
2926
+ ...style
2927
+ },
2928
+ children: [
2929
+ hasRenderableNode(icon) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.controlIcon, classNames?.icon), children: icon }) : null,
2930
+ /* @__PURE__ */ jsx(
2931
+ "button",
2932
+ {
2933
+ type: "button",
2934
+ id: `${selectId}-button`,
2935
+ disabled,
2936
+ "aria-haspopup": "listbox",
2937
+ "aria-expanded": open,
2938
+ "aria-controls": listboxId,
2939
+ "aria-invalid": nativeAriaInvalid ?? (invalid || void 0),
2940
+ "aria-label": nativeAriaLabel,
2941
+ "aria-labelledby": nativeAriaLabelledBy,
2942
+ className: cn(
2943
+ theme.slots.controlBase,
2944
+ theme.slots.controlSelect,
2945
+ "flex items-center text-left",
2946
+ classNames?.control
2947
+ ),
2948
+ onClick: () => {
2949
+ if (!forceOpen) {
2950
+ setUncontrolledOpen((current) => !current);
2951
+ }
2952
+ },
2953
+ onKeyDown: handleKeyDown,
2954
+ children: /* @__PURE__ */ jsx(
2955
+ "span",
2956
+ {
2957
+ className: cn(
2958
+ "min-w-0 flex-1 truncate",
2959
+ isPlaceholder && theme.slots.selectPlaceholder,
2960
+ isPlaceholder && classNames?.placeholder
2961
+ ),
2962
+ children: visibleLabel
2963
+ }
2964
+ )
2965
+ }
2966
+ ),
2967
+ /* @__PURE__ */ jsx(
2968
+ "span",
2969
+ {
2970
+ className: cn(
2971
+ theme.slots.selectChevron,
2972
+ open && "rotate-[225deg]"
2973
+ )
2974
+ }
2975
+ ),
2976
+ /* @__PURE__ */ jsxs(
2977
+ "select",
2978
+ {
2979
+ ...selectProps,
2980
+ ref: setSelectRef,
2981
+ id,
2982
+ name,
2983
+ value: selectedValue,
2984
+ required,
2985
+ disabled,
2986
+ "aria-hidden": "true",
2987
+ tabIndex: -1,
2988
+ className: theme.slots.selectNative,
2989
+ onChange,
2990
+ children: [
2991
+ hasRenderableNode(placeholder) ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }) : null,
2992
+ optionList.map((option) => /* @__PURE__ */ jsx(
2993
+ "option",
2994
+ {
2995
+ value: option.value,
2996
+ disabled: option.disabled,
2997
+ children: typeof option.label === "string" ? option.label : option.value
2998
+ },
2999
+ option.value
3000
+ ))
3001
+ ]
3002
+ }
3003
+ ),
3004
+ open ? /* @__PURE__ */ jsx(
3005
+ "div",
3006
+ {
3007
+ id: listboxId,
3008
+ role: "listbox",
3009
+ "aria-labelledby": `${selectId}-button`,
3010
+ className: cn(theme.slots.selectMenu, classNames?.menu),
3011
+ style: theme.styles.selectMenu,
3012
+ children: optionList.map((option, index) => {
3013
+ const selected = option.value === selectedValue;
3014
+ const active = index === activeIndex;
3015
+ return /* @__PURE__ */ jsx(
3016
+ "button",
3017
+ {
3018
+ type: "button",
3019
+ role: "option",
3020
+ "aria-selected": selected,
3021
+ disabled: option.disabled,
3022
+ className: cn(
3023
+ theme.slots.selectOption,
3024
+ active && theme.slots.selectOptionActive,
3025
+ selected && theme.slots.selectOptionSelected,
3026
+ option.disabled && theme.slots.selectOptionDisabled,
3027
+ classNames?.option
3028
+ ),
3029
+ style: {
3030
+ ...theme.styles.selectOption,
3031
+ ...active ? theme.styles.selectOptionActive : void 0,
3032
+ ...selected ? theme.styles.selectOptionSelected : void 0
3033
+ },
3034
+ onMouseDown: (event) => event.preventDefault(),
3035
+ onClick: () => commitValue(option.value, option.disabled),
3036
+ children: /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label })
3037
+ },
3038
+ option.value
3039
+ );
3040
+ })
3041
+ }
3042
+ ) : null
3043
+ ]
2624
3044
  }
3045
+ );
3046
+ }
3047
+ );
3048
+ function getInitialSegmentValue(options, defaultValue) {
3049
+ if (defaultValue && options?.some((option) => option.value === defaultValue)) {
3050
+ const defaultOption = options.find((option) => option.value === defaultValue);
3051
+ if (!defaultOption?.disabled) {
3052
+ return defaultValue;
2625
3053
  }
2626
- ) });
3054
+ }
3055
+ return options?.find((option) => !option.disabled)?.value ?? options?.[0]?.value;
2627
3056
  }
2628
- function BaseTableHeader({
3057
+ function BaseSegmentedControl({
3058
+ options = [],
3059
+ value,
3060
+ defaultValue,
2629
3061
  appearance,
2630
3062
  className,
2631
3063
  classNames,
2632
3064
  style,
2633
- ...headerProps
3065
+ onValueChange,
3066
+ ...controlProps
2634
3067
  }) {
2635
- const { theme } = useBaseTableContext(appearance);
2636
- return /* @__PURE__ */ jsx(
2637
- "thead",
2638
- {
2639
- ...headerProps,
2640
- className: cn(theme.slots.tableHeader, classNames?.root, className),
2641
- style: {
2642
- ...theme.styles.tableHeader,
2643
- ...style
2644
- }
2645
- }
3068
+ const theme = resolveBaseAppearance(appearance);
3069
+ const [uncontrolledValue, setUncontrolledValue] = useState(
3070
+ () => getInitialSegmentValue(options, defaultValue)
2646
3071
  );
2647
- }
2648
- function BaseTableBody({
2649
- appearance,
2650
- className,
2651
- classNames,
2652
- style,
2653
- ...bodyProps
2654
- }) {
2655
- const { theme } = useBaseTableContext(appearance);
3072
+ const isControlled = value !== void 0;
3073
+ const selectedValue = isControlled ? value : uncontrolledValue;
3074
+ const handleSelect = (nextValue, disabled) => {
3075
+ if (disabled) return;
3076
+ if (!isControlled) {
3077
+ setUncontrolledValue(nextValue);
3078
+ }
3079
+ onValueChange?.(nextValue);
3080
+ };
2656
3081
  return /* @__PURE__ */ jsx(
2657
- "tbody",
3082
+ "div",
2658
3083
  {
2659
- ...bodyProps,
2660
- className: cn(theme.slots.tableBody, classNames?.root, className),
3084
+ ...controlProps,
3085
+ role: "radiogroup",
3086
+ className: cn(theme.slots.segmentedRoot, classNames?.root, className),
2661
3087
  style: {
2662
- ...theme.styles.tableBody,
3088
+ ...theme.styles.segmentedRoot,
2663
3089
  ...style
2664
- }
3090
+ },
3091
+ children: options.map((option) => {
3092
+ const selected = option.value === selectedValue;
3093
+ return /* @__PURE__ */ jsxs(
3094
+ "button",
3095
+ {
3096
+ type: "button",
3097
+ role: "radio",
3098
+ "aria-checked": selected,
3099
+ disabled: option.disabled,
3100
+ className: cn(
3101
+ theme.slots.segmentedItem,
3102
+ selected && theme.slots.segmentedItemActive,
3103
+ option.disabled && theme.slots.segmentedItemDisabled,
3104
+ classNames?.item
3105
+ ),
3106
+ style: theme.styles.segmentedItem,
3107
+ onClick: () => handleSelect(option.value, option.disabled),
3108
+ children: [
3109
+ hasRenderableNode(option.icon) ? /* @__PURE__ */ jsx("span", { className: cn("inline-flex h-4 w-4 shrink-0", classNames?.icon), children: option.icon }) : null,
3110
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 truncate", classNames?.label), children: option.label })
3111
+ ]
3112
+ },
3113
+ option.value
3114
+ );
3115
+ })
2665
3116
  }
2666
3117
  );
2667
3118
  }
2668
- function BaseTableRow({
2669
- interactive,
2670
- selected,
2671
- disabled,
2672
- appearance,
2673
- className,
2674
- classNames,
2675
- style,
2676
- ...rowProps
2677
- }) {
2678
- const { theme } = useBaseTableContext(appearance);
3119
+ forwardRef(
3120
+ function BaseSwitch2({
3121
+ label,
3122
+ description,
3123
+ disabled = false,
3124
+ appearance,
3125
+ className,
3126
+ classNames,
3127
+ style,
3128
+ checked,
3129
+ defaultChecked,
3130
+ onChange,
3131
+ ...switchProps
3132
+ }, ref) {
3133
+ const theme = resolveBaseAppearance(appearance);
3134
+ const [uncontrolledChecked, setUncontrolledChecked] = useState(
3135
+ defaultChecked ?? false
3136
+ );
3137
+ const isControlled = checked !== void 0;
3138
+ const resolvedChecked = isControlled ? checked : uncontrolledChecked;
3139
+ const handleChange = (event) => {
3140
+ if (!isControlled) {
3141
+ setUncontrolledChecked(event.currentTarget.checked);
3142
+ }
3143
+ onChange?.(event);
3144
+ };
3145
+ return /* @__PURE__ */ jsxs(
3146
+ "label",
3147
+ {
3148
+ className: cn(
3149
+ theme.slots.switchRoot,
3150
+ disabled && theme.slots.switchDisabled,
3151
+ classNames?.root,
3152
+ className
3153
+ ),
3154
+ style: {
3155
+ ...theme.styles.switchRoot,
3156
+ ...style
3157
+ },
3158
+ children: [
3159
+ /* @__PURE__ */ jsxs(
3160
+ "span",
3161
+ {
3162
+ className: cn(
3163
+ theme.slots.switchTrack,
3164
+ resolvedChecked && theme.slots.switchChecked,
3165
+ classNames?.track
3166
+ ),
3167
+ style: theme.styles.switchTrack,
3168
+ children: [
3169
+ /* @__PURE__ */ jsx(
3170
+ "input",
3171
+ {
3172
+ ...switchProps,
3173
+ ref,
3174
+ type: "checkbox",
3175
+ disabled,
3176
+ checked,
3177
+ defaultChecked,
3178
+ onChange: handleChange,
3179
+ className: cn(theme.slots.switchInput, classNames?.input)
3180
+ }
3181
+ ),
3182
+ /* @__PURE__ */ jsx(
3183
+ "span",
3184
+ {
3185
+ className: cn(
3186
+ theme.slots.switchThumb,
3187
+ resolvedChecked && "translate-x-5",
3188
+ classNames?.thumb
3189
+ ),
3190
+ style: theme.styles.switchThumb
3191
+ }
3192
+ )
3193
+ ]
3194
+ }
3195
+ ),
3196
+ hasRenderableNode(label) || hasRenderableNode(description) ? /* @__PURE__ */ jsxs("span", { className: cn(theme.slots.switchContent, classNames?.content), children: [
3197
+ hasRenderableNode(label) ? /* @__PURE__ */ jsx("span", { className: cn(theme.slots.switchLabel, classNames?.label), children: label }) : null,
3198
+ hasRenderableNode(description) ? /* @__PURE__ */ jsx(
3199
+ "span",
3200
+ {
3201
+ className: cn(
3202
+ theme.slots.switchDescription,
3203
+ classNames?.description
3204
+ ),
3205
+ children: description
3206
+ }
3207
+ ) : null
3208
+ ] }) : null
3209
+ ]
3210
+ }
3211
+ );
3212
+ }
3213
+ );
3214
+ var DATA_TRANSFER_COLUMN_TYPE = "application/x-monkeys-base-table-column";
3215
+ var BaseTableContext = createContext(null);
3216
+ function useBaseTableContext(appearance) {
3217
+ const context = useContext(BaseTableContext);
3218
+ if (context) {
3219
+ return {
3220
+ ...context,
3221
+ theme: appearance ? resolveBaseAppearance(appearance) : context.theme,
3222
+ appearance: appearance ?? context.appearance
3223
+ };
3224
+ }
3225
+ const theme = resolveBaseAppearance(appearance);
3226
+ return {
3227
+ appearance,
3228
+ theme,
3229
+ setDraggingColumnId: () => {
3230
+ }
3231
+ };
3232
+ }
3233
+ function toCssSize(value) {
3234
+ if (value === void 0) return void 0;
3235
+ return typeof value === "number" ? `${value}px` : value;
3236
+ }
3237
+ function clampWidth2(value, minWidth, maxWidth) {
3238
+ const min = minWidth ?? 48;
3239
+ const max = maxWidth ?? Number.POSITIVE_INFINITY;
3240
+ return Math.min(Math.max(value, min), max);
3241
+ }
3242
+ function getNextColumnOrder(order, columnId, targetColumnId) {
3243
+ if (!order || columnId === targetColumnId) return void 0;
3244
+ const fromIndex = order.indexOf(columnId);
3245
+ const toIndex = order.indexOf(targetColumnId);
3246
+ if (fromIndex < 0 || toIndex < 0) return void 0;
3247
+ const next = [...order];
3248
+ const [moved] = next.splice(fromIndex, 1);
3249
+ next.splice(toIndex, 0, moved);
3250
+ return next;
3251
+ }
3252
+ function sortAriaValue(direction) {
3253
+ switch (direction) {
3254
+ case "asc":
3255
+ return "ascending";
3256
+ case "desc":
3257
+ return "descending";
3258
+ default:
3259
+ return void 0;
3260
+ }
3261
+ }
3262
+ function SortIndicator({
3263
+ direction,
3264
+ className
3265
+ }) {
2679
3266
  return /* @__PURE__ */ jsx(
2680
- "tr",
3267
+ "span",
2681
3268
  {
2682
- ...rowProps,
2683
- "aria-disabled": disabled || void 0,
2684
- "data-state": selected ? "selected" : void 0,
3269
+ "aria-hidden": "true",
2685
3270
  className: cn(
2686
- theme.slots.tableRow,
2687
- interactive && !disabled && theme.slots.tableRowInteractive,
2688
- selected && theme.slots.tableRowSelected,
2689
- disabled && theme.slots.tableRowDisabled,
3271
+ className,
3272
+ direction === "desc" && "rotate-180",
3273
+ (!direction || direction === "none") && "opacity-45"
3274
+ ),
3275
+ children: "\u25B2"
3276
+ }
3277
+ );
3278
+ }
3279
+ function DragHandleIcon() {
3280
+ return /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "grid gap-0.5", children: [
3281
+ /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" }),
3282
+ /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" }),
3283
+ /* @__PURE__ */ jsx("span", { className: "h-0.5 w-0.5 rounded-full bg-current" })
3284
+ ] });
3285
+ }
3286
+ function BaseTableContainer({
3287
+ appearance,
3288
+ attachedFooter = false,
3289
+ className,
3290
+ classNames,
3291
+ style,
3292
+ ...containerProps
3293
+ }) {
3294
+ const theme = resolveBaseAppearance(appearance);
3295
+ return /* @__PURE__ */ jsx(
3296
+ "div",
3297
+ {
3298
+ ...containerProps,
3299
+ "data-base-table-container": "",
3300
+ "data-attached-footer": attachedFooter ? "" : void 0,
3301
+ className: cn(
3302
+ theme.slots.tableContainer,
3303
+ attachedFooter && theme.slots.tableContainerFooterAttached,
2690
3304
  classNames?.root,
2691
3305
  className
2692
3306
  ),
2693
3307
  style: {
2694
- ...theme.styles.tableRow,
3308
+ ...theme.styles.tableContainer,
3309
+ ...attachedFooter ? theme.styles.tableContainerFooterAttached : void 0,
2695
3310
  ...style
2696
3311
  }
2697
3312
  }
2698
3313
  );
2699
3314
  }
2700
- function BaseTableHead({
2701
- columnId,
2702
- align = "left",
2703
- icon,
2704
- label,
2705
- description,
2706
- meta,
2707
- actions,
2708
- trailing,
2709
- sortable,
2710
- sortDirection = "none",
2711
- sortLabel,
2712
- onSort,
2713
- draggable,
2714
- dragLabel,
2715
- resizable,
2716
- resizeLabel,
2717
- width,
2718
- minWidth,
2719
- maxWidth,
3315
+ function BaseTable({
2720
3316
  appearance,
2721
3317
  className,
2722
3318
  classNames,
2723
3319
  style,
2724
- children,
2725
- onDragOver,
2726
- onDrop,
2727
- ...headProps
3320
+ columnOrder,
3321
+ columnSizes,
3322
+ columnDragEnabled = false,
3323
+ columnResizeEnabled = false,
3324
+ onColumnOrderChange,
3325
+ onColumnSizeChange,
3326
+ ...tableProps
2728
3327
  }) {
2729
- const tableContext = useBaseTableContext(appearance);
2730
- const { theme } = tableContext;
2731
- const headRef = useRef(null);
2732
- const controlledWidth = columnId && tableContext.columnSizes?.[columnId] !== void 0 ? tableContext.columnSizes[columnId] : width;
2733
- const canDrag = Boolean(
2734
- columnId && draggable !== false && (draggable || tableContext.columnDragEnabled) && tableContext.columnOrder && tableContext.onColumnOrderChange
2735
- );
2736
- const canResize = Boolean(
2737
- columnId && resizable !== false && (resizable || tableContext.columnResizeEnabled) && tableContext.onColumnSizeChange
2738
- );
2739
- const interactiveSort = Boolean(sortable || onSort);
2740
- const ariaSort = sortAriaValue(sortDirection);
2741
- const content = hasRenderableNode(label) ? label : children;
2742
- const usesRichHeader = canDrag || hasRenderableNode(icon) || hasRenderableNode(label) || hasRenderableNode(description) || hasRenderableNode(meta) || hasRenderableNode(actions) || hasRenderableNode(trailing) || interactiveSort;
2743
- const renderedContent = usesRichHeader ? /* @__PURE__ */ jsxs("div", { className: cn(theme.slots.tableHeadContent, classNames?.content), children: [
2744
- /* @__PURE__ */ jsxs("div", { className: cn(theme.slots.tableHeadMain, classNames?.main), children: [
2745
- canDrag ? /* @__PURE__ */ jsx(
2746
- "button",
2747
- {
2748
- type: "button",
2749
- draggable: true,
2750
- title: dragLabel,
2751
- "aria-label": dragLabel ?? `Drag column ${columnId}`,
2752
- className: cn(theme.slots.tableHeadDragHandle, classNames?.dragHandle),
2753
- onClick: (event) => event.stopPropagation(),
2754
- onDragStart: (event) => {
2755
- event.stopPropagation();
2756
- tableContext.setDraggingColumnId(columnId);
2757
- event.dataTransfer.effectAllowed = "move";
2758
- event.dataTransfer.setData(DATA_TRANSFER_COLUMN_TYPE, columnId);
2759
- },
2760
- onDragEnd: (event) => {
3328
+ const theme = resolveBaseAppearance(appearance);
3329
+ const [draggingColumnId, setDraggingColumnId] = useState();
3330
+ const contextValue = {
3331
+ appearance,
3332
+ theme,
3333
+ columnOrder,
3334
+ columnSizes,
3335
+ columnDragEnabled,
3336
+ columnResizeEnabled,
3337
+ onColumnOrderChange,
3338
+ onColumnSizeChange,
3339
+ draggingColumnId,
3340
+ setDraggingColumnId
3341
+ };
3342
+ return /* @__PURE__ */ jsx(BaseTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
3343
+ "table",
3344
+ {
3345
+ ...tableProps,
3346
+ className: cn(theme.slots.tableRoot, classNames?.root, className),
3347
+ style: {
3348
+ ...theme.styles.table,
3349
+ ...style
3350
+ }
3351
+ }
3352
+ ) });
3353
+ }
3354
+ function BaseTableHeader({
3355
+ appearance,
3356
+ className,
3357
+ classNames,
3358
+ style,
3359
+ ...headerProps
3360
+ }) {
3361
+ const { theme } = useBaseTableContext(appearance);
3362
+ return /* @__PURE__ */ jsx(
3363
+ "thead",
3364
+ {
3365
+ ...headerProps,
3366
+ className: cn(theme.slots.tableHeader, classNames?.root, className),
3367
+ style: {
3368
+ ...theme.styles.tableHeader,
3369
+ ...style
3370
+ }
3371
+ }
3372
+ );
3373
+ }
3374
+ function BaseTableBody({
3375
+ appearance,
3376
+ className,
3377
+ classNames,
3378
+ style,
3379
+ ...bodyProps
3380
+ }) {
3381
+ const { theme } = useBaseTableContext(appearance);
3382
+ return /* @__PURE__ */ jsx(
3383
+ "tbody",
3384
+ {
3385
+ ...bodyProps,
3386
+ className: cn(theme.slots.tableBody, classNames?.root, className),
3387
+ style: {
3388
+ ...theme.styles.tableBody,
3389
+ ...style
3390
+ }
3391
+ }
3392
+ );
3393
+ }
3394
+ function BaseTableRow({
3395
+ interactive,
3396
+ selected,
3397
+ disabled,
3398
+ appearance,
3399
+ className,
3400
+ classNames,
3401
+ style,
3402
+ ...rowProps
3403
+ }) {
3404
+ const { theme } = useBaseTableContext(appearance);
3405
+ return /* @__PURE__ */ jsx(
3406
+ "tr",
3407
+ {
3408
+ ...rowProps,
3409
+ "aria-disabled": disabled || void 0,
3410
+ "data-state": selected ? "selected" : void 0,
3411
+ className: cn(
3412
+ theme.slots.tableRow,
3413
+ interactive && !disabled && theme.slots.tableRowInteractive,
3414
+ selected && theme.slots.tableRowSelected,
3415
+ disabled && theme.slots.tableRowDisabled,
3416
+ classNames?.root,
3417
+ className
3418
+ ),
3419
+ style: {
3420
+ ...theme.styles.tableRow,
3421
+ ...style
3422
+ }
3423
+ }
3424
+ );
3425
+ }
3426
+ var BaseTableHead = forwardRef(function BaseTableHead2({
3427
+ columnId,
3428
+ align = "left",
3429
+ icon,
3430
+ label,
3431
+ description,
3432
+ meta,
3433
+ actions,
3434
+ trailing,
3435
+ sortable,
3436
+ sortDirection = "none",
3437
+ sortLabel,
3438
+ onSort,
3439
+ draggable,
3440
+ dragLabel,
3441
+ resizable,
3442
+ resizeLabel,
3443
+ width,
3444
+ minWidth,
3445
+ maxWidth,
3446
+ appearance,
3447
+ className,
3448
+ classNames,
3449
+ style,
3450
+ children,
3451
+ onDragOver,
3452
+ onDrop,
3453
+ ...headProps
3454
+ }, forwardedRef) {
3455
+ const tableContext = useBaseTableContext(appearance);
3456
+ const { theme } = tableContext;
3457
+ const headRef = useRef(null);
3458
+ const setHeadRef = (node) => {
3459
+ headRef.current = node;
3460
+ if (typeof forwardedRef === "function") {
3461
+ forwardedRef(node);
3462
+ } else if (forwardedRef) {
3463
+ forwardedRef.current = node;
3464
+ }
3465
+ };
3466
+ const controlledWidth = columnId && tableContext.columnSizes?.[columnId] !== void 0 ? tableContext.columnSizes[columnId] : width;
3467
+ const canDrag = Boolean(
3468
+ columnId && draggable !== false && (draggable || tableContext.columnDragEnabled) && tableContext.columnOrder && tableContext.onColumnOrderChange
3469
+ );
3470
+ const canResize = Boolean(
3471
+ columnId && resizable !== false && (resizable || tableContext.columnResizeEnabled) && tableContext.onColumnSizeChange
3472
+ );
3473
+ const interactiveSort = Boolean(sortable || onSort);
3474
+ const ariaSort = sortAriaValue(sortDirection);
3475
+ const content = hasRenderableNode(label) ? label : children;
3476
+ const usesRichHeader = canDrag || hasRenderableNode(icon) || hasRenderableNode(label) || hasRenderableNode(description) || hasRenderableNode(meta) || hasRenderableNode(actions) || hasRenderableNode(trailing) || interactiveSort;
3477
+ const renderedContent = usesRichHeader ? /* @__PURE__ */ jsxs("div", { className: cn(theme.slots.tableHeadContent, classNames?.content), children: [
3478
+ /* @__PURE__ */ jsxs("div", { className: cn(theme.slots.tableHeadMain, classNames?.main), children: [
3479
+ canDrag ? /* @__PURE__ */ jsx(
3480
+ "button",
3481
+ {
3482
+ type: "button",
3483
+ draggable: true,
3484
+ title: dragLabel,
3485
+ "aria-label": dragLabel ?? `Drag column ${columnId}`,
3486
+ className: cn(theme.slots.tableHeadDragHandle, classNames?.dragHandle),
3487
+ onClick: (event) => event.stopPropagation(),
3488
+ onDragStart: (event) => {
3489
+ event.stopPropagation();
3490
+ tableContext.setDraggingColumnId(columnId);
3491
+ event.dataTransfer.effectAllowed = "move";
3492
+ event.dataTransfer.setData(DATA_TRANSFER_COLUMN_TYPE, columnId);
3493
+ },
3494
+ onDragEnd: (event) => {
2761
3495
  event.stopPropagation();
2762
3496
  tableContext.setDraggingColumnId(void 0);
2763
3497
  },
@@ -2883,7 +3617,7 @@ function BaseTableHead({
2883
3617
  "th",
2884
3618
  {
2885
3619
  ...headProps,
2886
- ref: headRef,
3620
+ ref: setHeadRef,
2887
3621
  scope: headProps.scope ?? "col",
2888
3622
  "aria-sort": ariaSort,
2889
3623
  className: cn(
@@ -2918,7 +3652,7 @@ function BaseTableHead({
2918
3652
  ]
2919
3653
  }
2920
3654
  );
2921
- }
3655
+ });
2922
3656
  function BaseTableCell({
2923
3657
  align = "left",
2924
3658
  appearance,
@@ -3976,340 +4710,993 @@ var WorkbenchDetailSidebar = forwardRef(
3976
4710
  classNames?.root,
3977
4711
  className
3978
4712
  ),
3979
- style: {
3980
- ...resolveWidthStyle(open, width),
3981
- ...style
3982
- },
3983
- ...props,
3984
- children: [
3985
- resizeHandle ? /* @__PURE__ */ jsx("div", { className: cn(classNames?.resizeHandle, resizeHandleClassName), children: resizeHandle }) : null,
3986
- header ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 border-b border-border/40 px-4 py-3 dark:border-border/30", classNames?.header, headerClassName), children: header }) : null,
3987
- renderBodyWrapper ? /* @__PURE__ */ jsx(
3988
- BodyComponent,
3989
- {
3990
- className: cn("min-h-0 flex-1 overflow-y-auto", classNames?.body, bodyClassName, bodyPropsClassName),
3991
- ...restBodyProps,
3992
- children: autoContent
3993
- }
3994
- ) : autoContent,
3995
- footer ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 border-t border-border/40 px-4 py-3 dark:border-border/30", classNames?.footer, footerClassName), children: footer }) : null
3996
- ]
3997
- }
3998
- );
3999
- }
4000
- );
4001
- function isWorkbenchIconComponent(icon) {
4002
- if (typeof icon === "function") return true;
4003
- return typeof icon === "object" && icon !== null && !isValidElement(icon) && "$$typeof" in icon;
4713
+ style: {
4714
+ ...resolveWidthStyle(open, width),
4715
+ ...style
4716
+ },
4717
+ ...props,
4718
+ children: [
4719
+ resizeHandle ? /* @__PURE__ */ jsx("div", { className: cn(classNames?.resizeHandle, resizeHandleClassName), children: resizeHandle }) : null,
4720
+ header ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 border-b border-border/40 px-4 py-3 dark:border-border/30", classNames?.header, headerClassName), children: header }) : null,
4721
+ renderBodyWrapper ? /* @__PURE__ */ jsx(
4722
+ BodyComponent,
4723
+ {
4724
+ className: cn("min-h-0 flex-1 overflow-y-auto", classNames?.body, bodyClassName, bodyPropsClassName),
4725
+ ...restBodyProps,
4726
+ children: autoContent
4727
+ }
4728
+ ) : autoContent,
4729
+ footer ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 border-t border-border/40 px-4 py-3 dark:border-border/30", classNames?.footer, footerClassName), children: footer }) : null
4730
+ ]
4731
+ }
4732
+ );
4733
+ }
4734
+ );
4735
+ function isWorkbenchIconComponent(icon) {
4736
+ if (typeof icon === "function") return true;
4737
+ return typeof icon === "object" && icon !== null && !isValidElement(icon) && "$$typeof" in icon;
4738
+ }
4739
+ function renderWorkbenchIcon(icon, className) {
4740
+ if (!icon) return null;
4741
+ if (isValidElement(icon)) return icon;
4742
+ if (isWorkbenchIconComponent(icon)) {
4743
+ const Icon = icon;
4744
+ return /* @__PURE__ */ jsx(Icon, { className });
4745
+ }
4746
+ return icon;
4747
+ }
4748
+ function getWorkbenchIconComponent(icon) {
4749
+ if (!icon || !isWorkbenchIconComponent(icon)) return null;
4750
+ return icon;
4751
+ }
4752
+ function toCssSize2(value) {
4753
+ if (value === void 0) return void 0;
4754
+ return typeof value === "number" ? `${value}px` : value;
4755
+ }
4756
+ function defaultFormatLabel(value) {
4757
+ if (value === void 0 || value === null || value === false) return null;
4758
+ return value;
4759
+ }
4760
+ function toTitle(value) {
4761
+ if (typeof value === "string" || typeof value === "number") return String(value);
4762
+ return void 0;
4763
+ }
4764
+ function defaultGetRowKey(row, rowIndex) {
4765
+ return row?.id ?? row?.key ?? row?.linkKey ?? rowIndex;
4766
+ }
4767
+ function defaultGetRowSelectionKey(row) {
4768
+ return row?.linkKey ?? row?.id ?? row?.key;
4769
+ }
4770
+ function getOrderedColumns(columns, columnOrder) {
4771
+ if (!columnOrder?.length) return columns;
4772
+ const columnMap = new Map(columns.map((column) => [column.key, column]));
4773
+ const orderedColumns = columnOrder.map((columnKey) => columnMap.get(columnKey)).filter(Boolean);
4774
+ const orderedKeySet = new Set(orderedColumns.map((column) => column.key));
4775
+ const remainingColumns = columns.filter((column) => !orderedKeySet.has(column.key));
4776
+ return [...orderedColumns, ...remainingColumns];
4777
+ }
4778
+ function normalizeColumnOrder(columnKeys, columnOrder) {
4779
+ const validColumnKeys = new Set(columnKeys);
4780
+ const orderedKeys = (columnOrder || []).filter((columnKey) => validColumnKeys.has(columnKey));
4781
+ const orderedKeySet = new Set(orderedKeys);
4782
+ const remainingKeys = columnKeys.filter((columnKey) => !orderedKeySet.has(columnKey));
4783
+ return [...orderedKeys, ...remainingKeys];
4784
+ }
4785
+ function WorkbenchTableHeaderHelper({
4786
+ helperText,
4787
+ className
4788
+ }) {
4789
+ if (!hasRenderableNode(helperText)) return null;
4790
+ return /* @__PURE__ */ jsxs("span", { className: cn("group relative inline-flex items-center", className), children: [
4791
+ /* @__PURE__ */ jsx(
4792
+ "button",
4793
+ {
4794
+ type: "button",
4795
+ title: toTitle(helperText),
4796
+ "aria-label": toTitle(helperText) || "Field help",
4797
+ className: "inline-flex h-4 w-4 items-center justify-center rounded-full border border-border/60 bg-background text-[10px] font-semibold normal-case tracking-normal text-muted-foreground shadow-sm transition-colors hover:border-primary/40 hover:text-primary focus-visible:border-primary/40 focus-visible:text-primary focus-visible:outline-none",
4798
+ onClick: (event) => event.stopPropagation(),
4799
+ children: "?"
4800
+ }
4801
+ ),
4802
+ /* @__PURE__ */ jsx(
4803
+ "span",
4804
+ {
4805
+ role: "tooltip",
4806
+ className: "pointer-events-none absolute left-1/2 top-full z-40 mt-2 hidden w-72 -translate-x-1/2 whitespace-pre-line rounded-lg border border-border/60 bg-card px-3 py-2 text-[11px] font-normal normal-case leading-5 tracking-normal text-foreground shadow-sm backdrop-blur-sm group-hover:block group-focus-within:block",
4807
+ children: helperText
4808
+ }
4809
+ )
4810
+ ] });
4811
+ }
4812
+ function WorkbenchTableView({
4813
+ rows = [],
4814
+ columns = [],
4815
+ onRowClick,
4816
+ selectedRowKey,
4817
+ selectedLinkKey,
4818
+ activePrimaryColumn,
4819
+ activeTablePrimaryColumn,
4820
+ renderedRowCount,
4821
+ totalRowCount,
4822
+ tableMinWidth,
4823
+ minWidth,
4824
+ bodyMaxHeight = "min(58vh, 38rem)",
4825
+ stickyFirstColumn = true,
4826
+ appearance,
4827
+ columnOrder,
4828
+ columnSizes,
4829
+ columnDragEnabled,
4830
+ columnResizeEnabled,
4831
+ className,
4832
+ tableClassName,
4833
+ rowClassName,
4834
+ classNames,
4835
+ style,
4836
+ renderCell,
4837
+ renderFieldValue,
4838
+ renderColumnHeader,
4839
+ onColumnOrderChange,
4840
+ onColumnSizeChange,
4841
+ onSort,
4842
+ formatLabel = defaultFormatLabel,
4843
+ getColumnDataType,
4844
+ getColumnIcon,
4845
+ getColumnTypeIcon,
4846
+ getRowKey = defaultGetRowKey,
4847
+ getRowSelectionKey = defaultGetRowSelectionKey,
4848
+ isActionColumn,
4849
+ isActionField,
4850
+ isRowDisabled,
4851
+ isWorkbenchPlaceholderRow,
4852
+ emptyState = "-",
4853
+ hiddenRowsMessage
4854
+ }) {
4855
+ const columnKeySignature = columns.map((column) => column.key).join("");
4856
+ const defaultColumnOrder = useMemo(() => columnKeySignature ? columnKeySignature.split("") : [], [columnKeySignature]);
4857
+ const [internalColumnOrder, setInternalColumnOrder] = useState(defaultColumnOrder);
4858
+ const [internalColumnSizes, setInternalColumnSizes] = useState({});
4859
+ useEffect(() => {
4860
+ setInternalColumnOrder((current) => normalizeColumnOrder(defaultColumnOrder, current));
4861
+ }, [defaultColumnOrder]);
4862
+ const resolvedColumnOrder = columnOrder ? normalizeColumnOrder(defaultColumnOrder, columnOrder) : internalColumnOrder;
4863
+ const resolvedColumnSizes = columnSizes ?? internalColumnSizes;
4864
+ const handleColumnOrderChange = useCallback((nextOrder, detail) => {
4865
+ const normalizedOrder = normalizeColumnOrder(defaultColumnOrder, nextOrder);
4866
+ if (!columnOrder) {
4867
+ setInternalColumnOrder(normalizedOrder);
4868
+ }
4869
+ onColumnOrderChange?.(normalizedOrder, detail);
4870
+ }, [columnOrder, defaultColumnOrder, onColumnOrderChange]);
4871
+ const handleColumnSizeChange = useCallback((columnId, width, detail) => {
4872
+ if (!columnSizes) {
4873
+ setInternalColumnSizes((current) => ({
4874
+ ...current,
4875
+ [columnId]: width
4876
+ }));
4877
+ }
4878
+ onColumnSizeChange?.(columnId, width, detail);
4879
+ }, [columnSizes, onColumnSizeChange]);
4880
+ const resolvedSelectedKey = selectedRowKey ?? selectedLinkKey;
4881
+ const resolvedActivePrimaryColumn = activePrimaryColumn ?? activeTablePrimaryColumn;
4882
+ const orderedColumns = getOrderedColumns(columns, resolvedColumnOrder);
4883
+ const hiddenRowCount = Math.max(0, Number(totalRowCount || rows.length) - Number(renderedRowCount || rows.length));
4884
+ const resolvedMinWidth = tableMinWidth ?? minWidth ?? Math.max(760, Math.min(orderedColumns.length * 112, 1440));
4885
+ const renderValue = renderCell ?? renderFieldValue ?? ((column, row) => row?.[column.key]);
4886
+ const isAction = isActionColumn ?? isActionField ?? (() => false);
4887
+ const isDisabled = isRowDisabled ?? isWorkbenchPlaceholderRow ?? (() => false);
4888
+ const resolveColumnIcon = getColumnIcon ?? getColumnTypeIcon;
4889
+ const footer = hiddenRowCount > 0 && hiddenRowsMessage ? typeof hiddenRowsMessage === "function" ? hiddenRowsMessage(hiddenRowCount, renderedRowCount || rows.length, totalRowCount || rows.length) : hiddenRowsMessage : null;
4890
+ return /* @__PURE__ */ jsxs(
4891
+ BaseTableContainer,
4892
+ {
4893
+ appearance,
4894
+ className: cn("w-full overflow-hidden rounded-lg border border-border/40 bg-muted/15 dark:border-border/35 dark:bg-muted/10", classNames?.root, className),
4895
+ style,
4896
+ children: [
4897
+ /* @__PURE__ */ jsx(
4898
+ "div",
4899
+ {
4900
+ className: cn("w-full overflow-auto", classNames?.scrollArea),
4901
+ style: { maxHeight: toCssSize2(bodyMaxHeight) },
4902
+ children: /* @__PURE__ */ jsxs(
4903
+ BaseTable,
4904
+ {
4905
+ appearance,
4906
+ columnOrder: resolvedColumnOrder,
4907
+ columnSizes: resolvedColumnSizes,
4908
+ columnDragEnabled,
4909
+ columnResizeEnabled,
4910
+ onColumnOrderChange: handleColumnOrderChange,
4911
+ onColumnSizeChange: handleColumnSizeChange,
4912
+ className: cn("w-full table-auto text-left text-xs", classNames?.table, tableClassName),
4913
+ style: { minWidth: resolvedMinWidth },
4914
+ children: [
4915
+ /* @__PURE__ */ jsx(BaseTableHeader, { appearance, className: cn("text-[10px] font-mono uppercase tracking-wide text-muted-foreground", classNames?.header), children: /* @__PURE__ */ jsx(BaseTableRow, { className: cn("hover:bg-transparent", classNames?.headerRow), children: orderedColumns.map((column, columnIndex) => {
4916
+ const columnType = column.renderType || column.type || getColumnDataType?.(column.key, rows, column);
4917
+ const columnIcon = renderWorkbenchIcon(
4918
+ resolveColumnIcon?.(columnType, column),
4919
+ "h-3.5 w-3.5 shrink-0 text-primary"
4920
+ );
4921
+ const previousColumn = orderedColumns[columnIndex - 1];
4922
+ const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
4923
+ const headerContent = renderColumnHeader ? renderColumnHeader(column, { column, columnIndex, columns: orderedColumns, rows, columnType }) : formatLabel(column.label, { column });
4924
+ const headerTrailing = !renderColumnHeader && (hasRenderableNode(column.trailing) || hasRenderableNode(column.helperText)) ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
4925
+ hasRenderableNode(column.trailing) ? formatLabel(column.trailing, { column }) : null,
4926
+ /* @__PURE__ */ jsx(WorkbenchTableHeaderHelper, { helperText: formatLabel(column.helperText, { column }), className: classNames?.helper })
4927
+ ] }) : void 0;
4928
+ const sortable = Boolean(column.sortable);
4929
+ const handleSort = sortable && onSort ? () => onSort(column.key, column) : void 0;
4930
+ return /* @__PURE__ */ jsx(
4931
+ BaseTableHead,
4932
+ {
4933
+ appearance,
4934
+ columnId: column.key,
4935
+ align: column.align,
4936
+ icon: renderColumnHeader ? void 0 : columnIcon,
4937
+ label: headerContent,
4938
+ description: renderColumnHeader ? void 0 : formatLabel(column.description, { column }),
4939
+ meta: renderColumnHeader ? void 0 : formatLabel(column.meta, { column }),
4940
+ actions: renderColumnHeader ? void 0 : column.actions,
4941
+ trailing: headerTrailing,
4942
+ sortable,
4943
+ sortDirection: column.sortDirection,
4944
+ sortLabel: column.sortLabel,
4945
+ onSort: handleSort,
4946
+ draggable: column.draggable,
4947
+ dragLabel: column.dragLabel,
4948
+ resizable: column.resizable,
4949
+ resizeLabel: column.resizeLabel,
4950
+ width: column.width,
4951
+ minWidth: typeof column.minWidth === "number" ? column.minWidth : void 0,
4952
+ maxWidth: typeof column.maxWidth === "number" ? column.maxWidth : void 0,
4953
+ className: cn(
4954
+ "sticky top-0 z-20 h-auto whitespace-nowrap bg-card/95 px-4 py-3 font-medium backdrop-blur-sm supports-[backdrop-filter]:bg-card/90",
4955
+ stickyFirstColumn && columnIndex === 0 && "left-0 z-30 shadow-[1px_0_0_0_hsl(var(--border)/0.35)]",
4956
+ column.compactHeaderClassName,
4957
+ column.headerClassName,
4958
+ column.renderType === "icon" && "pl-3 pr-1",
4959
+ followsRecordIcon && "pl-2",
4960
+ classNames?.headerCell
4961
+ ),
4962
+ style: {
4963
+ minWidth: typeof column.minWidth === "string" ? column.minWidth : void 0,
4964
+ maxWidth: typeof column.maxWidth === "string" ? column.maxWidth : void 0
4965
+ }
4966
+ },
4967
+ column.key
4968
+ );
4969
+ }) }) }),
4970
+ /* @__PURE__ */ jsx(BaseTableBody, { appearance, className: cn("divide-y divide-border/35 dark:divide-border/30", classNames?.body), children: rows.length ? rows.map((row, rowIndex) => {
4971
+ const key = getRowKey(row, rowIndex);
4972
+ const disabled = isDisabled(row, rowIndex);
4973
+ const selectionKey = getRowSelectionKey(row, rowIndex);
4974
+ const selected = Boolean(resolvedSelectedKey && String(selectionKey) === String(resolvedSelectedKey));
4975
+ const resolvedRowClassName = typeof rowClassName === "function" ? rowClassName(row, rowIndex) : rowClassName;
4976
+ return /* @__PURE__ */ jsx(
4977
+ BaseTableRow,
4978
+ {
4979
+ appearance,
4980
+ interactive: Boolean(onRowClick) && !disabled,
4981
+ selected,
4982
+ disabled,
4983
+ onClick: () => {
4984
+ if (!disabled) {
4985
+ onRowClick?.(row, rowIndex);
4986
+ }
4987
+ },
4988
+ className: cn(
4989
+ onRowClick && !disabled ? "cursor-pointer" : "cursor-default",
4990
+ selected ? "bg-primary/10 hover:bg-primary/15" : disabled ? "" : "hover:bg-muted/25 dark:hover:bg-muted/15",
4991
+ classNames?.row,
4992
+ resolvedRowClassName
4993
+ ),
4994
+ children: orderedColumns.map((column, columnIndex) => {
4995
+ const shouldWrap = isAction(column) || column.wrap === true;
4996
+ const previousColumn = orderedColumns[columnIndex - 1];
4997
+ const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
4998
+ return /* @__PURE__ */ jsx(
4999
+ BaseTableCell,
5000
+ {
5001
+ appearance,
5002
+ align: column.align,
5003
+ className: cn(
5004
+ shouldWrap ? "align-top whitespace-normal" : "whitespace-nowrap",
5005
+ "px-4 py-3 text-muted-foreground",
5006
+ stickyFirstColumn && columnIndex === 0 && "sticky left-0 z-10 bg-card/95 text-foreground shadow-[1px_0_0_0_hsl(var(--border)/0.3)]",
5007
+ column.compactCellClassName,
5008
+ column.cellClassName,
5009
+ column.renderType === "icon" && "pl-3 pr-1",
5010
+ followsRecordIcon && "pl-2",
5011
+ classNames?.cell
5012
+ ),
5013
+ children: renderValue(column, row, {
5014
+ row,
5015
+ rowIndex,
5016
+ column,
5017
+ columnIndex,
5018
+ compact: true,
5019
+ surface: "list"
5020
+ })
5021
+ },
5022
+ `${key}-${column.key}`
5023
+ );
5024
+ })
5025
+ },
5026
+ key
5027
+ );
5028
+ }) : /* @__PURE__ */ jsx(
5029
+ BaseTableEmpty,
5030
+ {
5031
+ appearance,
5032
+ colSpan: Math.max(orderedColumns.length, 1),
5033
+ classNames: { cell: "px-4 py-10 text-center text-sm text-muted-foreground" },
5034
+ children: emptyState
5035
+ }
5036
+ ) })
5037
+ ]
5038
+ }
5039
+ )
5040
+ }
5041
+ ),
5042
+ footer ? /* @__PURE__ */ jsx("div", { className: cn("border-t border-border/40 px-4 py-2 text-[11px] text-muted-foreground dark:border-border/30", classNames?.footer), children: footer }) : null
5043
+ ]
5044
+ }
5045
+ );
4004
5046
  }
4005
- function renderWorkbenchIcon(icon, className) {
4006
- if (!icon) return null;
4007
- if (isValidElement(icon)) return icon;
4008
- if (isWorkbenchIconComponent(icon)) {
4009
- const Icon = icon;
4010
- return /* @__PURE__ */ jsx(Icon, { className });
5047
+ function toCssSize3(value) {
5048
+ if (value === void 0) return void 0;
5049
+ return typeof value === "number" ? `${value}px` : value;
5050
+ }
5051
+ function isBrowser() {
5052
+ return typeof window !== "undefined";
5053
+ }
5054
+ function defaultGetRowKey2(row, rowIndex) {
5055
+ return row?.id ?? row?.key ?? rowIndex;
5056
+ }
5057
+ function getColumnDefaultSize(column) {
5058
+ if (typeof column.width === "number") return column.width;
5059
+ if (typeof column.minWidth === "number") return column.minWidth;
5060
+ return 160;
5061
+ }
5062
+ function buildDefaultColumnSizes(columns, explicit) {
5063
+ return columns.reduce((acc, column) => {
5064
+ acc[column.key] = explicit?.[column.key] ?? getColumnDefaultSize(column);
5065
+ return acc;
5066
+ }, {});
5067
+ }
5068
+ function loadStoredColumnSizes(storageKey, defaults) {
5069
+ if (!storageKey || !isBrowser()) return defaults;
5070
+ try {
5071
+ const parsed = JSON.parse(window.localStorage.getItem(storageKey) || "{}");
5072
+ return Object.keys(defaults).reduce((acc, key) => {
5073
+ const value = Number(parsed?.[key]);
5074
+ acc[key] = Number.isFinite(value) ? value : defaults[key];
5075
+ return acc;
5076
+ }, {});
5077
+ } catch {
5078
+ return defaults;
4011
5079
  }
4012
- return icon;
4013
5080
  }
4014
- function getWorkbenchIconComponent(icon) {
4015
- if (!icon || !isWorkbenchIconComponent(icon)) return null;
4016
- return icon;
5081
+ function persistColumnSizes(storageKey, sizes) {
5082
+ if (!storageKey || !isBrowser()) return;
5083
+ window.localStorage.setItem(storageKey, JSON.stringify(sizes));
4017
5084
  }
4018
- function toCssSize2(value) {
4019
- if (value === void 0) return void 0;
4020
- return typeof value === "number" ? `${value}px` : value;
5085
+ function getFrozenColumnStorageKey(storageKey) {
5086
+ return storageKey ? `${storageKey}.frozenColumnCount` : void 0;
4021
5087
  }
4022
- function defaultFormatLabel(value) {
4023
- if (value === void 0 || value === null || value === false) return null;
4024
- return value;
5088
+ function getFrozenEndColumnStorageKey(storageKey) {
5089
+ return storageKey ? `${storageKey}.frozenEndColumnCount` : void 0;
4025
5090
  }
4026
- function toTitle(value) {
4027
- if (typeof value === "string" || typeof value === "number") return String(value);
4028
- return void 0;
5091
+ function clampFrozenColumnCount(count, columnCount) {
5092
+ if (!Number.isFinite(count)) return 0;
5093
+ return Math.max(0, Math.min(Math.round(count), columnCount));
4029
5094
  }
4030
- function defaultGetRowKey(row, rowIndex) {
4031
- return row?.id ?? row?.key ?? row?.linkKey ?? rowIndex;
5095
+ function normalizeFrozenColumnCounts(startCount, endCount, columnCount) {
5096
+ const normalizedStartCount = clampFrozenColumnCount(startCount, columnCount);
5097
+ const normalizedEndCount = clampFrozenColumnCount(endCount, Math.max(0, columnCount - normalizedStartCount));
5098
+ return {
5099
+ startCount: normalizedStartCount,
5100
+ endCount: normalizedEndCount
5101
+ };
4032
5102
  }
4033
- function defaultGetRowSelectionKey(row) {
4034
- return row?.linkKey ?? row?.id ?? row?.key;
5103
+ function loadStoredFrozenColumnCount(storageKey, defaultCount, columnCount) {
5104
+ const fallback = clampFrozenColumnCount(defaultCount, columnCount);
5105
+ const frozenStorageKey = getFrozenColumnStorageKey(storageKey);
5106
+ if (!frozenStorageKey || !isBrowser()) return fallback;
5107
+ try {
5108
+ const storedValue = window.localStorage.getItem(frozenStorageKey);
5109
+ if (storedValue === null) return fallback;
5110
+ const value = Number(storedValue);
5111
+ return Number.isFinite(value) ? clampFrozenColumnCount(value, columnCount) : fallback;
5112
+ } catch {
5113
+ return fallback;
5114
+ }
4035
5115
  }
4036
- function getOrderedColumns(columns, columnOrder) {
4037
- if (!columnOrder?.length) return columns;
4038
- const columnMap = new Map(columns.map((column) => [column.key, column]));
4039
- const orderedColumns = columnOrder.map((columnKey) => columnMap.get(columnKey)).filter(Boolean);
4040
- const orderedKeySet = new Set(orderedColumns.map((column) => column.key));
4041
- const remainingColumns = columns.filter((column) => !orderedKeySet.has(column.key));
4042
- return [...orderedColumns, ...remainingColumns];
5116
+ function persistFrozenColumnCount(storageKey, count) {
5117
+ const frozenStorageKey = getFrozenColumnStorageKey(storageKey);
5118
+ if (!frozenStorageKey || !isBrowser()) return;
5119
+ window.localStorage.setItem(frozenStorageKey, String(count));
4043
5120
  }
4044
- function normalizeColumnOrder(columnKeys, columnOrder) {
5121
+ function loadStoredFrozenEndColumnCount(storageKey, defaultCount, columnCount) {
5122
+ const fallback = clampFrozenColumnCount(defaultCount, columnCount);
5123
+ const frozenStorageKey = getFrozenEndColumnStorageKey(storageKey);
5124
+ if (!frozenStorageKey || !isBrowser()) return fallback;
5125
+ try {
5126
+ const storedValue = window.localStorage.getItem(frozenStorageKey);
5127
+ if (storedValue === null) return fallback;
5128
+ const value = Number(storedValue);
5129
+ return Number.isFinite(value) ? clampFrozenColumnCount(value, columnCount) : fallback;
5130
+ } catch {
5131
+ return fallback;
5132
+ }
5133
+ }
5134
+ function persistFrozenEndColumnCount(storageKey, count) {
5135
+ const frozenStorageKey = getFrozenEndColumnStorageKey(storageKey);
5136
+ if (!frozenStorageKey || !isBrowser()) return;
5137
+ window.localStorage.setItem(frozenStorageKey, String(count));
5138
+ }
5139
+ function normalizeColumnOrder2(columnKeys, columnOrder) {
4045
5140
  const validColumnKeys = new Set(columnKeys);
4046
5141
  const orderedKeys = (columnOrder || []).filter((columnKey) => validColumnKeys.has(columnKey));
4047
5142
  const orderedKeySet = new Set(orderedKeys);
4048
5143
  const remainingKeys = columnKeys.filter((columnKey) => !orderedKeySet.has(columnKey));
4049
5144
  return [...orderedKeys, ...remainingKeys];
4050
5145
  }
4051
- function WorkbenchTableHeaderHelper({
4052
- helperText,
4053
- className
5146
+ function getOrderedColumns2(columns, columnOrder) {
5147
+ const normalizedOrder = normalizeColumnOrder2(columns.map((column) => column.key), columnOrder);
5148
+ const columnMap = new Map(columns.map((column) => [column.key, column]));
5149
+ return normalizedOrder.map((columnKey) => columnMap.get(columnKey)).filter(Boolean);
5150
+ }
5151
+ function getColumnNumericWidth(column, columnSizes) {
5152
+ const controlledWidth = columnSizes[column.key];
5153
+ if (typeof controlledWidth === "number") return controlledWidth;
5154
+ return getColumnDefaultSize(column);
5155
+ }
5156
+ function buildFrozenOffsets(columns, columnSizes, frozenColumnCount) {
5157
+ const offsets = /* @__PURE__ */ new Map();
5158
+ let left = 0;
5159
+ columns.slice(0, Math.max(0, frozenColumnCount)).forEach((column) => {
5160
+ offsets.set(column.key, left);
5161
+ left += getColumnNumericWidth(column, columnSizes);
5162
+ });
5163
+ return offsets;
5164
+ }
5165
+ function buildFrozenEndOffsets(columns, columnSizes, frozenEndColumnCount) {
5166
+ const offsets = /* @__PURE__ */ new Map();
5167
+ let right = 0;
5168
+ columns.slice(Math.max(0, columns.length - frozenEndColumnCount)).reverse().forEach((column) => {
5169
+ offsets.set(column.key, right);
5170
+ right += getColumnNumericWidth(column, columnSizes);
5171
+ });
5172
+ return offsets;
5173
+ }
5174
+ function resolveRowClassName(rowClassName, row, rowIndex) {
5175
+ return typeof rowClassName === "function" ? rowClassName(row, rowIndex) : rowClassName;
5176
+ }
5177
+ function renderDefaultCell(column, row) {
5178
+ const value = row?.[column.key];
5179
+ if (value === void 0 || value === null || value === "") return "\u2014";
5180
+ return String(value);
5181
+ }
5182
+ function InteractiveTableCellContent({
5183
+ children,
5184
+ wrap
4054
5185
  }) {
4055
- if (!hasRenderableNode(helperText)) return null;
4056
- return /* @__PURE__ */ jsxs("span", { className: cn("group relative inline-flex items-center", className), children: [
4057
- /* @__PURE__ */ jsx(
4058
- "button",
4059
- {
4060
- type: "button",
4061
- title: toTitle(helperText),
4062
- "aria-label": toTitle(helperText) || "Field help",
4063
- className: "inline-flex h-4 w-4 items-center justify-center rounded-full border border-border/60 bg-background text-[10px] font-semibold normal-case tracking-normal text-muted-foreground shadow-sm transition-colors hover:border-primary/40 hover:text-primary focus-visible:border-primary/40 focus-visible:text-primary focus-visible:outline-none",
4064
- onClick: (event) => event.stopPropagation(),
4065
- children: "?"
4066
- }
4067
- ),
4068
- /* @__PURE__ */ jsx(
4069
- "span",
4070
- {
4071
- role: "tooltip",
4072
- className: "pointer-events-none absolute left-1/2 top-full z-40 mt-2 hidden w-72 -translate-x-1/2 whitespace-pre-line rounded-lg border border-border/60 bg-card px-3 py-2 text-[11px] font-normal normal-case leading-5 tracking-normal text-foreground shadow-sm backdrop-blur-sm group-hover:block group-focus-within:block",
4073
- children: helperText
4074
- }
4075
- )
4076
- ] });
5186
+ return /* @__PURE__ */ jsx(
5187
+ "div",
5188
+ {
5189
+ className: cn(
5190
+ "min-w-0 max-w-full overflow-auto overscroll-contain [scrollbar-width:thin]",
5191
+ wrap ? "max-h-20 whitespace-pre-wrap break-words leading-5" : "whitespace-nowrap"
5192
+ ),
5193
+ children
5194
+ }
5195
+ );
4077
5196
  }
4078
- function WorkbenchTableView({
5197
+ function PinIcon({ className }) {
5198
+ return /* @__PURE__ */ jsxs(
5199
+ "svg",
5200
+ {
5201
+ "aria-hidden": "true",
5202
+ viewBox: "0 0 16 16",
5203
+ className,
5204
+ fill: "none",
5205
+ stroke: "currentColor",
5206
+ strokeLinecap: "round",
5207
+ strokeLinejoin: "round",
5208
+ strokeWidth: "1.75",
5209
+ children: [
5210
+ /* @__PURE__ */ jsx("path", { d: "M5.25 2.75h5.5" }),
5211
+ /* @__PURE__ */ jsx("path", { d: "M6.25 2.75v4L4.5 9.25h7L9.75 6.75v-4" }),
5212
+ /* @__PURE__ */ jsx("path", { d: "M8 9.25v4" })
5213
+ ]
5214
+ }
5215
+ );
5216
+ }
5217
+ function InteractiveTable({
4079
5218
  rows = [],
4080
5219
  columns = [],
5220
+ pinnedTopRows = [],
5221
+ getRowKey = defaultGetRowKey2,
5222
+ getPinnedTopRowKey = defaultGetRowKey2,
5223
+ renderCell,
5224
+ renderPinnedTopCell,
5225
+ renderColumnHeader,
4081
5226
  onRowClick,
4082
- selectedRowKey,
4083
- selectedLinkKey,
4084
- activePrimaryColumn,
4085
- activeTablePrimaryColumn,
4086
- renderedRowCount,
4087
- totalRowCount,
4088
- tableMinWidth,
4089
- minWidth,
4090
- bodyMaxHeight = "min(58vh, 38rem)",
4091
- stickyFirstColumn = true,
4092
- appearance,
5227
+ getRowState,
5228
+ rowClassName,
5229
+ pinnedTopRowClassName,
5230
+ emptyState = "\u2014",
5231
+ columnMenuLabels,
5232
+ columnStorageKey,
4093
5233
  columnOrder,
4094
5234
  columnSizes,
4095
- columnDragEnabled,
4096
- columnResizeEnabled,
5235
+ defaultColumnSizes,
5236
+ columnDragEnabled = false,
5237
+ columnResizeEnabled = true,
5238
+ frozenColumnCount = 0,
5239
+ frozenEndColumnCount = 0,
5240
+ tableMinWidth,
5241
+ bodyMaxHeight = "min(60vh, 42rem)",
5242
+ appearance,
4097
5243
  className,
4098
5244
  tableClassName,
4099
- rowClassName,
4100
5245
  classNames,
4101
5246
  style,
4102
- renderCell,
4103
- renderFieldValue,
4104
- renderColumnHeader,
4105
5247
  onColumnOrderChange,
4106
5248
  onColumnSizeChange,
4107
- onSort,
4108
- formatLabel = defaultFormatLabel,
4109
- getColumnDataType,
4110
- getColumnIcon,
4111
- getColumnTypeIcon,
4112
- getRowKey = defaultGetRowKey,
4113
- getRowSelectionKey = defaultGetRowSelectionKey,
4114
- isActionColumn,
4115
- isActionField,
4116
- isRowDisabled,
4117
- isWorkbenchPlaceholderRow,
4118
- emptyState = "-",
4119
- hiddenRowsMessage
5249
+ onResetColumnSizes,
5250
+ onFrozenColumnCountChange,
5251
+ onFrozenEndColumnCountChange,
5252
+ onSort
4120
5253
  }) {
4121
5254
  const columnKeySignature = columns.map((column) => column.key).join("");
4122
- const defaultColumnOrder = useMemo(() => columnKeySignature ? columnKeySignature.split("") : [], [columnKeySignature]);
4123
- const [internalColumnOrder, setInternalColumnOrder] = useState(defaultColumnOrder);
4124
- const [internalColumnSizes, setInternalColumnSizes] = useState({});
5255
+ const defaultOrder = useMemo(
5256
+ () => columnKeySignature ? columnKeySignature.split("") : [],
5257
+ [columnKeySignature]
5258
+ );
5259
+ const defaultSizes = useMemo(
5260
+ () => buildDefaultColumnSizes(columns, defaultColumnSizes),
5261
+ [columns, defaultColumnSizes]
5262
+ );
5263
+ const [internalColumnOrder, setInternalColumnOrder] = useState(defaultOrder);
5264
+ const [internalColumnSizes, setInternalColumnSizes] = useState(() => loadStoredColumnSizes(columnStorageKey, defaultSizes));
5265
+ const [internalFrozenColumnCount, setInternalFrozenColumnCount] = useState(() => loadStoredFrozenColumnCount(columnStorageKey, frozenColumnCount, columns.length));
5266
+ const [internalFrozenEndColumnCount, setInternalFrozenEndColumnCount] = useState(() => loadStoredFrozenEndColumnCount(columnStorageKey, frozenEndColumnCount, columns.length));
4125
5267
  useEffect(() => {
4126
- setInternalColumnOrder((current) => normalizeColumnOrder(defaultColumnOrder, current));
4127
- }, [defaultColumnOrder]);
4128
- const resolvedColumnOrder = columnOrder ? normalizeColumnOrder(defaultColumnOrder, columnOrder) : internalColumnOrder;
5268
+ setInternalColumnOrder((current) => normalizeColumnOrder2(defaultOrder, current));
5269
+ }, [defaultOrder]);
5270
+ useEffect(() => {
5271
+ if (columnSizes) return;
5272
+ setInternalColumnSizes(loadStoredColumnSizes(columnStorageKey, defaultSizes));
5273
+ }, [columnSizes, columnStorageKey, defaultSizes]);
5274
+ useEffect(() => {
5275
+ setInternalFrozenColumnCount(loadStoredFrozenColumnCount(columnStorageKey, frozenColumnCount, columns.length));
5276
+ }, [columnStorageKey, columns.length, frozenColumnCount]);
5277
+ useEffect(() => {
5278
+ setInternalFrozenEndColumnCount(loadStoredFrozenEndColumnCount(columnStorageKey, frozenEndColumnCount, columns.length));
5279
+ }, [columnStorageKey, columns.length, frozenEndColumnCount]);
5280
+ const resolvedColumnOrder = columnOrder ? normalizeColumnOrder2(defaultOrder, columnOrder) : internalColumnOrder;
4129
5281
  const resolvedColumnSizes = columnSizes ?? internalColumnSizes;
5282
+ const orderedColumns = getOrderedColumns2(columns, resolvedColumnOrder);
5283
+ const {
5284
+ startCount: resolvedFrozenColumnCount,
5285
+ endCount: resolvedFrozenEndColumnCount
5286
+ } = normalizeFrozenColumnCounts(internalFrozenColumnCount, internalFrozenEndColumnCount, orderedColumns.length);
5287
+ const frozenOffsets = buildFrozenOffsets(orderedColumns, resolvedColumnSizes, resolvedFrozenColumnCount);
5288
+ const frozenEndOffsets = buildFrozenEndOffsets(orderedColumns, resolvedColumnSizes, resolvedFrozenEndColumnCount);
5289
+ const resolvedMinWidth = tableMinWidth ?? Math.max(760, orderedColumns.reduce((total, column) => total + getColumnNumericWidth(column, resolvedColumnSizes), 0));
5290
+ const labels = {
5291
+ columnActions: columnMenuLabels?.columnActions ?? "Column actions",
5292
+ freezeColumn: columnMenuLabels?.freezeColumn ?? "Freeze to left",
5293
+ freezeEndColumn: columnMenuLabels?.freezeEndColumn ?? "Freeze to right",
5294
+ unfreezeColumn: columnMenuLabels?.unfreezeColumn ?? "Unfreeze from left",
5295
+ unfreezeEndColumn: columnMenuLabels?.unfreezeEndColumn ?? "Unfreeze from right",
5296
+ unfreezeAllColumns: columnMenuLabels?.unfreezeAllColumns ?? "Unfreeze all columns",
5297
+ resetColumnWidth: columnMenuLabels?.resetColumnWidth ?? "Reset column width",
5298
+ frozenColumnTitle: columnMenuLabels?.frozenColumnTitle ?? "Frozen column"
5299
+ };
4130
5300
  const handleColumnOrderChange = useCallback((nextOrder, detail) => {
4131
- const normalizedOrder = normalizeColumnOrder(defaultColumnOrder, nextOrder);
5301
+ const normalizedOrder = normalizeColumnOrder2(defaultOrder, nextOrder);
4132
5302
  if (!columnOrder) {
4133
5303
  setInternalColumnOrder(normalizedOrder);
4134
5304
  }
4135
5305
  onColumnOrderChange?.(normalizedOrder, detail);
4136
- }, [columnOrder, defaultColumnOrder, onColumnOrderChange]);
5306
+ }, [columnOrder, defaultOrder, onColumnOrderChange]);
4137
5307
  const handleColumnSizeChange = useCallback((columnId, width, detail) => {
5308
+ const column = columns.find((item) => item.key === columnId);
5309
+ const minWidth = column?.minWidth;
5310
+ const maxWidth = column?.maxWidth;
5311
+ const nextWidth = Math.max(
5312
+ typeof minWidth === "number" ? minWidth : 0,
5313
+ Math.min(width, typeof maxWidth === "number" ? maxWidth : Number.POSITIVE_INFINITY)
5314
+ );
5315
+ const nextSizes = {
5316
+ ...resolvedColumnSizes,
5317
+ [columnId]: nextWidth
5318
+ };
4138
5319
  if (!columnSizes) {
4139
- setInternalColumnSizes((current) => ({
4140
- ...current,
4141
- [columnId]: width
4142
- }));
5320
+ setInternalColumnSizes(nextSizes);
4143
5321
  }
4144
- onColumnSizeChange?.(columnId, width, detail);
4145
- }, [columnSizes, onColumnSizeChange]);
4146
- const resolvedSelectedKey = selectedRowKey ?? selectedLinkKey;
4147
- const resolvedActivePrimaryColumn = activePrimaryColumn ?? activeTablePrimaryColumn;
4148
- const orderedColumns = getOrderedColumns(columns, resolvedColumnOrder);
4149
- const hiddenRowCount = Math.max(0, Number(totalRowCount || rows.length) - Number(renderedRowCount || rows.length));
4150
- const resolvedMinWidth = tableMinWidth ?? minWidth ?? Math.max(760, Math.min(orderedColumns.length * 112, 1440));
4151
- const renderValue = renderCell ?? renderFieldValue ?? ((column, row) => row?.[column.key]);
4152
- const isAction = isActionColumn ?? isActionField ?? (() => false);
4153
- const isDisabled = isRowDisabled ?? isWorkbenchPlaceholderRow ?? (() => false);
4154
- const resolveColumnIcon = getColumnIcon ?? getColumnTypeIcon;
4155
- const footer = hiddenRowCount > 0 && hiddenRowsMessage ? typeof hiddenRowsMessage === "function" ? hiddenRowsMessage(hiddenRowCount, renderedRowCount || rows.length, totalRowCount || rows.length) : hiddenRowsMessage : null;
4156
- return /* @__PURE__ */ jsxs(
5322
+ persistColumnSizes(columnStorageKey, nextSizes);
5323
+ onColumnSizeChange?.(columnId, nextWidth, detail);
5324
+ }, [columnSizes, columnStorageKey, columns, onColumnSizeChange, resolvedColumnSizes]);
5325
+ const handleResetColumnSize = useCallback((column) => {
5326
+ const nextWidth = defaultSizes[column.key] ?? getColumnDefaultSize(column);
5327
+ const previousWidth = getColumnNumericWidth(column, resolvedColumnSizes);
5328
+ const nextSizes = {
5329
+ ...resolvedColumnSizes,
5330
+ [column.key]: nextWidth
5331
+ };
5332
+ if (!columnSizes) {
5333
+ setInternalColumnSizes(nextSizes);
5334
+ }
5335
+ persistColumnSizes(columnStorageKey, nextSizes);
5336
+ onColumnSizeChange?.(column.key, nextWidth, {
5337
+ columnId: column.key,
5338
+ previousWidth,
5339
+ minWidth: column.minWidth,
5340
+ maxWidth: column.maxWidth
5341
+ });
5342
+ onResetColumnSizes?.(nextSizes);
5343
+ }, [columnSizes, columnStorageKey, defaultSizes, onColumnSizeChange, onResetColumnSizes, resolvedColumnSizes]);
5344
+ const setFrozenColumnCount = useCallback((nextCount) => {
5345
+ const normalizedCount = clampFrozenColumnCount(nextCount, Math.max(0, orderedColumns.length - resolvedFrozenEndColumnCount));
5346
+ setInternalFrozenColumnCount(normalizedCount);
5347
+ persistFrozenColumnCount(columnStorageKey, normalizedCount);
5348
+ onFrozenColumnCountChange?.(normalizedCount);
5349
+ }, [columnStorageKey, onFrozenColumnCountChange, orderedColumns.length, resolvedFrozenEndColumnCount]);
5350
+ const setFrozenEndColumnCount = useCallback((nextCount) => {
5351
+ const normalizedCount = clampFrozenColumnCount(nextCount, Math.max(0, orderedColumns.length - resolvedFrozenColumnCount));
5352
+ setInternalFrozenEndColumnCount(normalizedCount);
5353
+ persistFrozenEndColumnCount(columnStorageKey, normalizedCount);
5354
+ onFrozenEndColumnCountChange?.(normalizedCount);
5355
+ }, [columnStorageKey, onFrozenEndColumnCountChange, orderedColumns.length, resolvedFrozenColumnCount]);
5356
+ const getFrozenPosition = (columnIndex) => {
5357
+ if (columnIndex < resolvedFrozenColumnCount) return "start";
5358
+ if (columnIndex >= orderedColumns.length - resolvedFrozenEndColumnCount) return "end";
5359
+ return void 0;
5360
+ };
5361
+ const getFrozenClassName = (column, columnIndex, isHeader = false) => {
5362
+ const position = getFrozenPosition(columnIndex);
5363
+ if (!position) return void 0;
5364
+ return cn(
5365
+ "sticky",
5366
+ position === "start" ? "shadow-[1px_0_0_0_hsl(var(--border)/0.45)]" : "shadow-[-1px_0_0_0_hsl(var(--border)/0.45)]",
5367
+ isHeader ? "bg-muted/60" : "bg-inherit",
5368
+ isHeader ? "z-40" : "z-20",
5369
+ (columnIndex === 0 || columnIndex === orderedColumns.length - 1) && (isHeader ? "z-50" : "z-30")
5370
+ );
5371
+ };
5372
+ const getFrozenStyle = (column, columnIndex) => {
5373
+ const position = getFrozenPosition(columnIndex);
5374
+ if (position === "start") return { left: frozenOffsets.get(column.key) ?? 0 };
5375
+ if (position === "end") return { right: frozenEndOffsets.get(column.key) ?? 0 };
5376
+ return void 0;
5377
+ };
5378
+ return /* @__PURE__ */ jsx(
4157
5379
  BaseTableContainer,
4158
5380
  {
4159
5381
  appearance,
4160
- className: cn("w-full overflow-hidden rounded-lg border border-border/40 bg-muted/15 dark:border-border/35 dark:bg-muted/10", classNames?.root, className),
5382
+ className: cn("flex h-full min-h-0 flex-col overflow-hidden rounded-lg border border-border/60 bg-card", classNames?.root, className),
4161
5383
  style,
4162
- children: [
4163
- /* @__PURE__ */ jsx(
4164
- "div",
4165
- {
4166
- className: cn("w-full overflow-auto", classNames?.scrollArea),
4167
- style: { maxHeight: toCssSize2(bodyMaxHeight) },
4168
- children: /* @__PURE__ */ jsxs(
4169
- BaseTable,
4170
- {
4171
- appearance,
4172
- columnOrder: resolvedColumnOrder,
4173
- columnSizes: resolvedColumnSizes,
4174
- columnDragEnabled,
4175
- columnResizeEnabled,
4176
- onColumnOrderChange: handleColumnOrderChange,
4177
- onColumnSizeChange: handleColumnSizeChange,
4178
- className: cn("w-full table-auto text-left text-xs", classNames?.table, tableClassName),
4179
- style: { minWidth: resolvedMinWidth },
4180
- children: [
4181
- /* @__PURE__ */ jsx(BaseTableHeader, { appearance, className: cn("text-[10px] font-mono uppercase tracking-wide text-muted-foreground", classNames?.header), children: /* @__PURE__ */ jsx(BaseTableRow, { className: cn("hover:bg-transparent", classNames?.headerRow), children: orderedColumns.map((column, columnIndex) => {
4182
- const columnType = column.renderType || column.type || getColumnDataType?.(column.key, rows, column);
4183
- const columnIcon = renderWorkbenchIcon(
4184
- resolveColumnIcon?.(columnType, column),
4185
- "h-3.5 w-3.5 shrink-0 text-primary"
4186
- );
4187
- const previousColumn = orderedColumns[columnIndex - 1];
4188
- const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
4189
- const headerContent = renderColumnHeader ? renderColumnHeader(column, { column, columnIndex, columns: orderedColumns, rows, columnType }) : formatLabel(column.label, { column });
4190
- const headerTrailing = !renderColumnHeader && (hasRenderableNode(column.trailing) || hasRenderableNode(column.helperText)) ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
4191
- hasRenderableNode(column.trailing) ? formatLabel(column.trailing, { column }) : null,
4192
- /* @__PURE__ */ jsx(WorkbenchTableHeaderHelper, { helperText: formatLabel(column.helperText, { column }), className: classNames?.helper })
4193
- ] }) : void 0;
4194
- const sortable = Boolean(column.sortable);
4195
- const handleSort = sortable && onSort ? () => onSort(column.key, column) : void 0;
4196
- return /* @__PURE__ */ jsx(
5384
+ children: /* @__PURE__ */ jsx(
5385
+ "div",
5386
+ {
5387
+ className: cn("min-h-0 flex-1 overflow-auto", classNames?.scrollArea),
5388
+ style: { maxHeight: toCssSize3(bodyMaxHeight) },
5389
+ children: /* @__PURE__ */ jsxs(
5390
+ BaseTable,
5391
+ {
5392
+ appearance,
5393
+ columnOrder: resolvedColumnOrder,
5394
+ columnSizes: resolvedColumnSizes,
5395
+ columnDragEnabled,
5396
+ columnResizeEnabled,
5397
+ onColumnOrderChange: handleColumnOrderChange,
5398
+ onColumnSizeChange: handleColumnSizeChange,
5399
+ className: cn("w-full table-fixed text-left text-xs", classNames?.table, tableClassName),
5400
+ style: { minWidth: resolvedMinWidth },
5401
+ children: [
5402
+ /* @__PURE__ */ jsx("colgroup", { children: orderedColumns.map((column) => /* @__PURE__ */ jsx(
5403
+ "col",
5404
+ {
5405
+ style: {
5406
+ width: toCssSize3(resolvedColumnSizes[column.key] ?? column.width),
5407
+ minWidth: toCssSize3(column.minWidth)
5408
+ }
5409
+ },
5410
+ column.key
5411
+ )) }),
5412
+ /* @__PURE__ */ jsx(BaseTableHeader, { appearance, className: cn("border-b border-border/60 bg-muted/60 text-[11px] font-medium text-muted-foreground", classNames?.tableHeader), children: /* @__PURE__ */ jsx(BaseTableRow, { appearance, className: cn("hover:bg-transparent", classNames?.headerRow), children: orderedColumns.map((column, columnIndex) => {
5413
+ const headerContent = renderColumnHeader ? renderColumnHeader(column, { column, columnIndex, columns: orderedColumns, rows }) : column.label;
5414
+ const sortable = Boolean(column.sortable);
5415
+ const handleSort = sortable && onSort ? () => onSort(column.key, column) : void 0;
5416
+ const isFrozenStart = columnIndex < resolvedFrozenColumnCount;
5417
+ const isFrozenEnd = columnIndex >= orderedColumns.length - resolvedFrozenEndColumnCount;
5418
+ const isFrozen = isFrozenStart || isFrozenEnd;
5419
+ const isColumnAtDefaultWidth = getColumnNumericWidth(column, resolvedColumnSizes) === (defaultSizes[column.key] ?? getColumnDefaultSize(column));
5420
+ return /* @__PURE__ */ jsxs(BaseContextMenu, { modal: false, children: [
5421
+ /* @__PURE__ */ jsx(BaseContextMenuTrigger, { asChild: true, appearance, children: /* @__PURE__ */ jsx(
4197
5422
  BaseTableHead,
4198
5423
  {
4199
5424
  appearance,
4200
5425
  columnId: column.key,
4201
5426
  align: column.align,
4202
- icon: renderColumnHeader ? void 0 : columnIcon,
4203
5427
  label: headerContent,
4204
- description: renderColumnHeader ? void 0 : formatLabel(column.description, { column }),
4205
- meta: renderColumnHeader ? void 0 : formatLabel(column.meta, { column }),
4206
- actions: renderColumnHeader ? void 0 : column.actions,
4207
- trailing: headerTrailing,
5428
+ description: column.description,
5429
+ trailing: isFrozen ? /* @__PURE__ */ jsx("span", { title: labels.frozenColumnTitle, className: "inline-flex h-5 w-5 items-center justify-center rounded text-primary", children: /* @__PURE__ */ jsx(PinIcon, { className: "h-3.5 w-3.5" }) }) : null,
4208
5430
  sortable,
4209
5431
  sortDirection: column.sortDirection,
4210
5432
  sortLabel: column.sortLabel,
4211
5433
  onSort: handleSort,
4212
5434
  draggable: column.draggable,
4213
- dragLabel: column.dragLabel,
4214
5435
  resizable: column.resizable,
4215
- resizeLabel: column.resizeLabel,
4216
5436
  width: column.width,
4217
- minWidth: typeof column.minWidth === "number" ? column.minWidth : void 0,
4218
- maxWidth: typeof column.maxWidth === "number" ? column.maxWidth : void 0,
5437
+ minWidth: column.minWidth,
5438
+ maxWidth: column.maxWidth,
4219
5439
  className: cn(
4220
- "sticky top-0 z-20 h-auto whitespace-nowrap bg-card/95 px-4 py-3 font-medium backdrop-blur-sm supports-[backdrop-filter]:bg-card/90",
4221
- stickyFirstColumn && columnIndex === 0 && "left-0 z-30 shadow-[1px_0_0_0_hsl(var(--border)/0.35)]",
4222
- column.compactHeaderClassName,
5440
+ "sticky top-0 h-9 whitespace-nowrap border-r border-border/50 bg-muted/60 px-2.5 py-2 backdrop-blur",
5441
+ getFrozenClassName(column, columnIndex, true),
4223
5442
  column.headerClassName,
4224
- column.renderType === "icon" && "pl-3 pr-1",
4225
- followsRecordIcon && "pl-2",
5443
+ column.className,
4226
5444
  classNames?.headerCell
4227
5445
  ),
4228
- style: {
4229
- minWidth: typeof column.minWidth === "string" ? column.minWidth : void 0,
4230
- maxWidth: typeof column.maxWidth === "string" ? column.maxWidth : void 0
5446
+ style: getFrozenStyle(column, columnIndex)
5447
+ }
5448
+ ) }),
5449
+ /* @__PURE__ */ jsxs(BaseContextMenuContent, { appearance, alignOffset: -4, className: "min-w-44", children: [
5450
+ /* @__PURE__ */ jsx(BaseContextMenuLabel, { appearance, children: labels.columnActions }),
5451
+ isFrozen ? /* @__PURE__ */ jsx(
5452
+ BaseContextMenuItem,
5453
+ {
5454
+ appearance,
5455
+ onSelect: () => {
5456
+ if (isFrozenEnd) setFrozenEndColumnCount(orderedColumns.length - columnIndex - 1);
5457
+ else setFrozenColumnCount(columnIndex);
5458
+ },
5459
+ children: isFrozenEnd ? labels.unfreezeEndColumn : labels.unfreezeColumn
5460
+ }
5461
+ ) : /* @__PURE__ */ jsx(
5462
+ BaseContextMenuItem,
5463
+ {
5464
+ appearance,
5465
+ onSelect: () => setFrozenColumnCount(columnIndex + 1),
5466
+ children: labels.freezeColumn
5467
+ }
5468
+ ),
5469
+ !isFrozen ? /* @__PURE__ */ jsx(
5470
+ BaseContextMenuItem,
5471
+ {
5472
+ appearance,
5473
+ onSelect: () => setFrozenEndColumnCount(orderedColumns.length - columnIndex),
5474
+ children: labels.freezeEndColumn
5475
+ }
5476
+ ) : null,
5477
+ /* @__PURE__ */ jsx(
5478
+ BaseContextMenuItem,
5479
+ {
5480
+ appearance,
5481
+ disabled: resolvedFrozenColumnCount === 0 && resolvedFrozenEndColumnCount === 0,
5482
+ onSelect: () => {
5483
+ setFrozenColumnCount(0);
5484
+ setFrozenEndColumnCount(0);
5485
+ },
5486
+ children: labels.unfreezeAllColumns
4231
5487
  }
5488
+ ),
5489
+ /* @__PURE__ */ jsx(BaseContextMenuSeparator, { appearance }),
5490
+ /* @__PURE__ */ jsx(
5491
+ BaseContextMenuItem,
5492
+ {
5493
+ appearance,
5494
+ disabled: isColumnAtDefaultWidth,
5495
+ onSelect: () => handleResetColumnSize(column),
5496
+ children: labels.resetColumnWidth
5497
+ }
5498
+ )
5499
+ ] })
5500
+ ] }, column.key);
5501
+ }) }) }),
5502
+ /* @__PURE__ */ jsxs(BaseTableBody, { appearance, className: cn("divide-y divide-border/50", classNames?.body), children: [
5503
+ pinnedTopRows.map((row, rowIndex) => {
5504
+ const key = getPinnedTopRowKey(row, rowIndex);
5505
+ const resolvedRowClassName = resolveRowClassName(pinnedTopRowClassName, row, rowIndex);
5506
+ return /* @__PURE__ */ jsx(
5507
+ BaseTableRow,
5508
+ {
5509
+ appearance,
5510
+ className: cn("bg-card/95", classNames?.pinnedTopRow, resolvedRowClassName),
5511
+ children: orderedColumns.map((column, columnIndex) => /* @__PURE__ */ jsx(
5512
+ BaseTableCell,
5513
+ {
5514
+ appearance,
5515
+ align: column.align,
5516
+ className: cn(
5517
+ "h-[52px] border-r border-border/50 px-2.5 py-1.5 align-middle",
5518
+ column.wrap ? "whitespace-normal" : "whitespace-nowrap",
5519
+ getFrozenClassName(column, columnIndex),
5520
+ column.cellClassName,
5521
+ classNames?.cell
5522
+ ),
5523
+ style: getFrozenStyle(column, columnIndex),
5524
+ children: /* @__PURE__ */ jsx(InteractiveTableCellContent, { wrap: column.wrap, children: renderPinnedTopCell ? renderPinnedTopCell(column, row, { row, rowIndex, column, columnIndex, isPinnedTopRow: true }) : renderDefaultCell(column, row) })
5525
+ },
5526
+ `pinned-${key}-${column.key}`
5527
+ ))
4232
5528
  },
4233
- column.key
5529
+ `pinned-${key}`
4234
5530
  );
4235
- }) }) }),
4236
- /* @__PURE__ */ jsx(BaseTableBody, { appearance, className: cn("divide-y divide-border/35 dark:divide-border/30", classNames?.body), children: rows.length ? rows.map((row, rowIndex) => {
5531
+ }),
5532
+ rows.length ? rows.map((row, rowIndex) => {
4237
5533
  const key = getRowKey(row, rowIndex);
4238
- const disabled = isDisabled(row, rowIndex);
4239
- const selectionKey = getRowSelectionKey(row, rowIndex);
4240
- const selected = Boolean(resolvedSelectedKey && String(selectionKey) === String(resolvedSelectedKey));
4241
- const resolvedRowClassName = typeof rowClassName === "function" ? rowClassName(row, rowIndex) : rowClassName;
5534
+ const state = getRowState?.(row, rowIndex) || {};
5535
+ const resolvedRowClassName = resolveRowClassName(rowClassName, row, rowIndex);
4242
5536
  return /* @__PURE__ */ jsx(
4243
5537
  BaseTableRow,
4244
5538
  {
4245
5539
  appearance,
4246
- interactive: Boolean(onRowClick) && !disabled,
4247
- selected,
4248
- disabled,
5540
+ interactive: Boolean(onRowClick) && !state.disabled,
5541
+ selected: state.selected,
5542
+ disabled: state.disabled,
4249
5543
  onClick: () => {
4250
- if (!disabled) {
4251
- onRowClick?.(row, rowIndex);
4252
- }
5544
+ if (!state.disabled) onRowClick?.(row, rowIndex);
4253
5545
  },
4254
5546
  className: cn(
4255
- onRowClick && !disabled ? "cursor-pointer" : "cursor-default",
4256
- selected ? "bg-primary/10 hover:bg-primary/15" : disabled ? "" : "hover:bg-muted/25 dark:hover:bg-muted/15",
5547
+ "min-h-[52px] bg-card transition-colors",
5548
+ state.saving && "bg-primary/5",
5549
+ state.pending && "opacity-80",
5550
+ onRowClick && !state.disabled ? "cursor-pointer hover:bg-muted/30" : "hover:bg-muted/30",
4257
5551
  classNames?.row,
4258
5552
  resolvedRowClassName
4259
5553
  ),
4260
- children: orderedColumns.map((column, columnIndex) => {
4261
- const shouldWrap = isAction(column) || column.wrap === true;
4262
- const previousColumn = orderedColumns[columnIndex - 1];
4263
- const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
4264
- return /* @__PURE__ */ jsx(
4265
- BaseTableCell,
4266
- {
4267
- appearance,
4268
- align: column.align,
4269
- className: cn(
4270
- shouldWrap ? "align-top whitespace-normal" : "whitespace-nowrap",
4271
- "px-4 py-3 text-muted-foreground",
4272
- stickyFirstColumn && columnIndex === 0 && "sticky left-0 z-10 bg-card/95 text-foreground shadow-[1px_0_0_0_hsl(var(--border)/0.3)]",
4273
- column.compactCellClassName,
4274
- column.cellClassName,
4275
- column.renderType === "icon" && "pl-3 pr-1",
4276
- followsRecordIcon && "pl-2",
4277
- classNames?.cell
4278
- ),
4279
- children: renderValue(column, row, {
4280
- row,
4281
- rowIndex,
4282
- column,
4283
- columnIndex,
4284
- compact: true,
4285
- surface: "list"
4286
- })
4287
- },
4288
- `${key}-${column.key}`
4289
- );
4290
- })
5554
+ children: orderedColumns.map((column, columnIndex) => /* @__PURE__ */ jsx(
5555
+ BaseTableCell,
5556
+ {
5557
+ appearance,
5558
+ align: column.align,
5559
+ className: cn(
5560
+ "h-[52px] border-r border-border/50 px-2.5 py-1.5 align-middle",
5561
+ column.wrap ? "whitespace-normal" : "whitespace-nowrap",
5562
+ getFrozenClassName(column, columnIndex),
5563
+ column.cellClassName,
5564
+ classNames?.cell
5565
+ ),
5566
+ style: getFrozenStyle(column, columnIndex),
5567
+ children: /* @__PURE__ */ jsx(InteractiveTableCellContent, { wrap: column.wrap, children: renderCell ? renderCell(column, row, { row, rowIndex, column, columnIndex, isPinnedTopRow: false }) : renderDefaultCell(column, row) })
5568
+ },
5569
+ `${key}-${column.key}`
5570
+ ))
4291
5571
  },
4292
5572
  key
4293
5573
  );
4294
- }) : /* @__PURE__ */ jsx(
5574
+ }) : pinnedTopRows.length ? null : /* @__PURE__ */ jsx(
4295
5575
  BaseTableEmpty,
4296
5576
  {
4297
5577
  appearance,
4298
5578
  colSpan: Math.max(orderedColumns.length, 1),
4299
- classNames: { cell: "px-4 py-10 text-center text-sm text-muted-foreground" },
5579
+ className: classNames?.empty,
4300
5580
  children: emptyState
4301
5581
  }
4302
- ) })
4303
- ]
4304
- }
4305
- )
5582
+ )
5583
+ ] })
5584
+ ]
5585
+ }
5586
+ )
5587
+ }
5588
+ )
5589
+ }
5590
+ );
5591
+ }
5592
+ function InteractiveTableEditableTextCell({
5593
+ value,
5594
+ placeholder,
5595
+ disabled,
5596
+ multiline = false,
5597
+ commitOnBlur = true,
5598
+ className,
5599
+ inputClassName,
5600
+ onCommit
5601
+ }) {
5602
+ const initialValue = String(value || "");
5603
+ const [draft, setDraft] = useState(initialValue);
5604
+ useEffect(() => {
5605
+ setDraft(initialValue);
5606
+ }, [initialValue]);
5607
+ const commit = useCallback(async () => {
5608
+ const nextValue = String(draft || "").trim();
5609
+ const previousValue = String(initialValue || "").trim();
5610
+ if (nextValue === previousValue) return;
5611
+ try {
5612
+ await onCommit?.(nextValue);
5613
+ } catch {
5614
+ setDraft(initialValue);
5615
+ }
5616
+ }, [draft, initialValue, onCommit]);
5617
+ const controlClassName = cn(
5618
+ "w-full resize-none rounded-sm border border-transparent bg-transparent px-1.5 py-1 text-xs text-foreground outline-none transition-colors",
5619
+ "placeholder:text-muted-foreground/70 hover:border-border/60 hover:bg-background focus:border-primary/45 focus:bg-background",
5620
+ multiline ? "min-h-[42px] leading-5" : "h-8",
5621
+ disabled && "cursor-not-allowed text-muted-foreground hover:border-transparent hover:bg-transparent",
5622
+ inputClassName
5623
+ );
5624
+ if (multiline) {
5625
+ return /* @__PURE__ */ jsx(
5626
+ "textarea",
5627
+ {
5628
+ className: cn(controlClassName, className),
5629
+ disabled,
5630
+ value: draft,
5631
+ placeholder,
5632
+ onChange: (event) => setDraft(event.target.value),
5633
+ onBlur: () => {
5634
+ if (commitOnBlur) void commit();
5635
+ },
5636
+ onKeyDown: (event) => {
5637
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
5638
+ event.currentTarget.blur();
4306
5639
  }
4307
- ),
4308
- footer ? /* @__PURE__ */ jsx("div", { className: cn("border-t border-border/40 px-4 py-2 text-[11px] text-muted-foreground dark:border-border/30", classNames?.footer), children: footer }) : null
4309
- ]
5640
+ if (event.key === "Escape") {
5641
+ setDraft(initialValue);
5642
+ event.currentTarget.blur();
5643
+ }
5644
+ }
5645
+ }
5646
+ );
5647
+ }
5648
+ return /* @__PURE__ */ jsx(
5649
+ "input",
5650
+ {
5651
+ className: cn(controlClassName, className),
5652
+ disabled,
5653
+ value: draft,
5654
+ placeholder,
5655
+ onChange: (event) => setDraft(event.target.value),
5656
+ onBlur: () => {
5657
+ if (commitOnBlur) void commit();
5658
+ },
5659
+ onKeyDown: (event) => {
5660
+ if (event.key === "Enter") event.currentTarget.blur();
5661
+ if (event.key === "Escape") {
5662
+ setDraft(initialValue);
5663
+ event.currentTarget.blur();
5664
+ }
5665
+ }
4310
5666
  }
4311
5667
  );
4312
5668
  }
5669
+ function InteractiveTableReadonlyCell({
5670
+ children,
5671
+ mono = false,
5672
+ className
5673
+ }) {
5674
+ return /* @__PURE__ */ jsx("div", { className: cn("min-w-0 text-xs text-muted-foreground", mono && "font-mono", className), children: hasRenderableNode(children) ? children : "\u2014" });
5675
+ }
5676
+ function InteractiveTableSelectCell({
5677
+ value,
5678
+ options,
5679
+ disabled,
5680
+ ariaLabel,
5681
+ children,
5682
+ className,
5683
+ onChange
5684
+ }) {
5685
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative flex w-full items-center", className), children: [
5686
+ children,
5687
+ /* @__PURE__ */ jsx(
5688
+ "select",
5689
+ {
5690
+ "aria-label": ariaLabel,
5691
+ disabled,
5692
+ value,
5693
+ onChange: (event) => onChange?.(event.target.value),
5694
+ className: "absolute inset-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed",
5695
+ children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
5696
+ }
5697
+ )
5698
+ ] });
5699
+ }
4313
5700
  var imageExtPattern = /\.(png|jpe?g|webp|gif|svg|bmp|avif)$/i;
4314
5701
  var audioExtPattern = /\.(wav|mp3|ogg|m4a|flac|aac)$/i;
4315
5702
  var isLikelyUrl = (value) => /^https?:\/\//i.test(String(value || ""));
@@ -5496,7 +6883,174 @@ function WorkbenchGalleryView({
5496
6883
  }
5497
6884
  );
5498
6885
  }
6886
+ function toCssSize4(value) {
6887
+ if (value === void 0) return void 0;
6888
+ return typeof value === "number" ? `${value}px` : value;
6889
+ }
6890
+ function defaultGetRowId(row, rowIndex) {
6891
+ return String(row?.id ?? row?.key ?? rowIndex);
6892
+ }
6893
+ function defaultGetColumnId(row) {
6894
+ return String(row?.columnId ?? row?.status ?? "");
6895
+ }
6896
+ function defaultRenderCard(row) {
6897
+ const value = row?.title ?? row?.name ?? row?.id ?? "Untitled";
6898
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border/70 bg-card px-3 py-2 text-sm text-foreground shadow-sm", children: String(value) });
6899
+ }
6900
+ function WorkbenchLaneDraggableCard({
6901
+ row,
6902
+ rowId,
6903
+ rowIndex,
6904
+ column,
6905
+ classNames,
6906
+ renderCard
6907
+ }) {
6908
+ const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id: rowId });
6909
+ return /* @__PURE__ */ jsx(
6910
+ "div",
6911
+ {
6912
+ ref: setNodeRef,
6913
+ ...listeners,
6914
+ ...attributes,
6915
+ className: cn("touch-none", classNames?.cardWrapper),
6916
+ children: renderCard(row, { row, rowIndex, column, isDragging, isOverlay: false })
6917
+ }
6918
+ );
6919
+ }
6920
+ function WorkbenchLaneColumnView({
6921
+ column,
6922
+ columnRows,
6923
+ columnWidth,
6924
+ columnMinHeight,
6925
+ emptyColumn,
6926
+ classNames,
6927
+ renderCard
6928
+ }) {
6929
+ const { setNodeRef, isOver } = useDroppable({ id: column.id });
6930
+ return /* @__PURE__ */ jsxs(
6931
+ "section",
6932
+ {
6933
+ className: cn(
6934
+ "flex shrink-0 flex-col rounded-xl border border-border/60 bg-card p-2 shadow-sm",
6935
+ classNames?.column,
6936
+ column.className
6937
+ ),
6938
+ style: { width: toCssSize4(columnWidth) ?? "280px" },
6939
+ children: [
6940
+ /* @__PURE__ */ jsxs("div", { className: cn("flex h-10 items-center gap-2 px-1", classNames?.columnHeader, column.headerClassName), children: [
6941
+ column.icon ? /* @__PURE__ */ jsx("span", { className: cn("inline-flex h-4 w-4 items-center justify-center text-muted-foreground", classNames?.columnIcon, column.iconClassName), children: column.icon }) : null,
6942
+ /* @__PURE__ */ jsx("span", { className: cn("inline-flex items-center rounded px-2 py-0.5 text-xs font-semibold bg-muted text-muted-foreground", classNames?.columnBadge, column.badgeClassName), children: column.label ?? column.id }),
6943
+ /* @__PURE__ */ jsx("span", { className: cn("text-xs text-muted-foreground", classNames?.columnCount), children: columnRows.length })
6944
+ ] }),
6945
+ /* @__PURE__ */ jsx(
6946
+ "div",
6947
+ {
6948
+ ref: setNodeRef,
6949
+ className: cn(
6950
+ "mt-1 flex min-h-[200px] flex-1 flex-col gap-2 overflow-y-auto rounded-lg p-1 transition-colors [scrollbar-width:thin]",
6951
+ isOver && "bg-accent/60",
6952
+ classNames?.columnBody,
6953
+ column.bodyClassName
6954
+ ),
6955
+ style: { minHeight: toCssSize4(columnMinHeight) },
6956
+ children: columnRows.length ? columnRows.map(({ row, rowIndex, rowId }) => /* @__PURE__ */ jsx(
6957
+ WorkbenchLaneDraggableCard,
6958
+ {
6959
+ row,
6960
+ rowId,
6961
+ rowIndex,
6962
+ column,
6963
+ classNames,
6964
+ renderCard
6965
+ },
6966
+ rowId
6967
+ )) : emptyColumn ? /* @__PURE__ */ jsx("div", { className: cn("flex min-h-24 items-center justify-center rounded-lg border border-dashed border-border/60 px-3 py-4 text-xs text-muted-foreground", classNames?.emptyColumn), children: emptyColumn }) : null
6968
+ }
6969
+ )
6970
+ ]
6971
+ }
6972
+ );
6973
+ }
6974
+ function WorkbenchLaneView({
6975
+ rows = [],
6976
+ columns = [],
6977
+ getRowId = defaultGetRowId,
6978
+ getColumnId = defaultGetColumnId,
6979
+ renderCard = defaultRenderCard,
6980
+ renderOverlayCard,
6981
+ onMoveRow,
6982
+ emptyColumn,
6983
+ activationDistance = 5,
6984
+ columnWidth = 280,
6985
+ columnMinHeight,
6986
+ className,
6987
+ classNames,
6988
+ style
6989
+ }) {
6990
+ const [activeRowId, setActiveRowId] = useState(null);
6991
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: activationDistance } }));
6992
+ const columnMap = useMemo(() => new Map(columns.map((column) => [column.id, column])), [columns]);
6993
+ const rowEntries = useMemo(() => rows.map((row, rowIndex) => ({
6994
+ row,
6995
+ rowIndex,
6996
+ rowId: getRowId(row, rowIndex),
6997
+ columnId: getColumnId(row, rowIndex)
6998
+ })), [getColumnId, getRowId, rows]);
6999
+ const activeEntry = activeRowId ? rowEntries.find((entry) => entry.rowId === activeRowId) : void 0;
7000
+ const rowsByColumn = useMemo(() => {
7001
+ const next = /* @__PURE__ */ new Map();
7002
+ columns.forEach((column) => next.set(column.id, []));
7003
+ rowEntries.forEach(({ row, rowIndex, rowId, columnId }) => {
7004
+ next.get(columnId)?.push({ row, rowIndex, rowId });
7005
+ });
7006
+ return next;
7007
+ }, [columns, rowEntries]);
7008
+ const activeColumn = activeEntry ? columnMap.get(activeEntry.columnId) : void 0;
7009
+ const handleDragStart = useCallback((event) => {
7010
+ setActiveRowId(String(event.active.id));
7011
+ }, []);
7012
+ const handleDragEnd = useCallback((event) => {
7013
+ setActiveRowId(null);
7014
+ const rowId = String(event.active.id);
7015
+ const nextColumnId = String(event.over?.id ?? "");
7016
+ const activeRow = rowEntries.find((entry) => entry.rowId === rowId);
7017
+ if (!activeRow || !columnMap.has(nextColumnId) || activeRow.columnId === nextColumnId) return;
7018
+ onMoveRow?.(rowId, nextColumnId, activeRow.row);
7019
+ }, [columnMap, onMoveRow, rowEntries]);
7020
+ const handleDragCancel = useCallback(() => {
7021
+ setActiveRowId(null);
7022
+ }, []);
7023
+ return /* @__PURE__ */ jsxs(DndContext, { sensors, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDragCancel: handleDragCancel, children: [
7024
+ /* @__PURE__ */ jsx(
7025
+ "div",
7026
+ {
7027
+ className: cn("flex min-h-0 flex-1 gap-4 overflow-x-auto p-4 [scrollbar-width:thin]", classNames?.root, className),
7028
+ style,
7029
+ children: columns.map((column) => /* @__PURE__ */ jsx(
7030
+ WorkbenchLaneColumnView,
7031
+ {
7032
+ column,
7033
+ columnRows: rowsByColumn.get(column.id) || [],
7034
+ columnWidth,
7035
+ columnMinHeight,
7036
+ emptyColumn,
7037
+ classNames,
7038
+ renderCard
7039
+ },
7040
+ column.id
7041
+ ))
7042
+ }
7043
+ ),
7044
+ /* @__PURE__ */ jsx(DragOverlay, { children: activeEntry && activeColumn ? /* @__PURE__ */ jsx("div", { className: cn(classNames?.overlayWrapper), children: (renderOverlayCard || renderCard)(activeEntry.row, {
7045
+ row: activeEntry.row,
7046
+ rowIndex: activeEntry.rowIndex,
7047
+ column: activeColumn,
7048
+ isDragging: false,
7049
+ isOverlay: true
7050
+ }) }) : null })
7051
+ ] });
7052
+ }
5499
7053
 
5500
- export { WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGalleryView, WorkbenchMasonryLayout, WorkbenchResizableSidebar, WorkbenchTableView };
7054
+ export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGalleryView, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchResizableSidebar, WorkbenchTableView };
5501
7055
  //# sourceMappingURL=index.mjs.map
5502
7056
  //# sourceMappingURL=index.mjs.map