@tamagui/popover 1.43.2 → 1.43.4

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/src/Popover.tsx CHANGED
@@ -47,6 +47,7 @@ import { Freeze } from 'react-freeze'
47
47
  import { Platform, ScrollView, ScrollViewProps } from 'react-native'
48
48
 
49
49
  import { useFloatingContext } from './useFloatingContext'
50
+
50
51
  // adapted from radix-ui popover
51
52
 
52
53
  export type PopoverProps = PopperProps & {
@@ -148,6 +149,18 @@ export interface PopoverContentTypeProps
148
149
  export const PopoverContent = PopperContentFrame.extractable(
149
150
  React.forwardRef<PopoverContentTypeElement, PopoverContentTypeProps>(
150
151
  function PopoverContent(props: PopoverContentTypeProps, forwardedRef) {
152
+ return (
153
+ <PopoverContentPortal zIndex={props.zIndex}>
154
+ <PopoverContentInner {...props} ref={forwardedRef} />
155
+ </PopoverContentPortal>
156
+ )
157
+ }
158
+ )
159
+ )
160
+
161
+ const PopoverContentInner = React.memo(
162
+ React.forwardRef<PopoverContentTypeElement, PopoverContentTypeProps>(
163
+ (props, forwardedRef) => {
151
164
  const {
152
165
  allowPinchZoom,
153
166
  trapFocus,
@@ -159,6 +172,7 @@ export const PopoverContent = PopperContentFrame.extractable(
159
172
  const contentRef = React.useRef<any>(null)
160
173
  const composedRefs = useComposedRefs(forwardedRef, contentRef)
161
174
  const isRightClickOutsideRef = React.useRef(false)
175
+ const themeName = useThemeName()
162
176
 
163
177
  // aria-hide everything except the content (better supported equivalent to setting aria-modal)
164
178
  React.useEffect(() => {
@@ -167,49 +181,42 @@ export const PopoverContent = PopperContentFrame.extractable(
167
181
  if (content) return hideOthers(content)
168
182
  }, [context.open])
169
183
 
170
- const themeName = useThemeName()
171
184
  return (
172
- <PopoverContentPortal zIndex={zIndex}>
173
- <Stack pointerEvents={context.open ? 'auto' : 'none'}>
174
- <Theme name={themeName}>
175
- <PopoverContentImpl
176
- {...contentImplProps}
177
- disableRemoveScroll={disableRemoveScroll}
178
- ref={composedRefs}
179
- // we make sure we're not trapping once it's been closed
180
- // (closed !== unmounted when animating out)
181
- trapFocus={trapFocus ?? context.open}
182
- disableOutsidePointerEvents
183
- onCloseAutoFocus={composeEventHandlers(
184
- props.onCloseAutoFocus,
185
- (event) => {
186
- event.preventDefault()
187
- if (!isRightClickOutsideRef.current)
188
- context.triggerRef.current?.focus()
189
- }
190
- )}
191
- onPointerDownOutside={composeEventHandlers(
192
- props.onPointerDownOutside,
193
- (event) => {
194
- const originalEvent = event.detail.originalEvent
195
- const ctrlLeftClick =
196
- originalEvent.button === 0 && originalEvent.ctrlKey === true
197
- const isRightClick = originalEvent.button === 2 || ctrlLeftClick
198
- isRightClickOutsideRef.current = isRightClick
199
- },
200
- { checkDefaultPrevented: false }
201
- )}
202
- // When focus is trapped, a `focusout` event may still happen.
203
- // We make sure we don't trigger our `onDismiss` in such case.
204
- onFocusOutside={composeEventHandlers(
205
- props.onFocusOutside,
206
- (event) => event.preventDefault(),
207
- { checkDefaultPrevented: false }
208
- )}
209
- />
210
- </Theme>
211
- </Stack>
212
- </PopoverContentPortal>
185
+ <Stack pointerEvents={context.open ? 'auto' : 'none'}>
186
+ <Theme name={themeName}>
187
+ <PopoverContentImpl
188
+ {...contentImplProps}
189
+ disableRemoveScroll={disableRemoveScroll}
190
+ ref={composedRefs}
191
+ // we make sure we're not trapping once it's been closed
192
+ // (closed !== unmounted when animating out)
193
+ trapFocus={trapFocus ?? context.open}
194
+ disableOutsidePointerEvents
195
+ onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
196
+ event.preventDefault()
197
+ if (!isRightClickOutsideRef.current) context.triggerRef.current?.focus()
198
+ })}
199
+ onPointerDownOutside={composeEventHandlers(
200
+ props.onPointerDownOutside,
201
+ (event) => {
202
+ const originalEvent = event.detail.originalEvent
203
+ const ctrlLeftClick =
204
+ originalEvent.button === 0 && originalEvent.ctrlKey === true
205
+ const isRightClick = originalEvent.button === 2 || ctrlLeftClick
206
+ isRightClickOutsideRef.current = isRightClick
207
+ },
208
+ { checkDefaultPrevented: false }
209
+ )}
210
+ // When focus is trapped, a `focusout` event may still happen.
211
+ // We make sure we don't trigger our `onDismiss` in such case.
212
+ onFocusOutside={composeEventHandlers(
213
+ props.onFocusOutside,
214
+ (event) => event.preventDefault(),
215
+ { checkDefaultPrevented: false }
216
+ )}
217
+ />
218
+ </Theme>
219
+ </Stack>
213
220
  )
214
221
  }
215
222
  )
@@ -230,9 +237,20 @@ function PopoverRepropagateContext(props: {
230
237
  }
231
238
 
232
239
  function PopoverContentPortal(props: PopoverContentTypeProps) {
240
+ const zIndex = props.zIndex ?? 150_000
241
+
242
+ // Portal the contents and add a transparent bg overlay to handle dismiss on native
243
+ return (
244
+ <Portal zIndex={zIndex}>
245
+ <PopoverContentPortalContents {...props} />
246
+ </Portal>
247
+ )
248
+ }
249
+
250
+ const PopoverContentPortalContents = (props: PopoverContentTypeProps) => {
233
251
  const themeName = useThemeName()
234
- const context = usePopoverContext()
235
252
  const popperContext = usePopperContext()
253
+ const context = usePopoverContext()
236
254
 
237
255
  // on android we have to re-pass context
238
256
  let contents = props.children
@@ -245,21 +263,16 @@ function PopoverContentPortal(props: PopoverContentTypeProps) {
245
263
  )
246
264
  }
247
265
 
248
- const zIndex = props.zIndex ?? 150_000
249
-
250
- // Portal the contents and add a transparent bg overlay to handle dismiss on native
251
266
  return (
252
- <Portal zIndex={zIndex}>
253
- <Theme forceClassName name={themeName}>
254
- {!!context.open && !context.breakpointActive && (
255
- <YStack
256
- fullscreen
257
- onPress={composeEventHandlers(props.onPress as any, context.onOpenToggle)}
258
- />
259
- )}
260
- <Stack zIndex={(zIndex as number) + 1}>{contents}</Stack>
261
- </Theme>
262
- </Portal>
267
+ <Theme forceClassName name={themeName}>
268
+ {!!context.open && !context.breakpointActive && (
269
+ <YStack
270
+ fullscreen
271
+ onPress={composeEventHandlers(props.onPress as any, context.onOpenToggle)}
272
+ />
273
+ )}
274
+ {contents}
275
+ </Theme>
263
276
  )
264
277
  }
265
278
 
@@ -309,14 +322,22 @@ const PopoverContentImpl = React.forwardRef<
309
322
  ...contentProps
310
323
  } = props
311
324
  const context = usePopoverContext()
325
+ const { open, keepChildrenMounted } = context
312
326
  const popperContext = usePopperContext()
313
327
  const [isFullyHidden, setIsFullyHidden] = React.useState(!context.open)
328
+ const [hasShownOnce, setHasShownOnce] = React.useState(false)
329
+
330
+ React.useEffect(() => {
331
+ if (!open) {
332
+ setHasShownOnce(true)
333
+ }
334
+ }, [open])
314
335
 
315
- if (context.open && isFullyHidden) {
336
+ if (open && isFullyHidden) {
316
337
  setIsFullyHidden(false)
317
338
  }
318
339
 
319
- if (!context.keepChildrenMounted) {
340
+ if (!keepChildrenMounted) {
320
341
  if (isFullyHidden) {
321
342
  return null
322
343
  }
@@ -327,7 +348,7 @@ const PopoverContentImpl = React.forwardRef<
327
348
  // TODO this should be disabled through context
328
349
  const childrenWithoutScrollView = React.Children.toArray(children).map((child) => {
329
350
  if (React.isValidElement(child)) {
330
- if (child.type === PopoverScrollView) {
351
+ if (child.type === ScrollView) {
331
352
  return child.props.children
332
353
  }
333
354
  }
@@ -360,25 +381,35 @@ const PopoverContentImpl = React.forwardRef<
360
381
  // onDismiss={handleDismiss}
361
382
  // >
362
383
 
384
+ const contents = React.useMemo(() => {
385
+ return isWeb ? <div style={{ display: 'contents' }}>{children}</div> : children
386
+ }, [children])
387
+
388
+ const freeze = isFullyHidden && (hasShownOnce || !keepChildrenMounted)
389
+
363
390
  return (
364
391
  <Animate
365
392
  type="presence"
366
- present={Boolean(context.open)}
367
- keepChildrenMounted={context.keepChildrenMounted}
393
+ present={Boolean(open)}
394
+ keepChildrenMounted={keepChildrenMounted}
368
395
  onExitComplete={() => {
369
396
  setIsFullyHidden(true)
370
397
  }}
371
398
  >
372
- <Freeze freeze={isFullyHidden}>
399
+ <FreezeToLastContents
400
+ // freeze if fully hidden but fallback to last contents
401
+ // if keepChildrenMounted then mount it on the first
402
+ freeze={freeze}
403
+ >
373
404
  <PopperContent
374
405
  key={context.contentId}
375
- data-state={getState(context.open)}
406
+ data-state={getState(open)}
376
407
  id={context.contentId}
377
408
  ref={forwardedRef}
378
409
  {...contentProps}
379
410
  >
380
411
  <RemoveScroll
381
- enabled={disableRemoveScroll ? false : context.open}
412
+ enabled={disableRemoveScroll ? false : open}
382
413
  allowPinchZoom
383
414
  // causes lots of bugs on touch web on site
384
415
  removeScrollBar={false}
@@ -386,25 +417,31 @@ const PopoverContentImpl = React.forwardRef<
386
417
  display: 'contents',
387
418
  }}
388
419
  >
389
- {trapFocus === false ? (
390
- children
391
- ) : (
392
- <FocusScope
393
- loop
394
- trapped={trapFocus ?? context.open}
395
- onMountAutoFocus={onOpenAutoFocus}
396
- onUnmountAutoFocus={onCloseAutoFocus}
397
- >
398
- {isWeb ? <div style={{ display: 'contents' }}>{children}</div> : children}
399
- </FocusScope>
400
- )}
420
+ <FocusScope
421
+ loop
422
+ trapped={trapFocus ?? open}
423
+ onMountAutoFocus={onOpenAutoFocus}
424
+ onUnmountAutoFocus={onCloseAutoFocus}
425
+ >
426
+ {contents}
427
+ </FocusScope>
401
428
  </RemoveScroll>
402
429
  </PopperContent>
403
- </Freeze>
430
+ </FreezeToLastContents>
404
431
  </Animate>
405
432
  )
406
433
  })
407
434
 
435
+ const FreezeToLastContents = (props: { freeze: boolean; children: any }) => {
436
+ const last = React.useRef()
437
+
438
+ if (!props.freeze) {
439
+ last.current = props.children
440
+ }
441
+
442
+ return <Freeze placeholder={last.current} {...props} />
443
+ }
444
+
408
445
  /* -------------------------------------------------------------------------------------------------
409
446
  * PopoverClose
410
447
  * -----------------------------------------------------------------------------------------------*/
@@ -439,14 +476,6 @@ export const PopoverArrow = React.forwardRef<TamaguiElement, PopoverArrowProps>(
439
476
  }
440
477
  )
441
478
 
442
- /* -------------------------------------------------------------------------------------------------
443
- * PopoverScrollView
444
- * -----------------------------------------------------------------------------------------------*/
445
-
446
- const PopoverScrollView = React.forwardRef<ScrollView, ScrollViewProps>((props, ref) => {
447
- return <ScrollView ref={ref} {...props} />
448
- })
449
-
450
479
  /* -------------------------------------------------------------------------------------------------
451
480
  * Popover
452
481
  * -----------------------------------------------------------------------------------------------*/
@@ -539,7 +568,7 @@ export const Popover = withStaticProperties(
539
568
  Content: PopoverContent,
540
569
  Close: PopoverClose,
541
570
  Adapt,
542
- ScrollView: PopoverScrollView,
571
+ ScrollView: ScrollView,
543
572
  Sheet: Sheet.Controlled,
544
573
  }
545
574
  )
@@ -206,7 +206,7 @@ export declare const Popover: React.FC<PopoverProps> & {
206
206
  shouldForwardSpace: boolean;
207
207
  };
208
208
  };
209
- ScrollView: React.ForwardRefExoticComponent<ScrollViewProps & React.RefAttributes<ScrollView>>;
209
+ ScrollView: typeof ScrollView;
210
210
  Sheet: React.FunctionComponent<Omit<import("@tamagui/sheet").SheetProps, "open" | "onOpenChange"> & React.RefAttributes<import("react-native").View>> & {
211
211
  Frame: React.ForwardRefExoticComponent<Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers | "style"> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & {
212
212
  style?: import("@tamagui/core").StyleProp<React.CSSProperties | import("react-native").ViewStyle | (React.CSSProperties & import("react-native").ViewStyle)>;
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../src/Popover.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../src/Popover.tsx"],"names":[],"mappings":"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"}