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