@sanity/ui 2.6.5 → 2.6.7-canary.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.
Files changed (37) hide show
  1. package/dist/index.d.mts +42 -6
  2. package/dist/index.d.ts +42 -6
  3. package/dist/index.esm.js +80 -147
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +79 -146
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +80 -147
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +26 -34
  10. package/src/core/components/breadcrumbs/breadcrumbs.tsx +15 -6
  11. package/src/core/components/dialog/dialog.tsx +12 -21
  12. package/src/core/components/menu/menu.tsx +11 -18
  13. package/src/core/components/menu/menuButton.tsx +1 -1
  14. package/src/core/components/menu/menuContext.ts +1 -1
  15. package/src/core/components/menu/useMenuController.ts +11 -17
  16. package/src/core/components/toast/styles.ts +2 -1
  17. package/src/core/components/toast/useToast.ts +1 -0
  18. package/src/core/components/tree/tree.tsx +1 -0
  19. package/src/core/components/tree/treeItem.tsx +1 -0
  20. package/src/core/helpers/focus.ts +1 -0
  21. package/src/core/helpers/scroll.ts +1 -0
  22. package/src/core/hooks/index.ts +3 -2
  23. package/src/core/hooks/useClickOutside.ts +38 -72
  24. package/src/core/hooks/useElementSize.ts +1 -0
  25. package/src/core/hooks/useMatchMedia.ts +46 -0
  26. package/src/core/hooks/useMediaIndex/useMediaIndex.ts +2 -10
  27. package/src/core/hooks/usePrefersDark.ts +10 -55
  28. package/src/core/hooks/usePrefersReducedMotion.ts +10 -56
  29. package/src/core/primitives/popover/__workshop__/AlignedStory.tsx +9 -7
  30. package/src/core/primitives/tooltip/__workshop__/customPortal.tsx +8 -6
  31. package/src/core/primitives/tooltip/tooltip.tsx +7 -5
  32. package/src/core/primitives/tooltip/tooltipDelayGroup/tooltipDelayGroupProvider.tsx +1 -0
  33. package/src/core/utils/layer/layerProvider.tsx +1 -0
  34. package/src/core/utils/portal/__workshop__/named.tsx +10 -8
  35. package/src/core/utils/portal/portalProvider.tsx +2 -3
  36. package/src/core/hooks/_internal/index.ts +0 -1
  37. package/src/core/hooks/_internal/useUnique.ts +0 -34
package/dist/index.d.mts CHANGED
@@ -628,7 +628,7 @@ export declare interface CheckboxProps {
628
628
  /**
629
629
  * @public
630
630
  */
631
- export declare type ClickOutsideListener = (event: MouseEvent) => void
631
+ export declare type ClickOutsideListener = (event: MouseEvent | TouchEvent) => void
632
632
 
633
633
  /**
634
634
  * @public
@@ -1432,7 +1432,7 @@ export declare interface MenuProps extends ResponsivePaddingProps {
1432
1432
  * @deprecated Use `shouldFocus="last"` instead.
1433
1433
  */
1434
1434
  focusLast?: boolean
1435
- onClickOutside?: (event: MouseEvent) => void
1435
+ onClickOutside?: (event: MouseEvent | TouchEvent) => void
1436
1436
  onEscape?: () => void
1437
1437
  onItemClick?: () => void
1438
1438
  onItemSelect?: (index: number) => void
@@ -2649,13 +2649,22 @@ export declare function useArrayProp<T extends ArrayPropPrimitive = ArrayPropPri
2649
2649
  export declare function useBoundaryElement(): BoundaryElementContextValue
2650
2650
 
2651
2651
  /**
2652
+ * Use the callback version of `elementsArg` if you're using `useRef` to handle elements:
2653
+ * ```tsx
2654
+ * useClickOutside(
2655
+ * () => {},
2656
+ * () => [ref.current],
2657
+ * )
2658
+ *
2652
2659
  * @public
2653
2660
  */
2654
2661
  export declare function useClickOutside(
2655
2662
  listener: ClickOutsideListener,
2656
- elementsArg?: Array<HTMLElement | HTMLElement[] | null>,
2663
+ elementsArg?:
2664
+ | Array<HTMLElement | HTMLElement[] | null>
2665
+ | (() => Array<HTMLElement | HTMLElement[] | null>),
2657
2666
  boundaryElement?: HTMLElement | null,
2658
- ): (el: HTMLElement | null) => void
2667
+ ): void
2659
2668
 
2660
2669
  /**
2661
2670
  * @beta
@@ -2713,6 +2722,18 @@ export declare function useGlobalKeyDown(onKeyDown: (event: KeyboardEvent) => vo
2713
2722
  */
2714
2723
  export declare function useLayer(): LayerContextValue
2715
2724
 
2725
+ /**
2726
+ * Efficiently subscribes to `window.matchMedia` queries
2727
+ *
2728
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Required if the hook is called during SSR (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2729
+ *
2730
+ * @public
2731
+ */
2732
+ export declare function useMatchMedia(
2733
+ mediaQueryString: `(${string})`,
2734
+ getServerSnapshot?: () => boolean,
2735
+ ): boolean
2736
+
2716
2737
  /**
2717
2738
  * This API might change. DO NOT USE IN PRODUCTION.
2718
2739
  * @beta
@@ -2725,15 +2746,30 @@ export declare function useMediaIndex(): number
2725
2746
  export declare function usePortal(): PortalContextValue
2726
2747
 
2727
2748
  /**
2749
+ * Returns true if a dark color scheme is preferred, false if a light color scheme is preferred or the preference is not known.
2750
+ *
2751
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Since the server environment doesn't have access to the DOM, we can't determine the current value of the media query and we assume `(prefers-color-scheme: light)` since it's the most common scheme (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2752
+ *
2753
+ * If you persist the detected preference in a cookie or a header then you may implement your own server snapshot to read it.
2754
+ * Chrome supports reading the `prefers-color-scheme` media query from a header if the server response: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme
2755
+ * @example https://gist.github.com/stipsan/13c0cccf8dfc34f4b44bb1b984baf7df
2756
+ *
2728
2757
  * @public
2729
2758
  */
2730
- export declare function usePrefersDark(): boolean
2759
+ export declare function usePrefersDark(getServerSnapshot?: () => boolean): boolean
2731
2760
 
2732
2761
  /**
2733
2762
  * Returns true if motion should be reduced
2763
+ *
2764
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Since the server environment doesn't have access to the DOM, we can't determine the current value of the media query and we assume `(prefers-reduced-motion: no-preference)` since it's the most common scheme (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2765
+ *
2766
+ * If you persist the detected preference in a cookie or a header then you may implement your own server snapshot to read it.
2767
+ * Chrome supports reading the `prefers-reduced-motion` media query from a header if the server response: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion
2768
+ * @example https://gist.github.com/stipsan/0c0f839a27842249cada893e9fb7767b
2769
+ *
2734
2770
  * @public
2735
2771
  */
2736
- export declare function usePrefersReducedMotion(): boolean
2772
+ export declare function usePrefersReducedMotion(getServerSnapshot?: () => boolean): boolean
2737
2773
 
2738
2774
  /**
2739
2775
  * @public
package/dist/index.d.ts CHANGED
@@ -628,7 +628,7 @@ export declare interface CheckboxProps {
628
628
  /**
629
629
  * @public
630
630
  */
631
- export declare type ClickOutsideListener = (event: MouseEvent) => void
631
+ export declare type ClickOutsideListener = (event: MouseEvent | TouchEvent) => void
632
632
 
633
633
  /**
634
634
  * @public
@@ -1432,7 +1432,7 @@ export declare interface MenuProps extends ResponsivePaddingProps {
1432
1432
  * @deprecated Use `shouldFocus="last"` instead.
1433
1433
  */
1434
1434
  focusLast?: boolean
1435
- onClickOutside?: (event: MouseEvent) => void
1435
+ onClickOutside?: (event: MouseEvent | TouchEvent) => void
1436
1436
  onEscape?: () => void
1437
1437
  onItemClick?: () => void
1438
1438
  onItemSelect?: (index: number) => void
@@ -2649,13 +2649,22 @@ export declare function useArrayProp<T extends ArrayPropPrimitive = ArrayPropPri
2649
2649
  export declare function useBoundaryElement(): BoundaryElementContextValue
2650
2650
 
2651
2651
  /**
2652
+ * Use the callback version of `elementsArg` if you're using `useRef` to handle elements:
2653
+ * ```tsx
2654
+ * useClickOutside(
2655
+ * () => {},
2656
+ * () => [ref.current],
2657
+ * )
2658
+ *
2652
2659
  * @public
2653
2660
  */
2654
2661
  export declare function useClickOutside(
2655
2662
  listener: ClickOutsideListener,
2656
- elementsArg?: Array<HTMLElement | HTMLElement[] | null>,
2663
+ elementsArg?:
2664
+ | Array<HTMLElement | HTMLElement[] | null>
2665
+ | (() => Array<HTMLElement | HTMLElement[] | null>),
2657
2666
  boundaryElement?: HTMLElement | null,
2658
- ): (el: HTMLElement | null) => void
2667
+ ): void
2659
2668
 
2660
2669
  /**
2661
2670
  * @beta
@@ -2713,6 +2722,18 @@ export declare function useGlobalKeyDown(onKeyDown: (event: KeyboardEvent) => vo
2713
2722
  */
2714
2723
  export declare function useLayer(): LayerContextValue
2715
2724
 
2725
+ /**
2726
+ * Efficiently subscribes to `window.matchMedia` queries
2727
+ *
2728
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Required if the hook is called during SSR (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2729
+ *
2730
+ * @public
2731
+ */
2732
+ export declare function useMatchMedia(
2733
+ mediaQueryString: `(${string})`,
2734
+ getServerSnapshot?: () => boolean,
2735
+ ): boolean
2736
+
2716
2737
  /**
2717
2738
  * This API might change. DO NOT USE IN PRODUCTION.
2718
2739
  * @beta
@@ -2725,15 +2746,30 @@ export declare function useMediaIndex(): number
2725
2746
  export declare function usePortal(): PortalContextValue
2726
2747
 
2727
2748
  /**
2749
+ * Returns true if a dark color scheme is preferred, false if a light color scheme is preferred or the preference is not known.
2750
+ *
2751
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Since the server environment doesn't have access to the DOM, we can't determine the current value of the media query and we assume `(prefers-color-scheme: light)` since it's the most common scheme (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2752
+ *
2753
+ * If you persist the detected preference in a cookie or a header then you may implement your own server snapshot to read it.
2754
+ * Chrome supports reading the `prefers-color-scheme` media query from a header if the server response: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Color-Scheme
2755
+ * @example https://gist.github.com/stipsan/13c0cccf8dfc34f4b44bb1b984baf7df
2756
+ *
2728
2757
  * @public
2729
2758
  */
2730
- export declare function usePrefersDark(): boolean
2759
+ export declare function usePrefersDark(getServerSnapshot?: () => boolean): boolean
2731
2760
 
2732
2761
  /**
2733
2762
  * Returns true if motion should be reduced
2763
+ *
2764
+ * @param getServerSnapshot - Only called during server-side rendering, and hydration if using hydrateRoot. Since the server environment doesn't have access to the DOM, we can't determine the current value of the media query and we assume `(prefers-reduced-motion: no-preference)` since it's the most common scheme (https://react.dev/reference/react/useSyncExternalStore#adding-support-for-server-rendering)
2765
+ *
2766
+ * If you persist the detected preference in a cookie or a header then you may implement your own server snapshot to read it.
2767
+ * Chrome supports reading the `prefers-reduced-motion` media query from a header if the server response: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion
2768
+ * @example https://gist.github.com/stipsan/0c0f839a27842249cada893e9fb7767b
2769
+ *
2734
2770
  * @public
2735
2771
  */
2736
- export declare function usePrefersReducedMotion(): boolean
2772
+ export declare function usePrefersReducedMotion(getServerSnapshot?: () => boolean): boolean
2737
2773
 
2738
2774
  /**
2739
2775
  * @public
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { buildTheme, createColorTheme as createColorTheme$1, hexToRgb as hexToRgb$1, hslToRgb as hslToRgb$1, multiply as multiply$1, parseColor as parseColor$1, rgbToHex as rgbToHex$1, rgbToHsl as rgbToHsl$1, rgba as rgba$1, screen as screen$1, getTheme_v2, getScopedTheme } from "@sanity/ui/theme";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
- import { useMemo, useState, useRef, useEffect, createContext, useContext, useSyncExternalStore, useImperativeHandle, forwardRef, useId, useCallback, Children, isValidElement, cloneElement, Component, memo, useLayoutEffect, useReducer, Fragment as Fragment$1, startTransition } from "react";
3
+ import { useMemo, useEffect, useState, useRef, useImperativeHandle, useDebugValue, useSyncExternalStore, createContext, useContext, forwardRef, useId, useCallback, Children, isValidElement, cloneElement, Component, memo, useLayoutEffect, useReducer, Fragment as Fragment$1, startTransition } from "react";
4
4
  import ReactIs, { isValidElementType } from "react-is";
5
5
  import { ThemeProvider as ThemeProvider$1, useTheme as useTheme$1, css, styled, keyframes } from "styled-components";
6
6
  import { SpinnerIcon, CheckmarkIcon, RemoveIcon, ChevronDownIcon, CloseIcon, ChevronRightIcon, ToggleArrowRightIcon } from "@sanity/icons";
@@ -131,45 +131,26 @@ function useArrayProp(val, defaultVal) {
131
131
  [__perf_hash__]
132
132
  );
133
133
  }
134
- function _getElements(element, elementsArg) {
135
- const ret = [element];
136
- for (const el of elementsArg)
137
- Array.isArray(el) ? ret.push(...el) : ret.push(el);
138
- return ret.filter(Boolean);
139
- }
140
134
  function useClickOutside(listener, elementsArg = EMPTY_ARRAY, boundaryElement) {
141
- const [element, setElement] = useState(null), [elements, setElements] = useState(() => _getElements(element, elementsArg)), elementsRef = useRef(elements);
142
- return useEffect(() => {
143
- const prevElements = elementsRef.current, nextElements = _getElements(element, elementsArg);
144
- if (prevElements.length !== nextElements.length) {
145
- setElements(nextElements), elementsRef.current = nextElements;
135
+ const eventHandler = useEffectEvent((evt) => {
136
+ const target = evt.target;
137
+ if (!(target instanceof Node) || boundaryElement && !boundaryElement.contains(target))
146
138
  return;
147
- }
148
- for (const el of prevElements)
149
- if (!nextElements.includes(el)) {
150
- setElements(nextElements), elementsRef.current = nextElements;
151
- return;
152
- }
153
- for (const el of nextElements)
154
- if (!prevElements.includes(el)) {
155
- setElements(nextElements), elementsRef.current = nextElements;
139
+ const elements = (Array.isArray(elementsArg) ? elementsArg : elementsArg()).flat();
140
+ for (const el of elements)
141
+ if (el && (target === el || el.contains(target)))
156
142
  return;
157
- }
158
- }, [element, elementsArg]), useEffect(() => {
159
- if (!listener) return;
160
- const handleWindowMouseDown = (evt) => {
161
- const target = evt.target;
162
- if (target instanceof Node && !(boundaryElement && !boundaryElement.contains(target))) {
163
- for (const el of elements)
164
- if (target === el || el.contains(target))
165
- return;
166
- listener(evt);
167
- }
168
- };
169
- return window.addEventListener("mousedown", handleWindowMouseDown), () => {
170
- window.removeEventListener("mousedown", handleWindowMouseDown);
171
- };
172
- }, [boundaryElement, listener, elements]), setElement;
143
+ listener(evt);
144
+ });
145
+ useEffect(() => (document.addEventListener("mousedown", eventHandler), document.addEventListener("touchstart", eventHandler), () => {
146
+ document.removeEventListener("mousedown", eventHandler), document.removeEventListener("touchstart", eventHandler);
147
+ }), [eventHandler]);
148
+ }
149
+ function useCustomValidity(ref, customValidity) {
150
+ useEffect(() => {
151
+ var _a;
152
+ (_a = ref.current) == null || _a.setCustomValidity(customValidity || "");
153
+ }, [customValidity, ref]);
173
154
  }
174
155
  var resizeObservers = [], hasActiveObservations = function() {
175
156
  return resizeObservers.some(function(ro) {
@@ -504,9 +485,27 @@ function useElementRect(element) {
504
485
  const elementSize = useElementSize(element);
505
486
  return (elementSize == null ? void 0 : elementSize._contentRect) || null;
506
487
  }
488
+ function useForwardedRef(ref) {
489
+ const innerRef = useRef(null);
490
+ return useImperativeHandle(ref, () => innerRef.current), innerRef;
491
+ }
507
492
  function useGlobalKeyDown(onKeyDown) {
508
493
  return useEffect(() => (addEventListener("keydown", onKeyDown), () => removeEventListener("keydown", onKeyDown)), [onKeyDown]);
509
494
  }
495
+ function useMatchMedia(mediaQueryString, getServerSnapshot2) {
496
+ const { subscribe: subscribe2, getSnapshot } = useMemo(() => {
497
+ let MEDIA_QUERY_CACHE;
498
+ const getMatchMedia = () => (MEDIA_QUERY_CACHE || (MEDIA_QUERY_CACHE = window.matchMedia(mediaQueryString)), MEDIA_QUERY_CACHE);
499
+ return {
500
+ subscribe: (onStoreChange) => {
501
+ const matchMedia = getMatchMedia();
502
+ return matchMedia.addEventListener("change", onStoreChange), () => matchMedia.removeEventListener("change", onStoreChange);
503
+ },
504
+ getSnapshot: () => getMatchMedia().matches
505
+ };
506
+ }, [mediaQueryString]);
507
+ return useDebugValue(mediaQueryString), useSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot2);
508
+ }
510
509
  function getGlobalScope() {
511
510
  if (typeof globalThis < "u") return globalThis;
512
511
  if (typeof window < "u") return window;
@@ -549,7 +548,6 @@ function useTheme() {
549
548
  function useTheme_v2() {
550
549
  return getTheme_v2(useTheme$1());
551
550
  }
552
- const MEDIA_STORE_CACHE = /* @__PURE__ */ new WeakMap();
553
551
  function _getMediaQuery(media, index) {
554
552
  return index === 0 ? `screen and (max-width: ${media[index] - 1}px)` : index === media.length ? `screen and (min-width: ${media[index - 1]}px)` : `screen and (min-width: ${media[index - 1]}px) and (max-width: ${media[index] - 1}px)`;
555
553
  }
@@ -584,57 +582,18 @@ function _createMediaStore(media) {
584
582
  };
585
583
  } };
586
584
  }
587
- function getServerSnapshot$2() {
585
+ function getServerSnapshot() {
588
586
  return 0;
589
587
  }
590
588
  function useMediaIndex() {
591
- const { media } = useTheme_v2();
592
- let store = MEDIA_STORE_CACHE.get(media);
593
- return store || (store = _createMediaStore(media), MEDIA_STORE_CACHE.set(media, store)), useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot$2);
589
+ const { media } = useTheme_v2(), store = useMemo(() => _createMediaStore(media), [media]);
590
+ return useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);
594
591
  }
595
- let MEDIA_QUERY_CACHE$1;
596
- function getMatchMedia$1() {
597
- return MEDIA_QUERY_CACHE$1 || (MEDIA_QUERY_CACHE$1 = window.matchMedia("(prefers-color-scheme: dark)")), MEDIA_QUERY_CACHE$1;
592
+ function usePrefersDark(getServerSnapshot2 = () => !1) {
593
+ return useMatchMedia("(prefers-color-scheme: dark)", getServerSnapshot2);
598
594
  }
599
- function subscribe$2(onStoreChange) {
600
- const matchMedia = getMatchMedia$1();
601
- return matchMedia.addEventListener("change", onStoreChange), () => matchMedia.removeEventListener("change", onStoreChange);
602
- }
603
- function getSnapshot$1() {
604
- return getMatchMedia$1().matches;
605
- }
606
- function getServerSnapshot$1() {
607
- return !1;
608
- }
609
- function usePrefersDark() {
610
- return useSyncExternalStore(subscribe$2, getSnapshot$1, getServerSnapshot$1);
611
- }
612
- let MEDIA_QUERY_CACHE;
613
- function getMatchMedia() {
614
- return MEDIA_QUERY_CACHE || (MEDIA_QUERY_CACHE = window.matchMedia("(prefers-reduced-motion: reduce)")), MEDIA_QUERY_CACHE;
615
- }
616
- function subscribe$1(onStoreChange) {
617
- const matchMedia = getMatchMedia();
618
- return matchMedia.addEventListener("change", onStoreChange), () => matchMedia.removeEventListener("change", onStoreChange);
619
- }
620
- function getSnapshot() {
621
- return getMatchMedia().matches;
622
- }
623
- function getServerSnapshot() {
624
- return !1;
625
- }
626
- function usePrefersReducedMotion() {
627
- return useSyncExternalStore(subscribe$1, getSnapshot, getServerSnapshot);
628
- }
629
- function useForwardedRef(ref) {
630
- const innerRef = useRef(null);
631
- return useImperativeHandle(ref, () => innerRef.current), innerRef;
632
- }
633
- function useCustomValidity(ref, customValidity) {
634
- useEffect(() => {
635
- var _a;
636
- (_a = ref.current) == null || _a.setCustomValidity(customValidity || "");
637
- }, [customValidity, ref]);
595
+ function usePrefersReducedMotion(getServerSnapshot2 = () => !1) {
596
+ return useMatchMedia("(prefers-reduced-motion: reduce)", getServerSnapshot2);
638
597
  }
639
598
  function responsiveBorderStyle() {
640
599
  return [border, borderTop, borderRight, borderBottom, borderLeft];
@@ -3060,16 +3019,6 @@ function Portal(props) {
3060
3019
  const { children, __unstable_name: name } = props, portal = usePortal(), portalElement = (name ? portal.elements && portal.elements[name] : portal.element) || ((_a = portal.elements) == null ? void 0 : _a.default);
3061
3020
  return portalElement ? createPortal(children, portalElement) : null;
3062
3021
  }
3063
- function useUnique(value) {
3064
- const valueRef = useRef(value);
3065
- return _isEqual(valueRef.current, value) || (valueRef.current = value), valueRef.current;
3066
- }
3067
- function _isEqual(objA, objB) {
3068
- if (!objA || !objB)
3069
- return objA === objB;
3070
- const keysA = Object.keys(objA), keysB = Object.keys(objB);
3071
- return keysA.length !== keysB.length ? !1 : keysA.every((key2) => objA[key2] === objB[key2]);
3072
- }
3073
3022
  function useMounted() {
3074
3023
  return useSyncExternalStore(
3075
3024
  subscribe,
@@ -3080,7 +3029,7 @@ function useMounted() {
3080
3029
  const subscribe = () => () => {
3081
3030
  };
3082
3031
  function PortalProvider(props) {
3083
- const { boundaryElement, children, element, __unstable_elements: elementsProp } = props, elements = useUnique(elementsProp), mounted = useMounted(), value = useMemo(() => ({
3032
+ const { boundaryElement, children, element, __unstable_elements: elements } = props, mounted = useMounted(), value = useMemo(() => ({
3084
3033
  version: 0,
3085
3034
  boundaryElement: boundaryElement || null,
3086
3035
  element: element || mounted ? document.body : null,
@@ -4435,7 +4384,7 @@ const Root$a = styled(Layer)`
4435
4384
  },
4436
4385
  [childProp == null ? void 0 : childProp.props, handleIsOpenChange]
4437
4386
  );
4438
- useEffect(() => {
4387
+ useCloseOnMouseLeave({ handleIsOpenChange, referenceElement, showTooltip }), useEffect(() => {
4439
4388
  disabled && showTooltip && handleIsOpenChange(!1);
4440
4389
  }, [disabled, handleIsOpenChange, showTooltip]), useEffect(() => {
4441
4390
  !content && showTooltip && handleIsOpenChange(!1);
@@ -4447,7 +4396,7 @@ const Root$a = styled(Layer)`
4447
4396
  return window.addEventListener("keydown", handleWindowKeyDown), () => {
4448
4397
  window.removeEventListener("keydown", handleWindowKeyDown);
4449
4398
  };
4450
- }, [handleIsOpenChange, showTooltip]), useCloseOnMouseLeave({ handleIsOpenChange, referenceElement, showTooltip }), useLayoutEffect(() => {
4399
+ }, [handleIsOpenChange, showTooltip]), useLayoutEffect(() => {
4451
4400
  const availableWidths = [
4452
4401
  ...boundaryElement ? [boundaryElement.offsetWidth] : [],
4453
4402
  (portalElement == null ? void 0 : portalElement.offsetWidth) || document.body.offsetWidth
@@ -4545,13 +4494,13 @@ function useCloseOnMouseLeave({
4545
4494
  referenceElement,
4546
4495
  showTooltip
4547
4496
  }) {
4548
- const onMouseMove = useEffectEvent((target) => {
4549
- referenceElement && (referenceElement === target || target instanceof Node && referenceElement.contains(target) || handleIsOpenChange(!1));
4497
+ const onMouseMove = useEffectEvent((target, teardown) => {
4498
+ referenceElement && (referenceElement === target || target instanceof Node && referenceElement.contains(target) || (handleIsOpenChange(!1), teardown()));
4550
4499
  });
4551
4500
  useEffect(() => {
4552
4501
  if (!showTooltip) return;
4553
4502
  const handleMouseMove = (event) => {
4554
- onMouseMove(event.target);
4503
+ onMouseMove(event.target, () => window.removeEventListener("mousemove", handleMouseMove));
4555
4504
  };
4556
4505
  return window.addEventListener("mousemove", handleMouseMove), () => window.removeEventListener("mousemove", handleMouseMove);
4557
4506
  }, [onMouseMove, showTooltip]);
@@ -4967,8 +4916,8 @@ const AUTOCOMPLETE_LISTBOX_IGNORE_KEYS = [
4967
4916
  appearance: none;
4968
4917
  margin: -4px;
4969
4918
  `, Breadcrumbs = forwardRef(function(props, ref) {
4970
- const { children, maxLength, separator, space: spaceRaw = 2, ...restProps } = props, space = useArrayProp(spaceRaw), [open, setOpen] = useState(!1), [expandElement, setExpandElement] = useState(null), [popoverElement, setPopoverElement] = useState(null), collapse = useCallback(() => setOpen(!1), []), expand = useCallback(() => setOpen(!0), []);
4971
- useClickOutside(collapse, [expandElement, popoverElement]);
4919
+ const { children, maxLength, separator, space: spaceRaw = 2, ...restProps } = props, space = useArrayProp(spaceRaw), [open, setOpen] = useState(!1), expandElementRef = useRef(null), popoverElementRef = useRef(null), collapse = useCallback(() => setOpen(!1), []), expand = useCallback(() => setOpen(!0), []);
4920
+ useClickOutside(collapse, () => [expandElementRef.current, popoverElementRef.current]);
4972
4921
  const rawItems = useMemo(() => Children.toArray(children).filter(isValidElement), [children]), items = useMemo(() => {
4973
4922
  const len = rawItems.length;
4974
4923
  if (maxLength && len > maxLength) {
@@ -4983,7 +4932,7 @@ const AUTOCOMPLETE_LISTBOX_IGNORE_KEYS = [
4983
4932
  open,
4984
4933
  placement: "top",
4985
4934
  portal: !0,
4986
- ref: setPopoverElement,
4935
+ ref: popoverElementRef,
4987
4936
  children: /* @__PURE__ */ jsx(
4988
4937
  ExpandButton,
4989
4938
  {
@@ -4991,7 +4940,7 @@ const AUTOCOMPLETE_LISTBOX_IGNORE_KEYS = [
4991
4940
  mode: "bleed",
4992
4941
  onClick: open ? collapse : expand,
4993
4942
  padding: 1,
4994
- ref: setExpandElement,
4943
+ ref: expandElementRef,
4995
4944
  selected: open,
4996
4945
  text: "\u2026"
4997
4946
  }
@@ -5116,8 +5065,8 @@ const Root$7 = styled(Layer)(responsivePaddingStyle, dialogStyle, responsiveDial
5116
5065
  scheme,
5117
5066
  shadow: shadowProp,
5118
5067
  width: widthProp
5119
- } = props, portal = usePortal(), portalElement = portalProp ? ((_a = portal.elements) == null ? void 0 : _a[portalProp]) || null : portal.element, boundaryElement = useBoundaryElement().element, radius = useArrayProp(radiusProp), shadow = useArrayProp(shadowProp), width = useArrayProp(widthProp), ref = useRef(null), [rootElement, setRootElement] = useState(null), contentRef = useRef(null), layer = useLayer(), { isTopLayer } = layer, labelId = `${id}_label`, showCloseButton = !!onClose && hideCloseButton === !1, showHeader = !!header || showCloseButton;
5120
- useImperativeHandle(forwardedRef, () => ref.current), useImperativeHandle(
5068
+ } = props, portal = usePortal(), portalElement = portalProp ? ((_a = portal.elements) == null ? void 0 : _a[portalProp]) || null : portal.element, boundaryElement = useBoundaryElement().element, radius = useArrayProp(radiusProp), shadow = useArrayProp(shadowProp), width = useArrayProp(widthProp), ref = useRef(null), contentRef = useRef(null), layer = useLayer(), { isTopLayer } = layer, labelId = `${id}_label`, showCloseButton = !!onClose && hideCloseButton === !1, showHeader = !!header || showCloseButton;
5069
+ return useImperativeHandle(forwardedRef, () => ref.current), useImperativeHandle(
5121
5070
  forwardedContentRef,
5122
5071
  () => contentRef.current
5123
5072
  ), useEffect(() => {
@@ -5132,20 +5081,13 @@ const Root$7 = styled(Layer)(responsivePaddingStyle, dialogStyle, responsiveDial
5132
5081
  [boundaryElement, isTopLayer, onClose, portalElement]
5133
5082
  )
5134
5083
  ), useClickOutside(
5135
- useCallback(
5136
- (event) => {
5137
- if (!isTopLayer || !onClickOutside) return;
5138
- const target = event.target;
5139
- target && !isTargetWithinScope(boundaryElement, portalElement, target) || onClickOutside();
5140
- },
5141
- [boundaryElement, isTopLayer, onClickOutside, portalElement]
5142
- ),
5143
- [rootElement]
5144
- );
5145
- const setRef = useCallback((el) => {
5146
- setRootElement(el), ref.current = el;
5147
- }, []);
5148
- return /* @__PURE__ */ jsx(DialogContainer, { "data-ui": "DialogCard", width, children: /* @__PURE__ */ jsx(DialogCardRoot, { radius, ref: setRef, scheme, shadow, children: /* @__PURE__ */ jsxs(DialogLayout, { direction: "column", children: [
5084
+ (event) => {
5085
+ if (!isTopLayer || !onClickOutside) return;
5086
+ const target = event.target;
5087
+ target && !isTargetWithinScope(boundaryElement, portalElement, target) || onClickOutside();
5088
+ },
5089
+ () => [ref.current]
5090
+ ), /* @__PURE__ */ jsx(DialogContainer, { "data-ui": "DialogCard", width, children: /* @__PURE__ */ jsx(DialogCardRoot, { radius, ref, scheme, shadow, children: /* @__PURE__ */ jsxs(DialogLayout, { direction: "column", children: [
5149
5091
  showHeader && /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsxs(Flex, { align: "center", padding: 3, children: [
5150
5092
  /* @__PURE__ */ jsx(Box, { flex: 1, padding: 2, children: header && /* @__PURE__ */ jsx(Text, { id: labelId, size: 1, weight: "semibold", children: header }) }),
5151
5093
  showCloseButton && /* @__PURE__ */ jsx(Box, { flex: "none", children: /* @__PURE__ */ jsx(
@@ -5323,13 +5265,13 @@ function _sortElements(rootElement, elements) {
5323
5265
  elements.sort(_sort);
5324
5266
  }
5325
5267
  function useMenuController(props) {
5326
- const { onKeyDown, originElement, shouldFocus } = props, elementsRef = useRef([]), [rootElement, setRootElement] = useState(null), [activeIndex, _setActiveIndex] = useState(-1), activeIndexRef = useRef(activeIndex), activeElement = elementsRef.current[activeIndex] || null, mounted = !!rootElement, setActiveIndex = useCallback((nextActiveIndex) => {
5268
+ const { onKeyDown, originElement, shouldFocus, rootElementRef } = props, elementsRef = useRef([]), [activeIndex, _setActiveIndex] = useState(-1), activeIndexRef = useRef(activeIndex), activeElement = useMemo(() => elementsRef.current[activeIndex] || null, [activeIndex]), mounted = !!rootElementRef.current, setActiveIndex = useCallback((nextActiveIndex) => {
5327
5269
  _setActiveIndex(nextActiveIndex), activeIndexRef.current = nextActiveIndex;
5328
5270
  }, []), mount = useCallback(
5329
5271
  (element, selected) => {
5330
5272
  if (!element) return () => {
5331
5273
  };
5332
- if (elementsRef.current.indexOf(element) === -1 && (elementsRef.current.push(element), _sortElements(rootElement, elementsRef.current)), selected) {
5274
+ if (elementsRef.current.indexOf(element) === -1 && (elementsRef.current.push(element), _sortElements(rootElementRef.current, elementsRef.current)), selected) {
5333
5275
  const selectedIndex = elementsRef.current.indexOf(element);
5334
5276
  setActiveIndex(selectedIndex);
5335
5277
  }
@@ -5338,7 +5280,7 @@ function useMenuController(props) {
5338
5280
  idx > -1 && elementsRef.current.splice(idx, 1);
5339
5281
  };
5340
5282
  },
5341
- [rootElement, setActiveIndex]
5283
+ [rootElementRef, setActiveIndex]
5342
5284
  ), handleKeyDown = useCallback(
5343
5285
  (event) => {
5344
5286
  if (event.key === "Tab") {
@@ -5393,13 +5335,13 @@ function useMenuController(props) {
5393
5335
  },
5394
5336
  [setActiveIndex]
5395
5337
  ), handleItemMouseLeave = useCallback(() => {
5396
- setActiveIndex(-2), rootElement == null || rootElement.focus();
5397
- }, [setActiveIndex, rootElement]);
5338
+ var _a;
5339
+ setActiveIndex(-2), (_a = rootElementRef.current) == null || _a.focus();
5340
+ }, [rootElementRef, setActiveIndex]);
5398
5341
  return useEffect(() => {
5399
5342
  if (!mounted) return;
5400
5343
  const rafId = window.requestAnimationFrame(() => {
5401
- const _activeIndex = activeIndexRef.current;
5402
- if (_activeIndex === -1) {
5344
+ if (activeIndex === -1) {
5403
5345
  if (shouldFocus === "first") {
5404
5346
  const el = _getFocusableElements(elementsRef.current)[0];
5405
5347
  if (el) {
@@ -5416,7 +5358,7 @@ function useMenuController(props) {
5416
5358
  }
5417
5359
  return;
5418
5360
  }
5419
- const element = elementsRef.current[_activeIndex] || null;
5361
+ const element = elementsRef.current[activeIndex] || null;
5420
5362
  element == null || element.focus();
5421
5363
  });
5422
5364
  return () => {
@@ -5428,9 +5370,7 @@ function useMenuController(props) {
5428
5370
  handleItemMouseEnter,
5429
5371
  handleItemMouseLeave,
5430
5372
  handleKeyDown,
5431
- mount,
5432
- rootElement,
5433
- setRootElement
5373
+ mount
5434
5374
  };
5435
5375
  }
5436
5376
  const Root$5 = styled(Box)`
@@ -5462,23 +5402,18 @@ const Root$5 = styled(Box)`
5462
5402
  handleItemMouseEnter,
5463
5403
  handleItemMouseLeave,
5464
5404
  handleKeyDown,
5465
- mount,
5466
- rootElement,
5467
- setRootElement
5468
- } = useMenuController({ onKeyDown, originElement, shouldFocus }), handleRefChange = useCallback(
5405
+ mount
5406
+ } = useMenuController({ onKeyDown, originElement, shouldFocus, rootElementRef: ref }), handleRefChange = useCallback(
5469
5407
  (el) => {
5470
- setRootElement(el), ref.current = el;
5408
+ ref.current = el, ref.current && registerElement && registerElement(ref.current);
5471
5409
  },
5472
- [setRootElement]
5410
+ [registerElement]
5473
5411
  );
5474
5412
  useEffect(() => {
5475
5413
  onItemSelect && onItemSelect(activeIndex);
5476
5414
  }, [activeIndex, onItemSelect]), useClickOutside(
5477
- useCallback(
5478
- (event) => isTopLayer && onClickOutside && onClickOutside(event),
5479
- [isTopLayer, onClickOutside]
5480
- ),
5481
- [rootElement]
5415
+ (event) => isTopLayer && onClickOutside && onClickOutside(event),
5416
+ () => [ref.current]
5482
5417
  ), useGlobalKeyDown(
5483
5418
  useCallback(
5484
5419
  (event) => {
@@ -5486,10 +5421,7 @@ const Root$5 = styled(Box)`
5486
5421
  },
5487
5422
  [isTopLayer, onEscape]
5488
5423
  )
5489
- ), useEffect(() => {
5490
- if (!(!rootElement || !registerElement))
5491
- return registerElement(rootElement);
5492
- }, [registerElement, rootElement]);
5424
+ );
5493
5425
  const value = useMemo(
5494
5426
  () => ({
5495
5427
  version: 0,
@@ -6165,7 +6097,7 @@ const CustomInline = styled(Inline)`
6165
6097
  }
6166
6098
  100% {
6167
6099
  width: 100%;
6168
- }
6100
+ }
6169
6101
  `, LOADING_BAR_HEIGHT = 2;
6170
6102
  function rootStyles(props) {
6171
6103
  const { color } = getTheme_v2$1(props.theme), loadingBarColor = color.button.default[props.tone].enabled.bg;
@@ -6863,6 +6795,7 @@ export {
6863
6795
  useForwardedRef,
6864
6796
  useGlobalKeyDown,
6865
6797
  useLayer,
6798
+ useMatchMedia,
6866
6799
  useMediaIndex,
6867
6800
  usePortal,
6868
6801
  usePrefersDark,