@inf-monkeys-tech/monkeys-design 0.4.31 → 0.4.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ var React = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var ContextMenu = require('@radix-ui/react-context-menu');
6
6
  var DropdownMenu3 = require('@radix-ui/react-dropdown-menu');
7
+ var core = require('@dnd-kit/core');
7
8
  var Tooltip = require('@radix-ui/react-tooltip');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -4548,7 +4549,7 @@ var require_lodash = __commonJS({
4548
4549
  function valuesIn(object) {
4549
4550
  return object == null ? [] : baseValues(object, keysIn(object));
4550
4551
  }
4551
- function clamp3(number, lower, upper) {
4552
+ function clamp5(number, lower, upper) {
4552
4553
  if (upper === undefined2) {
4553
4554
  upper = lower;
4554
4555
  lower = undefined2;
@@ -5225,7 +5226,7 @@ var require_lodash = __commonJS({
5225
5226
  lodash.camelCase = camelCase;
5226
5227
  lodash.capitalize = capitalize;
5227
5228
  lodash.ceil = ceil;
5228
- lodash.clamp = clamp3;
5229
+ lodash.clamp = clamp5;
5229
5230
  lodash.clone = clone;
5230
5231
  lodash.cloneDeep = cloneDeep;
5231
5232
  lodash.cloneDeepWith = cloneDeepWith;
@@ -8580,7 +8581,41 @@ var baseSlots = {
8580
8581
  tableEmptyActions: "mt-4 flex flex-wrap items-center justify-center gap-2",
8581
8582
  tableLoadingRow: "border-b border-border/60",
8582
8583
  tableLoadingCell: "px-3 py-2",
8583
- tableLoadingSkeleton: "h-4 w-full rounded-md bg-muted/70"
8584
+ tableLoadingSkeleton: "h-4 w-full rounded-md bg-muted/70",
8585
+ layoutRoot: cn(
8586
+ "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",
8587
+ motionBase
8588
+ ),
8589
+ layoutRootFull: "h-full min-h-0",
8590
+ layoutHeader: "min-w-0",
8591
+ layoutBody: "grid min-h-0 min-w-0 overflow-hidden gap-3",
8592
+ layoutSidebar: "min-h-0 min-w-0 overflow-hidden",
8593
+ layoutMain: "min-h-0 min-w-0 overflow-hidden",
8594
+ layoutAside: "min-h-0 min-w-0 overflow-hidden",
8595
+ layoutFooter: "min-w-0",
8596
+ layoutPane: cn(
8597
+ "h-full max-h-full min-h-0 min-w-0 overflow-hidden rounded-lg bg-background text-foreground",
8598
+ motionBase
8599
+ ),
8600
+ layoutPaneScrollable: "overflow-auto",
8601
+ layoutPaneBordered: "border border-border/70",
8602
+ layoutPaneMuted: "bg-muted/25",
8603
+ layoutPaneSoft: "bg-background/95 shadow-sm",
8604
+ layoutPaneTransparent: "bg-transparent shadow-none",
8605
+ layoutSplitRoot: "grid min-h-0 min-w-0 overflow-hidden",
8606
+ layoutSplitHorizontal: "grid-flow-col",
8607
+ layoutSplitVertical: "grid-flow-row",
8608
+ layoutSplitPane: "min-h-0 min-w-0 overflow-hidden",
8609
+ layoutSplitPrimary: "",
8610
+ layoutSplitSecondary: "",
8611
+ layoutResizeHandle: cn(
8612
+ "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",
8613
+ motionInteractive
8614
+ ),
8615
+ layoutResizeHandleHorizontal: "w-2 cursor-col-resize",
8616
+ layoutResizeHandleVertical: "h-2 cursor-row-resize",
8617
+ layoutResizeHandleDisabled: "cursor-default opacity-60",
8618
+ layoutResizeHandleIndicator: "rounded-full bg-muted-foreground/45 group-hover/resize:bg-primary/70"
8584
8619
  };
8585
8620
  var densitySlots = {
8586
8621
  compact: {
@@ -8654,7 +8689,12 @@ var densitySlots = {
8654
8689
  tableCell: "px-2 py-1.5 text-xs",
8655
8690
  tableHeadLabel: "text-[11px]",
8656
8691
  tableHeadDescription: "text-[10px] leading-3",
8657
- tableLoadingCell: "px-2 py-1.5"
8692
+ tableLoadingCell: "px-2 py-1.5",
8693
+ layoutRoot: "gap-2 p-2",
8694
+ layoutBody: "gap-2",
8695
+ layoutPane: "rounded-md text-xs",
8696
+ layoutResizeHandleHorizontal: "w-1.5",
8697
+ layoutResizeHandleVertical: "h-1.5"
8658
8698
  },
8659
8699
  default: {
8660
8700
  buttonBase: "h-9"
@@ -8705,7 +8745,12 @@ var densitySlots = {
8705
8745
  menuSubTrigger: "min-h-9 px-3 py-2",
8706
8746
  tableHead: "h-12 px-4 py-3",
8707
8747
  tableCell: "px-4 py-3",
8708
- tableLoadingCell: "px-4 py-3"
8748
+ tableLoadingCell: "px-4 py-3",
8749
+ layoutRoot: "gap-4 p-4",
8750
+ layoutBody: "gap-4",
8751
+ layoutPane: "rounded-xl",
8752
+ layoutResizeHandleHorizontal: "w-2.5",
8753
+ layoutResizeHandleVertical: "h-2.5"
8709
8754
  }
8710
8755
  };
8711
8756
  var radiusSlots = {
@@ -8749,7 +8794,9 @@ var radiusSlots = {
8749
8794
  menuSubContent: "rounded-none",
8750
8795
  tableContainer: "rounded-none",
8751
8796
  tableEmptyIcon: "rounded-none",
8752
- tableLoadingSkeleton: "rounded-none"
8797
+ tableLoadingSkeleton: "rounded-none",
8798
+ layoutRoot: "rounded-none",
8799
+ layoutPane: "rounded-none"
8753
8800
  },
8754
8801
  sm: {
8755
8802
  buttonBase: "rounded-sm",
@@ -8791,7 +8838,9 @@ var radiusSlots = {
8791
8838
  menuSubContent: "rounded-sm",
8792
8839
  tableContainer: "rounded-sm",
8793
8840
  tableEmptyIcon: "rounded-sm",
8794
- tableLoadingSkeleton: "rounded-sm"
8841
+ tableLoadingSkeleton: "rounded-sm",
8842
+ layoutRoot: "rounded-sm",
8843
+ layoutPane: "rounded-sm"
8795
8844
  },
8796
8845
  md: {},
8797
8846
  lg: {
@@ -8828,7 +8877,9 @@ var radiusSlots = {
8828
8877
  menuSubContent: "rounded-lg",
8829
8878
  tableContainer: "rounded-xl",
8830
8879
  tableEmptyIcon: "rounded-xl",
8831
- tableLoadingSkeleton: "rounded-lg"
8880
+ tableLoadingSkeleton: "rounded-lg",
8881
+ layoutRoot: "rounded-xl",
8882
+ layoutPane: "rounded-xl"
8832
8883
  },
8833
8884
  xl: {
8834
8885
  buttonBase: "rounded-xl",
@@ -8866,7 +8917,9 @@ var radiusSlots = {
8866
8917
  menuSubContent: "rounded-xl",
8867
8918
  tableContainer: "rounded-2xl",
8868
8919
  tableEmptyIcon: "rounded-2xl",
8869
- tableLoadingSkeleton: "rounded-xl"
8920
+ tableLoadingSkeleton: "rounded-xl",
8921
+ layoutRoot: "rounded-2xl",
8922
+ layoutPane: "rounded-2xl"
8870
8923
  },
8871
8924
  full: {
8872
8925
  buttonBase: "rounded-full",
@@ -8908,7 +8961,9 @@ var radiusSlots = {
8908
8961
  menuSubContent: "rounded-2xl",
8909
8962
  tableContainer: "rounded-2xl",
8910
8963
  tableEmptyIcon: "rounded-full",
8911
- tableLoadingSkeleton: "rounded-full"
8964
+ tableLoadingSkeleton: "rounded-full",
8965
+ layoutRoot: "rounded-2xl",
8966
+ layoutPane: "rounded-2xl"
8912
8967
  }
8913
8968
  };
8914
8969
  var borderSlots = {
@@ -8950,7 +9005,10 @@ var borderSlots = {
8950
9005
  tableFooterBarAttached: "border-t border-transparent",
8951
9006
  tableRow: "border-transparent",
8952
9007
  tableEmptyRow: "border-transparent",
8953
- tableLoadingRow: "border-transparent"
9008
+ tableLoadingRow: "border-transparent",
9009
+ layoutRoot: "border-transparent",
9010
+ layoutPaneBordered: "border-transparent",
9011
+ layoutResizeHandle: "bg-transparent hover:bg-transparent active:bg-transparent focus-visible:bg-transparent"
8954
9012
  },
8955
9013
  subtle: {
8956
9014
  buttonDefault: "border-border/60",
@@ -8990,7 +9048,9 @@ var borderSlots = {
8990
9048
  tableFooterBarAttached: "border-t border-border/60",
8991
9049
  tableRow: "border-border/50",
8992
9050
  tableEmptyRow: "border-border/50",
8993
- tableLoadingRow: "border-border/50"
9051
+ tableLoadingRow: "border-border/50",
9052
+ layoutRoot: "border-border/60",
9053
+ layoutPaneBordered: "border-border/60"
8994
9054
  },
8995
9055
  solid: {},
8996
9056
  strong: {
@@ -9031,7 +9091,10 @@ var borderSlots = {
9031
9091
  tableFooterBarAttached: "border-t border-foreground/20",
9032
9092
  tableRow: "border-foreground/15",
9033
9093
  tableEmptyRow: "border-foreground/15",
9034
- tableLoadingRow: "border-foreground/15"
9094
+ tableLoadingRow: "border-foreground/15",
9095
+ layoutRoot: "border-foreground/20",
9096
+ layoutPaneBordered: "border-foreground/20",
9097
+ layoutResizeHandle: "hover:bg-foreground/15 active:bg-foreground/20 focus-visible:bg-foreground/15"
9035
9098
  }
9036
9099
  };
9037
9100
  var backgroundSlots = {
@@ -9073,7 +9136,11 @@ var backgroundSlots = {
9073
9136
  tableFooter: "bg-muted/35",
9074
9137
  tableFooterBar: "bg-muted/30 shadow-none",
9075
9138
  tableRowInteractive: "cursor-pointer hover:bg-muted/45",
9076
- tableLoadingSkeleton: "bg-muted"
9139
+ tableLoadingSkeleton: "bg-muted",
9140
+ layoutRoot: "bg-card",
9141
+ layoutPane: "bg-card",
9142
+ layoutPaneMuted: "bg-muted/35",
9143
+ layoutResizeHandle: "hover:bg-border/70 active:bg-border/80 focus-visible:bg-border/70"
9077
9144
  },
9078
9145
  soft: {
9079
9146
  buttonDefault: "bg-muted/30 hover:bg-muted/55",
@@ -9109,7 +9176,10 @@ var backgroundSlots = {
9109
9176
  tableFooter: "bg-muted/25",
9110
9177
  tableFooterBar: "bg-muted/25 shadow-none",
9111
9178
  tableRowInteractive: "cursor-pointer hover:bg-muted/35",
9112
- tableLoadingSkeleton: "bg-muted/65"
9179
+ tableLoadingSkeleton: "bg-muted/65",
9180
+ layoutRoot: "bg-background/95 shadow-sm",
9181
+ layoutPane: "bg-background/95 shadow-sm",
9182
+ layoutPaneSoft: "bg-background/95 shadow-md"
9113
9183
  },
9114
9184
  glass: {
9115
9185
  buttonBase: "backdrop-blur-md",
@@ -9170,7 +9240,13 @@ var backgroundSlots = {
9170
9240
  tableRow: "border-white/10",
9171
9241
  tableRowInteractive: "cursor-pointer hover:bg-white/[0.08]",
9172
9242
  tableHeadLabel: "text-foreground",
9173
- tableLoadingSkeleton: "bg-white/[0.16]"
9243
+ tableLoadingSkeleton: "bg-white/[0.16]",
9244
+ layoutRoot: "border-white/10 bg-white/[0.05] shadow-none backdrop-blur-md",
9245
+ layoutPane: "border-white/10 bg-white/[0.06] shadow-none backdrop-blur-md",
9246
+ layoutPaneMuted: "bg-white/[0.08]",
9247
+ layoutPaneSoft: "bg-white/[0.10] shadow-none backdrop-blur-md",
9248
+ layoutResizeHandle: "text-foreground/65 hover:bg-white/10 active:bg-white/15 focus-visible:bg-white/10",
9249
+ layoutResizeHandleIndicator: "bg-white/45 group-hover/resize:bg-white/75"
9174
9250
  },
9175
9251
  dark: {
9176
9252
  buttonBase: "border-white/15 text-white shadow-lg backdrop-blur",
@@ -9299,7 +9375,13 @@ var backgroundSlots = {
9299
9375
  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]",
9300
9376
  menuSubTriggerIcon: "text-white/55",
9301
9377
  menuSubContent: "border-white/10 bg-slate-950 text-white shadow-2xl",
9302
- tableLoadingSkeleton: "bg-white/[0.14]"
9378
+ tableLoadingSkeleton: "bg-white/[0.14]",
9379
+ layoutRoot: "border-white/10 bg-slate-950 text-white shadow-none",
9380
+ layoutPane: "border-white/10 bg-slate-950 text-white shadow-none",
9381
+ layoutPaneMuted: "bg-white/[0.06]",
9382
+ layoutPaneSoft: "bg-white/[0.08] shadow-none",
9383
+ layoutResizeHandle: "text-white/65 hover:bg-white/10 active:bg-white/15 focus-visible:bg-white/10",
9384
+ layoutResizeHandleIndicator: "bg-white/45 group-hover/resize:bg-white/75"
9303
9385
  }
9304
9386
  };
9305
9387
  var presetDefaults = {
@@ -11157,6 +11239,432 @@ var BaseInput = React.forwardRef(
11157
11239
  );
11158
11240
  }
11159
11241
  );
11242
+ var DEFAULT_SPLIT_SIZE = 50;
11243
+ var DEFAULT_MIN_SIZE = 20;
11244
+ var DEFAULT_MAX_SIZE = 80;
11245
+ var DEFAULT_KEYBOARD_STEP = 2.5;
11246
+ function toCssSize(value, fallback) {
11247
+ if (typeof value === "number") {
11248
+ if (!Number.isFinite(value) || value < 0) {
11249
+ throw new Error("BaseLayout size and gap props must be finite, non-negative numbers.");
11250
+ }
11251
+ return `${value}px`;
11252
+ }
11253
+ return value ?? fallback;
11254
+ }
11255
+ function assertPercent(name, value) {
11256
+ if (!Number.isFinite(value)) {
11257
+ throw new Error(`BaseLayoutSplit ${name} must be a finite number.`);
11258
+ }
11259
+ if (value < 0 || value > 100) {
11260
+ throw new Error(`BaseLayoutSplit ${name} must be between 0 and 100.`);
11261
+ }
11262
+ return value;
11263
+ }
11264
+ function clamp(value, min5, max5) {
11265
+ return Math.min(Math.max(value, min5), max5);
11266
+ }
11267
+ function resolveSplitBounds({
11268
+ minSize = DEFAULT_MIN_SIZE,
11269
+ maxSize = DEFAULT_MAX_SIZE,
11270
+ keyboardStep = DEFAULT_KEYBOARD_STEP
11271
+ }) {
11272
+ const min5 = assertPercent("minSize", minSize);
11273
+ const max5 = assertPercent("maxSize", maxSize);
11274
+ if (min5 > max5) {
11275
+ throw new Error("BaseLayoutSplit minSize cannot be greater than maxSize.");
11276
+ }
11277
+ if (!Number.isFinite(keyboardStep) || keyboardStep <= 0) {
11278
+ throw new Error("BaseLayoutSplit keyboardStep must be a finite positive number.");
11279
+ }
11280
+ return { min: min5, max: max5, keyboardStep };
11281
+ }
11282
+ function resolveSplitSize(name, value, fallback, min5, max5) {
11283
+ return clamp(assertPercent(name, value ?? fallback), min5, max5);
11284
+ }
11285
+ function getSeparatorOrientation(orientation) {
11286
+ return orientation === "horizontal" ? "vertical" : "horizontal";
11287
+ }
11288
+ function BaseLayout({
11289
+ header,
11290
+ sidebar,
11291
+ aside,
11292
+ footer,
11293
+ children,
11294
+ sidebarSize,
11295
+ asideSize,
11296
+ gap,
11297
+ fullHeight,
11298
+ appearance,
11299
+ className,
11300
+ classNames,
11301
+ style,
11302
+ ...layoutProps
11303
+ }) {
11304
+ const theme = resolveBaseAppearance(appearance);
11305
+ const hasHeader = hasRenderableNode(header);
11306
+ const hasSidebar = hasRenderableNode(sidebar);
11307
+ const hasAside = hasRenderableNode(aside);
11308
+ const hasFooter = hasRenderableNode(footer);
11309
+ const bodyColumns = [
11310
+ hasSidebar ? "var(--base-layout-sidebar-size)" : void 0,
11311
+ "minmax(0, 1fr)",
11312
+ hasAside ? "var(--base-layout-aside-size)" : void 0
11313
+ ].filter(Boolean).join(" ");
11314
+ const layoutRows = [
11315
+ hasHeader ? "auto" : void 0,
11316
+ "minmax(0, 1fr)",
11317
+ hasFooter ? "auto" : void 0
11318
+ ].filter(Boolean).join(" ");
11319
+ const resolvedGap = gap !== void 0 ? toCssSize(gap, "0px") : void 0;
11320
+ const layoutStyle = {
11321
+ ...theme.styles.layout,
11322
+ "--base-layout-sidebar-size": toCssSize(sidebarSize, "16rem"),
11323
+ "--base-layout-aside-size": toCssSize(asideSize, "20rem"),
11324
+ gridTemplateRows: layoutRows,
11325
+ ...resolvedGap !== void 0 ? { gap: resolvedGap } : {},
11326
+ ...style
11327
+ };
11328
+ const bodyStyle = {
11329
+ ...theme.styles.layoutBody,
11330
+ gridTemplateColumns: bodyColumns,
11331
+ ...resolvedGap !== void 0 ? { gap: resolvedGap } : {}
11332
+ };
11333
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11334
+ "div",
11335
+ {
11336
+ ...layoutProps,
11337
+ className: cn(
11338
+ theme.slots.layoutRoot,
11339
+ fullHeight && theme.slots.layoutRootFull,
11340
+ classNames?.root,
11341
+ className
11342
+ ),
11343
+ style: layoutStyle,
11344
+ children: [
11345
+ hasHeader ? /* @__PURE__ */ jsxRuntime.jsx(
11346
+ "div",
11347
+ {
11348
+ className: cn(theme.slots.layoutHeader, classNames?.header),
11349
+ style: theme.styles.layoutHeader,
11350
+ children: header
11351
+ }
11352
+ ) : null,
11353
+ /* @__PURE__ */ jsxRuntime.jsxs(
11354
+ "div",
11355
+ {
11356
+ className: cn(theme.slots.layoutBody, classNames?.body),
11357
+ style: bodyStyle,
11358
+ children: [
11359
+ hasSidebar ? /* @__PURE__ */ jsxRuntime.jsx(
11360
+ "aside",
11361
+ {
11362
+ className: cn(theme.slots.layoutSidebar, classNames?.sidebar),
11363
+ style: theme.styles.layoutSidebar,
11364
+ children: sidebar
11365
+ }
11366
+ ) : null,
11367
+ /* @__PURE__ */ jsxRuntime.jsx(
11368
+ "main",
11369
+ {
11370
+ className: cn(theme.slots.layoutMain, classNames?.main),
11371
+ style: theme.styles.layoutMain,
11372
+ children
11373
+ }
11374
+ ),
11375
+ hasAside ? /* @__PURE__ */ jsxRuntime.jsx(
11376
+ "aside",
11377
+ {
11378
+ className: cn(theme.slots.layoutAside, classNames?.aside),
11379
+ style: theme.styles.layoutAside,
11380
+ children: aside
11381
+ }
11382
+ ) : null
11383
+ ]
11384
+ }
11385
+ ),
11386
+ hasFooter ? /* @__PURE__ */ jsxRuntime.jsx(
11387
+ "div",
11388
+ {
11389
+ className: cn(theme.slots.layoutFooter, classNames?.footer),
11390
+ style: theme.styles.layoutFooter,
11391
+ children: footer
11392
+ }
11393
+ ) : null
11394
+ ]
11395
+ }
11396
+ );
11397
+ }
11398
+ function BaseLayoutPane({
11399
+ as = "div",
11400
+ scrollable = false,
11401
+ bordered = true,
11402
+ surface = "default",
11403
+ children,
11404
+ appearance,
11405
+ className,
11406
+ classNames,
11407
+ style,
11408
+ ...paneProps
11409
+ }) {
11410
+ const theme = resolveBaseAppearance(appearance);
11411
+ const Component = as;
11412
+ return /* @__PURE__ */ jsxRuntime.jsx(
11413
+ Component,
11414
+ {
11415
+ ...paneProps,
11416
+ className: cn(
11417
+ theme.slots.layoutPane,
11418
+ scrollable && theme.slots.layoutPaneScrollable,
11419
+ bordered && theme.slots.layoutPaneBordered,
11420
+ surface === "muted" && theme.slots.layoutPaneMuted,
11421
+ surface === "soft" && theme.slots.layoutPaneSoft,
11422
+ surface === "transparent" && theme.slots.layoutPaneTransparent,
11423
+ classNames?.root,
11424
+ className
11425
+ ),
11426
+ style: {
11427
+ ...theme.styles.layoutPane,
11428
+ ...style
11429
+ },
11430
+ children
11431
+ }
11432
+ );
11433
+ }
11434
+ function BaseLayoutResizeHandle({
11435
+ orientation = "horizontal",
11436
+ resizable = false,
11437
+ disabled = false,
11438
+ size,
11439
+ minSize,
11440
+ maxSize,
11441
+ label = "Resize panels",
11442
+ appearance,
11443
+ className,
11444
+ classNames,
11445
+ style,
11446
+ tabIndex,
11447
+ ...handleProps
11448
+ }) {
11449
+ const theme = resolveBaseAppearance(appearance);
11450
+ const interactive = resizable && !disabled;
11451
+ const separatorOrientation = getSeparatorOrientation(orientation);
11452
+ return /* @__PURE__ */ jsxRuntime.jsx(
11453
+ "div",
11454
+ {
11455
+ ...handleProps,
11456
+ role: interactive ? "separator" : void 0,
11457
+ "aria-label": interactive ? label : void 0,
11458
+ "aria-orientation": interactive ? separatorOrientation : void 0,
11459
+ "aria-valuemin": interactive ? minSize : void 0,
11460
+ "aria-valuemax": interactive ? maxSize : void 0,
11461
+ "aria-valuenow": interactive ? size : void 0,
11462
+ "aria-disabled": interactive ? void 0 : true,
11463
+ tabIndex: interactive ? tabIndex ?? 0 : void 0,
11464
+ className: cn(
11465
+ theme.slots.layoutResizeHandle,
11466
+ orientation === "horizontal" ? theme.slots.layoutResizeHandleHorizontal : theme.slots.layoutResizeHandleVertical,
11467
+ !interactive && theme.slots.layoutResizeHandleDisabled,
11468
+ classNames?.root,
11469
+ className
11470
+ ),
11471
+ style: {
11472
+ ...theme.styles.layoutResizeHandle,
11473
+ ...style
11474
+ },
11475
+ children: /* @__PURE__ */ jsxRuntime.jsx(
11476
+ "span",
11477
+ {
11478
+ "aria-hidden": "true",
11479
+ className: cn(
11480
+ theme.slots.layoutResizeHandleIndicator,
11481
+ orientation === "horizontal" ? "h-8 w-px" : "h-px w-8",
11482
+ classNames?.indicator
11483
+ )
11484
+ }
11485
+ )
11486
+ }
11487
+ );
11488
+ }
11489
+ function BaseLayoutSplit({
11490
+ orientation = "horizontal",
11491
+ primary,
11492
+ secondary,
11493
+ children,
11494
+ resizable = false,
11495
+ size,
11496
+ defaultSize,
11497
+ minSize,
11498
+ maxSize,
11499
+ gap,
11500
+ keyboardStep,
11501
+ resizeLabel,
11502
+ appearance,
11503
+ className,
11504
+ classNames,
11505
+ style,
11506
+ onSizeChange,
11507
+ ...splitProps
11508
+ }) {
11509
+ const theme = resolveBaseAppearance(appearance);
11510
+ const bounds = resolveSplitBounds({ minSize, maxSize, keyboardStep });
11511
+ const initialSize = resolveSplitSize(
11512
+ "defaultSize",
11513
+ defaultSize,
11514
+ DEFAULT_SPLIT_SIZE,
11515
+ bounds.min,
11516
+ bounds.max
11517
+ );
11518
+ const [uncontrolledSize, setUncontrolledSize] = React.useState(initialSize);
11519
+ const rootRef = React.useRef(null);
11520
+ const cleanupRef = React.useRef(null);
11521
+ const controlled = size !== void 0;
11522
+ const renderedSize = resolveSplitSize(
11523
+ "size",
11524
+ controlled ? size : uncontrolledSize,
11525
+ initialSize,
11526
+ bounds.min,
11527
+ bounds.max
11528
+ );
11529
+ const commitSize = React.useCallback(
11530
+ (nextSize) => {
11531
+ const clampedSize = clamp(nextSize, bounds.min, bounds.max);
11532
+ if (!controlled) {
11533
+ setUncontrolledSize(clampedSize);
11534
+ }
11535
+ onSizeChange?.(clampedSize);
11536
+ },
11537
+ [bounds.max, bounds.min, controlled, onSizeChange]
11538
+ );
11539
+ const updateFromPointer = React.useCallback(
11540
+ (event) => {
11541
+ const root = rootRef.current;
11542
+ if (!root) return;
11543
+ const rect = root.getBoundingClientRect();
11544
+ const total = orientation === "horizontal" ? rect.width : rect.height;
11545
+ if (total <= 0) return;
11546
+ const offset = orientation === "horizontal" ? event.clientX - rect.left : event.clientY - rect.top;
11547
+ commitSize(offset / total * 100);
11548
+ },
11549
+ [commitSize, orientation]
11550
+ );
11551
+ const stopResize = React.useCallback(() => {
11552
+ cleanupRef.current?.();
11553
+ cleanupRef.current = null;
11554
+ }, []);
11555
+ React.useEffect(() => stopResize, [stopResize]);
11556
+ const handlePointerDown = (event) => {
11557
+ if (!resizable) return;
11558
+ event.preventDefault();
11559
+ stopResize();
11560
+ updateFromPointer(event);
11561
+ const handleMove = (nextEvent) => {
11562
+ updateFromPointer(nextEvent);
11563
+ };
11564
+ const handleStop = () => {
11565
+ stopResize();
11566
+ };
11567
+ window.addEventListener("pointermove", handleMove);
11568
+ window.addEventListener("pointerup", handleStop, { once: true });
11569
+ window.addEventListener("pointercancel", handleStop, { once: true });
11570
+ cleanupRef.current = () => {
11571
+ window.removeEventListener("pointermove", handleMove);
11572
+ window.removeEventListener("pointerup", handleStop);
11573
+ window.removeEventListener("pointercancel", handleStop);
11574
+ };
11575
+ };
11576
+ const handleKeyDown = (event) => {
11577
+ if (!resizable) return;
11578
+ const step = event.shiftKey ? bounds.keyboardStep * 4 : bounds.keyboardStep;
11579
+ let nextSize;
11580
+ if (event.key === "Home") nextSize = bounds.min;
11581
+ if (event.key === "End") nextSize = bounds.max;
11582
+ if (orientation === "horizontal" && event.key === "ArrowLeft") {
11583
+ nextSize = renderedSize - step;
11584
+ }
11585
+ if (orientation === "horizontal" && event.key === "ArrowRight") {
11586
+ nextSize = renderedSize + step;
11587
+ }
11588
+ if (orientation === "vertical" && event.key === "ArrowUp") {
11589
+ nextSize = renderedSize - step;
11590
+ }
11591
+ if (orientation === "vertical" && event.key === "ArrowDown") {
11592
+ nextSize = renderedSize + step;
11593
+ }
11594
+ if (nextSize === void 0) return;
11595
+ event.preventDefault();
11596
+ commitSize(nextSize);
11597
+ };
11598
+ const resolvedGap = gap !== void 0 ? toCssSize(gap, "0px") : void 0;
11599
+ const resizeTrack = resolvedGap !== void 0 ? "var(--base-layout-split-gap)" : "auto";
11600
+ const resizeHandleStyle = resolvedGap !== void 0 ? orientation === "horizontal" ? { width: "var(--base-layout-split-gap)" } : { height: "var(--base-layout-split-gap)" } : void 0;
11601
+ const splitStyle = {
11602
+ ...theme.styles.layoutSplit,
11603
+ [orientation === "horizontal" ? "gridTemplateColumns" : "gridTemplateRows"]: resizable ? `${renderedSize}% ${resizeTrack} minmax(0, 1fr)` : `${renderedSize}% minmax(0, 1fr)`,
11604
+ ...resizable ? { gap: 0 } : {},
11605
+ ...resolvedGap !== void 0 ? {
11606
+ "--base-layout-split-gap": resolvedGap,
11607
+ ...resizable ? {} : { gap: resolvedGap }
11608
+ } : {},
11609
+ ...style
11610
+ };
11611
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11612
+ "div",
11613
+ {
11614
+ ...splitProps,
11615
+ ref: rootRef,
11616
+ className: cn(
11617
+ theme.slots.layoutSplitRoot,
11618
+ orientation === "horizontal" ? theme.slots.layoutSplitHorizontal : theme.slots.layoutSplitVertical,
11619
+ classNames?.root,
11620
+ className
11621
+ ),
11622
+ style: splitStyle,
11623
+ children: [
11624
+ /* @__PURE__ */ jsxRuntime.jsx(
11625
+ "div",
11626
+ {
11627
+ className: cn(
11628
+ theme.slots.layoutSplitPane,
11629
+ theme.slots.layoutSplitPrimary,
11630
+ classNames?.primary
11631
+ ),
11632
+ style: theme.styles.layoutSplitPane,
11633
+ children: hasRenderableNode(primary) ? primary : children
11634
+ }
11635
+ ),
11636
+ resizable ? /* @__PURE__ */ jsxRuntime.jsx(
11637
+ BaseLayoutResizeHandle,
11638
+ {
11639
+ orientation,
11640
+ resizable: true,
11641
+ size: renderedSize,
11642
+ minSize: bounds.min,
11643
+ maxSize: bounds.max,
11644
+ label: resizeLabel,
11645
+ appearance,
11646
+ className: classNames?.handle,
11647
+ style: resizeHandleStyle,
11648
+ onPointerDown: handlePointerDown,
11649
+ onKeyDown: handleKeyDown
11650
+ }
11651
+ ) : null,
11652
+ /* @__PURE__ */ jsxRuntime.jsx(
11653
+ "div",
11654
+ {
11655
+ className: cn(
11656
+ theme.slots.layoutSplitPane,
11657
+ theme.slots.layoutSplitSecondary,
11658
+ classNames?.secondary
11659
+ ),
11660
+ style: theme.styles.layoutSplitPane,
11661
+ children: secondary
11662
+ }
11663
+ )
11664
+ ]
11665
+ }
11666
+ );
11667
+ }
11160
11668
  function DefaultLoadingIcon({ className }) {
11161
11669
  return /* @__PURE__ */ jsxRuntime.jsxs(
11162
11670
  "svg",
@@ -11446,7 +11954,7 @@ function BasePagination({
11446
11954
  function toFiniteNumber(value, fallback) {
11447
11955
  return Number.isFinite(value) ? Number(value) : fallback;
11448
11956
  }
11449
- function clamp(value, min5, max5) {
11957
+ function clamp2(value, min5, max5) {
11450
11958
  return Math.min(Math.max(value, min5), max5);
11451
11959
  }
11452
11960
  function BaseProgress({
@@ -11464,7 +11972,7 @@ function BaseProgress({
11464
11972
  }) {
11465
11973
  const theme = resolveBaseAppearance(appearance);
11466
11974
  const safeMax = Math.max(toFiniteNumber(max5, 100), 1);
11467
- const safeValue = clamp(toFiniteNumber(value, 0), 0, safeMax);
11975
+ const safeValue = clamp2(toFiniteNumber(value, 0), 0, safeMax);
11468
11976
  const percent = safeValue / safeMax * 100;
11469
11977
  const renderedValue = valueFormatter?.(safeValue, safeMax) ?? `${Math.round(percent)}%`;
11470
11978
  const hasLabelRow = hasRenderableNode(label) || showValue;
@@ -12230,7 +12738,7 @@ function useBaseTableContext(appearance) {
12230
12738
  }
12231
12739
  };
12232
12740
  }
12233
- function toCssSize(value) {
12741
+ function toCssSize2(value) {
12234
12742
  if (value === void 0) return void 0;
12235
12743
  return typeof value === "number" ? `${value}px` : value;
12236
12744
  }
@@ -12443,7 +12951,7 @@ function BaseTableRow({
12443
12951
  }
12444
12952
  );
12445
12953
  }
12446
- function BaseTableHead({
12954
+ var BaseTableHead = React.forwardRef(function BaseTableHead2({
12447
12955
  columnId,
12448
12956
  align = "left",
12449
12957
  icon,
@@ -12471,10 +12979,18 @@ function BaseTableHead({
12471
12979
  onDragOver,
12472
12980
  onDrop,
12473
12981
  ...headProps
12474
- }) {
12982
+ }, forwardedRef) {
12475
12983
  const tableContext = useBaseTableContext(appearance);
12476
12984
  const { theme } = tableContext;
12477
12985
  const headRef = React.useRef(null);
12986
+ const setHeadRef = (node) => {
12987
+ headRef.current = node;
12988
+ if (typeof forwardedRef === "function") {
12989
+ forwardedRef(node);
12990
+ } else if (forwardedRef) {
12991
+ forwardedRef.current = node;
12992
+ }
12993
+ };
12478
12994
  const controlledWidth = columnId && tableContext.columnSizes?.[columnId] !== void 0 ? tableContext.columnSizes[columnId] : width;
12479
12995
  const canDrag = Boolean(
12480
12996
  columnId && draggable !== false && (draggable || tableContext.columnDragEnabled) && tableContext.columnOrder && tableContext.onColumnOrderChange
@@ -12629,7 +13145,7 @@ function BaseTableHead({
12629
13145
  "th",
12630
13146
  {
12631
13147
  ...headProps,
12632
- ref: headRef,
13148
+ ref: setHeadRef,
12633
13149
  scope: headProps.scope ?? "col",
12634
13150
  "aria-sort": ariaSort,
12635
13151
  className: cn(
@@ -12641,9 +13157,9 @@ function BaseTableHead({
12641
13157
  ),
12642
13158
  style: {
12643
13159
  ...theme.styles.tableHead,
12644
- width: toCssSize(controlledWidth),
12645
- minWidth: toCssSize(minWidth),
12646
- maxWidth: toCssSize(maxWidth),
13160
+ width: toCssSize2(controlledWidth),
13161
+ minWidth: toCssSize2(minWidth),
13162
+ maxWidth: toCssSize2(maxWidth),
12647
13163
  ...style
12648
13164
  },
12649
13165
  onDragOver: handleDragOver,
@@ -12664,7 +13180,7 @@ function BaseTableHead({
12664
13180
  ]
12665
13181
  }
12666
13182
  );
12667
- }
13183
+ });
12668
13184
  function BaseTableCell({
12669
13185
  align = "left",
12670
13186
  appearance,
@@ -12792,7 +13308,7 @@ function BaseTableLoading({
12792
13308
  classNames?.skeleton
12793
13309
  ),
12794
13310
  style: {
12795
- width: toCssSize(columnWidths[columnIndex])
13311
+ width: toCssSize2(columnWidths[columnIndex])
12796
13312
  }
12797
13313
  }
12798
13314
  )
@@ -15807,7 +16323,7 @@ var DEFAULT_ZOOM_STEP = 1.18;
15807
16323
  var DEFAULT_STAGE_PADDING = 16;
15808
16324
  var MAX_SAFE_SCALE = 1e6;
15809
16325
  var MIN_SAFE_SCALE = 1e-6;
15810
- var clamp2 = (value, min5, max5) => Math.min(max5, Math.max(min5, value));
16326
+ var clamp3 = (value, min5, max5) => Math.min(max5, Math.max(min5, value));
15811
16327
  var isNoDragTarget = (target) => target instanceof Element && Boolean(target.closest('[data-no-drag="true"]'));
15812
16328
  function ResetIcon() {
15813
16329
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -15931,7 +16447,7 @@ function DataExplorerImagePreview({
15931
16447
  availableWidth / size.width,
15932
16448
  availableHeight / size.height
15933
16449
  );
15934
- const nextScale = clamp2(
16450
+ const nextScale = clamp3(
15935
16451
  fitScale,
15936
16452
  normalizedMinScale,
15937
16453
  normalizedMaxScale
@@ -15985,7 +16501,7 @@ function DataExplorerImagePreview({
15985
16501
  if (!Number.isFinite(factor) || factor === 1) return;
15986
16502
  if (!Number.isFinite(stageX) || !Number.isFinite(stageY)) return;
15987
16503
  setView((current) => {
15988
- const nextScale = clamp2(
16504
+ const nextScale = clamp3(
15989
16505
  current.scale * factor,
15990
16506
  normalizedMinScale,
15991
16507
  normalizedMaxScale
@@ -19996,6 +20512,3637 @@ function AppLayout({ header, sidebar, children, flush = false, className }) {
19996
20512
  ] })
19997
20513
  ] });
19998
20514
  }
20515
+ function ClampIcon({ expanded }) {
20516
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 20 20", className: "h-4 w-4", fill: "none", children: [
20517
+ /* @__PURE__ */ jsxRuntime.jsx(
20518
+ "path",
20519
+ {
20520
+ d: "M4 4.5h12M4 15.5h12M7.5 7.5 5 10l2.5 2.5M12.5 7.5 15 10l-2.5 2.5",
20521
+ stroke: "currentColor",
20522
+ strokeWidth: "1.6",
20523
+ strokeLinecap: "round",
20524
+ strokeLinejoin: "round",
20525
+ className: expanded ? "" : "hidden"
20526
+ }
20527
+ ),
20528
+ /* @__PURE__ */ jsxRuntime.jsx(
20529
+ "path",
20530
+ {
20531
+ d: "M4 4.5h12M4 15.5h12M5 7.5 7.5 10 5 12.5M15 7.5 12.5 10l2.5 2.5",
20532
+ stroke: "currentColor",
20533
+ strokeWidth: "1.6",
20534
+ strokeLinecap: "round",
20535
+ strokeLinejoin: "round",
20536
+ className: expanded ? "hidden" : ""
20537
+ }
20538
+ )
20539
+ ] });
20540
+ }
20541
+ function ResizeGripIcon() {
20542
+ return /* @__PURE__ */ jsxRuntime.jsx(
20543
+ "span",
20544
+ {
20545
+ "aria-hidden": "true",
20546
+ className: "pointer-events-none absolute right-1/2 top-3 bottom-3 w-px translate-x-1/2 rounded-full bg-border/65 opacity-0 transition-opacity group-hover/resize:opacity-100"
20547
+ }
20548
+ );
20549
+ }
20550
+ function getItemTitle(item) {
20551
+ if (item.title) return item.title;
20552
+ return typeof item.label === "string" ? item.label : void 0;
20553
+ }
20554
+ function clampWidth2(width, minWidth, maxWidth) {
20555
+ return Math.min(Math.max(width, minWidth), maxWidth);
20556
+ }
20557
+ function assignRef(ref, node) {
20558
+ if (typeof ref === "function") {
20559
+ ref(node);
20560
+ } else if (ref) {
20561
+ ref.current = node;
20562
+ }
20563
+ }
20564
+ function readStoredLayout(storageKey, options) {
20565
+ const fallback = {
20566
+ collapsed: options.defaultCollapsed,
20567
+ width: clampWidth2(options.defaultWidth, options.minWidth, options.maxWidth)
20568
+ };
20569
+ if (typeof window === "undefined" || !storageKey) return fallback;
20570
+ try {
20571
+ const rawValue = window.localStorage.getItem(storageKey);
20572
+ if (!rawValue) return fallback;
20573
+ const parsedValue = JSON.parse(rawValue);
20574
+ return {
20575
+ collapsed: typeof parsedValue.collapsed === "boolean" ? parsedValue.collapsed : fallback.collapsed,
20576
+ width: typeof parsedValue.width === "number" && Number.isFinite(parsedValue.width) ? clampWidth2(parsedValue.width, options.minWidth, options.maxWidth) : fallback.width
20577
+ };
20578
+ } catch {
20579
+ return fallback;
20580
+ }
20581
+ }
20582
+ var WorkbenchResizableSidebar = React.forwardRef(
20583
+ function WorkbenchResizableSidebar2({
20584
+ title,
20585
+ items,
20586
+ activeItemId,
20587
+ itemAs,
20588
+ collapsed,
20589
+ defaultCollapsed = false,
20590
+ onCollapsedChange,
20591
+ width,
20592
+ onWidthChange,
20593
+ defaultWidth = 220,
20594
+ minWidth = 180,
20595
+ maxWidth = 420,
20596
+ collapsedWidth = 60,
20597
+ collapseThreshold = 140,
20598
+ storageKey,
20599
+ resizable = true,
20600
+ collapsible = true,
20601
+ collapseLabel = "Collapse sidebar",
20602
+ expandLabel = "Expand sidebar",
20603
+ resizeLabel = "Resize sidebar",
20604
+ desktopClassName = "hidden md:flex",
20605
+ mobileClassName = "flex md:hidden",
20606
+ className,
20607
+ classNames,
20608
+ style
20609
+ }, ref) {
20610
+ const initialLayoutRef = React.useRef(null);
20611
+ if (!initialLayoutRef.current) {
20612
+ initialLayoutRef.current = readStoredLayout(storageKey, {
20613
+ defaultCollapsed,
20614
+ defaultWidth,
20615
+ minWidth,
20616
+ maxWidth
20617
+ });
20618
+ }
20619
+ const sidebarRef = React.useRef(null);
20620
+ const [internalCollapsed, setInternalCollapsed] = React.useState(initialLayoutRef.current.collapsed);
20621
+ const [internalWidth, setInternalWidth] = React.useState(initialLayoutRef.current.width);
20622
+ const [isResizing, setIsResizing] = React.useState(false);
20623
+ const resolvedCollapsed = collapsed ?? internalCollapsed;
20624
+ const resolvedWidth = width ?? internalWidth;
20625
+ const isCollapsedControlled = collapsed !== void 0;
20626
+ const isWidthControlled = width !== void 0;
20627
+ const setSidebarRef = (node) => {
20628
+ sidebarRef.current = node;
20629
+ assignRef(ref, node);
20630
+ };
20631
+ const updateCollapsed = (nextCollapsed) => {
20632
+ if (!collapsible && nextCollapsed) return;
20633
+ if (!isCollapsedControlled) {
20634
+ setInternalCollapsed(nextCollapsed);
20635
+ }
20636
+ onCollapsedChange?.(nextCollapsed);
20637
+ };
20638
+ const updateWidth = (nextWidth) => {
20639
+ const clampedWidth = clampWidth2(nextWidth, minWidth, maxWidth);
20640
+ if (!isWidthControlled) {
20641
+ setInternalWidth(clampedWidth);
20642
+ }
20643
+ onWidthChange?.(clampedWidth);
20644
+ };
20645
+ const startResize = (event) => {
20646
+ if (!resizable) return;
20647
+ event.preventDefault();
20648
+ setIsResizing(true);
20649
+ };
20650
+ const handleResizeKeyDown = (event) => {
20651
+ if (!resizable) return;
20652
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
20653
+ event.preventDefault();
20654
+ if (event.key === "ArrowLeft") {
20655
+ const nextWidth = resolvedWidth - 24;
20656
+ if (nextWidth < collapseThreshold && collapsible) {
20657
+ updateCollapsed(true);
20658
+ return;
20659
+ }
20660
+ updateWidth(nextWidth);
20661
+ } else {
20662
+ if (resolvedCollapsed) {
20663
+ updateCollapsed(false);
20664
+ updateWidth(Math.max(resolvedWidth, minWidth));
20665
+ return;
20666
+ }
20667
+ updateWidth(resolvedWidth + 24);
20668
+ }
20669
+ };
20670
+ React.useEffect(() => {
20671
+ if (typeof window === "undefined" || !storageKey) return;
20672
+ window.localStorage.setItem(storageKey, JSON.stringify({
20673
+ collapsed: resolvedCollapsed,
20674
+ width: clampWidth2(resolvedWidth, minWidth, maxWidth)
20675
+ }));
20676
+ }, [maxWidth, minWidth, resolvedCollapsed, resolvedWidth, storageKey]);
20677
+ React.useEffect(() => {
20678
+ if (!isResizing) return void 0;
20679
+ const handlePointerMove = (event) => {
20680
+ const sidebarNode = sidebarRef.current;
20681
+ if (!sidebarNode) return;
20682
+ const nextWidth = event.clientX - sidebarNode.getBoundingClientRect().left;
20683
+ if (nextWidth < collapseThreshold && collapsible) {
20684
+ updateCollapsed(true);
20685
+ return;
20686
+ }
20687
+ updateCollapsed(false);
20688
+ updateWidth(nextWidth);
20689
+ };
20690
+ const handlePointerUp = () => setIsResizing(false);
20691
+ window.addEventListener("pointermove", handlePointerMove);
20692
+ window.addEventListener("pointerup", handlePointerUp);
20693
+ document.body.style.cursor = "col-resize";
20694
+ document.body.style.userSelect = "none";
20695
+ return () => {
20696
+ window.removeEventListener("pointermove", handlePointerMove);
20697
+ window.removeEventListener("pointerup", handlePointerUp);
20698
+ document.body.style.cursor = "";
20699
+ document.body.style.userSelect = "";
20700
+ };
20701
+ }, [collapseThreshold, collapsible, isResizing, maxWidth, minWidth, resolvedWidth, resolvedCollapsed]);
20702
+ const renderItem = (item, mobile = false) => {
20703
+ const active = item.active ?? item.id === activeItemId;
20704
+ const ItemComponent = itemAs ?? (item.href ? "a" : "button");
20705
+ const itemTitle = getItemTitle(item);
20706
+ const itemProps = {
20707
+ ...item.to ? { to: item.to } : {},
20708
+ ...item.href ? { href: item.href } : {},
20709
+ ...ItemComponent === "button" ? { type: "button" } : {},
20710
+ title: itemTitle,
20711
+ "aria-current": active ? "page" : void 0,
20712
+ "aria-disabled": item.disabled || void 0,
20713
+ tabIndex: item.disabled ? -1 : void 0,
20714
+ onClick: (event) => {
20715
+ if (item.disabled) {
20716
+ event.preventDefault();
20717
+ return;
20718
+ }
20719
+ item.onClick?.(event);
20720
+ }
20721
+ };
20722
+ return /* @__PURE__ */ jsxRuntime.jsxs(
20723
+ ItemComponent,
20724
+ {
20725
+ ...itemProps,
20726
+ "data-active": active ? "true" : "false",
20727
+ className: cn(
20728
+ mobile ? "inline-flex h-9 shrink-0 items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors" : "relative flex h-9 w-full items-center justify-between gap-2 overflow-hidden rounded-md border px-2 text-left text-[12px] shadow-none transition-colors",
20729
+ mobile ? active ? "border-primary/40 bg-primary/12 text-foreground" : "border-border/60 bg-card/60 text-muted-foreground hover:bg-card/80 hover:text-foreground" : active ? "border-primary/40 bg-primary/12 text-foreground shadow-sm" : "border-border/60 bg-card/60 text-foreground hover:border-primary/20 hover:bg-card/80",
20730
+ !mobile && resolvedCollapsed && "justify-center px-0",
20731
+ item.disabled && "pointer-events-none opacity-50",
20732
+ mobile ? classNames?.mobileItem : classNames?.item,
20733
+ item.className
20734
+ ),
20735
+ children: [
20736
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("inline-flex h-4 w-4 shrink-0 items-center justify-center [&_svg]:h-3.5 [&_svg]:w-3.5", classNames?.itemIcon), children: item.icon }),
20737
+ mobile || !resolvedCollapsed ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("min-w-0 flex-1 truncate", classNames?.itemLabel), children: item.label }) : null,
20738
+ !mobile && !resolvedCollapsed && item.endContent ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: item.endContent }) : null
20739
+ ]
20740
+ },
20741
+ item.id
20742
+ );
20743
+ };
20744
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20745
+ /* @__PURE__ */ jsxRuntime.jsxs(
20746
+ "aside",
20747
+ {
20748
+ ref: setSidebarRef,
20749
+ "data-workbench-resizable-sidebar": true,
20750
+ "data-collapsed": resolvedCollapsed ? "true" : "false",
20751
+ className: cn(
20752
+ "relative z-20 h-full min-h-0 flex-shrink-0 flex-col rounded-xl border border-border/70 bg-card p-3 text-card-foreground shadow-sm",
20753
+ "transition-[width,opacity] duration-300",
20754
+ resolvedCollapsed && "items-center",
20755
+ desktopClassName,
20756
+ classNames?.root,
20757
+ className
20758
+ ),
20759
+ style: {
20760
+ width: resolvedCollapsed ? collapsedWidth : resolvedWidth,
20761
+ transition: isResizing ? "none" : void 0,
20762
+ ...style
20763
+ },
20764
+ children: [
20765
+ resizable ? /* @__PURE__ */ jsxRuntime.jsx(
20766
+ "button",
20767
+ {
20768
+ type: "button",
20769
+ "aria-label": resizeLabel,
20770
+ title: resizeLabel,
20771
+ className: cn("group/resize absolute -right-1.5 bottom-0 top-0 z-50 w-3 cursor-col-resize bg-transparent outline-none focus-visible:ring-2 focus-visible:ring-primary/30", classNames?.resizeHandle),
20772
+ onPointerDown: startResize,
20773
+ onKeyDown: handleResizeKeyDown,
20774
+ children: /* @__PURE__ */ jsxRuntime.jsx(ResizeGripIcon, {})
20775
+ }
20776
+ ) : null,
20777
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full min-w-0 flex-col overflow-visible", children: [
20778
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mb-3 flex min-w-0 items-center gap-2", resolvedCollapsed ? "justify-center px-0" : "justify-between px-2", classNames?.header), children: [
20779
+ !resolvedCollapsed && title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("min-w-0 truncate text-[11px] font-medium uppercase text-muted-foreground", classNames?.title), children: title }) : null,
20780
+ collapsible ? /* @__PURE__ */ jsxRuntime.jsx(
20781
+ "button",
20782
+ {
20783
+ type: "button",
20784
+ className: cn("inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30", classNames?.collapseButton),
20785
+ "aria-label": resolvedCollapsed ? expandLabel : collapseLabel,
20786
+ title: resolvedCollapsed ? expandLabel : collapseLabel,
20787
+ onClick: () => updateCollapsed(!resolvedCollapsed),
20788
+ children: /* @__PURE__ */ jsxRuntime.jsx(ClampIcon, { expanded: !resolvedCollapsed })
20789
+ }
20790
+ ) : null
20791
+ ] }),
20792
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("min-h-0 flex-1 space-y-2 overflow-y-auto", resolvedCollapsed && "flex w-full flex-col items-center", classNames?.list), children: items.map((item) => renderItem(item)) })
20793
+ ] })
20794
+ ]
20795
+ }
20796
+ ),
20797
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { className: cn("gap-2 overflow-x-auto pb-1", mobileClassName, classNames?.mobileNav), "aria-label": typeof title === "string" ? title : void 0, children: items.map((item) => renderItem(item, true)) })
20798
+ ] });
20799
+ }
20800
+ );
20801
+ function shouldRenderBodyWrapper(props) {
20802
+ return Boolean(
20803
+ props.header || props.footer || props.bodyAs || props.bodyClassName || props.bodyProps || props.classNames?.body
20804
+ );
20805
+ }
20806
+ var WorkbenchContentPane = React.forwardRef(
20807
+ function WorkbenchContentPane2({
20808
+ as: Component = "section",
20809
+ bodyAs: BodyComponent = "div",
20810
+ header,
20811
+ footer,
20812
+ children,
20813
+ className,
20814
+ headerClassName,
20815
+ bodyClassName,
20816
+ footerClassName,
20817
+ bodyProps,
20818
+ classNames,
20819
+ style,
20820
+ ...props
20821
+ }, ref) {
20822
+ const renderBodyWrapper = shouldRenderBodyWrapper({
20823
+ header,
20824
+ footer,
20825
+ bodyAs: BodyComponent === "div" ? void 0 : BodyComponent,
20826
+ bodyClassName,
20827
+ bodyProps,
20828
+ classNames
20829
+ });
20830
+ const { className: bodyPropsClassName, ...restBodyProps } = bodyProps ?? {};
20831
+ return /* @__PURE__ */ jsxRuntime.jsxs(
20832
+ Component,
20833
+ {
20834
+ ref,
20835
+ "data-workbench-content-pane": true,
20836
+ className: cn(
20837
+ "workbench-surface-subtle flex h-full min-w-0 flex-1 flex-col overflow-hidden rounded-xl border border-border/50 transition-all duration-300 dark:border-border/40",
20838
+ classNames?.root,
20839
+ className
20840
+ ),
20841
+ style,
20842
+ ...props,
20843
+ children: [
20844
+ header ? /* @__PURE__ */ jsxRuntime.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,
20845
+ renderBodyWrapper ? /* @__PURE__ */ jsxRuntime.jsx(
20846
+ BodyComponent,
20847
+ {
20848
+ className: cn("min-h-0 flex-1 overflow-hidden", classNames?.body, bodyClassName, bodyPropsClassName),
20849
+ ...restBodyProps,
20850
+ children
20851
+ }
20852
+ ) : children,
20853
+ footer ? /* @__PURE__ */ jsxRuntime.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
20854
+ ]
20855
+ }
20856
+ );
20857
+ }
20858
+ );
20859
+ var defaultLabels = {
20860
+ settingsButton: "Gallery settings",
20861
+ title: "Gallery settings",
20862
+ visibleColumns: "Visible fields",
20863
+ coverField: "Cover field",
20864
+ autoDetect: "Auto",
20865
+ cardDensity: "Card density",
20866
+ cardColumns: "Cards per row",
20867
+ detailColumns: "Detail columns",
20868
+ fieldVisibility: "Field visibility",
20869
+ fieldLimit: "Field limit",
20870
+ fieldLimitHint: "Uses current field order",
20871
+ layout: "Gallery layout",
20872
+ compact: "Compact",
20873
+ comfortable: "Standard",
20874
+ detailed: "Detailed",
20875
+ autoColumns: "Auto",
20876
+ columns: (count) => `${count}`,
20877
+ bentoColumns: (count) => `${count}`,
20878
+ topLimit: "First fields",
20879
+ allFields: "All fields",
20880
+ adaptiveGrid: "Grid",
20881
+ masonry: "Masonry"
20882
+ };
20883
+ function normalizeColumnKey(column) {
20884
+ return String(column?.key || "");
20885
+ }
20886
+ function getDefaultColumnLabel(column) {
20887
+ return column.label ?? column.key;
20888
+ }
20889
+ function getDefaultVisibleColumnKeys(columns) {
20890
+ return columns.filter((column) => normalizeColumnKey(column) && column.hidden !== true).map((column) => normalizeColumnKey(column));
20891
+ }
20892
+ function getResolvedVisibleColumnKeys({
20893
+ columns,
20894
+ visibleColumnKeys,
20895
+ allowEmptyVisibleColumns
20896
+ }) {
20897
+ const validKeys = new Set(columns.map(normalizeColumnKey).filter(Boolean));
20898
+ const controlledKeys = Array.isArray(visibleColumnKeys) ? visibleColumnKeys.filter((key) => validKeys.has(String(key))) : null;
20899
+ if (controlledKeys && (controlledKeys.length || allowEmptyVisibleColumns)) {
20900
+ return controlledKeys;
20901
+ }
20902
+ return getDefaultVisibleColumnKeys(columns);
20903
+ }
20904
+ function getDefaultDensityOptions(labels) {
20905
+ return [
20906
+ { value: "compact", label: labels.compact },
20907
+ { value: "comfortable", label: labels.comfortable },
20908
+ { value: "detailed", label: labels.detailed }
20909
+ ];
20910
+ }
20911
+ function getDefaultGridColumnOptions(labels) {
20912
+ return [
20913
+ { value: "auto", label: labels.autoColumns },
20914
+ { value: 1, label: labels.columns(1) },
20915
+ { value: 2, label: labels.columns(2) },
20916
+ { value: 3, label: labels.columns(3) },
20917
+ { value: 4, label: labels.columns(4) }
20918
+ ];
20919
+ }
20920
+ function getDefaultBentoColumnOptions(labels) {
20921
+ return [
20922
+ { value: 1, label: labels.bentoColumns(1) },
20923
+ { value: 2, label: labels.bentoColumns(2) },
20924
+ { value: 3, label: labels.bentoColumns(3) }
20925
+ ];
20926
+ }
20927
+ function getDefaultDetailVisibilityOptions(labels) {
20928
+ return [
20929
+ { value: "limit", label: labels.topLimit },
20930
+ { value: "all", label: labels.allFields }
20931
+ ];
20932
+ }
20933
+ function getDefaultLayoutOptions(labels) {
20934
+ return [
20935
+ { value: "fixed", label: labels.adaptiveGrid },
20936
+ { value: "masonry", label: labels.masonry }
20937
+ ];
20938
+ }
20939
+ function normalizeOptionValue(value) {
20940
+ return String(value);
20941
+ }
20942
+ function getOptionValue(options, rawValue, fallbackValue) {
20943
+ const valueText = String(rawValue ?? fallbackValue);
20944
+ return options.some((option) => String(option.value) === valueText) ? valueText : String(fallbackValue);
20945
+ }
20946
+ function parseNumberOption(value) {
20947
+ const parsed = Number.parseInt(value, 10);
20948
+ return Number.isFinite(parsed) ? parsed : 1;
20949
+ }
20950
+ var compactSegmentedClassNames = {
20951
+ root: "flex w-full flex-wrap",
20952
+ item: "min-w-[58px] flex-1 px-2 text-[11px]",
20953
+ label: "text-[11px]"
20954
+ };
20955
+ function WorkbenchGallerySettingsPanel({
20956
+ columns = [],
20957
+ galleryFieldOptions,
20958
+ value,
20959
+ onValueChange,
20960
+ labels,
20961
+ densityOptions,
20962
+ gridColumnOptions,
20963
+ bentoColumnOptions,
20964
+ detailVisibilityOptions,
20965
+ layoutOptions,
20966
+ getColumnLabel = getDefaultColumnLabel,
20967
+ getColumnDescription,
20968
+ showColumnVisibility = true,
20969
+ showGalleryControls = true,
20970
+ showLayoutControl = true,
20971
+ showGridColumns = true,
20972
+ showDetailColumns = true,
20973
+ allowEmptyVisibleColumns = false,
20974
+ className,
20975
+ classNames
20976
+ }) {
20977
+ const resolvedLabels = { ...defaultLabels, ...labels };
20978
+ const resolvedValue = value || {};
20979
+ const resolvedColumns = columns.filter((column) => normalizeColumnKey(column));
20980
+ const resolvedVisibleColumnKeys = getResolvedVisibleColumnKeys({
20981
+ columns: resolvedColumns,
20982
+ visibleColumnKeys: resolvedValue.visibleColumnKeys,
20983
+ allowEmptyVisibleColumns
20984
+ });
20985
+ const visibleColumnKeySet = new Set(resolvedVisibleColumnKeys);
20986
+ const resolvedGalleryFieldOptions = (galleryFieldOptions || resolvedColumns).filter((column) => normalizeColumnKey(column));
20987
+ const resolvedDensityOptions = densityOptions || getDefaultDensityOptions(resolvedLabels);
20988
+ const resolvedGridColumnOptions = gridColumnOptions || getDefaultGridColumnOptions(resolvedLabels);
20989
+ const resolvedBentoColumnOptions = bentoColumnOptions || getDefaultBentoColumnOptions(resolvedLabels);
20990
+ const resolvedDetailVisibilityOptions = detailVisibilityOptions || getDefaultDetailVisibilityOptions(resolvedLabels);
20991
+ const resolvedLayoutOptions = layoutOptions || getDefaultLayoutOptions(resolvedLabels);
20992
+ const canUpdate = typeof onValueChange === "function";
20993
+ const updateValue = (patch) => {
20994
+ onValueChange?.({ ...resolvedValue, ...patch }, patch);
20995
+ };
20996
+ const toggleColumn = (columnKey) => {
20997
+ if (!canUpdate) return;
20998
+ const nextVisibleSet = new Set(resolvedVisibleColumnKeys);
20999
+ if (nextVisibleSet.has(columnKey)) {
21000
+ nextVisibleSet.delete(columnKey);
21001
+ } else {
21002
+ nextVisibleSet.add(columnKey);
21003
+ }
21004
+ let nextVisibleColumnKeys = resolvedColumns.map(normalizeColumnKey).filter((key) => nextVisibleSet.has(key));
21005
+ if (!nextVisibleColumnKeys.length && !allowEmptyVisibleColumns) {
21006
+ nextVisibleColumnKeys = [columnKey];
21007
+ }
21008
+ updateValue({ visibleColumnKeys: nextVisibleColumnKeys });
21009
+ };
21010
+ const shouldRenderColumnVisibility = showColumnVisibility && resolvedColumns.length > 0;
21011
+ const shouldRenderGalleryControls = showGalleryControls;
21012
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-3 text-foreground", classNames?.root, className), children: [
21013
+ shouldRenderColumnVisibility ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: cn("space-y-2", classNames?.section), children: [
21014
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-[10px] font-medium uppercase tracking-wide text-muted-foreground", classNames?.sectionHeader), children: resolvedLabels.visibleColumns }),
21015
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("max-h-[220px] space-y-1 overflow-y-auto pr-1", classNames?.columnList), children: resolvedColumns.map((column) => {
21016
+ const columnKey = normalizeColumnKey(column);
21017
+ return /* @__PURE__ */ jsxRuntime.jsx(
21018
+ BaseCheckbox,
21019
+ {
21020
+ checked: visibleColumnKeySet.has(columnKey),
21021
+ disabled: !canUpdate,
21022
+ label: getColumnLabel(column),
21023
+ description: getColumnDescription?.(column),
21024
+ onChange: () => toggleColumn(columnKey),
21025
+ className: cn("flex w-full rounded-lg px-2 py-1.5 hover:bg-muted/50", classNames?.columnItem)
21026
+ },
21027
+ `workbench-gallery-column-${columnKey}`
21028
+ );
21029
+ }) })
21030
+ ] }) : null,
21031
+ shouldRenderGalleryControls ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: cn("space-y-3 border-t border-border/60 pt-3", classNames?.section), children: [
21032
+ /* @__PURE__ */ jsxRuntime.jsx(
21033
+ BaseField,
21034
+ {
21035
+ label: resolvedLabels.coverField,
21036
+ classNames: {
21037
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21038
+ },
21039
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21040
+ BaseSelect,
21041
+ {
21042
+ value: String(resolvedValue.galleryFieldKey || "auto"),
21043
+ options: [
21044
+ { value: "auto", label: resolvedLabels.autoDetect },
21045
+ ...resolvedGalleryFieldOptions.map((column) => ({
21046
+ value: normalizeColumnKey(column),
21047
+ label: getColumnLabel(column)
21048
+ }))
21049
+ ],
21050
+ disabled: !canUpdate,
21051
+ onChange: (event) => updateValue({ galleryFieldKey: event.currentTarget.value || "auto" }),
21052
+ className: classNames?.control
21053
+ }
21054
+ )
21055
+ }
21056
+ ),
21057
+ /* @__PURE__ */ jsxRuntime.jsx(
21058
+ BaseField,
21059
+ {
21060
+ label: resolvedLabels.cardDensity,
21061
+ classNames: {
21062
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21063
+ },
21064
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21065
+ BaseSegmentedControl,
21066
+ {
21067
+ value: getOptionValue(resolvedDensityOptions, resolvedValue.galleryDensity, "comfortable"),
21068
+ options: resolvedDensityOptions.map((option) => ({
21069
+ value: normalizeOptionValue(option.value),
21070
+ label: option.label,
21071
+ disabled: option.disabled
21072
+ })),
21073
+ onValueChange: (nextValue) => updateValue({ galleryDensity: nextValue }),
21074
+ className: cn("w-full", classNames?.control),
21075
+ classNames: compactSegmentedClassNames
21076
+ }
21077
+ )
21078
+ }
21079
+ ),
21080
+ showGridColumns ? /* @__PURE__ */ jsxRuntime.jsx(
21081
+ BaseField,
21082
+ {
21083
+ label: resolvedLabels.cardColumns,
21084
+ classNames: {
21085
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21086
+ },
21087
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21088
+ BaseSegmentedControl,
21089
+ {
21090
+ value: getOptionValue(resolvedGridColumnOptions, resolvedValue.galleryGridColumns, "auto"),
21091
+ options: resolvedGridColumnOptions.map((option) => ({
21092
+ value: normalizeOptionValue(option.value),
21093
+ label: option.label,
21094
+ disabled: option.disabled
21095
+ })),
21096
+ onValueChange: (nextValue) => updateValue({
21097
+ galleryGridColumns: nextValue === "auto" ? "auto" : parseNumberOption(nextValue)
21098
+ }),
21099
+ className: cn("w-full", classNames?.control),
21100
+ classNames: compactSegmentedClassNames
21101
+ }
21102
+ )
21103
+ }
21104
+ ) : null,
21105
+ showDetailColumns ? /* @__PURE__ */ jsxRuntime.jsx(
21106
+ BaseField,
21107
+ {
21108
+ label: resolvedLabels.detailColumns,
21109
+ classNames: {
21110
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21111
+ },
21112
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21113
+ BaseSegmentedControl,
21114
+ {
21115
+ value: getOptionValue(resolvedBentoColumnOptions, resolvedValue.galleryBentoColumns, 2),
21116
+ options: resolvedBentoColumnOptions.map((option) => ({
21117
+ value: normalizeOptionValue(option.value),
21118
+ label: option.label,
21119
+ disabled: option.disabled
21120
+ })),
21121
+ onValueChange: (nextValue) => updateValue({ galleryBentoColumns: parseNumberOption(nextValue) }),
21122
+ className: cn("w-full", classNames?.control),
21123
+ classNames: compactSegmentedClassNames
21124
+ }
21125
+ )
21126
+ }
21127
+ ) : null,
21128
+ /* @__PURE__ */ jsxRuntime.jsx(
21129
+ BaseField,
21130
+ {
21131
+ label: resolvedLabels.fieldVisibility,
21132
+ classNames: {
21133
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21134
+ },
21135
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21136
+ BaseSegmentedControl,
21137
+ {
21138
+ value: getOptionValue(resolvedDetailVisibilityOptions, resolvedValue.galleryDetailVisibility, "limit"),
21139
+ options: resolvedDetailVisibilityOptions.map((option) => ({
21140
+ value: normalizeOptionValue(option.value),
21141
+ label: option.label,
21142
+ disabled: option.disabled
21143
+ })),
21144
+ onValueChange: (nextValue) => updateValue({ galleryDetailVisibility: nextValue }),
21145
+ className: cn("w-full", classNames?.control),
21146
+ classNames: compactSegmentedClassNames
21147
+ }
21148
+ )
21149
+ }
21150
+ ),
21151
+ resolvedValue.galleryDetailVisibility !== "all" ? /* @__PURE__ */ jsxRuntime.jsx(
21152
+ BaseField,
21153
+ {
21154
+ label: resolvedLabels.fieldLimit,
21155
+ description: resolvedLabels.fieldLimitHint,
21156
+ classNames: {
21157
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground",
21158
+ description: "text-[10px]"
21159
+ },
21160
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21161
+ BaseInput,
21162
+ {
21163
+ type: "number",
21164
+ min: 1,
21165
+ step: 1,
21166
+ value: String(resolvedValue.galleryDetailLimit || 4),
21167
+ disabled: !canUpdate,
21168
+ onChange: (event) => updateValue({ galleryDetailLimit: event.currentTarget.value }),
21169
+ className: classNames?.control
21170
+ }
21171
+ )
21172
+ }
21173
+ ) : null,
21174
+ showLayoutControl ? /* @__PURE__ */ jsxRuntime.jsx(
21175
+ BaseField,
21176
+ {
21177
+ label: resolvedLabels.layout,
21178
+ classNames: {
21179
+ label: "text-[10px] uppercase tracking-wide text-muted-foreground"
21180
+ },
21181
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21182
+ BaseSegmentedControl,
21183
+ {
21184
+ value: getOptionValue(resolvedLayoutOptions, resolvedValue.galleryLayout, "fixed"),
21185
+ options: resolvedLayoutOptions.map((option) => ({
21186
+ value: normalizeOptionValue(option.value),
21187
+ label: option.label,
21188
+ disabled: option.disabled
21189
+ })),
21190
+ onValueChange: (nextValue) => updateValue({ galleryLayout: nextValue }),
21191
+ className: cn("w-full", classNames?.control),
21192
+ classNames: compactSegmentedClassNames
21193
+ }
21194
+ )
21195
+ }
21196
+ ) : null
21197
+ ] }) : null
21198
+ ] });
21199
+ }
21200
+ function WorkbenchGallerySettingsButton({
21201
+ open,
21202
+ defaultOpen = false,
21203
+ onOpenChange,
21204
+ triggerIcon,
21205
+ triggerLabel,
21206
+ triggerTitle,
21207
+ align = "end",
21208
+ popoverWidth = 320,
21209
+ panelHeader,
21210
+ panelBefore,
21211
+ panelAfter,
21212
+ panelClassName,
21213
+ buttonClassName,
21214
+ popoverClassName,
21215
+ buttonClassNames,
21216
+ labels,
21217
+ className,
21218
+ classNames,
21219
+ ...panelProps
21220
+ }) {
21221
+ const resolvedLabels = { ...defaultLabels, ...labels };
21222
+ const rootRef = React.useRef(null);
21223
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
21224
+ const [popoverStyle, setPopoverStyle] = React.useState({});
21225
+ const isControlled = open !== void 0;
21226
+ const isOpen = isControlled ? Boolean(open) : uncontrolledOpen;
21227
+ const setOpen = (nextOpen) => {
21228
+ if (!isControlled) {
21229
+ setUncontrolledOpen(nextOpen);
21230
+ }
21231
+ onOpenChange?.(nextOpen);
21232
+ };
21233
+ React.useLayoutEffect(() => {
21234
+ if (!isOpen) return void 0;
21235
+ const updatePopoverPosition = () => {
21236
+ const triggerRect = rootRef.current?.getBoundingClientRect();
21237
+ if (!triggerRect || typeof window === "undefined") return;
21238
+ const viewportPadding = 12;
21239
+ const availableWidth = Math.max(window.innerWidth - viewportPadding * 2, 0);
21240
+ const resolvedWidth = Math.min(popoverWidth, availableWidth || popoverWidth);
21241
+ const preferredLeft = align === "start" ? triggerRect.left : triggerRect.right - resolvedWidth;
21242
+ const left = Math.min(
21243
+ Math.max(preferredLeft, viewportPadding),
21244
+ Math.max(window.innerWidth - resolvedWidth - viewportPadding, viewportPadding)
21245
+ );
21246
+ const top = Math.min(
21247
+ triggerRect.bottom + 8,
21248
+ Math.max(window.innerHeight - 80, viewportPadding)
21249
+ );
21250
+ setPopoverStyle({
21251
+ left,
21252
+ top,
21253
+ width: resolvedWidth,
21254
+ maxHeight: `calc(100vh - ${Math.round(top + viewportPadding)}px)`
21255
+ });
21256
+ };
21257
+ const handlePointerDown = (event) => {
21258
+ if (!rootRef.current?.contains(event.target)) {
21259
+ setOpen(false);
21260
+ }
21261
+ };
21262
+ const handleKeyDown = (event) => {
21263
+ if (event.key === "Escape") setOpen(false);
21264
+ };
21265
+ updatePopoverPosition();
21266
+ window.addEventListener("resize", updatePopoverPosition);
21267
+ window.addEventListener("scroll", updatePopoverPosition, true);
21268
+ window.addEventListener("pointerdown", handlePointerDown);
21269
+ window.addEventListener("keydown", handleKeyDown);
21270
+ return () => {
21271
+ window.removeEventListener("resize", updatePopoverPosition);
21272
+ window.removeEventListener("scroll", updatePopoverPosition, true);
21273
+ window.removeEventListener("pointerdown", handlePointerDown);
21274
+ window.removeEventListener("keydown", handleKeyDown);
21275
+ };
21276
+ }, [align, isOpen, popoverWidth]);
21277
+ const resolvedTriggerLabel = triggerLabel ?? resolvedLabels.settingsButton;
21278
+ const resolvedPanelHeader = panelHeader ?? resolvedLabels.title;
21279
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn("relative inline-flex", buttonClassNames?.root, className), children: [
21280
+ /* @__PURE__ */ jsxRuntime.jsx(
21281
+ BaseButton,
21282
+ {
21283
+ icon: triggerIcon,
21284
+ label: resolvedTriggerLabel,
21285
+ title: triggerTitle || (typeof resolvedTriggerLabel === "string" ? resolvedTriggerLabel : void 0),
21286
+ iconOnly: Boolean(triggerIcon),
21287
+ active: isOpen,
21288
+ tone: "muted",
21289
+ "aria-haspopup": "dialog",
21290
+ "aria-expanded": isOpen,
21291
+ className: cn(buttonClassNames?.trigger, buttonClassName),
21292
+ onClick: () => setOpen(!isOpen)
21293
+ }
21294
+ ),
21295
+ isOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
21296
+ "div",
21297
+ {
21298
+ role: "dialog",
21299
+ "aria-label": typeof resolvedPanelHeader === "string" ? resolvedPanelHeader : void 0,
21300
+ className: cn(
21301
+ "fixed z-50 overflow-y-auto rounded-xl border border-border bg-card p-3 text-foreground shadow-lg",
21302
+ align === "start" ? "origin-top-left" : "origin-top-right",
21303
+ buttonClassNames?.popover,
21304
+ popoverClassName
21305
+ ),
21306
+ style: popoverStyle,
21307
+ children: [
21308
+ resolvedPanelHeader ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-3 text-[11px] font-medium text-foreground", buttonClassNames?.header), children: resolvedPanelHeader }) : null,
21309
+ panelBefore,
21310
+ /* @__PURE__ */ jsxRuntime.jsx(
21311
+ WorkbenchGallerySettingsPanel,
21312
+ {
21313
+ ...panelProps,
21314
+ labels: resolvedLabels,
21315
+ className: cn(buttonClassNames?.panel, panelClassName),
21316
+ classNames
21317
+ }
21318
+ ),
21319
+ panelAfter
21320
+ ]
21321
+ }
21322
+ ) : null
21323
+ ] });
21324
+ }
21325
+ function TableViewIcon() {
21326
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
21327
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
21328
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18M9 4v16" })
21329
+ ] });
21330
+ }
21331
+ function GalleryViewIcon() {
21332
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
21333
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1.5" }),
21334
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1.5" }),
21335
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1.5" }),
21336
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1.5" })
21337
+ ] });
21338
+ }
21339
+ function SettingsIcon() {
21340
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
21341
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 7h-9M7 7H4M14 17H4M20 17h-3" }),
21342
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "7", r: "2" }),
21343
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "16", cy: "17", r: "2" })
21344
+ ] });
21345
+ }
21346
+ function ChevronDownIcon3({ open }) {
21347
+ return /* @__PURE__ */ jsxRuntime.jsx(
21348
+ "svg",
21349
+ {
21350
+ "aria-hidden": "true",
21351
+ viewBox: "0 0 24 24",
21352
+ className: cn("h-3 w-3 opacity-55 transition-transform", open && "rotate-180"),
21353
+ fill: "none",
21354
+ stroke: "currentColor",
21355
+ strokeWidth: "2",
21356
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
21357
+ }
21358
+ );
21359
+ }
21360
+ var defaultViewModeOptions = [
21361
+ { value: "list", label: "Table view", icon: /* @__PURE__ */ jsxRuntime.jsx(TableViewIcon, {}) },
21362
+ { value: "gallery", label: "Gallery view", icon: /* @__PURE__ */ jsxRuntime.jsx(GalleryViewIcon, {}) }
21363
+ ];
21364
+ function getViewModeOptionIcon(option) {
21365
+ if (option.icon !== void 0) return option.icon;
21366
+ if (option.value === "list" || option.value === "table") return /* @__PURE__ */ jsxRuntime.jsx(TableViewIcon, {});
21367
+ if (option.value === "gallery") return /* @__PURE__ */ jsxRuntime.jsx(GalleryViewIcon, {});
21368
+ return null;
21369
+ }
21370
+ function getSettingsTriggerLabel(settings) {
21371
+ return settings.triggerLabel ?? settings.labels?.settingsButton ?? "Settings";
21372
+ }
21373
+ function WorkbenchContentToolbarViewModeControl({
21374
+ value,
21375
+ options,
21376
+ onValueChange,
21377
+ classNames
21378
+ }) {
21379
+ const rootRef = React.useRef(null);
21380
+ const [open, setOpen] = React.useState(false);
21381
+ const activeOption = options.find((option) => option.value === value) || options.find((option) => !option.disabled) || options[0];
21382
+ const activeIcon = activeOption ? getViewModeOptionIcon(activeOption) : null;
21383
+ React.useEffect(() => {
21384
+ if (!open) return void 0;
21385
+ const handlePointerDown = (event) => {
21386
+ if (!rootRef.current?.contains(event.target)) {
21387
+ setOpen(false);
21388
+ }
21389
+ };
21390
+ const handleKeyDown = (event) => {
21391
+ if (event.key === "Escape") setOpen(false);
21392
+ };
21393
+ window.addEventListener("pointerdown", handlePointerDown);
21394
+ window.addEventListener("keydown", handleKeyDown);
21395
+ return () => {
21396
+ window.removeEventListener("pointerdown", handlePointerDown);
21397
+ window.removeEventListener("keydown", handleKeyDown);
21398
+ };
21399
+ }, [open]);
21400
+ if (!activeOption) return null;
21401
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn("relative inline-flex", classNames?.viewModeRoot), children: [
21402
+ /* @__PURE__ */ jsxRuntime.jsxs(
21403
+ "button",
21404
+ {
21405
+ type: "button",
21406
+ "aria-haspopup": "listbox",
21407
+ "aria-expanded": open,
21408
+ className: cn(
21409
+ "inline-flex h-7 min-w-0 items-center justify-center gap-1.5 rounded-md border border-border/70 bg-card px-2 text-xs font-medium text-foreground shadow-none transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25",
21410
+ classNames?.viewModeTrigger
21411
+ ),
21412
+ onClick: () => setOpen((current) => !current),
21413
+ children: [
21414
+ activeIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center text-muted-foreground", children: activeIcon }) : null,
21415
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: activeOption.label }),
21416
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon3, { open })
21417
+ ]
21418
+ }
21419
+ ),
21420
+ open ? /* @__PURE__ */ jsxRuntime.jsx(
21421
+ "div",
21422
+ {
21423
+ role: "listbox",
21424
+ className: cn(
21425
+ "absolute left-0 top-full z-50 mt-2 min-w-[160px] overflow-hidden rounded-xl border border-border/60 bg-card/95 p-1.5 text-xs text-foreground shadow-lg backdrop-blur-xl",
21426
+ classNames?.viewModeMenu
21427
+ ),
21428
+ children: options.map((option) => {
21429
+ const selected = option.value === activeOption.value;
21430
+ const optionIcon = getViewModeOptionIcon(option);
21431
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21432
+ "button",
21433
+ {
21434
+ type: "button",
21435
+ role: "option",
21436
+ "aria-selected": selected,
21437
+ disabled: option.disabled,
21438
+ className: cn(
21439
+ "flex min-h-8 w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-xs font-medium text-muted-foreground transition-colors hover:bg-muted/55 hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50",
21440
+ selected && "bg-muted/60 text-foreground",
21441
+ classNames?.viewModeItem
21442
+ ),
21443
+ onClick: () => {
21444
+ if (option.disabled) return;
21445
+ onValueChange?.(option.value, option);
21446
+ setOpen(false);
21447
+ },
21448
+ children: [
21449
+ optionIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center", children: optionIcon }) : null,
21450
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: option.label })
21451
+ ]
21452
+ },
21453
+ option.value
21454
+ );
21455
+ })
21456
+ }
21457
+ ) : null
21458
+ ] });
21459
+ }
21460
+ var WorkbenchContentToolbar = React.forwardRef(
21461
+ function WorkbenchContentToolbar2({
21462
+ as: Component = "div",
21463
+ children,
21464
+ end,
21465
+ viewMode,
21466
+ viewModeOptions,
21467
+ onViewModeChange,
21468
+ gallerySettings,
21469
+ gallerySettingsPlacement = "start",
21470
+ className,
21471
+ startClassName,
21472
+ endClassName,
21473
+ classNames,
21474
+ ...props
21475
+ }, ref) {
21476
+ const resolvedViewModeOptions = viewModeOptions || (viewMode ? defaultViewModeOptions : []);
21477
+ const resolvedGallerySettings = gallerySettings && typeof gallerySettings === "object" ? gallerySettings : null;
21478
+ const shouldRenderViewMode = Boolean(resolvedViewModeOptions.length);
21479
+ const shouldRenderSettings = Boolean(resolvedGallerySettings);
21480
+ const shouldRenderSettingsInStart = shouldRenderSettings && gallerySettingsPlacement !== "end";
21481
+ const shouldRenderSettingsInEnd = shouldRenderSettings && gallerySettingsPlacement === "end";
21482
+ const shouldRenderStart = shouldRenderViewMode || shouldRenderSettingsInStart || Boolean(children);
21483
+ const shouldRenderEnd = Boolean(end) || shouldRenderSettingsInEnd;
21484
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21485
+ Component,
21486
+ {
21487
+ ref,
21488
+ "data-workbench-content-toolbar": true,
21489
+ className: cn(
21490
+ "flex min-h-[46px] shrink-0 flex-col gap-2 border-b border-border/60 px-4 py-2 md:flex-row md:items-center md:justify-between",
21491
+ classNames?.root,
21492
+ className
21493
+ ),
21494
+ ...props,
21495
+ children: [
21496
+ shouldRenderStart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-wrap items-center gap-2", classNames?.start, startClassName), children: [
21497
+ shouldRenderViewMode ? /* @__PURE__ */ jsxRuntime.jsx(
21498
+ WorkbenchContentToolbarViewModeControl,
21499
+ {
21500
+ value: viewMode,
21501
+ options: resolvedViewModeOptions,
21502
+ onValueChange: onViewModeChange,
21503
+ classNames
21504
+ }
21505
+ ) : null,
21506
+ shouldRenderSettingsInStart && resolvedGallerySettings ? /* @__PURE__ */ jsxRuntime.jsx(
21507
+ WorkbenchGallerySettingsButton,
21508
+ {
21509
+ align: "end",
21510
+ triggerIcon: /* @__PURE__ */ jsxRuntime.jsx(SettingsIcon, {}),
21511
+ triggerLabel: getSettingsTriggerLabel(resolvedGallerySettings),
21512
+ ...resolvedGallerySettings,
21513
+ buttonClassName: cn(
21514
+ "!h-7 !w-7 !min-h-0 !rounded-md !p-0 text-xs",
21515
+ classNames?.settings,
21516
+ resolvedGallerySettings.buttonClassName
21517
+ )
21518
+ }
21519
+ ) : null,
21520
+ children
21521
+ ] }) : null,
21522
+ shouldRenderEnd ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex shrink-0 items-center gap-2", classNames?.end, endClassName), children: [
21523
+ end,
21524
+ shouldRenderSettingsInEnd && resolvedGallerySettings ? /* @__PURE__ */ jsxRuntime.jsx(
21525
+ WorkbenchGallerySettingsButton,
21526
+ {
21527
+ align: "end",
21528
+ triggerIcon: /* @__PURE__ */ jsxRuntime.jsx(SettingsIcon, {}),
21529
+ triggerLabel: getSettingsTriggerLabel(resolvedGallerySettings),
21530
+ ...resolvedGallerySettings,
21531
+ buttonClassName: cn(
21532
+ "!h-7 !w-7 !min-h-0 !rounded-md !p-0 text-xs",
21533
+ classNames?.settings,
21534
+ resolvedGallerySettings.buttonClassName
21535
+ )
21536
+ }
21537
+ ) : null
21538
+ ] }) : null
21539
+ ]
21540
+ }
21541
+ );
21542
+ }
21543
+ );
21544
+ function shouldRenderBodyWrapper2(props) {
21545
+ return Boolean(
21546
+ props.header || props.footer || props.bodyAs || props.bodyClassName || props.bodyProps || props.classNames?.body
21547
+ );
21548
+ }
21549
+ function hasRenderableChildren(children) {
21550
+ if (children === null || children === void 0 || typeof children === "boolean") return false;
21551
+ if (typeof children === "string") return children.trim().length > 0;
21552
+ if (Array.isArray(children)) return children.some(hasRenderableChildren);
21553
+ const childList = React.Children.toArray(children);
21554
+ if (!childList.length) return false;
21555
+ return childList.some((child) => typeof child === "string" ? child.trim().length > 0 : true);
21556
+ }
21557
+ function resolveWidthStyle(open, width) {
21558
+ if (width === void 0) return {};
21559
+ if (open === void 0) return { width };
21560
+ return {
21561
+ width: open ? width : 0,
21562
+ opacity: open ? 1 : 0
21563
+ };
21564
+ }
21565
+ function getFallbackFieldLabel(field) {
21566
+ return field.label ?? field.key;
21567
+ }
21568
+ function getObjectDisplayValue(value) {
21569
+ const displayKeys = ["text", "label", "title", "display", "value", "recordId"];
21570
+ for (const key of displayKeys) {
21571
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
21572
+ const displayValue = value[key];
21573
+ if (displayValue !== null && displayValue !== void 0 && displayValue !== "") {
21574
+ return displayValue;
21575
+ }
21576
+ }
21577
+ return void 0;
21578
+ }
21579
+ function isEmptyDetailValue(value) {
21580
+ return value === null || value === void 0 || value === "";
21581
+ }
21582
+ function isPlainDisplayValue(value) {
21583
+ return ["string", "number", "boolean"].includes(typeof value);
21584
+ }
21585
+ function getMediaDisplayData(value) {
21586
+ if (!value) return null;
21587
+ if (typeof value === "string") {
21588
+ const isDataImage = value.startsWith("data:image/");
21589
+ const isImageUrl = /\.(avif|gif|jpe?g|png|svg|webp)(\?.*)?$/i.test(value);
21590
+ return isDataImage || isImageUrl ? { src: value } : null;
21591
+ }
21592
+ if (typeof value !== "object" || React.isValidElement(value)) return null;
21593
+ const media = value;
21594
+ const src = media.src || media.url || media.thumbnail || media.preview || media.image;
21595
+ return src ? {
21596
+ src: String(src),
21597
+ alt: media.alt || media.label || media.title || "",
21598
+ caption: media.caption || media.description || media.label || media.title
21599
+ } : null;
21600
+ }
21601
+ function shouldRenderAsMedia(field, value) {
21602
+ const renderType = String(field?.renderType || "").toLowerCase();
21603
+ return ["image", "media", "preview", "thumbnail"].includes(renderType) || Boolean(getMediaDisplayData(value));
21604
+ }
21605
+ function renderMaybeFieldIcon(icon, className) {
21606
+ if (!icon) {
21607
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("relative inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center", className), children: [
21608
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 rounded-full border border-primary/25 bg-primary/10" }),
21609
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-primary" })
21610
+ ] });
21611
+ }
21612
+ if (typeof icon === "string" || typeof icon === "number") {
21613
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("inline-flex h-3.5 min-w-3.5 shrink-0 items-center justify-center rounded-sm text-[10px] font-semibold text-primary", className), children: icon });
21614
+ }
21615
+ if (typeof icon === "boolean") return null;
21616
+ if (React.isValidElement(icon)) return icon;
21617
+ const IconComponent = icon;
21618
+ return /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: cn("h-3.5 w-3.5 shrink-0 text-primary", className) });
21619
+ }
21620
+ function renderDetailFieldLabel(label, field, classNames) {
21621
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("inline-flex min-w-0 items-center gap-1.5 text-[11px] font-semibold text-foreground", classNames?.fieldLabel), children: [
21622
+ renderMaybeFieldIcon(field.labelIcon || field.icon, classNames?.fieldLabelIcon),
21623
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: label })
21624
+ ] });
21625
+ }
21626
+ function WorkbenchDetailSidebarMediaValue({
21627
+ media,
21628
+ classNames
21629
+ }) {
21630
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid gap-2", classNames?.mediaValue), children: [
21631
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-md border border-border/55 bg-muted/20 dark:border-border/45 dark:bg-muted/10", children: /* @__PURE__ */ jsxRuntime.jsx(
21632
+ "img",
21633
+ {
21634
+ src: media.src,
21635
+ alt: String(media.alt || ""),
21636
+ className: cn("block aspect-[16/9] w-full object-cover", classNames?.mediaImage)
21637
+ }
21638
+ ) }),
21639
+ media.caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("truncate text-[11px] leading-4 text-muted-foreground", classNames?.mediaCaption), children: media.caption }) : null
21640
+ ] });
21641
+ }
21642
+ function getDefaultDetailDisplayValue(value, emptyValue, field, classNames) {
21643
+ if (isEmptyDetailValue(value)) return emptyValue;
21644
+ if (React.isValidElement(value)) return value;
21645
+ if (shouldRenderAsMedia(field, value)) {
21646
+ const media = getMediaDisplayData(value);
21647
+ if (media) return /* @__PURE__ */ jsxRuntime.jsx(WorkbenchDetailSidebarMediaValue, { media, classNames });
21648
+ }
21649
+ if (Array.isArray(value)) {
21650
+ const parts = value.map((item) => getDefaultDetailDisplayValue(item, "", void 0, classNames)).filter((item) => !isEmptyDetailValue(item));
21651
+ if (!parts.length) return emptyValue;
21652
+ if (parts.every(isPlainDisplayValue)) return parts.map(String).join(" \xB7 ");
21653
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex flex-wrap items-center gap-1", children: parts.map((part, index) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
21654
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\xB7" }) : null,
21655
+ isPlainDisplayValue(part) ? String(part) : part
21656
+ ] }, index)) });
21657
+ }
21658
+ if (typeof value === "object") {
21659
+ const displayValue = getObjectDisplayValue(value);
21660
+ return displayValue === void 0 ? emptyValue : getDefaultDetailDisplayValue(displayValue, emptyValue, field, classNames);
21661
+ }
21662
+ return String(value);
21663
+ }
21664
+ function getDefaultFieldValue(field, record) {
21665
+ if (Object.prototype.hasOwnProperty.call(field, "value")) {
21666
+ return typeof field.value === "function" ? field.value(record, field) : field.value;
21667
+ }
21668
+ return record ? record?.[field.key] : void 0;
21669
+ }
21670
+ function shouldHideField(field, record) {
21671
+ return typeof field.hidden === "function" ? field.hidden(field, record) : Boolean(field.hidden);
21672
+ }
21673
+ function shouldHideSection(section, record) {
21674
+ return typeof section.hidden === "function" ? section.hidden(section, record) : Boolean(section.hidden);
21675
+ }
21676
+ function WorkbenchDetailSidebarAutoContent({
21677
+ record,
21678
+ fields,
21679
+ sections,
21680
+ fieldColumns = 1,
21681
+ emptyValue = "\u2014",
21682
+ emptyState,
21683
+ getFieldValue,
21684
+ renderFieldValue,
21685
+ formatFieldValue,
21686
+ formatFieldLabel,
21687
+ classNames
21688
+ }) {
21689
+ const resolvedSections = sections?.length ? sections : fields?.length ? [{ fields, columns: fieldColumns }] : [];
21690
+ const visibleSections = resolvedSections.filter((section) => !shouldHideSection(section, record));
21691
+ if (!visibleSections.length) {
21692
+ return emptyState ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("rounded-lg border border-dashed border-border/60 px-3 py-6 text-center text-xs text-muted-foreground", classNames?.emptyState), children: emptyState }) : null;
21693
+ }
21694
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-3", classNames?.autoBody), children: visibleSections.map((section, sectionIndex) => {
21695
+ const visibleFields = (section.fields || []).filter((field) => !shouldHideField(field, record));
21696
+ const sectionKey = section.id || `section-${sectionIndex}`;
21697
+ if (!visibleFields.length && !section.emptyState) return null;
21698
+ const items = visibleFields.map((field, fieldIndex) => {
21699
+ const context = {
21700
+ field,
21701
+ fieldIndex,
21702
+ section,
21703
+ sectionIndex,
21704
+ record
21705
+ };
21706
+ const rawValue = getFieldValue ? getFieldValue(field, record, context) : getDefaultFieldValue(field, record);
21707
+ const value = renderFieldValue ? renderFieldValue(field, record, context) : formatFieldValue ? formatFieldValue(rawValue, context) : getDefaultDetailDisplayValue(rawValue, field.emptyValue ?? emptyValue, field, classNames);
21708
+ const fieldLabel = formatFieldLabel ? formatFieldLabel(getFallbackFieldLabel(field), context) : getFallbackFieldLabel(field);
21709
+ return {
21710
+ term: renderDetailFieldLabel(fieldLabel, field, classNames),
21711
+ value
21712
+ };
21713
+ });
21714
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: cn("min-w-0 space-y-3", classNames?.section), children: [
21715
+ section.title || section.description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-w-0 space-y-1.5", classNames?.sectionHeader), children: [
21716
+ section.title ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("inline-flex max-w-full items-center gap-2 rounded-md border border-primary/20 bg-primary/5 px-2.5 py-1.5 text-xs font-medium text-primary dark:border-primary/25 dark:bg-primary/10", classNames?.sectionTitle), children: section.title }) : null,
21717
+ section.description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-[11px] leading-5 text-muted-foreground", classNames?.sectionDescription), children: section.description }) : null
21718
+ ] }) : null,
21719
+ items.length ? /* @__PURE__ */ jsxRuntime.jsx(
21720
+ BaseDescriptionList,
21721
+ {
21722
+ items,
21723
+ columns: section.columns || fieldColumns,
21724
+ className: cn("gap-3", classNames?.descriptionList),
21725
+ classNames: {
21726
+ item: cn("!border-0 !bg-transparent !p-0 !shadow-none !gap-1.5", classNames?.descriptionListItem),
21727
+ term: cn("!normal-case !tracking-normal !text-foreground", classNames?.descriptionListTerm),
21728
+ value: cn(
21729
+ "min-h-10 rounded-md border border-border/55 bg-muted/25 px-3 py-2 text-xs leading-5 text-foreground shadow-[inset_0_1px_0_hsl(var(--background)/0.8)] dark:border-border/45 dark:bg-white/[0.035]",
21730
+ classNames?.fieldValue,
21731
+ classNames?.descriptionListValue
21732
+ )
21733
+ }
21734
+ }
21735
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("py-3 text-center text-xs text-muted-foreground", classNames?.emptyState), children: section.emptyState })
21736
+ ] }, sectionKey);
21737
+ }) });
21738
+ }
21739
+ var WorkbenchDetailSidebar = React.forwardRef(
21740
+ function WorkbenchDetailSidebar2({
21741
+ as: Component = "aside",
21742
+ bodyAs: BodyComponent = "div",
21743
+ open,
21744
+ width,
21745
+ header,
21746
+ footer,
21747
+ resizeHandle,
21748
+ children,
21749
+ record,
21750
+ fields,
21751
+ sections,
21752
+ fieldColumns,
21753
+ emptyValue,
21754
+ emptyState,
21755
+ getFieldValue,
21756
+ renderFieldValue,
21757
+ formatFieldValue,
21758
+ formatFieldLabel,
21759
+ className,
21760
+ headerClassName,
21761
+ bodyClassName,
21762
+ footerClassName,
21763
+ resizeHandleClassName,
21764
+ bodyProps,
21765
+ classNames,
21766
+ style,
21767
+ ...props
21768
+ }, ref) {
21769
+ const autoContent = hasRenderableChildren(children) ? children : /* @__PURE__ */ jsxRuntime.jsx(
21770
+ WorkbenchDetailSidebarAutoContent,
21771
+ {
21772
+ record,
21773
+ fields,
21774
+ sections,
21775
+ fieldColumns,
21776
+ emptyValue,
21777
+ emptyState,
21778
+ getFieldValue,
21779
+ renderFieldValue,
21780
+ formatFieldValue,
21781
+ formatFieldLabel,
21782
+ classNames
21783
+ }
21784
+ );
21785
+ const renderBodyWrapper = shouldRenderBodyWrapper2({
21786
+ header,
21787
+ footer,
21788
+ bodyAs: BodyComponent === "div" ? void 0 : BodyComponent,
21789
+ bodyClassName,
21790
+ bodyProps,
21791
+ classNames
21792
+ });
21793
+ const { className: bodyPropsClassName, ...restBodyProps } = bodyProps ?? {};
21794
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21795
+ Component,
21796
+ {
21797
+ ref,
21798
+ "data-workbench-detail-sidebar": true,
21799
+ "data-open": open === void 0 ? void 0 : open ? "true" : "false",
21800
+ className: cn(
21801
+ "workbench-surface-subtle relative flex flex-shrink-0 flex-col self-stretch overflow-hidden rounded-lg border border-border/50 transition-all duration-300 dark:border-border/40",
21802
+ open === false && "pointer-events-none",
21803
+ classNames?.root,
21804
+ className
21805
+ ),
21806
+ style: {
21807
+ ...resolveWidthStyle(open, width),
21808
+ ...style
21809
+ },
21810
+ ...props,
21811
+ children: [
21812
+ resizeHandle ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(classNames?.resizeHandle, resizeHandleClassName), children: resizeHandle }) : null,
21813
+ header ? /* @__PURE__ */ jsxRuntime.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,
21814
+ renderBodyWrapper ? /* @__PURE__ */ jsxRuntime.jsx(
21815
+ BodyComponent,
21816
+ {
21817
+ className: cn("min-h-0 flex-1 overflow-y-auto", classNames?.body, bodyClassName, bodyPropsClassName),
21818
+ ...restBodyProps,
21819
+ children: autoContent
21820
+ }
21821
+ ) : autoContent,
21822
+ footer ? /* @__PURE__ */ jsxRuntime.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
21823
+ ]
21824
+ }
21825
+ );
21826
+ }
21827
+ );
21828
+ function isWorkbenchIconComponent(icon) {
21829
+ if (typeof icon === "function") return true;
21830
+ return typeof icon === "object" && icon !== null && !React.isValidElement(icon) && "$$typeof" in icon;
21831
+ }
21832
+ function renderWorkbenchIcon(icon, className) {
21833
+ if (!icon) return null;
21834
+ if (React.isValidElement(icon)) return icon;
21835
+ if (isWorkbenchIconComponent(icon)) {
21836
+ const Icon = icon;
21837
+ return /* @__PURE__ */ jsxRuntime.jsx(Icon, { className });
21838
+ }
21839
+ return icon;
21840
+ }
21841
+ function getWorkbenchIconComponent(icon) {
21842
+ if (!icon || !isWorkbenchIconComponent(icon)) return null;
21843
+ return icon;
21844
+ }
21845
+ function toCssSize3(value) {
21846
+ if (value === void 0) return void 0;
21847
+ return typeof value === "number" ? `${value}px` : value;
21848
+ }
21849
+ function defaultFormatLabel(value) {
21850
+ if (value === void 0 || value === null || value === false) return null;
21851
+ return value;
21852
+ }
21853
+ function toTitle(value) {
21854
+ if (typeof value === "string" || typeof value === "number") return String(value);
21855
+ return void 0;
21856
+ }
21857
+ function defaultGetRowKey(row, rowIndex) {
21858
+ return row?.id ?? row?.key ?? row?.linkKey ?? rowIndex;
21859
+ }
21860
+ function defaultGetRowSelectionKey(row) {
21861
+ return row?.linkKey ?? row?.id ?? row?.key;
21862
+ }
21863
+ function getOrderedColumns(columns, columnOrder) {
21864
+ if (!columnOrder?.length) return columns;
21865
+ const columnMap = new Map(columns.map((column) => [column.key, column]));
21866
+ const orderedColumns = columnOrder.map((columnKey) => columnMap.get(columnKey)).filter(Boolean);
21867
+ const orderedKeySet = new Set(orderedColumns.map((column) => column.key));
21868
+ const remainingColumns = columns.filter((column) => !orderedKeySet.has(column.key));
21869
+ return [...orderedColumns, ...remainingColumns];
21870
+ }
21871
+ function normalizeColumnOrder(columnKeys, columnOrder) {
21872
+ const validColumnKeys = new Set(columnKeys);
21873
+ const orderedKeys = (columnOrder || []).filter((columnKey) => validColumnKeys.has(columnKey));
21874
+ const orderedKeySet = new Set(orderedKeys);
21875
+ const remainingKeys = columnKeys.filter((columnKey) => !orderedKeySet.has(columnKey));
21876
+ return [...orderedKeys, ...remainingKeys];
21877
+ }
21878
+ function WorkbenchTableHeaderHelper({
21879
+ helperText,
21880
+ className
21881
+ }) {
21882
+ if (!hasRenderableNode(helperText)) return null;
21883
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("group relative inline-flex items-center", className), children: [
21884
+ /* @__PURE__ */ jsxRuntime.jsx(
21885
+ "button",
21886
+ {
21887
+ type: "button",
21888
+ title: toTitle(helperText),
21889
+ "aria-label": toTitle(helperText) || "Field help",
21890
+ 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",
21891
+ onClick: (event) => event.stopPropagation(),
21892
+ children: "?"
21893
+ }
21894
+ ),
21895
+ /* @__PURE__ */ jsxRuntime.jsx(
21896
+ "span",
21897
+ {
21898
+ role: "tooltip",
21899
+ 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",
21900
+ children: helperText
21901
+ }
21902
+ )
21903
+ ] });
21904
+ }
21905
+ function WorkbenchTableView({
21906
+ rows = [],
21907
+ columns = [],
21908
+ onRowClick,
21909
+ selectedRowKey,
21910
+ selectedLinkKey,
21911
+ activePrimaryColumn,
21912
+ activeTablePrimaryColumn,
21913
+ renderedRowCount,
21914
+ totalRowCount,
21915
+ tableMinWidth,
21916
+ minWidth,
21917
+ bodyMaxHeight = "min(58vh, 38rem)",
21918
+ stickyFirstColumn = true,
21919
+ appearance,
21920
+ columnOrder,
21921
+ columnSizes,
21922
+ columnDragEnabled,
21923
+ columnResizeEnabled,
21924
+ className,
21925
+ tableClassName,
21926
+ rowClassName,
21927
+ classNames,
21928
+ style,
21929
+ renderCell,
21930
+ renderFieldValue,
21931
+ renderColumnHeader,
21932
+ onColumnOrderChange,
21933
+ onColumnSizeChange,
21934
+ onSort,
21935
+ formatLabel = defaultFormatLabel,
21936
+ getColumnDataType,
21937
+ getColumnIcon,
21938
+ getColumnTypeIcon,
21939
+ getRowKey = defaultGetRowKey,
21940
+ getRowSelectionKey = defaultGetRowSelectionKey,
21941
+ isActionColumn,
21942
+ isActionField,
21943
+ isRowDisabled,
21944
+ isWorkbenchPlaceholderRow,
21945
+ emptyState = "-",
21946
+ hiddenRowsMessage
21947
+ }) {
21948
+ const columnKeySignature = columns.map((column) => column.key).join("");
21949
+ const defaultColumnOrder = React.useMemo(() => columnKeySignature ? columnKeySignature.split("") : [], [columnKeySignature]);
21950
+ const [internalColumnOrder, setInternalColumnOrder] = React.useState(defaultColumnOrder);
21951
+ const [internalColumnSizes, setInternalColumnSizes] = React.useState({});
21952
+ React.useEffect(() => {
21953
+ setInternalColumnOrder((current) => normalizeColumnOrder(defaultColumnOrder, current));
21954
+ }, [defaultColumnOrder]);
21955
+ const resolvedColumnOrder = columnOrder ? normalizeColumnOrder(defaultColumnOrder, columnOrder) : internalColumnOrder;
21956
+ const resolvedColumnSizes = columnSizes ?? internalColumnSizes;
21957
+ const handleColumnOrderChange = React.useCallback((nextOrder, detail) => {
21958
+ const normalizedOrder = normalizeColumnOrder(defaultColumnOrder, nextOrder);
21959
+ if (!columnOrder) {
21960
+ setInternalColumnOrder(normalizedOrder);
21961
+ }
21962
+ onColumnOrderChange?.(normalizedOrder, detail);
21963
+ }, [columnOrder, defaultColumnOrder, onColumnOrderChange]);
21964
+ const handleColumnSizeChange = React.useCallback((columnId, width, detail) => {
21965
+ if (!columnSizes) {
21966
+ setInternalColumnSizes((current) => ({
21967
+ ...current,
21968
+ [columnId]: width
21969
+ }));
21970
+ }
21971
+ onColumnSizeChange?.(columnId, width, detail);
21972
+ }, [columnSizes, onColumnSizeChange]);
21973
+ const resolvedSelectedKey = selectedRowKey ?? selectedLinkKey;
21974
+ const resolvedActivePrimaryColumn = activePrimaryColumn ?? activeTablePrimaryColumn;
21975
+ const orderedColumns = getOrderedColumns(columns, resolvedColumnOrder);
21976
+ const hiddenRowCount = Math.max(0, Number(totalRowCount || rows.length) - Number(renderedRowCount || rows.length));
21977
+ const resolvedMinWidth = tableMinWidth ?? minWidth ?? Math.max(760, Math.min(orderedColumns.length * 112, 1440));
21978
+ const renderValue = renderCell ?? renderFieldValue ?? ((column, row) => row?.[column.key]);
21979
+ const isAction = isActionColumn ?? isActionField ?? (() => false);
21980
+ const isDisabled = isRowDisabled ?? isWorkbenchPlaceholderRow ?? (() => false);
21981
+ const resolveColumnIcon = getColumnIcon ?? getColumnTypeIcon;
21982
+ const footer = hiddenRowCount > 0 && hiddenRowsMessage ? typeof hiddenRowsMessage === "function" ? hiddenRowsMessage(hiddenRowCount, renderedRowCount || rows.length, totalRowCount || rows.length) : hiddenRowsMessage : null;
21983
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21984
+ BaseTableContainer,
21985
+ {
21986
+ appearance,
21987
+ 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),
21988
+ style,
21989
+ children: [
21990
+ /* @__PURE__ */ jsxRuntime.jsx(
21991
+ "div",
21992
+ {
21993
+ className: cn("w-full overflow-auto", classNames?.scrollArea),
21994
+ style: { maxHeight: toCssSize3(bodyMaxHeight) },
21995
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
21996
+ BaseTable,
21997
+ {
21998
+ appearance,
21999
+ columnOrder: resolvedColumnOrder,
22000
+ columnSizes: resolvedColumnSizes,
22001
+ columnDragEnabled,
22002
+ columnResizeEnabled,
22003
+ onColumnOrderChange: handleColumnOrderChange,
22004
+ onColumnSizeChange: handleColumnSizeChange,
22005
+ className: cn("w-full table-auto text-left text-xs", classNames?.table, tableClassName),
22006
+ style: { minWidth: resolvedMinWidth },
22007
+ children: [
22008
+ /* @__PURE__ */ jsxRuntime.jsx(BaseTableHeader, { appearance, className: cn("text-[10px] font-mono uppercase tracking-wide text-muted-foreground", classNames?.header), children: /* @__PURE__ */ jsxRuntime.jsx(BaseTableRow, { className: cn("hover:bg-transparent", classNames?.headerRow), children: orderedColumns.map((column, columnIndex) => {
22009
+ const columnType = column.renderType || column.type || getColumnDataType?.(column.key, rows, column);
22010
+ const columnIcon = renderWorkbenchIcon(
22011
+ resolveColumnIcon?.(columnType, column),
22012
+ "h-3.5 w-3.5 shrink-0 text-primary"
22013
+ );
22014
+ const previousColumn = orderedColumns[columnIndex - 1];
22015
+ const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
22016
+ const headerContent = renderColumnHeader ? renderColumnHeader(column, { column, columnIndex, columns: orderedColumns, rows, columnType }) : formatLabel(column.label, { column });
22017
+ const headerTrailing = !renderColumnHeader && (hasRenderableNode(column.trailing) || hasRenderableNode(column.helperText)) ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
22018
+ hasRenderableNode(column.trailing) ? formatLabel(column.trailing, { column }) : null,
22019
+ /* @__PURE__ */ jsxRuntime.jsx(WorkbenchTableHeaderHelper, { helperText: formatLabel(column.helperText, { column }), className: classNames?.helper })
22020
+ ] }) : void 0;
22021
+ const sortable = Boolean(column.sortable);
22022
+ const handleSort = sortable && onSort ? () => onSort(column.key, column) : void 0;
22023
+ return /* @__PURE__ */ jsxRuntime.jsx(
22024
+ BaseTableHead,
22025
+ {
22026
+ appearance,
22027
+ columnId: column.key,
22028
+ align: column.align,
22029
+ icon: renderColumnHeader ? void 0 : columnIcon,
22030
+ label: headerContent,
22031
+ description: renderColumnHeader ? void 0 : formatLabel(column.description, { column }),
22032
+ meta: renderColumnHeader ? void 0 : formatLabel(column.meta, { column }),
22033
+ actions: renderColumnHeader ? void 0 : column.actions,
22034
+ trailing: headerTrailing,
22035
+ sortable,
22036
+ sortDirection: column.sortDirection,
22037
+ sortLabel: column.sortLabel,
22038
+ onSort: handleSort,
22039
+ draggable: column.draggable,
22040
+ dragLabel: column.dragLabel,
22041
+ resizable: column.resizable,
22042
+ resizeLabel: column.resizeLabel,
22043
+ width: column.width,
22044
+ minWidth: typeof column.minWidth === "number" ? column.minWidth : void 0,
22045
+ maxWidth: typeof column.maxWidth === "number" ? column.maxWidth : void 0,
22046
+ className: cn(
22047
+ "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",
22048
+ stickyFirstColumn && columnIndex === 0 && "left-0 z-30 shadow-[1px_0_0_0_hsl(var(--border)/0.35)]",
22049
+ column.compactHeaderClassName,
22050
+ column.headerClassName,
22051
+ column.renderType === "icon" && "pl-3 pr-1",
22052
+ followsRecordIcon && "pl-2",
22053
+ classNames?.headerCell
22054
+ ),
22055
+ style: {
22056
+ minWidth: typeof column.minWidth === "string" ? column.minWidth : void 0,
22057
+ maxWidth: typeof column.maxWidth === "string" ? column.maxWidth : void 0
22058
+ }
22059
+ },
22060
+ column.key
22061
+ );
22062
+ }) }) }),
22063
+ /* @__PURE__ */ jsxRuntime.jsx(BaseTableBody, { appearance, className: cn("divide-y divide-border/35 dark:divide-border/30", classNames?.body), children: rows.length ? rows.map((row, rowIndex) => {
22064
+ const key = getRowKey(row, rowIndex);
22065
+ const disabled = isDisabled(row, rowIndex);
22066
+ const selectionKey = getRowSelectionKey(row, rowIndex);
22067
+ const selected = Boolean(resolvedSelectedKey && String(selectionKey) === String(resolvedSelectedKey));
22068
+ const resolvedRowClassName = typeof rowClassName === "function" ? rowClassName(row, rowIndex) : rowClassName;
22069
+ return /* @__PURE__ */ jsxRuntime.jsx(
22070
+ BaseTableRow,
22071
+ {
22072
+ appearance,
22073
+ interactive: Boolean(onRowClick) && !disabled,
22074
+ selected,
22075
+ disabled,
22076
+ onClick: () => {
22077
+ if (!disabled) {
22078
+ onRowClick?.(row, rowIndex);
22079
+ }
22080
+ },
22081
+ className: cn(
22082
+ onRowClick && !disabled ? "cursor-pointer" : "cursor-default",
22083
+ selected ? "bg-primary/10 hover:bg-primary/15" : disabled ? "" : "hover:bg-muted/25 dark:hover:bg-muted/15",
22084
+ classNames?.row,
22085
+ resolvedRowClassName
22086
+ ),
22087
+ children: orderedColumns.map((column, columnIndex) => {
22088
+ const shouldWrap = isAction(column) || column.wrap === true;
22089
+ const previousColumn = orderedColumns[columnIndex - 1];
22090
+ const followsRecordIcon = previousColumn?.renderType === "icon" && column.key === resolvedActivePrimaryColumn?.key;
22091
+ return /* @__PURE__ */ jsxRuntime.jsx(
22092
+ BaseTableCell,
22093
+ {
22094
+ appearance,
22095
+ align: column.align,
22096
+ className: cn(
22097
+ shouldWrap ? "align-top whitespace-normal" : "whitespace-nowrap",
22098
+ "px-4 py-3 text-muted-foreground",
22099
+ stickyFirstColumn && columnIndex === 0 && "sticky left-0 z-10 bg-card/95 text-foreground shadow-[1px_0_0_0_hsl(var(--border)/0.3)]",
22100
+ column.compactCellClassName,
22101
+ column.cellClassName,
22102
+ column.renderType === "icon" && "pl-3 pr-1",
22103
+ followsRecordIcon && "pl-2",
22104
+ classNames?.cell
22105
+ ),
22106
+ children: renderValue(column, row, {
22107
+ row,
22108
+ rowIndex,
22109
+ column,
22110
+ columnIndex,
22111
+ compact: true,
22112
+ surface: "list"
22113
+ })
22114
+ },
22115
+ `${key}-${column.key}`
22116
+ );
22117
+ })
22118
+ },
22119
+ key
22120
+ );
22121
+ }) : /* @__PURE__ */ jsxRuntime.jsx(
22122
+ BaseTableEmpty,
22123
+ {
22124
+ appearance,
22125
+ colSpan: Math.max(orderedColumns.length, 1),
22126
+ classNames: { cell: "px-4 py-10 text-center text-sm text-muted-foreground" },
22127
+ children: emptyState
22128
+ }
22129
+ ) })
22130
+ ]
22131
+ }
22132
+ )
22133
+ }
22134
+ ),
22135
+ footer ? /* @__PURE__ */ jsxRuntime.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
22136
+ ]
22137
+ }
22138
+ );
22139
+ }
22140
+ function toCssSize4(value) {
22141
+ if (value === void 0) return void 0;
22142
+ return typeof value === "number" ? `${value}px` : value;
22143
+ }
22144
+ function isBrowser() {
22145
+ return typeof window !== "undefined";
22146
+ }
22147
+ function defaultGetRowKey2(row, rowIndex) {
22148
+ return row?.id ?? row?.key ?? rowIndex;
22149
+ }
22150
+ function getColumnDefaultSize(column) {
22151
+ if (typeof column.width === "number") return column.width;
22152
+ if (typeof column.minWidth === "number") return column.minWidth;
22153
+ return 160;
22154
+ }
22155
+ function buildDefaultColumnSizes(columns, explicit) {
22156
+ return columns.reduce((acc, column) => {
22157
+ acc[column.key] = explicit?.[column.key] ?? getColumnDefaultSize(column);
22158
+ return acc;
22159
+ }, {});
22160
+ }
22161
+ function loadStoredColumnSizes(storageKey, defaults) {
22162
+ if (!storageKey || !isBrowser()) return defaults;
22163
+ try {
22164
+ const parsed = JSON.parse(window.localStorage.getItem(storageKey) || "{}");
22165
+ return Object.keys(defaults).reduce((acc, key) => {
22166
+ const value = Number(parsed?.[key]);
22167
+ acc[key] = Number.isFinite(value) ? value : defaults[key];
22168
+ return acc;
22169
+ }, {});
22170
+ } catch {
22171
+ return defaults;
22172
+ }
22173
+ }
22174
+ function persistColumnSizes(storageKey, sizes) {
22175
+ if (!storageKey || !isBrowser()) return;
22176
+ window.localStorage.setItem(storageKey, JSON.stringify(sizes));
22177
+ }
22178
+ function getFrozenColumnStorageKey(storageKey) {
22179
+ return storageKey ? `${storageKey}.frozenColumnCount` : void 0;
22180
+ }
22181
+ function getFrozenEndColumnStorageKey(storageKey) {
22182
+ return storageKey ? `${storageKey}.frozenEndColumnCount` : void 0;
22183
+ }
22184
+ function clampFrozenColumnCount(count, columnCount) {
22185
+ if (!Number.isFinite(count)) return 0;
22186
+ return Math.max(0, Math.min(Math.round(count), columnCount));
22187
+ }
22188
+ function normalizeFrozenColumnCounts(startCount, endCount, columnCount) {
22189
+ const normalizedStartCount = clampFrozenColumnCount(startCount, columnCount);
22190
+ const normalizedEndCount = clampFrozenColumnCount(endCount, Math.max(0, columnCount - normalizedStartCount));
22191
+ return {
22192
+ startCount: normalizedStartCount,
22193
+ endCount: normalizedEndCount
22194
+ };
22195
+ }
22196
+ function loadStoredFrozenColumnCount(storageKey, defaultCount, columnCount) {
22197
+ const fallback = clampFrozenColumnCount(defaultCount, columnCount);
22198
+ const frozenStorageKey = getFrozenColumnStorageKey(storageKey);
22199
+ if (!frozenStorageKey || !isBrowser()) return fallback;
22200
+ try {
22201
+ const storedValue = window.localStorage.getItem(frozenStorageKey);
22202
+ if (storedValue === null) return fallback;
22203
+ const value = Number(storedValue);
22204
+ return Number.isFinite(value) ? clampFrozenColumnCount(value, columnCount) : fallback;
22205
+ } catch {
22206
+ return fallback;
22207
+ }
22208
+ }
22209
+ function persistFrozenColumnCount(storageKey, count) {
22210
+ const frozenStorageKey = getFrozenColumnStorageKey(storageKey);
22211
+ if (!frozenStorageKey || !isBrowser()) return;
22212
+ window.localStorage.setItem(frozenStorageKey, String(count));
22213
+ }
22214
+ function loadStoredFrozenEndColumnCount(storageKey, defaultCount, columnCount) {
22215
+ const fallback = clampFrozenColumnCount(defaultCount, columnCount);
22216
+ const frozenStorageKey = getFrozenEndColumnStorageKey(storageKey);
22217
+ if (!frozenStorageKey || !isBrowser()) return fallback;
22218
+ try {
22219
+ const storedValue = window.localStorage.getItem(frozenStorageKey);
22220
+ if (storedValue === null) return fallback;
22221
+ const value = Number(storedValue);
22222
+ return Number.isFinite(value) ? clampFrozenColumnCount(value, columnCount) : fallback;
22223
+ } catch {
22224
+ return fallback;
22225
+ }
22226
+ }
22227
+ function persistFrozenEndColumnCount(storageKey, count) {
22228
+ const frozenStorageKey = getFrozenEndColumnStorageKey(storageKey);
22229
+ if (!frozenStorageKey || !isBrowser()) return;
22230
+ window.localStorage.setItem(frozenStorageKey, String(count));
22231
+ }
22232
+ function normalizeColumnOrder2(columnKeys, columnOrder) {
22233
+ const validColumnKeys = new Set(columnKeys);
22234
+ const orderedKeys = (columnOrder || []).filter((columnKey) => validColumnKeys.has(columnKey));
22235
+ const orderedKeySet = new Set(orderedKeys);
22236
+ const remainingKeys = columnKeys.filter((columnKey) => !orderedKeySet.has(columnKey));
22237
+ return [...orderedKeys, ...remainingKeys];
22238
+ }
22239
+ function getOrderedColumns2(columns, columnOrder) {
22240
+ const normalizedOrder = normalizeColumnOrder2(columns.map((column) => column.key), columnOrder);
22241
+ const columnMap = new Map(columns.map((column) => [column.key, column]));
22242
+ return normalizedOrder.map((columnKey) => columnMap.get(columnKey)).filter(Boolean);
22243
+ }
22244
+ function getColumnNumericWidth(column, columnSizes) {
22245
+ const controlledWidth = columnSizes[column.key];
22246
+ if (typeof controlledWidth === "number") return controlledWidth;
22247
+ return getColumnDefaultSize(column);
22248
+ }
22249
+ function buildFrozenOffsets(columns, columnSizes, frozenColumnCount) {
22250
+ const offsets = /* @__PURE__ */ new Map();
22251
+ let left = 0;
22252
+ columns.slice(0, Math.max(0, frozenColumnCount)).forEach((column) => {
22253
+ offsets.set(column.key, left);
22254
+ left += getColumnNumericWidth(column, columnSizes);
22255
+ });
22256
+ return offsets;
22257
+ }
22258
+ function buildFrozenEndOffsets(columns, columnSizes, frozenEndColumnCount) {
22259
+ const offsets = /* @__PURE__ */ new Map();
22260
+ let right = 0;
22261
+ columns.slice(Math.max(0, columns.length - frozenEndColumnCount)).reverse().forEach((column) => {
22262
+ offsets.set(column.key, right);
22263
+ right += getColumnNumericWidth(column, columnSizes);
22264
+ });
22265
+ return offsets;
22266
+ }
22267
+ function resolveRowClassName(rowClassName, row, rowIndex) {
22268
+ return typeof rowClassName === "function" ? rowClassName(row, rowIndex) : rowClassName;
22269
+ }
22270
+ function renderDefaultCell(column, row) {
22271
+ const value = row?.[column.key];
22272
+ if (value === void 0 || value === null || value === "") return "\u2014";
22273
+ return String(value);
22274
+ }
22275
+ function InteractiveTableCellContent({
22276
+ children,
22277
+ wrap
22278
+ }) {
22279
+ return /* @__PURE__ */ jsxRuntime.jsx(
22280
+ "div",
22281
+ {
22282
+ className: cn(
22283
+ "min-w-0 max-w-full overflow-auto overscroll-contain [scrollbar-width:thin]",
22284
+ wrap ? "max-h-20 whitespace-pre-wrap break-words leading-5" : "whitespace-nowrap"
22285
+ ),
22286
+ children
22287
+ }
22288
+ );
22289
+ }
22290
+ function PinIcon({ className }) {
22291
+ return /* @__PURE__ */ jsxRuntime.jsxs(
22292
+ "svg",
22293
+ {
22294
+ "aria-hidden": "true",
22295
+ viewBox: "0 0 16 16",
22296
+ className,
22297
+ fill: "none",
22298
+ stroke: "currentColor",
22299
+ strokeLinecap: "round",
22300
+ strokeLinejoin: "round",
22301
+ strokeWidth: "1.75",
22302
+ children: [
22303
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.25 2.75h5.5" }),
22304
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.25 2.75v4L4.5 9.25h7L9.75 6.75v-4" }),
22305
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 9.25v4" })
22306
+ ]
22307
+ }
22308
+ );
22309
+ }
22310
+ function InteractiveTable({
22311
+ rows = [],
22312
+ columns = [],
22313
+ pinnedTopRows = [],
22314
+ getRowKey = defaultGetRowKey2,
22315
+ getPinnedTopRowKey = defaultGetRowKey2,
22316
+ renderCell,
22317
+ renderPinnedTopCell,
22318
+ renderColumnHeader,
22319
+ onRowClick,
22320
+ getRowState,
22321
+ rowClassName,
22322
+ pinnedTopRowClassName,
22323
+ emptyState = "\u2014",
22324
+ columnMenuLabels,
22325
+ columnStorageKey,
22326
+ columnOrder,
22327
+ columnSizes,
22328
+ defaultColumnSizes,
22329
+ columnDragEnabled = false,
22330
+ columnResizeEnabled = true,
22331
+ frozenColumnCount = 0,
22332
+ frozenEndColumnCount = 0,
22333
+ tableMinWidth,
22334
+ bodyMaxHeight = "min(60vh, 42rem)",
22335
+ appearance,
22336
+ className,
22337
+ tableClassName,
22338
+ classNames,
22339
+ style,
22340
+ onColumnOrderChange,
22341
+ onColumnSizeChange,
22342
+ onResetColumnSizes,
22343
+ onFrozenColumnCountChange,
22344
+ onFrozenEndColumnCountChange,
22345
+ onSort
22346
+ }) {
22347
+ const columnKeySignature = columns.map((column) => column.key).join("");
22348
+ const defaultOrder = React.useMemo(
22349
+ () => columnKeySignature ? columnKeySignature.split("") : [],
22350
+ [columnKeySignature]
22351
+ );
22352
+ const defaultSizes = React.useMemo(
22353
+ () => buildDefaultColumnSizes(columns, defaultColumnSizes),
22354
+ [columns, defaultColumnSizes]
22355
+ );
22356
+ const [internalColumnOrder, setInternalColumnOrder] = React.useState(defaultOrder);
22357
+ const [internalColumnSizes, setInternalColumnSizes] = React.useState(() => loadStoredColumnSizes(columnStorageKey, defaultSizes));
22358
+ const [internalFrozenColumnCount, setInternalFrozenColumnCount] = React.useState(() => loadStoredFrozenColumnCount(columnStorageKey, frozenColumnCount, columns.length));
22359
+ const [internalFrozenEndColumnCount, setInternalFrozenEndColumnCount] = React.useState(() => loadStoredFrozenEndColumnCount(columnStorageKey, frozenEndColumnCount, columns.length));
22360
+ React.useEffect(() => {
22361
+ setInternalColumnOrder((current) => normalizeColumnOrder2(defaultOrder, current));
22362
+ }, [defaultOrder]);
22363
+ React.useEffect(() => {
22364
+ if (columnSizes) return;
22365
+ setInternalColumnSizes(loadStoredColumnSizes(columnStorageKey, defaultSizes));
22366
+ }, [columnSizes, columnStorageKey, defaultSizes]);
22367
+ React.useEffect(() => {
22368
+ setInternalFrozenColumnCount(loadStoredFrozenColumnCount(columnStorageKey, frozenColumnCount, columns.length));
22369
+ }, [columnStorageKey, columns.length, frozenColumnCount]);
22370
+ React.useEffect(() => {
22371
+ setInternalFrozenEndColumnCount(loadStoredFrozenEndColumnCount(columnStorageKey, frozenEndColumnCount, columns.length));
22372
+ }, [columnStorageKey, columns.length, frozenEndColumnCount]);
22373
+ const resolvedColumnOrder = columnOrder ? normalizeColumnOrder2(defaultOrder, columnOrder) : internalColumnOrder;
22374
+ const resolvedColumnSizes = columnSizes ?? internalColumnSizes;
22375
+ const orderedColumns = getOrderedColumns2(columns, resolvedColumnOrder);
22376
+ const {
22377
+ startCount: resolvedFrozenColumnCount,
22378
+ endCount: resolvedFrozenEndColumnCount
22379
+ } = normalizeFrozenColumnCounts(internalFrozenColumnCount, internalFrozenEndColumnCount, orderedColumns.length);
22380
+ const frozenOffsets = buildFrozenOffsets(orderedColumns, resolvedColumnSizes, resolvedFrozenColumnCount);
22381
+ const frozenEndOffsets = buildFrozenEndOffsets(orderedColumns, resolvedColumnSizes, resolvedFrozenEndColumnCount);
22382
+ const resolvedMinWidth = tableMinWidth ?? Math.max(760, orderedColumns.reduce((total, column) => total + getColumnNumericWidth(column, resolvedColumnSizes), 0));
22383
+ const labels = {
22384
+ columnActions: columnMenuLabels?.columnActions ?? "Column actions",
22385
+ freezeColumn: columnMenuLabels?.freezeColumn ?? "Freeze to left",
22386
+ freezeEndColumn: columnMenuLabels?.freezeEndColumn ?? "Freeze to right",
22387
+ unfreezeColumn: columnMenuLabels?.unfreezeColumn ?? "Unfreeze from left",
22388
+ unfreezeEndColumn: columnMenuLabels?.unfreezeEndColumn ?? "Unfreeze from right",
22389
+ unfreezeAllColumns: columnMenuLabels?.unfreezeAllColumns ?? "Unfreeze all columns",
22390
+ resetColumnWidth: columnMenuLabels?.resetColumnWidth ?? "Reset column width",
22391
+ frozenColumnTitle: columnMenuLabels?.frozenColumnTitle ?? "Frozen column"
22392
+ };
22393
+ const handleColumnOrderChange = React.useCallback((nextOrder, detail) => {
22394
+ const normalizedOrder = normalizeColumnOrder2(defaultOrder, nextOrder);
22395
+ if (!columnOrder) {
22396
+ setInternalColumnOrder(normalizedOrder);
22397
+ }
22398
+ onColumnOrderChange?.(normalizedOrder, detail);
22399
+ }, [columnOrder, defaultOrder, onColumnOrderChange]);
22400
+ const handleColumnSizeChange = React.useCallback((columnId, width, detail) => {
22401
+ const column = columns.find((item) => item.key === columnId);
22402
+ const minWidth = column?.minWidth;
22403
+ const maxWidth = column?.maxWidth;
22404
+ const nextWidth = Math.max(
22405
+ typeof minWidth === "number" ? minWidth : 0,
22406
+ Math.min(width, typeof maxWidth === "number" ? maxWidth : Number.POSITIVE_INFINITY)
22407
+ );
22408
+ const nextSizes = {
22409
+ ...resolvedColumnSizes,
22410
+ [columnId]: nextWidth
22411
+ };
22412
+ if (!columnSizes) {
22413
+ setInternalColumnSizes(nextSizes);
22414
+ }
22415
+ persistColumnSizes(columnStorageKey, nextSizes);
22416
+ onColumnSizeChange?.(columnId, nextWidth, detail);
22417
+ }, [columnSizes, columnStorageKey, columns, onColumnSizeChange, resolvedColumnSizes]);
22418
+ const handleResetColumnSize = React.useCallback((column) => {
22419
+ const nextWidth = defaultSizes[column.key] ?? getColumnDefaultSize(column);
22420
+ const previousWidth = getColumnNumericWidth(column, resolvedColumnSizes);
22421
+ const nextSizes = {
22422
+ ...resolvedColumnSizes,
22423
+ [column.key]: nextWidth
22424
+ };
22425
+ if (!columnSizes) {
22426
+ setInternalColumnSizes(nextSizes);
22427
+ }
22428
+ persistColumnSizes(columnStorageKey, nextSizes);
22429
+ onColumnSizeChange?.(column.key, nextWidth, {
22430
+ columnId: column.key,
22431
+ previousWidth,
22432
+ minWidth: column.minWidth,
22433
+ maxWidth: column.maxWidth
22434
+ });
22435
+ onResetColumnSizes?.(nextSizes);
22436
+ }, [columnSizes, columnStorageKey, defaultSizes, onColumnSizeChange, onResetColumnSizes, resolvedColumnSizes]);
22437
+ const setFrozenColumnCount = React.useCallback((nextCount) => {
22438
+ const normalizedCount = clampFrozenColumnCount(nextCount, Math.max(0, orderedColumns.length - resolvedFrozenEndColumnCount));
22439
+ setInternalFrozenColumnCount(normalizedCount);
22440
+ persistFrozenColumnCount(columnStorageKey, normalizedCount);
22441
+ onFrozenColumnCountChange?.(normalizedCount);
22442
+ }, [columnStorageKey, onFrozenColumnCountChange, orderedColumns.length, resolvedFrozenEndColumnCount]);
22443
+ const setFrozenEndColumnCount = React.useCallback((nextCount) => {
22444
+ const normalizedCount = clampFrozenColumnCount(nextCount, Math.max(0, orderedColumns.length - resolvedFrozenColumnCount));
22445
+ setInternalFrozenEndColumnCount(normalizedCount);
22446
+ persistFrozenEndColumnCount(columnStorageKey, normalizedCount);
22447
+ onFrozenEndColumnCountChange?.(normalizedCount);
22448
+ }, [columnStorageKey, onFrozenEndColumnCountChange, orderedColumns.length, resolvedFrozenColumnCount]);
22449
+ const getFrozenPosition = (columnIndex) => {
22450
+ if (columnIndex < resolvedFrozenColumnCount) return "start";
22451
+ if (columnIndex >= orderedColumns.length - resolvedFrozenEndColumnCount) return "end";
22452
+ return void 0;
22453
+ };
22454
+ const getFrozenClassName = (column, columnIndex, isHeader = false) => {
22455
+ const position = getFrozenPosition(columnIndex);
22456
+ if (!position) return void 0;
22457
+ return cn(
22458
+ "sticky",
22459
+ position === "start" ? "shadow-[1px_0_0_0_hsl(var(--border)/0.45)]" : "shadow-[-1px_0_0_0_hsl(var(--border)/0.45)]",
22460
+ isHeader ? "bg-muted/60" : "bg-inherit",
22461
+ isHeader ? "z-40" : "z-20",
22462
+ (columnIndex === 0 || columnIndex === orderedColumns.length - 1) && (isHeader ? "z-50" : "z-30")
22463
+ );
22464
+ };
22465
+ const getFrozenStyle = (column, columnIndex) => {
22466
+ const position = getFrozenPosition(columnIndex);
22467
+ if (position === "start") return { left: frozenOffsets.get(column.key) ?? 0 };
22468
+ if (position === "end") return { right: frozenEndOffsets.get(column.key) ?? 0 };
22469
+ return void 0;
22470
+ };
22471
+ return /* @__PURE__ */ jsxRuntime.jsx(
22472
+ BaseTableContainer,
22473
+ {
22474
+ appearance,
22475
+ className: cn("flex h-full min-h-0 flex-col overflow-hidden rounded-lg border border-border/60 bg-card", classNames?.root, className),
22476
+ style,
22477
+ children: /* @__PURE__ */ jsxRuntime.jsx(
22478
+ "div",
22479
+ {
22480
+ className: cn("min-h-0 flex-1 overflow-auto", classNames?.scrollArea),
22481
+ style: { maxHeight: toCssSize4(bodyMaxHeight) },
22482
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
22483
+ BaseTable,
22484
+ {
22485
+ appearance,
22486
+ columnOrder: resolvedColumnOrder,
22487
+ columnSizes: resolvedColumnSizes,
22488
+ columnDragEnabled,
22489
+ columnResizeEnabled,
22490
+ onColumnOrderChange: handleColumnOrderChange,
22491
+ onColumnSizeChange: handleColumnSizeChange,
22492
+ className: cn("w-full table-fixed text-left text-xs", classNames?.table, tableClassName),
22493
+ style: { minWidth: resolvedMinWidth },
22494
+ children: [
22495
+ /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: orderedColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
22496
+ "col",
22497
+ {
22498
+ style: {
22499
+ width: toCssSize4(resolvedColumnSizes[column.key] ?? column.width),
22500
+ minWidth: toCssSize4(column.minWidth)
22501
+ }
22502
+ },
22503
+ column.key
22504
+ )) }),
22505
+ /* @__PURE__ */ jsxRuntime.jsx(BaseTableHeader, { appearance, className: cn("border-b border-border/60 bg-muted/60 text-[11px] font-medium text-muted-foreground", classNames?.tableHeader), children: /* @__PURE__ */ jsxRuntime.jsx(BaseTableRow, { appearance, className: cn("hover:bg-transparent", classNames?.headerRow), children: orderedColumns.map((column, columnIndex) => {
22506
+ const headerContent = renderColumnHeader ? renderColumnHeader(column, { column, columnIndex, columns: orderedColumns, rows }) : column.label;
22507
+ const sortable = Boolean(column.sortable);
22508
+ const handleSort = sortable && onSort ? () => onSort(column.key, column) : void 0;
22509
+ const isFrozenStart = columnIndex < resolvedFrozenColumnCount;
22510
+ const isFrozenEnd = columnIndex >= orderedColumns.length - resolvedFrozenEndColumnCount;
22511
+ const isFrozen = isFrozenStart || isFrozenEnd;
22512
+ const isColumnAtDefaultWidth = getColumnNumericWidth(column, resolvedColumnSizes) === (defaultSizes[column.key] ?? getColumnDefaultSize(column));
22513
+ return /* @__PURE__ */ jsxRuntime.jsxs(BaseContextMenu, { modal: false, children: [
22514
+ /* @__PURE__ */ jsxRuntime.jsx(BaseContextMenuTrigger, { asChild: true, appearance, children: /* @__PURE__ */ jsxRuntime.jsx(
22515
+ BaseTableHead,
22516
+ {
22517
+ appearance,
22518
+ columnId: column.key,
22519
+ align: column.align,
22520
+ label: headerContent,
22521
+ description: column.description,
22522
+ trailing: isFrozen ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: labels.frozenColumnTitle, className: "inline-flex h-5 w-5 items-center justify-center rounded text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(PinIcon, { className: "h-3.5 w-3.5" }) }) : null,
22523
+ sortable,
22524
+ sortDirection: column.sortDirection,
22525
+ sortLabel: column.sortLabel,
22526
+ onSort: handleSort,
22527
+ draggable: column.draggable,
22528
+ resizable: column.resizable,
22529
+ width: column.width,
22530
+ minWidth: column.minWidth,
22531
+ maxWidth: column.maxWidth,
22532
+ className: cn(
22533
+ "sticky top-0 h-9 whitespace-nowrap border-r border-border/50 bg-muted/60 px-2.5 py-2 backdrop-blur",
22534
+ getFrozenClassName(column, columnIndex, true),
22535
+ column.headerClassName,
22536
+ column.className,
22537
+ classNames?.headerCell
22538
+ ),
22539
+ style: getFrozenStyle(column, columnIndex)
22540
+ }
22541
+ ) }),
22542
+ /* @__PURE__ */ jsxRuntime.jsxs(BaseContextMenuContent, { appearance, alignOffset: -4, className: "min-w-44", children: [
22543
+ /* @__PURE__ */ jsxRuntime.jsx(BaseContextMenuLabel, { appearance, children: labels.columnActions }),
22544
+ isFrozen ? /* @__PURE__ */ jsxRuntime.jsx(
22545
+ BaseContextMenuItem,
22546
+ {
22547
+ appearance,
22548
+ onSelect: () => {
22549
+ if (isFrozenEnd) setFrozenEndColumnCount(orderedColumns.length - columnIndex - 1);
22550
+ else setFrozenColumnCount(columnIndex);
22551
+ },
22552
+ children: isFrozenEnd ? labels.unfreezeEndColumn : labels.unfreezeColumn
22553
+ }
22554
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
22555
+ BaseContextMenuItem,
22556
+ {
22557
+ appearance,
22558
+ onSelect: () => setFrozenColumnCount(columnIndex + 1),
22559
+ children: labels.freezeColumn
22560
+ }
22561
+ ),
22562
+ !isFrozen ? /* @__PURE__ */ jsxRuntime.jsx(
22563
+ BaseContextMenuItem,
22564
+ {
22565
+ appearance,
22566
+ onSelect: () => setFrozenEndColumnCount(orderedColumns.length - columnIndex),
22567
+ children: labels.freezeEndColumn
22568
+ }
22569
+ ) : null,
22570
+ /* @__PURE__ */ jsxRuntime.jsx(
22571
+ BaseContextMenuItem,
22572
+ {
22573
+ appearance,
22574
+ disabled: resolvedFrozenColumnCount === 0 && resolvedFrozenEndColumnCount === 0,
22575
+ onSelect: () => {
22576
+ setFrozenColumnCount(0);
22577
+ setFrozenEndColumnCount(0);
22578
+ },
22579
+ children: labels.unfreezeAllColumns
22580
+ }
22581
+ ),
22582
+ /* @__PURE__ */ jsxRuntime.jsx(BaseContextMenuSeparator, { appearance }),
22583
+ /* @__PURE__ */ jsxRuntime.jsx(
22584
+ BaseContextMenuItem,
22585
+ {
22586
+ appearance,
22587
+ disabled: isColumnAtDefaultWidth,
22588
+ onSelect: () => handleResetColumnSize(column),
22589
+ children: labels.resetColumnWidth
22590
+ }
22591
+ )
22592
+ ] })
22593
+ ] }, column.key);
22594
+ }) }) }),
22595
+ /* @__PURE__ */ jsxRuntime.jsxs(BaseTableBody, { appearance, className: cn("divide-y divide-border/50", classNames?.body), children: [
22596
+ pinnedTopRows.map((row, rowIndex) => {
22597
+ const key = getPinnedTopRowKey(row, rowIndex);
22598
+ const resolvedRowClassName = resolveRowClassName(pinnedTopRowClassName, row, rowIndex);
22599
+ return /* @__PURE__ */ jsxRuntime.jsx(
22600
+ BaseTableRow,
22601
+ {
22602
+ appearance,
22603
+ className: cn("bg-card/95", classNames?.pinnedTopRow, resolvedRowClassName),
22604
+ children: orderedColumns.map((column, columnIndex) => /* @__PURE__ */ jsxRuntime.jsx(
22605
+ BaseTableCell,
22606
+ {
22607
+ appearance,
22608
+ align: column.align,
22609
+ className: cn(
22610
+ "h-[52px] border-r border-border/50 px-2.5 py-1.5 align-middle",
22611
+ column.wrap ? "whitespace-normal" : "whitespace-nowrap",
22612
+ getFrozenClassName(column, columnIndex),
22613
+ column.cellClassName,
22614
+ classNames?.cell
22615
+ ),
22616
+ style: getFrozenStyle(column, columnIndex),
22617
+ children: /* @__PURE__ */ jsxRuntime.jsx(InteractiveTableCellContent, { wrap: column.wrap, children: renderPinnedTopCell ? renderPinnedTopCell(column, row, { row, rowIndex, column, columnIndex, isPinnedTopRow: true }) : renderDefaultCell(column, row) })
22618
+ },
22619
+ `pinned-${key}-${column.key}`
22620
+ ))
22621
+ },
22622
+ `pinned-${key}`
22623
+ );
22624
+ }),
22625
+ rows.length ? rows.map((row, rowIndex) => {
22626
+ const key = getRowKey(row, rowIndex);
22627
+ const state = getRowState?.(row, rowIndex) || {};
22628
+ const resolvedRowClassName = resolveRowClassName(rowClassName, row, rowIndex);
22629
+ return /* @__PURE__ */ jsxRuntime.jsx(
22630
+ BaseTableRow,
22631
+ {
22632
+ appearance,
22633
+ interactive: Boolean(onRowClick) && !state.disabled,
22634
+ selected: state.selected,
22635
+ disabled: state.disabled,
22636
+ onClick: () => {
22637
+ if (!state.disabled) onRowClick?.(row, rowIndex);
22638
+ },
22639
+ className: cn(
22640
+ "min-h-[52px] bg-card transition-colors",
22641
+ state.saving && "bg-primary/5",
22642
+ state.pending && "opacity-80",
22643
+ onRowClick && !state.disabled ? "cursor-pointer hover:bg-muted/30" : "hover:bg-muted/30",
22644
+ classNames?.row,
22645
+ resolvedRowClassName
22646
+ ),
22647
+ children: orderedColumns.map((column, columnIndex) => /* @__PURE__ */ jsxRuntime.jsx(
22648
+ BaseTableCell,
22649
+ {
22650
+ appearance,
22651
+ align: column.align,
22652
+ className: cn(
22653
+ "h-[52px] border-r border-border/50 px-2.5 py-1.5 align-middle",
22654
+ column.wrap ? "whitespace-normal" : "whitespace-nowrap",
22655
+ getFrozenClassName(column, columnIndex),
22656
+ column.cellClassName,
22657
+ classNames?.cell
22658
+ ),
22659
+ style: getFrozenStyle(column, columnIndex),
22660
+ children: /* @__PURE__ */ jsxRuntime.jsx(InteractiveTableCellContent, { wrap: column.wrap, children: renderCell ? renderCell(column, row, { row, rowIndex, column, columnIndex, isPinnedTopRow: false }) : renderDefaultCell(column, row) })
22661
+ },
22662
+ `${key}-${column.key}`
22663
+ ))
22664
+ },
22665
+ key
22666
+ );
22667
+ }) : pinnedTopRows.length ? null : /* @__PURE__ */ jsxRuntime.jsx(
22668
+ BaseTableEmpty,
22669
+ {
22670
+ appearance,
22671
+ colSpan: Math.max(orderedColumns.length, 1),
22672
+ className: classNames?.empty,
22673
+ children: emptyState
22674
+ }
22675
+ )
22676
+ ] })
22677
+ ]
22678
+ }
22679
+ )
22680
+ }
22681
+ )
22682
+ }
22683
+ );
22684
+ }
22685
+ function InteractiveTableEditableTextCell({
22686
+ value,
22687
+ placeholder,
22688
+ disabled,
22689
+ multiline = false,
22690
+ commitOnBlur = true,
22691
+ className,
22692
+ inputClassName,
22693
+ onCommit
22694
+ }) {
22695
+ const initialValue = String(value || "");
22696
+ const [draft, setDraft] = React.useState(initialValue);
22697
+ React.useEffect(() => {
22698
+ setDraft(initialValue);
22699
+ }, [initialValue]);
22700
+ const commit = React.useCallback(async () => {
22701
+ const nextValue = String(draft || "").trim();
22702
+ const previousValue = String(initialValue || "").trim();
22703
+ if (nextValue === previousValue) return;
22704
+ try {
22705
+ await onCommit?.(nextValue);
22706
+ } catch {
22707
+ setDraft(initialValue);
22708
+ }
22709
+ }, [draft, initialValue, onCommit]);
22710
+ const controlClassName = cn(
22711
+ "w-full resize-none rounded-sm border border-transparent bg-transparent px-1.5 py-1 text-xs text-foreground outline-none transition-colors",
22712
+ "placeholder:text-muted-foreground/70 hover:border-border/60 hover:bg-background focus:border-primary/45 focus:bg-background",
22713
+ multiline ? "min-h-[42px] leading-5" : "h-8",
22714
+ disabled && "cursor-not-allowed text-muted-foreground hover:border-transparent hover:bg-transparent",
22715
+ inputClassName
22716
+ );
22717
+ if (multiline) {
22718
+ return /* @__PURE__ */ jsxRuntime.jsx(
22719
+ "textarea",
22720
+ {
22721
+ className: cn(controlClassName, className),
22722
+ disabled,
22723
+ value: draft,
22724
+ placeholder,
22725
+ onChange: (event) => setDraft(event.target.value),
22726
+ onBlur: () => {
22727
+ if (commitOnBlur) void commit();
22728
+ },
22729
+ onKeyDown: (event) => {
22730
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
22731
+ event.currentTarget.blur();
22732
+ }
22733
+ if (event.key === "Escape") {
22734
+ setDraft(initialValue);
22735
+ event.currentTarget.blur();
22736
+ }
22737
+ }
22738
+ }
22739
+ );
22740
+ }
22741
+ return /* @__PURE__ */ jsxRuntime.jsx(
22742
+ "input",
22743
+ {
22744
+ className: cn(controlClassName, className),
22745
+ disabled,
22746
+ value: draft,
22747
+ placeholder,
22748
+ onChange: (event) => setDraft(event.target.value),
22749
+ onBlur: () => {
22750
+ if (commitOnBlur) void commit();
22751
+ },
22752
+ onKeyDown: (event) => {
22753
+ if (event.key === "Enter") event.currentTarget.blur();
22754
+ if (event.key === "Escape") {
22755
+ setDraft(initialValue);
22756
+ event.currentTarget.blur();
22757
+ }
22758
+ }
22759
+ }
22760
+ );
22761
+ }
22762
+ function InteractiveTableReadonlyCell({
22763
+ children,
22764
+ mono = false,
22765
+ className
22766
+ }) {
22767
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("min-w-0 text-xs text-muted-foreground", mono && "font-mono", className), children: hasRenderableNode(children) ? children : "\u2014" });
22768
+ }
22769
+ function InteractiveTableSelectCell({
22770
+ value,
22771
+ options,
22772
+ disabled,
22773
+ ariaLabel,
22774
+ children,
22775
+ className,
22776
+ onChange
22777
+ }) {
22778
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative flex w-full items-center", className), children: [
22779
+ children,
22780
+ /* @__PURE__ */ jsxRuntime.jsx(
22781
+ "select",
22782
+ {
22783
+ "aria-label": ariaLabel,
22784
+ disabled,
22785
+ value,
22786
+ onChange: (event) => onChange?.(event.target.value),
22787
+ className: "absolute inset-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed",
22788
+ children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))
22789
+ }
22790
+ )
22791
+ ] });
22792
+ }
22793
+ var imageExtPattern = /\.(png|jpe?g|webp|gif|svg|bmp|avif)$/i;
22794
+ var audioExtPattern = /\.(wav|mp3|ogg|m4a|flac|aac)$/i;
22795
+ var isLikelyUrl = (value) => /^https?:\/\//i.test(String(value || ""));
22796
+ var getColumnRenderKind = (column) => String(column?.renderType || column?.type || "").toLowerCase();
22797
+ var isImageLikeValue = (value) => String(value || "").startsWith("data:image/") || imageExtPattern.test(String(value || ""));
22798
+ var isAudioLikeValue = (value) => String(value || "").startsWith("data:audio/") || audioExtPattern.test(String(value || ""));
22799
+ var escapeSvgText = (value) => String(value || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
22800
+ var getDefaultGalleryFieldValue = (column, row) => {
22801
+ if (!column) return null;
22802
+ return row?.[column.key] ?? null;
22803
+ };
22804
+ var getDefaultGalleryDisplayText = (value) => {
22805
+ if (value === null || value === void 0 || value === "") return "\u2014";
22806
+ if (Array.isArray(value)) {
22807
+ const parts = value.map((item) => {
22808
+ if (typeof item === "string") return item;
22809
+ if (!item || typeof item !== "object") return "";
22810
+ const objectItem = item;
22811
+ return objectItem.text || objectItem.label || objectItem.title || objectItem.display || objectItem.value || objectItem.recordId || "";
22812
+ }).filter(Boolean);
22813
+ return parts.join(" \xB7 ") || "\u2014";
22814
+ }
22815
+ if (typeof value === "object") {
22816
+ const objectValue = value;
22817
+ return String(objectValue.text || objectValue.label || objectValue.title || objectValue.display || objectValue.value || "\u2014");
22818
+ }
22819
+ return String(value);
22820
+ };
22821
+ var isDefaultGalleryImageField = (column = { key: "" }, value) => getColumnRenderKind(column) === "image" || isImageLikeValue(value);
22822
+ var isDefaultGalleryAudioField = (column = { key: "" }, value) => getColumnRenderKind(column) === "audio" || isAudioLikeValue(value);
22823
+ var getDefaultGalleryImagePreviewSrc = (value, rowId, columnLabel) => {
22824
+ if (isLikelyUrl(value) || String(value || "").startsWith("data:image/")) return String(value);
22825
+ const title = escapeSvgText(value || columnLabel || rowId || "");
22826
+ const titleText = title ? `<text x='68' y='450' fill='white' font-family='Inter, Arial' font-size='52' font-weight='700'>${title}</text>` : "";
22827
+ const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 960 540'><defs><linearGradient id='g' x1='0' y1='0' x2='1' y2='1'><stop offset='0%' stop-color='#0f172a'/><stop offset='55%' stop-color='#1d4ed8'/><stop offset='100%' stop-color='#14b8a6'/></linearGradient></defs><rect width='960' height='540' fill='url(#g)'/><g opacity='0.28'><circle cx='780' cy='130' r='150' fill='#67e8f9'/><circle cx='180' cy='430' r='170' fill='#a78bfa'/></g>${titleText}</svg>`;
22828
+ return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
22829
+ };
22830
+ var isDefaultGalleryMediaColumn = (column, row, {
22831
+ getFieldValue = getDefaultGalleryFieldValue,
22832
+ shouldEnhanceMultimodal = true,
22833
+ isImageField = isDefaultGalleryImageField,
22834
+ isAudioField = isDefaultGalleryAudioField
22835
+ } = {}) => {
22836
+ if (!column || !shouldEnhanceMultimodal) return false;
22837
+ const value = getFieldValue(column, row);
22838
+ return isImageField(column, value) || isAudioField(column, value);
22839
+ };
22840
+ var isDefaultGalleryTitleCandidate = (column, row, { isMediaColumn = () => false } = {}) => {
22841
+ if (!column || column.renderType === "icon") return false;
22842
+ return !isMediaColumn(column, row);
22843
+ };
22844
+ var isDefaultGallerySummaryCandidate = (column, row, { isMediaColumn = () => false } = {}) => {
22845
+ if (!column || column.renderType === "icon") return false;
22846
+ return !isMediaColumn(column, row);
22847
+ };
22848
+ var renderDefaultGalleryFieldValue = (column, row, {
22849
+ compact = false,
22850
+ getFieldValue = getDefaultGalleryFieldValue,
22851
+ getDisplayText = getDefaultGalleryDisplayText
22852
+ } = {}) => {
22853
+ const value = getFieldValue(column, row);
22854
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("leading-relaxed", compact && column?.wrap === true && "line-clamp-2 block"), children: getDisplayText(value) });
22855
+ };
22856
+ var getDefaultGalleryDetailLimit = (density) => {
22857
+ if (density === "compact") return 2;
22858
+ if (density === "detailed") return 6;
22859
+ return 4;
22860
+ };
22861
+ var getNormalizedGalleryBentoColumns = (columns, density) => {
22862
+ if (columns === 1 || columns === 2 || columns === 3) return Number(columns);
22863
+ return density === "detailed" ? 1 : 2;
22864
+ };
22865
+ var getNormalizedGalleryDetailLimit = ({
22866
+ density,
22867
+ visibility,
22868
+ limit
22869
+ }) => {
22870
+ if (visibility === "all") return Number.POSITIVE_INFINITY;
22871
+ const parsedLimit = Number.parseInt(String(limit), 10);
22872
+ if (Number.isFinite(parsedLimit) && parsedLimit > 0) return parsedLimit;
22873
+ return getDefaultGalleryDetailLimit(density);
22874
+ };
22875
+ var getGalleryCardPaddingClassName = (density) => {
22876
+ if (density === "compact") return "p-3";
22877
+ if (density === "detailed") return "p-4";
22878
+ return "p-3.5";
22879
+ };
22880
+ var getGalleryPreviewClassName = (density, isMasonry) => {
22881
+ if (isMasonry) return "h-auto w-full object-cover";
22882
+ if (density === "compact") return "h-32 w-full object-cover";
22883
+ if (density === "detailed") return "h-48 w-full object-cover";
22884
+ return "h-40 w-full object-cover";
22885
+ };
22886
+ var getGalleryDetailGridClassName = (columns) => {
22887
+ if (columns === 1) return "grid-cols-1";
22888
+ if (columns === 3) return "grid-cols-1 sm:grid-cols-2 2xl:grid-cols-3";
22889
+ return "grid-cols-1 sm:grid-cols-2";
22890
+ };
22891
+ function getIconComponent(icon) {
22892
+ return getWorkbenchIconComponent(icon);
22893
+ }
22894
+ function defaultFormatLabel2(value) {
22895
+ return value;
22896
+ }
22897
+ function getLabelText(value) {
22898
+ if (typeof value === "string" || typeof value === "number") return String(value);
22899
+ return "";
22900
+ }
22901
+ function WorkbenchGalleryCard({
22902
+ row,
22903
+ columns,
22904
+ onClick = () => {
22905
+ },
22906
+ isSelected = false,
22907
+ isMasonry = false,
22908
+ galleryFieldKey = "auto",
22909
+ galleryDensity = "comfortable",
22910
+ galleryBentoColumns,
22911
+ galleryDetailVisibility = "limit",
22912
+ galleryDetailLimit,
22913
+ shouldEnhanceMultimodal = true,
22914
+ getFieldValue,
22915
+ isMediaColumn,
22916
+ isTitleCandidate,
22917
+ isSummaryCandidate,
22918
+ getDisplayText,
22919
+ renderFieldValue,
22920
+ getImagePreviewSrc,
22921
+ isImageField,
22922
+ isAudioField,
22923
+ AudioPlayerComponent,
22924
+ cardVariant = "default",
22925
+ renderPreview,
22926
+ renderMeta,
22927
+ renderLeadingVisual,
22928
+ resolveRecordVisual,
22929
+ hiddenDetailFieldKeys = [],
22930
+ labels,
22931
+ formatLabel = defaultFormatLabel2,
22932
+ className
22933
+ }) {
22934
+ const resolvedGetFieldValue = getFieldValue || getDefaultGalleryFieldValue;
22935
+ const resolvedGetDisplayText = getDisplayText || getDefaultGalleryDisplayText;
22936
+ const resolvedIsImageField = isImageField || isDefaultGalleryImageField;
22937
+ const resolvedIsAudioField = isAudioField || isDefaultGalleryAudioField;
22938
+ const resolvedGetImagePreviewSrc = getImagePreviewSrc || getDefaultGalleryImagePreviewSrc;
22939
+ const resolvedIsMediaColumn = isMediaColumn || ((column, candidateRow) => isDefaultGalleryMediaColumn(column, candidateRow, {
22940
+ getFieldValue: resolvedGetFieldValue,
22941
+ shouldEnhanceMultimodal,
22942
+ isImageField: resolvedIsImageField,
22943
+ isAudioField: resolvedIsAudioField
22944
+ }));
22945
+ const resolvedIsTitleCandidate = isTitleCandidate || ((column, candidateRow) => isDefaultGalleryTitleCandidate(column, candidateRow, { isMediaColumn: resolvedIsMediaColumn }));
22946
+ const resolvedIsSummaryCandidate = isSummaryCandidate || ((column, candidateRow) => isDefaultGallerySummaryCandidate(column, candidateRow, { isMediaColumn: resolvedIsMediaColumn }));
22947
+ const resolvedRenderFieldValue = renderFieldValue || ((column, candidateRow, { compact } = {}) => renderDefaultGalleryFieldValue(column, candidateRow, {
22948
+ compact,
22949
+ getFieldValue: resolvedGetFieldValue,
22950
+ getDisplayText: resolvedGetDisplayText
22951
+ }));
22952
+ const isPreviewOnly = cardVariant === "preview-only";
22953
+ const isImageOnly = cardVariant === "image-only";
22954
+ const isChromaticBento = cardVariant === "chromatic-bento";
22955
+ const selectedGalleryColumn = galleryFieldKey !== "auto" ? columns.find((column) => column.key === galleryFieldKey && resolvedIsMediaColumn(column, row)) : null;
22956
+ const mediaColumn = selectedGalleryColumn || (shouldEnhanceMultimodal ? columns.find((column) => resolvedIsMediaColumn(column, row)) : null);
22957
+ const iconColumn = columns.find((column) => column.renderType === "icon");
22958
+ const iconVisual = iconColumn && resolveRecordVisual ? resolveRecordVisual(row[iconColumn.key], row, iconColumn) : null;
22959
+ const IconComponent = getIconComponent(iconVisual?.Icon || iconVisual?.icon);
22960
+ const mediaValue = mediaColumn ? resolvedGetFieldValue(mediaColumn, row) : null;
22961
+ const isImageMedia = mediaColumn ? resolvedIsImageField(mediaColumn, mediaValue) : false;
22962
+ const isAudioMedia = mediaColumn ? resolvedIsAudioField(mediaColumn, mediaValue) : false;
22963
+ const contentColumns = columns.filter((column) => column.key !== mediaColumn?.key && column.renderType !== "icon");
22964
+ const titleCandidates = contentColumns.filter((column) => {
22965
+ if (!column || resolvedIsMediaColumn(column, row) || !resolvedIsTitleCandidate(column, row)) return false;
22966
+ const value = resolvedGetFieldValue(column, row);
22967
+ return !(value === null || value === void 0 || value === "");
22968
+ });
22969
+ const titleColumn = titleCandidates[0] || null;
22970
+ const titleText = titleColumn ? resolvedGetDisplayText(resolvedGetFieldValue(titleColumn, row)) : resolvedGetDisplayText(row.linkKey || row.id);
22971
+ const summaryColumn = contentColumns.find((column) => {
22972
+ if (!column || column.key === titleColumn?.key || resolvedIsMediaColumn(column, row) || !resolvedIsSummaryCandidate(column, row)) return false;
22973
+ const summaryText2 = String(resolvedGetDisplayText(resolvedGetFieldValue(column, row)));
22974
+ return summaryText2 !== "\u2014" && summaryText2.length > 12;
22975
+ }) || contentColumns.find((column) => {
22976
+ if (!column || column.key === titleColumn?.key || resolvedIsMediaColumn(column, row) || !resolvedIsSummaryCandidate(column, row)) return false;
22977
+ const fallbackText = String(resolvedGetDisplayText(resolvedGetFieldValue(column, row)));
22978
+ return fallbackText !== "\u2014";
22979
+ }) || null;
22980
+ const summaryText = summaryColumn ? resolvedGetDisplayText(resolvedGetFieldValue(summaryColumn, row)) : "";
22981
+ const hiddenDetailKeySet = new Set(hiddenDetailFieldKeys);
22982
+ const detailColumns = contentColumns.filter((column) => column.key !== titleColumn?.key && column.key !== summaryColumn?.key && !hiddenDetailKeySet.has(column.key));
22983
+ const resolvedDetailLimit = getNormalizedGalleryDetailLimit({
22984
+ density: galleryDensity,
22985
+ visibility: galleryDetailVisibility,
22986
+ limit: galleryDetailLimit
22987
+ });
22988
+ const visibleDetailColumns = Number.isFinite(resolvedDetailLimit) ? detailColumns.slice(0, resolvedDetailLimit) : detailColumns;
22989
+ const isDetailedCard = galleryDensity === "detailed";
22990
+ const resolvedBentoColumns = getNormalizedGalleryBentoColumns(galleryBentoColumns, galleryDensity);
22991
+ const cardPaddingClassName = getGalleryCardPaddingClassName(galleryDensity);
22992
+ const detailGridClassName = getGalleryDetailGridClassName(resolvedBentoColumns);
22993
+ const previewClassName = isImageOnly ? "block h-auto w-full transition-transform duration-500 group-hover:scale-[1.02]" : getGalleryPreviewClassName(galleryDensity, isMasonry);
22994
+ const customPreview = typeof renderPreview === "function" ? renderPreview({
22995
+ row,
22996
+ mediaColumn,
22997
+ mediaValue,
22998
+ isImageMedia,
22999
+ isAudioMedia,
23000
+ iconVisual,
23001
+ IconComponent,
23002
+ previewClassName
23003
+ }) : null;
23004
+ const metaContent = typeof renderMeta === "function" ? renderMeta({
23005
+ row,
23006
+ contentColumns,
23007
+ detailColumns,
23008
+ titleColumn,
23009
+ summaryColumn,
23010
+ getDisplayText: resolvedGetDisplayText,
23011
+ getFieldValue: resolvedGetFieldValue
23012
+ }) : null;
23013
+ const customLeadingVisual = typeof renderLeadingVisual === "function" ? renderLeadingVisual({
23014
+ row,
23015
+ contentColumns,
23016
+ detailColumns,
23017
+ titleColumn,
23018
+ summaryColumn,
23019
+ iconVisual,
23020
+ getDisplayText: resolvedGetDisplayText,
23021
+ getFieldValue: resolvedGetFieldValue
23022
+ }) : null;
23023
+ const defaultLeadingVisual = !customLeadingVisual && iconVisual ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex h-9 w-9 items-center justify-center rounded-lg border", iconVisual.chipClassName || "border-primary/20 bg-primary/10 text-primary"), children: renderWorkbenchIcon(iconVisual.Icon || iconVisual.icon, cn("h-4 w-4", iconVisual.iconClassName || "text-primary")) }) : null;
23024
+ const leadingVisual = customLeadingVisual || defaultLeadingVisual;
23025
+ const defaultMetaClassName = isChromaticBento ? "shrink-0 rounded-full border border-border/40 bg-muted/25 px-2.5 py-1 text-[10px] text-muted-foreground transition-all duration-300 group-hover:border-primary/30 group-hover:bg-primary/10 group-hover:text-primary dark:border-border/35 dark:bg-muted/15" : "shrink-0 rounded-md border border-border/40 bg-muted/25 px-2 py-1 text-[10px] text-muted-foreground dark:border-border/35 dark:bg-muted/15";
23026
+ const detailCellClassName = isChromaticBento ? "rounded-xl border border-border/35 bg-muted/20 px-3 py-2.5 transition-all duration-300 group-hover:border-primary/25 group-hover:bg-primary/5 dark:border-border/30 dark:bg-muted/10" : "rounded-lg border border-border/35 bg-muted/20 px-2.5 py-2 dark:border-border/30 dark:bg-muted/10";
23027
+ const detailLabelClassName = isChromaticBento ? "text-[10px] uppercase tracking-[0.14em] text-muted-foreground transition-colors duration-300 group-hover:text-foreground" : "text-[10px] uppercase tracking-[0.12em] text-muted-foreground";
23028
+ const detailValueClassName = isChromaticBento ? "mt-1.5 text-[11px] text-muted-foreground transition-colors duration-300 group-hover:text-foreground [&_*]:max-w-full [&_pre]:text-[11px] [&_pre]:leading-relaxed" : "mt-1.5 text-[11px] text-foreground [&_*]:max-w-full [&_pre]:text-[11px] [&_pre]:leading-relaxed";
23029
+ const fieldCountLabel = labels?.fieldCount?.(contentColumns.length);
23030
+ const coverOnlyHint = labels?.coverOnlyHint;
23031
+ return /* @__PURE__ */ jsxRuntime.jsxs(
23032
+ "button",
23033
+ {
23034
+ type: "button",
23035
+ onClick,
23036
+ "aria-label": getLabelText(titleText),
23037
+ className: cn(
23038
+ "group relative w-full text-left transition-all duration-300",
23039
+ isImageOnly ? "overflow-hidden rounded-xl bg-transparent p-0 shadow-none" : isPreviewOnly ? "overflow-hidden rounded-3xl bg-transparent p-0" : cn("overflow-hidden rounded-xl border", isChromaticBento && "rounded-3xl shadow-none"),
23040
+ !isPreviewOnly && !isImageOnly && cardPaddingClassName,
23041
+ !isPreviewOnly && !isImageOnly && (isSelected ? isChromaticBento ? "border-primary/35 bg-background/85 ring-1 ring-primary/20" : "border-primary/40 bg-primary/10 ring-1 ring-primary/30" : isChromaticBento ? "workbench-surface-card hover:-translate-y-1 hover:border-primary/20" : "workbench-surface-card hover:border-primary/30"),
23042
+ isPreviewOnly && isSelected && "ring-1 ring-primary/30",
23043
+ isImageOnly && (isSelected ? "ring-1 ring-primary/30" : "hover:-translate-y-0.5"),
23044
+ isMasonry ? "block h-full w-full min-w-0" : "h-full min-w-0",
23045
+ className
23046
+ ),
23047
+ children: [
23048
+ isChromaticBento ? /* @__PURE__ */ jsxRuntime.jsx(
23049
+ "div",
23050
+ {
23051
+ "aria-hidden": "true",
23052
+ className: cn(
23053
+ "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_right,rgba(34,211,238,0.18),transparent_40%),radial-gradient(circle_at_bottom_left,rgba(16,185,129,0.12),transparent_45%)] opacity-0 transition-opacity duration-300",
23054
+ isSelected ? "opacity-100" : "group-hover:opacity-100"
23055
+ )
23056
+ }
23057
+ ) : null,
23058
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-[1]", children: [
23059
+ customPreview ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23060
+ isImageMedia && mediaColumn ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
23061
+ "overflow-hidden bg-card/50",
23062
+ isImageOnly ? "rounded-xl bg-transparent" : isPreviewOnly ? "rounded-3xl" : "mb-3 rounded-lg border border-border/70"
23063
+ ), children: /* @__PURE__ */ jsxRuntime.jsx(
23064
+ "img",
23065
+ {
23066
+ src: resolvedGetImagePreviewSrc(mediaValue, row.id, mediaColumn.label),
23067
+ alt: String(mediaValue || mediaColumn.label || ""),
23068
+ className: previewClassName,
23069
+ loading: "lazy",
23070
+ referrerPolicy: "no-referrer",
23071
+ onError: (event) => {
23072
+ event.currentTarget.onerror = null;
23073
+ event.currentTarget.src = resolvedGetImagePreviewSrc("", row.id, mediaColumn.label);
23074
+ }
23075
+ }
23076
+ ) }) : null,
23077
+ !isImageMedia && iconVisual && isPreviewOnly ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
23078
+ "flex items-center justify-center",
23079
+ isPreviewOnly ? cn("rounded-3xl border py-10", iconVisual.chipClassName || "border-primary/20 bg-primary/5") : "mb-3 h-24 rounded-lg border border-border/60 bg-primary/5"
23080
+ ), children: renderWorkbenchIcon(iconVisual.Icon || iconVisual.icon, cn("h-10 w-10", iconVisual.iconClassName || "text-primary")) }) : null,
23081
+ isAudioMedia && AudioPlayerComponent ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(!isPreviewOnly && "mb-3"), children: /* @__PURE__ */ jsxRuntime.jsx(AudioPlayerComponent, { filename: String(mediaValue) }) }) : null
23082
+ ] }),
23083
+ !isPreviewOnly && !isImageOnly ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23084
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
23085
+ leadingVisual ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: leadingVisual }) : null,
23086
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-start justify-between gap-3", children: [
23087
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
23088
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
23089
+ "flex items-center gap-2 text-sm font-semibold",
23090
+ isChromaticBento ? "text-muted-foreground transition-colors duration-300 group-hover:text-foreground" : "text-foreground"
23091
+ ), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: titleText }) }),
23092
+ summaryText && summaryText !== titleText ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
23093
+ "mt-1 text-[11px] leading-5 text-muted-foreground",
23094
+ isDetailedCard ? "line-clamp-4" : "line-clamp-2",
23095
+ isChromaticBento && "transition-colors duration-300 group-hover:text-foreground"
23096
+ ), children: summaryText }) : null
23097
+ ] }),
23098
+ metaContent ?? (hasRenderableNode(fieldCountLabel) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: defaultMetaClassName, children: fieldCountLabel }) : null)
23099
+ ] })
23100
+ ] }),
23101
+ visibleDetailColumns.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mt-3 grid grid-flow-row gap-2", detailGridClassName), children: visibleDetailColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: detailCellClassName, children: [
23102
+ column.label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: detailLabelClassName, children: formatLabel(column.label, { column }) }) : null,
23103
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(detailValueClassName, !column.label && "mt-0"), children: resolvedRenderFieldValue(column, row, { compact: galleryDensity !== "detailed", surface: "gallery" }) })
23104
+ ] }, `${row.id || row.linkKey}-${column.key}`)) }) : null,
23105
+ !summaryText && visibleDetailColumns.length === 0 && hasRenderableNode(coverOnlyHint) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
23106
+ "mt-3 text-[11px] text-muted-foreground",
23107
+ isChromaticBento && "transition-colors duration-300 group-hover:text-foreground"
23108
+ ), children: coverOnlyHint }) : null
23109
+ ] }) : null
23110
+ ] })
23111
+ ]
23112
+ }
23113
+ );
23114
+ }
23115
+ var DEFAULT_MASONRY_GAP_PX = 12;
23116
+ var DEFAULT_MASONRY_ROW_HEIGHT_PX = 8;
23117
+ var DEFAULT_MASONRY_COLUMN_WIDTH_PX = 280;
23118
+ var DEFAULT_MASONRY_ITEM_HEIGHT_PX = 240;
23119
+ function clamp4(value, min5, max5) {
23120
+ return Math.min(Math.max(value, min5), max5);
23121
+ }
23122
+ function getRootFontSize(node) {
23123
+ if (typeof window === "undefined") return 16;
23124
+ const target = node || document.documentElement;
23125
+ const parsed = Number.parseFloat(window.getComputedStyle(target).fontSize);
23126
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;
23127
+ }
23128
+ function resolveLengthToPixels(value, fallback, node) {
23129
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
23130
+ if (typeof value !== "string") return fallback;
23131
+ const normalized = value.trim().toLowerCase();
23132
+ if (!normalized) return fallback;
23133
+ if (/^\d+(\.\d+)?$/.test(normalized)) {
23134
+ const parsed = Number.parseFloat(normalized);
23135
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
23136
+ }
23137
+ if (normalized.endsWith("px")) {
23138
+ const parsed = Number.parseFloat(normalized);
23139
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
23140
+ }
23141
+ if (normalized.endsWith("rem")) {
23142
+ const parsed = Number.parseFloat(normalized);
23143
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
23144
+ return parsed * getRootFontSize(node);
23145
+ }
23146
+ return fallback;
23147
+ }
23148
+ function areMeasurementMapsEqual(prev, next) {
23149
+ const prevKeys = Object.keys(prev);
23150
+ const nextKeys = Object.keys(next);
23151
+ if (prevKeys.length !== nextKeys.length) return false;
23152
+ for (const key of nextKeys) {
23153
+ if (prev[key] !== next[key]) return false;
23154
+ }
23155
+ return true;
23156
+ }
23157
+ function getMasonryColumnCount({
23158
+ containerWidth,
23159
+ itemCount,
23160
+ targetColumnWidth,
23161
+ gap
23162
+ }) {
23163
+ if (!containerWidth) return 1;
23164
+ const safeItemCount = Math.max(itemCount, 1);
23165
+ const maxCandidate = Math.max(
23166
+ 1,
23167
+ Math.min(
23168
+ safeItemCount,
23169
+ Math.ceil((containerWidth + gap) / (Math.max(targetColumnWidth * 0.58, 1) + gap))
23170
+ )
23171
+ );
23172
+ let bestCount = 1;
23173
+ let bestScore = Number.POSITIVE_INFINITY;
23174
+ for (let candidateCount = 1; candidateCount <= maxCandidate; candidateCount += 1) {
23175
+ const actualColumnWidth = (containerWidth - gap * Math.max(candidateCount - 1, 0)) / candidateCount;
23176
+ if (!Number.isFinite(actualColumnWidth) || actualColumnWidth <= 0) continue;
23177
+ const underflowPenalty = Math.max(0, targetColumnWidth * 0.78 - actualColumnWidth);
23178
+ const overflowPenalty = Math.max(0, actualColumnWidth - targetColumnWidth * 1.35);
23179
+ const candidateScore = Math.abs(actualColumnWidth - targetColumnWidth) + underflowPenalty * 3 + overflowPenalty * 2;
23180
+ if (candidateScore < bestScore) {
23181
+ bestScore = candidateScore;
23182
+ bestCount = candidateCount;
23183
+ }
23184
+ }
23185
+ return bestCount;
23186
+ }
23187
+ function getItemColumnSpan({
23188
+ size,
23189
+ columnWidth,
23190
+ columnCount,
23191
+ gap
23192
+ }) {
23193
+ if (Number.isFinite(size?.columnSpan) && Number(size?.columnSpan) > 0) {
23194
+ return clamp4(Math.round(Number(size?.columnSpan)), 1, columnCount);
23195
+ }
23196
+ const itemWidth = resolveLengthToPixels(size?.width, columnWidth, null);
23197
+ return clamp4(Math.ceil((itemWidth + gap) / (columnWidth + gap)), 1, columnCount);
23198
+ }
23199
+ function getItemRowSpan({
23200
+ size,
23201
+ measuredHeight,
23202
+ rowHeight,
23203
+ gap
23204
+ }) {
23205
+ if (Number.isFinite(size?.rowSpan) && Number(size?.rowSpan) > 0) {
23206
+ return Math.max(1, Math.round(Number(size?.rowSpan)));
23207
+ }
23208
+ const itemHeight = Number.isFinite(measuredHeight) && Number(measuredHeight) > 0 ? Number(measuredHeight) : resolveLengthToPixels(size?.height, DEFAULT_MASONRY_ITEM_HEIGHT_PX, null);
23209
+ return Math.max(1, Math.ceil((itemHeight + gap) / (rowHeight + gap)));
23210
+ }
23211
+ function getResolvedItemHeight({
23212
+ size,
23213
+ measuredHeight
23214
+ }) {
23215
+ return Number.isFinite(measuredHeight) && Number(measuredHeight) > 0 ? Number(measuredHeight) : resolveLengthToPixels(size?.height, DEFAULT_MASONRY_ITEM_HEIGHT_PX, null);
23216
+ }
23217
+ function WorkbenchMasonryLayout({
23218
+ items = [],
23219
+ renderItem,
23220
+ getItemKey = (item, index) => item?.id ?? item?.key ?? index,
23221
+ getItemSize,
23222
+ columnWidth = DEFAULT_MASONRY_COLUMN_WIDTH_PX,
23223
+ gap = DEFAULT_MASONRY_GAP_PX,
23224
+ rowHeight = DEFAULT_MASONRY_ROW_HEIGHT_PX,
23225
+ placementStrategy = "shelf",
23226
+ className
23227
+ }) {
23228
+ const containerRef = React.useRef(null);
23229
+ const itemNodesRef = React.useRef(/* @__PURE__ */ new Map());
23230
+ const itemObserverRef = React.useRef(null);
23231
+ const [containerWidth, setContainerWidth] = React.useState(0);
23232
+ const [measuredHeights, setMeasuredHeights] = React.useState({});
23233
+ const itemKeys = React.useMemo(
23234
+ () => items.map((item, index) => String(getItemKey(item, index))),
23235
+ [getItemKey, items]
23236
+ );
23237
+ const itemKeysSignature = itemKeys.join("|");
23238
+ React.useEffect(() => {
23239
+ const node = containerRef.current;
23240
+ if (!node) return void 0;
23241
+ const updateWidth = () => {
23242
+ const nextWidth = Math.round(node.getBoundingClientRect().width);
23243
+ setContainerWidth((prevWidth) => prevWidth === nextWidth ? prevWidth : nextWidth);
23244
+ };
23245
+ updateWidth();
23246
+ if (typeof ResizeObserver === "function") {
23247
+ const observer = new ResizeObserver(() => updateWidth());
23248
+ observer.observe(node);
23249
+ return () => observer.disconnect();
23250
+ }
23251
+ window.addEventListener("resize", updateWidth);
23252
+ return () => window.removeEventListener("resize", updateWidth);
23253
+ }, []);
23254
+ React.useEffect(() => {
23255
+ setMeasuredHeights((prev) => {
23256
+ const next = Object.fromEntries(
23257
+ Object.entries(prev).filter(([key]) => itemKeys.includes(key))
23258
+ );
23259
+ return areMeasurementMapsEqual(prev, next) ? prev : next;
23260
+ });
23261
+ }, [itemKeys, itemKeysSignature]);
23262
+ const resolvedTargetColumnWidth = resolveLengthToPixels(
23263
+ columnWidth,
23264
+ DEFAULT_MASONRY_COLUMN_WIDTH_PX,
23265
+ containerRef.current
23266
+ );
23267
+ const isDensePlacement = placementStrategy === "dense";
23268
+ const columnCount = getMasonryColumnCount({
23269
+ containerWidth,
23270
+ itemCount: items.length,
23271
+ targetColumnWidth: resolvedTargetColumnWidth,
23272
+ gap
23273
+ });
23274
+ const resolvedColumnWidth = containerWidth > 0 ? (containerWidth - gap * Math.max(columnCount - 1, 0)) / columnCount : resolvedTargetColumnWidth;
23275
+ const layoutItems = React.useMemo(() => items.map((item, index) => {
23276
+ const key = itemKeys[index];
23277
+ const size = typeof getItemSize === "function" ? getItemSize(item, {
23278
+ columnCount,
23279
+ columnWidth: resolvedColumnWidth,
23280
+ containerWidth,
23281
+ gap,
23282
+ placementStrategy,
23283
+ rowHeight
23284
+ }) || {} : {};
23285
+ return {
23286
+ key,
23287
+ item,
23288
+ size,
23289
+ columnSpan: getItemColumnSpan({
23290
+ size,
23291
+ columnWidth: resolvedColumnWidth,
23292
+ columnCount,
23293
+ gap
23294
+ }),
23295
+ rowSpan: getItemRowSpan({
23296
+ size,
23297
+ measuredHeight: measuredHeights[key],
23298
+ rowHeight,
23299
+ gap
23300
+ })
23301
+ };
23302
+ }), [
23303
+ columnCount,
23304
+ containerWidth,
23305
+ gap,
23306
+ getItemSize,
23307
+ itemKeys,
23308
+ items,
23309
+ measuredHeights,
23310
+ placementStrategy,
23311
+ resolvedColumnWidth,
23312
+ rowHeight
23313
+ ]);
23314
+ React.useLayoutEffect(() => {
23315
+ const nextMeasurements = {};
23316
+ itemNodesRef.current.forEach((node, key) => {
23317
+ const nextHeight = Math.ceil(node.getBoundingClientRect().height);
23318
+ if (Number.isFinite(nextHeight) && nextHeight > 0) {
23319
+ nextMeasurements[key] = nextHeight;
23320
+ }
23321
+ });
23322
+ setMeasuredHeights((prev) => {
23323
+ if (!Object.keys(nextMeasurements).length) return prev;
23324
+ const merged = { ...prev, ...nextMeasurements };
23325
+ return areMeasurementMapsEqual(prev, merged) ? prev : merged;
23326
+ });
23327
+ }, [columnCount, isDensePlacement, itemKeysSignature, resolvedColumnWidth]);
23328
+ React.useEffect(() => {
23329
+ if (typeof ResizeObserver !== "function") return void 0;
23330
+ const observer = new ResizeObserver((entries) => {
23331
+ setMeasuredHeights((prev) => {
23332
+ const next = { ...prev };
23333
+ let didChange = false;
23334
+ for (const entry of entries) {
23335
+ const key = entry.target.dataset.masonryKey;
23336
+ if (!key) continue;
23337
+ const nextHeight = Math.ceil(entry.contentRect.height);
23338
+ if (!Number.isFinite(nextHeight) || nextHeight <= 0 || next[key] === nextHeight) continue;
23339
+ next[key] = nextHeight;
23340
+ didChange = true;
23341
+ }
23342
+ return didChange ? next : prev;
23343
+ });
23344
+ });
23345
+ itemObserverRef.current = observer;
23346
+ itemNodesRef.current.forEach((node) => observer.observe(node));
23347
+ return () => {
23348
+ observer.disconnect();
23349
+ itemObserverRef.current = null;
23350
+ };
23351
+ }, [isDensePlacement, itemKeysSignature]);
23352
+ const registerItemNode = (key, node) => {
23353
+ const currentNodes = itemNodesRef.current;
23354
+ const previousNode = currentNodes.get(key);
23355
+ if (previousNode && previousNode !== node && itemObserverRef.current) {
23356
+ itemObserverRef.current.unobserve(previousNode);
23357
+ }
23358
+ if (!node) {
23359
+ currentNodes.delete(key);
23360
+ return;
23361
+ }
23362
+ node.dataset.masonryKey = key;
23363
+ currentNodes.set(key, node);
23364
+ if (itemObserverRef.current) {
23365
+ itemObserverRef.current.observe(node);
23366
+ }
23367
+ };
23368
+ if (!isDensePlacement) {
23369
+ const orderedLayout = (() => {
23370
+ const columnBottoms = Array.from({ length: columnCount }, () => 0);
23371
+ let nextColumnIndex = 0;
23372
+ let maxBottom = 0;
23373
+ const positionedItems = layoutItems.map(({ key, item, columnSpan, rowSpan, size }) => {
23374
+ const resolvedSpan = clamp4(columnSpan, 1, columnCount);
23375
+ let startColumn = nextColumnIndex;
23376
+ if (startColumn + resolvedSpan > columnCount) {
23377
+ startColumn = 0;
23378
+ }
23379
+ startColumn = Math.min(startColumn, columnCount - resolvedSpan);
23380
+ const itemWidth = resolvedColumnWidth * resolvedSpan + gap * Math.max(resolvedSpan - 1, 0);
23381
+ const itemHeight = getResolvedItemHeight({
23382
+ size,
23383
+ measuredHeight: measuredHeights[key]
23384
+ });
23385
+ const top = Math.max(...columnBottoms.slice(startColumn, startColumn + resolvedSpan));
23386
+ const left = startColumn * (resolvedColumnWidth + gap);
23387
+ const bottom = top + itemHeight;
23388
+ for (let columnIndex = startColumn; columnIndex < startColumn + resolvedSpan; columnIndex += 1) {
23389
+ columnBottoms[columnIndex] = bottom + gap;
23390
+ }
23391
+ maxBottom = Math.max(maxBottom, bottom);
23392
+ nextColumnIndex = startColumn + resolvedSpan;
23393
+ if (nextColumnIndex >= columnCount) {
23394
+ nextColumnIndex = 0;
23395
+ }
23396
+ return {
23397
+ key,
23398
+ item,
23399
+ columnSpan: resolvedSpan,
23400
+ itemHeight,
23401
+ itemWidth,
23402
+ left,
23403
+ rowSpan,
23404
+ size,
23405
+ top
23406
+ };
23407
+ });
23408
+ return {
23409
+ containerHeight: Math.max(0, maxBottom),
23410
+ positionedItems
23411
+ };
23412
+ })();
23413
+ return /* @__PURE__ */ jsxRuntime.jsx(
23414
+ "div",
23415
+ {
23416
+ ref: containerRef,
23417
+ className: cn("relative w-full", className),
23418
+ style: { height: `${orderedLayout.containerHeight}px` },
23419
+ children: orderedLayout.positionedItems.map(({ key, item, columnSpan, rowSpan, size, itemWidth, left, top }) => {
23420
+ const unresolvedSingleColumnWidth = containerWidth <= 0 && columnCount === 1;
23421
+ const itemWidthValue = unresolvedSingleColumnWidth ? "100%" : `${itemWidth}px`;
23422
+ return /* @__PURE__ */ jsxRuntime.jsx(
23423
+ "div",
23424
+ {
23425
+ className: "absolute min-w-0",
23426
+ style: {
23427
+ left: unresolvedSingleColumnWidth ? 0 : `${left}px`,
23428
+ top: `${top}px`,
23429
+ width: itemWidthValue,
23430
+ maxWidth: itemWidthValue
23431
+ },
23432
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: (node) => registerItemNode(key, node), className: "min-w-0", children: renderItem(item, {
23433
+ columnCount,
23434
+ columnSpan,
23435
+ columnWidth: resolvedColumnWidth,
23436
+ containerWidth,
23437
+ gap,
23438
+ itemWidth,
23439
+ placementStrategy,
23440
+ rowSpan,
23441
+ rowHeight,
23442
+ size
23443
+ }) })
23444
+ },
23445
+ key
23446
+ );
23447
+ })
23448
+ }
23449
+ );
23450
+ }
23451
+ return /* @__PURE__ */ jsxRuntime.jsx(
23452
+ "div",
23453
+ {
23454
+ ref: containerRef,
23455
+ className: cn("grid w-full items-start", className),
23456
+ style: {
23457
+ gap: `${gap}px`,
23458
+ gridAutoFlow: "row dense",
23459
+ gridAutoRows: `${rowHeight}px`,
23460
+ gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
23461
+ },
23462
+ children: layoutItems.map(({ key, item, columnSpan, rowSpan, size }) => /* @__PURE__ */ jsxRuntime.jsx(
23463
+ "div",
23464
+ {
23465
+ className: "min-w-0",
23466
+ style: {
23467
+ gridColumn: `span ${columnSpan}`,
23468
+ gridRow: `span ${rowSpan}`
23469
+ },
23470
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: (node) => registerItemNode(key, node), className: "h-full", children: renderItem(item, {
23471
+ columnCount,
23472
+ columnSpan,
23473
+ columnWidth: resolvedColumnWidth,
23474
+ containerWidth,
23475
+ gap,
23476
+ placementStrategy,
23477
+ rowSpan,
23478
+ rowHeight,
23479
+ size
23480
+ }) })
23481
+ },
23482
+ key
23483
+ ))
23484
+ }
23485
+ );
23486
+ }
23487
+ var GALLERY_GRID_GAP_PX = 12;
23488
+ function getNormalizedGalleryGridCardWidth(cardWidth) {
23489
+ if (typeof cardWidth === "number" && Number.isFinite(cardWidth) && cardWidth > 0) {
23490
+ return `${cardWidth}px`;
23491
+ }
23492
+ if (typeof cardWidth === "string" && cardWidth.trim()) {
23493
+ return cardWidth.trim();
23494
+ }
23495
+ return void 0;
23496
+ }
23497
+ function getDefaultGalleryDetailLimit2(density) {
23498
+ if (density === "compact") return 2;
23499
+ if (density === "detailed") return 6;
23500
+ return 4;
23501
+ }
23502
+ function getNormalizedGalleryBentoColumns2(columns, density) {
23503
+ if (columns === 1 || columns === 2 || columns === 3) return Number(columns);
23504
+ return density === "detailed" ? 1 : 2;
23505
+ }
23506
+ function getNormalizedGalleryDetailLimit2({
23507
+ density,
23508
+ visibility,
23509
+ limit
23510
+ }) {
23511
+ if (visibility === "all") return Number.POSITIVE_INFINITY;
23512
+ const parsedLimit = Number.parseInt(String(limit), 10);
23513
+ if (Number.isFinite(parsedLimit) && parsedLimit > 0) return parsedLimit;
23514
+ return getDefaultGalleryDetailLimit2(density);
23515
+ }
23516
+ function getGalleryCardWidthMetrics(density) {
23517
+ if (density === "compact") return { min: 220, ideal: 244, max: 268 };
23518
+ if (density === "detailed") return { min: 320, ideal: 372, max: 420 };
23519
+ return { min: 260, ideal: 304, max: 348 };
23520
+ }
23521
+ function getGalleryCardWidthForColumnCount({
23522
+ containerWidth,
23523
+ columnCount,
23524
+ gap
23525
+ }) {
23526
+ if (!containerWidth || !columnCount) return 0;
23527
+ return (containerWidth - gap * Math.max(columnCount - 1, 0)) / columnCount;
23528
+ }
23529
+ function getNormalizedGalleryGridColumns(columns) {
23530
+ if (columns === void 0 || columns === null || columns === "" || columns === "auto") {
23531
+ return void 0;
23532
+ }
23533
+ const parsedColumns = Number.parseInt(String(columns), 10);
23534
+ if (!Number.isFinite(parsedColumns) || parsedColumns <= 0) return void 0;
23535
+ return Math.max(1, Math.min(parsedColumns, 8));
23536
+ }
23537
+ function getGalleryGridColumnCount({
23538
+ containerWidth,
23539
+ rowCount,
23540
+ minCardWidth,
23541
+ idealCardWidth,
23542
+ maxCardWidth,
23543
+ gap
23544
+ }) {
23545
+ if (!containerWidth) return 1;
23546
+ const safeRowCount = Math.max(rowCount, 1);
23547
+ const lowerBound = Math.max(1, Math.ceil((containerWidth + gap) / (maxCardWidth + gap)));
23548
+ const upperBound = Math.max(1, Math.floor((containerWidth + gap) / (minCardWidth + gap)));
23549
+ const idealCount = Math.max(1, Math.round((containerWidth + gap) / (idealCardWidth + gap)));
23550
+ const phantomPenalty = Math.round((idealCardWidth - minCardWidth) / 2) + gap;
23551
+ const maxCandidate = Math.max(1, lowerBound, upperBound + 1, idealCount + 1);
23552
+ let bestCount = 1;
23553
+ let bestScore = Number.POSITIVE_INFINITY;
23554
+ for (let candidateCount = 1; candidateCount <= maxCandidate; candidateCount += 1) {
23555
+ const cardWidth = getGalleryCardWidthForColumnCount({ containerWidth, columnCount: candidateCount, gap });
23556
+ const overflowPenalty = Math.max(0, cardWidth - maxCardWidth);
23557
+ const underflowPenalty = Math.max(0, minCardWidth - cardWidth);
23558
+ const idealPenalty = Math.abs(cardWidth - idealCardWidth);
23559
+ const phantomColumns = Math.max(0, candidateCount - safeRowCount);
23560
+ const candidateScore = overflowPenalty * 3 + underflowPenalty * 2 + idealPenalty + phantomColumns * phantomPenalty;
23561
+ if (candidateScore < bestScore) {
23562
+ bestScore = candidateScore;
23563
+ bestCount = candidateCount;
23564
+ }
23565
+ }
23566
+ return bestCount;
23567
+ }
23568
+ function getGalleryGridLayoutStyle({
23569
+ isRailLayout,
23570
+ railCardWidth,
23571
+ fixedCardWidth,
23572
+ fixedColumnCount,
23573
+ containerWidth,
23574
+ rowCount,
23575
+ minCardWidth,
23576
+ idealCardWidth,
23577
+ maxCardWidth
23578
+ }) {
23579
+ if (isRailLayout) {
23580
+ return { gridAutoColumns: `${railCardWidth}px` };
23581
+ }
23582
+ if (fixedColumnCount) {
23583
+ const responsiveColumnCount = containerWidth ? Math.max(1, Math.min(
23584
+ fixedColumnCount,
23585
+ Math.floor((containerWidth + GALLERY_GRID_GAP_PX) / (minCardWidth + GALLERY_GRID_GAP_PX)) || 1
23586
+ )) : fixedColumnCount;
23587
+ return {
23588
+ gridTemplateColumns: `repeat(${responsiveColumnCount}, minmax(0, 1fr))`,
23589
+ justifyContent: "start",
23590
+ alignContent: "start"
23591
+ };
23592
+ }
23593
+ if (fixedCardWidth) {
23594
+ return {
23595
+ gridTemplateColumns: `repeat(auto-fit, minmax(min(100%, ${fixedCardWidth}), ${fixedCardWidth}))`,
23596
+ justifyContent: "start",
23597
+ alignContent: "start"
23598
+ };
23599
+ }
23600
+ if (!containerWidth) {
23601
+ return {
23602
+ gridTemplateColumns: `repeat(auto-fit, minmax(min(100%, ${minCardWidth}px), min(100%, ${maxCardWidth}px)))`,
23603
+ justifyContent: "start",
23604
+ alignContent: "start"
23605
+ };
23606
+ }
23607
+ const columnCount = getGalleryGridColumnCount({
23608
+ containerWidth,
23609
+ rowCount,
23610
+ minCardWidth,
23611
+ idealCardWidth,
23612
+ maxCardWidth,
23613
+ gap: GALLERY_GRID_GAP_PX
23614
+ });
23615
+ return {
23616
+ gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`,
23617
+ justifyContent: "start",
23618
+ alignContent: "start"
23619
+ };
23620
+ }
23621
+ function getGalleryTextLength(value) {
23622
+ if (value === null || value === void 0) return 0;
23623
+ const text = String(value).trim();
23624
+ return text && text !== "\u2014" ? text.length : 0;
23625
+ }
23626
+ function getGalleryFieldText({
23627
+ column,
23628
+ row,
23629
+ getFieldValue,
23630
+ getDisplayText
23631
+ }) {
23632
+ if (!column) return "";
23633
+ const rawValue = getFieldValue(column, row);
23634
+ if (rawValue === null || rawValue === void 0 || rawValue === "") return "";
23635
+ const textValue = getDisplayText(rawValue);
23636
+ return textValue === "\u2014" ? "" : String(textValue);
23637
+ }
23638
+ function estimateLineCount({
23639
+ text,
23640
+ charsPerLine,
23641
+ maxLines
23642
+ }) {
23643
+ const textLength = getGalleryTextLength(text);
23644
+ if (!textLength) return 0;
23645
+ return Math.max(1, Math.min(maxLines, Math.ceil(textLength / charsPerLine)));
23646
+ }
23647
+ function estimateGalleryDetailCellHeight({
23648
+ text,
23649
+ density,
23650
+ bentoColumns
23651
+ }) {
23652
+ const baseHeight = density === "detailed" ? 54 : density === "compact" ? 44 : 48;
23653
+ const charsPerLine = bentoColumns === 1 ? density === "detailed" ? 32 : 26 : density === "detailed" ? 18 : 15;
23654
+ const maxLines = density === "detailed" ? 3 : 2;
23655
+ const lineCount = estimateLineCount({ text, charsPerLine, maxLines });
23656
+ if (!lineCount) return baseHeight;
23657
+ return baseHeight + Math.max(0, lineCount - 1) * 16;
23658
+ }
23659
+ function estimateGalleryDetailGridHeight({
23660
+ columns,
23661
+ density,
23662
+ bentoColumns
23663
+ }) {
23664
+ if (!columns.length) return 0;
23665
+ const cellHeights = columns.map((column) => estimateGalleryDetailCellHeight({
23666
+ text: column.text,
23667
+ density,
23668
+ bentoColumns
23669
+ }));
23670
+ if (bentoColumns === 1) {
23671
+ return 12 + cellHeights.reduce((sum, height) => sum + height, 0) + Math.max(0, columns.length - 1) * 8;
23672
+ }
23673
+ let totalHeight = 12;
23674
+ for (let index = 0; index < cellHeights.length; index += bentoColumns) {
23675
+ const rowHeights = cellHeights.slice(index, index + bentoColumns);
23676
+ totalHeight += Math.max(...rowHeights);
23677
+ if (index + bentoColumns < cellHeights.length) totalHeight += 8;
23678
+ }
23679
+ return totalHeight;
23680
+ }
23681
+ function getDefaultGalleryMasonryItemSize({
23682
+ row,
23683
+ columns,
23684
+ galleryFieldKey,
23685
+ galleryDensity,
23686
+ galleryBentoColumns,
23687
+ galleryDetailVisibility,
23688
+ galleryDetailLimit,
23689
+ getFieldValue,
23690
+ isMediaColumn,
23691
+ isTitleCandidate,
23692
+ isSummaryCandidate,
23693
+ getDisplayText,
23694
+ isImageField,
23695
+ isAudioField,
23696
+ cardVariant,
23697
+ renderPreview,
23698
+ renderLeadingVisual,
23699
+ hiddenDetailFieldKeys,
23700
+ layout,
23701
+ resolveRecordVisual
23702
+ }) {
23703
+ const iconColumn = columns.find((column) => column.renderType === "icon");
23704
+ const iconVisual = iconColumn && resolveRecordVisual ? resolveRecordVisual(row?.[iconColumn.key], row, iconColumn) : null;
23705
+ const selectedGalleryColumn = galleryFieldKey !== "auto" ? columns.find((column) => column.key === galleryFieldKey && isMediaColumn(column, row)) : null;
23706
+ const mediaColumn = selectedGalleryColumn || columns.find((column) => isMediaColumn(column, row)) || null;
23707
+ const mediaValue = mediaColumn ? getFieldValue(mediaColumn, row) : null;
23708
+ const isImageMedia = mediaColumn ? isImageField(mediaColumn, mediaValue) : false;
23709
+ const isAudioMedia = mediaColumn ? isAudioField(mediaColumn, mediaValue) : false;
23710
+ const hasDefaultLeadingVisual = Boolean(iconVisual);
23711
+ const hasLeadingVisual = Boolean(renderLeadingVisual) || hasDefaultLeadingVisual;
23712
+ const contentColumns = columns.filter((column) => column.key !== mediaColumn?.key && column.renderType !== "icon");
23713
+ const titleCandidates = contentColumns.filter((column) => {
23714
+ if (!column || isMediaColumn(column, row) || !isTitleCandidate(column, row)) return false;
23715
+ const value = getFieldValue(column, row);
23716
+ return !(value === null || value === void 0 || value === "");
23717
+ });
23718
+ const titleColumn = titleCandidates[0] || null;
23719
+ const titleText = titleColumn ? getGalleryFieldText({ column: titleColumn, row, getFieldValue, getDisplayText }) : String(getDisplayText(row?.linkKey || row?.id || ""));
23720
+ const summaryColumn = contentColumns.find((column) => {
23721
+ if (!column || column.key === titleColumn?.key || isMediaColumn(column, row) || !isSummaryCandidate(column, row)) return false;
23722
+ const summaryText2 = getGalleryFieldText({ column, row, getFieldValue, getDisplayText });
23723
+ return summaryText2.length > 12;
23724
+ }) || contentColumns.find((column) => {
23725
+ if (!column || column.key === titleColumn?.key || isMediaColumn(column, row) || !isSummaryCandidate(column, row)) return false;
23726
+ return getGalleryTextLength(getGalleryFieldText({ column, row, getFieldValue, getDisplayText })) > 0;
23727
+ }) || null;
23728
+ const summaryText = summaryColumn ? getGalleryFieldText({ column: summaryColumn, row, getFieldValue, getDisplayText }) : "";
23729
+ const hiddenDetailKeySet = new Set(hiddenDetailFieldKeys);
23730
+ const detailColumns = contentColumns.filter((column) => column.key !== titleColumn?.key && column.key !== summaryColumn?.key && !hiddenDetailKeySet.has(column.key)).map((column) => ({
23731
+ column,
23732
+ text: getGalleryFieldText({ column, row, getFieldValue, getDisplayText })
23733
+ }));
23734
+ const resolvedDetailLimit = getNormalizedGalleryDetailLimit2({
23735
+ density: galleryDensity,
23736
+ visibility: galleryDetailVisibility,
23737
+ limit: galleryDetailLimit
23738
+ });
23739
+ const visibleDetailColumns = Number.isFinite(resolvedDetailLimit) ? detailColumns.slice(0, resolvedDetailLimit) : detailColumns;
23740
+ const hiddenDetailCount = Math.max(detailColumns.length - visibleDetailColumns.length, 0);
23741
+ const resolvedBentoColumns = getNormalizedGalleryBentoColumns2(galleryBentoColumns, galleryDensity);
23742
+ const resolvedColumnWidth = layout?.columnWidth || getGalleryCardWidthMetrics(galleryDensity).ideal;
23743
+ if (cardVariant === "image-only") {
23744
+ return {
23745
+ width: resolvedColumnWidth,
23746
+ height: Math.round(resolvedColumnWidth * 1.25)
23747
+ };
23748
+ }
23749
+ if (cardVariant === "preview-only") {
23750
+ return {
23751
+ width: resolvedColumnWidth,
23752
+ height: Math.round(resolvedColumnWidth * 0.82)
23753
+ };
23754
+ }
23755
+ let estimatedHeight = galleryDensity === "detailed" ? 84 : galleryDensity === "compact" ? 64 : 72;
23756
+ if (typeof renderPreview === "function") {
23757
+ estimatedHeight += galleryDensity === "detailed" ? 188 : galleryDensity === "compact" ? 140 : 164;
23758
+ } else if (isImageMedia) {
23759
+ estimatedHeight += Math.round(resolvedColumnWidth * (galleryDensity === "detailed" ? 0.72 : 0.62)) + 12;
23760
+ } else if (isAudioMedia) {
23761
+ estimatedHeight += 92;
23762
+ }
23763
+ const titleLines = estimateLineCount({
23764
+ text: titleText,
23765
+ charsPerLine: galleryDensity === "detailed" ? 26 : 24,
23766
+ maxLines: 2
23767
+ }) || 1;
23768
+ const summaryLines = estimateLineCount({
23769
+ text: summaryText,
23770
+ charsPerLine: hasLeadingVisual ? 22 : galleryDensity === "detailed" ? 30 : 26,
23771
+ maxLines: galleryDensity === "detailed" ? 4 : 2
23772
+ });
23773
+ const textHeaderHeight = 26 + titleLines * 18 + (summaryLines > 0 ? summaryLines * 16 + 4 : 0);
23774
+ estimatedHeight += Math.max(hasLeadingVisual ? 56 : 0, textHeaderHeight);
23775
+ estimatedHeight += estimateGalleryDetailGridHeight({
23776
+ columns: visibleDetailColumns,
23777
+ density: galleryDensity,
23778
+ bentoColumns: resolvedBentoColumns
23779
+ });
23780
+ if (hiddenDetailCount > 0) estimatedHeight += 18;
23781
+ if (!summaryText && visibleDetailColumns.length === 0) estimatedHeight += 24;
23782
+ return {
23783
+ width: resolvedColumnWidth,
23784
+ height: estimatedHeight
23785
+ };
23786
+ }
23787
+ function WorkbenchGalleryView({
23788
+ rows = [],
23789
+ columns = [],
23790
+ onRowClick = () => {
23791
+ },
23792
+ selectedLinkKey,
23793
+ selectedRowKey,
23794
+ className,
23795
+ isMasonry = false,
23796
+ galleryLayoutMode = "auto",
23797
+ galleryRailCardWidth,
23798
+ galleryGridColumns,
23799
+ galleryGridCardWidth,
23800
+ galleryMasonryColumnWidth,
23801
+ masonryPlacementStrategy = "shelf",
23802
+ galleryFieldKey = "auto",
23803
+ galleryDensity = "comfortable",
23804
+ galleryBentoColumns = 2,
23805
+ galleryDetailVisibility = "limit",
23806
+ galleryDetailLimit,
23807
+ shouldEnhanceMultimodal = true,
23808
+ getFieldValue,
23809
+ isMediaColumn,
23810
+ isTitleCandidate,
23811
+ isSummaryCandidate,
23812
+ getDisplayText,
23813
+ renderFieldValue,
23814
+ getImagePreviewSrc,
23815
+ isImageField,
23816
+ isAudioField,
23817
+ AudioPlayerComponent,
23818
+ cardVariant = "default",
23819
+ renderPreview,
23820
+ renderMeta,
23821
+ renderLeadingVisual,
23822
+ resolveRecordVisual,
23823
+ hiddenDetailFieldKeys = [],
23824
+ labels,
23825
+ formatLabel,
23826
+ getMasonryItemSize
23827
+ }) {
23828
+ const containerRef = React.useRef(null);
23829
+ const [containerWidth, setContainerWidth] = React.useState(0);
23830
+ const { min: resolvedMinCardWidth, ideal: resolvedIdealCardWidth, max: resolvedMaxCardWidth } = getGalleryCardWidthMetrics(galleryDensity);
23831
+ const resolvedRailCardWidth = galleryRailCardWidth || resolvedMinCardWidth;
23832
+ const resolvedGridColumnCount = getNormalizedGalleryGridColumns(galleryGridColumns);
23833
+ const resolvedGridCardWidth = getNormalizedGalleryGridCardWidth(galleryGridCardWidth);
23834
+ const resolvedMasonryColumnWidth = galleryMasonryColumnWidth || resolvedMinCardWidth;
23835
+ const isRailLayout = galleryLayoutMode === "rail";
23836
+ const resolvedGetFieldValue = getFieldValue || getDefaultGalleryFieldValue;
23837
+ const resolvedGetDisplayText = getDisplayText || getDefaultGalleryDisplayText;
23838
+ const resolvedIsImageField = isImageField || isDefaultGalleryImageField;
23839
+ const resolvedIsAudioField = isAudioField || isDefaultGalleryAudioField;
23840
+ const resolvedIsMediaColumn = isMediaColumn || ((column, row) => isDefaultGalleryMediaColumn(column, row, {
23841
+ getFieldValue: resolvedGetFieldValue,
23842
+ shouldEnhanceMultimodal,
23843
+ isImageField: resolvedIsImageField,
23844
+ isAudioField: resolvedIsAudioField
23845
+ }));
23846
+ const resolvedIsTitleCandidate = isTitleCandidate || ((column, row) => isDefaultGalleryTitleCandidate(column, row, { isMediaColumn: resolvedIsMediaColumn }));
23847
+ const resolvedIsSummaryCandidate = isSummaryCandidate || ((column, row) => isDefaultGallerySummaryCandidate(column, row, { isMediaColumn: resolvedIsMediaColumn }));
23848
+ const resolvedRenderFieldValue = renderFieldValue || ((column, row, { compact } = {}) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: resolvedGetDisplayText(resolvedGetFieldValue(column, row)) }));
23849
+ React.useEffect(() => {
23850
+ if (isMasonry || isRailLayout || resolvedGridCardWidth) return void 0;
23851
+ const node = containerRef.current;
23852
+ if (!node) return void 0;
23853
+ const updateWidth = () => {
23854
+ const nextWidth = Math.round(node.getBoundingClientRect().width);
23855
+ setContainerWidth((prevWidth) => prevWidth === nextWidth ? prevWidth : nextWidth);
23856
+ };
23857
+ updateWidth();
23858
+ if (typeof ResizeObserver === "function") {
23859
+ const observer = new ResizeObserver(() => updateWidth());
23860
+ observer.observe(node);
23861
+ return () => observer.disconnect();
23862
+ }
23863
+ window.addEventListener("resize", updateWidth);
23864
+ return () => window.removeEventListener("resize", updateWidth);
23865
+ }, [isMasonry, isRailLayout, resolvedGridCardWidth]);
23866
+ const layoutStyle = React.useMemo(() => getGalleryGridLayoutStyle({
23867
+ isRailLayout,
23868
+ railCardWidth: resolvedRailCardWidth,
23869
+ fixedCardWidth: resolvedGridCardWidth,
23870
+ fixedColumnCount: resolvedGridColumnCount,
23871
+ containerWidth,
23872
+ rowCount: rows.length,
23873
+ minCardWidth: resolvedMinCardWidth,
23874
+ idealCardWidth: resolvedIdealCardWidth,
23875
+ maxCardWidth: resolvedMaxCardWidth
23876
+ }), [
23877
+ containerWidth,
23878
+ isRailLayout,
23879
+ resolvedGridCardWidth,
23880
+ resolvedGridColumnCount,
23881
+ resolvedIdealCardWidth,
23882
+ resolvedMaxCardWidth,
23883
+ resolvedMinCardWidth,
23884
+ resolvedRailCardWidth,
23885
+ rows.length
23886
+ ]);
23887
+ const renderGalleryCard = (row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
23888
+ WorkbenchGalleryCard,
23889
+ {
23890
+ row,
23891
+ columns,
23892
+ onClick: () => onRowClick(row, rowIndex),
23893
+ isSelected: String(row?.linkKey || row?.id || "") === String(selectedRowKey || selectedLinkKey || ""),
23894
+ isMasonry,
23895
+ galleryFieldKey,
23896
+ galleryDensity,
23897
+ galleryBentoColumns,
23898
+ galleryDetailVisibility,
23899
+ galleryDetailLimit,
23900
+ shouldEnhanceMultimodal,
23901
+ getFieldValue: resolvedGetFieldValue,
23902
+ isMediaColumn: resolvedIsMediaColumn,
23903
+ isTitleCandidate: resolvedIsTitleCandidate,
23904
+ isSummaryCandidate: resolvedIsSummaryCandidate,
23905
+ getDisplayText: resolvedGetDisplayText,
23906
+ renderFieldValue: resolvedRenderFieldValue,
23907
+ getImagePreviewSrc,
23908
+ isImageField: resolvedIsImageField,
23909
+ isAudioField: resolvedIsAudioField,
23910
+ AudioPlayerComponent,
23911
+ cardVariant,
23912
+ renderPreview,
23913
+ renderMeta,
23914
+ renderLeadingVisual,
23915
+ resolveRecordVisual,
23916
+ hiddenDetailFieldKeys,
23917
+ labels,
23918
+ formatLabel
23919
+ },
23920
+ row?.id || row?.linkKey || rowIndex
23921
+ );
23922
+ if (isMasonry) {
23923
+ return /* @__PURE__ */ jsxRuntime.jsx(
23924
+ WorkbenchMasonryLayout,
23925
+ {
23926
+ items: rows,
23927
+ className,
23928
+ gap: GALLERY_GRID_GAP_PX,
23929
+ columnWidth: resolvedMasonryColumnWidth,
23930
+ placementStrategy: masonryPlacementStrategy,
23931
+ getItemKey: (row, rowIndex) => row?.id || row?.linkKey || rowIndex,
23932
+ getItemSize: (row, layout) => {
23933
+ const defaultSize = getDefaultGalleryMasonryItemSize({
23934
+ row,
23935
+ columns,
23936
+ galleryFieldKey,
23937
+ galleryDensity,
23938
+ galleryBentoColumns,
23939
+ galleryDetailVisibility,
23940
+ galleryDetailLimit,
23941
+ getFieldValue: resolvedGetFieldValue,
23942
+ isMediaColumn: resolvedIsMediaColumn,
23943
+ isTitleCandidate: resolvedIsTitleCandidate,
23944
+ isSummaryCandidate: resolvedIsSummaryCandidate,
23945
+ getDisplayText: resolvedGetDisplayText,
23946
+ isImageField: resolvedIsImageField,
23947
+ isAudioField: resolvedIsAudioField,
23948
+ cardVariant,
23949
+ renderPreview,
23950
+ renderLeadingVisual,
23951
+ hiddenDetailFieldKeys,
23952
+ layout,
23953
+ resolveRecordVisual
23954
+ });
23955
+ if (typeof getMasonryItemSize !== "function") return defaultSize;
23956
+ const customSize = getMasonryItemSize(row, { ...layout, defaultSize }) || {};
23957
+ return {
23958
+ ...defaultSize,
23959
+ ...customSize
23960
+ };
23961
+ },
23962
+ renderItem: (row) => renderGalleryCard(row, rows.indexOf(row))
23963
+ }
23964
+ );
23965
+ }
23966
+ return /* @__PURE__ */ jsxRuntime.jsx(
23967
+ "div",
23968
+ {
23969
+ ref: containerRef,
23970
+ className: cn(
23971
+ isRailLayout ? "grid grid-flow-col items-center gap-3" : "grid items-start gap-3",
23972
+ className
23973
+ ),
23974
+ style: layoutStyle,
23975
+ children: rows.map((row, rowIndex) => renderGalleryCard(row, rowIndex))
23976
+ }
23977
+ );
23978
+ }
23979
+ function toCssSize5(value) {
23980
+ if (value === void 0) return void 0;
23981
+ return typeof value === "number" ? `${value}px` : value;
23982
+ }
23983
+ function defaultGetRowId(row, rowIndex) {
23984
+ return String(row?.id ?? row?.key ?? rowIndex);
23985
+ }
23986
+ function defaultGetColumnId(row) {
23987
+ return String(row?.columnId ?? row?.status ?? "");
23988
+ }
23989
+ function defaultRenderCard(row) {
23990
+ const value = row?.title ?? row?.name ?? row?.id ?? "Untitled";
23991
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-border/70 bg-card px-3 py-2 text-sm text-foreground shadow-sm", children: String(value) });
23992
+ }
23993
+ function WorkbenchLaneDraggableCard({
23994
+ row,
23995
+ rowId,
23996
+ rowIndex,
23997
+ column,
23998
+ classNames,
23999
+ renderCard
24000
+ }) {
24001
+ const { attributes, listeners, setNodeRef, isDragging } = core.useDraggable({ id: rowId });
24002
+ return /* @__PURE__ */ jsxRuntime.jsx(
24003
+ "div",
24004
+ {
24005
+ ref: setNodeRef,
24006
+ ...listeners,
24007
+ ...attributes,
24008
+ className: cn("touch-none", classNames?.cardWrapper),
24009
+ children: renderCard(row, { row, rowIndex, column, isDragging, isOverlay: false })
24010
+ }
24011
+ );
24012
+ }
24013
+ function WorkbenchLaneColumnView({
24014
+ column,
24015
+ columnRows,
24016
+ columnWidth,
24017
+ columnMinHeight,
24018
+ emptyColumn,
24019
+ classNames,
24020
+ renderCard
24021
+ }) {
24022
+ const { setNodeRef, isOver } = core.useDroppable({ id: column.id });
24023
+ return /* @__PURE__ */ jsxRuntime.jsxs(
24024
+ "section",
24025
+ {
24026
+ className: cn(
24027
+ "flex shrink-0 flex-col rounded-xl border border-border/60 bg-card p-2 shadow-sm",
24028
+ classNames?.column,
24029
+ column.className
24030
+ ),
24031
+ style: { width: toCssSize5(columnWidth) ?? "280px" },
24032
+ children: [
24033
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-10 items-center gap-2 px-1", classNames?.columnHeader, column.headerClassName), children: [
24034
+ column.icon ? /* @__PURE__ */ jsxRuntime.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,
24035
+ /* @__PURE__ */ jsxRuntime.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 }),
24036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs text-muted-foreground", classNames?.columnCount), children: columnRows.length })
24037
+ ] }),
24038
+ /* @__PURE__ */ jsxRuntime.jsx(
24039
+ "div",
24040
+ {
24041
+ ref: setNodeRef,
24042
+ className: cn(
24043
+ "mt-1 flex min-h-[200px] flex-1 flex-col gap-2 overflow-y-auto rounded-lg p-1 transition-colors [scrollbar-width:thin]",
24044
+ isOver && "bg-accent/60",
24045
+ classNames?.columnBody,
24046
+ column.bodyClassName
24047
+ ),
24048
+ style: { minHeight: toCssSize5(columnMinHeight) },
24049
+ children: columnRows.length ? columnRows.map(({ row, rowIndex, rowId }) => /* @__PURE__ */ jsxRuntime.jsx(
24050
+ WorkbenchLaneDraggableCard,
24051
+ {
24052
+ row,
24053
+ rowId,
24054
+ rowIndex,
24055
+ column,
24056
+ classNames,
24057
+ renderCard
24058
+ },
24059
+ rowId
24060
+ )) : emptyColumn ? /* @__PURE__ */ jsxRuntime.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
24061
+ }
24062
+ )
24063
+ ]
24064
+ }
24065
+ );
24066
+ }
24067
+ function WorkbenchLaneView({
24068
+ rows = [],
24069
+ columns = [],
24070
+ getRowId = defaultGetRowId,
24071
+ getColumnId = defaultGetColumnId,
24072
+ renderCard = defaultRenderCard,
24073
+ renderOverlayCard,
24074
+ onMoveRow,
24075
+ emptyColumn,
24076
+ activationDistance = 5,
24077
+ columnWidth = 280,
24078
+ columnMinHeight,
24079
+ className,
24080
+ classNames,
24081
+ style
24082
+ }) {
24083
+ const [activeRowId, setActiveRowId] = React.useState(null);
24084
+ const sensors = core.useSensors(core.useSensor(core.PointerSensor, { activationConstraint: { distance: activationDistance } }));
24085
+ const columnMap = React.useMemo(() => new Map(columns.map((column) => [column.id, column])), [columns]);
24086
+ const rowEntries = React.useMemo(() => rows.map((row, rowIndex) => ({
24087
+ row,
24088
+ rowIndex,
24089
+ rowId: getRowId(row, rowIndex),
24090
+ columnId: getColumnId(row, rowIndex)
24091
+ })), [getColumnId, getRowId, rows]);
24092
+ const activeEntry = activeRowId ? rowEntries.find((entry) => entry.rowId === activeRowId) : void 0;
24093
+ const rowsByColumn = React.useMemo(() => {
24094
+ const next = /* @__PURE__ */ new Map();
24095
+ columns.forEach((column) => next.set(column.id, []));
24096
+ rowEntries.forEach(({ row, rowIndex, rowId, columnId }) => {
24097
+ next.get(columnId)?.push({ row, rowIndex, rowId });
24098
+ });
24099
+ return next;
24100
+ }, [columns, rowEntries]);
24101
+ const activeColumn = activeEntry ? columnMap.get(activeEntry.columnId) : void 0;
24102
+ const handleDragStart = React.useCallback((event) => {
24103
+ setActiveRowId(String(event.active.id));
24104
+ }, []);
24105
+ const handleDragEnd = React.useCallback((event) => {
24106
+ setActiveRowId(null);
24107
+ const rowId = String(event.active.id);
24108
+ const nextColumnId = String(event.over?.id ?? "");
24109
+ const activeRow = rowEntries.find((entry) => entry.rowId === rowId);
24110
+ if (!activeRow || !columnMap.has(nextColumnId) || activeRow.columnId === nextColumnId) return;
24111
+ onMoveRow?.(rowId, nextColumnId, activeRow.row);
24112
+ }, [columnMap, onMoveRow, rowEntries]);
24113
+ const handleDragCancel = React.useCallback(() => {
24114
+ setActiveRowId(null);
24115
+ }, []);
24116
+ return /* @__PURE__ */ jsxRuntime.jsxs(core.DndContext, { sensors, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDragCancel: handleDragCancel, children: [
24117
+ /* @__PURE__ */ jsxRuntime.jsx(
24118
+ "div",
24119
+ {
24120
+ className: cn("flex min-h-0 flex-1 gap-4 overflow-x-auto p-4 [scrollbar-width:thin]", classNames?.root, className),
24121
+ style,
24122
+ children: columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(
24123
+ WorkbenchLaneColumnView,
24124
+ {
24125
+ column,
24126
+ columnRows: rowsByColumn.get(column.id) || [],
24127
+ columnWidth,
24128
+ columnMinHeight,
24129
+ emptyColumn,
24130
+ classNames,
24131
+ renderCard
24132
+ },
24133
+ column.id
24134
+ ))
24135
+ }
24136
+ ),
24137
+ /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { children: activeEntry && activeColumn ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(classNames?.overlayWrapper), children: (renderOverlayCard || renderCard)(activeEntry.row, {
24138
+ row: activeEntry.row,
24139
+ rowIndex: activeEntry.rowIndex,
24140
+ column: activeColumn,
24141
+ isDragging: false,
24142
+ isOverlay: true
24143
+ }) }) : null })
24144
+ ] });
24145
+ }
19999
24146
  function cn4(...inputs) {
20000
24147
  return inputs.filter(Boolean).join(" ");
20001
24148
  }
@@ -20323,6 +24470,10 @@ exports.BaseDropdownMenu = BaseDropdownMenu;
20323
24470
  exports.BaseEmptyState = BaseEmptyState;
20324
24471
  exports.BaseField = BaseField;
20325
24472
  exports.BaseInput = BaseInput;
24473
+ exports.BaseLayout = BaseLayout;
24474
+ exports.BaseLayoutPane = BaseLayoutPane;
24475
+ exports.BaseLayoutResizeHandle = BaseLayoutResizeHandle;
24476
+ exports.BaseLayoutSplit = BaseLayoutSplit;
20326
24477
  exports.BaseLoadingState = BaseLoadingState;
20327
24478
  exports.BaseNotice = BaseNotice;
20328
24479
  exports.BasePagination = BasePagination;
@@ -20387,11 +24538,26 @@ exports.DefaultLandingPage = DefaultLandingPage;
20387
24538
  exports.DynamicComponent = DynamicComponent;
20388
24539
  exports.EmailAuth = EmailAuth;
20389
24540
  exports.I18nSelector = I18nSelector;
24541
+ exports.InteractiveTable = InteractiveTable;
24542
+ exports.InteractiveTableEditableTextCell = InteractiveTableEditableTextCell;
24543
+ exports.InteractiveTableReadonlyCell = InteractiveTableReadonlyCell;
24544
+ exports.InteractiveTableSelectCell = InteractiveTableSelectCell;
20390
24545
  exports.LoginLayout = LoginLayout;
20391
24546
  exports.NavButton = NavButton;
20392
24547
  exports.OAuthButton = OAuthButton;
20393
24548
  exports.OIDCButton = OIDCButton;
20394
24549
  exports.PendingApproval = PendingApproval;
24550
+ exports.WorkbenchContentPane = WorkbenchContentPane;
24551
+ exports.WorkbenchContentToolbar = WorkbenchContentToolbar;
24552
+ exports.WorkbenchDetailSidebar = WorkbenchDetailSidebar;
24553
+ exports.WorkbenchGalleryCard = WorkbenchGalleryCard;
24554
+ exports.WorkbenchGallerySettingsButton = WorkbenchGallerySettingsButton;
24555
+ exports.WorkbenchGallerySettingsPanel = WorkbenchGallerySettingsPanel;
24556
+ exports.WorkbenchGalleryView = WorkbenchGalleryView;
24557
+ exports.WorkbenchLaneView = WorkbenchLaneView;
24558
+ exports.WorkbenchMasonryLayout = WorkbenchMasonryLayout;
24559
+ exports.WorkbenchResizableSidebar = WorkbenchResizableSidebar;
24560
+ exports.WorkbenchTableView = WorkbenchTableView;
20395
24561
  exports.applyMonkeysTheme = applyMonkeysTheme;
20396
24562
  exports.calculateHue = calculateHue;
20397
24563
  exports.calculateLightness = calculateLightness;