@tamagui/popover 1.1.7 → 1.1.8

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
@@ -2,13 +2,23 @@
2
2
 
3
3
  import '@tamagui/polyfill-dev'
4
4
 
5
+ import type { UseFloatingProps } from '@floating-ui/react-dom-interactions'
6
+ import {
7
+ useDismiss,
8
+ useFloating,
9
+ useInteractions,
10
+ useRole,
11
+ } from '@floating-ui/react-dom-interactions'
5
12
  import { Adapt, useAdaptParent } from '@tamagui/adapt'
6
13
  import { AnimatePresence } from '@tamagui/animate-presence'
7
14
  import { hideOthers } from '@tamagui/aria-hidden'
8
15
  import { useComposedRefs } from '@tamagui/compose-refs'
9
16
  import {
17
+ GestureReponderEvent,
10
18
  MediaQueryKey,
11
19
  SizeTokens,
20
+ Stack,
21
+ TamaguiElement,
12
22
  Theme,
13
23
  composeEventHandlers,
14
24
  isWeb,
@@ -22,9 +32,9 @@ import {
22
32
  import type { Scope } from '@tamagui/create-context'
23
33
  import { createContextScope } from '@tamagui/create-context'
24
34
  import { DismissableProps } from '@tamagui/dismissable'
35
+ import { FloatingOverrideContext } from '@tamagui/floating'
25
36
  import { FocusScope, FocusScopeProps } from '@tamagui/focus-scope'
26
37
  import {
27
- FloatingOverrideContext,
28
38
  Popper,
29
39
  PopperAnchor,
30
40
  PopperArrow,
@@ -39,13 +49,17 @@ import {
39
49
  import { Portal, PortalHost, PortalItem } from '@tamagui/portal'
40
50
  import { RemoveScroll, RemoveScrollProps } from '@tamagui/remove-scroll'
41
51
  import { ControlledSheet, SheetController } from '@tamagui/sheet'
42
- import { YStack, YStackProps } from '@tamagui/stacks'
52
+ import { SizableStack, XStack, YStack, YStackProps, ZStack } from '@tamagui/stacks'
43
53
  import { useControllableState } from '@tamagui/use-controllable-state'
44
54
  import * as React from 'react'
45
- import { Platform, ScrollView, ScrollViewProps, View } from 'react-native'
46
-
47
- import type { UseFloatingProps } from './floating'
48
- import { useDismiss, useFloating, useFocus, useInteractions, useRole } from './floating'
55
+ import { useEffect } from 'react'
56
+ import {
57
+ GestureResponderEvent,
58
+ Platform,
59
+ ScrollView,
60
+ ScrollViewProps,
61
+ View,
62
+ } from 'react-native'
49
63
 
50
64
  const POPOVER_NAME = 'Popover'
51
65
 
@@ -58,7 +72,7 @@ export type PopoverProps = PopperProps & {
58
72
  }
59
73
 
60
74
  type PopoverContextValue = {
61
- triggerRef: React.RefObject<HTMLButtonElement>
75
+ triggerRef: React.RefObject<any>
62
76
  contentId?: string
63
77
  open: boolean
64
78
  onOpenChange(open: boolean): void
@@ -70,6 +84,7 @@ type PopoverContextValue = {
70
84
  sheetBreakpoint: any
71
85
  scopeKey: string
72
86
  popperScope: any
87
+ breakpointActive?: boolean
73
88
  }
74
89
 
75
90
  const [createPopoverContext, createPopoverScopeInternal] = createContextScope(
@@ -183,7 +198,7 @@ export const PopoverContent = React.forwardRef<
183
198
  ...contentModalProps
184
199
  } = props
185
200
  const context = usePopoverInternalContext(CONTENT_NAME, props.__scopePopover)
186
- const contentRef = React.useRef<HTMLDivElement>(null)
201
+ const contentRef = React.useRef<any>(null)
187
202
  const composedRefs = useComposedRefs(forwardedRef, contentRef)
188
203
  const isRightClickOutsideRef = React.useRef(false)
189
204
 
@@ -233,13 +248,13 @@ export const PopoverContent = React.forwardRef<
233
248
 
234
249
  function PopoverContentPortal(props: ScopedProps<PopoverContentTypeProps>) {
235
250
  const themeName = useThemeName()
251
+ const context = usePopoverInternalContext(CONTENT_NAME, props.__scopePopover)
236
252
 
237
253
  // on android we have to re-pass context
238
254
  let contents = props.children
239
255
 
240
256
  if (Platform.OS === 'android') {
241
257
  // ok conditional hooks by platform
242
- const context = usePopoverInternalContext(CONTENT_NAME, props.__scopePopover)
243
258
  const popperContext = usePopperContext(CONTENT_NAME, context.popperScope)
244
259
 
245
260
  contents = (
@@ -252,10 +267,19 @@ function PopoverContentPortal(props: ScopedProps<PopoverContentTypeProps>) {
252
267
  )
253
268
  }
254
269
 
270
+ const zIndex = props.zIndex ?? 1000
271
+
272
+ // Portal the contents and add a transparent bg overlay to handle dismiss on native
255
273
  return (
256
- <Portal zIndex={props.zIndex ?? 1000}>
274
+ <Portal zIndex={zIndex}>
257
275
  <Theme forceClassName name={themeName}>
258
- {contents}
276
+ {!!context.open && !context.breakpointActive && (
277
+ <YStack
278
+ fullscreen
279
+ onPress={composeEventHandlers(props.onPress as any, context.onOpenToggle)}
280
+ />
281
+ )}
282
+ <Stack zIndex={(zIndex as number) + 1}>{contents}</Stack>
259
283
  </Theme>
260
284
  </Portal>
261
285
  )
@@ -309,9 +333,8 @@ const PopoverContentImpl = React.forwardRef<
309
333
  } = props
310
334
  const popperScope = usePopoverScope(__scopePopover)
311
335
  const context = usePopoverInternalContext(CONTENT_NAME, popperScope.__scopePopover)
312
- const showSheet = useShowPopoverSheet(context)
313
336
 
314
- if (showSheet) {
337
+ if (context.breakpointActive) {
315
338
  // unwrap the PopoverScrollView if used, as it will use the SheetScrollView if that exists
316
339
  const childrenWithoutScrollView = React.Children.toArray(children).map((child) => {
317
340
  if (React.isValidElement(child)) {
@@ -330,7 +353,9 @@ const PopoverContentImpl = React.forwardRef<
330
353
  )
331
354
  }
332
355
 
333
- // const handleDismiss = React.useCallback(() => context.onOpenChange(false), [])
356
+ // const handleDismiss = React.useCallback((event: GestureResponderEvent) =>{
357
+ // context.onOpenChange(false);
358
+ // }, [])
334
359
  // <Dismissable
335
360
  // disableOutsidePointerEvents={disableOutsidePointerEvents}
336
361
  // // onInteractOutside={onInteractOutside}
@@ -344,13 +369,13 @@ const PopoverContentImpl = React.forwardRef<
344
369
  <AnimatePresence>
345
370
  {!!context.open && (
346
371
  <PopperContent
347
- key="popper-content"
372
+ key={context.contentId}
348
373
  data-state={getState(context.open)}
349
374
  id={context.contentId}
350
375
  pointerEvents="auto"
376
+ ref={forwardedRef}
351
377
  {...popperScope}
352
378
  {...contentProps}
353
- ref={forwardedRef}
354
379
  >
355
380
  <RemoveScroll
356
381
  enabled={disableRemoveScroll ? false : context.open}
@@ -370,7 +395,7 @@ const PopoverContentImpl = React.forwardRef<
370
395
  onMountAutoFocus={onOpenAutoFocus}
371
396
  onUnmountAutoFocus={onCloseAutoFocus}
372
397
  >
373
- <div style={{ display: 'contents' }}>{children}</div>
398
+ {isWeb ? <div style={{ display: 'contents' }}>{children}</div> : children}
374
399
  </FocusScope>
375
400
  )}
376
401
  </RemoveScroll>
@@ -418,11 +443,6 @@ export type PopoverArrowProps = PopperArrowProps
418
443
 
419
444
  export const PopoverArrow = React.forwardRef<PopoverArrowElement, PopoverArrowProps>(
420
445
  (props: ScopedProps<PopoverArrowProps>, forwardedRef) => {
421
- // we dont show on native and i'm getting an err
422
- if (!isWeb) {
423
- return null
424
- }
425
-
426
446
  const { __scopePopover, ...arrowProps } = props
427
447
  const popperScope = usePopoverScope(__scopePopover)
428
448
  return <PopperArrow {...popperScope} {...arrowProps} ref={forwardedRef} />
@@ -465,7 +485,7 @@ export const Popover = withStaticProperties(
465
485
 
466
486
  const sheetBreakpoint = when
467
487
  const popperScope = usePopoverScope(__scopePopover)
468
- const triggerRef = React.useRef<HTMLButtonElement>(null)
488
+ const triggerRef = React.useRef<TamaguiElement>(null)
469
489
  const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false)
470
490
  const [open, setOpen] = useControllableState({
471
491
  prop: openProp,
@@ -476,6 +496,7 @@ export const Popover = withStaticProperties(
476
496
 
477
497
  const breakpointActive = useSheetBreakpointActive(sheetBreakpoint)
478
498
 
499
+ // Custom floating context to override the Popper on web
479
500
  const useFloatingContext = React.useCallback(
480
501
  (props: UseFloatingProps) => {
481
502
  const floating = useFloating({
@@ -510,6 +531,7 @@ export const Popover = withStaticProperties(
510
531
  contentId: useId(),
511
532
  triggerRef,
512
533
  open,
534
+ breakpointActive,
513
535
  onOpenChange: setOpen,
514
536
  onOpenToggle: useEvent(() => {
515
537
  if (open && breakpointActive) {
@@ -529,20 +551,25 @@ export const Popover = withStaticProperties(
529
551
  // })
530
552
  // }
531
553
 
554
+ const contents = (
555
+ <Popper {...popperScope} stayInFrame {...restProps}>
556
+ <PopoverProviderInternal {...popoverContext}>
557
+ <PopoverSheetController onOpenChange={setOpen} __scopePopover={__scopePopover}>
558
+ {children}
559
+ </PopoverSheetController>
560
+ </PopoverProviderInternal>
561
+ </Popper>
562
+ )
563
+
532
564
  return (
533
565
  <AdaptProvider>
534
- <FloatingOverrideContext.Provider value={useFloatingContext as any}>
535
- <Popper {...popperScope} stayInFrame {...restProps}>
536
- <PopoverProviderInternal {...popoverContext}>
537
- <PopoverSheetController
538
- onOpenChange={setOpen}
539
- __scopePopover={__scopePopover}
540
- >
541
- {children}
542
- </PopoverSheetController>
543
- </PopoverProviderInternal>
544
- </Popper>
545
- </FloatingOverrideContext.Provider>
566
+ {isWeb ? (
567
+ <FloatingOverrideContext.Provider value={useFloatingContext as any}>
568
+ {contents}
569
+ </FloatingOverrideContext.Provider>
570
+ ) : (
571
+ contents
572
+ )}
546
573
  </AdaptProvider>
547
574
  )
548
575
  }) as React.FC<PopoverProps>,
@@ -577,7 +604,7 @@ const PopoverSheetController = (
577
604
  props.__scopePopover
578
605
  )
579
606
  const showSheet = useShowPopoverSheet(context)
580
- const breakpointActive = useSheetBreakpointActive(context.sheetBreakpoint)
607
+ const breakpointActive = context.breakpointActive
581
608
  const getShowSheet = useGet(showSheet)
582
609
  return (
583
610
  <SheetController
@@ -596,14 +623,13 @@ const PopoverSheetController = (
596
623
 
597
624
  const useSheetBreakpointActive = (breakpoint?: MediaQueryKey | null | boolean) => {
598
625
  const media = useMedia()
599
- if (!breakpoint) return false
600
- if (breakpoint === true) return true
626
+ if (typeof breakpoint === 'boolean' || !breakpoint) {
627
+ return !!breakpoint
628
+ }
601
629
  return media[breakpoint]
602
630
  }
603
631
 
604
632
  const useShowPopoverSheet = (context: PopoverContextValue) => {
605
- // for now always show as sheet on native
606
- if (!isWeb) return true
607
633
  const breakpointActive = useSheetBreakpointActive(context.sheetBreakpoint)
608
634
  return context.open === false ? false : breakpointActive
609
635
  }
@@ -1,5 +1,5 @@
1
1
  import '@tamagui/polyfill-dev';
2
- import { SizeTokens } from '@tamagui/core';
2
+ import { SizeTokens, TamaguiElement } from '@tamagui/core';
3
3
  import type { Scope } from '@tamagui/create-context';
4
4
  import { DismissableProps } from '@tamagui/dismissable';
5
5
  import { FocusScopeProps } from '@tamagui/focus-scope';
@@ -14,7 +14,7 @@ export type PopoverProps = PopperProps & {
14
14
  onOpenChange?: (open: boolean) => void;
15
15
  };
16
16
  type PopoverContextValue = {
17
- triggerRef: React.RefObject<HTMLButtonElement>;
17
+ triggerRef: React.RefObject<any>;
18
18
  contentId?: string;
19
19
  open: boolean;
20
20
  onOpenChange(open: boolean): void;
@@ -26,6 +26,7 @@ type PopoverContextValue = {
26
26
  sheetBreakpoint: any;
27
27
  scopeKey: string;
28
28
  popperScope: any;
29
+ breakpointActive?: boolean;
29
30
  };
30
31
  export declare const usePopoverScope: (scope: Scope<any>) => {
31
32
  [__scopeProp: string]: Scope<any>;
@@ -212,7 +213,7 @@ export declare const Popover: React.FC<PopoverProps> & {
212
213
  [x: string]: undefined;
213
214
  }>> & import("@tamagui/core").PseudoProps<Partial<ScrollViewProps & Omit<import("@tamagui/core").StackProps, keyof ScrollViewProps> & Omit<{}, string | number> & {
214
215
  [x: string]: undefined;
215
- }>>, string | number>) & React.RefAttributes<import("@tamagui/core").TamaguiElement>>;
216
+ }>>, string | number>) & React.RefAttributes<TamaguiElement>>;
216
217
  };
217
218
  };
218
219
  export {};
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import * as Floating from './floating';
3
+ export type UseFloatingFn = typeof Floating.useFloating;
4
+ type InferFloatingProps = UseFloatingFn extends (props: infer Props) => any ? Props : never;
5
+ export type UseFloatingProps = InferFloatingProps & {
6
+ sameScrollView?: boolean;
7
+ };
8
+ type InferUseFloatingReturn = ReturnType<UseFloatingFn>;
9
+ export type UseFloatingReturn = InferUseFloatingReturn & {
10
+ context?: any;
11
+ getFloatingProps?: (props: {
12
+ ref: any;
13
+ [key: string]: any;
14
+ }) => any;
15
+ getReferenceProps?: (props: {
16
+ ref: any;
17
+ [key: string]: any;
18
+ }) => any;
19
+ };
20
+ export declare const FloatingOverrideContext: import("react").Context<typeof Floating.useFloating | null>;
21
+ export declare const useFloating: (props: UseFloatingProps) => UseFloatingReturn;
22
+ export {};
23
+ //# sourceMappingURL=useFloating.d.ts.map
@@ -1,18 +0,0 @@
1
- export const useDismiss = () => {}
2
- export const useFloating = () => {
3
- return {
4
- context: {},
5
- reference: () => {},
6
- floating: () => {},
7
- refs: {
8
- floating: {},
9
- reference: {},
10
- },
11
- middlewareData: {},
12
- }
13
- }
14
- export const useFocus = () => {}
15
- export const useInteractions = () => {
16
- return {}
17
- }
18
- export const useRole = () => {}
package/src/floating.ts DELETED
@@ -1,8 +0,0 @@
1
- export {
2
- type UseFloatingProps,
3
- useDismiss,
4
- useFloating,
5
- useFocus,
6
- useInteractions,
7
- useRole,
8
- } from '@floating-ui/react-dom-interactions'