@sanity/ui 2.7.1-canary.1 → 2.7.1-canary.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.
@@ -5,11 +5,16 @@ import {EMPTY_ARRAY} from '../constants'
5
5
  /**
6
6
  * @public
7
7
  */
8
- export type ClickOutsideListener = (event: MouseEvent | TouchEvent) => void
8
+ export type ClickOutsideListener = (event: MouseEvent) => void
9
9
 
10
10
  /**
11
11
  * @public
12
- * @deprecated -- do not use
12
+ */
13
+ export type ClickOutsideElements = (HTMLElement | null | (HTMLElement | null)[])[]
14
+
15
+ /**
16
+ * @public
17
+ * @deprecated - use your own `const [element, setElement] = useState(null)` logic instead
13
18
  */
14
19
  export type UseClickOutsideSetElement = (el: HTMLElement | null) => void
15
20
 
@@ -17,11 +22,28 @@ export type UseClickOutsideSetElement = (el: HTMLElement | null) => void
17
22
  * @public
18
23
  */
19
24
  export function useClickOutside(
20
- listener: ClickOutsideListener,
21
- elementsArg: () => (HTMLElement | HTMLElement[] | null)[],
22
- boundaryElement?: HTMLElement | null,
25
+ listener: ClickOutsideListener | false | undefined,
26
+ elementsArg: () => ClickOutsideElements,
27
+ boundaryElement?: () => HTMLElement | null,
23
28
  ): void
24
-
29
+ /**
30
+ * @public
31
+ * @deprecated - change `useClickOutside(handler, () => [...], boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
32
+ */
33
+ export function useClickOutside(
34
+ listener: ClickOutsideListener | false | undefined,
35
+ elementsArg: () => ClickOutsideElements,
36
+ boundaryElement: HTMLElement | null,
37
+ ): void
38
+ /**
39
+ * @public
40
+ * @deprecated - change `useClickOutside(handler, [...], () => boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
41
+ */
42
+ export function useClickOutside(
43
+ listener: ClickOutsideListener | false | undefined,
44
+ elementsArg: ClickOutsideElements,
45
+ boundaryElement: () => HTMLElement | null,
46
+ ): UseClickOutsideSetElement
25
47
  /**
26
48
  * @public
27
49
  * @deprecated
@@ -50,8 +72,8 @@ export function useClickOutside(
50
72
  * ```
51
73
  */
52
74
  export function useClickOutside(
53
- listener: ClickOutsideListener,
54
- elementsArg: (HTMLElement | HTMLElement[] | null)[],
75
+ listener: ClickOutsideListener | false | undefined,
76
+ elementsArg: ClickOutsideElements,
55
77
  boundaryElement?: HTMLElement | null,
56
78
  ): UseClickOutsideSetElement
57
79
 
@@ -59,11 +81,9 @@ export function useClickOutside(
59
81
  * @public
60
82
  */
61
83
  export function useClickOutside(
62
- listener: ClickOutsideListener,
63
- elementsArg:
64
- | (HTMLElement | HTMLElement[] | null)[]
65
- | (() => (HTMLElement | HTMLElement[] | null)[]) = EMPTY_ARRAY,
66
- boundaryElement?: HTMLElement | null,
84
+ listener: ClickOutsideListener | false | undefined,
85
+ elementsArg: ClickOutsideElements | (() => ClickOutsideElements) = EMPTY_ARRAY,
86
+ boundaryElement?: HTMLElement | null | (() => HTMLElement | null),
67
87
  ): UseClickOutsideSetElement | void {
68
88
  /** @deprecated */
69
89
  const [legacyElement, setLegacyElement] = useState<HTMLElement | null>(null)
@@ -72,14 +92,20 @@ export function useClickOutside(
72
92
  * The `useEffectEvent` hook allow us to always see the latest value of `listener`, `elementsArg` and `boundaryElement` without needing to
73
93
  * juggle `useState`, `useRef` and `useState` to make sure the `mousedown` event listener isn't constantly being added and removed.
74
94
  */
75
- const onEvent = useEffectEvent((evt: MouseEvent | TouchEvent) => {
95
+ const onEvent = useEffectEvent((evt: MouseEvent) => {
96
+ if (!listener) {
97
+ return
98
+ }
99
+
76
100
  const target = evt.target
77
101
 
78
102
  if (!(target instanceof Node)) {
79
103
  return
80
104
  }
81
105
 
82
- if (boundaryElement && !boundaryElement.contains(target)) {
106
+ const resolvedBoundaryElement =
107
+ typeof boundaryElement === 'function' ? boundaryElement() : boundaryElement
108
+ if (resolvedBoundaryElement && !resolvedBoundaryElement.contains(target)) {
83
109
  return
84
110
  }
85
111
 
@@ -104,14 +130,12 @@ export function useClickOutside(
104
130
  useEffect(() => {
105
131
  if (!hasListener) return undefined
106
132
 
107
- const handleEvent = (evt: MouseEvent | TouchEvent) => onEvent(evt)
133
+ const handleEvent = (evt: MouseEvent) => onEvent(evt)
108
134
 
109
135
  document.addEventListener('mousedown', handleEvent)
110
- document.addEventListener('touchstart', handleEvent)
111
136
 
112
137
  return () => {
113
138
  document.removeEventListener('mousedown', handleEvent)
114
- document.removeEventListener('touchstart', handleEvent)
115
139
  }
116
140
  }, [hasListener, onEvent])
117
141
 
@@ -1,7 +1,7 @@
1
1
  import {EllipsisVerticalIcon} from '@sanity/icons'
2
2
  import {Button, Card, Flex, Popover, Text, useClickOutside} from '@sanity/ui'
3
3
  import {useBoolean, useSelect} from '@sanity/ui-workshop'
4
- import {useCallback, useState} from 'react'
4
+ import {useCallback, useRef, useState} from 'react'
5
5
  import {
6
6
  WORKSHOP_FLEX_ALIGN_OPTIONS,
7
7
  WORKSHOP_FLEX_JUSTIFY_OPTIONS,
@@ -20,8 +20,8 @@ export default function AlignedStory() {
20
20
 
21
21
  const [open, setOpen] = useState(false)
22
22
  const [boundaryElement, setBoundaryElement] = useState<HTMLDivElement | null>(null)
23
- const [buttonElement, setButtonElement] = useState<HTMLButtonElement | null>(null)
24
- const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)
23
+ const buttonElementRef = useRef<HTMLButtonElement | null>(null)
24
+ const popoverElementRef = useRef<HTMLDivElement | null>(null)
25
25
 
26
26
  const content = (
27
27
  <Text>
@@ -39,9 +39,11 @@ export default function AlignedStory() {
39
39
  )
40
40
 
41
41
  const handleToggleOpen = useCallback(() => setOpen((v) => !v), [])
42
- const handleClose = useCallback(() => setOpen(false), [])
43
42
 
44
- useClickOutside(handleClose, [buttonElement, popoverElement])
43
+ useClickOutside(
44
+ () => setOpen(false),
45
+ () => [buttonElementRef.current, popoverElementRef.current],
46
+ )
45
47
 
46
48
  return (
47
49
  <Card height="fill" padding={[4, 5, 6]} sizing="border" tone="transparent">
@@ -56,14 +58,14 @@ export default function AlignedStory() {
56
58
  padding={3}
57
59
  portal={portal}
58
60
  placement={placement}
59
- ref={setPopoverElement}
61
+ ref={popoverElementRef}
60
62
  width={width}
61
63
  >
62
64
  <Button
63
65
  icon={EllipsisVerticalIcon}
64
66
  mode="bleed"
65
67
  onClick={handleToggleOpen}
66
- ref={setButtonElement}
68
+ ref={buttonElementRef}
67
69
  selected={open}
68
70
  />
69
71
  </Popover>