@inf-monkeys-tech/monkeys-design 1.0.38 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/components/agent-workbench/index.js +9 -0
  2. package/dist/components/agent-workbench/index.js.map +1 -1
  3. package/dist/components/agent-workbench/index.mjs +9 -0
  4. package/dist/components/agent-workbench/index.mjs.map +1 -1
  5. package/dist/components/base/index.js +9 -0
  6. package/dist/components/base/index.js.map +1 -1
  7. package/dist/components/base/index.mjs +9 -0
  8. package/dist/components/base/index.mjs.map +1 -1
  9. package/dist/components/data-explorer/index.js +9 -0
  10. package/dist/components/data-explorer/index.js.map +1 -1
  11. package/dist/components/data-explorer/index.mjs +9 -0
  12. package/dist/components/data-explorer/index.mjs.map +1 -1
  13. package/dist/components/layout/index.js +9 -0
  14. package/dist/components/layout/index.js.map +1 -1
  15. package/dist/components/layout/index.mjs +9 -0
  16. package/dist/components/layout/index.mjs.map +1 -1
  17. package/dist/components/runtime/index.js +9 -0
  18. package/dist/components/runtime/index.js.map +1 -1
  19. package/dist/components/runtime/index.mjs +9 -0
  20. package/dist/components/runtime/index.mjs.map +1 -1
  21. package/dist/components/toast/index.d.mts +1 -1
  22. package/dist/components/toast/index.d.ts +1 -1
  23. package/dist/components/toast/index.js +9 -0
  24. package/dist/components/toast/index.js.map +1 -1
  25. package/dist/components/toast/index.mjs +9 -0
  26. package/dist/components/toast/index.mjs.map +1 -1
  27. package/dist/components/toolbar/index.js +9 -0
  28. package/dist/components/toolbar/index.js.map +1 -1
  29. package/dist/components/toolbar/index.mjs +9 -0
  30. package/dist/components/toolbar/index.mjs.map +1 -1
  31. package/dist/components/workbench/index.d.mts +218 -6
  32. package/dist/components/workbench/index.d.ts +218 -6
  33. package/dist/components/workbench/index.js +1088 -97
  34. package/dist/components/workbench/index.js.map +1 -1
  35. package/dist/components/workbench/index.mjs +1089 -99
  36. package/dist/components/workbench/index.mjs.map +1 -1
  37. package/dist/index.d.mts +2 -2
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.js +838 -100
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +838 -101
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/locale/index.d.mts +20 -2
  44. package/dist/locale/index.d.ts +20 -2
  45. package/dist/locale/index.js +22 -0
  46. package/dist/locale/index.js.map +1 -1
  47. package/dist/locale/index.mjs +22 -0
  48. package/dist/locale/index.mjs.map +1 -1
  49. package/dist/provider/index.d.mts +2 -2
  50. package/dist/provider/index.d.ts +2 -2
  51. package/dist/provider/index.js +22 -0
  52. package/dist/provider/index.js.map +1 -1
  53. package/dist/provider/index.mjs +22 -0
  54. package/dist/provider/index.mjs.map +1 -1
  55. package/dist/styles.css +1 -1
  56. package/dist/{types-b8d18b1454c2.d.mts → types-453d18eab188.d.mts} +10 -0
  57. package/dist/{types-b8d18b1454c2.d.ts → types-453d18eab188.d.ts} +10 -0
  58. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { forwardRef, useRef, useState, useEffect, createContext, useCallback, useId, useMemo, createElement, useContext, Children, isValidElement, useLayoutEffect } from 'react';
1
+ import { forwardRef, useRef, useState, useEffect, createContext, useCallback, useId, useMemo, createElement, useContext, Children, isValidElement, useLayoutEffect, Fragment as Fragment$1 } from 'react';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
4
  import * as ContextMenu from '@radix-ui/react-context-menu';
@@ -469,6 +469,15 @@ var enUS = {
469
469
  }
470
470
  },
471
471
  workbench: {
472
+ collection: {
473
+ label: "Collection",
474
+ loading: "Loading items",
475
+ empty: "No items",
476
+ loadError: "Unable to load items",
477
+ refreshError: "Unable to refresh items",
478
+ retry: "Retry",
479
+ loadingMore: "Loading more items"
480
+ },
472
481
  interactiveTable: {
473
482
  columnActions: "Column actions",
474
483
  freezeColumn: "Freeze to left",
@@ -2201,6 +2210,16 @@ function getBaseButtonToneClassName(theme, tone = "default", active = false) {
2201
2210
  active && theme.slots.buttonActive
2202
2211
  );
2203
2212
  }
2213
+ function getBaseNoticeToneClassName(theme, tone = "default") {
2214
+ return cn(
2215
+ tone === "default" && theme.slots.noticeDefault,
2216
+ tone === "primary" && theme.slots.noticePrimary,
2217
+ tone === "success" && theme.slots.noticeSuccess,
2218
+ tone === "warning" && theme.slots.noticeWarning,
2219
+ tone === "danger" && theme.slots.noticeDanger,
2220
+ tone === "muted" && theme.slots.noticeMuted
2221
+ );
2222
+ }
2204
2223
  function getBaseMenuItemToneClassName(theme, tone = "default") {
2205
2224
  return cn(
2206
2225
  tone === "default" && theme.slots.menuItemDefault,
@@ -3434,6 +3453,98 @@ function BaseDescriptionList({
3434
3453
  }
3435
3454
  );
3436
3455
  }
3456
+ function DefaultEmptyIcon() {
3457
+ return /* @__PURE__ */ jsxs(
3458
+ "svg",
3459
+ {
3460
+ "aria-hidden": "true",
3461
+ viewBox: "0 0 24 24",
3462
+ className: "h-6 w-6",
3463
+ fill: "none",
3464
+ stroke: "currentColor",
3465
+ strokeLinecap: "round",
3466
+ strokeLinejoin: "round",
3467
+ strokeWidth: "1.8",
3468
+ children: [
3469
+ /* @__PURE__ */ jsx("rect", { width: "16", height: "12", x: "4", y: "6", rx: "2" }),
3470
+ /* @__PURE__ */ jsx("path", { d: "M8 10h8" }),
3471
+ /* @__PURE__ */ jsx("path", { d: "M8 14h5" })
3472
+ ]
3473
+ }
3474
+ );
3475
+ }
3476
+ var BaseEmptyState = forwardRef(
3477
+ function BaseEmptyState2({
3478
+ icon = /* @__PURE__ */ jsx(DefaultEmptyIcon, {}),
3479
+ title,
3480
+ description,
3481
+ actions,
3482
+ appearance,
3483
+ className,
3484
+ classNames,
3485
+ style,
3486
+ ...stateProps
3487
+ }, ref) {
3488
+ const resolvedAppearance = useMonkeysBaseAppearance(appearance);
3489
+ const componentAttributes = useMonkeysComponentAttributes();
3490
+ const theme = resolveBaseAppearance(resolvedAppearance);
3491
+ return /* @__PURE__ */ jsxs(
3492
+ "div",
3493
+ {
3494
+ ...componentAttributes,
3495
+ ...stateProps,
3496
+ ref,
3497
+ "data-monkeys-component": "empty-state",
3498
+ "data-slot": "root",
3499
+ "data-state": "empty",
3500
+ className: cn(theme.slots.stateRoot, classNames?.root, className),
3501
+ style: {
3502
+ ...theme.styles.stateRoot,
3503
+ ...style
3504
+ },
3505
+ children: [
3506
+ hasRenderableNode(icon) ? /* @__PURE__ */ jsx(
3507
+ "div",
3508
+ {
3509
+ "data-slot": "icon",
3510
+ "data-state": "empty",
3511
+ className: cn(theme.slots.stateIcon, classNames?.icon),
3512
+ style: theme.styles.stateIcon,
3513
+ children: icon
3514
+ }
3515
+ ) : null,
3516
+ hasRenderableNode(title) ? /* @__PURE__ */ jsx(
3517
+ "div",
3518
+ {
3519
+ "data-slot": "title",
3520
+ "data-state": "empty",
3521
+ className: cn(theme.slots.stateTitle, classNames?.title),
3522
+ children: title
3523
+ }
3524
+ ) : null,
3525
+ hasRenderableNode(description) ? /* @__PURE__ */ jsx(
3526
+ "div",
3527
+ {
3528
+ "data-slot": "description",
3529
+ "data-state": "empty",
3530
+ className: cn(theme.slots.stateDescription, classNames?.description),
3531
+ children: description
3532
+ }
3533
+ ) : null,
3534
+ hasRenderableNode(actions) ? /* @__PURE__ */ jsx(
3535
+ "div",
3536
+ {
3537
+ "data-slot": "actions",
3538
+ "data-state": "empty",
3539
+ className: cn(theme.slots.stateActions, classNames?.actions),
3540
+ children: actions
3541
+ }
3542
+ ) : null
3543
+ ]
3544
+ }
3545
+ );
3546
+ }
3547
+ );
3437
3548
  function mergeAriaIds(...values) {
3438
3549
  const ids = values.flatMap(
3439
3550
  (value) => value?.split(/\s+/).filter(Boolean) ?? []
@@ -3792,6 +3903,170 @@ var BaseInput = forwardRef(
3792
3903
  );
3793
3904
  }
3794
3905
  );
3906
+ function DefaultLoadingIcon({ className }) {
3907
+ return /* @__PURE__ */ jsxs(
3908
+ "svg",
3909
+ {
3910
+ "aria-hidden": "true",
3911
+ viewBox: "0 0 24 24",
3912
+ className,
3913
+ fill: "none",
3914
+ children: [
3915
+ /* @__PURE__ */ jsx(
3916
+ "circle",
3917
+ {
3918
+ cx: "12",
3919
+ cy: "12",
3920
+ r: "9",
3921
+ className: "opacity-25",
3922
+ stroke: "currentColor",
3923
+ strokeWidth: "3"
3924
+ }
3925
+ ),
3926
+ /* @__PURE__ */ jsx(
3927
+ "path",
3928
+ {
3929
+ className: "opacity-75",
3930
+ fill: "currentColor",
3931
+ d: "M12 3a9 9 0 0 1 9 9h-3a6 6 0 0 0-6-6V3Z"
3932
+ }
3933
+ )
3934
+ ]
3935
+ }
3936
+ );
3937
+ }
3938
+ var BaseLoadingState = forwardRef(function BaseLoadingState2({
3939
+ icon,
3940
+ title,
3941
+ description,
3942
+ actions,
3943
+ appearance,
3944
+ className,
3945
+ classNames,
3946
+ style,
3947
+ role = "status",
3948
+ "aria-live": ariaLive = "polite",
3949
+ "aria-busy": ariaBusy = true,
3950
+ "aria-label": nativeAriaLabel,
3951
+ "aria-labelledby": nativeAriaLabelledBy,
3952
+ ...stateProps
3953
+ }, ref) {
3954
+ const resolvedAppearance = useMonkeysBaseAppearance(appearance);
3955
+ const componentAttributes = useMonkeysComponentAttributes();
3956
+ const loadingMessages = useMonkeysLocaleMessages().loading;
3957
+ const theme = resolveBaseAppearance(resolvedAppearance);
3958
+ const resolvedIcon = icon === void 0 ? /* @__PURE__ */ jsx(DefaultLoadingIcon, { className: theme.slots.loadingSpinner }) : icon;
3959
+ const resolvedAriaLabel = nativeAriaLabel ?? (nativeAriaLabelledBy === void 0 ? loadingMessages.spinner : void 0);
3960
+ return /* @__PURE__ */ jsxs(
3961
+ "div",
3962
+ {
3963
+ ...componentAttributes,
3964
+ ...stateProps,
3965
+ ref,
3966
+ role,
3967
+ "aria-live": ariaLive,
3968
+ "aria-busy": ariaBusy,
3969
+ "aria-label": resolvedAriaLabel,
3970
+ "aria-labelledby": nativeAriaLabelledBy,
3971
+ "data-monkeys-component": "loading-state",
3972
+ "data-slot": "root",
3973
+ "data-state": "loading",
3974
+ className: cn(theme.slots.stateRoot, classNames?.root, className),
3975
+ style: {
3976
+ ...theme.styles.stateRoot,
3977
+ ...style
3978
+ },
3979
+ children: [
3980
+ hasRenderableNode(resolvedIcon) ? /* @__PURE__ */ jsx(
3981
+ "div",
3982
+ {
3983
+ "data-slot": "icon",
3984
+ "data-state": "loading",
3985
+ className: cn(theme.slots.stateIcon, classNames?.icon),
3986
+ style: theme.styles.stateIcon,
3987
+ children: resolvedIcon
3988
+ }
3989
+ ) : null,
3990
+ hasRenderableNode(title) ? /* @__PURE__ */ jsx(
3991
+ "div",
3992
+ {
3993
+ "data-slot": "title",
3994
+ "data-state": "loading",
3995
+ className: cn(theme.slots.stateTitle, classNames?.title),
3996
+ children: title
3997
+ }
3998
+ ) : null,
3999
+ hasRenderableNode(description) ? /* @__PURE__ */ jsx(
4000
+ "div",
4001
+ {
4002
+ "data-slot": "description",
4003
+ "data-state": "loading",
4004
+ className: cn(theme.slots.stateDescription, classNames?.description),
4005
+ children: description
4006
+ }
4007
+ ) : null,
4008
+ hasRenderableNode(actions) ? /* @__PURE__ */ jsx(
4009
+ "div",
4010
+ {
4011
+ "data-slot": "actions",
4012
+ "data-state": "loading",
4013
+ className: cn(theme.slots.stateActions, classNames?.actions),
4014
+ children: actions
4015
+ }
4016
+ ) : null
4017
+ ]
4018
+ }
4019
+ );
4020
+ });
4021
+ function BaseNotice({
4022
+ tone,
4023
+ icon,
4024
+ title,
4025
+ description,
4026
+ actions,
4027
+ children,
4028
+ appearance,
4029
+ className,
4030
+ classNames,
4031
+ style,
4032
+ ...noticeProps
4033
+ }) {
4034
+ const theme = resolveBaseAppearance(appearance);
4035
+ const resolvedDescription = children ?? description;
4036
+ return /* @__PURE__ */ jsxs(
4037
+ "div",
4038
+ {
4039
+ ...noticeProps,
4040
+ className: cn(
4041
+ theme.slots.noticeBase,
4042
+ getBaseNoticeToneClassName(theme, tone),
4043
+ classNames?.root,
4044
+ className
4045
+ ),
4046
+ style: {
4047
+ ...theme.styles.notice,
4048
+ ...style
4049
+ },
4050
+ children: [
4051
+ hasRenderableNode(icon) ? /* @__PURE__ */ jsx("div", { className: cn(theme.slots.noticeIcon, classNames?.icon), children: icon }) : null,
4052
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
4053
+ hasRenderableNode(title) ? /* @__PURE__ */ jsx("div", { className: cn(theme.slots.noticeTitle, classNames?.title), children: title }) : null,
4054
+ hasRenderableNode(resolvedDescription) ? /* @__PURE__ */ jsx(
4055
+ "div",
4056
+ {
4057
+ className: cn(
4058
+ theme.slots.noticeDescription,
4059
+ classNames?.description
4060
+ ),
4061
+ children: resolvedDescription
4062
+ }
4063
+ ) : null,
4064
+ hasRenderableNode(actions) ? /* @__PURE__ */ jsx("div", { className: cn(theme.slots.noticeActions, classNames?.actions), children: actions }) : null
4065
+ ] })
4066
+ ]
4067
+ }
4068
+ );
4069
+ }
3795
4070
  var typeaheadResetDelay = 500;
3796
4071
  function validateSelectProps({
3797
4072
  options,
@@ -7945,6 +8220,7 @@ var DEFAULT_MASONRY_GAP_PX = 12;
7945
8220
  var DEFAULT_MASONRY_ROW_HEIGHT_PX = 8;
7946
8221
  var DEFAULT_MASONRY_COLUMN_WIDTH_PX = 280;
7947
8222
  var DEFAULT_MASONRY_ITEM_HEIGHT_PX = 240;
8223
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
7948
8224
  function clamp(value, min, max) {
7949
8225
  return Math.min(Math.max(value, min), max);
7950
8226
  }
@@ -8049,9 +8325,12 @@ function WorkbenchMasonryLayout({
8049
8325
  getItemKey = (item, index) => item?.id ?? item?.key ?? index,
8050
8326
  getItemSize,
8051
8327
  columnWidth = DEFAULT_MASONRY_COLUMN_WIDTH_PX,
8328
+ columnCount: requestedColumnCount,
8052
8329
  gap = DEFAULT_MASONRY_GAP_PX,
8053
8330
  rowHeight = DEFAULT_MASONRY_ROW_HEIGHT_PX,
8054
8331
  placementStrategy = "shelf",
8332
+ containerProps,
8333
+ getItemProps,
8055
8334
  className
8056
8335
  }) {
8057
8336
  const containerRef = useRef(null);
@@ -8082,8 +8361,9 @@ function WorkbenchMasonryLayout({
8082
8361
  }, []);
8083
8362
  useEffect(() => {
8084
8363
  setMeasuredHeights((prev) => {
8364
+ const currentItemKeys = new Set(itemKeys);
8085
8365
  const next = Object.fromEntries(
8086
- Object.entries(prev).filter(([key]) => itemKeys.includes(key))
8366
+ Object.entries(prev).filter(([key]) => currentItemKeys.has(key))
8087
8367
  );
8088
8368
  return areMeasurementMapsEqual(prev, next) ? prev : next;
8089
8369
  });
@@ -8094,7 +8374,8 @@ function WorkbenchMasonryLayout({
8094
8374
  containerRef.current
8095
8375
  );
8096
8376
  const isDensePlacement = placementStrategy === "dense";
8097
- const columnCount = getMasonryColumnCount({
8377
+ const normalizedRequestedColumnCount = Number.isFinite(requestedColumnCount) && Number(requestedColumnCount) > 0 ? clamp(Math.round(Number(requestedColumnCount)), 1, 24) : void 0;
8378
+ const columnCount = normalizedRequestedColumnCount || getMasonryColumnCount({
8098
8379
  containerWidth,
8099
8380
  itemCount: items.length,
8100
8381
  targetColumnWidth: resolvedTargetColumnWidth,
@@ -8140,7 +8421,7 @@ function WorkbenchMasonryLayout({
8140
8421
  resolvedColumnWidth,
8141
8422
  rowHeight
8142
8423
  ]);
8143
- useLayoutEffect(() => {
8424
+ useIsomorphicLayoutEffect(() => {
8144
8425
  const nextMeasurements = {};
8145
8426
  itemNodesRef.current.forEach((node, key) => {
8146
8427
  const nextHeight = Math.ceil(node.getBoundingClientRect().height);
@@ -8202,10 +8483,21 @@ function WorkbenchMasonryLayout({
8202
8483
  const positionedItems = layoutItems.map(({ key, item, columnSpan, rowSpan, size }) => {
8203
8484
  const resolvedSpan = clamp(columnSpan, 1, columnCount);
8204
8485
  let startColumn = nextColumnIndex;
8205
- if (startColumn + resolvedSpan > columnCount) {
8206
- startColumn = 0;
8486
+ if (placementStrategy === "shortest") {
8487
+ let shortestBottom = Number.POSITIVE_INFINITY;
8488
+ for (let candidate = 0; candidate <= columnCount - resolvedSpan; candidate += 1) {
8489
+ const candidateBottom = Math.max(...columnBottoms.slice(candidate, candidate + resolvedSpan));
8490
+ if (candidateBottom < shortestBottom) {
8491
+ shortestBottom = candidateBottom;
8492
+ startColumn = candidate;
8493
+ }
8494
+ }
8495
+ } else {
8496
+ if (startColumn + resolvedSpan > columnCount) {
8497
+ startColumn = 0;
8498
+ }
8499
+ startColumn = Math.min(startColumn, columnCount - resolvedSpan);
8207
8500
  }
8208
- startColumn = Math.min(startColumn, columnCount - resolvedSpan);
8209
8501
  const itemWidth = resolvedColumnWidth * resolvedSpan + gap * Math.max(resolvedSpan - 1, 0);
8210
8502
  const itemHeight = getResolvedItemHeight({
8211
8503
  size,
@@ -8218,9 +8510,11 @@ function WorkbenchMasonryLayout({
8218
8510
  columnBottoms[columnIndex] = bottom + gap;
8219
8511
  }
8220
8512
  maxBottom = Math.max(maxBottom, bottom);
8221
- nextColumnIndex = startColumn + resolvedSpan;
8222
- if (nextColumnIndex >= columnCount) {
8223
- nextColumnIndex = 0;
8513
+ if (placementStrategy !== "shortest") {
8514
+ nextColumnIndex = startColumn + resolvedSpan;
8515
+ if (nextColumnIndex >= columnCount) {
8516
+ nextColumnIndex = 0;
8517
+ }
8224
8518
  }
8225
8519
  return {
8226
8520
  key,
@@ -8243,33 +8537,38 @@ function WorkbenchMasonryLayout({
8243
8537
  "div",
8244
8538
  {
8245
8539
  ref: containerRef,
8246
- className: cn("relative w-full", className),
8247
- style: { height: `${orderedLayout.containerHeight}px` },
8540
+ ...containerProps,
8541
+ className: cn("relative w-full", className, containerProps?.className),
8542
+ style: { ...containerProps?.style, height: `${orderedLayout.containerHeight}px` },
8248
8543
  children: orderedLayout.positionedItems.map(({ key, item, columnSpan, rowSpan, size, itemWidth, left, top }) => {
8249
8544
  const unresolvedSingleColumnWidth = containerWidth <= 0 && columnCount === 1;
8250
8545
  const itemWidthValue = unresolvedSingleColumnWidth ? "100%" : `${itemWidth}px`;
8546
+ const layoutContext = {
8547
+ columnCount,
8548
+ columnSpan,
8549
+ columnWidth: resolvedColumnWidth,
8550
+ containerWidth,
8551
+ gap,
8552
+ itemWidth,
8553
+ placementStrategy,
8554
+ rowSpan,
8555
+ rowHeight,
8556
+ size
8557
+ };
8558
+ const itemProps = getItemProps?.(item, layoutContext);
8251
8559
  return /* @__PURE__ */ jsx(
8252
8560
  "div",
8253
8561
  {
8254
- className: "absolute min-w-0",
8562
+ ...itemProps,
8563
+ className: cn("absolute min-w-0", itemProps?.className),
8255
8564
  style: {
8565
+ ...itemProps?.style,
8256
8566
  left: unresolvedSingleColumnWidth ? 0 : `${left}px`,
8257
8567
  top: `${top}px`,
8258
8568
  width: itemWidthValue,
8259
8569
  maxWidth: itemWidthValue
8260
8570
  },
8261
- children: /* @__PURE__ */ jsx("div", { ref: (node) => registerItemNode(key, node), className: "min-w-0", children: renderItem(item, {
8262
- columnCount,
8263
- columnSpan,
8264
- columnWidth: resolvedColumnWidth,
8265
- containerWidth,
8266
- gap,
8267
- itemWidth,
8268
- placementStrategy,
8269
- rowSpan,
8270
- rowHeight,
8271
- size
8272
- }) })
8571
+ children: /* @__PURE__ */ jsx("div", { ref: (node) => registerItemNode(key, node), role: "presentation", className: "min-w-0", children: renderItem(item, layoutContext) })
8273
8572
  },
8274
8573
  key
8275
8574
  );
@@ -8281,35 +8580,717 @@ function WorkbenchMasonryLayout({
8281
8580
  "div",
8282
8581
  {
8283
8582
  ref: containerRef,
8284
- className: cn("grid w-full items-start", className),
8583
+ ...containerProps,
8584
+ className: cn("grid w-full items-start", className, containerProps?.className),
8285
8585
  style: {
8586
+ ...containerProps?.style,
8286
8587
  gap: `${gap}px`,
8287
8588
  gridAutoFlow: "row dense",
8288
8589
  gridAutoRows: `${rowHeight}px`,
8289
8590
  gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
8290
8591
  },
8291
- children: layoutItems.map(({ key, item, columnSpan, rowSpan, size }) => /* @__PURE__ */ jsx(
8292
- "div",
8592
+ children: layoutItems.map(({ key, item, columnSpan, rowSpan, size }) => {
8593
+ const layoutContext = {
8594
+ columnCount,
8595
+ columnSpan,
8596
+ columnWidth: resolvedColumnWidth,
8597
+ containerWidth,
8598
+ gap,
8599
+ placementStrategy,
8600
+ rowSpan,
8601
+ rowHeight,
8602
+ size
8603
+ };
8604
+ const itemProps = getItemProps?.(item, layoutContext);
8605
+ return /* @__PURE__ */ jsx(
8606
+ "div",
8607
+ {
8608
+ ...itemProps,
8609
+ className: cn("min-w-0", itemProps?.className),
8610
+ style: {
8611
+ ...itemProps?.style,
8612
+ gridColumn: `span ${columnSpan}`,
8613
+ gridRow: `span ${rowSpan}`
8614
+ },
8615
+ children: /* @__PURE__ */ jsx("div", { ref: (node) => registerItemNode(key, node), role: "presentation", className: "min-w-0", children: renderItem(item, layoutContext) })
8616
+ },
8617
+ key
8618
+ );
8619
+ })
8620
+ }
8621
+ );
8622
+ }
8623
+ var DEFAULT_GAP_PX = 12;
8624
+ var DEFAULT_ROW_HEIGHT_PX = 8;
8625
+ var DEFAULT_CARD_WIDTH_PX = 280;
8626
+ var BREAKPOINT_TABLET_PX = 640;
8627
+ var BREAKPOINT_DESKTOP_PX = 1024;
8628
+ var MAX_COLUMN_COUNT = 24;
8629
+ function clamp2(value, min, max) {
8630
+ return Math.min(Math.max(value, min), max);
8631
+ }
8632
+ function resolveRenderableSlot(slot, context) {
8633
+ return typeof slot === "function" ? slot(context) : slot;
8634
+ }
8635
+ function resolveLengthToPixels2(value, fallback, node) {
8636
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
8637
+ if (typeof value !== "string") return fallback;
8638
+ const normalized = value.trim().toLowerCase();
8639
+ if (!normalized) return fallback;
8640
+ if (/^\d+(\.\d+)?(px)?$/.test(normalized)) {
8641
+ const parsed = Number.parseFloat(normalized);
8642
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
8643
+ }
8644
+ if (normalized.endsWith("rem")) {
8645
+ const parsed = Number.parseFloat(normalized);
8646
+ const rootFontSize = typeof window === "undefined" ? 16 : Number.parseFloat(window.getComputedStyle(node || document.documentElement).fontSize) || 16;
8647
+ return Number.isFinite(parsed) && parsed > 0 ? parsed * rootFontSize : fallback;
8648
+ }
8649
+ return fallback;
8650
+ }
8651
+ function normalizeColumns(value) {
8652
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
8653
+ return clamp2(Math.round(value), 1, MAX_COLUMN_COUNT);
8654
+ }
8655
+ function resolveResponsiveColumns(columns, containerWidth) {
8656
+ if (columns === "auto" || columns === void 0) return void 0;
8657
+ if (typeof columns === "number") return normalizeColumns(columns);
8658
+ const mobile = normalizeColumns(columns.mobile);
8659
+ const tablet = normalizeColumns(columns.tablet);
8660
+ const desktop = normalizeColumns(columns.desktop);
8661
+ if (containerWidth >= BREAKPOINT_DESKTOP_PX) return desktop ?? tablet ?? mobile;
8662
+ if (containerWidth >= BREAKPOINT_TABLET_PX) return tablet ?? mobile ?? desktop;
8663
+ return mobile ?? tablet ?? desktop;
8664
+ }
8665
+ function resolveColumnCount({
8666
+ containerWidth,
8667
+ itemCount,
8668
+ gap,
8669
+ columns,
8670
+ minCardWidth,
8671
+ idealCardWidth,
8672
+ maxCardWidth,
8673
+ node
8674
+ }) {
8675
+ const fixedColumns = resolveResponsiveColumns(columns, containerWidth);
8676
+ if (fixedColumns) return fixedColumns;
8677
+ if (!containerWidth) return 1;
8678
+ const idealWidth = resolveLengthToPixels2(idealCardWidth, DEFAULT_CARD_WIDTH_PX, node);
8679
+ const minWidth = resolveLengthToPixels2(minCardWidth, idealWidth * 0.78, node);
8680
+ const maxWidth = Math.max(
8681
+ minWidth,
8682
+ resolveLengthToPixels2(maxCardWidth, idealWidth * 1.35, node)
8683
+ );
8684
+ const safeItemCount = Math.max(itemCount, 1);
8685
+ const maxCandidate = Math.max(
8686
+ 1,
8687
+ Math.min(
8688
+ safeItemCount,
8689
+ Math.ceil((containerWidth + gap) / (Math.max(minWidth * 0.75, 1) + gap))
8690
+ )
8691
+ );
8692
+ let bestCount = 1;
8693
+ let bestScore = Number.POSITIVE_INFINITY;
8694
+ for (let candidate = 1; candidate <= maxCandidate; candidate += 1) {
8695
+ const width = (containerWidth - gap * Math.max(candidate - 1, 0)) / candidate;
8696
+ if (!Number.isFinite(width) || width <= 0) continue;
8697
+ const score = Math.abs(width - idealWidth) + Math.max(0, minWidth - width) * 3 + Math.max(0, width - maxWidth) * 2;
8698
+ if (score < bestScore) {
8699
+ bestScore = score;
8700
+ bestCount = candidate;
8701
+ }
8702
+ }
8703
+ return bestCount;
8704
+ }
8705
+ function normalizeGap(value) {
8706
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : DEFAULT_GAP_PX;
8707
+ }
8708
+ function normalizeRowHeight(value) {
8709
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_ROW_HEIGHT_PX;
8710
+ }
8711
+ function normalizeThreshold(value) {
8712
+ return typeof value === "number" && Number.isFinite(value) ? clamp2(value, 0, 1) : 0;
8713
+ }
8714
+ function normalizeItemSize(size, aspectRatio, columnWidth) {
8715
+ const normalizedAspectRatio = Number.isFinite(aspectRatio) && Number(aspectRatio) > 0 ? Number(aspectRatio) : void 0;
8716
+ const normalizedHeight = size?.height ?? (normalizedAspectRatio ? Math.max(1, columnWidth / normalizedAspectRatio) : void 0);
8717
+ return {
8718
+ ...size,
8719
+ height: normalizedHeight
8720
+ };
8721
+ }
8722
+ function getDefaultItemKey(item, index) {
8723
+ if (item && typeof item === "object") {
8724
+ const candidate = item;
8725
+ if (typeof candidate.id === "string" || typeof candidate.id === "number") return candidate.id;
8726
+ if (typeof candidate.key === "string" || typeof candidate.key === "number") return candidate.key;
8727
+ }
8728
+ return index;
8729
+ }
8730
+ function getScrollStorageKey(key) {
8731
+ return `@inf-monkeys-tech/monkeys-design:workbench-collection:${key}`;
8732
+ }
8733
+ function getParentScrollOwner(node) {
8734
+ let current = node?.parentElement ?? null;
8735
+ while (current) {
8736
+ if (typeof window === "undefined") return current;
8737
+ const overflowY = window.getComputedStyle(current).overflowY;
8738
+ if (overflowY === "auto" || overflowY === "scroll") return current;
8739
+ current = current.parentElement;
8740
+ }
8741
+ return null;
8742
+ }
8743
+ function setsEqual(left, right) {
8744
+ if (left.size !== right.size) return false;
8745
+ for (const value of left) {
8746
+ if (!right.has(value)) return false;
8747
+ }
8748
+ return true;
8749
+ }
8750
+ function isInteractiveEventTarget(target, currentTarget) {
8751
+ if (typeof Element === "undefined" || !(target instanceof Element) || target === currentTarget) return false;
8752
+ const control = target.closest(
8753
+ 'a, button, input, select, textarea, summary, [contenteditable="true"], [data-collection-action]'
8754
+ );
8755
+ return Boolean(control && currentTarget.contains(control));
8756
+ }
8757
+ function warnOnDuplicateKeys(keys) {
8758
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
8759
+ const seen = /* @__PURE__ */ new Set();
8760
+ const duplicates = /* @__PURE__ */ new Set();
8761
+ keys.forEach((key) => {
8762
+ const stringKey = String(key);
8763
+ if (seen.has(stringKey)) duplicates.add(stringKey);
8764
+ seen.add(stringKey);
8765
+ });
8766
+ if (duplicates.size) {
8767
+ console.warn(`WorkbenchCollection received duplicate item keys: ${Array.from(duplicates).join(", ")}`);
8768
+ }
8769
+ }
8770
+ function WorkbenchCollection({
8771
+ items,
8772
+ config,
8773
+ renderItem,
8774
+ slots,
8775
+ callbacks,
8776
+ className,
8777
+ classNames,
8778
+ style,
8779
+ ariaLabel
8780
+ }) {
8781
+ const componentAttributes = useMonkeysComponentAttributes();
8782
+ const localeMessages = useMonkeysLocaleMessages().workbench.collection;
8783
+ const componentId = useId().replace(/:/g, "");
8784
+ const rootRef = useRef(null);
8785
+ const itemsRef = useRef(null);
8786
+ const loadMoreRef = useRef(null);
8787
+ const lastSelectedIndexRef = useRef(null);
8788
+ const loadMoreLockedRef = useRef(false);
8789
+ const layoutReadyRef = useRef(false);
8790
+ const [containerWidth, setContainerWidth] = useState(0);
8791
+ const [itemsNode, setItemsNode] = useState(null);
8792
+ const [internalSelectedKeys, setInternalSelectedKeys] = useState(
8793
+ () => new Set(config.selection?.defaultSelectedKeys ?? [])
8794
+ );
8795
+ const callbacksRef = useRef(callbacks);
8796
+ callbacksRef.current = callbacks;
8797
+ const registerItemsNode = useCallback((node) => {
8798
+ itemsRef.current = node;
8799
+ setItemsNode(node);
8800
+ }, []);
8801
+ const mode = config.layout.mode;
8802
+ if (mode !== "grid" && mode !== "masonry" && mode !== "dense" && mode !== "rail") {
8803
+ throw new TypeError(`WorkbenchCollection layout.mode "${String(mode)}" is not supported.`);
8804
+ }
8805
+ const gap = normalizeGap(config.layout.gap);
8806
+ const rowHeight = normalizeRowHeight(config.layout.rowHeight);
8807
+ const getItemKey = config.getItemKey ?? getDefaultItemKey;
8808
+ const normalizedItems = useMemo(() => items.map((item, index) => {
8809
+ const key = getItemKey(item, index);
8810
+ return { item, index, key, stringKey: String(key) };
8811
+ }), [getItemKey, items]);
8812
+ const keys = useMemo(
8813
+ () => normalizedItems.map(({ key }) => key),
8814
+ [normalizedItems]
8815
+ );
8816
+ const keysSignature = normalizedItems.map(({ stringKey }) => stringKey).join("");
8817
+ useEffect(() => warnOnDuplicateKeys(keys), [keys, keysSignature]);
8818
+ const selectionMode = config.selection?.mode ?? "none";
8819
+ const controlledSelection = config.selection?.selectedKeys !== void 0;
8820
+ const selectedKeys = useMemo(
8821
+ () => selectionMode === "none" ? /* @__PURE__ */ new Set() : controlledSelection ? new Set(config.selection?.selectedKeys ?? []) : internalSelectedKeys,
8822
+ [config.selection?.selectedKeys, controlledSelection, internalSelectedKeys, selectionMode]
8823
+ );
8824
+ useEffect(() => {
8825
+ if (controlledSelection) return;
8826
+ const availableKeys = new Set(keys);
8827
+ setInternalSelectedKeys((previous) => {
8828
+ const next = new Set(Array.from(previous).filter((key) => availableKeys.has(key)));
8829
+ return setsEqual(previous, next) ? previous : next;
8830
+ });
8831
+ }, [controlledSelection, keys, keysSignature]);
8832
+ useEffect(() => {
8833
+ const node = itemsNode;
8834
+ if (!node) return void 0;
8835
+ const updateWidth = () => {
8836
+ const nextWidth = Math.round(node.getBoundingClientRect().width);
8837
+ setContainerWidth((previous) => previous === nextWidth ? previous : nextWidth);
8838
+ };
8839
+ updateWidth();
8840
+ if (typeof ResizeObserver === "function") {
8841
+ const observer = new ResizeObserver(updateWidth);
8842
+ observer.observe(node);
8843
+ return () => observer.disconnect();
8844
+ }
8845
+ if (typeof window === "undefined") return void 0;
8846
+ window.addEventListener("resize", updateWidth);
8847
+ return () => window.removeEventListener("resize", updateWidth);
8848
+ }, [itemsNode]);
8849
+ const columnCount = resolveColumnCount({
8850
+ containerWidth,
8851
+ itemCount: normalizedItems.length,
8852
+ gap,
8853
+ columns: config.layout.columns,
8854
+ minCardWidth: config.layout.minCardWidth,
8855
+ idealCardWidth: config.layout.idealCardWidth ?? config.layout.columnWidth,
8856
+ maxCardWidth: config.layout.maxCardWidth,
8857
+ node: itemsRef.current
8858
+ });
8859
+ const columnWidth = containerWidth > 0 ? Math.max(0, (containerWidth - gap * Math.max(columnCount - 1, 0)) / columnCount) : resolveLengthToPixels2(
8860
+ config.layout.cardWidth ?? config.layout.columnWidth ?? config.layout.idealCardWidth,
8861
+ DEFAULT_CARD_WIDTH_PX,
8862
+ itemsRef.current
8863
+ );
8864
+ const placementStrategy = config.layout.placementStrategy ?? (mode === "dense" ? "dense" : mode === "masonry" ? "shortest" : "shelf");
8865
+ const labels = useMemo(() => ({
8866
+ collection: config.labels?.collection ?? localeMessages.label,
8867
+ loading: config.labels?.loading ?? localeMessages.loading,
8868
+ empty: config.labels?.empty ?? localeMessages.empty,
8869
+ loadError: config.labels?.loadError ?? localeMessages.loadError,
8870
+ refreshError: config.labels?.refreshError ?? localeMessages.refreshError,
8871
+ retry: config.labels?.retry ?? localeMessages.retry,
8872
+ loadingMore: config.labels?.loadingMore ?? localeMessages.loadingMore
8873
+ }), [config.labels, localeMessages]);
8874
+ const virtualizationError = useMemo(() => {
8875
+ const virtualization = config.virtualization;
8876
+ if (virtualization?.enabled !== true || virtualization.fallback !== "error") return null;
8877
+ if (!virtualization.adapter) {
8878
+ return new Error("WorkbenchCollection virtualization requires an adapter.");
8879
+ }
8880
+ if (virtualization.adapter.supports?.(mode) === false) {
8881
+ return new Error(`WorkbenchCollection virtualization adapter does not support mode "${mode}".`);
8882
+ }
8883
+ return null;
8884
+ }, [config.virtualization, mode]);
8885
+ const layoutSnapshot = useMemo(() => ({
8886
+ mode,
8887
+ columnCount,
8888
+ columnWidth,
8889
+ containerWidth,
8890
+ gap,
8891
+ itemCount: normalizedItems.length
8892
+ }), [columnCount, columnWidth, containerWidth, gap, mode, normalizedItems.length]);
8893
+ useEffect(() => {
8894
+ callbacksRef.current?.onLayoutChange?.(layoutSnapshot);
8895
+ if (containerWidth > 0 && !layoutReadyRef.current) {
8896
+ layoutReadyRef.current = true;
8897
+ callbacksRef.current?.onLayoutReady?.(layoutSnapshot);
8898
+ }
8899
+ }, [layoutSnapshot, containerWidth]);
8900
+ useEffect(() => {
8901
+ layoutReadyRef.current = false;
8902
+ }, [mode]);
8903
+ const resolveScrollOwner = useCallback(() => {
8904
+ const requestedOwner = config.layout.scrollOwner;
8905
+ if (requestedOwner && requestedOwner !== "self" && requestedOwner !== "parent") return requestedOwner;
8906
+ if (requestedOwner === "parent") return getParentScrollOwner(rootRef.current);
8907
+ return rootRef.current;
8908
+ }, [config.layout.scrollOwner]);
8909
+ useEffect(() => {
8910
+ const restorationKey = config.scrollRestorationKey?.trim();
8911
+ if (!restorationKey || typeof window === "undefined") return void 0;
8912
+ const owner = resolveScrollOwner();
8913
+ if (!owner) return void 0;
8914
+ const storageKey = getScrollStorageKey(restorationKey);
8915
+ try {
8916
+ const stored = Number.parseFloat(window.sessionStorage.getItem(storageKey) ?? "");
8917
+ if (Number.isFinite(stored) && stored >= 0) owner.scrollTop = stored;
8918
+ } catch {
8919
+ }
8920
+ const saveScrollPosition = () => {
8921
+ try {
8922
+ window.sessionStorage.setItem(storageKey, String(owner.scrollTop));
8923
+ } catch {
8924
+ }
8925
+ };
8926
+ owner.addEventListener("scroll", saveScrollPosition, { passive: true });
8927
+ return () => {
8928
+ saveScrollPosition();
8929
+ owner.removeEventListener("scroll", saveScrollPosition);
8930
+ };
8931
+ }, [config.scrollRestorationKey, resolveScrollOwner]);
8932
+ const state = config.state;
8933
+ const loading = state?.loading === true;
8934
+ const loadingMore = state?.loadingMore === true;
8935
+ const hasMore = state?.hasMore === true;
8936
+ const canLoadMore = typeof callbacks?.onLoadMore === "function";
8937
+ const effectiveError = state?.error ?? virtualizationError;
8938
+ useEffect(() => {
8939
+ if (!loadingMore || !hasMore) loadMoreLockedRef.current = false;
8940
+ }, [hasMore, loadingMore, normalizedItems.length, keysSignature]);
8941
+ useEffect(() => {
8942
+ const sentinel = loadMoreRef.current;
8943
+ if (!sentinel || !canLoadMore || !hasMore || loadingMore) return void 0;
8944
+ if (typeof IntersectionObserver !== "function") return void 0;
8945
+ const owner = resolveScrollOwner();
8946
+ const observer = new IntersectionObserver((entries) => {
8947
+ if (!entries.some((entry) => entry.isIntersecting) || loadMoreLockedRef.current) return;
8948
+ loadMoreLockedRef.current = true;
8949
+ try {
8950
+ const result = callbacksRef.current?.onLoadMore?.();
8951
+ if (result && typeof result.then === "function") {
8952
+ void result.catch(() => {
8953
+ loadMoreLockedRef.current = false;
8954
+ });
8955
+ }
8956
+ } catch (error) {
8957
+ loadMoreLockedRef.current = false;
8958
+ throw error;
8959
+ }
8960
+ }, {
8961
+ root: owner === rootRef.current ? owner : owner || null,
8962
+ rootMargin: config.loading?.rootMargin ?? "240px",
8963
+ threshold: normalizeThreshold(config.loading?.threshold)
8964
+ });
8965
+ observer.observe(sentinel);
8966
+ return () => observer.disconnect();
8967
+ }, [canLoadMore, config.loading?.rootMargin, config.loading?.threshold, hasMore, keysSignature, loadingMore, normalizedItems.length, resolveScrollOwner]);
8968
+ const groups = useMemo(() => {
8969
+ if (!config.grouping) {
8970
+ return [{ key: "__all__", stringKey: "__all__", items: normalizedItems }];
8971
+ }
8972
+ const grouped = /* @__PURE__ */ new Map();
8973
+ normalizedItems.forEach((entry) => {
8974
+ const groupKey = config.grouping?.getGroupKey(entry.item, entry.index) ?? "__all__";
8975
+ const stringKey = String(groupKey);
8976
+ const existing = grouped.get(stringKey);
8977
+ if (existing) {
8978
+ existing.items.push(entry);
8979
+ return;
8980
+ }
8981
+ grouped.set(stringKey, {
8982
+ key: groupKey,
8983
+ stringKey,
8984
+ label: config.grouping?.getGroupLabel?.(groupKey, entry.item),
8985
+ items: [entry]
8986
+ });
8987
+ });
8988
+ return Array.from(grouped.values());
8989
+ }, [config.grouping, normalizedItems]);
8990
+ const setSelection = useCallback((entry, behavior = config.selection?.behavior ?? (selectionMode === "multiple" ? "toggle" : "replace")) => {
8991
+ if (selectionMode === "none" || config.selection?.isItemDisabled?.(entry.item, entry.index)) return;
8992
+ const current = new Set(selectedKeys);
8993
+ const next = /* @__PURE__ */ new Set();
8994
+ if (selectionMode === "single") {
8995
+ if (!(behavior === "toggle" && current.has(entry.key))) next.add(entry.key);
8996
+ } else if (behavior === "range" && lastSelectedIndexRef.current !== null) {
8997
+ current.forEach((key) => next.add(key));
8998
+ const start = Math.min(lastSelectedIndexRef.current, entry.index);
8999
+ const end = Math.max(lastSelectedIndexRef.current, entry.index);
9000
+ normalizedItems.slice(start, end + 1).forEach((candidate) => {
9001
+ if (!config.selection?.isItemDisabled?.(candidate.item, candidate.index)) next.add(candidate.key);
9002
+ });
9003
+ } else if (behavior === "replace") {
9004
+ next.add(entry.key);
9005
+ } else {
9006
+ current.forEach((key) => next.add(key));
9007
+ if (next.has(entry.key)) next.delete(entry.key);
9008
+ else next.add(entry.key);
9009
+ }
9010
+ lastSelectedIndexRef.current = entry.index;
9011
+ if (!controlledSelection) setInternalSelectedKeys(next);
9012
+ callbacks?.onSelectionChange?.(next, { item: entry.item, key: entry.key, behavior });
9013
+ }, [callbacks, config.selection, controlledSelection, normalizedItems, selectedKeys, selectionMode]);
9014
+ const createItemContext = useCallback((entry, layout) => {
9015
+ const disabled = config.selection?.isItemDisabled?.(entry.item, entry.index) ?? false;
9016
+ const context = {
9017
+ item: entry.item,
9018
+ index: entry.index,
9019
+ key: entry.key,
9020
+ status: config.getItemStatus?.(entry.item, entry.index) ?? "idle",
9021
+ disabled,
9022
+ selected: selectedKeys.has(entry.key),
9023
+ selectionMode,
9024
+ layout,
9025
+ select: (behavior) => setSelection(entry, behavior),
9026
+ preview: () => callbacks?.onItemPreview?.(entry.item, context),
9027
+ detail: () => callbacks?.onItemDetail?.(entry.item, context),
9028
+ renderSlot: (name) => {
9029
+ return slots?.item?.[name]?.(entry.item, context);
9030
+ },
9031
+ notifyMediaLoad: () => callbacks?.onMediaLoad?.(entry.item, context),
9032
+ notifyMediaError: (error) => callbacks?.onMediaError?.(entry.item, context, error)
9033
+ };
9034
+ return context;
9035
+ }, [callbacks, config.getItemStatus, config.selection, selectedKeys, selectionMode, setSelection, slots?.item]);
9036
+ const getItemInteractionProps = useCallback((entry, context) => {
9037
+ const handleKeyboard = (event) => {
9038
+ if (event.target !== event.currentTarget || event.key !== "Enter" && event.key !== " ") return;
9039
+ event.preventDefault();
9040
+ if (selectionMode !== "none") context.select(event.shiftKey ? "range" : void 0);
9041
+ else callbacks?.onItemClick?.(entry.item, context, event);
9042
+ };
9043
+ return {
9044
+ id: `${componentId}-item-${entry.index}`,
9045
+ "data-monkeys-collection-item": "",
9046
+ "data-item-key": entry.stringKey,
9047
+ "data-selected": context.selected || void 0,
9048
+ "data-disabled": context.disabled || void 0,
9049
+ "data-status": context.status,
9050
+ role: selectionMode === "none" ? "listitem" : "option",
9051
+ "aria-selected": selectionMode === "none" ? void 0 : context.selected,
9052
+ "aria-disabled": context.disabled || void 0,
9053
+ tabIndex: callbacks?.onItemClick || selectionMode !== "none" ? 0 : void 0,
9054
+ draggable: callbacks?.onItemDragStart ? true : void 0,
9055
+ className: cn(
9056
+ "min-w-0 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
9057
+ config.appearance?.hover === "lift" && "transition-transform hover:-translate-y-0.5 motion-reduce:transform-none",
9058
+ config.appearance?.selection === "ring" && context.selected && "ring-2 ring-primary",
9059
+ config.appearance?.selection === "outline" && context.selected && "outline outline-2 outline-primary",
9060
+ classNames?.item
9061
+ ),
9062
+ onClick: (event) => {
9063
+ if (isInteractiveEventTarget(event.target, event.currentTarget)) return;
9064
+ if (selectionMode !== "none") context.select(event.shiftKey ? "range" : void 0);
9065
+ callbacks?.onItemClick?.(entry.item, context, event);
9066
+ },
9067
+ onDoubleClick: (event) => {
9068
+ if (isInteractiveEventTarget(event.target, event.currentTarget)) return;
9069
+ callbacks?.onItemDoubleClick?.(entry.item, context, event);
9070
+ },
9071
+ onKeyDown: handleKeyboard,
9072
+ onDragStart: (event) => callbacks?.onItemDragStart?.(entry.item, context, event),
9073
+ onDragOver: callbacks?.onItemDrop ? (event) => event.preventDefault() : void 0,
9074
+ onDrop: (event) => callbacks?.onItemDrop?.(entry.item, context, event)
9075
+ };
9076
+ }, [callbacks, classNames?.item, componentId, config.appearance, selectionMode]);
9077
+ const renderEntry = useCallback((entry, layout, includeShell = true) => {
9078
+ const context = createItemContext(entry, layout);
9079
+ if (!includeShell) return renderItem(entry.item, context);
9080
+ return /* @__PURE__ */ jsx("div", { ...getItemInteractionProps(entry, context), children: renderItem(entry.item, context) });
9081
+ }, [createItemContext, getItemInteractionProps, renderItem]);
9082
+ const baseLayoutContext = useMemo(() => ({
9083
+ mode,
9084
+ columnCount,
9085
+ columnWidth,
9086
+ containerWidth,
9087
+ gap,
9088
+ placementStrategy,
9089
+ rowHeight
9090
+ }), [columnCount, columnWidth, containerWidth, gap, mode, placementStrategy, rowHeight]);
9091
+ const renderGroupItems = (group) => {
9092
+ const virtualization = config.virtualization;
9093
+ const adapter = virtualization?.adapter;
9094
+ const virtualizationRequested = virtualization?.enabled === true;
9095
+ if (virtualizationRequested && (!adapter || adapter.supports?.(mode) === false)) {
9096
+ if (virtualization?.fallback === "error") {
9097
+ return null;
9098
+ }
9099
+ }
9100
+ if (virtualizationRequested && adapter && adapter.supports?.(mode) !== false) {
9101
+ return adapter.render({
9102
+ items: group.items.map(({ item }) => item),
9103
+ keys: group.items.map(({ key }) => key),
9104
+ layout: config.layout,
9105
+ scrollOwner: resolveScrollOwner(),
9106
+ renderItem: (item, localIndex, layout) => {
9107
+ const entry = group.items[localIndex];
9108
+ return entry ? renderEntry(entry, layout) : null;
9109
+ }
9110
+ });
9111
+ }
9112
+ if (mode === "masonry" || mode === "dense") {
9113
+ return /* @__PURE__ */ jsx(
9114
+ WorkbenchMasonryLayout,
8293
9115
  {
8294
- className: "min-w-0",
8295
- style: {
8296
- gridColumn: `span ${columnSpan}`,
8297
- gridRow: `span ${rowSpan}`
9116
+ items: group.items,
9117
+ columnCount,
9118
+ columnWidth: config.layout.cardWidth ?? config.layout.columnWidth ?? config.layout.idealCardWidth,
9119
+ gap,
9120
+ rowHeight,
9121
+ placementStrategy: mode === "dense" ? "dense" : placementStrategy,
9122
+ className: classNames?.layout,
9123
+ containerProps: {
9124
+ role: selectionMode === "none" ? "list" : "listbox",
9125
+ "aria-label": ariaLabel ?? labels.collection,
9126
+ "aria-multiselectable": selectionMode === "multiple" || void 0
8298
9127
  },
8299
- children: /* @__PURE__ */ jsx("div", { ref: (node) => registerItemNode(key, node), className: "h-full", children: renderItem(item, {
8300
- columnCount,
8301
- columnSpan,
8302
- columnWidth: resolvedColumnWidth,
8303
- containerWidth,
8304
- gap,
8305
- placementStrategy,
8306
- rowSpan,
8307
- rowHeight,
8308
- size
8309
- }) })
9128
+ getItemProps: (entry, masonryLayout) => {
9129
+ const context = createItemContext(entry, { ...masonryLayout, mode });
9130
+ return getItemInteractionProps(entry, context);
9131
+ },
9132
+ getItemKey: (entry) => entry.key,
9133
+ getItemSize: (entry, masonryLayout) => {
9134
+ const layout = {
9135
+ ...masonryLayout,
9136
+ mode
9137
+ };
9138
+ const customSize = config.layout.getItemSize?.(entry.item, layout);
9139
+ const aspectRatio = config.layout.getItemAspectRatio?.(entry.item, entry.index);
9140
+ return normalizeItemSize(customSize, aspectRatio, masonryLayout.columnWidth);
9141
+ },
9142
+ renderItem: (entry, masonryLayout) => renderEntry(entry, {
9143
+ ...masonryLayout,
9144
+ mode
9145
+ }, false)
9146
+ }
9147
+ );
9148
+ }
9149
+ if (mode === "rail") {
9150
+ const cardWidth = config.layout.cardWidth ?? config.layout.idealCardWidth ?? DEFAULT_CARD_WIDTH_PX;
9151
+ return /* @__PURE__ */ jsx(
9152
+ "div",
9153
+ {
9154
+ role: selectionMode === "none" ? "list" : "listbox",
9155
+ "aria-label": ariaLabel ?? labels.collection,
9156
+ "aria-multiselectable": selectionMode === "multiple" || void 0,
9157
+ className: cn("grid min-w-0 grid-flow-col items-start overflow-x-auto", classNames?.layout),
9158
+ style: { gap, gridAutoColumns: typeof cardWidth === "number" ? `${cardWidth}px` : cardWidth },
9159
+ children: group.items.map((entry) => /* @__PURE__ */ jsx(Fragment$1, { children: renderEntry(entry, baseLayoutContext) }, entry.stringKey))
9160
+ }
9161
+ );
9162
+ }
9163
+ return /* @__PURE__ */ jsx(
9164
+ "div",
9165
+ {
9166
+ role: selectionMode === "none" ? "list" : "listbox",
9167
+ "aria-label": ariaLabel ?? labels.collection,
9168
+ "aria-multiselectable": selectionMode === "multiple" || void 0,
9169
+ className: cn("grid min-w-0 items-start", classNames?.layout),
9170
+ style: {
9171
+ gap,
9172
+ gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
8310
9173
  },
8311
- key
8312
- ))
9174
+ children: group.items.map((entry) => {
9175
+ const customSize = config.layout.getItemSize?.(entry.item, baseLayoutContext);
9176
+ const span = clamp2(Math.round(Number(customSize?.columnSpan) || 1), 1, columnCount);
9177
+ const aspectRatio = config.layout.getItemAspectRatio?.(entry.item, entry.index);
9178
+ return /* @__PURE__ */ jsx(
9179
+ "div",
9180
+ {
9181
+ ...getItemInteractionProps(
9182
+ entry,
9183
+ createItemContext(entry, { ...baseLayoutContext, columnSpan: span, size: customSize })
9184
+ ),
9185
+ style: {
9186
+ gridColumn: span > 1 ? `span ${span}` : void 0,
9187
+ aspectRatio: Number.isFinite(aspectRatio) && Number(aspectRatio) > 0 ? String(aspectRatio) : void 0
9188
+ },
9189
+ children: renderEntry(entry, { ...baseLayoutContext, columnSpan: span, size: customSize }, false)
9190
+ },
9191
+ entry.stringKey
9192
+ );
9193
+ })
9194
+ }
9195
+ );
9196
+ };
9197
+ const slotContext = {
9198
+ items,
9199
+ error: effectiveError,
9200
+ loading,
9201
+ loadingMore,
9202
+ selectedKeys,
9203
+ retry: () => callbacks?.onRetry?.()
9204
+ };
9205
+ const header = resolveRenderableSlot(slots?.header, slotContext);
9206
+ const toolbar = resolveRenderableSlot(slots?.toolbar, slotContext);
9207
+ const selectionToolbar = selectedKeys.size > 0 ? resolveRenderableSlot(slots?.selectionToolbar, slotContext) : null;
9208
+ const beforeItems = resolveRenderableSlot(slots?.beforeItems, slotContext);
9209
+ const footer = resolveRenderableSlot(slots?.footer, slotContext);
9210
+ const showInitialLoading = loading && items.length === 0;
9211
+ const showInitialError = Boolean(effectiveError) && items.length === 0 && !showInitialLoading;
9212
+ const showEmpty = !showInitialLoading && !showInitialError && (state?.empty === true || items.length === 0);
9213
+ const loadingSlot = resolveRenderableSlot(slots?.loading, slotContext);
9214
+ const errorSlot = resolveRenderableSlot(slots?.error, slotContext);
9215
+ const emptySlot = resolveRenderableSlot(slots?.empty, slotContext);
9216
+ const loadMoreSlot = resolveRenderableSlot(slots?.loadMore, slotContext);
9217
+ const selfScrollable = config.layout.scrollOwner === "self" || config.layout.scrollOwner === void 0 && (config.layout.fillHeight || config.layout.maxHeight);
9218
+ const rootStyle = {
9219
+ ...style,
9220
+ padding: config.layout.padding ?? style?.padding,
9221
+ height: config.layout.fillHeight ? "100%" : style?.height,
9222
+ maxHeight: config.layout.maxHeight ?? style?.maxHeight,
9223
+ overflow: selfScrollable ? "auto" : style?.overflow
9224
+ };
9225
+ return /* @__PURE__ */ jsxs(
9226
+ "section",
9227
+ {
9228
+ ref: rootRef,
9229
+ ...componentAttributes,
9230
+ "data-monkeys-component": "workbench-collection",
9231
+ "data-layout-mode": mode,
9232
+ "data-density": config.appearance?.density,
9233
+ "data-radius": config.appearance?.radius,
9234
+ "data-media-fit": config.appearance?.mediaFit,
9235
+ "aria-label": ariaLabel ?? labels.collection,
9236
+ "aria-busy": loading || loadingMore || void 0,
9237
+ className: cn("min-h-0 min-w-0", config.layout.fillHeight && "h-full", classNames?.root, className),
9238
+ style: rootStyle,
9239
+ children: [
9240
+ hasRenderableNode(header) ? /* @__PURE__ */ jsx("div", { className: classNames?.header, children: header }) : null,
9241
+ hasRenderableNode(toolbar) ? /* @__PURE__ */ jsx("div", { className: classNames?.toolbar, children: toolbar }) : null,
9242
+ hasRenderableNode(selectionToolbar) ? /* @__PURE__ */ jsx("div", { className: classNames?.selectionToolbar, children: selectionToolbar }) : null,
9243
+ hasRenderableNode(beforeItems) ? /* @__PURE__ */ jsx("div", { className: classNames?.beforeItems, children: beforeItems }) : null,
9244
+ showInitialLoading ? hasRenderableNode(loadingSlot) ? loadingSlot : /* @__PURE__ */ jsx(BaseLoadingState, { title: labels.loading }) : showInitialError ? hasRenderableNode(errorSlot) ? errorSlot : /* @__PURE__ */ jsx(
9245
+ BaseNotice,
9246
+ {
9247
+ tone: "danger",
9248
+ role: "alert",
9249
+ "aria-live": "assertive",
9250
+ title: labels.loadError,
9251
+ actions: callbacks?.onRetry ? /* @__PURE__ */ jsx(BaseButton, { size: "sm", label: labels.retry, onClick: callbacks.onRetry }) : void 0
9252
+ }
9253
+ ) : showEmpty ? hasRenderableNode(emptySlot) ? emptySlot : /* @__PURE__ */ jsx(BaseEmptyState, { title: labels.empty }) : /* @__PURE__ */ jsx(
9254
+ "div",
9255
+ {
9256
+ ref: registerItemsNode,
9257
+ className: cn("min-w-0", classNames?.items),
9258
+ children: groups.map((group, groupIndex) => {
9259
+ const groupContext = {
9260
+ key: group.key,
9261
+ label: group.label,
9262
+ items: group.items.map(({ item }) => item),
9263
+ groupIndex
9264
+ };
9265
+ const heading = config.grouping ? slots?.groupHeading?.(groupContext, slotContext) ?? group.label : null;
9266
+ const headingId = `${componentId}-group-${groupIndex}`;
9267
+ return /* @__PURE__ */ jsxs(
9268
+ "div",
9269
+ {
9270
+ "data-collection-group": group.stringKey,
9271
+ className: classNames?.group,
9272
+ children: [
9273
+ hasRenderableNode(heading) ? /* @__PURE__ */ jsx("div", { id: headingId, role: "heading", "aria-level": 2, className: classNames?.groupHeading, children: heading }) : null,
9274
+ renderGroupItems(group)
9275
+ ]
9276
+ },
9277
+ group.stringKey
9278
+ );
9279
+ })
9280
+ }
9281
+ ),
9282
+ items.length > 0 && effectiveError ? /* @__PURE__ */ jsx("div", { className: classNames?.status, children: hasRenderableNode(errorSlot) ? errorSlot : /* @__PURE__ */ jsx(
9283
+ BaseNotice,
9284
+ {
9285
+ tone: "danger",
9286
+ role: "alert",
9287
+ title: labels.refreshError,
9288
+ actions: callbacks?.onRetry ? /* @__PURE__ */ jsx(BaseButton, { size: "sm", label: labels.retry, onClick: callbacks.onRetry }) : void 0
9289
+ }
9290
+ ) }) : null,
9291
+ items.length > 0 && (hasMore || loadingMore) ? /* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: classNames?.loadMore, "data-collection-load-more": "", children: hasRenderableNode(loadMoreSlot) ? loadMoreSlot : loadingMore ? /* @__PURE__ */ jsx(BaseLoadingState, { title: labels.loadingMore }) : null }) : null,
9292
+ hasRenderableNode(footer) ? /* @__PURE__ */ jsx("div", { className: classNames?.footer, children: footer }) : null
9293
+ ]
8313
9294
  }
8314
9295
  );
8315
9296
  }
@@ -8750,45 +9731,54 @@ function WorkbenchGalleryView({
8750
9731
  );
8751
9732
  if (isMasonry) {
8752
9733
  return /* @__PURE__ */ jsx(
8753
- WorkbenchMasonryLayout,
9734
+ WorkbenchCollection,
8754
9735
  {
8755
9736
  items: rows,
8756
- className,
8757
- gap: GALLERY_GRID_GAP_PX,
8758
- columnWidth: resolvedMasonryColumnWidth,
8759
- placementStrategy: masonryPlacementStrategy,
8760
- getItemKey: (row, rowIndex) => row?.id || row?.linkKey || rowIndex,
8761
- getItemSize: (row, layout) => {
8762
- const defaultSize = getDefaultGalleryMasonryItemSize({
8763
- row,
8764
- columns,
8765
- galleryFieldKey,
8766
- galleryDensity,
8767
- galleryBentoColumns,
8768
- galleryDetailVisibility,
8769
- galleryDetailLimit,
8770
- getFieldValue: resolvedGetFieldValue,
8771
- isMediaColumn: resolvedIsMediaColumn,
8772
- isTitleCandidate: resolvedIsTitleCandidate,
8773
- isSummaryCandidate: resolvedIsSummaryCandidate,
8774
- getDisplayText: resolvedGetDisplayText,
8775
- isImageField: resolvedIsImageField,
8776
- isAudioField: resolvedIsAudioField,
8777
- cardVariant,
8778
- renderPreview,
8779
- renderLeadingVisual,
8780
- hiddenDetailFieldKeys,
8781
- layout,
8782
- resolveRecordVisual
8783
- });
8784
- if (typeof getMasonryItemSize !== "function") return defaultSize;
8785
- const customSize = getMasonryItemSize(row, { ...layout, defaultSize }) || {};
8786
- return {
8787
- ...defaultSize,
8788
- ...customSize
8789
- };
9737
+ classNames: { layout: className },
9738
+ config: {
9739
+ getItemKey: (row, rowIndex) => row?.id || row?.linkKey || rowIndex,
9740
+ layout: {
9741
+ mode: masonryPlacementStrategy === "dense" ? "dense" : "masonry",
9742
+ gap: GALLERY_GRID_GAP_PX,
9743
+ idealCardWidth: resolvedMasonryColumnWidth,
9744
+ placementStrategy: masonryPlacementStrategy,
9745
+ getItemSize: (row, layout) => {
9746
+ const defaultSize = getDefaultGalleryMasonryItemSize({
9747
+ row,
9748
+ columns,
9749
+ galleryFieldKey,
9750
+ galleryDensity,
9751
+ galleryBentoColumns,
9752
+ galleryDetailVisibility,
9753
+ galleryDetailLimit,
9754
+ getFieldValue: resolvedGetFieldValue,
9755
+ isMediaColumn: resolvedIsMediaColumn,
9756
+ isTitleCandidate: resolvedIsTitleCandidate,
9757
+ isSummaryCandidate: resolvedIsSummaryCandidate,
9758
+ getDisplayText: resolvedGetDisplayText,
9759
+ isImageField: resolvedIsImageField,
9760
+ isAudioField: resolvedIsAudioField,
9761
+ cardVariant,
9762
+ renderPreview,
9763
+ renderLeadingVisual,
9764
+ hiddenDetailFieldKeys,
9765
+ layout,
9766
+ resolveRecordVisual
9767
+ });
9768
+ if (typeof getMasonryItemSize !== "function") return defaultSize;
9769
+ const customSize = getMasonryItemSize(row, {
9770
+ ...layout,
9771
+ placementStrategy: layout.placementStrategy === "dense" ? "dense" : "shelf",
9772
+ defaultSize
9773
+ }) || {};
9774
+ return {
9775
+ ...defaultSize,
9776
+ ...customSize
9777
+ };
9778
+ }
9779
+ }
8790
9780
  },
8791
- renderItem: (row) => renderGalleryCard(row, rows.indexOf(row))
9781
+ renderItem: (row, context) => renderGalleryCard(row, context.index)
8792
9782
  }
8793
9783
  );
8794
9784
  }
@@ -9306,7 +10296,7 @@ var getDomain = (values, min, max) => {
9306
10296
  return lower < upper ? [lower, upper] : [upper, lower];
9307
10297
  };
9308
10298
  var scale = (value, domain, start, end) => start + (value - domain[0]) / (domain[1] - domain[0]) * (end - start);
9309
- var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
10299
+ var clamp3 = (value, min, max) => Math.min(max, Math.max(min, value));
9310
10300
  var activatePoint = (event, point, onPointSelect) => {
9311
10301
  if (!onPointSelect || event.key !== "Enter" && event.key !== " ") return;
9312
10302
  event.preventDefault();
@@ -9388,9 +10378,9 @@ function WorkbenchScatterPlot({
9388
10378
  xThreshold === void 0 ? null : /* @__PURE__ */ jsx(
9389
10379
  "line",
9390
10380
  {
9391
- x1: clamp2(xThreshold, plotLeft, plotRight),
10381
+ x1: clamp3(xThreshold, plotLeft, plotRight),
9392
10382
  y1: plotTop,
9393
- x2: clamp2(xThreshold, plotLeft, plotRight),
10383
+ x2: clamp3(xThreshold, plotLeft, plotRight),
9394
10384
  y2: plotBottom,
9395
10385
  className: "stroke-muted-foreground/50",
9396
10386
  strokeDasharray: "5 5"
@@ -9400,9 +10390,9 @@ function WorkbenchScatterPlot({
9400
10390
  "line",
9401
10391
  {
9402
10392
  x1: plotLeft,
9403
- y1: clamp2(yThreshold, plotTop, plotBottom),
10393
+ y1: clamp3(yThreshold, plotTop, plotBottom),
9404
10394
  x2: plotRight,
9405
- y2: clamp2(yThreshold, plotTop, plotBottom),
10395
+ y2: clamp3(yThreshold, plotTop, plotBottom),
9406
10396
  className: "stroke-muted-foreground/50",
9407
10397
  strokeDasharray: "5 5"
9408
10398
  }
@@ -9429,17 +10419,17 @@ function WorkbenchScatterPlot({
9429
10419
  }
9430
10420
  ),
9431
10421
  validPoints.map((point) => {
9432
- const x = clamp2(
10422
+ const x = clamp3(
9433
10423
  scale(point.x, xDomain, plotLeft, plotRight),
9434
10424
  plotLeft,
9435
10425
  plotRight
9436
10426
  );
9437
- const y = clamp2(
10427
+ const y = clamp3(
9438
10428
  scale(point.y, yDomain, plotBottom, plotTop),
9439
10429
  plotTop,
9440
10430
  plotBottom
9441
10431
  );
9442
- const radius = point.size === void 0 ? 9 : clamp2(scale(point.size, sizeDomain, 7, 18), 7, 18);
10432
+ const radius = point.size === void 0 ? 9 : clamp3(scale(point.size, sizeDomain, 7, 18), 7, 18);
9443
10433
  const selected = selectedPointId === point.id;
9444
10434
  return /* @__PURE__ */ jsxs(
9445
10435
  "g",
@@ -9971,7 +10961,7 @@ var getDomain2 = (values, min, max) => {
9971
10961
  return lower < upper ? [lower, upper] : [upper, lower];
9972
10962
  };
9973
10963
  var scale2 = (value, domain, start, end) => start + (value - domain[0]) / (domain[1] - domain[0]) * (end - start);
9974
- var clamp3 = (value, min, max) => Math.min(max, Math.max(min, value));
10964
+ var clamp4 = (value, min, max) => Math.min(max, Math.max(min, value));
9975
10965
  var toneVariable = {
9976
10966
  primary: "--radar-series-one",
9977
10967
  secondary: "--radar-series-two",
@@ -10034,7 +11024,7 @@ function WorkbenchRadarMatrix({
10034
11024
  const plotRight = width;
10035
11025
  const plotTop = 0;
10036
11026
  const plotBottom = height;
10037
- const xThreshold = clamp3(
11027
+ const xThreshold = clamp4(
10038
11028
  scale2(
10039
11029
  Number.isFinite(thresholds?.x) ? Number(thresholds?.x) : (xDomain[0] + xDomain[1]) / 2,
10040
11030
  xDomain,
@@ -10044,7 +11034,7 @@ function WorkbenchRadarMatrix({
10044
11034
  plotLeft,
10045
11035
  plotRight
10046
11036
  );
10047
- const yThreshold = clamp3(
11037
+ const yThreshold = clamp4(
10048
11038
  scale2(
10049
11039
  Number.isFinite(thresholds?.y) ? Number(thresholds?.y) : (yDomain[0] + yDomain[1]) / 2,
10050
11040
  yDomain,
@@ -10152,13 +11142,13 @@ function WorkbenchRadarMatrix({
10152
11142
  ] }, quadrant.id);
10153
11143
  }),
10154
11144
  validPoints.map((point, index) => {
10155
- const x = clamp3(scale2(point.x, xDomain, 40, width - 40), 40, width - 40);
10156
- const y = clamp3(scale2(point.y, yDomain, height - 48, 54), 54, height - 48);
11145
+ const x = clamp4(scale2(point.x, xDomain, 40, width - 40), 40, width - 40);
11146
+ const y = clamp4(scale2(point.y, yDomain, height - 48, 54), 54, height - 48);
10157
11147
  const tone = point.tone || (index % 2 === 0 ? "primary" : "accent");
10158
11148
  const selected = selectedPointId === point.id;
10159
11149
  const labelled = labelledPointIds.has(point.id);
10160
- const radius = labelled ? clamp3(scale2(point.size ?? 1, sizeDomain, 5, 9), 5, 9) : 3.5;
10161
- const fontSize = labelled ? clamp3(scale2(point.size ?? 1, sizeDomain, 14, 31), 14, 31) : 0;
11150
+ const radius = labelled ? clamp4(scale2(point.size ?? 1, sizeDomain, 5, 9), 5, 9) : 3.5;
11151
+ const fontSize = labelled ? clamp4(scale2(point.size ?? 1, sizeDomain, 14, 31), 14, 31) : 0;
10162
11152
  const pointStyle = {
10163
11153
  fill: toneColor(tone),
10164
11154
  stroke: "hsl(var(--foreground) / 0.74)"
@@ -10260,8 +11250,8 @@ function WorkbenchRadarMatrix({
10260
11250
  validPoints.map((point, index) => /* @__PURE__ */ jsx(
10261
11251
  "circle",
10262
11252
  {
10263
- cx: clamp3(scale2(point.x, xDomain, 40, width - 40), 40, width - 40),
10264
- cy: clamp3(scale2(point.y, yDomain, height - 48, 54), 54, height - 48),
11253
+ cx: clamp4(scale2(point.x, xDomain, 40, width - 40), 40, width - 40),
11254
+ cy: clamp4(scale2(point.y, yDomain, height - 48, 54), 54, height - 48),
10265
11255
  r: "8",
10266
11256
  style: { fill: toneColor(point.tone || (index % 2 === 0 ? "primary" : "accent")) }
10267
11257
  },
@@ -10295,6 +11285,6 @@ function WorkbenchRadarMatrix({
10295
11285
  );
10296
11286
  }
10297
11287
 
10298
- export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchRadarFilterChip, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView };
11288
+ export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchCollection, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchRadarFilterChip, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView };
10299
11289
  //# sourceMappingURL=index.mjs.map
10300
11290
  //# sourceMappingURL=index.mjs.map