@tamagui/context-menu 2.7.7 → 3.0.0-beta.643.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/ContextMenu.cjs +152 -166
- package/dist/cjs/ContextMenu.native.cjs +178 -0
- package/dist/cjs/ContextMenu.native.js +157 -170
- package/dist/cjs/ContextMenu.native.js.map +1 -1
- package/dist/cjs/createNonNativeContextMenu.cjs +358 -422
- package/dist/cjs/createNonNativeContextMenu.native.cjs +405 -0
- package/dist/cjs/createNonNativeContextMenu.native.js +380 -443
- package/dist/cjs/createNonNativeContextMenu.native.js.map +1 -1
- package/dist/cjs/index.cjs +15 -29
- package/dist/cjs/index.native.cjs +29 -0
- package/dist/cjs/index.native.js +16 -29
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/ContextMenu.mjs +136 -140
- package/dist/esm/ContextMenu.mjs.map +1 -1
- package/dist/esm/ContextMenu.native.js +141 -145
- package/dist/esm/ContextMenu.native.js.map +1 -1
- package/dist/esm/createNonNativeContextMenu.mjs +342 -398
- package/dist/esm/createNonNativeContextMenu.mjs.map +1 -1
- package/dist/esm/createNonNativeContextMenu.native.js +365 -421
- package/dist/esm/createNonNativeContextMenu.native.js.map +1 -1
- package/dist/esm/index.js +3 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +3 -12
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -12
- package/dist/esm/index.native.js.map +1 -1
- package/dist/jsx/ContextMenu.mjs +136 -140
- package/dist/jsx/ContextMenu.mjs.map +1 -1
- package/dist/jsx/ContextMenu.native.cjs +178 -0
- package/dist/jsx/ContextMenu.native.js +157 -170
- package/dist/jsx/ContextMenu.native.js.map +1 -1
- package/dist/jsx/createNonNativeContextMenu.mjs +342 -398
- package/dist/jsx/createNonNativeContextMenu.mjs.map +1 -1
- package/dist/jsx/createNonNativeContextMenu.native.cjs +405 -0
- package/dist/jsx/createNonNativeContextMenu.native.js +380 -443
- package/dist/jsx/createNonNativeContextMenu.native.js.map +1 -1
- package/dist/jsx/index.js +3 -12
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +3 -12
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.cjs +29 -0
- package/dist/jsx/index.native.js +16 -29
- package/dist/jsx/index.native.js.map +1 -1
- package/package.json +9 -7
- package/src/ContextMenu.tsx +2 -3
- package/src/createNonNativeContextMenu.tsx +131 -104
- package/src/index.tsx +1 -13
- package/types/ContextMenu.d.ts +85 -76
- package/types/ContextMenu.d.ts.map +1 -1
- package/types/createNonNativeContextMenu.d.ts +77 -107
- package/types/createNonNativeContextMenu.d.ts.map +1 -1
- package/types/index.d.ts +84 -74
- package/types/index.d.ts.map +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { createRefComponent } from '@tamagui/compose-refs'
|
|
2
|
+
import type * as BaseMenuTypes from '@tamagui/create-menu'
|
|
3
|
+
import { createBaseMenu } from '@tamagui/create-menu'
|
|
3
4
|
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
4
5
|
import {
|
|
6
|
+
createStyledHOC,
|
|
5
7
|
composeEventHandlers,
|
|
6
8
|
composeRefs,
|
|
7
9
|
createStyledContext,
|
|
@@ -44,6 +46,7 @@ type ContextMenuContextValue = {
|
|
|
44
46
|
|
|
45
47
|
interface ContextMenuProps extends BaseMenuTypes.MenuProps {
|
|
46
48
|
children?: React.ReactNode
|
|
49
|
+
defaultOpen?: boolean
|
|
47
50
|
onOpenChange?(open: boolean, event?: ContextMenuOpenChangeEvent): void
|
|
48
51
|
dir?: Direction
|
|
49
52
|
modal?: boolean
|
|
@@ -55,7 +58,6 @@ interface ContextMenuTriggerProps extends ViewProps {
|
|
|
55
58
|
|
|
56
59
|
type ContextMenuPortalProps = React.ComponentPropsWithoutRef<BaseMenu['Portal']>
|
|
57
60
|
|
|
58
|
-
type ContextMenuContentElement = React.ComponentRef<BaseMenu['Content']>
|
|
59
61
|
interface ContextMenuContentProps extends Omit<
|
|
60
62
|
React.ComponentPropsWithoutRef<BaseMenu['Content']>,
|
|
61
63
|
'onEntryFocus' | 'side' | 'sideOffset' | 'align'
|
|
@@ -85,13 +87,12 @@ interface ContextMenuSubProps extends BaseMenuTypes.MenuSubProps {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
type ContextMenuSubTriggerProps = React.ComponentPropsWithoutRef<BaseMenu['SubTrigger']>
|
|
88
|
-
type ContextMenuSubContentElement = React.ComponentRef<BaseMenu['Content']>
|
|
89
90
|
type ContextMenuSubContentProps = React.ComponentPropsWithoutRef<BaseMenu['SubContent']>
|
|
90
91
|
|
|
91
92
|
/* -----------------------------------------------------------------------------------------------*/
|
|
92
93
|
|
|
93
|
-
export function createNonNativeContextMenu(
|
|
94
|
-
const { Menu } = createBaseMenu(
|
|
94
|
+
export function createNonNativeContextMenu() {
|
|
95
|
+
const { Menu } = createBaseMenu()
|
|
95
96
|
|
|
96
97
|
/* -------------------------------------------------------------------------------------------------
|
|
97
98
|
* ContextMenu
|
|
@@ -103,8 +104,22 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
103
104
|
createStyledContext<ContextMenuContextValue>()
|
|
104
105
|
|
|
105
106
|
const ContextMenuComp = (props: ScopedProps<ContextMenuProps>) => {
|
|
106
|
-
const {
|
|
107
|
-
|
|
107
|
+
const {
|
|
108
|
+
scope,
|
|
109
|
+
children,
|
|
110
|
+
onOpenChange,
|
|
111
|
+
open: openProp,
|
|
112
|
+
defaultOpen,
|
|
113
|
+
dir,
|
|
114
|
+
modal = true,
|
|
115
|
+
...rest
|
|
116
|
+
} = props
|
|
117
|
+
// onOpenChange carries an event a caller can cancel, so it is called from
|
|
118
|
+
// handleOpenChange instead of through useControllableState's onChange
|
|
119
|
+
const [open, setOpen] = useControllableState({
|
|
120
|
+
prop: openProp,
|
|
121
|
+
defaultProp: defaultOpen ?? false,
|
|
122
|
+
})
|
|
108
123
|
const triggerRef = React.useRef<TamaguiElement>(null)
|
|
109
124
|
|
|
110
125
|
const handleOpenChange = React.useCallback(
|
|
@@ -113,7 +128,7 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
113
128
|
if (event?.defaultPrevented) return
|
|
114
129
|
setOpen(open)
|
|
115
130
|
},
|
|
116
|
-
[onOpenChange]
|
|
131
|
+
[onOpenChange, setOpen]
|
|
117
132
|
)
|
|
118
133
|
|
|
119
134
|
return (
|
|
@@ -148,9 +163,18 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
148
163
|
|
|
149
164
|
const TRIGGER_NAME = 'ContextMenuTrigger'
|
|
150
165
|
|
|
151
|
-
const ContextMenuTrigger =
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
const ContextMenuTrigger = createStyledHOC(
|
|
167
|
+
View,
|
|
168
|
+
(props: ScopedProps<ContextMenuTriggerProps>, forwardedRef) => {
|
|
169
|
+
const {
|
|
170
|
+
scope,
|
|
171
|
+
style,
|
|
172
|
+
className,
|
|
173
|
+
disabled = false,
|
|
174
|
+
asChild,
|
|
175
|
+
children,
|
|
176
|
+
...triggerProps
|
|
177
|
+
} = props
|
|
154
178
|
const context = useContextMenuContext(scope)
|
|
155
179
|
const pointRef = React.useRef<Point>({ x: 0, y: 0 })
|
|
156
180
|
const virtualRef = React.useMemo(
|
|
@@ -223,7 +247,7 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
223
247
|
<Menu.Anchor scope={scope || CONTEXTMENU_CONTEXT} virtualRef={virtualRef} />
|
|
224
248
|
<Comp
|
|
225
249
|
render="span"
|
|
226
|
-
|
|
250
|
+
className={`is_${TRIGGER_NAME} ${className || ''}`.trim()}
|
|
227
251
|
id={context.triggerId}
|
|
228
252
|
data-state={context.open ? 'open' : 'closed'}
|
|
229
253
|
data-disabled={disabled ? '' : undefined}
|
|
@@ -319,36 +343,37 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
319
343
|
|
|
320
344
|
const CONTENT_NAME = 'ContextMenuContent'
|
|
321
345
|
|
|
322
|
-
const ContextMenuContent =
|
|
323
|
-
|
|
324
|
-
ScopedProps<ContextMenuContentProps
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const hasInteractedOutsideRef = React.useRef(false)
|
|
346
|
+
const ContextMenuContent = createStyledHOC(
|
|
347
|
+
Menu.Content,
|
|
348
|
+
(props: ScopedProps<ContextMenuContentProps>, forwardedRef) => {
|
|
349
|
+
const { scope, ...contentProps } = props
|
|
350
|
+
const context = useContextMenuContext(scope)
|
|
351
|
+
const hasInteractedOutsideRef = React.useRef(false)
|
|
329
352
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
353
|
+
return (
|
|
354
|
+
<Menu.Content
|
|
355
|
+
id={context.contentId}
|
|
356
|
+
aria-labelledby={context.triggerId}
|
|
357
|
+
scope={scope || CONTEXTMENU_CONTEXT}
|
|
358
|
+
{...contentProps}
|
|
359
|
+
ref={forwardedRef}
|
|
360
|
+
onCloseAutoFocus={composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
361
|
+
if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus()
|
|
362
|
+
hasInteractedOutsideRef.current = false
|
|
363
|
+
event.cancel()
|
|
364
|
+
})}
|
|
365
|
+
onInteractOutside={composeEventHandlers(props.onInteractOutside, (event) => {
|
|
366
|
+
if (event.interaction !== 'pointer' || !event.event) return
|
|
367
|
+
const originalEvent = event.event
|
|
368
|
+
const ctrlLeftClick =
|
|
369
|
+
originalEvent.button === 0 && originalEvent.ctrlKey === true
|
|
370
|
+
const isRightClick = originalEvent.button === 2 || ctrlLeftClick
|
|
371
|
+
if (!context.modal || isRightClick) hasInteractedOutsideRef.current = true
|
|
372
|
+
})}
|
|
373
|
+
/>
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
)
|
|
352
377
|
|
|
353
378
|
ContextMenuContent.displayName = CONTENT_NAME
|
|
354
379
|
|
|
@@ -358,14 +383,14 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
358
383
|
|
|
359
384
|
const ITEM_NAME = 'ContextMenuItem'
|
|
360
385
|
|
|
361
|
-
const ContextMenuItem =
|
|
386
|
+
const ContextMenuItem = createRefComponent<
|
|
362
387
|
TamaguiElement,
|
|
363
388
|
ScopedProps<ContextMenuItemProps>
|
|
364
389
|
>((props, forwardedRef) => {
|
|
365
|
-
const { scope, ...itemProps } = props
|
|
390
|
+
const { scope, className, ...itemProps } = props
|
|
366
391
|
return (
|
|
367
392
|
<Menu.Item
|
|
368
|
-
|
|
393
|
+
className={`is_${ITEM_NAME} ${className || ''}`.trim()}
|
|
369
394
|
scope={scope || CONTEXTMENU_CONTEXT}
|
|
370
395
|
{...itemProps}
|
|
371
396
|
ref={forwardedRef}
|
|
@@ -381,14 +406,14 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
381
406
|
|
|
382
407
|
const CHECKBOX_ITEM_NAME = 'ContextMenuCheckboxItem'
|
|
383
408
|
|
|
384
|
-
const ContextMenuCheckboxItem =
|
|
409
|
+
const ContextMenuCheckboxItem = createRefComponent<
|
|
385
410
|
TamaguiElement,
|
|
386
411
|
ScopedProps<ContextMenuCheckboxItemProps>
|
|
387
412
|
>((props, forwardedRef) => {
|
|
388
|
-
const { scope, ...checkboxItemProps } = props
|
|
413
|
+
const { scope, className, ...checkboxItemProps } = props
|
|
389
414
|
return (
|
|
390
415
|
<Menu.CheckboxItem
|
|
391
|
-
|
|
416
|
+
className={`is_${CHECKBOX_ITEM_NAME} ${className || ''}`.trim()}
|
|
392
417
|
scope={scope || CONTEXTMENU_CONTEXT}
|
|
393
418
|
{...checkboxItemProps}
|
|
394
419
|
ref={forwardedRef}
|
|
@@ -404,7 +429,7 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
404
429
|
|
|
405
430
|
const RADIO_GROUP_NAME = 'ContextMenuRadioGroup'
|
|
406
431
|
|
|
407
|
-
const ContextMenuRadioGroup =
|
|
432
|
+
const ContextMenuRadioGroup = createRefComponent<
|
|
408
433
|
ContextMenuRadioGroupElement,
|
|
409
434
|
ScopedProps<ContextMenuRadioGroupProps>
|
|
410
435
|
>((props, forwardedRef) => {
|
|
@@ -426,14 +451,14 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
426
451
|
|
|
427
452
|
const RADIO_ITEM_NAME = 'ContextMenuRadioItem'
|
|
428
453
|
|
|
429
|
-
const ContextMenuRadioItem =
|
|
454
|
+
const ContextMenuRadioItem = createRefComponent<
|
|
430
455
|
TamaguiElement,
|
|
431
456
|
ScopedProps<ContextMenuRadioItemProps>
|
|
432
457
|
>((props, forwardedRef) => {
|
|
433
|
-
const { scope, ...radioItemProps } = props
|
|
458
|
+
const { scope, className, ...radioItemProps } = props
|
|
434
459
|
return (
|
|
435
460
|
<Menu.RadioItem
|
|
436
|
-
|
|
461
|
+
className={`is_${RADIO_ITEM_NAME} ${className || ''}`.trim()}
|
|
437
462
|
scope={scope || CONTEXTMENU_CONTEXT}
|
|
438
463
|
{...radioItemProps}
|
|
439
464
|
ref={forwardedRef}
|
|
@@ -449,19 +474,20 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
449
474
|
|
|
450
475
|
const INDICATOR_NAME = 'ContextMenuItemIndicator'
|
|
451
476
|
|
|
452
|
-
const ContextMenuItemIndicator =
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
477
|
+
const ContextMenuItemIndicator = createStyledHOC(
|
|
478
|
+
Menu.ItemIndicator,
|
|
479
|
+
(props: ScopedProps<ContextMenuItemIndicatorProps>, forwardedRef) => {
|
|
480
|
+
const { scope, className, ...itemIndicatorProps } = props
|
|
481
|
+
return (
|
|
482
|
+
<Menu.ItemIndicator
|
|
483
|
+
className={`is_${INDICATOR_NAME} ${className || ''}`.trim()}
|
|
484
|
+
scope={scope || CONTEXTMENU_CONTEXT}
|
|
485
|
+
{...itemIndicatorProps}
|
|
486
|
+
ref={forwardedRef}
|
|
487
|
+
/>
|
|
488
|
+
)
|
|
489
|
+
}
|
|
490
|
+
)
|
|
465
491
|
|
|
466
492
|
ContextMenuItemIndicator.displayName = INDICATOR_NAME
|
|
467
493
|
|
|
@@ -499,12 +525,13 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
499
525
|
|
|
500
526
|
const SUB_TRIGGER_NAME = 'ContextMenuSubTrigger'
|
|
501
527
|
|
|
502
|
-
const ContextMenuSubTrigger =
|
|
503
|
-
|
|
504
|
-
|
|
528
|
+
const ContextMenuSubTrigger = createStyledHOC(
|
|
529
|
+
View,
|
|
530
|
+
(props: ScopedProps<ContextMenuSubTriggerProps>, forwardedRef) => {
|
|
531
|
+
const { scope, className, ...subTriggerProps } = props
|
|
505
532
|
return (
|
|
506
533
|
<Menu.SubTrigger
|
|
507
|
-
|
|
534
|
+
className={`is_${SUB_TRIGGER_NAME} ${className || ''}`.trim()}
|
|
508
535
|
scope={scope || CONTEXTMENU_CONTEXT}
|
|
509
536
|
{...subTriggerProps}
|
|
510
537
|
ref={forwardedRef}
|
|
@@ -521,38 +548,38 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
521
548
|
|
|
522
549
|
const SUB_CONTENT_NAME = 'ContextMenuSubContent'
|
|
523
550
|
|
|
524
|
-
const ContextMenuSubContent =
|
|
525
|
-
|
|
526
|
-
ScopedProps<ContextMenuSubContentProps
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
'
|
|
541
|
-
|
|
542
|
-
'
|
|
543
|
-
|
|
544
|
-
'
|
|
545
|
-
|
|
546
|
-
'
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
551
|
+
const ContextMenuSubContent = createStyledHOC(
|
|
552
|
+
Menu.SubContent,
|
|
553
|
+
(props: ScopedProps<ContextMenuSubContentProps>, forwardedRef) => {
|
|
554
|
+
const { scope, ...subContentProps } = props
|
|
555
|
+
return (
|
|
556
|
+
<Menu.SubContent
|
|
557
|
+
scope={scope || CONTEXTMENU_CONTEXT}
|
|
558
|
+
{...subContentProps}
|
|
559
|
+
ref={forwardedRef}
|
|
560
|
+
style={
|
|
561
|
+
isWeb
|
|
562
|
+
? {
|
|
563
|
+
...(props.style as object),
|
|
564
|
+
...({
|
|
565
|
+
'--tamagui-context-menu-content-transform-origin':
|
|
566
|
+
'var(--tamagui-popper-transform-origin)',
|
|
567
|
+
'--tamagui-context-menu-content-available-width':
|
|
568
|
+
'var(--tamagui-popper-available-width)',
|
|
569
|
+
'--tamagui-context-menu-content-available-height':
|
|
570
|
+
'var(--tamagui-popper-available-height)',
|
|
571
|
+
'--tamagui-context-menu-trigger-width':
|
|
572
|
+
'var(--tamagui-popper-anchor-width)',
|
|
573
|
+
'--tamagui-context-menu-trigger-height':
|
|
574
|
+
'var(--tamagui-popper-anchor-height)',
|
|
575
|
+
} as React.CSSProperties),
|
|
576
|
+
}
|
|
577
|
+
: null
|
|
578
|
+
}
|
|
579
|
+
/>
|
|
580
|
+
)
|
|
581
|
+
}
|
|
582
|
+
)
|
|
556
583
|
|
|
557
584
|
ContextMenuSubContent.displayName = SUB_CONTENT_NAME
|
|
558
585
|
|
|
@@ -562,14 +589,14 @@ export function createNonNativeContextMenu(params: CreateBaseMenuProps) {
|
|
|
562
589
|
|
|
563
590
|
const ARROW_NAME = 'ContextMenuArrow'
|
|
564
591
|
|
|
565
|
-
const ContextMenuArrow =
|
|
592
|
+
const ContextMenuArrow = createRefComponent<
|
|
566
593
|
TamaguiElement,
|
|
567
594
|
ScopedProps<ContextMenuArrowProps>
|
|
568
595
|
>((props, forwardedRef) => {
|
|
569
|
-
const { scope, ...arrowProps } = props
|
|
596
|
+
const { scope, className, ...arrowProps } = props
|
|
570
597
|
return (
|
|
571
598
|
<Menu.Arrow
|
|
572
|
-
|
|
599
|
+
className={`is_${ARROW_NAME} ${className || ''}`.trim()}
|
|
573
600
|
scope={scope || CONTEXTMENU_CONTEXT}
|
|
574
601
|
{...arrowProps}
|
|
575
602
|
ref={forwardedRef}
|
package/src/index.tsx
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import '@tamagui/polyfill-dev'
|
|
2
2
|
|
|
3
|
-
import { MenuPredefined } from '@tamagui/create-menu'
|
|
4
|
-
|
|
5
3
|
import { createContextMenu } from './ContextMenu'
|
|
6
4
|
|
|
7
|
-
export const ContextMenu = createContextMenu(
|
|
8
|
-
Icon: MenuPredefined.MenuIcon,
|
|
9
|
-
Image: MenuPredefined.MenuImage,
|
|
10
|
-
Indicator: MenuPredefined.MenuIndicator,
|
|
11
|
-
Item: MenuPredefined.MenuItem,
|
|
12
|
-
Label: MenuPredefined.MenuLabel,
|
|
13
|
-
MenuGroup: MenuPredefined.MenuGroup,
|
|
14
|
-
Separator: MenuPredefined.MenuSeparator,
|
|
15
|
-
SubTitle: MenuPredefined.SubTitle,
|
|
16
|
-
Title: MenuPredefined.Title,
|
|
17
|
-
})
|
|
5
|
+
export const ContextMenu = createContextMenu()
|