@tamagui/popover 2.0.0-rc.8 → 2.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/cjs/Popover.cjs +624 -408
- package/dist/cjs/Popover.native.js +637 -438
- package/dist/cjs/Popover.native.js.map +1 -1
- package/dist/cjs/index.cjs +7 -5
- package/dist/cjs/index.native.js +7 -5
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/useFloatingContext.cjs +226 -58
- package/dist/cjs/useFloatingContext.native.js +28 -26
- package/dist/cjs/useFloatingContext.native.js.map +1 -1
- package/dist/esm/Popover.mjs +576 -377
- package/dist/esm/Popover.mjs.map +1 -1
- package/dist/esm/Popover.native.js +591 -409
- package/dist/esm/Popover.native.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -6
- package/dist/esm/useFloatingContext.mjs +200 -34
- package/dist/esm/useFloatingContext.mjs.map +1 -1
- package/dist/jsx/Popover.mjs +576 -377
- package/dist/jsx/Popover.mjs.map +1 -1
- package/dist/jsx/Popover.native.js +637 -438
- package/dist/jsx/Popover.native.js.map +1 -1
- package/dist/jsx/index.js +2 -2
- package/dist/jsx/index.js.map +1 -6
- package/dist/jsx/index.native.js +7 -5
- package/dist/jsx/useFloatingContext.mjs +200 -34
- package/dist/jsx/useFloatingContext.mjs.map +1 -1
- package/dist/jsx/useFloatingContext.native.js +28 -26
- package/dist/jsx/useFloatingContext.native.js.map +1 -1
- package/package.json +26 -31
- package/src/Popover.tsx +494 -175
- package/src/useFloatingContext.tsx +321 -43
- package/types/Popover.d.ts +126 -8
- package/types/Popover.d.ts.map +1 -1
- package/types/useFloatingContext.d.ts +14 -8
- package/types/useFloatingContext.d.ts.map +1 -1
- package/dist/cjs/Popover.js +0 -394
- package/dist/cjs/Popover.js.map +0 -6
- package/dist/cjs/index.js +0 -16
- package/dist/cjs/index.js.map +0 -6
- package/dist/cjs/useFloatingContext.js +0 -74
- package/dist/cjs/useFloatingContext.js.map +0 -6
- package/dist/esm/Popover.js +0 -415
- package/dist/esm/Popover.js.map +0 -6
- package/dist/esm/useFloatingContext.js +0 -59
- package/dist/esm/useFloatingContext.js.map +0 -6
- package/dist/jsx/Popover.js +0 -415
- package/dist/jsx/Popover.js.map +0 -6
- package/dist/jsx/useFloatingContext.js +0 -59
- package/dist/jsx/useFloatingContext.js.map +0 -6
package/src/Popover.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@tamagui/polyfill-dev'
|
|
2
2
|
|
|
3
|
-
import type { UseHoverProps } from '@floating
|
|
3
|
+
import type { UseHoverProps } from '@tamagui/floating'
|
|
4
4
|
import {
|
|
5
5
|
Adapt,
|
|
6
6
|
AdaptParent,
|
|
@@ -12,19 +12,20 @@ import {
|
|
|
12
12
|
import { Animate } from '@tamagui/animate'
|
|
13
13
|
import { ResetPresence } from '@tamagui/animate-presence'
|
|
14
14
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
15
|
-
import { isWeb } from '@tamagui/constants'
|
|
16
|
-
import type { SizeTokens,
|
|
15
|
+
import { isWeb, useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
16
|
+
import type { SizeTokens, TamaguiElement, ViewProps } from '@tamagui/core'
|
|
17
17
|
import {
|
|
18
18
|
createStyledContext,
|
|
19
|
-
styled,
|
|
20
|
-
Theme,
|
|
21
19
|
useCreateShallowSetState,
|
|
22
20
|
useEvent,
|
|
23
21
|
useGet,
|
|
24
|
-
useThemeName,
|
|
25
22
|
View,
|
|
26
23
|
} from '@tamagui/core'
|
|
27
|
-
import
|
|
24
|
+
import {
|
|
25
|
+
Dismissable,
|
|
26
|
+
DismissableBranch,
|
|
27
|
+
type DismissableProps,
|
|
28
|
+
} from '@tamagui/dismissable'
|
|
28
29
|
import { FloatingOverrideContext } from '@tamagui/floating'
|
|
29
30
|
import type { FocusScopeProps } from '@tamagui/focus-scope'
|
|
30
31
|
import { FocusScope, FocusScopeController } from '@tamagui/focus-scope'
|
|
@@ -43,14 +44,13 @@ import {
|
|
|
43
44
|
PopperProvider,
|
|
44
45
|
usePopperContext,
|
|
45
46
|
} from '@tamagui/popper'
|
|
46
|
-
import { needsPortalRepropagation, Portal
|
|
47
|
+
import { needsPortalRepropagation, Portal } from '@tamagui/portal'
|
|
47
48
|
import { RemoveScroll } from '@tamagui/remove-scroll'
|
|
48
49
|
import { ScrollView, type ScrollViewProps } from '@tamagui/scroll-view'
|
|
49
50
|
import { SheetController } from '@tamagui/sheet/controller'
|
|
50
51
|
import type { YStackProps } from '@tamagui/stacks'
|
|
51
52
|
import { YStack } from '@tamagui/stacks'
|
|
52
53
|
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
53
|
-
import { StackZIndexContext } from '@tamagui/z-index-stack'
|
|
54
54
|
import * as React from 'react'
|
|
55
55
|
import { useFloatingContext } from './useFloatingContext'
|
|
56
56
|
|
|
@@ -62,6 +62,28 @@ type ScopedPopoverProps<P> = Omit<P, 'scope'> & {
|
|
|
62
62
|
|
|
63
63
|
const needsRepropagation = needsPortalRepropagation()
|
|
64
64
|
|
|
65
|
+
const openPopovers = new Set<React.Dispatch<React.SetStateAction<boolean>>>()
|
|
66
|
+
|
|
67
|
+
export const hasOpenPopovers = () => {
|
|
68
|
+
return openPopovers.size > 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const closeOpenPopovers = () => {
|
|
72
|
+
if (openPopovers.size === 0) return false
|
|
73
|
+
openPopovers.forEach((setOpen) => setOpen(false))
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const closeLastOpenedPopover = () => {
|
|
78
|
+
if (openPopovers.size === 0) return false
|
|
79
|
+
const last = Array.from(openPopovers).pop()
|
|
80
|
+
if (last) {
|
|
81
|
+
last(false)
|
|
82
|
+
return true
|
|
83
|
+
}
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
65
87
|
type PopoverVia = 'hover' | 'press'
|
|
66
88
|
|
|
67
89
|
export type PopoverProps = ScopedPopoverProps<PopperProps> & {
|
|
@@ -86,6 +108,24 @@ export type PopoverProps = ScopedPopoverProps<PopperProps> & {
|
|
|
86
108
|
* Disable focusing behavior on open
|
|
87
109
|
*/
|
|
88
110
|
disableFocus?: boolean
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Disable the dismissable layer (escape key, outside click handling).
|
|
114
|
+
* Useful for popovers that stay mounted but are visually hidden.
|
|
115
|
+
*/
|
|
116
|
+
disableDismissable?: boolean
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* z-index for the popover portal. Use this when popovers need to appear
|
|
120
|
+
* above other portaled content like dialogs or fixed headers.
|
|
121
|
+
*
|
|
122
|
+
* By default, Tamagui automatically stacks overlays - later-opened content
|
|
123
|
+
* appears above earlier content, and nested content appears above its parent.
|
|
124
|
+
* Only set this if you need to override the automatic stacking behavior.
|
|
125
|
+
*
|
|
126
|
+
* @see https://tamagui.dev/ui/z-index
|
|
127
|
+
*/
|
|
128
|
+
zIndex?: number
|
|
89
129
|
}
|
|
90
130
|
|
|
91
131
|
// let users override for type safety
|
|
@@ -106,7 +146,24 @@ type PopoverContextValue = {
|
|
|
106
146
|
size?: SizeTokens
|
|
107
147
|
breakpointActive?: boolean
|
|
108
148
|
keepChildrenMounted?: boolean | 'lazy'
|
|
149
|
+
disableDismissable?: boolean
|
|
150
|
+
hoverable?: boolean | object
|
|
109
151
|
anchorTo?: Rect
|
|
152
|
+
// scoped branches Set for DismissableBranch/Dismissable to share
|
|
153
|
+
branches: Set<HTMLElement>
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type PopoverTriggerStateSetter = React.Dispatch<React.SetStateAction<boolean>>
|
|
157
|
+
|
|
158
|
+
type PopoverTriggerContextValue = {
|
|
159
|
+
triggerRef: React.RefObject<any>
|
|
160
|
+
hasCustomAnchor: boolean
|
|
161
|
+
anchorTo?: Rect
|
|
162
|
+
branches: Set<HTMLElement>
|
|
163
|
+
onOpenToggle(): void
|
|
164
|
+
setActiveTrigger(id: string | null): void
|
|
165
|
+
registerTrigger(id: string, setOpen: PopoverTriggerStateSetter): void
|
|
166
|
+
unregisterTrigger(id: string): void
|
|
110
167
|
}
|
|
111
168
|
|
|
112
169
|
export const PopoverContext = createStyledContext<PopoverContextValue>(
|
|
@@ -115,93 +172,302 @@ export const PopoverContext = createStyledContext<PopoverContextValue>(
|
|
|
115
172
|
'Popover__'
|
|
116
173
|
)
|
|
117
174
|
|
|
175
|
+
// zIndex flows from root Popover prop to PopoverContent portal
|
|
176
|
+
export const PopoverZIndexContext = React.createContext<number | undefined>(undefined)
|
|
177
|
+
|
|
178
|
+
export const PopoverTriggerContext = createStyledContext<PopoverTriggerContextValue>(
|
|
179
|
+
{} as PopoverTriggerContextValue,
|
|
180
|
+
'PopoverTrigger__'
|
|
181
|
+
)
|
|
182
|
+
|
|
118
183
|
export const usePopoverContext = PopoverContext.useStyledContext
|
|
184
|
+
export const usePopoverTriggerContext = PopoverTriggerContext.useStyledContext
|
|
119
185
|
|
|
120
|
-
|
|
121
|
-
*
|
|
122
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Read reactive popover open state from the popover context.
|
|
188
|
+
*/
|
|
189
|
+
export function usePopoverOpen(scope?: string): boolean {
|
|
190
|
+
return usePopoverContext(scope).open
|
|
191
|
+
}
|
|
123
192
|
|
|
124
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Hook to set up trigger registration/isolation logic.
|
|
195
|
+
* Used internally by Popover and can be used by Tooltip.
|
|
196
|
+
*/
|
|
197
|
+
export function usePopoverTriggerSetup(open: boolean) {
|
|
198
|
+
const triggerStateSettersRef = React.useRef(
|
|
199
|
+
new Map<string, PopoverTriggerStateSetter>()
|
|
200
|
+
)
|
|
201
|
+
const activeTriggerIdRef = React.useRef<string | null>(null)
|
|
125
202
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
203
|
+
const setActiveTrigger = useEvent((id: string | null) => {
|
|
204
|
+
const prevId = activeTriggerIdRef.current
|
|
205
|
+
if (prevId === id) return
|
|
206
|
+
if (prevId) {
|
|
207
|
+
triggerStateSettersRef.current.get(prevId)?.(false)
|
|
208
|
+
}
|
|
209
|
+
activeTriggerIdRef.current = id
|
|
210
|
+
if (id && open) {
|
|
211
|
+
triggerStateSettersRef.current.get(id)?.(true)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
131
214
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
215
|
+
const registerTrigger = useEvent(
|
|
216
|
+
(id: string, setOpenState: PopoverTriggerStateSetter) => {
|
|
217
|
+
triggerStateSettersRef.current.set(id, setOpenState)
|
|
218
|
+
setOpenState(activeTriggerIdRef.current === id && open)
|
|
219
|
+
}
|
|
220
|
+
)
|
|
136
221
|
|
|
137
|
-
|
|
222
|
+
const unregisterTrigger = useEvent((id: string) => {
|
|
223
|
+
triggerStateSettersRef.current.delete(id)
|
|
224
|
+
if (activeTriggerIdRef.current === id) {
|
|
225
|
+
activeTriggerIdRef.current = null
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
React.useEffect(() => {
|
|
230
|
+
if (!open) {
|
|
231
|
+
setActiveTrigger(null)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
const activeId = activeTriggerIdRef.current
|
|
235
|
+
if (activeId) {
|
|
236
|
+
triggerStateSettersRef.current.get(activeId)?.(true)
|
|
237
|
+
}
|
|
238
|
+
}, [open, setActiveTrigger])
|
|
239
|
+
|
|
240
|
+
return { setActiveTrigger, registerTrigger, unregisterTrigger }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export type PopoverContextProviderProps = {
|
|
244
|
+
scope: string
|
|
245
|
+
children: React.ReactNode
|
|
246
|
+
// PopoverContext values
|
|
247
|
+
open: boolean
|
|
248
|
+
onOpenChange(open: boolean, via?: 'hover' | 'press'): void
|
|
249
|
+
onOpenToggle(): void
|
|
250
|
+
triggerRef: React.RefObject<any>
|
|
251
|
+
id?: string
|
|
252
|
+
contentId?: string
|
|
253
|
+
hasCustomAnchor?: boolean
|
|
254
|
+
onCustomAnchorAdd?: () => void
|
|
255
|
+
onCustomAnchorRemove?: () => void
|
|
256
|
+
anchorTo?: Rect
|
|
257
|
+
// extra props for Popover (optional for Tooltip)
|
|
258
|
+
adaptScope?: string
|
|
259
|
+
breakpointActive?: boolean
|
|
260
|
+
keepChildrenMounted?: boolean | 'lazy'
|
|
261
|
+
disableDismissable?: boolean
|
|
262
|
+
hoverable?: boolean | object
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Provider that sets up both PopoverContext and PopoverTriggerContext.
|
|
267
|
+
* Use this in Tooltip or other components that need popover trigger behavior.
|
|
268
|
+
*/
|
|
269
|
+
export const PopoverContextProvider = React.memo(
|
|
270
|
+
({
|
|
271
|
+
scope,
|
|
272
|
+
children,
|
|
273
|
+
open,
|
|
274
|
+
onOpenChange,
|
|
275
|
+
onOpenToggle,
|
|
276
|
+
triggerRef,
|
|
277
|
+
id = '',
|
|
278
|
+
contentId,
|
|
279
|
+
hasCustomAnchor = false,
|
|
280
|
+
onCustomAnchorAdd = voidFn,
|
|
281
|
+
onCustomAnchorRemove = voidFn,
|
|
282
|
+
anchorTo,
|
|
283
|
+
adaptScope,
|
|
284
|
+
breakpointActive,
|
|
285
|
+
keepChildrenMounted,
|
|
286
|
+
disableDismissable,
|
|
287
|
+
hoverable,
|
|
288
|
+
}: PopoverContextProviderProps) => {
|
|
289
|
+
const [branches] = React.useState(() => new Set<HTMLElement>())
|
|
290
|
+
const { setActiveTrigger, registerTrigger, unregisterTrigger } =
|
|
291
|
+
usePopoverTriggerSetup(open)
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<PopoverContext.Provider
|
|
295
|
+
scope={scope}
|
|
296
|
+
popoverScope={scope}
|
|
297
|
+
adaptScope={adaptScope}
|
|
298
|
+
id={id}
|
|
299
|
+
contentId={contentId}
|
|
300
|
+
triggerRef={triggerRef}
|
|
301
|
+
open={open}
|
|
302
|
+
onOpenChange={onOpenChange}
|
|
303
|
+
onOpenToggle={onOpenToggle}
|
|
304
|
+
hasCustomAnchor={hasCustomAnchor}
|
|
305
|
+
onCustomAnchorAdd={onCustomAnchorAdd}
|
|
306
|
+
onCustomAnchorRemove={onCustomAnchorRemove}
|
|
307
|
+
anchorTo={anchorTo}
|
|
308
|
+
branches={branches}
|
|
309
|
+
breakpointActive={breakpointActive}
|
|
310
|
+
keepChildrenMounted={keepChildrenMounted}
|
|
311
|
+
disableDismissable={disableDismissable}
|
|
312
|
+
hoverable={hoverable}
|
|
313
|
+
>
|
|
314
|
+
<PopoverTriggerContext.Provider
|
|
315
|
+
scope={scope}
|
|
316
|
+
triggerRef={triggerRef}
|
|
317
|
+
hasCustomAnchor={hasCustomAnchor}
|
|
318
|
+
anchorTo={anchorTo}
|
|
319
|
+
branches={branches}
|
|
320
|
+
onOpenToggle={onOpenToggle}
|
|
321
|
+
setActiveTrigger={setActiveTrigger}
|
|
322
|
+
registerTrigger={registerTrigger}
|
|
323
|
+
unregisterTrigger={unregisterTrigger}
|
|
324
|
+
>
|
|
325
|
+
{children}
|
|
326
|
+
</PopoverTriggerContext.Provider>
|
|
327
|
+
</PopoverContext.Provider>
|
|
328
|
+
)
|
|
138
329
|
}
|
|
139
330
|
)
|
|
140
331
|
|
|
332
|
+
const voidFn = () => {}
|
|
333
|
+
|
|
141
334
|
/* -------------------------------------------------------------------------------------------------
|
|
142
|
-
*
|
|
335
|
+
* PopoverAnchor
|
|
143
336
|
* -----------------------------------------------------------------------------------------------*/
|
|
144
337
|
|
|
145
|
-
export type
|
|
338
|
+
export type PopoverAnchorProps = ScopedPopoverProps<YStackProps>
|
|
146
339
|
|
|
147
|
-
export const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
340
|
+
export const PopoverAnchor = React.memo(
|
|
341
|
+
React.forwardRef<TamaguiElement, PopoverAnchorProps>(
|
|
342
|
+
function PopoverAnchor(props, forwardedRef) {
|
|
343
|
+
const { scope, ...rest } = props
|
|
344
|
+
const context = usePopoverContext(scope)
|
|
345
|
+
const { onCustomAnchorAdd, onCustomAnchorRemove } = context || {}
|
|
151
346
|
|
|
152
|
-
|
|
153
|
-
|
|
347
|
+
React.useEffect(() => {
|
|
348
|
+
onCustomAnchorAdd()
|
|
349
|
+
return () => onCustomAnchorRemove()
|
|
350
|
+
}, [onCustomAnchorAdd, onCustomAnchorRemove])
|
|
154
351
|
|
|
155
|
-
|
|
156
|
-
return null
|
|
352
|
+
return <PopperAnchor scope={scope} {...rest} ref={forwardedRef} />
|
|
157
353
|
}
|
|
354
|
+
)
|
|
355
|
+
)
|
|
158
356
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
357
|
+
/* -------------------------------------------------------------------------------------------------
|
|
358
|
+
* PopoverTrigger
|
|
359
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
360
|
+
|
|
361
|
+
export type PopoverTriggerProps = ScopedPopoverProps<
|
|
362
|
+
ViewProps & {
|
|
363
|
+
/**
|
|
364
|
+
* When true, disables the built-in click-to-toggle behavior on the trigger.
|
|
365
|
+
* Useful for hoverable popovers where you want to control open/close
|
|
366
|
+
* entirely through hover or your own handlers.
|
|
367
|
+
*/
|
|
368
|
+
disablePressTrigger?: boolean
|
|
369
|
+
}
|
|
370
|
+
>
|
|
371
|
+
|
|
372
|
+
export const PopoverTrigger = React.memo(
|
|
373
|
+
React.forwardRef<TamaguiElement, PopoverTriggerProps>(
|
|
374
|
+
function PopoverTrigger(props, forwardedRef) {
|
|
375
|
+
const { scope, disablePressTrigger, ...rest } = props
|
|
376
|
+
const triggerContext = usePopoverTriggerContext(scope)
|
|
377
|
+
const triggerId = React.useId()
|
|
378
|
+
const [open, setOpen] = React.useState(false)
|
|
379
|
+
const anchorTo = triggerContext.anchorTo
|
|
380
|
+
const triggerElRef = React.useRef<TamaguiElement>(null)
|
|
381
|
+
const composedTriggerRef = useComposedRefs(forwardedRef, triggerElRef)
|
|
382
|
+
|
|
383
|
+
const { registerTrigger, unregisterTrigger } = triggerContext
|
|
384
|
+
React.useEffect(() => {
|
|
385
|
+
registerTrigger(triggerId, setOpen)
|
|
386
|
+
return () => {
|
|
387
|
+
unregisterTrigger(triggerId)
|
|
388
|
+
}
|
|
389
|
+
}, [registerTrigger, unregisterTrigger, triggerId])
|
|
171
390
|
|
|
172
|
-
|
|
173
|
-
if (!anchorTo) {
|
|
391
|
+
if (!rest.children) {
|
|
174
392
|
return null
|
|
175
393
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
c(anchorTo?.x, anchorTo?.y, anchorTo?.width, anchorTo?.height),
|
|
184
|
-
}),
|
|
185
|
-
},
|
|
394
|
+
|
|
395
|
+
const activateSelf = () => {
|
|
396
|
+
triggerContext.setActiveTrigger(triggerId)
|
|
397
|
+
const el = triggerElRef.current
|
|
398
|
+
if (el) {
|
|
399
|
+
triggerContext.triggerRef.current = el
|
|
400
|
+
}
|
|
186
401
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
402
|
+
|
|
403
|
+
const trigger = (
|
|
404
|
+
<View
|
|
405
|
+
aria-expanded={open}
|
|
406
|
+
// TODO not matching
|
|
407
|
+
// aria-controls={context.contentId}
|
|
408
|
+
data-state={getState(open)}
|
|
409
|
+
{...rest}
|
|
410
|
+
// @ts-ignore
|
|
411
|
+
ref={composedTriggerRef}
|
|
412
|
+
onPress={composeEventHandlers(rest.onPress as any, () => {
|
|
413
|
+
if (disablePressTrigger) return
|
|
414
|
+
triggerContext.setActiveTrigger(open ? null : triggerId)
|
|
415
|
+
triggerContext.onOpenToggle()
|
|
416
|
+
})}
|
|
417
|
+
onMouseEnter={composeEventHandlers(rest.onMouseEnter as any, activateSelf)}
|
|
418
|
+
onPressIn={composeEventHandlers(rest.onPressIn as any, activateSelf)}
|
|
419
|
+
onFocus={composeEventHandlers(rest.onFocus as any, activateSelf)}
|
|
420
|
+
/>
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
const virtualRef = React.useMemo(() => {
|
|
424
|
+
if (!anchorTo) {
|
|
425
|
+
return null
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
current: {
|
|
429
|
+
getBoundingClientRect: () => (isWeb ? DOMRect.fromRect(anchorTo) : anchorTo),
|
|
430
|
+
...(!isWeb && {
|
|
431
|
+
measure: (c) =>
|
|
432
|
+
c(anchorTo?.x, anchorTo?.y, anchorTo?.width, anchorTo?.height),
|
|
433
|
+
measureInWindow: (c) =>
|
|
434
|
+
c(anchorTo?.x, anchorTo?.y, anchorTo?.width, anchorTo?.height),
|
|
435
|
+
}),
|
|
436
|
+
},
|
|
437
|
+
}
|
|
438
|
+
}, [
|
|
439
|
+
triggerContext.anchorTo,
|
|
440
|
+
anchorTo?.x,
|
|
441
|
+
anchorTo?.y,
|
|
442
|
+
anchorTo?.height,
|
|
443
|
+
anchorTo?.width,
|
|
444
|
+
])
|
|
445
|
+
|
|
446
|
+
// wrap trigger in DismissableBranch so clicking it doesn't fire pointerDownOutside
|
|
447
|
+
// which would close the popover before onPress can toggle it
|
|
448
|
+
const wrappedTrigger = isWeb ? (
|
|
449
|
+
<DismissableBranch branches={triggerContext.branches}>
|
|
450
|
+
{trigger}
|
|
451
|
+
</DismissableBranch>
|
|
452
|
+
) : (
|
|
453
|
+
trigger
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
return triggerContext.hasCustomAnchor ? (
|
|
457
|
+
wrappedTrigger
|
|
458
|
+
) : (
|
|
459
|
+
<PopperAnchor {...(virtualRef && { virtualRef })} scope={scope} asChild>
|
|
460
|
+
{wrappedTrigger}
|
|
461
|
+
</PopperAnchor>
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
)
|
|
197
465
|
)
|
|
198
466
|
|
|
199
467
|
/* -------------------------------------------------------------------------------------------------
|
|
200
468
|
* PopoverContent
|
|
201
469
|
* -----------------------------------------------------------------------------------------------*/
|
|
202
470
|
|
|
203
|
-
type PopoverContentTypeElement = PopoverContentImplElement
|
|
204
|
-
|
|
205
471
|
export interface PopoverContentTypeProps extends Omit<
|
|
206
472
|
PopoverContentImplProps,
|
|
207
473
|
'disableOutsidePointerEvents'
|
|
@@ -216,38 +482,38 @@ export interface PopoverContentTypeProps extends Omit<
|
|
|
216
482
|
|
|
217
483
|
export type PopoverContentProps = PopoverContentTypeProps
|
|
218
484
|
|
|
219
|
-
const
|
|
220
|
-
name: 'Popover',
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
export const PopoverContent = PopoverContentFrame.styleable<PopoverContentProps>(
|
|
485
|
+
export const PopoverContent = PopperContentFrame.styleable<PopoverContentProps>(
|
|
224
486
|
function PopoverContent(props, forwardedRef) {
|
|
225
487
|
const {
|
|
226
488
|
trapFocus,
|
|
227
489
|
enableRemoveScroll = false,
|
|
228
|
-
zIndex,
|
|
490
|
+
zIndex: zIndexProp,
|
|
229
491
|
scope,
|
|
230
492
|
...contentImplProps
|
|
231
493
|
} = props
|
|
232
494
|
|
|
233
495
|
const context = usePopoverContext(scope)
|
|
496
|
+
const zIndexFromContext = React.useContext(PopoverZIndexContext)
|
|
497
|
+
// prop on Content takes precedence for backwards compatibility, then context from root
|
|
498
|
+
const zIndex = zIndexProp ?? zIndexFromContext
|
|
499
|
+
const open = usePopoverOpen(scope)
|
|
234
500
|
const contentRef = React.useRef<any>(null)
|
|
235
501
|
const composedRefs = useComposedRefs(forwardedRef, contentRef)
|
|
236
502
|
const isRightClickOutsideRef = React.useRef(false)
|
|
237
|
-
const [isFullyHidden, setIsFullyHidden] = React.useState(!
|
|
503
|
+
const [isFullyHidden, setIsFullyHidden] = React.useState(!open)
|
|
238
504
|
|
|
239
505
|
// Reset isFullyHidden when popover opens (useEffect avoids render-phase timing issues)
|
|
240
506
|
// there was a hard to isolate bug in tamagui.dev where moving between /ui docs pages quickly
|
|
241
507
|
// caused it to infinite loop, the setState in render (and useLayoutEffect) made it too prone
|
|
242
508
|
// to bug, useEffect maybe fine here because its hidden, ok to be slightly delayed while hidden
|
|
243
|
-
|
|
244
|
-
if (
|
|
509
|
+
useIsomorphicLayoutEffect(() => {
|
|
510
|
+
if (open && isFullyHidden) {
|
|
245
511
|
setIsFullyHidden(false)
|
|
246
512
|
}
|
|
247
|
-
}, [
|
|
513
|
+
}, [open, isFullyHidden])
|
|
248
514
|
|
|
249
515
|
if (!context.keepChildrenMounted) {
|
|
250
|
-
if (isFullyHidden && !
|
|
516
|
+
if (isFullyHidden && !open) {
|
|
251
517
|
return null
|
|
252
518
|
}
|
|
253
519
|
}
|
|
@@ -256,24 +522,24 @@ export const PopoverContent = PopoverContentFrame.styleable<PopoverContentProps>
|
|
|
256
522
|
<PopoverPortal
|
|
257
523
|
passThrough={context.breakpointActive}
|
|
258
524
|
context={context}
|
|
525
|
+
open={open}
|
|
259
526
|
zIndex={zIndex}
|
|
260
527
|
>
|
|
261
528
|
<View
|
|
262
529
|
passThrough={context.breakpointActive}
|
|
263
|
-
pointerEvents={
|
|
264
|
-
context.open ? (contentImplProps.pointerEvents ?? 'auto') : 'none'
|
|
265
|
-
}
|
|
530
|
+
pointerEvents={open ? (contentImplProps.pointerEvents ?? 'auto') : 'none'}
|
|
266
531
|
>
|
|
267
532
|
<PopoverContentImpl
|
|
268
533
|
{...contentImplProps}
|
|
269
534
|
context={context}
|
|
535
|
+
open={open}
|
|
270
536
|
enableRemoveScroll={enableRemoveScroll}
|
|
271
537
|
ref={composedRefs}
|
|
272
538
|
setIsFullyHidden={setIsFullyHidden}
|
|
273
539
|
scope={scope}
|
|
274
540
|
// we make sure we're not trapping once it's been closed
|
|
275
541
|
// (closed !== unmounted when animating out)
|
|
276
|
-
trapFocus={trapFocus ??
|
|
542
|
+
trapFocus={trapFocus ?? open}
|
|
277
543
|
disableOutsidePointerEvents
|
|
278
544
|
onCloseAutoFocus={
|
|
279
545
|
props.onCloseAutoFocus === false
|
|
@@ -312,12 +578,14 @@ export const PopoverContent = PopoverContentFrame.styleable<PopoverContentProps>
|
|
|
312
578
|
|
|
313
579
|
const useParentContexts = (scope: string) => {
|
|
314
580
|
const context = usePopoverContext(scope)
|
|
581
|
+
const triggerContext = usePopoverTriggerContext(scope)
|
|
315
582
|
const popperContext = usePopperContext(scope)
|
|
316
583
|
const adaptContext = useAdaptContext(context.adaptScope)
|
|
317
584
|
return {
|
|
318
585
|
popperContext,
|
|
319
586
|
adaptContext,
|
|
320
587
|
context,
|
|
588
|
+
triggerContext,
|
|
321
589
|
}
|
|
322
590
|
}
|
|
323
591
|
|
|
@@ -327,14 +595,17 @@ function RepropagateParentContexts({
|
|
|
327
595
|
adaptContext,
|
|
328
596
|
children,
|
|
329
597
|
context,
|
|
598
|
+
triggerContext,
|
|
330
599
|
popperContext,
|
|
331
600
|
}: ParentContexts & {
|
|
332
601
|
children: React.ReactNode
|
|
333
602
|
}) {
|
|
334
603
|
return (
|
|
335
604
|
<PopperProvider scope={context.popoverScope} {...popperContext}>
|
|
336
|
-
<PopoverContext.Provider {...context}>
|
|
337
|
-
<
|
|
605
|
+
<PopoverContext.Provider scope={context.popoverScope} {...context}>
|
|
606
|
+
<PopoverTriggerContext.Provider scope={context.popoverScope} {...triggerContext}>
|
|
607
|
+
<ProvideAdaptContext {...adaptContext}>{children}</ProvideAdaptContext>
|
|
608
|
+
</PopoverTriggerContext.Provider>
|
|
338
609
|
</PopoverContext.Provider>
|
|
339
610
|
</PopperProvider>
|
|
340
611
|
)
|
|
@@ -347,6 +618,8 @@ const PortalAdaptSafe = ({
|
|
|
347
618
|
children?: React.ReactNode
|
|
348
619
|
context: PopoverContextValue
|
|
349
620
|
}) => {
|
|
621
|
+
'use no memo'
|
|
622
|
+
|
|
350
623
|
if (needsRepropagation) {
|
|
351
624
|
const parentContexts = useParentContexts(context.popoverScope)
|
|
352
625
|
return (
|
|
@@ -363,42 +636,40 @@ const PortalAdaptSafe = ({
|
|
|
363
636
|
|
|
364
637
|
function PopoverPortal({
|
|
365
638
|
context,
|
|
639
|
+
open,
|
|
366
640
|
zIndex,
|
|
367
641
|
passThrough,
|
|
368
642
|
children,
|
|
369
643
|
onPress,
|
|
370
644
|
}: Pick<PopoverContentProps, 'zIndex' | 'passThrough' | 'children' | 'onPress'> & {
|
|
371
645
|
context: PopoverContextValue
|
|
646
|
+
open: boolean
|
|
372
647
|
}) {
|
|
373
|
-
|
|
648
|
+
'use no memo'
|
|
374
649
|
|
|
375
650
|
let content = children
|
|
376
651
|
|
|
377
|
-
// native
|
|
652
|
+
// native without teleport
|
|
378
653
|
if (needsRepropagation) {
|
|
379
654
|
const parentContexts = useParentContexts(context.popoverScope)
|
|
380
|
-
|
|
381
655
|
content = (
|
|
382
656
|
<RepropagateParentContexts {...parentContexts}>{content}</RepropagateParentContexts>
|
|
383
657
|
)
|
|
384
658
|
}
|
|
385
659
|
|
|
386
660
|
return (
|
|
387
|
-
<Portal passThrough={passThrough} stackZIndex zIndex={zIndex
|
|
661
|
+
<Portal passThrough={passThrough} stackZIndex zIndex={zIndex}>
|
|
388
662
|
{/* forceClassName avoids forced re-mount renders for some reason... see the HeadMenu as you change tints a few times */}
|
|
389
663
|
{/* without this you'll see the site menu re-rendering. It must be something in wrapping children in Theme */}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
)}
|
|
664
|
+
{!!open && !context.breakpointActive && !context.hoverable && (
|
|
665
|
+
<YStack
|
|
666
|
+
fullscreen
|
|
667
|
+
onPress={composeEventHandlers(onPress as any, context.onOpenToggle)}
|
|
668
|
+
/>
|
|
669
|
+
)}
|
|
397
670
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
</StackZIndexContext>
|
|
401
|
-
</Theme>
|
|
671
|
+
{/* i removed a hardcoded StackZIndex because Portal has it internally now with useStackedZIndex + ZIndexHardcoded */}
|
|
672
|
+
{content}
|
|
402
673
|
</Portal>
|
|
403
674
|
)
|
|
404
675
|
}
|
|
@@ -440,10 +711,20 @@ export type PopoverContentImplProps = PopperContentProps &
|
|
|
440
711
|
enableRemoveScroll?: boolean
|
|
441
712
|
|
|
442
713
|
freezeContentsWhenHidden?: boolean
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Performance - if never going to use feature can permanently disable
|
|
717
|
+
*/
|
|
718
|
+
alwaysDisable?: {
|
|
719
|
+
focus?: boolean
|
|
720
|
+
'remove-scroll'?: boolean
|
|
721
|
+
dismiss?: boolean
|
|
722
|
+
}
|
|
443
723
|
}
|
|
444
724
|
|
|
445
725
|
type PopoverContentImplInteralProps = PopoverContentImplProps & {
|
|
446
726
|
context: PopoverContextValue
|
|
727
|
+
open: boolean
|
|
447
728
|
setIsFullyHidden: React.Dispatch<React.SetStateAction<boolean>>
|
|
448
729
|
}
|
|
449
730
|
|
|
@@ -467,11 +748,14 @@ const PopoverContentImpl = React.forwardRef<
|
|
|
467
748
|
freezeContentsWhenHidden,
|
|
468
749
|
setIsFullyHidden,
|
|
469
750
|
lazyMount,
|
|
751
|
+
forceUnmount,
|
|
470
752
|
context,
|
|
753
|
+
open,
|
|
754
|
+
alwaysDisable,
|
|
471
755
|
...contentProps
|
|
472
756
|
} = props
|
|
473
757
|
|
|
474
|
-
const {
|
|
758
|
+
const { keepChildrenMounted, disableDismissable } = context
|
|
475
759
|
|
|
476
760
|
const handleExitComplete = React.useCallback(() => {
|
|
477
761
|
setIsFullyHidden?.(true)
|
|
@@ -481,14 +765,16 @@ const PopoverContentImpl = React.forwardRef<
|
|
|
481
765
|
<ResetPresence disable={context.breakpointActive}>{children}</ResetPresence>
|
|
482
766
|
)
|
|
483
767
|
|
|
768
|
+
const handleDismiss = React.useCallback(() => {
|
|
769
|
+
context.onOpenChange(false, 'press')
|
|
770
|
+
}, [context])
|
|
771
|
+
|
|
484
772
|
// i want to avoid reparenting but react-remove-scroll makes it hard
|
|
485
773
|
// TODO its removed now so we can probable do it now
|
|
486
774
|
if (!context.breakpointActive) {
|
|
487
775
|
if (process.env.TAMAGUI_TARGET !== 'native') {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
enabled={context.breakpointActive ? false : enableRemoveScroll ? open : false}
|
|
491
|
-
>
|
|
776
|
+
if (!alwaysDisable || !alwaysDisable.focus) {
|
|
777
|
+
contents = (
|
|
492
778
|
<FocusScope
|
|
493
779
|
loop={trapFocus !== false}
|
|
494
780
|
enabled={context.breakpointActive ? false : disableFocusScope ? false : open}
|
|
@@ -498,24 +784,36 @@ const PopoverContentImpl = React.forwardRef<
|
|
|
498
784
|
>
|
|
499
785
|
<div style={dspContentsStyle}>{contents}</div>
|
|
500
786
|
</FocusScope>
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
}
|
|
787
|
+
)
|
|
788
|
+
}
|
|
505
789
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
// onDismiss={handleDismiss}
|
|
516
|
-
// >
|
|
790
|
+
if (!alwaysDisable || !alwaysDisable['remove-scroll']) {
|
|
791
|
+
contents = (
|
|
792
|
+
<RemoveScroll
|
|
793
|
+
enabled={context.breakpointActive ? false : enableRemoveScroll ? open : false}
|
|
794
|
+
>
|
|
795
|
+
{contents}
|
|
796
|
+
</RemoveScroll>
|
|
797
|
+
)
|
|
798
|
+
}
|
|
517
799
|
|
|
518
|
-
|
|
800
|
+
if (!alwaysDisable || !alwaysDisable.dismiss) {
|
|
801
|
+
contents = (
|
|
802
|
+
<Dismissable
|
|
803
|
+
branches={context.branches}
|
|
804
|
+
forceUnmount={disableDismissable || (forceUnmount ?? !open)}
|
|
805
|
+
onEscapeKeyDown={onEscapeKeyDown}
|
|
806
|
+
onPointerDownOutside={onPointerDownOutside}
|
|
807
|
+
onFocusOutside={onFocusOutside}
|
|
808
|
+
onInteractOutside={onInteractOutside}
|
|
809
|
+
onDismiss={handleDismiss}
|
|
810
|
+
>
|
|
811
|
+
{contents}
|
|
812
|
+
</Dismissable>
|
|
813
|
+
)
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
519
817
|
|
|
520
818
|
return (
|
|
521
819
|
<Animate
|
|
@@ -533,6 +831,11 @@ const PopoverContentImpl = React.forwardRef<
|
|
|
533
831
|
id={context.contentId}
|
|
534
832
|
ref={forwardedRef}
|
|
535
833
|
passThrough={context.breakpointActive}
|
|
834
|
+
{...(!contentProps.unstyled && {
|
|
835
|
+
size: '$true',
|
|
836
|
+
backgroundColor: '$background',
|
|
837
|
+
alignItems: 'center',
|
|
838
|
+
})}
|
|
536
839
|
{...contentProps}
|
|
537
840
|
>
|
|
538
841
|
<PortalAdaptSafe context={context}>{contents}</PortalAdaptSafe>
|
|
@@ -683,6 +986,8 @@ const PopoverInner = React.forwardRef<
|
|
|
683
986
|
keepChildrenMounted: keepChildrenMountedProp,
|
|
684
987
|
hoverable,
|
|
685
988
|
disableFocus,
|
|
989
|
+
disableDismissable,
|
|
990
|
+
zIndex,
|
|
686
991
|
id,
|
|
687
992
|
adaptScope,
|
|
688
993
|
...restProps
|
|
@@ -691,11 +996,13 @@ const PopoverInner = React.forwardRef<
|
|
|
691
996
|
const triggerRef = React.useRef<TamaguiElement>(null)
|
|
692
997
|
const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false)
|
|
693
998
|
const viaRef = React.useRef<PopoverVia>(undefined)
|
|
999
|
+
|
|
694
1000
|
const [keepChildrenMounted] = useControllableState({
|
|
695
1001
|
prop: keepChildrenMountedProp,
|
|
696
1002
|
defaultProp: false,
|
|
697
1003
|
transition: keepChildrenMountedProp === 'lazy',
|
|
698
1004
|
})
|
|
1005
|
+
|
|
699
1006
|
const [open, setOpen] = useControllableState({
|
|
700
1007
|
prop: openProp,
|
|
701
1008
|
defaultProp: defaultOpen || false,
|
|
@@ -704,6 +1011,15 @@ const PopoverInner = React.forwardRef<
|
|
|
704
1011
|
},
|
|
705
1012
|
})
|
|
706
1013
|
|
|
1014
|
+
// track open popovers for closeOpenPopovers()
|
|
1015
|
+
React.useEffect(() => {
|
|
1016
|
+
if (!open) return
|
|
1017
|
+
openPopovers.add(setOpen)
|
|
1018
|
+
return () => {
|
|
1019
|
+
openPopovers.delete(setOpen)
|
|
1020
|
+
}
|
|
1021
|
+
}, [open, setOpen])
|
|
1022
|
+
|
|
707
1023
|
const handleOpenChange = useEvent((val, via) => {
|
|
708
1024
|
viaRef.current = via
|
|
709
1025
|
setOpen(val)
|
|
@@ -717,7 +1033,7 @@ const PopoverInner = React.forwardRef<
|
|
|
717
1033
|
disable: isAdapted,
|
|
718
1034
|
hoverable,
|
|
719
1035
|
disableFocus: disableFocus,
|
|
720
|
-
})
|
|
1036
|
+
})
|
|
721
1037
|
|
|
722
1038
|
const [anchorTo, setAnchorToRaw] = React.useState<Rect>()
|
|
723
1039
|
|
|
@@ -733,56 +1049,46 @@ const PopoverInner = React.forwardRef<
|
|
|
733
1049
|
setOpen,
|
|
734
1050
|
}))
|
|
735
1051
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
if (open && isAdapted) {
|
|
748
|
-
return
|
|
749
|
-
}
|
|
750
|
-
setOpen(!open)
|
|
751
|
-
}),
|
|
752
|
-
hasCustomAnchor,
|
|
753
|
-
anchorTo,
|
|
754
|
-
onCustomAnchorAdd: React.useCallback(() => setHasCustomAnchor(true), []),
|
|
755
|
-
onCustomAnchorRemove: React.useCallback(() => setHasCustomAnchor(false), []),
|
|
756
|
-
keepChildrenMounted,
|
|
757
|
-
} satisfies PopoverContextValue
|
|
758
|
-
|
|
759
|
-
// // debug if changing too often
|
|
760
|
-
// if (process.env.NODE_ENV === 'development') {
|
|
761
|
-
// Object.keys(popoverContext).forEach((key) => {
|
|
762
|
-
// React.useEffect(
|
|
763
|
-
// () => console.log(`changed`, key, popoverContext[key]),
|
|
764
|
-
// [popoverContext[key]]
|
|
765
|
-
// )
|
|
766
|
-
// })
|
|
767
|
-
// }
|
|
768
|
-
|
|
769
|
-
const memoizedChildren = React.useMemo(() => {
|
|
770
|
-
return (
|
|
771
|
-
<PopoverContext.Provider scope={scope} {...popoverContext}>
|
|
772
|
-
<PopoverSheetController context={popoverContext} onOpenChange={setOpen}>
|
|
773
|
-
{children}
|
|
774
|
-
</PopoverSheetController>
|
|
775
|
-
</PopoverContext.Provider>
|
|
776
|
-
)
|
|
777
|
-
}, [scope, setOpen, children, ...Object.values(popoverContext)])
|
|
1052
|
+
const contentId = React.useId()
|
|
1053
|
+
|
|
1054
|
+
const onOpenToggle = useEvent(() => {
|
|
1055
|
+
if (open && isAdapted) {
|
|
1056
|
+
return
|
|
1057
|
+
}
|
|
1058
|
+
setOpen(!open)
|
|
1059
|
+
})
|
|
1060
|
+
|
|
1061
|
+
const onCustomAnchorAdd = React.useCallback(() => setHasCustomAnchor(true), [])
|
|
1062
|
+
const onCustomAnchorRemove = React.useCallback(() => setHasCustomAnchor(false), [])
|
|
778
1063
|
|
|
779
1064
|
const contents = (
|
|
780
1065
|
<Popper open={open} passThrough={isAdapted} scope={scope} stayInFrame {...restProps}>
|
|
781
|
-
|
|
1066
|
+
<PopoverContextProvider
|
|
1067
|
+
scope={scope}
|
|
1068
|
+
open={open}
|
|
1069
|
+
onOpenChange={handleOpenChange}
|
|
1070
|
+
onOpenToggle={onOpenToggle}
|
|
1071
|
+
triggerRef={triggerRef}
|
|
1072
|
+
id={id}
|
|
1073
|
+
contentId={contentId}
|
|
1074
|
+
hasCustomAnchor={hasCustomAnchor}
|
|
1075
|
+
onCustomAnchorAdd={onCustomAnchorAdd}
|
|
1076
|
+
onCustomAnchorRemove={onCustomAnchorRemove}
|
|
1077
|
+
anchorTo={anchorTo}
|
|
1078
|
+
adaptScope={adaptScope}
|
|
1079
|
+
breakpointActive={isAdapted}
|
|
1080
|
+
keepChildrenMounted={keepChildrenMounted}
|
|
1081
|
+
disableDismissable={disableDismissable}
|
|
1082
|
+
hoverable={hoverable}
|
|
1083
|
+
>
|
|
1084
|
+
<PopoverSheetController onOpenChange={setOpen} open={open} scope={scope}>
|
|
1085
|
+
{children}
|
|
1086
|
+
</PopoverSheetController>
|
|
1087
|
+
</PopoverContextProvider>
|
|
782
1088
|
</Popper>
|
|
783
1089
|
)
|
|
784
1090
|
|
|
785
|
-
|
|
1091
|
+
let result = (
|
|
786
1092
|
<>
|
|
787
1093
|
{isWeb ? (
|
|
788
1094
|
<FloatingOverrideContext.Provider value={floatingContext}>
|
|
@@ -793,6 +1099,16 @@ const PopoverInner = React.forwardRef<
|
|
|
793
1099
|
)}
|
|
794
1100
|
</>
|
|
795
1101
|
)
|
|
1102
|
+
|
|
1103
|
+
if (zIndex !== undefined) {
|
|
1104
|
+
return (
|
|
1105
|
+
<PopoverZIndexContext.Provider value={zIndex}>
|
|
1106
|
+
{result}
|
|
1107
|
+
</PopoverZIndexContext.Provider>
|
|
1108
|
+
)
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
return result
|
|
796
1112
|
})
|
|
797
1113
|
|
|
798
1114
|
/* -----------------------------------------------------------------------------------------------*/
|
|
@@ -802,25 +1118,28 @@ function getState(open: boolean) {
|
|
|
802
1118
|
}
|
|
803
1119
|
|
|
804
1120
|
const PopoverSheetController = ({
|
|
805
|
-
|
|
1121
|
+
open,
|
|
1122
|
+
scope,
|
|
806
1123
|
...props
|
|
807
1124
|
}: {
|
|
808
|
-
|
|
1125
|
+
open: boolean
|
|
1126
|
+
scope?: string
|
|
809
1127
|
children: React.ReactNode
|
|
810
1128
|
onOpenChange: React.Dispatch<React.SetStateAction<boolean>>
|
|
811
1129
|
}) => {
|
|
812
|
-
const
|
|
813
|
-
const
|
|
1130
|
+
const context = usePopoverContext(scope)
|
|
1131
|
+
const showSheet = useShowPopoverSheet(context, open)
|
|
1132
|
+
const breakpointActive = context?.breakpointActive
|
|
814
1133
|
const getShowSheet = useGet(showSheet)
|
|
815
1134
|
|
|
816
1135
|
return (
|
|
817
1136
|
<SheetController
|
|
818
|
-
onOpenChange={(val) => {
|
|
1137
|
+
onOpenChange={(val: boolean) => {
|
|
819
1138
|
if (getShowSheet()) {
|
|
820
1139
|
props.onOpenChange?.(val)
|
|
821
1140
|
}
|
|
822
1141
|
}}
|
|
823
|
-
open={
|
|
1142
|
+
open={open}
|
|
824
1143
|
hidden={!breakpointActive}
|
|
825
1144
|
>
|
|
826
1145
|
{props.children}
|
|
@@ -828,7 +1147,7 @@ const PopoverSheetController = ({
|
|
|
828
1147
|
)
|
|
829
1148
|
}
|
|
830
1149
|
|
|
831
|
-
const useShowPopoverSheet = (context: PopoverContextValue) => {
|
|
1150
|
+
const useShowPopoverSheet = (context: PopoverContextValue, open: boolean) => {
|
|
832
1151
|
const isAdapted = useAdaptIsActive(context.adaptScope)
|
|
833
|
-
return
|
|
1152
|
+
return open === false ? false : isAdapted
|
|
834
1153
|
}
|