@sanity/ui 2.8.0 → 2.8.2

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.d.mts CHANGED
@@ -630,6 +630,16 @@ export declare interface CheckboxProps {
630
630
  */
631
631
  export declare type ClickOutsideElements = (HTMLElement | null | (HTMLElement | null)[])[]
632
632
 
633
+ /**
634
+ * @public
635
+ */
636
+ export declare type ClickOutsideEventElements = (HTMLElement | null | (HTMLElement | null)[])[]
637
+
638
+ /**
639
+ * @public
640
+ */
641
+ export declare type ClickOutsideEventListener = (event: MouseEvent) => void
642
+
633
643
  /**
634
644
  * @public
635
645
  */
@@ -2655,71 +2665,33 @@ export declare function useBoundaryElement(): BoundaryElementContextValue
2655
2665
 
2656
2666
  /**
2657
2667
  * @public
2658
- */
2659
- export declare function useClickOutside(
2660
- listener: ClickOutsideListener | false | undefined,
2661
- elementsArg: () => ClickOutsideElements,
2662
- boundaryElement?: () => HTMLElement | null,
2663
- ): void
2664
-
2665
- /**
2666
- * @public
2667
- * @deprecated - change `useClickOutside(handler, () => [...], boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
2668
- */
2669
- export declare function useClickOutside(
2670
- listener: ClickOutsideListener | false | undefined,
2671
- elementsArg: () => ClickOutsideElements,
2672
- boundaryElement: HTMLElement | null,
2673
- ): void
2674
-
2675
- /**
2676
- * @public
2677
- * @deprecated - change `useClickOutside(handler, [...], () => boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
2678
- */
2679
- export declare function useClickOutside(
2680
- listener: ClickOutsideListener | false | undefined,
2681
- elementsArg: ClickOutsideElements,
2682
- boundaryElement: () => HTMLElement | null,
2683
- ): UseClickOutsideSetElement
2684
-
2685
- /**
2686
- * @public
2687
- * @deprecated
2688
- * Instead of:
2668
+ * @deprecated replaced by the new `useClickOutsideEvent` hook, instead of:
2689
2669
  * ```tsx
2690
- * const buttonRef = useRef(null)
2691
- * const setElement = useClickOutside(() => {}, [buttonRef.current])
2692
- * return (
2693
- * <>
2694
- * <button ref={buttonRef} />
2695
- * {open && <div ref={setElement} />}
2696
- * </>
2697
- * )
2670
+ * const [button, setButtonElement] = useState(null)
2671
+ * useClickOutside((event) => {}, [button])
2672
+ * return <button ref={setButtonElement} />
2698
2673
  * ```
2699
- * Use:
2674
+ * do:
2700
2675
  * ```tsx
2701
2676
  * const buttonRef = useRef()
2702
- * const [element, setElement] = useState(null)
2703
- * useClickOutside(() => {}, () => [buttonRef.current, element])
2704
- * return (
2705
- * <>
2706
- * <button ref={buttonRef} />
2707
- * {open && <div ref={setElement} />}
2708
- * </>
2709
- * )
2677
+ * useClickOutsideEvent((event) => {}, () => [buttonRef.current])
2678
+ * return <button ref={buttonRef} />
2710
2679
  * ```
2711
2680
  */
2712
2681
  export declare function useClickOutside(
2713
- listener: ClickOutsideListener | false | undefined,
2714
- elementsArg: ClickOutsideElements,
2682
+ listener: ClickOutsideListener,
2683
+ elementsArg?: ClickOutsideElements,
2715
2684
  boundaryElement?: HTMLElement | null,
2716
- ): UseClickOutsideSetElement
2685
+ ): (el: HTMLElement | null) => void
2717
2686
 
2718
2687
  /**
2719
2688
  * @public
2720
- * @deprecated - use your own `const [element, setElement] = useState(null)` logic instead
2721
2689
  */
2722
- export declare type UseClickOutsideSetElement = (el: HTMLElement | null) => void
2690
+ export declare function useClickOutsideEvent(
2691
+ listener: ClickOutsideEventListener | false | undefined,
2692
+ elementsArg?: () => ClickOutsideEventElements,
2693
+ boundaryElement?: () => HTMLElement | null,
2694
+ ): void
2723
2695
 
2724
2696
  /**
2725
2697
  * @beta
package/dist/index.d.ts CHANGED
@@ -630,6 +630,16 @@ export declare interface CheckboxProps {
630
630
  */
631
631
  export declare type ClickOutsideElements = (HTMLElement | null | (HTMLElement | null)[])[]
632
632
 
633
+ /**
634
+ * @public
635
+ */
636
+ export declare type ClickOutsideEventElements = (HTMLElement | null | (HTMLElement | null)[])[]
637
+
638
+ /**
639
+ * @public
640
+ */
641
+ export declare type ClickOutsideEventListener = (event: MouseEvent) => void
642
+
633
643
  /**
634
644
  * @public
635
645
  */
@@ -2655,71 +2665,33 @@ export declare function useBoundaryElement(): BoundaryElementContextValue
2655
2665
 
2656
2666
  /**
2657
2667
  * @public
2658
- */
2659
- export declare function useClickOutside(
2660
- listener: ClickOutsideListener | false | undefined,
2661
- elementsArg: () => ClickOutsideElements,
2662
- boundaryElement?: () => HTMLElement | null,
2663
- ): void
2664
-
2665
- /**
2666
- * @public
2667
- * @deprecated - change `useClickOutside(handler, () => [...], boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
2668
- */
2669
- export declare function useClickOutside(
2670
- listener: ClickOutsideListener | false | undefined,
2671
- elementsArg: () => ClickOutsideElements,
2672
- boundaryElement: HTMLElement | null,
2673
- ): void
2674
-
2675
- /**
2676
- * @public
2677
- * @deprecated - change `useClickOutside(handler, [...], () => boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
2678
- */
2679
- export declare function useClickOutside(
2680
- listener: ClickOutsideListener | false | undefined,
2681
- elementsArg: ClickOutsideElements,
2682
- boundaryElement: () => HTMLElement | null,
2683
- ): UseClickOutsideSetElement
2684
-
2685
- /**
2686
- * @public
2687
- * @deprecated
2688
- * Instead of:
2668
+ * @deprecated replaced by the new `useClickOutsideEvent` hook, instead of:
2689
2669
  * ```tsx
2690
- * const buttonRef = useRef(null)
2691
- * const setElement = useClickOutside(() => {}, [buttonRef.current])
2692
- * return (
2693
- * <>
2694
- * <button ref={buttonRef} />
2695
- * {open && <div ref={setElement} />}
2696
- * </>
2697
- * )
2670
+ * const [button, setButtonElement] = useState(null)
2671
+ * useClickOutside((event) => {}, [button])
2672
+ * return <button ref={setButtonElement} />
2698
2673
  * ```
2699
- * Use:
2674
+ * do:
2700
2675
  * ```tsx
2701
2676
  * const buttonRef = useRef()
2702
- * const [element, setElement] = useState(null)
2703
- * useClickOutside(() => {}, () => [buttonRef.current, element])
2704
- * return (
2705
- * <>
2706
- * <button ref={buttonRef} />
2707
- * {open && <div ref={setElement} />}
2708
- * </>
2709
- * )
2677
+ * useClickOutsideEvent((event) => {}, () => [buttonRef.current])
2678
+ * return <button ref={buttonRef} />
2710
2679
  * ```
2711
2680
  */
2712
2681
  export declare function useClickOutside(
2713
- listener: ClickOutsideListener | false | undefined,
2714
- elementsArg: ClickOutsideElements,
2682
+ listener: ClickOutsideListener,
2683
+ elementsArg?: ClickOutsideElements,
2715
2684
  boundaryElement?: HTMLElement | null,
2716
- ): UseClickOutsideSetElement
2685
+ ): (el: HTMLElement | null) => void
2717
2686
 
2718
2687
  /**
2719
2688
  * @public
2720
- * @deprecated - use your own `const [element, setElement] = useState(null)` logic instead
2721
2689
  */
2722
- export declare type UseClickOutsideSetElement = (el: HTMLElement | null) => void
2690
+ export declare function useClickOutsideEvent(
2691
+ listener: ClickOutsideEventListener | false | undefined,
2692
+ elementsArg?: () => ClickOutsideEventElements,
2693
+ boundaryElement?: () => HTMLElement | null,
2694
+ ): void
2723
2695
 
2724
2696
  /**
2725
2697
  * @beta
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, useEffect, useRef, useImperativeHandle, useDebugValue, useSyncExternalStore, createContext, useContext, forwardRef, useId, useCallback, Children, isValidElement, cloneElement, Component, memo, useLayoutEffect, useReducer, Fragment as Fragment$1, startTransition } from "react";
3
+ import { useMemo, useState, useRef, useEffect, 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,8 +131,48 @@ 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
+ }
134
140
  function useClickOutside(listener, elementsArg = EMPTY_ARRAY, boundaryElement) {
135
- const [legacyElement, setLegacyElement] = useState(null), onEvent = useEffectEvent((evt) => {
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;
146
+ 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;
156
+ 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;
173
+ }
174
+ function useClickOutsideEvent(listener, elementsArg = () => EMPTY_ARRAY, boundaryElement) {
175
+ const onEvent = useEffectEvent((evt) => {
136
176
  if (!listener)
137
177
  return;
138
178
  const target = evt.target;
@@ -141,20 +181,19 @@ function useClickOutside(listener, elementsArg = EMPTY_ARRAY, boundaryElement) {
141
181
  const resolvedBoundaryElement = typeof boundaryElement == "function" ? boundaryElement() : boundaryElement;
142
182
  if (resolvedBoundaryElement && !resolvedBoundaryElement.contains(target))
143
183
  return;
144
- const elements = (Array.isArray(elementsArg) ? [legacyElement, ...elementsArg] : elementsArg()).flat();
184
+ const elements = (Array.isArray(elementsArg) ? elementsArg : elementsArg()).flat();
145
185
  for (const el of elements)
146
186
  if (el && (target === el || el.contains(target)))
147
187
  return;
148
188
  listener(evt);
149
189
  }), hasListener = !!listener;
150
- if (useEffect(() => {
190
+ useEffect(() => {
151
191
  if (!hasListener) return;
152
192
  const handleEvent = (evt) => onEvent(evt);
153
193
  return document.addEventListener("mousedown", handleEvent), () => {
154
194
  document.removeEventListener("mousedown", handleEvent);
155
195
  };
156
- }, [hasListener, onEvent]), Array.isArray(elementsArg))
157
- return setLegacyElement;
196
+ }, [hasListener, onEvent]);
158
197
  }
159
198
  function useCustomValidity(ref, customValidity) {
160
199
  useEffect(() => {
@@ -5109,11 +5148,14 @@ const Root$7 = styled(Layer)(responsivePaddingStyle, dialogStyle, responsiveDial
5109
5148
  [boundaryElement, isTopLayer, onClose, portalElement]
5110
5149
  )
5111
5150
  ), useClickOutside(
5112
- (event) => {
5113
- if (!isTopLayer || !onClickOutside) return;
5114
- const target = event.target;
5115
- target && !isTargetWithinScope(boundaryElement, portalElement, target) || onClickOutside();
5116
- },
5151
+ useCallback(
5152
+ (event) => {
5153
+ if (!isTopLayer || !onClickOutside) return;
5154
+ const target = event.target;
5155
+ target && !isTargetWithinScope(boundaryElement, portalElement, target) || onClickOutside();
5156
+ },
5157
+ [boundaryElement, isTopLayer, onClickOutside, portalElement]
5158
+ ),
5117
5159
  [rootElement]
5118
5160
  );
5119
5161
  const setRef = useCallback((el) => {
@@ -5450,7 +5492,13 @@ const Root$5 = styled(Box)`
5450
5492
  );
5451
5493
  useEffect(() => {
5452
5494
  onItemSelect && onItemSelect(activeIndex);
5453
- }, [activeIndex, onItemSelect]), useClickOutside((event) => isTopLayer && onClickOutside && onClickOutside(event), [rootElement]), useGlobalKeyDown(
5495
+ }, [activeIndex, onItemSelect]), useClickOutside(
5496
+ useCallback(
5497
+ (event) => isTopLayer && onClickOutside && onClickOutside(event),
5498
+ [isTopLayer, onClickOutside]
5499
+ ),
5500
+ [rootElement]
5501
+ ), useGlobalKeyDown(
5454
5502
  useCallback(
5455
5503
  (event) => {
5456
5504
  isTopLayer && event.key === "Escape" && (event.stopPropagation(), onEscape && onEscape());
@@ -6841,6 +6889,7 @@ export {
6841
6889
  useArrayProp,
6842
6890
  useBoundaryElement,
6843
6891
  useClickOutside,
6892
+ useClickOutsideEvent,
6844
6893
  useCustomValidity,
6845
6894
  useDialog,
6846
6895
  useElementRect,