@tamagui/create-menu 2.7.7 → 3.0.0-beta.1093.1
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/createBaseMenu.cjs +1032 -1247
- package/dist/cjs/createBaseMenu.native.cjs +1207 -0
- package/dist/cjs/createBaseMenu.native.js +1149 -1391
- package/dist/cjs/createBaseMenu.native.js.map +1 -1
- package/dist/cjs/createNativeMenu/createNativeMenu.cjs +345 -377
- package/dist/cjs/createNativeMenu/createNativeMenu.native.cjs +438 -0
- package/dist/cjs/createNativeMenu/createNativeMenu.native.js +404 -439
- package/dist/cjs/createNativeMenu/createNativeMenu.native.js.map +1 -1
- package/dist/cjs/createNativeMenu/createNativeMenuTypes.cjs +9 -11
- package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.cjs +18 -0
- package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js +9 -10
- package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js.map +1 -1
- package/dist/cjs/createNativeMenu/utils.cjs +75 -86
- package/dist/cjs/createNativeMenu/utils.native.cjs +106 -0
- package/dist/cjs/createNativeMenu/utils.native.js +81 -92
- package/dist/cjs/createNativeMenu/utils.native.js.map +1 -1
- package/dist/cjs/createNativeMenu/withNativeMenu.cjs +30 -35
- package/dist/cjs/createNativeMenu/withNativeMenu.native.cjs +45 -0
- package/dist/cjs/createNativeMenu/withNativeMenu.native.js +30 -34
- package/dist/cjs/createNativeMenu/withNativeMenu.native.js.map +1 -1
- package/dist/cjs/index.cjs +8 -20
- package/dist/cjs/index.native.cjs +22 -0
- package/dist/cjs/index.native.js +9 -20
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/createBaseMenu.mjs +1021 -1225
- package/dist/esm/createBaseMenu.mjs.map +1 -1
- package/dist/esm/createBaseMenu.native.js +1138 -1370
- package/dist/esm/createBaseMenu.native.js.map +1 -1
- package/dist/esm/createNativeMenu/createNativeMenu.mjs +332 -353
- package/dist/esm/createNativeMenu/createNativeMenu.mjs.map +1 -1
- package/dist/esm/createNativeMenu/createNativeMenu.native.js +392 -417
- package/dist/esm/createNativeMenu/createNativeMenu.native.js.map +1 -1
- package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs +0 -2
- package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js +0 -2
- package/dist/esm/createNativeMenu/utils.mjs +55 -57
- package/dist/esm/createNativeMenu/utils.mjs.map +1 -1
- package/dist/esm/createNativeMenu/utils.native.js +62 -65
- package/dist/esm/createNativeMenu/utils.native.js.map +1 -1
- package/dist/esm/createNativeMenu/withNativeMenu.mjs +18 -17
- package/dist/esm/createNativeMenu/withNativeMenu.mjs.map +1 -1
- package/dist/esm/createNativeMenu/withNativeMenu.native.js +19 -18
- package/dist/esm/createNativeMenu/withNativeMenu.native.js.map +1 -1
- package/dist/esm/index.js +5 -6
- package/dist/esm/index.mjs +5 -6
- package/dist/esm/index.native.js +5 -6
- package/dist/jsx/createBaseMenu.mjs +1021 -1225
- package/dist/jsx/createBaseMenu.mjs.map +1 -1
- package/dist/jsx/createBaseMenu.native.cjs +1207 -0
- package/dist/jsx/createBaseMenu.native.js +1149 -1391
- package/dist/jsx/createBaseMenu.native.js.map +1 -1
- package/dist/jsx/createNativeMenu/createNativeMenu.mjs +332 -353
- package/dist/jsx/createNativeMenu/createNativeMenu.mjs.map +1 -1
- package/dist/jsx/createNativeMenu/createNativeMenu.native.cjs +438 -0
- package/dist/jsx/createNativeMenu/createNativeMenu.native.js +404 -439
- package/dist/jsx/createNativeMenu/createNativeMenu.native.js.map +1 -1
- package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs +0 -2
- package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.cjs +18 -0
- package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js +9 -10
- package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js.map +1 -1
- package/dist/jsx/createNativeMenu/utils.mjs +55 -57
- package/dist/jsx/createNativeMenu/utils.mjs.map +1 -1
- package/dist/jsx/createNativeMenu/utils.native.cjs +106 -0
- package/dist/jsx/createNativeMenu/utils.native.js +81 -92
- package/dist/jsx/createNativeMenu/utils.native.js.map +1 -1
- package/dist/jsx/createNativeMenu/withNativeMenu.mjs +18 -17
- package/dist/jsx/createNativeMenu/withNativeMenu.mjs.map +1 -1
- package/dist/jsx/createNativeMenu/withNativeMenu.native.cjs +45 -0
- package/dist/jsx/createNativeMenu/withNativeMenu.native.js +30 -34
- package/dist/jsx/createNativeMenu/withNativeMenu.native.js.map +1 -1
- package/dist/jsx/index.js +5 -6
- package/dist/jsx/index.mjs +5 -6
- package/dist/jsx/index.native.cjs +22 -0
- package/dist/jsx/index.native.js +9 -20
- package/dist/jsx/index.native.js.map +1 -1
- package/package.json +26 -23
- package/src/createBaseMenu.tsx +214 -232
- package/src/createNativeMenu/createNativeMenuTypes.ts +1 -7
- package/src/createNativeMenu/utils.tsx +6 -6
- package/src/createNativeMenu/withNativeMenu.tsx +8 -2
- package/src/index.tsx +0 -1
- package/types/createBaseMenu.d.ts +36 -124
- package/types/createBaseMenu.d.ts.map +1 -1
- package/types/createNativeMenu/createNativeMenu.d.ts +1 -1
- package/types/createNativeMenu/createNativeMenu.d.ts.map +1 -1
- package/types/createNativeMenu/createNativeMenuTypes.d.ts +1 -7
- package/types/createNativeMenu/createNativeMenuTypes.d.ts.map +1 -1
- package/types/createNativeMenu/utils.d.ts +5 -5
- package/types/createNativeMenu/utils.d.ts.map +1 -1
- package/types/createNativeMenu/withNativeMenu.d.ts.map +1 -1
- package/types/index.d.ts +0 -1
- package/types/index.d.ts.map +1 -1
- package/dist/cjs/MenuPredefined.cjs +0 -191
- package/dist/cjs/MenuPredefined.native.js +0 -194
- package/dist/cjs/MenuPredefined.native.js.map +0 -1
- package/dist/esm/MenuPredefined.mjs +0 -166
- package/dist/esm/MenuPredefined.mjs.map +0 -1
- package/dist/esm/MenuPredefined.native.js +0 -166
- package/dist/esm/MenuPredefined.native.js.map +0 -1
- package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs.map +0 -1
- package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/index.mjs.map +0 -1
- package/dist/esm/index.native.js.map +0 -1
- package/dist/jsx/MenuPredefined.mjs +0 -166
- package/dist/jsx/MenuPredefined.mjs.map +0 -1
- package/dist/jsx/MenuPredefined.native.js +0 -194
- package/dist/jsx/MenuPredefined.native.js.map +0 -1
- package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs.map +0 -1
- package/dist/jsx/index.js.map +0 -1
- package/dist/jsx/index.mjs.map +0 -1
- package/src/MenuPredefined.tsx +0 -204
- package/types/MenuPredefined.d.ts +0 -31
- package/types/MenuPredefined.d.ts.map +0 -1
package/src/createBaseMenu.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createStyledHOC, createRefComponent } from '@tamagui/core'
|
|
1
2
|
import { Animate } from '@tamagui/animate'
|
|
2
3
|
import { AnimatePresence as Presence } from '@tamagui/animate-presence'
|
|
3
4
|
import { createCollection } from '@tamagui/collection'
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
} from '@tamagui/dismissable'
|
|
8
9
|
import { useFocusGuards } from '@tamagui/focus-guard'
|
|
9
10
|
import { FocusScope } from '@tamagui/focus-scope'
|
|
11
|
+
import { Image as TamaguiImage, type ImageProps } from '@tamagui/image'
|
|
10
12
|
import type { PopperContentProps } from '@tamagui/popper'
|
|
11
13
|
import * as PopperPrimitive from '@tamagui/popper'
|
|
12
14
|
import { needsPortalRepropagation, Portal as PortalPrimitive } from '@tamagui/portal'
|
|
@@ -17,6 +19,7 @@ import { useCallbackRef } from '@tamagui/use-callback-ref'
|
|
|
17
19
|
import { useDirection } from '@tamagui/use-direction'
|
|
18
20
|
import type { TextProps } from '@tamagui/web'
|
|
19
21
|
import {
|
|
22
|
+
type GetRef,
|
|
20
23
|
type ViewProps,
|
|
21
24
|
composeEventHandlers,
|
|
22
25
|
composeRefs,
|
|
@@ -34,9 +37,6 @@ import {
|
|
|
34
37
|
import type { TamaguiElement } from '@tamagui/web/types'
|
|
35
38
|
import * as React from 'react'
|
|
36
39
|
import { useId } from 'react'
|
|
37
|
-
import type { Image, ImageProps } from 'react-native'
|
|
38
|
-
|
|
39
|
-
import { MenuPredefined } from './MenuPredefined'
|
|
40
40
|
|
|
41
41
|
type Direction = 'ltr' | 'rtl'
|
|
42
42
|
|
|
@@ -156,7 +156,7 @@ interface MenuRootContentTypeProps extends Omit<
|
|
|
156
156
|
|
|
157
157
|
/* ---------------------------------------------------------------------------------------------- */
|
|
158
158
|
|
|
159
|
-
type MenuContentImplElement =
|
|
159
|
+
type MenuContentImplElement = GetRef<typeof PopperPrimitive.PopperContent>
|
|
160
160
|
type FocusScopeProps = React.ComponentPropsWithoutRef<typeof FocusScope>
|
|
161
161
|
type DismissableLayerProps = React.ComponentPropsWithoutRef<typeof DismissableLayer>
|
|
162
162
|
type MenuContentImplPrivateProps = {
|
|
@@ -175,18 +175,18 @@ type MenuContentImplPrivateProps = {
|
|
|
175
175
|
* (default: false)
|
|
176
176
|
*/
|
|
177
177
|
trapFocus?: FocusScopeProps['trapped']
|
|
178
|
-
|
|
178
|
+
}
|
|
179
|
+
interface MenuContentImplProps
|
|
180
|
+
extends MenuContentImplPrivateProps, Omit<PopperContentProps, 'dir' | 'onPlaced'> {
|
|
179
181
|
/**
|
|
180
182
|
* Whether to disable dismissing the menu when the user scrolls outside of it
|
|
181
183
|
* (default: false, meaning scroll will dismiss on web)
|
|
182
184
|
*/
|
|
183
185
|
disableDismissOnScroll?: boolean
|
|
184
|
-
|
|
185
|
-
interface MenuContentImplProps
|
|
186
|
-
extends MenuContentImplPrivateProps, Omit<PopperContentProps, 'dir' | 'onPlaced'> {
|
|
186
|
+
|
|
187
187
|
/**
|
|
188
188
|
* Event handler called when auto-focusing on close.
|
|
189
|
-
* Can be
|
|
189
|
+
* Can be canceled.
|
|
190
190
|
*/
|
|
191
191
|
onCloseAutoFocus?: FocusScopeProps['onUnmountAutoFocus']
|
|
192
192
|
|
|
@@ -203,7 +203,7 @@ interface MenuContentImplProps
|
|
|
203
203
|
onInteractOutside?: DismissableLayerProps['onInteractOutside']
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
type
|
|
206
|
+
type StyledHOCMenuContentProps = MenuContentImplProps & ViewProps
|
|
207
207
|
|
|
208
208
|
interface MenuGroupProps extends ViewProps {}
|
|
209
209
|
|
|
@@ -211,12 +211,11 @@ interface MenuGroupProps extends ViewProps {}
|
|
|
211
211
|
* MenuLabel
|
|
212
212
|
* -----------------------------------------------------------------------------------------------*/
|
|
213
213
|
|
|
214
|
-
interface MenuLabelProps extends
|
|
214
|
+
interface MenuLabelProps extends TextProps {}
|
|
215
215
|
|
|
216
216
|
type MenuItemElement = MenuItemImplElement
|
|
217
217
|
interface MenuItemProps extends Omit<MenuItemImplProps, 'onSelect'> {
|
|
218
218
|
onSelect?: (event: Event) => void
|
|
219
|
-
unstyled?: boolean
|
|
220
219
|
/**
|
|
221
220
|
* Prevents the menu from closing when this item is selected.
|
|
222
221
|
* Useful for toggle items or multi-select scenarios.
|
|
@@ -229,7 +228,6 @@ type MenuItemImplElement = TamaguiElement
|
|
|
229
228
|
interface MenuItemImplProps extends ViewProps {
|
|
230
229
|
disabled?: boolean
|
|
231
230
|
textValue?: string
|
|
232
|
-
unstyled?: boolean
|
|
233
231
|
}
|
|
234
232
|
|
|
235
233
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -299,7 +297,6 @@ interface MenuItemIndicatorProps extends PrimitiveSpanProps {
|
|
|
299
297
|
* MenuSeparator
|
|
300
298
|
* -----------------------------------------------------------------------------------------------*/
|
|
301
299
|
|
|
302
|
-
// type MenuSeparatorElement = React.ElementRef<typeof Stack>
|
|
303
300
|
interface MenuSeparatorProps extends ViewProps {}
|
|
304
301
|
|
|
305
302
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -308,9 +305,7 @@ interface MenuSeparatorProps extends ViewProps {}
|
|
|
308
305
|
|
|
309
306
|
// type MenuArrowElement = React.ElementRef<typeof PopperPrimitive.PopperArrow>
|
|
310
307
|
type PopperArrowProps = React.ComponentPropsWithoutRef<typeof PopperPrimitive.PopperArrow>
|
|
311
|
-
|
|
312
|
-
unstyled?: boolean
|
|
313
|
-
}
|
|
308
|
+
type MenuArrowProps = PopperArrowProps
|
|
314
309
|
|
|
315
310
|
/* -------------------------------------------------------------------------------------------------
|
|
316
311
|
* MenuSub
|
|
@@ -375,29 +370,11 @@ const { Provider: MenuRootProvider, useStyledContext: useMenuRootContext } =
|
|
|
375
370
|
|
|
376
371
|
const MENU_CONTEXT = 'MenuContext'
|
|
377
372
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
Title?: typeof MenuPredefined.Title
|
|
382
|
-
SubTitle?: typeof MenuPredefined.SubTitle
|
|
383
|
-
Image?: React.ElementType
|
|
384
|
-
Icon?: typeof MenuPredefined.MenuIcon
|
|
385
|
-
Indicator?: typeof MenuPredefined.MenuIndicator
|
|
386
|
-
Separator?: typeof MenuPredefined.MenuSeparator
|
|
387
|
-
Label?: typeof MenuPredefined.MenuLabel
|
|
388
|
-
}
|
|
373
|
+
const MenuImageFrame = styled(TamaguiImage, {
|
|
374
|
+
displayName: 'MenuItemImage',
|
|
375
|
+
})
|
|
389
376
|
|
|
390
|
-
export function createBaseMenu({
|
|
391
|
-
Item: _Item = MenuPredefined.MenuItem,
|
|
392
|
-
Title: _Title = MenuPredefined.Title,
|
|
393
|
-
SubTitle: _SubTitle = MenuPredefined.SubTitle,
|
|
394
|
-
Image: _Image = MenuPredefined.MenuImage,
|
|
395
|
-
Icon: _Icon = MenuPredefined.MenuIcon,
|
|
396
|
-
Indicator: _Indicator = MenuPredefined.MenuIndicator,
|
|
397
|
-
Separator: _Separator = MenuPredefined.MenuSeparator,
|
|
398
|
-
MenuGroup: _MenuGroup = MenuPredefined.MenuGroup,
|
|
399
|
-
Label: _Label = MenuPredefined.MenuLabel,
|
|
400
|
-
}: CreateBaseMenuProps) {
|
|
377
|
+
export function createBaseMenu() {
|
|
401
378
|
const MenuComp = (props: ScopedProps<MenuBaseProps>) => {
|
|
402
379
|
const direction = useDirection(props.dir)
|
|
403
380
|
// default placement: bottom-start for LTR, bottom-end for RTL
|
|
@@ -535,8 +512,10 @@ export function createBaseMenu({
|
|
|
535
512
|
|
|
536
513
|
const PORTAL_NAME = 'MenuPortal'
|
|
537
514
|
|
|
515
|
+
// Menu.Portal is optional, so Content and SubContent read this context with no
|
|
516
|
+
// provider above them: an undefined default makes that a crash
|
|
538
517
|
const { Provider: PortalProvider, useStyledContext: usePortalContext } =
|
|
539
|
-
createStyledContext<PortalContextValue>(
|
|
518
|
+
createStyledContext<PortalContextValue>({}, 'Portal')
|
|
540
519
|
|
|
541
520
|
const MenuPortal = (props: ScopedProps<MenuPortalProps>) => {
|
|
542
521
|
const { scope = MENU_CONTEXT, forceMount, zIndex, children } = props
|
|
@@ -604,11 +583,12 @@ export function createBaseMenu({
|
|
|
604
583
|
createStyledContext<MenuContentContextValue>()
|
|
605
584
|
|
|
606
585
|
const MenuContentFrame = styled(PopperPrimitive.PopperContentFrame, {
|
|
607
|
-
|
|
586
|
+
displayName: CONTENT_NAME,
|
|
608
587
|
})
|
|
609
588
|
|
|
610
|
-
const MenuContent =
|
|
611
|
-
|
|
589
|
+
const MenuContent = createStyledHOC(
|
|
590
|
+
MenuContentFrame,
|
|
591
|
+
(props: ScopedProps<MenuContentProps>, forwardedRef) => {
|
|
612
592
|
const scope = props.scope || MENU_CONTEXT
|
|
613
593
|
const portalContext = usePortalContext(scope)
|
|
614
594
|
const { forceMount = portalContext.forceMount, ...contentProps } = props
|
|
@@ -630,7 +610,7 @@ export function createBaseMenu({
|
|
|
630
610
|
|
|
631
611
|
/* ---------------------------------------------------------------------------------------------- */
|
|
632
612
|
|
|
633
|
-
const MenuRootContentModal =
|
|
613
|
+
const MenuRootContentModal = createRefComponent<
|
|
634
614
|
MenuRootContentTypeElement,
|
|
635
615
|
ScopedProps<MenuRootContentTypeProps>
|
|
636
616
|
>((props, forwardedRef) => {
|
|
@@ -662,7 +642,7 @@ export function createBaseMenu({
|
|
|
662
642
|
// We make sure we don't trigger our `onDismiss` in such case.
|
|
663
643
|
onFocusOutside={composeEventHandlers(
|
|
664
644
|
props.onFocusOutside,
|
|
665
|
-
(event
|
|
645
|
+
(event) => event.cancel(),
|
|
666
646
|
{ checkDefaultPrevented: false }
|
|
667
647
|
)}
|
|
668
648
|
onDismiss={() => context.onOpenChange(false)}
|
|
@@ -670,7 +650,7 @@ export function createBaseMenu({
|
|
|
670
650
|
)
|
|
671
651
|
})
|
|
672
652
|
|
|
673
|
-
const MenuRootContentNonModal =
|
|
653
|
+
const MenuRootContentNonModal = createRefComponent<
|
|
674
654
|
MenuRootContentTypeElement,
|
|
675
655
|
ScopedProps<MenuRootContentTypeProps>
|
|
676
656
|
>((props, forwardedRef) => {
|
|
@@ -689,9 +669,9 @@ export function createBaseMenu({
|
|
|
689
669
|
)
|
|
690
670
|
})
|
|
691
671
|
|
|
692
|
-
const MenuContentImpl =
|
|
672
|
+
const MenuContentImpl = createRefComponent<
|
|
693
673
|
MenuContentImplElement,
|
|
694
|
-
ScopedProps<
|
|
674
|
+
ScopedProps<StyledHOCMenuContentProps>
|
|
695
675
|
>((props, forwardedRef) => {
|
|
696
676
|
const {
|
|
697
677
|
scope = MENU_CONTEXT,
|
|
@@ -708,7 +688,6 @@ export function createBaseMenu({
|
|
|
708
688
|
onDismiss,
|
|
709
689
|
disableOutsideScroll,
|
|
710
690
|
disableDismissOnScroll = false,
|
|
711
|
-
unstyled = process.env.TAMAGUI_HEADLESS === '1',
|
|
712
691
|
...contentProps
|
|
713
692
|
} = props
|
|
714
693
|
|
|
@@ -805,13 +784,13 @@ export function createBaseMenu({
|
|
|
805
784
|
// relative to the viewport. window/document scrolls have `document`
|
|
806
785
|
// as the target, which contains the anchor, so those still dismiss.
|
|
807
786
|
if (anchor && !scrolled.contains(anchor)) return
|
|
808
|
-
|
|
787
|
+
context.onOpenChange(false)
|
|
809
788
|
}
|
|
810
789
|
window.addEventListener('scroll', handleScroll, { capture: true, passive: true })
|
|
811
790
|
return () => {
|
|
812
791
|
window.removeEventListener('scroll', handleScroll, { capture: true })
|
|
813
792
|
}
|
|
814
|
-
}, [disableDismissOnScroll, context.open,
|
|
793
|
+
}, [disableDismissOnScroll, context.open, context.onOpenChange, popperContext.refs])
|
|
815
794
|
|
|
816
795
|
// Make sure the whole tree has focus guards as our `MenuContent` may be
|
|
817
796
|
// the last element in the DOM (beacuse of the `Portal`)
|
|
@@ -832,14 +811,6 @@ export function createBaseMenu({
|
|
|
832
811
|
// tabIndex allows the content to be focusable so that onItemLeave can
|
|
833
812
|
// focus the content frame and properly blur the previously focused item
|
|
834
813
|
tabIndex={-1}
|
|
835
|
-
unstyled={unstyled}
|
|
836
|
-
{...(!unstyled && {
|
|
837
|
-
backgroundColor: '$background',
|
|
838
|
-
borderWidth: 1,
|
|
839
|
-
borderColor: '$borderColor',
|
|
840
|
-
outlineWidth: 0,
|
|
841
|
-
minWidth: 180,
|
|
842
|
-
})}
|
|
843
814
|
aria-orientation="vertical"
|
|
844
815
|
data-state={getOpenState(context.open)}
|
|
845
816
|
data-tamagui-menu-content=""
|
|
@@ -945,7 +916,7 @@ export function createBaseMenu({
|
|
|
945
916
|
onMountAutoFocus={composeEventHandlers(onOpenAutoFocus, (event) => {
|
|
946
917
|
// when opening, explicitly focus the content area only and leave
|
|
947
918
|
// `onEntryFocus` in control of focusing first item
|
|
948
|
-
event.
|
|
919
|
+
event.cancel()
|
|
949
920
|
// contentRef.current doesn't reliably point to the focusable DOM element
|
|
950
921
|
// due to how refs propagate through Tamagui's styled component chain,
|
|
951
922
|
// so we query for the element directly using the data attribute
|
|
@@ -977,7 +948,7 @@ export function createBaseMenu({
|
|
|
977
948
|
// for keyboard users, focus first item for immediate navigation
|
|
978
949
|
// for mouse users, prevent auto-focus to avoid showing focus style
|
|
979
950
|
if (!rootContext.isUsingKeyboardRef.current) {
|
|
980
|
-
event.
|
|
951
|
+
event.cancel()
|
|
981
952
|
}
|
|
982
953
|
})}
|
|
983
954
|
>
|
|
@@ -999,119 +970,118 @@ export function createBaseMenu({
|
|
|
999
970
|
const ITEM_NAME = 'MenuItem'
|
|
1000
971
|
const ITEM_SELECT = 'menu.itemSelect'
|
|
1001
972
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
973
|
+
const MenuItem = createStyledHOC(
|
|
974
|
+
View,
|
|
975
|
+
(props: ScopedProps<MenuItemProps>, forwardedRef) => {
|
|
976
|
+
const {
|
|
977
|
+
disabled = false,
|
|
978
|
+
onSelect,
|
|
979
|
+
preventCloseOnSelect,
|
|
980
|
+
children,
|
|
981
|
+
scope = MENU_CONTEXT,
|
|
982
|
+
// filter out native-only props that shouldn't reach the DOM
|
|
983
|
+
// @ts-ignore
|
|
984
|
+
destructive,
|
|
985
|
+
// @ts-ignore
|
|
986
|
+
hidden,
|
|
987
|
+
// @ts-ignore
|
|
988
|
+
androidIconName,
|
|
989
|
+
...itemProps
|
|
990
|
+
} = props
|
|
991
|
+
const ref = React.useRef<TamaguiElement>(null)
|
|
992
|
+
const rootContext = useMenuRootContext(scope)
|
|
993
|
+
const contentContext = useMenuContentContext(scope)
|
|
994
|
+
const composedRefs = useComposedRefs(forwardedRef, ref)
|
|
995
|
+
const isPointerDownRef = React.useRef(false)
|
|
996
|
+
|
|
997
|
+
const handleSelect = () => {
|
|
998
|
+
const menuItem = ref.current
|
|
999
|
+
if (!disabled && menuItem) {
|
|
1000
|
+
if (isWeb) {
|
|
1001
|
+
const menuItemEl = menuItem as HTMLElement
|
|
1002
|
+
const itemSelectEvent = new CustomEvent(ITEM_SELECT, {
|
|
1003
|
+
bubbles: true,
|
|
1004
|
+
cancelable: true,
|
|
1005
|
+
})
|
|
1006
|
+
menuItemEl.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), {
|
|
1007
|
+
once: true,
|
|
1008
|
+
})
|
|
1009
|
+
dispatchDiscreteCustomEvent(menuItemEl, itemSelectEvent)
|
|
1010
|
+
// close the menu unless preventCloseOnSelect is set or event.preventDefault() was called
|
|
1011
|
+
if (itemSelectEvent.defaultPrevented || preventCloseOnSelect) {
|
|
1012
|
+
isPointerDownRef.current = false
|
|
1013
|
+
} else {
|
|
1014
|
+
rootContext.onClose()
|
|
1015
|
+
}
|
|
1043
1016
|
} else {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if (!preventCloseOnSelect) {
|
|
1051
|
-
rootContext.onClose()
|
|
1017
|
+
// TODO: find a better way to handle this on native
|
|
1018
|
+
onSelect?.({ target: menuItem } as unknown as Event)
|
|
1019
|
+
isPointerDownRef.current = false
|
|
1020
|
+
if (!preventCloseOnSelect) {
|
|
1021
|
+
rootContext.onClose()
|
|
1022
|
+
}
|
|
1052
1023
|
}
|
|
1053
1024
|
}
|
|
1054
1025
|
}
|
|
1055
|
-
}
|
|
1056
1026
|
|
|
1057
|
-
|
|
1027
|
+
const content = typeof children === 'string' ? <Text>{children}</Text> : children
|
|
1058
1028
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
if (!isPointerDownRef.current) event.currentTarget?.click()
|
|
1079
|
-
}
|
|
1080
|
-
})}
|
|
1081
|
-
{...(isWeb
|
|
1082
|
-
? {
|
|
1083
|
-
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
1084
|
-
const isTypingAhead = contentContext.searchRef.current !== ''
|
|
1085
|
-
if (disabled || (isTypingAhead && event.key === ' ')) return
|
|
1086
|
-
if (SELECTION_KEYS.includes(event.key)) {
|
|
1087
|
-
// @ts-ignore
|
|
1088
|
-
event.currentTarget?.click()
|
|
1089
|
-
/**
|
|
1090
|
-
* We prevent default browser behaviour for selection keys as they should trigger
|
|
1091
|
-
* a selection only:
|
|
1092
|
-
* - prevents space from scrolling the page.
|
|
1093
|
-
* - if keydown causes focus to move, prevents keydown from firing on the new target.
|
|
1094
|
-
*/
|
|
1095
|
-
event.preventDefault()
|
|
1096
|
-
}
|
|
1097
|
-
}),
|
|
1029
|
+
return (
|
|
1030
|
+
<MenuItemImpl
|
|
1031
|
+
{...itemProps}
|
|
1032
|
+
scope={scope}
|
|
1033
|
+
// @ts-ignore
|
|
1034
|
+
ref={composedRefs}
|
|
1035
|
+
disabled={disabled}
|
|
1036
|
+
onPress={composeEventHandlers(props.onPress, handleSelect)}
|
|
1037
|
+
onPointerDown={(event) => {
|
|
1038
|
+
props.onPointerDown?.(event)
|
|
1039
|
+
isPointerDownRef.current = true
|
|
1040
|
+
}}
|
|
1041
|
+
onPointerUp={composeEventHandlers(props.onPointerUp, (event) => {
|
|
1042
|
+
// Pointer down can move to a different menu item which should activate it on pointer up.
|
|
1043
|
+
// We dispatch a click for selection to allow composition with click based triggers and to
|
|
1044
|
+
// prevent Firefox from getting stuck in text selection mode when the menu closes.
|
|
1045
|
+
if (isWeb) {
|
|
1046
|
+
// @ts-ignore
|
|
1047
|
+
if (!isPointerDownRef.current) event.currentTarget?.click()
|
|
1098
1048
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1049
|
+
})}
|
|
1050
|
+
{...(isWeb
|
|
1051
|
+
? {
|
|
1052
|
+
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
1053
|
+
const isTypingAhead = contentContext.searchRef.current !== ''
|
|
1054
|
+
if (disabled || (isTypingAhead && event.key === ' ')) return
|
|
1055
|
+
if (SELECTION_KEYS.includes(event.key)) {
|
|
1056
|
+
// @ts-ignore
|
|
1057
|
+
event.currentTarget?.click()
|
|
1058
|
+
/**
|
|
1059
|
+
* We prevent default browser behaviour for selection keys as they should trigger
|
|
1060
|
+
* a selection only:
|
|
1061
|
+
* - prevents space from scrolling the page.
|
|
1062
|
+
* - if keydown causes focus to move, prevents keydown from firing on the new target.
|
|
1063
|
+
*/
|
|
1064
|
+
event.preventDefault()
|
|
1065
|
+
}
|
|
1066
|
+
}),
|
|
1067
|
+
}
|
|
1068
|
+
: {})}
|
|
1069
|
+
>
|
|
1070
|
+
{content}
|
|
1071
|
+
</MenuItemImpl>
|
|
1072
|
+
)
|
|
1073
|
+
}
|
|
1074
|
+
)
|
|
1105
1075
|
|
|
1106
|
-
const MenuItemImpl =
|
|
1076
|
+
const MenuItemImpl = createRefComponent<
|
|
1107
1077
|
MenuItemImplElement,
|
|
1108
1078
|
ScopedProps<MenuItemImplProps>
|
|
1109
1079
|
>((props, forwardedRef) => {
|
|
1110
1080
|
const {
|
|
1111
1081
|
scope = MENU_CONTEXT,
|
|
1082
|
+
className,
|
|
1112
1083
|
disabled = false,
|
|
1113
1084
|
textValue,
|
|
1114
|
-
unstyled = process.env.TAMAGUI_HEADLESS === '1',
|
|
1115
1085
|
...itemProps
|
|
1116
1086
|
} = props
|
|
1117
1087
|
const contentContext = useMenuContentContext(scope)
|
|
@@ -1140,11 +1110,10 @@ export function createBaseMenu({
|
|
|
1140
1110
|
<RovingFocusGroup.Item
|
|
1141
1111
|
asChild
|
|
1142
1112
|
__scopeRovingFocusGroup={scope}
|
|
1143
|
-
|
|
1113
|
+
tabIndex={disabled ? -1 : 0}
|
|
1144
1114
|
>
|
|
1145
|
-
<
|
|
1146
|
-
|
|
1147
|
-
componentName={ITEM_NAME}
|
|
1115
|
+
<View
|
|
1116
|
+
className={`is_${ITEM_NAME} ${className || ''}`.trim()}
|
|
1148
1117
|
role="menuitem"
|
|
1149
1118
|
data-highlighted={isFocused ? '' : undefined}
|
|
1150
1119
|
aria-disabled={disabled || undefined}
|
|
@@ -1195,9 +1164,12 @@ export function createBaseMenu({
|
|
|
1195
1164
|
* MenuItemTitle
|
|
1196
1165
|
* -----------------------------------------------------------------------------------------------*/
|
|
1197
1166
|
const ITEM_TITLE_NAME = 'MenuItemTitle'
|
|
1198
|
-
const MenuItemTitle =
|
|
1199
|
-
|
|
1200
|
-
|
|
1167
|
+
const MenuItemTitle = createStyledHOC(
|
|
1168
|
+
Text,
|
|
1169
|
+
(props: MenuItemTitleProps, forwardedRef) => {
|
|
1170
|
+
return <Text {...props} ref={forwardedRef} />
|
|
1171
|
+
}
|
|
1172
|
+
)
|
|
1201
1173
|
|
|
1202
1174
|
MenuItemTitle.displayName = ITEM_TITLE_NAME
|
|
1203
1175
|
/* ---------------------------------------------------------------------------------------------- */
|
|
@@ -1206,9 +1178,10 @@ export function createBaseMenu({
|
|
|
1206
1178
|
* MenuItemSubTitle
|
|
1207
1179
|
* -----------------------------------------------------------------------------------------------*/
|
|
1208
1180
|
const ITEM_SUB_TITLE_NAME = 'MenuItemSubTitle'
|
|
1209
|
-
const MenuItemSubTitle =
|
|
1210
|
-
|
|
1211
|
-
|
|
1181
|
+
const MenuItemSubTitle = createStyledHOC(
|
|
1182
|
+
Text,
|
|
1183
|
+
(props: MenuItemSubTitleProps, forwardedRef) => {
|
|
1184
|
+
return <Text {...props} ref={forwardedRef} />
|
|
1212
1185
|
}
|
|
1213
1186
|
)
|
|
1214
1187
|
|
|
@@ -1220,19 +1193,19 @@ export function createBaseMenu({
|
|
|
1220
1193
|
* MenuItemImage
|
|
1221
1194
|
* -----------------------------------------------------------------------------------------------*/
|
|
1222
1195
|
const ITEM_IMAGE = 'MenuItemImage'
|
|
1223
|
-
const MenuItemImage =
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1196
|
+
const MenuItemImage = createRefComponent<TamaguiElement, ImageProps>(
|
|
1197
|
+
(props, forwardedRef) => {
|
|
1198
|
+
// filter out native-only props that shouldn't reach the DOM
|
|
1199
|
+
const {
|
|
1200
|
+
// @ts-ignore - native menu ios config
|
|
1201
|
+
ios,
|
|
1202
|
+
// @ts-ignore
|
|
1203
|
+
androidIconName,
|
|
1204
|
+
...rest
|
|
1205
|
+
} = props
|
|
1206
|
+
return <MenuImageFrame {...rest} ref={forwardedRef} />
|
|
1207
|
+
}
|
|
1208
|
+
)
|
|
1236
1209
|
|
|
1237
1210
|
MenuItemImage.displayName = ITEM_IMAGE
|
|
1238
1211
|
|
|
@@ -1243,7 +1216,7 @@ export function createBaseMenu({
|
|
|
1243
1216
|
* -----------------------------------------------------------------------------------------------*/
|
|
1244
1217
|
|
|
1245
1218
|
const ITEM_ICON = 'MenuItemIcon'
|
|
1246
|
-
const MenuItemIcon =
|
|
1219
|
+
const MenuItemIcon = createStyledHOC(View, (props: MenuItemIconProps, forwardedRef) => {
|
|
1247
1220
|
// filter out native-only props that shouldn't reach the DOM
|
|
1248
1221
|
const {
|
|
1249
1222
|
// @ts-ignore
|
|
@@ -1252,11 +1225,9 @@ export function createBaseMenu({
|
|
|
1252
1225
|
android,
|
|
1253
1226
|
// @ts-ignore
|
|
1254
1227
|
androidIconName,
|
|
1255
|
-
// @ts-ignore
|
|
1256
|
-
iosIconName,
|
|
1257
1228
|
...rest
|
|
1258
1229
|
} = props
|
|
1259
|
-
return <
|
|
1230
|
+
return <View {...rest} ref={forwardedRef} />
|
|
1260
1231
|
})
|
|
1261
1232
|
|
|
1262
1233
|
MenuItemIcon.displayName = ITEM_ICON
|
|
@@ -1269,8 +1240,9 @@ export function createBaseMenu({
|
|
|
1269
1240
|
|
|
1270
1241
|
const CHECKBOX_ITEM_NAME = 'MenuCheckboxItem'
|
|
1271
1242
|
|
|
1272
|
-
const MenuCheckboxItem =
|
|
1273
|
-
|
|
1243
|
+
const MenuCheckboxItem = createStyledHOC(
|
|
1244
|
+
View,
|
|
1245
|
+
(props: ScopedProps<MenuCheckboxItemProps>, forwardedRef) => {
|
|
1274
1246
|
const {
|
|
1275
1247
|
checked = false,
|
|
1276
1248
|
onCheckedChange,
|
|
@@ -1280,12 +1252,13 @@ export function createBaseMenu({
|
|
|
1280
1252
|
value,
|
|
1281
1253
|
// @ts-ignore - native menu value change handler
|
|
1282
1254
|
onValueChange,
|
|
1255
|
+
className,
|
|
1283
1256
|
...checkboxItemProps
|
|
1284
1257
|
} = props
|
|
1285
1258
|
return (
|
|
1286
1259
|
<ItemIndicatorProvider scope={scope} checked={checked}>
|
|
1287
1260
|
<MenuItem
|
|
1288
|
-
|
|
1261
|
+
className={`is_${CHECKBOX_ITEM_NAME} ${className || ''}`.trim()}
|
|
1289
1262
|
role={(isWeb ? 'menuitemcheckbox' : 'menuitem') as 'menuitem'}
|
|
1290
1263
|
aria-checked={isIndeterminate(checked) ? 'mixed' : checked}
|
|
1291
1264
|
{...checkboxItemProps}
|
|
@@ -1313,14 +1286,21 @@ export function createBaseMenu({
|
|
|
1313
1286
|
const { Provider: RadioGroupProvider, useStyledContext: useRadioGroupContext } =
|
|
1314
1287
|
createStyledContext<MenuRadioGroupProps>()
|
|
1315
1288
|
|
|
1316
|
-
const MenuRadioGroup =
|
|
1317
|
-
|
|
1318
|
-
|
|
1289
|
+
const MenuRadioGroup = createStyledHOC(
|
|
1290
|
+
View,
|
|
1291
|
+
(props: ScopedProps<MenuRadioGroupProps>, forwardedRef) => {
|
|
1292
|
+
const {
|
|
1293
|
+
value,
|
|
1294
|
+
onValueChange,
|
|
1295
|
+
scope = MENU_CONTEXT,
|
|
1296
|
+
className,
|
|
1297
|
+
...groupProps
|
|
1298
|
+
} = props
|
|
1319
1299
|
const handleValueChange = useCallbackRef(onValueChange)
|
|
1320
1300
|
return (
|
|
1321
1301
|
<RadioGroupProvider scope={scope} value={value} onValueChange={handleValueChange}>
|
|
1322
|
-
<
|
|
1323
|
-
|
|
1302
|
+
<View
|
|
1303
|
+
className={`is_${RADIO_GROUP_NAME} ${className || ''}`.trim()}
|
|
1324
1304
|
{...groupProps}
|
|
1325
1305
|
ref={forwardedRef}
|
|
1326
1306
|
/>
|
|
@@ -1336,15 +1316,16 @@ export function createBaseMenu({
|
|
|
1336
1316
|
|
|
1337
1317
|
const RADIO_ITEM_NAME = 'MenuRadioItem'
|
|
1338
1318
|
|
|
1339
|
-
const MenuRadioItem =
|
|
1340
|
-
|
|
1341
|
-
|
|
1319
|
+
const MenuRadioItem = createStyledHOC(
|
|
1320
|
+
View,
|
|
1321
|
+
(props: ScopedProps<MenuRadioItemProps>, forwardedRef) => {
|
|
1322
|
+
const { value, scope = MENU_CONTEXT, className, ...radioItemProps } = props
|
|
1342
1323
|
const context = useRadioGroupContext(scope)
|
|
1343
1324
|
const checked = value === context.value
|
|
1344
1325
|
return (
|
|
1345
1326
|
<ItemIndicatorProvider scope={scope} checked={checked}>
|
|
1346
1327
|
<MenuItem
|
|
1347
|
-
|
|
1328
|
+
className={`is_${RADIO_ITEM_NAME} ${className || ''}`.trim()}
|
|
1348
1329
|
{...radioItemProps}
|
|
1349
1330
|
scope={scope}
|
|
1350
1331
|
aria-checked={checked}
|
|
@@ -1373,17 +1354,18 @@ export function createBaseMenu({
|
|
|
1373
1354
|
const { Provider: ItemIndicatorProvider, useStyledContext: useItemIndicatorContext } =
|
|
1374
1355
|
createStyledContext<CheckboxContextValue>()
|
|
1375
1356
|
|
|
1376
|
-
const MenuItemIndicator =
|
|
1377
|
-
|
|
1378
|
-
|
|
1357
|
+
const MenuItemIndicator = createStyledHOC(
|
|
1358
|
+
View,
|
|
1359
|
+
(props: ScopedProps<MenuItemIndicatorProps>, forwardedRef) => {
|
|
1360
|
+
const { scope = MENU_CONTEXT, className, forceMount, ...itemIndicatorProps } = props
|
|
1379
1361
|
const indicatorContext = useItemIndicatorContext(scope)
|
|
1380
1362
|
return (
|
|
1381
1363
|
<Presence>
|
|
1382
1364
|
{forceMount ||
|
|
1383
1365
|
isIndeterminate(indicatorContext.checked) ||
|
|
1384
1366
|
indicatorContext.checked === true ? (
|
|
1385
|
-
<
|
|
1386
|
-
|
|
1367
|
+
<View
|
|
1368
|
+
className={`is_${ITEM_INDICATOR_NAME} ${className || ''}`.trim()}
|
|
1387
1369
|
render="span"
|
|
1388
1370
|
{...itemIndicatorProps}
|
|
1389
1371
|
ref={forwardedRef}
|
|
@@ -1401,22 +1383,14 @@ export function createBaseMenu({
|
|
|
1401
1383
|
* MenuArrow
|
|
1402
1384
|
* -----------------------------------------------------------------------------------------------*/
|
|
1403
1385
|
|
|
1404
|
-
// TODO this
|
|
1405
|
-
const MenuArrow =
|
|
1386
|
+
// TODO this wrapped a styled component but it cant flatten anyways so likely fine just need to check
|
|
1387
|
+
const MenuArrow = createRefComponent<TamaguiElement, MenuArrowProps>(
|
|
1406
1388
|
function MenuArrow(props, forwardedRef) {
|
|
1407
|
-
const {
|
|
1408
|
-
scope = MENU_CONTEXT,
|
|
1409
|
-
unstyled = process.env.TAMAGUI_HEADLESS === '1',
|
|
1410
|
-
...rest
|
|
1411
|
-
} = props
|
|
1389
|
+
const { scope = MENU_CONTEXT, className, ...rest } = props
|
|
1412
1390
|
return (
|
|
1413
1391
|
<PopperPrimitive.PopperArrow
|
|
1414
1392
|
scope={scope}
|
|
1415
|
-
|
|
1416
|
-
unstyled={unstyled}
|
|
1417
|
-
{...(!unstyled && {
|
|
1418
|
-
backgroundColor: '$background',
|
|
1419
|
-
})}
|
|
1393
|
+
className={`is_PopperArrow ${className || ''}`.trim()}
|
|
1420
1394
|
{...rest}
|
|
1421
1395
|
ref={forwardedRef}
|
|
1422
1396
|
/>
|
|
@@ -1534,7 +1508,7 @@ export function createBaseMenu({
|
|
|
1534
1508
|
|
|
1535
1509
|
const SUB_TRIGGER_NAME = 'MenuSubTrigger'
|
|
1536
1510
|
|
|
1537
|
-
const MenuSubTrigger =
|
|
1511
|
+
const MenuSubTrigger = createRefComponent<
|
|
1538
1512
|
TamaguiElement,
|
|
1539
1513
|
ScopedProps<MenuSubTriggerProps>
|
|
1540
1514
|
>((props, forwardedRef) => {
|
|
@@ -1567,14 +1541,17 @@ export function createBaseMenu({
|
|
|
1567
1541
|
}, [pointerGraceTimerRef, onPointerGraceIntentChange])
|
|
1568
1542
|
|
|
1569
1543
|
return (
|
|
1570
|
-
<MenuAnchor
|
|
1544
|
+
<MenuAnchor
|
|
1545
|
+
className={`is_${SUB_TRIGGER_NAME}`}
|
|
1546
|
+
asChild="except-style"
|
|
1547
|
+
scope={scope}
|
|
1548
|
+
>
|
|
1571
1549
|
<MenuItemImpl
|
|
1572
1550
|
id={subContext.triggerId}
|
|
1573
1551
|
aria-haspopup="menu"
|
|
1574
1552
|
aria-expanded={context.open}
|
|
1575
1553
|
aria-controls={subContext.contentId}
|
|
1576
1554
|
data-state={getOpenState(context.open)}
|
|
1577
|
-
outlineStyle="none"
|
|
1578
1555
|
{...props}
|
|
1579
1556
|
ref={composeRefs(forwardedRef, subContext.onTriggerChange)}
|
|
1580
1557
|
// This is redundant for mouse users but we cannot determine pointer type from
|
|
@@ -1776,11 +1753,12 @@ export function createBaseMenu({
|
|
|
1776
1753
|
const SUB_CONTENT_NAME = 'MenuSubContent'
|
|
1777
1754
|
|
|
1778
1755
|
const MenuSubContentFrame = styled(PopperPrimitive.PopperContentFrame, {
|
|
1779
|
-
|
|
1756
|
+
displayName: SUB_CONTENT_NAME,
|
|
1780
1757
|
})
|
|
1781
1758
|
|
|
1782
|
-
const MenuSubContent =
|
|
1783
|
-
|
|
1759
|
+
const MenuSubContent = createStyledHOC(
|
|
1760
|
+
MenuSubContentFrame,
|
|
1761
|
+
(props: ScopedProps<MenuSubContentProps>, forwardedRef) => {
|
|
1784
1762
|
const scope = props.scope || MENU_CONTEXT
|
|
1785
1763
|
const portalContext = usePortalContext(scope)
|
|
1786
1764
|
const { forceMount = portalContext.forceMount, ...subContentProps } = props
|
|
@@ -1834,15 +1812,16 @@ export function createBaseMenu({
|
|
|
1834
1812
|
) as HTMLElement | null
|
|
1835
1813
|
;(content || root)?.focus({ preventScroll: true })
|
|
1836
1814
|
}
|
|
1837
|
-
event.
|
|
1815
|
+
event.cancel()
|
|
1838
1816
|
}}
|
|
1839
1817
|
// The menu might close because of focusing another menu item in the parent menu. We
|
|
1840
1818
|
// don't want it to refocus the trigger in that case so we handle trigger focus ourselves.
|
|
1841
|
-
onCloseAutoFocus={(event) => event.
|
|
1819
|
+
onCloseAutoFocus={(event) => event.cancel()}
|
|
1842
1820
|
onFocusOutside={composeEventHandlers(props.onFocusOutside, (event) => {
|
|
1843
1821
|
// We prevent closing when the trigger is focused to avoid triggering a re-open animation
|
|
1844
1822
|
// on pointer interaction.
|
|
1845
|
-
if (event.target !== subContext.trigger)
|
|
1823
|
+
if (event.event?.target !== subContext.trigger)
|
|
1824
|
+
context.onOpenChange(false)
|
|
1846
1825
|
})}
|
|
1847
1826
|
onEscapeKeyDown={composeEventHandlers(props.onEscapeKeyDown, (event) => {
|
|
1848
1827
|
// close only this submenu, not the root menu
|
|
@@ -1850,8 +1829,11 @@ export function createBaseMenu({
|
|
|
1850
1829
|
// return focus to the submenu trigger with focusVisible since this is keyboard navigation
|
|
1851
1830
|
// @ts-ignore focusVisible is a newer API
|
|
1852
1831
|
subContext.trigger?.focus({ focusVisible: true })
|
|
1853
|
-
//
|
|
1854
|
-
event.
|
|
1832
|
+
// we close the submenu ourselves, so veto the layer's dismiss
|
|
1833
|
+
event.cancel()
|
|
1834
|
+
// and still ensure escape doesn't exit fullscreen (cancel no
|
|
1835
|
+
// longer touches the native event)
|
|
1836
|
+
event.event?.preventDefault?.()
|
|
1855
1837
|
})}
|
|
1856
1838
|
{...(isWeb
|
|
1857
1839
|
? {
|
|
@@ -1888,12 +1870,12 @@ export function createBaseMenu({
|
|
|
1888
1870
|
const Anchor = MenuAnchor
|
|
1889
1871
|
const Portal = MenuPortal
|
|
1890
1872
|
const Content = MenuContent
|
|
1891
|
-
const Group =
|
|
1892
|
-
return <
|
|
1873
|
+
const Group = createStyledHOC(View, (props: MenuGroupProps, ref) => {
|
|
1874
|
+
return <View role="group" {...props} ref={ref} />
|
|
1893
1875
|
})
|
|
1894
1876
|
Group.displayName = 'MenuGroup'
|
|
1895
|
-
const Label =
|
|
1896
|
-
return <
|
|
1877
|
+
const Label = createStyledHOC(Text, (props: MenuLabelProps, ref) => {
|
|
1878
|
+
return <Text {...props} ref={ref} />
|
|
1897
1879
|
})
|
|
1898
1880
|
Label.displayName = 'MenuLabel'
|
|
1899
1881
|
const Item = MenuItem
|
|
@@ -1901,8 +1883,8 @@ export function createBaseMenu({
|
|
|
1901
1883
|
const RadioGroup = MenuRadioGroup
|
|
1902
1884
|
const RadioItem = MenuRadioItem
|
|
1903
1885
|
const ItemIndicator = MenuItemIndicator
|
|
1904
|
-
const Separator =
|
|
1905
|
-
return <
|
|
1886
|
+
const Separator = createStyledHOC(View, (props: MenuSeparatorProps, ref) => {
|
|
1887
|
+
return <View role="separator" aria-orientation="horizontal" {...props} ref={ref} />
|
|
1906
1888
|
})
|
|
1907
1889
|
Separator.displayName = 'MenuSeparator'
|
|
1908
1890
|
const Arrow = MenuArrow
|