@inf-monkeys-tech/monkeys-design 1.0.109 → 1.0.111

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.
@@ -10850,6 +10850,142 @@ function WorkbenchCollectionSkeleton({
10850
10850
  }
10851
10851
  );
10852
10852
  }
10853
+ function setsEqual(left, right) {
10854
+ if (left.size !== right.size) return false;
10855
+ for (const value of left) {
10856
+ if (!right.has(value)) return false;
10857
+ }
10858
+ return true;
10859
+ }
10860
+ function getComparableKey(key) {
10861
+ return String(key);
10862
+ }
10863
+ function getDefaultBehavior(mode) {
10864
+ return mode === "multiple" ? "toggle" : "replace";
10865
+ }
10866
+ function useWorkbenchCollectionSelection({
10867
+ items,
10868
+ getItemKey,
10869
+ mode = "none",
10870
+ behavior,
10871
+ selectedKeys: controlledSelectedKeys,
10872
+ defaultSelectedKeys,
10873
+ isItemDisabled,
10874
+ onSelectionChange
10875
+ }) {
10876
+ const controlled = controlledSelectedKeys !== void 0;
10877
+ const [internalSelectedKeys, setInternalSelectedKeys] = useState(
10878
+ () => new Set(defaultSelectedKeys ?? [])
10879
+ );
10880
+ const anchorKeyRef = useRef(null);
10881
+ const onSelectionChangeRef = useRef(onSelectionChange);
10882
+ onSelectionChangeRef.current = onSelectionChange;
10883
+ const normalizedItems = useMemo(() => {
10884
+ const seenKeys = /* @__PURE__ */ new Map();
10885
+ return items.map((item, index) => {
10886
+ const key = getItemKey(item, index);
10887
+ const comparableKey = getComparableKey(key);
10888
+ const duplicateIndex = seenKeys.get(comparableKey);
10889
+ if (duplicateIndex !== void 0) {
10890
+ throw new TypeError(
10891
+ `useWorkbenchCollectionSelection received duplicate item key "${comparableKey}" at indices ${duplicateIndex} and ${index}.`
10892
+ );
10893
+ }
10894
+ seenKeys.set(comparableKey, index);
10895
+ return { item, index, key };
10896
+ });
10897
+ }, [getItemKey, items]);
10898
+ const itemByKey = useMemo(() => {
10899
+ const entries = /* @__PURE__ */ new Map();
10900
+ normalizedItems.forEach((entry) => entries.set(entry.key, entry));
10901
+ return entries;
10902
+ }, [normalizedItems]);
10903
+ const selectedKeys = useMemo(
10904
+ () => mode === "none" ? /* @__PURE__ */ new Set() : controlled ? new Set(controlledSelectedKeys ?? []) : internalSelectedKeys,
10905
+ [controlled, controlledSelectedKeys, internalSelectedKeys, mode]
10906
+ );
10907
+ const selectedKeysRef = useRef(selectedKeys);
10908
+ selectedKeysRef.current = selectedKeys;
10909
+ const resetAnchor = useCallback(() => {
10910
+ anchorKeyRef.current = null;
10911
+ }, []);
10912
+ useEffect(() => {
10913
+ if (controlled) return;
10914
+ const availableKeys = new Set(normalizedItems.map(({ key }) => key));
10915
+ setInternalSelectedKeys((previous) => {
10916
+ const next = new Set(Array.from(previous).filter((key) => availableKeys.has(key)));
10917
+ if (setsEqual(previous, next)) return previous;
10918
+ selectedKeysRef.current = next;
10919
+ return next;
10920
+ });
10921
+ }, [controlled, normalizedItems]);
10922
+ useEffect(() => {
10923
+ const anchorKey = anchorKeyRef.current;
10924
+ if (mode !== "multiple" || selectedKeys.size === 0 || anchorKey === null) {
10925
+ resetAnchor();
10926
+ return;
10927
+ }
10928
+ const anchor = itemByKey.get(anchorKey);
10929
+ if (!anchor || isItemDisabled?.(anchor.item, anchor.index)) resetAnchor();
10930
+ }, [isItemDisabled, itemByKey, mode, resetAnchor, selectedKeys.size]);
10931
+ const selectKey = useCallback((key, intent = {}) => {
10932
+ if (mode === "none") return;
10933
+ const entry = itemByKey.get(key);
10934
+ if (!entry || isItemDisabled?.(entry.item, entry.index)) return;
10935
+ const current = new Set(selectedKeysRef.current);
10936
+ const configuredBehavior = behavior ?? getDefaultBehavior(mode);
10937
+ let effectiveBehavior = intent.shiftKey && mode === "multiple" ? "range" : intent.behavior ?? configuredBehavior;
10938
+ if (mode === "single") {
10939
+ effectiveBehavior = effectiveBehavior === "toggle" ? "toggle" : "replace";
10940
+ }
10941
+ const anchor = anchorKeyRef.current === null ? void 0 : itemByKey.get(anchorKeyRef.current);
10942
+ const hasValidAnchor = Boolean(
10943
+ anchor && !isItemDisabled?.(anchor.item, anchor.index)
10944
+ );
10945
+ if (mode === "multiple" && effectiveBehavior === "range" && !hasValidAnchor) {
10946
+ effectiveBehavior = configuredBehavior === "range" ? "toggle" : configuredBehavior;
10947
+ }
10948
+ const next = /* @__PURE__ */ new Set();
10949
+ if (mode === "single") {
10950
+ if (!(effectiveBehavior === "toggle" && current.has(entry.key))) next.add(entry.key);
10951
+ } else if (effectiveBehavior === "range" && anchor) {
10952
+ current.forEach((selectedKey) => next.add(selectedKey));
10953
+ const start = Math.min(anchor.index, entry.index);
10954
+ const end = Math.max(anchor.index, entry.index);
10955
+ normalizedItems.slice(start, end + 1).forEach((candidate) => {
10956
+ if (!isItemDisabled?.(candidate.item, candidate.index)) next.add(candidate.key);
10957
+ });
10958
+ } else if (effectiveBehavior === "replace") {
10959
+ next.add(entry.key);
10960
+ } else {
10961
+ current.forEach((selectedKey) => next.add(selectedKey));
10962
+ if (next.has(entry.key)) next.delete(entry.key);
10963
+ else next.add(entry.key);
10964
+ }
10965
+ anchorKeyRef.current = mode === "multiple" ? entry.key : null;
10966
+ if (!controlled) {
10967
+ selectedKeysRef.current = next;
10968
+ setInternalSelectedKeys(next);
10969
+ }
10970
+ onSelectionChangeRef.current?.(next, {
10971
+ item: entry.item,
10972
+ index: entry.index,
10973
+ key: entry.key,
10974
+ behavior: effectiveBehavior
10975
+ });
10976
+ }, [behavior, controlled, isItemDisabled, itemByKey, mode, normalizedItems]);
10977
+ const isSelected = useCallback(
10978
+ (key) => selectedKeys.has(key),
10979
+ [selectedKeys]
10980
+ );
10981
+ return {
10982
+ mode,
10983
+ selectedKeys,
10984
+ isSelected,
10985
+ selectKey,
10986
+ resetAnchor
10987
+ };
10988
+ }
10853
10989
  var DEFAULT_GAP_PX = 12;
10854
10990
  var DEFAULT_ROW_HEIGHT_PX = 8;
10855
10991
  var DEFAULT_CARD_WIDTH_PX = 280;
@@ -10973,13 +11109,6 @@ function getParentScrollOwner(node) {
10973
11109
  }
10974
11110
  return null;
10975
11111
  }
10976
- function setsEqual(left, right) {
10977
- if (left.size !== right.size) return false;
10978
- for (const value of left) {
10979
- if (!right.has(value)) return false;
10980
- }
10981
- return true;
10982
- }
10983
11112
  function isInteractiveEventTarget(target, currentTarget) {
10984
11113
  if (typeof Element === "undefined" || !(target instanceof Element) || target === currentTarget) return false;
10985
11114
  const control = target.closest(
@@ -10987,19 +11116,6 @@ function isInteractiveEventTarget(target, currentTarget) {
10987
11116
  );
10988
11117
  return Boolean(control && currentTarget.contains(control));
10989
11118
  }
10990
- function warnOnDuplicateKeys(keys) {
10991
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
10992
- const seen = /* @__PURE__ */ new Set();
10993
- const duplicates = /* @__PURE__ */ new Set();
10994
- keys.forEach((key) => {
10995
- const stringKey = String(key);
10996
- if (seen.has(stringKey)) duplicates.add(stringKey);
10997
- seen.add(stringKey);
10998
- });
10999
- if (duplicates.size) {
11000
- console.warn(`WorkbenchCollection received duplicate item keys: ${Array.from(duplicates).join(", ")}`);
11001
- }
11002
- }
11003
11119
  function normalizeTitleMaxLines(value) {
11004
11120
  if (!Number.isFinite(value) || Number(value) <= 0) return void 0;
11005
11121
  return clamp3(Math.round(Number(value)), 1, 12);
@@ -11022,7 +11138,6 @@ function WorkbenchCollection({
11022
11138
  const rootRef = useRef(null);
11023
11139
  const itemsRef = useRef(null);
11024
11140
  const loadMoreRef = useRef(null);
11025
- const lastSelectedIndexRef = useRef(null);
11026
11141
  const loadMoreRequestPendingRef = useRef(false);
11027
11142
  const loadMoreIntersectionActiveRef = useRef(false);
11028
11143
  const loadMoreIntersectionConsumedRef = useRef(false);
@@ -11031,9 +11146,6 @@ function WorkbenchCollection({
11031
11146
  const layoutReadyRef = useRef(false);
11032
11147
  const [containerWidth, setContainerWidth] = useState(0);
11033
11148
  const [itemsNode, setItemsNode] = useState(null);
11034
- const [internalSelectedKeys, setInternalSelectedKeys] = useState(
11035
- () => new Set(config.selection?.defaultSelectedKeys ?? [])
11036
- );
11037
11149
  const callbacksRef = useRef(callbacks);
11038
11150
  callbacksRef.current = callbacks;
11039
11151
  const registerItemsNode = useCallback((node) => {
@@ -11051,10 +11163,6 @@ function WorkbenchCollection({
11051
11163
  const key = getItemKey(item, index);
11052
11164
  return { item, index, key, stringKey: String(key) };
11053
11165
  }), [getItemKey, items]);
11054
- const keys = useMemo(
11055
- () => normalizedItems.map(({ key }) => key),
11056
- [normalizedItems]
11057
- );
11058
11166
  const keysSignature = normalizedItems.map(({ stringKey }) => stringKey).join("");
11059
11167
  const state = config.state;
11060
11168
  const loading = state?.loading === true;
@@ -11062,21 +11170,32 @@ function WorkbenchCollection({
11062
11170
  const hasMore = state?.hasMore === true;
11063
11171
  const loadingVariant = resolveWorkbenchCollectionLoadingVariant(config.loading?.variant);
11064
11172
  const layoutItemCount = loading && normalizedItems.length === 0 && loadingVariant === "skeleton" ? resolveWorkbenchCollectionSkeletonCapacity(config.loading?.skeleton) : normalizedItems.length;
11065
- useEffect(() => warnOnDuplicateKeys(keys), [keys, keysSignature]);
11066
11173
  const selectionMode = config.selection?.mode ?? "none";
11067
- const controlledSelection = config.selection?.selectedKeys !== void 0;
11068
- const selectedKeys = useMemo(
11069
- () => selectionMode === "none" ? /* @__PURE__ */ new Set() : controlledSelection ? new Set(config.selection?.selectedKeys ?? []) : internalSelectedKeys,
11070
- [config.selection?.selectedKeys, controlledSelection, internalSelectedKeys, selectionMode]
11174
+ const isSelectionItemDisabled = useCallback(
11175
+ (entry) => config.selection?.isItemDisabled?.(entry.item, entry.index) ?? false,
11176
+ [config.selection?.isItemDisabled]
11071
11177
  );
11072
- useEffect(() => {
11073
- if (controlledSelection) return;
11074
- const availableKeys = new Set(keys);
11075
- setInternalSelectedKeys((previous) => {
11076
- const next = new Set(Array.from(previous).filter((key) => availableKeys.has(key)));
11077
- return setsEqual(previous, next) ? previous : next;
11178
+ const getSelectionItemKey = useCallback(
11179
+ (entry) => entry.key,
11180
+ []
11181
+ );
11182
+ const handleSelectionChange = useCallback((next, details) => {
11183
+ callbacksRef.current?.onSelectionChange?.(next, {
11184
+ item: details.item.item,
11185
+ key: details.key,
11186
+ behavior: details.behavior
11078
11187
  });
11079
- }, [controlledSelection, keys, keysSignature]);
11188
+ }, []);
11189
+ const { selectedKeys, selectKey } = useWorkbenchCollectionSelection({
11190
+ items: normalizedItems,
11191
+ getItemKey: getSelectionItemKey,
11192
+ mode: selectionMode,
11193
+ behavior: config.selection?.behavior,
11194
+ selectedKeys: config.selection?.selectedKeys,
11195
+ defaultSelectedKeys: config.selection?.defaultSelectedKeys,
11196
+ isItemDisabled: isSelectionItemDisabled,
11197
+ onSelectionChange: handleSelectionChange
11198
+ });
11080
11199
  useEffect(() => {
11081
11200
  const node = itemsNode;
11082
11201
  if (!node) return void 0;
@@ -11314,30 +11433,6 @@ function WorkbenchCollection({
11314
11433
  });
11315
11434
  return Array.from(grouped.values());
11316
11435
  }, [config.grouping, normalizedItems]);
11317
- const setSelection = useCallback((entry, behavior = config.selection?.behavior ?? (selectionMode === "multiple" ? "toggle" : "replace")) => {
11318
- if (selectionMode === "none" || config.selection?.isItemDisabled?.(entry.item, entry.index)) return;
11319
- const current = new Set(selectedKeys);
11320
- const next = /* @__PURE__ */ new Set();
11321
- if (selectionMode === "single") {
11322
- if (!(behavior === "toggle" && current.has(entry.key))) next.add(entry.key);
11323
- } else if (behavior === "range" && lastSelectedIndexRef.current !== null) {
11324
- current.forEach((key) => next.add(key));
11325
- const start = Math.min(lastSelectedIndexRef.current, entry.index);
11326
- const end = Math.max(lastSelectedIndexRef.current, entry.index);
11327
- normalizedItems.slice(start, end + 1).forEach((candidate) => {
11328
- if (!config.selection?.isItemDisabled?.(candidate.item, candidate.index)) next.add(candidate.key);
11329
- });
11330
- } else if (behavior === "replace") {
11331
- next.add(entry.key);
11332
- } else {
11333
- current.forEach((key) => next.add(key));
11334
- if (next.has(entry.key)) next.delete(entry.key);
11335
- else next.add(entry.key);
11336
- }
11337
- lastSelectedIndexRef.current = entry.index;
11338
- if (!controlledSelection) setInternalSelectedKeys(next);
11339
- callbacks?.onSelectionChange?.(next, { item: entry.item, key: entry.key, behavior });
11340
- }, [callbacks, config.selection, controlledSelection, normalizedItems, selectedKeys, selectionMode]);
11341
11436
  const createItemContext = useCallback((entry, layout) => {
11342
11437
  const disabled = config.selection?.isItemDisabled?.(entry.item, entry.index) ?? false;
11343
11438
  const context = {
@@ -11349,7 +11444,11 @@ function WorkbenchCollection({
11349
11444
  selected: selectedKeys.has(entry.key),
11350
11445
  selectionMode,
11351
11446
  layout,
11352
- select: (behavior) => setSelection(entry, behavior),
11447
+ select: (behavior) => selectKey(entry.key, { behavior }),
11448
+ selectFromEvent: (event, behavior) => selectKey(entry.key, {
11449
+ behavior,
11450
+ shiftKey: event.shiftKey
11451
+ }),
11353
11452
  preview: () => callbacks?.onItemPreview?.(entry.item, context),
11354
11453
  detail: () => callbacks?.onItemDetail?.(entry.item, context),
11355
11454
  renderSlot: (name) => {
@@ -11359,12 +11458,12 @@ function WorkbenchCollection({
11359
11458
  notifyMediaError: (error) => callbacks?.onMediaError?.(entry.item, context, error)
11360
11459
  };
11361
11460
  return context;
11362
- }, [callbacks, config.getItemStatus, config.selection, selectedKeys, selectionMode, setSelection, slots?.item]);
11461
+ }, [callbacks, config.getItemStatus, config.selection, selectedKeys, selectKey, selectionMode, slots?.item]);
11363
11462
  const getItemInteractionProps = useCallback((entry, context) => {
11364
11463
  const handleKeyboard = (event) => {
11365
11464
  if (event.target !== event.currentTarget || event.key !== "Enter" && event.key !== " ") return;
11366
11465
  event.preventDefault();
11367
- if (selectionMode !== "none") context.select(event.shiftKey ? "range" : void 0);
11466
+ if (selectionMode !== "none") context.selectFromEvent(event);
11368
11467
  else callbacks?.onItemClick?.(entry.item, context, event);
11369
11468
  };
11370
11469
  return {
@@ -11393,7 +11492,7 @@ function WorkbenchCollection({
11393
11492
  ),
11394
11493
  onClick: (event) => {
11395
11494
  if (isInteractiveEventTarget(event.target, event.currentTarget)) return;
11396
- if (selectionMode !== "none") context.select(event.shiftKey ? "range" : void 0);
11495
+ if (selectionMode !== "none") context.selectFromEvent(event);
11397
11496
  callbacks?.onItemClick?.(entry.item, context, event);
11398
11497
  },
11399
11498
  onDoubleClick: (event) => {
@@ -13936,6 +14035,6 @@ function WorkbenchRadarMatrix({
13936
14035
  );
13937
14036
  }
13938
14037
 
13939
- export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchCollection, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGallerySkeleton, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchPageSkeleton, WorkbenchRadarFilterChip, WorkbenchRadarFilterRow, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView };
14038
+ export { InteractiveTable, InteractiveTableEditableTextCell, InteractiveTableReadonlyCell, InteractiveTableSelectCell, WorkbenchAssetGallery, WorkbenchCollection, WorkbenchContentPane, WorkbenchContentToolbar, WorkbenchDetailSidebar, WorkbenchEvidenceList, WorkbenchGalleryCard, WorkbenchGallerySettingsButton, WorkbenchGallerySettingsPanel, WorkbenchGallerySkeleton, WorkbenchGalleryView, WorkbenchJourneyNavigation, WorkbenchLaneView, WorkbenchMasonryLayout, WorkbenchMetricGrid, WorkbenchPageSkeleton, WorkbenchRadarFilterChip, WorkbenchRadarFilterRow, WorkbenchRadarInspectorSection, WorkbenchRadarMatrix, WorkbenchRadarNavigation, WorkbenchRadarWorkspace, WorkbenchRankedList, WorkbenchRelationshipGraph, WorkbenchResizableSidebar, WorkbenchScatterPlot, WorkbenchSelectionTray, WorkbenchTableView, useWorkbenchCollectionSelection };
13940
14039
  //# sourceMappingURL=index.mjs.map
13941
14040
  //# sourceMappingURL=index.mjs.map