@tamagui/menu 2.0.0-rc.4 → 2.0.0-rc.40
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/Menu.cjs +156 -140
- package/dist/cjs/Menu.native.js +182 -164
- package/dist/cjs/Menu.native.js.map +1 -1
- package/dist/cjs/createNonNativeMenu.cjs +346 -330
- package/dist/cjs/createNonNativeMenu.native.js +359 -352
- package/dist/cjs/createNonNativeMenu.native.js.map +1 -1
- package/dist/cjs/index.cjs +15 -13
- package/dist/cjs/index.native.js +26 -24
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/Menu.mjs +129 -115
- package/dist/esm/Menu.mjs.map +1 -1
- package/dist/esm/Menu.native.js +155 -139
- package/dist/esm/Menu.native.js.map +1 -1
- package/dist/esm/createNonNativeMenu.mjs +317 -303
- package/dist/esm/createNonNativeMenu.mjs.map +1 -1
- package/dist/esm/createNonNativeMenu.native.js +330 -325
- package/dist/esm/createNonNativeMenu.native.js.map +1 -1
- package/dist/esm/index.js +2 -5
- package/dist/esm/index.js.map +1 -6
- package/dist/esm/index.mjs +0 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +0 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/jsx/Menu.mjs +129 -115
- package/dist/jsx/Menu.mjs.map +1 -1
- package/dist/jsx/Menu.native.js +182 -164
- package/dist/jsx/Menu.native.js.map +1 -1
- package/dist/jsx/createNonNativeMenu.mjs +317 -303
- package/dist/jsx/createNonNativeMenu.mjs.map +1 -1
- package/dist/jsx/createNonNativeMenu.native.js +359 -352
- package/dist/jsx/createNonNativeMenu.native.js.map +1 -1
- package/dist/jsx/index.js +2 -5
- package/dist/jsx/index.js.map +1 -6
- package/dist/jsx/index.mjs +0 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +26 -24
- package/dist/jsx/index.native.js.map +1 -1
- package/package.json +12 -14
- package/src/Menu.tsx +11 -3
- package/src/createNonNativeMenu.tsx +220 -290
- package/types/Menu.d.ts +81 -46
- package/types/Menu.d.ts.map +1 -1
- package/types/createNonNativeMenu.d.ts +116 -68
- package/types/createNonNativeMenu.d.ts.map +1 -1
- package/types/index.d.ts +81 -46
- package/types/index.d.ts.map +1 -1
- package/dist/cjs/Menu.js +0 -137
- package/dist/cjs/Menu.js.map +0 -6
- package/dist/cjs/createNonNativeMenu.js +0 -334
- package/dist/cjs/createNonNativeMenu.js.map +0 -6
- package/dist/cjs/index.js +0 -32
- package/dist/cjs/index.js.map +0 -6
- package/dist/esm/Menu.js +0 -119
- package/dist/esm/Menu.js.map +0 -6
- package/dist/esm/createNonNativeMenu.js +0 -325
- package/dist/esm/createNonNativeMenu.js.map +0 -6
- package/dist/jsx/Menu.js +0 -119
- package/dist/jsx/Menu.js.map +0 -6
- package/dist/jsx/createNonNativeMenu.js +0 -325
- package/dist/jsx/createNonNativeMenu.js.map +0 -6
|
@@ -1,5 +1,23 @@
|
|
|
1
|
-
import type BaseMenuTypes from '@tamagui/create-menu'
|
|
2
|
-
import {
|
|
1
|
+
import type * as BaseMenuTypes from '@tamagui/create-menu'
|
|
2
|
+
import {
|
|
3
|
+
type MenuArrowProps as BaseMenuArrowProps,
|
|
4
|
+
type MenuCheckboxItemProps as BaseMenuCheckboxItemProps,
|
|
5
|
+
type MenuContentProps as BaseMenuContentProps,
|
|
6
|
+
type MenuGroupProps as BaseMenuGroupProps,
|
|
7
|
+
type MenuItemIndicatorProps as BaseMenuItemIndicatorProps,
|
|
8
|
+
type MenuItemProps as BaseMenuItemProps,
|
|
9
|
+
type MenuLabelProps as BaseMenuLabelProps,
|
|
10
|
+
type MenuPortalProps as BaseMenuPortalProps,
|
|
11
|
+
type MenuRadioGroupProps as BaseMenuRadioGroupProps,
|
|
12
|
+
type MenuRadioItemProps as BaseMenuRadioItemProps,
|
|
13
|
+
type MenuSeparatorProps as BaseMenuSeparatorProps,
|
|
14
|
+
type MenuSubContentProps as BaseMenuSubContentProps,
|
|
15
|
+
type MenuSubTriggerProps as BaseMenuSubTriggerProps,
|
|
16
|
+
createBaseMenu,
|
|
17
|
+
type CreateBaseMenuProps,
|
|
18
|
+
} from '@tamagui/create-menu'
|
|
19
|
+
import { usePopperContextSlow } from '@tamagui/popper'
|
|
20
|
+
import { ScrollView, type ScrollViewProps } from '@tamagui/scroll-view'
|
|
3
21
|
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
4
22
|
import {
|
|
5
23
|
composeEventHandlers,
|
|
@@ -8,7 +26,9 @@ import {
|
|
|
8
26
|
isAndroid,
|
|
9
27
|
isWeb,
|
|
10
28
|
Slot,
|
|
29
|
+
styled,
|
|
11
30
|
type TamaguiElement,
|
|
31
|
+
useEvent,
|
|
12
32
|
useIsTouchDevice,
|
|
13
33
|
View,
|
|
14
34
|
type ViewProps,
|
|
@@ -27,14 +47,61 @@ export const DROPDOWN_MENU_CONTEXT = 'MenuContext'
|
|
|
27
47
|
|
|
28
48
|
type ScopedProps<P> = P & { scope?: string }
|
|
29
49
|
|
|
50
|
+
type MenuTriggerStateSetter = React.Dispatch<React.SetStateAction<boolean>>
|
|
51
|
+
|
|
30
52
|
type MenuContextValue = {
|
|
31
53
|
triggerId: string
|
|
32
54
|
triggerRef: React.RefObject<TamaguiElement | null>
|
|
33
55
|
contentId: string
|
|
34
|
-
|
|
56
|
+
openRef: React.RefObject<boolean>
|
|
35
57
|
onOpenChange(open: boolean): void
|
|
36
58
|
onOpenToggle(): void
|
|
37
59
|
modal: boolean
|
|
60
|
+
setActiveTrigger(id: string | null): void
|
|
61
|
+
registerTrigger(id: string, setOpen: MenuTriggerStateSetter): void
|
|
62
|
+
unregisterTrigger(id: string): void
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function useMenuTriggerSetup(open: boolean) {
|
|
66
|
+
const triggerStateSettersRef = React.useRef(new Map<string, MenuTriggerStateSetter>())
|
|
67
|
+
const activeTriggerIdRef = React.useRef<string | null>(null)
|
|
68
|
+
|
|
69
|
+
const setActiveTrigger = useEvent((id: string | null) => {
|
|
70
|
+
const prevId = activeTriggerIdRef.current
|
|
71
|
+
if (prevId === id) return
|
|
72
|
+
if (prevId) {
|
|
73
|
+
triggerStateSettersRef.current.get(prevId)?.(false)
|
|
74
|
+
}
|
|
75
|
+
activeTriggerIdRef.current = id
|
|
76
|
+
if (id && open) {
|
|
77
|
+
triggerStateSettersRef.current.get(id)?.(true)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const registerTrigger = useEvent((id: string, setOpenState: MenuTriggerStateSetter) => {
|
|
82
|
+
triggerStateSettersRef.current.set(id, setOpenState)
|
|
83
|
+
setOpenState(activeTriggerIdRef.current === id && open)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const unregisterTrigger = useEvent((id: string) => {
|
|
87
|
+
triggerStateSettersRef.current.delete(id)
|
|
88
|
+
if (activeTriggerIdRef.current === id) {
|
|
89
|
+
activeTriggerIdRef.current = null
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
if (!open) {
|
|
95
|
+
setActiveTrigger(null)
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
const activeId = activeTriggerIdRef.current
|
|
99
|
+
if (activeId) {
|
|
100
|
+
triggerStateSettersRef.current.get(activeId)?.(true)
|
|
101
|
+
}
|
|
102
|
+
}, [open, setActiveTrigger])
|
|
103
|
+
|
|
104
|
+
return { setActiveTrigger, registerTrigger, unregisterTrigger }
|
|
38
105
|
}
|
|
39
106
|
|
|
40
107
|
interface MenuProps extends BaseMenuTypes.MenuProps {
|
|
@@ -46,8 +113,6 @@ interface MenuProps extends BaseMenuTypes.MenuProps {
|
|
|
46
113
|
modal?: boolean
|
|
47
114
|
}
|
|
48
115
|
|
|
49
|
-
type BaseMenu = ReturnType<typeof createBaseMenu>['Menu']
|
|
50
|
-
|
|
51
116
|
/* -------------------------------------------------------------------------------------------------
|
|
52
117
|
* MenuTrigger
|
|
53
118
|
* -----------------------------------------------------------------------------------------------*/
|
|
@@ -60,54 +125,51 @@ interface MenuTriggerProps extends ViewProps {
|
|
|
60
125
|
* MenuPortal
|
|
61
126
|
* -----------------------------------------------------------------------------------------------*/
|
|
62
127
|
|
|
63
|
-
type MenuPortalProps =
|
|
128
|
+
type MenuPortalProps = BaseMenuPortalProps
|
|
64
129
|
|
|
65
130
|
/* -------------------------------------------------------------------------------------------------
|
|
66
131
|
* MenuContent
|
|
67
132
|
* -----------------------------------------------------------------------------------------------*/
|
|
68
133
|
|
|
69
|
-
type MenuContentElement =
|
|
70
|
-
interface MenuContentProps extends Omit<
|
|
71
|
-
React.ComponentPropsWithoutRef<BaseMenu['Content']>,
|
|
72
|
-
'onEntryFocus'
|
|
73
|
-
> {}
|
|
134
|
+
type MenuContentElement = TamaguiElement
|
|
135
|
+
interface MenuContentProps extends Omit<BaseMenuContentProps, 'onEntryFocus'> {}
|
|
74
136
|
|
|
75
137
|
/* -------------------------------------------------------------------------------------------------
|
|
76
138
|
* MenuGroup
|
|
77
139
|
* -----------------------------------------------------------------------------------------------*/
|
|
78
140
|
|
|
79
|
-
type MenuGroupProps =
|
|
141
|
+
type MenuGroupProps = BaseMenuGroupProps
|
|
80
142
|
|
|
81
143
|
/* -------------------------------------------------------------------------------------------------
|
|
82
144
|
* MenuLabel
|
|
83
145
|
* -----------------------------------------------------------------------------------------------*/
|
|
84
146
|
|
|
85
|
-
type MenuLabelProps =
|
|
147
|
+
type MenuLabelProps = BaseMenuLabelProps
|
|
86
148
|
|
|
87
149
|
/* -------------------------------------------------------------------------------------------------
|
|
88
150
|
* MenuItem
|
|
89
151
|
* -----------------------------------------------------------------------------------------------*/
|
|
90
152
|
|
|
91
|
-
type MenuItemProps =
|
|
153
|
+
type MenuItemProps = BaseMenuItemProps
|
|
92
154
|
|
|
93
|
-
type MenuCheckboxItemProps =
|
|
155
|
+
type MenuCheckboxItemProps = BaseMenuCheckboxItemProps
|
|
94
156
|
|
|
95
|
-
type MenuRadioGroupElement =
|
|
96
|
-
type MenuRadioGroupProps =
|
|
97
|
-
type MenuRadioItemProps =
|
|
98
|
-
type MenuItemIndicatorProps =
|
|
157
|
+
type MenuRadioGroupElement = TamaguiElement
|
|
158
|
+
type MenuRadioGroupProps = BaseMenuRadioGroupProps
|
|
159
|
+
type MenuRadioItemProps = BaseMenuRadioItemProps
|
|
160
|
+
type MenuItemIndicatorProps = BaseMenuItemIndicatorProps
|
|
99
161
|
|
|
100
162
|
/* -------------------------------------------------------------------------------------------------
|
|
101
163
|
* MenuSeparator
|
|
102
164
|
* -----------------------------------------------------------------------------------------------*/
|
|
103
165
|
|
|
104
|
-
type MenuSeparatorProps =
|
|
166
|
+
type MenuSeparatorProps = BaseMenuSeparatorProps
|
|
105
167
|
|
|
106
168
|
/* -------------------------------------------------------------------------------------------------
|
|
107
169
|
* MenuArrow
|
|
108
170
|
* -----------------------------------------------------------------------------------------------*/
|
|
109
171
|
|
|
110
|
-
type MenuArrowProps =
|
|
172
|
+
type MenuArrowProps = BaseMenuArrowProps
|
|
111
173
|
|
|
112
174
|
/* -------------------------------------------------------------------------------------------------
|
|
113
175
|
* MenuSub
|
|
@@ -124,14 +186,20 @@ type MenuSubProps = BaseMenuTypes.MenuSubProps & {
|
|
|
124
186
|
* MenuSubTrigger
|
|
125
187
|
* -----------------------------------------------------------------------------------------------*/
|
|
126
188
|
|
|
127
|
-
type MenuSubTriggerProps =
|
|
189
|
+
type MenuSubTriggerProps = BaseMenuSubTriggerProps
|
|
128
190
|
|
|
129
191
|
/* -------------------------------------------------------------------------------------------------
|
|
130
192
|
* MenuSubContent
|
|
131
193
|
* -----------------------------------------------------------------------------------------------*/
|
|
132
194
|
|
|
133
|
-
type MenuSubContentElement =
|
|
134
|
-
type MenuSubContentProps =
|
|
195
|
+
type MenuSubContentElement = TamaguiElement
|
|
196
|
+
type MenuSubContentProps = BaseMenuSubContentProps
|
|
197
|
+
|
|
198
|
+
/* -------------------------------------------------------------------------------------------------
|
|
199
|
+
* MenuScrollView
|
|
200
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
201
|
+
|
|
202
|
+
type MenuScrollViewProps = ScrollViewProps
|
|
135
203
|
|
|
136
204
|
/* -----------------------------------------------------------------------------------------------*/
|
|
137
205
|
|
|
@@ -164,21 +232,30 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
164
232
|
defaultProp: defaultOpen!,
|
|
165
233
|
onChange: onOpenChange,
|
|
166
234
|
})
|
|
235
|
+
const openRef = React.useRef(open)
|
|
236
|
+
openRef.current = open
|
|
237
|
+
const { setActiveTrigger, registerTrigger, unregisterTrigger } =
|
|
238
|
+
useMenuTriggerSetup(open)
|
|
167
239
|
|
|
168
240
|
return (
|
|
169
241
|
<MenuProvider
|
|
170
242
|
scope={scope}
|
|
171
243
|
triggerId={useId()}
|
|
172
|
-
// TODO
|
|
173
244
|
triggerRef={triggerRef}
|
|
174
245
|
contentId={useId()}
|
|
175
|
-
|
|
176
|
-
onOpenChange={
|
|
246
|
+
openRef={openRef}
|
|
247
|
+
onOpenChange={React.useCallback(
|
|
248
|
+
(nextOpen: boolean) => setOpen(nextOpen),
|
|
249
|
+
[setOpen]
|
|
250
|
+
)}
|
|
177
251
|
onOpenToggle={React.useCallback(
|
|
178
252
|
() => setOpen((prevOpen) => !prevOpen),
|
|
179
253
|
[setOpen]
|
|
180
254
|
)}
|
|
181
255
|
modal={modal}
|
|
256
|
+
setActiveTrigger={setActiveTrigger}
|
|
257
|
+
registerTrigger={registerTrigger}
|
|
258
|
+
unregisterTrigger={unregisterTrigger}
|
|
182
259
|
>
|
|
183
260
|
<Menu
|
|
184
261
|
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
@@ -215,8 +292,35 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
215
292
|
...triggerProps
|
|
216
293
|
} = props
|
|
217
294
|
const context = useMenuContext(scope)
|
|
295
|
+
const popperCtx = usePopperContextSlow(scope || DROPDOWN_MENU_CONTEXT)
|
|
218
296
|
const Comp = asChild ? Slot : View
|
|
219
297
|
const isTouchDevice = useIsTouchDevice()
|
|
298
|
+
const triggerElRef = React.useRef<TamaguiElement>(null)
|
|
299
|
+
|
|
300
|
+
// multi-trigger: per-trigger open state
|
|
301
|
+
const triggerId = React.useId()
|
|
302
|
+
const [triggerOpen, setTriggerOpen] = React.useState(false)
|
|
303
|
+
|
|
304
|
+
// extract stable refs so re-registration doesn't happen when context object changes
|
|
305
|
+
const { registerTrigger, unregisterTrigger } = context
|
|
306
|
+
React.useEffect(() => {
|
|
307
|
+
registerTrigger(triggerId, setTriggerOpen)
|
|
308
|
+
return () => unregisterTrigger(triggerId)
|
|
309
|
+
}, [registerTrigger, unregisterTrigger, triggerId])
|
|
310
|
+
|
|
311
|
+
// activate this trigger: set popper reference and update shared triggerRef for close-auto-focus
|
|
312
|
+
const activateSelf = React.useCallback(() => {
|
|
313
|
+
context.setActiveTrigger(triggerId)
|
|
314
|
+
const el = triggerElRef.current
|
|
315
|
+
if (el) {
|
|
316
|
+
// update shared ref so close-auto-focus returns to the active trigger
|
|
317
|
+
context.triggerRef.current = el
|
|
318
|
+
if (el instanceof HTMLElement) {
|
|
319
|
+
popperCtx.refs?.setReference(el)
|
|
320
|
+
requestAnimationFrame(() => popperCtx.update?.())
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}, [context, triggerId, popperCtx])
|
|
220
324
|
|
|
221
325
|
// Use onClick for touch devices to avoid race condition with Dismissable
|
|
222
326
|
// Use onPointerDown for mouse for faster feedback
|
|
@@ -232,12 +336,12 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
232
336
|
role="button"
|
|
233
337
|
id={context.triggerId}
|
|
234
338
|
aria-haspopup="menu"
|
|
235
|
-
aria-expanded={
|
|
236
|
-
aria-controls={
|
|
237
|
-
data-state={
|
|
339
|
+
aria-expanded={triggerOpen}
|
|
340
|
+
aria-controls={triggerOpen ? context.contentId : undefined}
|
|
341
|
+
data-state={triggerOpen ? 'open' : 'closed'}
|
|
238
342
|
data-disabled={disabled ? '' : undefined}
|
|
239
343
|
aria-disabled={disabled || undefined}
|
|
240
|
-
ref={composeRefs(forwardedRef, context.triggerRef)}
|
|
344
|
+
ref={composeRefs(forwardedRef, context.triggerRef, triggerElRef)}
|
|
241
345
|
{...{
|
|
242
346
|
[pressEvent]: composeEventHandlers(
|
|
243
347
|
//@ts-ignore
|
|
@@ -253,10 +357,15 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
253
357
|
event.ctrlKey === true
|
|
254
358
|
)
|
|
255
359
|
return
|
|
360
|
+
if (context.openRef.current) {
|
|
361
|
+
context.setActiveTrigger(null)
|
|
362
|
+
} else {
|
|
363
|
+
activateSelf()
|
|
364
|
+
}
|
|
256
365
|
context.onOpenToggle()
|
|
257
366
|
// prevent trigger focusing when opening
|
|
258
367
|
// this allows the content to be given focus without competition
|
|
259
|
-
if (!context.
|
|
368
|
+
if (!context.openRef.current) event.preventDefault()
|
|
260
369
|
}
|
|
261
370
|
}
|
|
262
371
|
),
|
|
@@ -264,8 +373,18 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
264
373
|
{...(isWeb && {
|
|
265
374
|
onKeyDown: composeEventHandlers(onKeydown, (event) => {
|
|
266
375
|
if (disabled) return
|
|
267
|
-
if (['Enter', ' '].includes(event.key))
|
|
268
|
-
|
|
376
|
+
if (['Enter', ' '].includes(event.key)) {
|
|
377
|
+
if (context.openRef.current) {
|
|
378
|
+
context.setActiveTrigger(null)
|
|
379
|
+
} else {
|
|
380
|
+
activateSelf()
|
|
381
|
+
}
|
|
382
|
+
context.onOpenToggle()
|
|
383
|
+
}
|
|
384
|
+
if (event.key === 'ArrowDown') {
|
|
385
|
+
activateSelf()
|
|
386
|
+
context.onOpenChange(true)
|
|
387
|
+
}
|
|
269
388
|
// prevent keydown from scrolling window / first focused item to execute
|
|
270
389
|
// that keydown (inadvertently closing the menu)
|
|
271
390
|
if (['Enter', ' ', 'ArrowDown'].includes(event.key))
|
|
@@ -328,7 +447,15 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
328
447
|
{...contentProps}
|
|
329
448
|
ref={forwardedRef}
|
|
330
449
|
onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
331
|
-
if (!hasInteractedOutsideRef.current)
|
|
450
|
+
if (!hasInteractedOutsideRef.current) {
|
|
451
|
+
// delay to let React render new components and run their autoFocus effects
|
|
452
|
+
requestAnimationFrame(() => {
|
|
453
|
+
const activeEl = document.activeElement
|
|
454
|
+
if (!activeEl || activeEl === document.body) {
|
|
455
|
+
context.triggerRef.current?.focus()
|
|
456
|
+
}
|
|
457
|
+
})
|
|
458
|
+
}
|
|
332
459
|
hasInteractedOutsideRef.current = false
|
|
333
460
|
// Always prevent auto focus because we either focus manually or want user agent focus
|
|
334
461
|
event.preventDefault()
|
|
@@ -340,7 +467,24 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
340
467
|
const isRightClick = originalEvent.button === 2 || ctrlLeftClick
|
|
341
468
|
if (!context.modal || isRightClick) hasInteractedOutsideRef.current = true
|
|
342
469
|
})}
|
|
343
|
-
{
|
|
470
|
+
style={
|
|
471
|
+
isWeb
|
|
472
|
+
? {
|
|
473
|
+
...(props.style as object),
|
|
474
|
+
...({
|
|
475
|
+
'--tamagui-menu-content-transform-origin':
|
|
476
|
+
'var(--tamagui-popper-transform-origin)',
|
|
477
|
+
'--tamagui-menu-content-available-width':
|
|
478
|
+
'var(--tamagui-popper-available-width)',
|
|
479
|
+
'--tamagui-menu-content-available-height':
|
|
480
|
+
'var(--tamagui-popper-available-height)',
|
|
481
|
+
'--tamagui-menu-trigger-width': 'var(--tamagui-popper-anchor-width)',
|
|
482
|
+
'--tamagui-menu-trigger-height':
|
|
483
|
+
'var(--tamagui-popper-anchor-height)',
|
|
484
|
+
} as React.CSSProperties),
|
|
485
|
+
}
|
|
486
|
+
: props.style
|
|
487
|
+
}
|
|
344
488
|
/>
|
|
345
489
|
)
|
|
346
490
|
}
|
|
@@ -348,214 +492,12 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
348
492
|
|
|
349
493
|
MenuContent.displayName = CONTENT_NAME
|
|
350
494
|
|
|
351
|
-
/* -------------------------------------------------------------------------------------------------
|
|
352
|
-
* MenuGroup
|
|
353
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
354
|
-
|
|
355
|
-
const GROUP_NAME = 'MenuGroup'
|
|
356
|
-
|
|
357
|
-
const MenuGroup = Menu.Group
|
|
358
|
-
|
|
359
|
-
MenuGroup.displayName = GROUP_NAME
|
|
360
|
-
|
|
361
|
-
/* -------------------------------------------------------------------------------------------------
|
|
362
|
-
* MenuLabel
|
|
363
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
364
|
-
|
|
365
|
-
const LABEL_NAME = 'MenuLabel'
|
|
366
|
-
|
|
367
|
-
const MenuLabel = Menu.Label
|
|
368
|
-
|
|
369
|
-
MenuLabel.displayName = LABEL_NAME
|
|
370
|
-
|
|
371
|
-
/* -------------------------------------------------------------------------------------------------
|
|
372
|
-
* MenuItem
|
|
373
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
374
|
-
|
|
375
|
-
const ITEM_NAME = 'MenuItem'
|
|
376
|
-
|
|
377
|
-
const MenuItemFrame = Menu.Item
|
|
378
|
-
|
|
379
|
-
const MenuItem = React.forwardRef<TamaguiElement, ScopedProps<MenuItemProps>>(
|
|
380
|
-
(props, forwardedRef) => {
|
|
381
|
-
const { scope, ...itemProps } = props
|
|
382
|
-
return (
|
|
383
|
-
<MenuItemFrame
|
|
384
|
-
componentName={ITEM_NAME}
|
|
385
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
386
|
-
{...itemProps}
|
|
387
|
-
ref={forwardedRef}
|
|
388
|
-
/>
|
|
389
|
-
)
|
|
390
|
-
}
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
MenuItem.displayName = ITEM_NAME
|
|
394
|
-
|
|
395
|
-
/* -------------------------------------------------------------------------------------------------
|
|
396
|
-
* MenuItemTitle
|
|
397
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
398
|
-
|
|
399
|
-
const ITEM_TITLE_NAME = 'MenuItemTitle'
|
|
400
|
-
const MenuItemTitle = Menu.ItemTitle
|
|
401
|
-
MenuItemTitle.displayName = ITEM_TITLE_NAME
|
|
402
|
-
|
|
403
|
-
/* -------------------------------------------------------------------------------------------------
|
|
404
|
-
* MenuItemSubTitle
|
|
405
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
406
|
-
|
|
407
|
-
const ITEM_SUB_TITLE_NAME = 'MenuItemSubTitle'
|
|
408
|
-
const MenuItemSubTitle = Menu.ItemSubtitle
|
|
409
|
-
MenuItemSubTitle.displayName = ITEM_SUB_TITLE_NAME
|
|
410
|
-
|
|
411
|
-
/* -------------------------------------------------------------------------------------------------
|
|
412
|
-
* MenuItemImage
|
|
413
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
414
|
-
|
|
415
|
-
const ITEM_IMAGE_NAME = 'MenuItemImage'
|
|
416
|
-
const MenuItemImage = Menu.ItemImage
|
|
417
|
-
MenuItemImage.displayName = ITEM_IMAGE_NAME
|
|
418
|
-
|
|
419
|
-
/* -------------------------------------------------------------------------------------------------
|
|
420
|
-
* MenuItemIcon
|
|
421
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
422
|
-
|
|
423
|
-
const ITEM_ICON_NAME = 'MenuItemIcon'
|
|
424
|
-
const MenuItemIcon = Menu.ItemIcon
|
|
425
|
-
MenuItemIcon.displayName = ITEM_ICON_NAME
|
|
426
|
-
/* -------------------------------------------------------------------------------------------------
|
|
427
|
-
* MenuCheckboxItem
|
|
428
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
429
|
-
|
|
430
|
-
const CHECKBOX_ITEM_NAME = 'MenuCheckboxItem'
|
|
431
|
-
|
|
432
|
-
const MenuCheckboxItemFrame = Menu.CheckboxItem
|
|
433
|
-
|
|
434
|
-
const MenuCheckboxItem = React.forwardRef<
|
|
435
|
-
TamaguiElement,
|
|
436
|
-
ScopedProps<MenuCheckboxItemProps>
|
|
437
|
-
>((props, forwardedRef) => {
|
|
438
|
-
const { scope, ...checkboxItemProps } = props
|
|
439
|
-
return (
|
|
440
|
-
<MenuCheckboxItemFrame
|
|
441
|
-
componentName={CHECKBOX_ITEM_NAME}
|
|
442
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
443
|
-
{...checkboxItemProps}
|
|
444
|
-
ref={forwardedRef}
|
|
445
|
-
/>
|
|
446
|
-
)
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME
|
|
450
|
-
|
|
451
|
-
/* -------------------------------------------------------------------------------------------------
|
|
452
|
-
* MenuRadioGroup
|
|
453
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
454
|
-
|
|
455
|
-
const RADIO_GROUP_NAME = 'MenuRadioGroup'
|
|
456
|
-
|
|
457
|
-
const MenuRadioGroup = React.forwardRef<
|
|
458
|
-
MenuRadioGroupElement,
|
|
459
|
-
ScopedProps<MenuRadioGroupProps>
|
|
460
|
-
>((props, forwardedRef) => {
|
|
461
|
-
const { scope, ...radioGroupProps } = props
|
|
462
|
-
return (
|
|
463
|
-
<Menu.RadioGroup
|
|
464
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
465
|
-
{...radioGroupProps}
|
|
466
|
-
ref={forwardedRef}
|
|
467
|
-
/>
|
|
468
|
-
)
|
|
469
|
-
})
|
|
470
|
-
|
|
471
|
-
MenuRadioGroup.displayName = RADIO_GROUP_NAME
|
|
472
|
-
|
|
473
|
-
/* -------------------------------------------------------------------------------------------------
|
|
474
|
-
* MenuRadioItem
|
|
475
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
476
|
-
|
|
477
|
-
const RADIO_ITEM_NAME = 'MenuRadioItem'
|
|
478
|
-
|
|
479
|
-
const MenuRadioItemFrame = Menu.RadioItem
|
|
480
|
-
|
|
481
|
-
const MenuRadioItem = React.forwardRef<TamaguiElement, ScopedProps<MenuRadioItemProps>>(
|
|
482
|
-
(props, forwardedRef) => {
|
|
483
|
-
const { scope, ...radioItemProps } = props
|
|
484
|
-
return (
|
|
485
|
-
// @ts-ignore explanation: deeply nested types typescript limitation
|
|
486
|
-
<MenuRadioItemFrame
|
|
487
|
-
componentName={RADIO_ITEM_NAME}
|
|
488
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
489
|
-
{...radioItemProps}
|
|
490
|
-
ref={forwardedRef}
|
|
491
|
-
/>
|
|
492
|
-
)
|
|
493
|
-
}
|
|
494
|
-
)
|
|
495
|
-
|
|
496
|
-
MenuRadioItem.displayName = RADIO_ITEM_NAME
|
|
497
|
-
|
|
498
|
-
/* -------------------------------------------------------------------------------------------------
|
|
499
|
-
* MenuItemIndicator
|
|
500
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
501
|
-
|
|
502
|
-
const INDICATOR_NAME = 'MenuItemIndicator'
|
|
503
|
-
|
|
504
|
-
const MenuItemIndicatorFrame = Menu.ItemIndicator
|
|
505
|
-
|
|
506
|
-
const MenuItemIndicator = MenuItemIndicatorFrame.styleable<
|
|
507
|
-
ScopedProps<MenuItemIndicatorProps>
|
|
508
|
-
>((props, forwardedRef) => {
|
|
509
|
-
const { scope, ...itemIndicatorProps } = props
|
|
510
|
-
return (
|
|
511
|
-
<MenuItemIndicatorFrame
|
|
512
|
-
componentName={INDICATOR_NAME}
|
|
513
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
514
|
-
{...itemIndicatorProps}
|
|
515
|
-
ref={forwardedRef}
|
|
516
|
-
/>
|
|
517
|
-
)
|
|
518
|
-
})
|
|
519
|
-
|
|
520
|
-
MenuItemIndicator.displayName = INDICATOR_NAME
|
|
521
|
-
|
|
522
|
-
/* -------------------------------------------------------------------------------------------------
|
|
523
|
-
* MenuSeparator
|
|
524
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
525
|
-
|
|
526
|
-
const SEPARATOR_NAME = 'MenuSeparator'
|
|
527
|
-
|
|
528
|
-
const MenuSeparator = Menu.Separator
|
|
529
|
-
|
|
530
|
-
MenuSeparator.displayName = SEPARATOR_NAME
|
|
531
|
-
|
|
532
|
-
/* -------------------------------------------------------------------------------------------------
|
|
533
|
-
* MenuArrow
|
|
534
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
535
|
-
|
|
536
|
-
const ARROW_NAME = 'MenuArrow'
|
|
537
|
-
|
|
538
|
-
const MenuArrow = React.forwardRef<TamaguiElement, ScopedProps<MenuArrowProps>>(
|
|
539
|
-
(props, forwardedRef) => {
|
|
540
|
-
const { scope, ...arrowProps } = props
|
|
541
|
-
return (
|
|
542
|
-
<Menu.Arrow
|
|
543
|
-
componentName={ARROW_NAME}
|
|
544
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
545
|
-
{...arrowProps}
|
|
546
|
-
ref={forwardedRef}
|
|
547
|
-
/>
|
|
548
|
-
)
|
|
549
|
-
}
|
|
550
|
-
)
|
|
551
|
-
|
|
552
|
-
MenuArrow.displayName = ARROW_NAME
|
|
553
|
-
|
|
554
495
|
/* -------------------------------------------------------------------------------------------------
|
|
555
496
|
* MenuSub
|
|
556
497
|
* -----------------------------------------------------------------------------------------------*/
|
|
557
498
|
|
|
558
499
|
const DROPDOWN_MENU_SUB_NAME = 'MenuSub'
|
|
500
|
+
|
|
559
501
|
const MenuSub = (props: ScopedProps<MenuSubProps>) => {
|
|
560
502
|
const { scope, children, open: openProp, onOpenChange, defaultOpen, ...rest } = props
|
|
561
503
|
const [open = false, setOpen] = useControllableState({
|
|
@@ -578,29 +520,6 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
578
520
|
|
|
579
521
|
MenuSub.displayName = DROPDOWN_MENU_SUB_NAME
|
|
580
522
|
|
|
581
|
-
/* -------------------------------------------------------------------------------------------------
|
|
582
|
-
* MenuSubTrigger
|
|
583
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
584
|
-
|
|
585
|
-
const SUB_TRIGGER_NAME = 'MenuSubTrigger'
|
|
586
|
-
|
|
587
|
-
const MenuSubTrigger = View.styleable<ScopedProps<MenuSubTriggerProps>>(
|
|
588
|
-
(props, forwardedRef) => {
|
|
589
|
-
// TODO: having asChild will create a problem, find a fix for that
|
|
590
|
-
const { scope, asChild, ...subTriggerProps } = props
|
|
591
|
-
return (
|
|
592
|
-
<Menu.SubTrigger
|
|
593
|
-
componentName={SUB_TRIGGER_NAME}
|
|
594
|
-
scope={scope || DROPDOWN_MENU_CONTEXT}
|
|
595
|
-
{...subTriggerProps}
|
|
596
|
-
ref={forwardedRef}
|
|
597
|
-
/>
|
|
598
|
-
)
|
|
599
|
-
}
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
MenuSubTrigger.displayName = SUB_TRIGGER_NAME
|
|
603
|
-
|
|
604
523
|
/* -------------------------------------------------------------------------------------------------
|
|
605
524
|
* MenuSubContent
|
|
606
525
|
* -----------------------------------------------------------------------------------------------*/
|
|
@@ -622,8 +541,6 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
622
541
|
isWeb
|
|
623
542
|
? {
|
|
624
543
|
...(props.style as object),
|
|
625
|
-
// re-namespace exposed content custom properties
|
|
626
|
-
// TODO: find a better way to do this, or maybe not do it at all
|
|
627
544
|
...({
|
|
628
545
|
'--tamagui-menu-content-transform-origin':
|
|
629
546
|
'var(--tamagui-popper-transform-origin)',
|
|
@@ -643,34 +560,45 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
643
560
|
|
|
644
561
|
MenuSubContent.displayName = SUB_CONTENT_NAME
|
|
645
562
|
|
|
563
|
+
/* -------------------------------------------------------------------------------------------------
|
|
564
|
+
* MenuScrollView
|
|
565
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
566
|
+
|
|
567
|
+
const MenuScrollView = styled(ScrollView, {
|
|
568
|
+
flexShrink: 1,
|
|
569
|
+
alignSelf: 'stretch',
|
|
570
|
+
showsHorizontalScrollIndicator: false,
|
|
571
|
+
showsVerticalScrollIndicator: false,
|
|
572
|
+
|
|
573
|
+
'$platform-web': {
|
|
574
|
+
maxHeight: 'var(--tamagui-menu-content-available-height)',
|
|
575
|
+
},
|
|
576
|
+
})
|
|
577
|
+
|
|
646
578
|
/* -----------------------------------------------------------------------------------------------*/
|
|
647
579
|
|
|
648
|
-
|
|
649
|
-
const
|
|
650
|
-
const
|
|
651
|
-
const
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
const
|
|
655
|
-
const
|
|
656
|
-
const
|
|
657
|
-
const
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
const
|
|
661
|
-
const
|
|
662
|
-
const
|
|
663
|
-
const
|
|
664
|
-
const ItemTitle = MenuItemTitle
|
|
665
|
-
const ItemSubtitle = MenuItemSubTitle
|
|
666
|
-
const ItemImage = MenuItemImage
|
|
667
|
-
const ItemIcon = MenuItemIcon
|
|
580
|
+
// direct pass-through from base menu (preserves styleable)
|
|
581
|
+
const Group = Menu.Group
|
|
582
|
+
const Label = Menu.Label
|
|
583
|
+
const Item = Menu.Item
|
|
584
|
+
const CheckboxItem = Menu.CheckboxItem
|
|
585
|
+
const RadioGroup = Menu.RadioGroup
|
|
586
|
+
const RadioItem = Menu.RadioItem
|
|
587
|
+
const ItemIndicator = Menu.ItemIndicator
|
|
588
|
+
const Separator = Menu.Separator
|
|
589
|
+
const Arrow = Menu.Arrow
|
|
590
|
+
const SubTrigger = Menu.SubTrigger
|
|
591
|
+
|
|
592
|
+
const ItemTitle = Menu.ItemTitle
|
|
593
|
+
const ItemSubtitle = Menu.ItemSubtitle
|
|
594
|
+
const ItemImage = Menu.ItemImage
|
|
595
|
+
const ItemIcon = Menu.ItemIcon
|
|
668
596
|
|
|
669
597
|
return withStaticProperties(MenuComp, {
|
|
670
|
-
Root,
|
|
671
|
-
Trigger,
|
|
672
|
-
Portal,
|
|
673
|
-
Content,
|
|
598
|
+
Root: MenuComp,
|
|
599
|
+
Trigger: MenuTrigger,
|
|
600
|
+
Portal: MenuPortal,
|
|
601
|
+
Content: MenuContent,
|
|
674
602
|
Group,
|
|
675
603
|
Label,
|
|
676
604
|
Item,
|
|
@@ -680,13 +608,14 @@ export function createNonNativeMenu(params: CreateBaseMenuProps) {
|
|
|
680
608
|
ItemIndicator,
|
|
681
609
|
Separator,
|
|
682
610
|
Arrow,
|
|
683
|
-
Sub,
|
|
611
|
+
Sub: MenuSub,
|
|
684
612
|
SubTrigger,
|
|
685
|
-
SubContent,
|
|
613
|
+
SubContent: MenuSubContent,
|
|
686
614
|
ItemTitle,
|
|
687
615
|
ItemSubtitle,
|
|
688
616
|
ItemImage,
|
|
689
617
|
ItemIcon,
|
|
618
|
+
ScrollView: MenuScrollView,
|
|
690
619
|
})
|
|
691
620
|
}
|
|
692
621
|
|
|
@@ -702,6 +631,7 @@ export type {
|
|
|
702
631
|
MenuProps,
|
|
703
632
|
MenuRadioGroupProps,
|
|
704
633
|
MenuRadioItemProps,
|
|
634
|
+
MenuScrollViewProps,
|
|
705
635
|
MenuSubContentProps,
|
|
706
636
|
MenuSubProps,
|
|
707
637
|
MenuSubTriggerProps,
|