cetec-design-system 3.3.0-0 → 3.5.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9183,7 +9183,7 @@ function useListNavigation(context2, props) {
9183
9183
  const isCrossCloseKey = isCrossOrientationCloseKey(event.key, orientation, rtl, cols);
9184
9184
  const isParentCrossOpenKey = isCrossOrientationOpenKey(event.key, getParentOrientation(), rtl);
9185
9185
  const isMainKey = isMainOrientationKey(event.key, orientation);
9186
- const isNavigationKey = (nested ? isParentCrossOpenKey : isMainKey) || event.key === "Enter" || event.key.trim() === "";
9186
+ const isNavigationKey2 = (nested ? isParentCrossOpenKey : isMainKey) || event.key === "Enter" || event.key.trim() === "";
9187
9187
  if (virtual && open) {
9188
9188
  const rootNode = tree == null ? void 0 : tree.nodesRef.current.find((node) => node.parentId == null);
9189
9189
  const deepestNode = tree && rootNode ? getDeepestNode(tree.nodesRef.current, rootNode.id) : null;
@@ -9216,7 +9216,7 @@ function useListNavigation(context2, props) {
9216
9216
  if (!open && !openOnArrowKeyDown && isArrowKey) {
9217
9217
  return;
9218
9218
  }
9219
- if (isNavigationKey) {
9219
+ if (isNavigationKey2) {
9220
9220
  const isParentMainKey = isMainOrientationKey(event.key, getParentOrientation());
9221
9221
  keyRef.current = nested && isParentMainKey ? null : event.key;
9222
9222
  }
@@ -14948,6 +14948,21 @@ const createOverlayMiddleware = (options = {}) => {
14948
14948
  ...extras
14949
14949
  ];
14950
14950
  };
14951
+ const availableHeightMiddleware = (options = {}) => {
14952
+ const { matchReferenceWidth = false, padding = 8 } = options;
14953
+ return size({
14954
+ padding,
14955
+ apply({ rects, elements, availableHeight }) {
14956
+ if (matchReferenceWidth) {
14957
+ elements.floating.style.minWidth = `${rects.reference.width}px`;
14958
+ }
14959
+ elements.floating.style.setProperty(
14960
+ "--available-height",
14961
+ `${Math.max(availableHeight, 0)}px`
14962
+ );
14963
+ }
14964
+ });
14965
+ };
14951
14966
  const useOverlayFloating = (options) => {
14952
14967
  const {
14953
14968
  open,
@@ -15003,13 +15018,15 @@ const Tooltip = (props) => {
15003
15018
  placement = "bottom",
15004
15019
  offset: offset2 = 8,
15005
15020
  delay,
15021
+ disabled = false,
15006
15022
  ...rest
15007
15023
  } = props;
15008
15024
  const [className, otherProps] = splitProps(rest);
15009
15025
  const [isOpen, setIsOpen] = useState(false);
15026
+ if (disabled && isOpen) setIsOpen(false);
15010
15027
  const arrowRef = useRef(null);
15011
15028
  const { refs, elements, floatingStyles, context: context2 } = useOverlayFloating({
15012
- open: isOpen,
15029
+ open: isOpen && !disabled,
15013
15030
  onOpenChange: setIsOpen,
15014
15031
  placement,
15015
15032
  middleware: createOverlayMiddleware({
@@ -15017,10 +15034,10 @@ const Tooltip = (props) => {
15017
15034
  extras: [arrow({ element: arrowRef })]
15018
15035
  })
15019
15036
  });
15020
- const hover = useHover(context2, { move: false, delay });
15021
- const focus = useFocus(context2);
15022
- const dismiss = useDismiss(context2);
15023
- const role = useRole(context2, { role: "tooltip" });
15037
+ const hover = useHover(context2, { move: false, delay, enabled: !disabled });
15038
+ const focus = useFocus(context2, { enabled: !disabled });
15039
+ const dismiss = useDismiss(context2, { enabled: !disabled });
15040
+ const role = useRole(context2, { role: "tooltip", enabled: !disabled });
15024
15041
  const { getReferenceProps, getFloatingProps } = useInteractions([
15025
15042
  hover,
15026
15043
  focus,
@@ -15042,7 +15059,7 @@ const Tooltip = (props) => {
15042
15059
  children
15043
15060
  }
15044
15061
  ),
15045
- isOpen && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(DsChainPortalRoot, { reference: elements.domReference, children: /* @__PURE__ */ jsxs(
15062
+ isOpen && !disabled && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(DsChainPortalRoot, { reference: elements.domReference, children: /* @__PURE__ */ jsxs(
15046
15063
  Box,
15047
15064
  {
15048
15065
  ...dsComponent("Tooltip"),
@@ -16555,6 +16572,7 @@ const ChipGroupContext = createContext(
16555
16572
  const useChipGroup = () => {
16556
16573
  return useContext(ChipGroupContext);
16557
16574
  };
16575
+ const MAX_VISIBLE_ITEMS = 2;
16558
16576
  const Chip = (props) => {
16559
16577
  const groupContext = useChipGroup();
16560
16578
  const fieldContext = useFieldContext();
@@ -16562,6 +16580,7 @@ const Chip = (props) => {
16562
16580
  const {
16563
16581
  size: sizeProp,
16564
16582
  children,
16583
+ items,
16565
16584
  before,
16566
16585
  after,
16567
16586
  loading,
@@ -16591,19 +16610,20 @@ const Chip = (props) => {
16591
16610
  const isDisabled = disabled || loading;
16592
16611
  const isSelectable = value !== void 0 && groupContext !== null;
16593
16612
  const hasPrimaryAction = Boolean(onClick) || isSelectable;
16613
+ const isEmpty = (items == null ? void 0 : items.length) === 0;
16594
16614
  const isMultiSelected = isSelectable && value !== void 0 && groupContext !== null && groupContext.type === "multi" && Array.isArray(groupContext.value) && groupContext.value.includes(value);
16595
16615
  const isSelected = isSelectable && groupContext !== null ? groupContext.type === "single" ? groupContext.value === value : isMultiSelected : false;
16596
16616
  const hasBefore = Boolean(before) || isMultiSelected;
16597
16617
  const hasAfter = Boolean(after) || dismissable;
16598
16618
  useEffect(() => {
16599
- if (!isSelectable || isDisabled || !registerChip || !unregisterChip || value === void 0) {
16619
+ if (!isSelectable || isDisabled || isEmpty || !registerChip || !unregisterChip || value === void 0) {
16600
16620
  return;
16601
16621
  }
16602
16622
  registerChip(value, buttonRef);
16603
16623
  return () => {
16604
16624
  unregisterChip(value);
16605
16625
  };
16606
- }, [isDisabled, isSelectable, registerChip, unregisterChip, value]);
16626
+ }, [isDisabled, isEmpty, isSelectable, registerChip, unregisterChip, value]);
16607
16627
  const classes = chip({
16608
16628
  size: size2,
16609
16629
  before: hasBefore,
@@ -16674,7 +16694,9 @@ const Chip = (props) => {
16674
16694
  }
16675
16695
  return 0;
16676
16696
  };
16677
- const resolvedDismissLabel = dismissLabel || `Remove ${children}`;
16697
+ const isOverflowing = items !== void 0 && items.length > MAX_VISIBLE_ITEMS;
16698
+ const label2 = items ? isOverflowing ? `${items.slice(0, MAX_VISIBLE_ITEMS).join(", ")} +${items.length - MAX_VISIBLE_ITEMS}` : items.join(", ") : children;
16699
+ const resolvedDismissLabel = dismissLabel || `Remove ${items ? items.join(", ") : children}`;
16678
16700
  const handleDismissClick = (e) => {
16679
16701
  e.stopPropagation();
16680
16702
  onDismiss == null ? void 0 : onDismiss();
@@ -16704,7 +16726,10 @@ const Chip = (props) => {
16704
16726
  const bodyContent = /* @__PURE__ */ jsxs(Fragment, { children: [
16705
16727
  isMultiSelected && /* @__PURE__ */ jsx(Box, { as: "span", className: classes.slot, children: /* @__PURE__ */ jsx(Icon, { name: "check", fill: "icon.inverse", "aria-hidden": true }) }),
16706
16728
  renderSlot(before, "before"),
16707
- /* @__PURE__ */ jsx(Box, { as: "span", className: classes.mainContent, children }),
16729
+ /* @__PURE__ */ jsx(Box, { as: "span", className: classes.mainContent, children: items ? /* @__PURE__ */ jsxs(Fragment, { children: [
16730
+ /* @__PURE__ */ jsx("span", { "aria-hidden": isOverflowing || void 0, children: label2 }),
16731
+ isOverflowing && /* @__PURE__ */ jsx(Box, { as: "span", srOnly: true, children: items.join(", ") })
16732
+ ] }) : label2 }),
16708
16733
  renderSlot(after, "after")
16709
16734
  ] });
16710
16735
  const body = hasPrimaryAction ? /* @__PURE__ */ jsx(
@@ -16734,6 +16759,7 @@ const Chip = (props) => {
16734
16759
  {
16735
16760
  as: "span",
16736
16761
  className: classes.body,
16762
+ tabIndex: isOverflowing && !isDisabled ? 0 : void 0,
16737
16763
  "data-deleted": deleted ? true : void 0,
16738
16764
  "data-disabled": isDisabled || void 0,
16739
16765
  "data-error": error2 || void 0,
@@ -16742,6 +16768,9 @@ const Chip = (props) => {
16742
16768
  children: bodyContent
16743
16769
  }
16744
16770
  );
16771
+ if (isEmpty) {
16772
+ return null;
16773
+ }
16745
16774
  return /* @__PURE__ */ jsxs(
16746
16775
  Box,
16747
16776
  {
@@ -16757,7 +16786,7 @@ const Chip = (props) => {
16757
16786
  "aria-invalid": invalid || void 0,
16758
16787
  ...otherProps,
16759
16788
  children: [
16760
- body,
16789
+ items ? /* @__PURE__ */ jsx(Tooltip, { text: items.join(", "), disabled: !isOverflowing || loading, children: body }) : body,
16761
16790
  dismissable && dismissButton,
16762
16791
  loading && /* @__PURE__ */ jsx(Spinner, { size: "sm", centered: true })
16763
16792
  ]
@@ -18455,9 +18484,14 @@ const Menu = (props) => {
18455
18484
  } = props;
18456
18485
  const [className, otherProps] = splitProps(rest);
18457
18486
  const userStyle = otherProps.style;
18458
- const classes = menu({ density, panel, layer: floatingLayer });
18459
- const listClassName = list({ density });
18460
18487
  const hasReference = Boolean(trigger) && !inline;
18488
+ const classes = menu({
18489
+ density,
18490
+ panel,
18491
+ layer: floatingLayer,
18492
+ scrollable: hasReference && !panel
18493
+ });
18494
+ const listClassName = list({ density });
18461
18495
  const [uncontrolledOpen, setUncontrolledOpen] = useState(
18462
18496
  defaultOpen ?? false
18463
18497
  );
@@ -18493,7 +18527,7 @@ const Menu = (props) => {
18493
18527
  placement,
18494
18528
  strategy,
18495
18529
  middleware: createOverlayMiddleware({
18496
- extras: [size()]
18530
+ extras: [availableHeightMiddleware()]
18497
18531
  })
18498
18532
  });
18499
18533
  const listRef = useRef([]);
@@ -18600,6 +18634,25 @@ const Menu = (props) => {
18600
18634
  const shouldUsePanelDiginProbeFill = Boolean(panel) && subMenuInteraction === "digin";
18601
18635
  const shouldUseDiginSizing = subMenuInteraction === "digin" && hasVisibleResults;
18602
18636
  const sizeProbeRef = useRef(null);
18637
+ const activeLevelRef = useRef(null);
18638
+ const activeBackHeaderRef = useRef(null);
18639
+ useLayoutEffect(() => {
18640
+ const levelEl = activeLevelRef.current;
18641
+ const headerEl = activeBackHeaderRef.current;
18642
+ if (!levelEl) return;
18643
+ if (!headerEl) {
18644
+ levelEl.style.removeProperty("--menu-back-header-height");
18645
+ return;
18646
+ }
18647
+ const update = () => levelEl.style.setProperty(
18648
+ "--menu-back-header-height",
18649
+ `${headerEl.offsetHeight}px`
18650
+ );
18651
+ update();
18652
+ const observer = new ResizeObserver(update);
18653
+ observer.observe(headerEl);
18654
+ return () => observer.disconnect();
18655
+ }, [diginDepth, density, hasVisibleResults]);
18603
18656
  useLayoutEffect(() => {
18604
18657
  if (!isMenuVisible || !shouldUseDiginSizing) {
18605
18658
  setWrapperSize({ width: null, height: null });
@@ -18737,6 +18790,7 @@ const Menu = (props) => {
18737
18790
  children: /* @__PURE__ */ jsx(FloatingList, { elementsRef: listRef, labelsRef, children: /* @__PURE__ */ jsxs(
18738
18791
  Box,
18739
18792
  {
18793
+ ref: activeLevelRef,
18740
18794
  className: classes.level,
18741
18795
  style: {
18742
18796
  flex: `0 0 ${levelWidthPercent}%`
@@ -18747,6 +18801,7 @@ const Menu = (props) => {
18747
18801
  {
18748
18802
  as: "button",
18749
18803
  type: "button",
18804
+ ref: activeBackHeaderRef,
18750
18805
  className: classes.backHeader,
18751
18806
  onClick: rootContextValue.onPopDiginLevel,
18752
18807
  children: [
@@ -19255,7 +19310,8 @@ const SubMenu = (props) => {
19255
19310
  const resolvedDensity = typeof density === "string" ? density : rootContext.density;
19256
19311
  const classes = menu({
19257
19312
  density: resolvedDensity,
19258
- layer: floatingLayer
19313
+ layer: floatingLayer,
19314
+ scrollable: true
19259
19315
  });
19260
19316
  const listClassName = list({ density: resolvedDensity });
19261
19317
  const itemClassName = listItem({
@@ -19303,7 +19359,8 @@ const SubMenu = (props) => {
19303
19359
  middleware: [
19304
19360
  offset({ mainAxis: 0, alignmentAxis: -4 }),
19305
19361
  flip(),
19306
- shift({ padding: 8 })
19362
+ shift({ padding: 8 }),
19363
+ availableHeightMiddleware()
19307
19364
  ]
19308
19365
  });
19309
19366
  const hover = useHover(floating.context, {
@@ -23136,6 +23193,8 @@ const isSelectOptionElement = (child) => {
23136
23193
  const getOptionText = (option) => {
23137
23194
  return option.props.label;
23138
23195
  };
23196
+ const NAVIGATION_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "Home", "End"]);
23197
+ const isNavigationKey = (event) => NAVIGATION_KEYS.has(event.key) || event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
23139
23198
  const getSelectedDisplay = (options, value, multiple, placeholder) => {
23140
23199
  if (value === null || value === void 0 || value === "") {
23141
23200
  return placeholder;
@@ -23180,7 +23239,7 @@ const Select = (props) => {
23180
23239
  name,
23181
23240
  disabled = false,
23182
23241
  error: error2 = false,
23183
- size: size$12 = "md",
23242
+ size: size2 = "md",
23184
23243
  density = defaultDensity,
23185
23244
  autoSize = false,
23186
23245
  "data-ds-component": dsComponentName,
@@ -23195,9 +23254,12 @@ const Select = (props) => {
23195
23254
  const [internalOpen, setInternalOpen] = useState(defaultOpen);
23196
23255
  const [internalValue, setInternalValue] = useState(defaultValue);
23197
23256
  const [activeIndex, setActiveIndex] = useState(null);
23257
+ const [hasNavigated, setHasNavigated] = useState(false);
23258
+ const [openedByKeyboard, setOpenedByKeyboard] = useState(false);
23198
23259
  const isOpenControlled = controlledOpen !== void 0;
23199
23260
  const isOpen = isOpenControlled ? controlledOpen : internalOpen;
23200
23261
  const value = controlledValue !== void 0 ? controlledValue : internalValue;
23262
+ const [prevIsOpen, setPrevIsOpen] = useState(isOpen);
23201
23263
  const options = useMemo(() => {
23202
23264
  return Children.toArray(children).filter(isSelectOptionElement);
23203
23265
  }, [children]);
@@ -23228,10 +23290,15 @@ const Select = (props) => {
23228
23290
  );
23229
23291
  }, [options]);
23230
23292
  const initialActiveIndex = selectedIndex >= 0 ? selectedIndex : firstEnabledIndex >= 0 ? firstEnabledIndex : null;
23231
- const resolvedActiveIndex = isOpen ? activeIndex ?? initialActiveIndex : null;
23293
+ if (isOpen !== prevIsOpen) {
23294
+ setPrevIsOpen(isOpen);
23295
+ setActiveIndex(isOpen ? initialActiveIndex : null);
23296
+ setHasNavigated(isOpen && openedByKeyboard);
23297
+ setOpenedByKeyboard(false);
23298
+ }
23299
+ const resolvedActiveIndex = isOpen ? activeIndex ?? (hasNavigated ? null : initialActiveIndex) : null;
23232
23300
  const activeOptionId = resolvedActiveIndex !== null ? `${triggerId}-option-${resolvedActiveIndex}` : void 0;
23233
23301
  const setOpenState = (nextOpen) => {
23234
- setActiveIndex(nextOpen ? initialActiveIndex : null);
23235
23302
  if (!isOpenControlled) {
23236
23303
  setInternalOpen(nextOpen);
23237
23304
  }
@@ -23259,19 +23326,8 @@ const Select = (props) => {
23259
23326
  extras: [
23260
23327
  // Floating UI only positions the listbox; without a height cap a long
23261
23328
  // option list overflows the viewport on whichever side flip() picks.
23262
- // Only measured values are written here; the `menu` recipe's
23263
- // `scrollable` variant applies the cap and scrolling. `padding`
23264
- // mirrors the overlay middleware's default `shiftPadding`.
23265
- size({
23266
- padding: 8,
23267
- apply({ rects, elements, availableHeight }) {
23268
- elements.floating.style.minWidth = `${rects.reference.width}px`;
23269
- elements.floating.style.setProperty(
23270
- "--available-height",
23271
- `${Math.max(availableHeight, 0)}px`
23272
- );
23273
- }
23274
- })
23329
+ // The `menu` recipe's `scrollable` variant applies the cap.
23330
+ availableHeightMiddleware({ matchReferenceWidth: true })
23275
23331
  ]
23276
23332
  })
23277
23333
  });
@@ -23315,14 +23371,14 @@ const Select = (props) => {
23315
23371
  placeholder
23316
23372
  );
23317
23373
  const selectedOptions = getSelectedOptions(options, value, multiple);
23318
- const classes = select({ size: size$12, multiple, autoSize });
23374
+ const classes = select({ size: size2, multiple, autoSize });
23319
23375
  const menuClasses = menu({
23320
23376
  density,
23321
23377
  layer: floatingLayer,
23322
23378
  scrollable: true
23323
23379
  });
23324
23380
  const hasValue = value !== null && value !== void 0 && value !== "";
23325
- const chipSize = resolveChipSize(size$12);
23381
+ const chipSize = resolveChipSize(size2);
23326
23382
  const accessibleName = typeof displayValue === "string" && displayValue.length > 0 ? displayValue : placeholder;
23327
23383
  const handleTriggerKeyDown = (event) => {
23328
23384
  if (disabled) {
@@ -23330,6 +23386,7 @@ const Select = (props) => {
23330
23386
  }
23331
23387
  if (!isOpen && (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ")) {
23332
23388
  event.preventDefault();
23389
+ setOpenedByKeyboard(true);
23333
23390
  setOpenState(true);
23334
23391
  }
23335
23392
  if (!multiple && hasValue && (event.key === "Backspace" || event.key === "Delete")) {
@@ -23459,10 +23516,26 @@ const Select = (props) => {
23459
23516
  density,
23460
23517
  className: menuClasses.wrapper,
23461
23518
  style: floating.floatingStyles,
23462
- ...getFloatingProps(),
23519
+ ...getFloatingProps({
23520
+ // floating-ui also reports `onNavigate` while opening, so
23521
+ // only real input on the list counts as the user pointing
23522
+ // at a row. Option events bubble here, and the listbox
23523
+ // itself holds focus after the pointer leaves the options.
23524
+ onKeyDown: (event) => {
23525
+ if (isNavigationKey(event)) {
23526
+ setHasNavigated(true);
23527
+ }
23528
+ },
23529
+ onPointerMove: (event) => {
23530
+ if (event.pointerType !== "touch") {
23531
+ setHasNavigated(true);
23532
+ }
23533
+ }
23534
+ }),
23463
23535
  children: options.map((option, index2) => {
23464
23536
  const optionLabel = getOptionText(option);
23465
23537
  const isSelected = multiple ? selectedValueSet.has(option.props.value) : value === option.props.value;
23538
+ const isPointed = !option.props.disabled && hasNavigated && activeIndex === index2;
23466
23539
  return /* @__PURE__ */ jsx(
23467
23540
  ListItem,
23468
23541
  {
@@ -23476,7 +23549,7 @@ const Select = (props) => {
23476
23549
  variant: multiple ? "checkbox" : "default",
23477
23550
  label: optionLabel,
23478
23551
  description: option.props.description,
23479
- iconBefore: !multiple ? option.props.iconLeft ?? "check" : option.props.iconLeft,
23552
+ iconBefore: !multiple ? isSelected && isPointed ? "x" : option.props.iconLeft ?? "check" : option.props.iconLeft,
23480
23553
  iconBeforeFill: !multiple ? isSelected ? "icon" : option.props.iconLeft ? void 0 : "transparent" : void 0,
23481
23554
  iconAfter: option.props.iconRight,
23482
23555
  ...getItemProps({