cetec-design-system 1.2.1 → 1.3.0-next.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
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { forwardRef, useMemo, createElement, createContext, useContext, useLayoutEffect, useState, useRef, useId as useId$1, useEffect, Children, isValidElement, cloneElement, useReducer, useSyncExternalStore, useCallback } from "react";
2
+ import { forwardRef, useMemo, createElement, createContext, useContext, useLayoutEffect, useState, useRef, useId as useId$1, useEffect, Children, isValidElement, useCallback, cloneElement, useReducer, useSyncExternalStore } from "react";
3
3
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
4
4
  import * as ReactDOM from "react-dom";
5
5
  import { b as breakpoints, c as containerSizes } from "./cetec-preset-D3bQHejk.js";
@@ -6087,6 +6087,44 @@ const arrow = (options, deps) => ({
6087
6087
  ...arrow$1(options),
6088
6088
  options: [options, deps]
6089
6089
  });
6090
+ function useMergeRefs(refs) {
6091
+ const cleanupRef = React.useRef(void 0);
6092
+ const refEffect = React.useCallback((instance) => {
6093
+ const cleanups = refs.map((ref) => {
6094
+ if (ref == null) {
6095
+ return;
6096
+ }
6097
+ if (typeof ref === "function") {
6098
+ const refCallback = ref;
6099
+ const refCleanup = refCallback(instance);
6100
+ return typeof refCleanup === "function" ? refCleanup : () => {
6101
+ refCallback(null);
6102
+ };
6103
+ }
6104
+ ref.current = instance;
6105
+ return () => {
6106
+ ref.current = null;
6107
+ };
6108
+ });
6109
+ return () => {
6110
+ cleanups.forEach((refCleanup) => refCleanup == null ? void 0 : refCleanup());
6111
+ };
6112
+ }, refs);
6113
+ return React.useMemo(() => {
6114
+ if (refs.every((ref) => ref == null)) {
6115
+ return null;
6116
+ }
6117
+ return (value) => {
6118
+ if (cleanupRef.current) {
6119
+ cleanupRef.current();
6120
+ cleanupRef.current = void 0;
6121
+ }
6122
+ if (value != null) {
6123
+ cleanupRef.current = refEffect(value);
6124
+ }
6125
+ };
6126
+ }, refs);
6127
+ }
6090
6128
  function sortByDocumentPosition(a2, b) {
6091
6129
  const position = a2.compareDocumentPosition(b);
6092
6130
  if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
@@ -15233,6 +15271,58 @@ const hasMatchingItems = (children, filterContext) => {
15233
15271
  return true;
15234
15272
  });
15235
15273
  };
15274
+ function useBlockPointerEventsForHoverPolygon() {
15275
+ const [block, setBlock] = useState(false);
15276
+ useLayoutEffect(() => {
15277
+ const mq = window.matchMedia("(any-pointer: coarse)");
15278
+ const apply = () => {
15279
+ setBlock(!mq.matches);
15280
+ };
15281
+ apply();
15282
+ mq.addEventListener("change", apply);
15283
+ return () => mq.removeEventListener("change", apply);
15284
+ }, []);
15285
+ return block;
15286
+ }
15287
+ function findFirstEnabledListIndex(listRef) {
15288
+ const items = listRef.current;
15289
+ if (!(items == null ? void 0 : items.length)) {
15290
+ return null;
15291
+ }
15292
+ for (let i = 0; i < items.length; i++) {
15293
+ const el = items[i];
15294
+ if (!el) {
15295
+ continue;
15296
+ }
15297
+ if (el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true") {
15298
+ continue;
15299
+ }
15300
+ return i;
15301
+ }
15302
+ return null;
15303
+ }
15304
+ function navigateListMainAxisLoop(listRef, direction, previousIndex) {
15305
+ const items = listRef.current;
15306
+ const len = items.length;
15307
+ if (len === 0) {
15308
+ return previousIndex ?? null;
15309
+ }
15310
+ const isDisabled = (index2) => {
15311
+ const el = items[index2];
15312
+ if (!el) {
15313
+ return true;
15314
+ }
15315
+ return el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true";
15316
+ };
15317
+ let current = previousIndex ?? 0;
15318
+ for (let step = 0; step < len; step++) {
15319
+ current = (current + direction + len) % len;
15320
+ if (!isDisabled(current)) {
15321
+ return current;
15322
+ }
15323
+ }
15324
+ return previousIndex ?? null;
15325
+ }
15236
15326
  const defaultGetItemText = ({
15237
15327
  label: label2,
15238
15328
  description
@@ -15274,6 +15364,7 @@ const Menu = (props) => {
15274
15364
  renderNoResults,
15275
15365
  highlightMatches = Boolean(query),
15276
15366
  getItemText = defaultGetItemText,
15367
+ onMenubarEdgeNavigate,
15277
15368
  ...rest
15278
15369
  } = props;
15279
15370
  const [className, otherProps] = splitProps(rest);
@@ -15322,6 +15413,7 @@ const Menu = (props) => {
15322
15413
  const listRef = useRef([]);
15323
15414
  const labelsRef = useRef([]);
15324
15415
  const [activeIndex, setActiveIndex] = useState(null);
15416
+ const blockPointerEventsForHoverPolygon = useBlockPointerEventsForHoverPolygon();
15325
15417
  const hover = useHover(floating.context, {
15326
15418
  enabled: hasReference && (triggerInteraction === "hover" || triggerInteraction === "click-and-hover"),
15327
15419
  delay: {
@@ -15329,7 +15421,7 @@ const Menu = (props) => {
15329
15421
  close: triggerCloseDelay
15330
15422
  },
15331
15423
  handleClose: safePolygon({
15332
- blockPointerEvents: true
15424
+ blockPointerEvents: blockPointerEventsForHoverPolygon
15333
15425
  })
15334
15426
  });
15335
15427
  const click = useClick(floating.context, {
@@ -15395,11 +15487,19 @@ const Menu = (props) => {
15395
15487
  onPopDiginLevel: () => {
15396
15488
  setDiginLevels((prev) => prev.slice(0, -1));
15397
15489
  },
15398
- diginDepth
15490
+ diginDepth,
15491
+ onMenubarEdgeNavigate
15399
15492
  };
15493
+ const navigateMainAxis = useCallback((direction) => {
15494
+ setActiveIndex(
15495
+ (prev) => navigateListMainAxisLoop(listRef, direction, prev)
15496
+ );
15497
+ }, []);
15400
15498
  const menuListContextValue = {
15401
15499
  activeIndex,
15402
- getItemProps: (userProps) => getItemProps(userProps)
15500
+ getItemProps: (userProps) => getItemProps(userProps),
15501
+ navigateMainAxis,
15502
+ nestedMenuDepth: 0
15403
15503
  };
15404
15504
  const levels = [{ key: "root", title: "Menu", children }, ...diginLevels];
15405
15505
  const activeLevel = levels[Math.min(diginDepth, levels.length - 1)];
@@ -15579,17 +15679,65 @@ const Menu = (props) => {
15579
15679
  }
15580
15680
  ) }) });
15581
15681
  const shouldRenderInline = inline || !trigger;
15682
+ const triggerRefProp = isValidElement(trigger) ? trigger.props.ref : void 0;
15683
+ const mergedTriggerRef = useMergeRefs([
15684
+ triggerRefProp,
15685
+ floating.refs.setReference
15686
+ ]);
15582
15687
  if (shouldRenderInline) {
15583
15688
  return /* @__PURE__ */ jsx(FloatingTree, { children: /* @__PURE__ */ jsx(FloatingNode, { id: nodeId, children: content }) });
15584
15689
  }
15690
+ const triggerExtract = isValidElement(trigger) && trigger.props ? (() => {
15691
+ const {
15692
+ ref: _r,
15693
+ children: _ch,
15694
+ onKeyDown: triggerOnKeyDownProp,
15695
+ ...rest2
15696
+ } = trigger.props;
15697
+ return {
15698
+ rest: rest2,
15699
+ onKeyDown: triggerOnKeyDownProp
15700
+ };
15701
+ })() : {
15702
+ rest: {},
15703
+ onKeyDown: void 0
15704
+ };
15705
+ const triggerPropsForReference = triggerExtract.rest;
15706
+ const triggerOnKeyDown = triggerExtract.onKeyDown;
15707
+ const referencePropsFromFloating = getReferenceProps({
15708
+ ...triggerPropsForReference,
15709
+ ref: mergedTriggerRef
15710
+ });
15711
+ const composedTriggerOnKeyDown = (event) => {
15712
+ if (isOpen && (event.key === "ArrowLeft" || event.key === "ArrowRight") && typeof triggerOnKeyDown === "function") {
15713
+ triggerOnKeyDown(event);
15714
+ return;
15715
+ }
15716
+ const refOnKeyDown = referencePropsFromFloating.onKeyDown;
15717
+ if (typeof refOnKeyDown === "function") {
15718
+ refOnKeyDown(event);
15719
+ }
15720
+ if (typeof triggerOnKeyDown === "function") {
15721
+ triggerOnKeyDown(event);
15722
+ }
15723
+ };
15585
15724
  return /* @__PURE__ */ jsx(FloatingTree, { children: /* @__PURE__ */ jsxs(FloatingNode, { id: nodeId, children: [
15586
15725
  cloneElement(
15587
15726
  trigger,
15588
- getReferenceProps({
15589
- ref: floating.refs.setReference
15590
- })
15727
+ {
15728
+ ...referencePropsFromFloating,
15729
+ onKeyDown: composedTriggerOnKeyDown
15730
+ }
15591
15731
  ),
15592
- isOpen && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(FloatingFocusManager, { context: floating.context, modal: false, children: content }) })
15732
+ isOpen && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(
15733
+ FloatingFocusManager,
15734
+ {
15735
+ context: floating.context,
15736
+ modal: false,
15737
+ order: onMenubarEdgeNavigate ? ["reference", "content"] : void 0,
15738
+ children: content
15739
+ }
15740
+ ) })
15593
15741
  ] }) });
15594
15742
  };
15595
15743
  const MenuGroup = (props) => {
@@ -15631,6 +15779,9 @@ const MenuItem = (props) => {
15631
15779
  ...rest
15632
15780
  } = props;
15633
15781
  const [className, otherProps] = splitProps(rest);
15782
+ const restProps = { ...otherProps };
15783
+ const userOnKeyDown = "onKeyDown" in restProps && typeof restProps.onKeyDown === "function" ? restProps.onKeyDown : void 0;
15784
+ delete restProps.onKeyDown;
15634
15785
  const rootContext = useMenuRootContext();
15635
15786
  const tree = useFloatingTree();
15636
15787
  const filterContext = useMenuFilterContext();
@@ -15682,6 +15833,38 @@ const MenuItem = (props) => {
15682
15833
  }) : {
15683
15834
  onClick: handleSelect
15684
15835
  };
15836
+ const { onKeyDown: itemOnKeyDown, ...itemPropsRest } = itemProps;
15837
+ const handleItemKeyDown = (event) => {
15838
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
15839
+ if (href) {
15840
+ itemOnKeyDown == null ? void 0 : itemOnKeyDown(event);
15841
+ return;
15842
+ }
15843
+ const depth = (listContext == null ? void 0 : listContext.nestedMenuDepth) ?? 0;
15844
+ if (event.key === "ArrowLeft" && depth > 0 && (listContext == null ? void 0 : listContext.closeParentSubMenuFlyout)) {
15845
+ event.preventDefault();
15846
+ event.stopPropagation();
15847
+ listContext.closeParentSubMenuFlyout();
15848
+ return;
15849
+ }
15850
+ if (event.key === "ArrowLeft" && depth === 0 && rootContext.onMenubarEdgeNavigate) {
15851
+ event.preventDefault();
15852
+ event.stopPropagation();
15853
+ rootContext.onCloseMenu();
15854
+ rootContext.onMenubarEdgeNavigate(-1);
15855
+ return;
15856
+ }
15857
+ if (event.key === "ArrowRight" && rootContext.onMenubarEdgeNavigate) {
15858
+ event.preventDefault();
15859
+ event.stopPropagation();
15860
+ rootContext.onCloseMenu();
15861
+ rootContext.onMenubarEdgeNavigate(1);
15862
+ return;
15863
+ }
15864
+ }
15865
+ itemOnKeyDown == null ? void 0 : itemOnKeyDown(event);
15866
+ userOnKeyDown == null ? void 0 : userOnKeyDown(event);
15867
+ };
15685
15868
  const role = variant === "checkbox" || variant === "toggle" ? "menuitemcheckbox" : "menuitem";
15686
15869
  const elementProps = href ? {
15687
15870
  as: "a",
@@ -15714,8 +15897,9 @@ const MenuItem = (props) => {
15714
15897
  "data-disabled": disabled,
15715
15898
  "data-active": listContext ? listContext.activeIndex === listItemData.index : false,
15716
15899
  tabIndex: listContext ? listContext.activeIndex === listItemData.index ? 0 : -1 : 0,
15717
- ...itemProps,
15718
- ...otherProps,
15900
+ ...itemPropsRest,
15901
+ onKeyDown: handleItemKeyDown,
15902
+ ...restProps,
15719
15903
  children: [
15720
15904
  variant === "checkbox" && /* @__PURE__ */ jsx(
15721
15905
  Checkbox,
@@ -15822,6 +16006,14 @@ const SubMenu = (props) => {
15822
16006
  const [activeIndex, setActiveIndex] = useState(null);
15823
16007
  const floatingListRef = useRef([]);
15824
16008
  const labelsRef = useRef([]);
16009
+ const subMenuTriggerRef = useRef(null);
16010
+ const blockPointerEventsForHoverPolygon = useBlockPointerEventsForHoverPolygon();
16011
+ const openedFromParentArrowRightRef = useRef(false);
16012
+ const keyboardFocusFirstNestedItemRef = useRef(false);
16013
+ const openNestedFromParentKeyboard = useCallback(() => {
16014
+ openedFromParentArrowRightRef.current = true;
16015
+ setOpen(true);
16016
+ }, []);
15825
16017
  const handleOpenChange = (nextOpen, _event, reason) => {
15826
16018
  if (!nextOpen && reason === "focus-out" && resolvedInteraction === "hover" && parentId != null) {
15827
16019
  return;
@@ -15844,7 +16036,7 @@ const SubMenu = (props) => {
15844
16036
  enabled: !disabled && parentId != null,
15845
16037
  delay: { open: 75 },
15846
16038
  handleClose: safePolygon({
15847
- blockPointerEvents: true
16039
+ blockPointerEvents: blockPointerEventsForHoverPolygon
15848
16040
  })
15849
16041
  });
15850
16042
  const click = useClick(floating.context, {
@@ -15858,7 +16050,15 @@ const SubMenu = (props) => {
15858
16050
  listRef: floatingListRef,
15859
16051
  activeIndex,
15860
16052
  onNavigate: setActiveIndex,
15861
- nested: true
16053
+ nested: true,
16054
+ // Default nested behavior focuses the first child when the flyout opens
16055
+ // (see Floating UI useListNavigation sync when nested is true). That
16056
+ // steals focus from the submenu trigger so ArrowDown navigates inside the
16057
+ // flyout instead of among sibling rows (Quotes → Orders) in the parent
16058
+ // menu. Keep focus on the trigger until the user opens into the panel with
16059
+ // ArrowRight (handled below and by the nested reference path). After
16060
+ // ArrowRight we set `activeIndex` and focus the first item in a layout effect.
16061
+ focusItemOnOpen: false
15862
16062
  });
15863
16063
  const typeahead = useTypeahead(floating.context, {
15864
16064
  listRef: labelsRef,
@@ -15893,6 +16093,47 @@ const SubMenu = (props) => {
15893
16093
  tree.events.emit("menuopen", { parentId, nodeId });
15894
16094
  }
15895
16095
  }, [tree, open, nodeId, parentId]);
16096
+ useEffect(() => {
16097
+ if (!open) {
16098
+ setActiveIndex(null);
16099
+ }
16100
+ }, [open]);
16101
+ useLayoutEffect(() => {
16102
+ if (!open || !openedFromParentArrowRightRef.current) {
16103
+ return;
16104
+ }
16105
+ const applyFirst = () => {
16106
+ const idx = findFirstEnabledListIndex(floatingListRef);
16107
+ if (idx === null) {
16108
+ return false;
16109
+ }
16110
+ openedFromParentArrowRightRef.current = false;
16111
+ keyboardFocusFirstNestedItemRef.current = true;
16112
+ setActiveIndex(idx);
16113
+ return true;
16114
+ };
16115
+ if (!applyFirst()) {
16116
+ requestAnimationFrame(() => {
16117
+ if (!applyFirst()) {
16118
+ openedFromParentArrowRightRef.current = false;
16119
+ }
16120
+ });
16121
+ }
16122
+ }, [open]);
16123
+ useEffect(() => {
16124
+ if (!open) {
16125
+ keyboardFocusFirstNestedItemRef.current = false;
16126
+ return;
16127
+ }
16128
+ if (!keyboardFocusFirstNestedItemRef.current || activeIndex === null) {
16129
+ return;
16130
+ }
16131
+ const el = floatingListRef.current[activeIndex];
16132
+ if (el) {
16133
+ el.focus({ preventScroll: true });
16134
+ }
16135
+ keyboardFocusFirstNestedItemRef.current = false;
16136
+ }, [open, activeIndex]);
15896
16137
  const nestedFilterContext = useMemo(
15897
16138
  () => ({
15898
16139
  query: filterContext.query,
@@ -15902,9 +16143,26 @@ const SubMenu = (props) => {
15902
16143
  }),
15903
16144
  [filterContext]
15904
16145
  );
16146
+ const navigateNestedMainAxis = useCallback((direction) => {
16147
+ setActiveIndex(
16148
+ (prev) => navigateListMainAxisLoop(floatingListRef, direction, prev)
16149
+ );
16150
+ }, []);
16151
+ const closeNestedFlyout = useCallback(() => {
16152
+ setOpen(false);
16153
+ queueMicrotask(() => {
16154
+ var _a;
16155
+ (_a = subMenuTriggerRef.current) == null ? void 0 : _a.focus();
16156
+ });
16157
+ }, []);
16158
+ const parentNestedDepth = (parentListContext == null ? void 0 : parentListContext.nestedMenuDepth) ?? 0;
16159
+ const nestedMenuDepth = parentNestedDepth + 1;
15905
16160
  const nestedListContext = {
15906
16161
  activeIndex,
15907
- getItemProps: (userProps) => getItemProps(userProps)
16162
+ getItemProps: (userProps) => getItemProps(userProps),
16163
+ navigateMainAxis: navigateNestedMainAxis,
16164
+ nestedMenuDepth,
16165
+ closeParentSubMenuFlyout: closeNestedFlyout
15908
16166
  };
15909
16167
  const floatingStyle = {
15910
16168
  ...floating.floatingStyles,
@@ -15914,20 +16172,57 @@ const SubMenu = (props) => {
15914
16172
  onKeyDown: (event) => {
15915
16173
  if (event.key === "ArrowRight" && !disabled) {
15916
16174
  event.preventDefault();
15917
- setOpen(true);
16175
+ openNestedFromParentKeyboard();
15918
16176
  }
15919
16177
  }
15920
16178
  }) : {
15921
16179
  onKeyDown: (event) => {
15922
16180
  if (event.key === "ArrowRight" && !disabled) {
15923
16181
  event.preventDefault();
15924
- setOpen(true);
16182
+ openNestedFromParentKeyboard();
15925
16183
  }
15926
16184
  }
15927
16185
  };
15928
16186
  const referenceProps = getReferenceProps(parentItemProps);
16187
+ const referenceOnKeyDown = referenceProps.onKeyDown;
15929
16188
  const referencePropsWithoutRef = {
15930
- ...referenceProps
16189
+ ...referenceProps,
16190
+ onKeyDown: (event) => {
16191
+ if (resolvedInteraction !== "digin" && parentListContext) {
16192
+ const depth = parentListContext.nestedMenuDepth ?? 0;
16193
+ if (event.key === "ArrowLeft") {
16194
+ if (open) {
16195
+ event.preventDefault();
16196
+ event.stopPropagation();
16197
+ setOpen(false);
16198
+ queueMicrotask(() => {
16199
+ var _a;
16200
+ return (_a = subMenuTriggerRef.current) == null ? void 0 : _a.focus();
16201
+ });
16202
+ return;
16203
+ }
16204
+ if (depth === 0 && rootContext.onMenubarEdgeNavigate) {
16205
+ event.preventDefault();
16206
+ event.stopPropagation();
16207
+ rootContext.onCloseMenu();
16208
+ rootContext.onMenubarEdgeNavigate(-1);
16209
+ return;
16210
+ }
16211
+ }
16212
+ }
16213
+ if (resolvedInteraction !== "digin" && (parentListContext == null ? void 0 : parentListContext.navigateMainAxis) && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
16214
+ event.preventDefault();
16215
+ event.stopPropagation();
16216
+ if (open) {
16217
+ setOpen(false);
16218
+ }
16219
+ parentListContext.navigateMainAxis(event.key === "ArrowDown" ? 1 : -1);
16220
+ return;
16221
+ }
16222
+ if (typeof referenceOnKeyDown === "function") {
16223
+ referenceOnKeyDown(event);
16224
+ }
16225
+ }
15931
16226
  };
15932
16227
  if (!isVisible) {
15933
16228
  return null;
@@ -16026,6 +16321,7 @@ const SubMenu = (props) => {
16026
16321
  disabled,
16027
16322
  className: itemClassName.wrapper,
16028
16323
  ref: (node) => {
16324
+ subMenuTriggerRef.current = node;
16029
16325
  listItemData.ref(node);
16030
16326
  floating.refs.setReference(node);
16031
16327
  },
@@ -16076,6 +16372,12 @@ const SubMenu = (props) => {
16076
16372
  if (event.key === "ArrowLeft") {
16077
16373
  event.preventDefault();
16078
16374
  setOpen(false);
16375
+ queueMicrotask(
16376
+ () => {
16377
+ var _a;
16378
+ return (_a = subMenuTriggerRef.current) == null ? void 0 : _a.focus();
16379
+ }
16380
+ );
16079
16381
  }
16080
16382
  }
16081
16383
  }),