@tamagui/create-menu 2.0.0-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.
Files changed (162) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/MenuPredefined.cjs +182 -0
  3. package/dist/cjs/MenuPredefined.js +162 -0
  4. package/dist/cjs/MenuPredefined.js.map +6 -0
  5. package/dist/cjs/MenuPredefined.native.js +185 -0
  6. package/dist/cjs/MenuPredefined.native.js.map +1 -0
  7. package/dist/cjs/createBaseMenu.cjs +927 -0
  8. package/dist/cjs/createBaseMenu.js +724 -0
  9. package/dist/cjs/createBaseMenu.js.map +6 -0
  10. package/dist/cjs/createBaseMenu.native.js +1105 -0
  11. package/dist/cjs/createBaseMenu.native.js.map +1 -0
  12. package/dist/cjs/createNativeMenu/createNativeMenu.cjs +224 -0
  13. package/dist/cjs/createNativeMenu/createNativeMenu.js +172 -0
  14. package/dist/cjs/createNativeMenu/createNativeMenu.js.map +6 -0
  15. package/dist/cjs/createNativeMenu/createNativeMenu.native.js +287 -0
  16. package/dist/cjs/createNativeMenu/createNativeMenu.native.js.map +1 -0
  17. package/dist/cjs/createNativeMenu/createNativeMenuTypes.cjs +16 -0
  18. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js +14 -0
  19. package/dist/cjs/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  20. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js +19 -0
  21. package/dist/cjs/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  22. package/dist/cjs/createNativeMenu/index.cjs +19 -0
  23. package/dist/cjs/createNativeMenu/index.js +16 -0
  24. package/dist/cjs/createNativeMenu/index.js.map +6 -0
  25. package/dist/cjs/createNativeMenu/index.native.js +22 -0
  26. package/dist/cjs/createNativeMenu/index.native.js.map +1 -0
  27. package/dist/cjs/createNativeMenu/utils.cjs +68 -0
  28. package/dist/cjs/createNativeMenu/utils.js +66 -0
  29. package/dist/cjs/createNativeMenu/utils.js.map +6 -0
  30. package/dist/cjs/createNativeMenu/utils.native.js +94 -0
  31. package/dist/cjs/createNativeMenu/utils.native.js.map +1 -0
  32. package/dist/cjs/createNativeMenu/withNativeMenu.cjs +37 -0
  33. package/dist/cjs/createNativeMenu/withNativeMenu.js +30 -0
  34. package/dist/cjs/createNativeMenu/withNativeMenu.js.map +6 -0
  35. package/dist/cjs/createNativeMenu/withNativeMenu.native.js +43 -0
  36. package/dist/cjs/createNativeMenu/withNativeMenu.native.js.map +1 -0
  37. package/dist/cjs/index.cjs +30 -0
  38. package/dist/cjs/index.js +24 -0
  39. package/dist/cjs/index.js.map +6 -0
  40. package/dist/cjs/index.native.js +33 -0
  41. package/dist/cjs/index.native.js.map +1 -0
  42. package/dist/esm/MenuPredefined.js +147 -0
  43. package/dist/esm/MenuPredefined.js.map +6 -0
  44. package/dist/esm/MenuPredefined.mjs +159 -0
  45. package/dist/esm/MenuPredefined.mjs.map +1 -0
  46. package/dist/esm/MenuPredefined.native.js +159 -0
  47. package/dist/esm/MenuPredefined.native.js.map +1 -0
  48. package/dist/esm/createBaseMenu.js +729 -0
  49. package/dist/esm/createBaseMenu.js.map +6 -0
  50. package/dist/esm/createBaseMenu.mjs +893 -0
  51. package/dist/esm/createBaseMenu.mjs.map +1 -0
  52. package/dist/esm/createBaseMenu.native.js +1068 -0
  53. package/dist/esm/createBaseMenu.native.js.map +1 -0
  54. package/dist/esm/createNativeMenu/createNativeMenu.js +150 -0
  55. package/dist/esm/createNativeMenu/createNativeMenu.js.map +6 -0
  56. package/dist/esm/createNativeMenu/createNativeMenu.mjs +190 -0
  57. package/dist/esm/createNativeMenu/createNativeMenu.mjs.map +1 -0
  58. package/dist/esm/createNativeMenu/createNativeMenu.native.js +250 -0
  59. package/dist/esm/createNativeMenu/createNativeMenu.native.js.map +1 -0
  60. package/dist/esm/createNativeMenu/createNativeMenuTypes.js +1 -0
  61. package/dist/esm/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  62. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  63. package/dist/esm/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  64. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js +2 -0
  65. package/dist/esm/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  66. package/dist/esm/createNativeMenu/index.js +3 -0
  67. package/dist/esm/createNativeMenu/index.js.map +6 -0
  68. package/dist/esm/createNativeMenu/index.mjs +3 -0
  69. package/dist/esm/createNativeMenu/index.mjs.map +1 -0
  70. package/dist/esm/createNativeMenu/index.native.js +3 -0
  71. package/dist/esm/createNativeMenu/index.native.js.map +1 -0
  72. package/dist/esm/createNativeMenu/utils.js +47 -0
  73. package/dist/esm/createNativeMenu/utils.js.map +6 -0
  74. package/dist/esm/createNativeMenu/utils.mjs +29 -0
  75. package/dist/esm/createNativeMenu/utils.mjs.map +1 -0
  76. package/dist/esm/createNativeMenu/utils.native.js +52 -0
  77. package/dist/esm/createNativeMenu/utils.native.js.map +1 -0
  78. package/dist/esm/createNativeMenu/withNativeMenu.js +15 -0
  79. package/dist/esm/createNativeMenu/withNativeMenu.js.map +6 -0
  80. package/dist/esm/createNativeMenu/withNativeMenu.mjs +14 -0
  81. package/dist/esm/createNativeMenu/withNativeMenu.mjs.map +1 -0
  82. package/dist/esm/createNativeMenu/withNativeMenu.native.js +17 -0
  83. package/dist/esm/createNativeMenu/withNativeMenu.native.js.map +1 -0
  84. package/dist/esm/index.js +8 -0
  85. package/dist/esm/index.js.map +6 -0
  86. package/dist/esm/index.mjs +6 -0
  87. package/dist/esm/index.mjs.map +1 -0
  88. package/dist/esm/index.native.js +6 -0
  89. package/dist/esm/index.native.js.map +1 -0
  90. package/dist/jsx/MenuPredefined.js +147 -0
  91. package/dist/jsx/MenuPredefined.js.map +6 -0
  92. package/dist/jsx/MenuPredefined.mjs +159 -0
  93. package/dist/jsx/MenuPredefined.mjs.map +1 -0
  94. package/dist/jsx/MenuPredefined.native.js +185 -0
  95. package/dist/jsx/MenuPredefined.native.js.map +1 -0
  96. package/dist/jsx/createBaseMenu.js +729 -0
  97. package/dist/jsx/createBaseMenu.js.map +6 -0
  98. package/dist/jsx/createBaseMenu.mjs +893 -0
  99. package/dist/jsx/createBaseMenu.mjs.map +1 -0
  100. package/dist/jsx/createBaseMenu.native.js +1105 -0
  101. package/dist/jsx/createBaseMenu.native.js.map +1 -0
  102. package/dist/jsx/createNativeMenu/createNativeMenu.js +150 -0
  103. package/dist/jsx/createNativeMenu/createNativeMenu.js.map +6 -0
  104. package/dist/jsx/createNativeMenu/createNativeMenu.mjs +190 -0
  105. package/dist/jsx/createNativeMenu/createNativeMenu.mjs.map +1 -0
  106. package/dist/jsx/createNativeMenu/createNativeMenu.native.js +287 -0
  107. package/dist/jsx/createNativeMenu/createNativeMenu.native.js.map +1 -0
  108. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js +1 -0
  109. package/dist/jsx/createNativeMenu/createNativeMenuTypes.js.map +6 -0
  110. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs +2 -0
  111. package/dist/jsx/createNativeMenu/createNativeMenuTypes.mjs.map +1 -0
  112. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js +19 -0
  113. package/dist/jsx/createNativeMenu/createNativeMenuTypes.native.js.map +1 -0
  114. package/dist/jsx/createNativeMenu/index.js +3 -0
  115. package/dist/jsx/createNativeMenu/index.js.map +6 -0
  116. package/dist/jsx/createNativeMenu/index.mjs +3 -0
  117. package/dist/jsx/createNativeMenu/index.mjs.map +1 -0
  118. package/dist/jsx/createNativeMenu/index.native.js +22 -0
  119. package/dist/jsx/createNativeMenu/index.native.js.map +1 -0
  120. package/dist/jsx/createNativeMenu/utils.js +47 -0
  121. package/dist/jsx/createNativeMenu/utils.js.map +6 -0
  122. package/dist/jsx/createNativeMenu/utils.mjs +29 -0
  123. package/dist/jsx/createNativeMenu/utils.mjs.map +1 -0
  124. package/dist/jsx/createNativeMenu/utils.native.js +94 -0
  125. package/dist/jsx/createNativeMenu/utils.native.js.map +1 -0
  126. package/dist/jsx/createNativeMenu/withNativeMenu.js +15 -0
  127. package/dist/jsx/createNativeMenu/withNativeMenu.js.map +6 -0
  128. package/dist/jsx/createNativeMenu/withNativeMenu.mjs +14 -0
  129. package/dist/jsx/createNativeMenu/withNativeMenu.mjs.map +1 -0
  130. package/dist/jsx/createNativeMenu/withNativeMenu.native.js +43 -0
  131. package/dist/jsx/createNativeMenu/withNativeMenu.native.js.map +1 -0
  132. package/dist/jsx/index.js +8 -0
  133. package/dist/jsx/index.js.map +6 -0
  134. package/dist/jsx/index.mjs +6 -0
  135. package/dist/jsx/index.mjs.map +1 -0
  136. package/dist/jsx/index.native.js +33 -0
  137. package/dist/jsx/index.native.js.map +1 -0
  138. package/package.json +80 -0
  139. package/src/MenuPredefined.tsx +195 -0
  140. package/src/createBaseMenu.tsx +1703 -0
  141. package/src/createNativeMenu/createNativeMenu.tsx +372 -0
  142. package/src/createNativeMenu/createNativeMenuTypes.ts +214 -0
  143. package/src/createNativeMenu/index.tsx +7 -0
  144. package/src/createNativeMenu/utils.tsx +150 -0
  145. package/src/createNativeMenu/withNativeMenu.tsx +38 -0
  146. package/src/index.tsx +9 -0
  147. package/types/MenuPredefined.d.ts +28 -0
  148. package/types/MenuPredefined.d.ts.map +1 -0
  149. package/types/createBaseMenu.d.ts +207 -0
  150. package/types/createBaseMenu.d.ts.map +1 -0
  151. package/types/createNativeMenu/createNativeMenu.d.ts +42 -0
  152. package/types/createNativeMenu/createNativeMenu.d.ts.map +1 -0
  153. package/types/createNativeMenu/createNativeMenuTypes.d.ts +188 -0
  154. package/types/createNativeMenu/createNativeMenuTypes.d.ts.map +1 -0
  155. package/types/createNativeMenu/index.d.ts +4 -0
  156. package/types/createNativeMenu/index.d.ts.map +1 -0
  157. package/types/createNativeMenu/utils.d.ts +38 -0
  158. package/types/createNativeMenu/utils.d.ts.map +1 -0
  159. package/types/createNativeMenu/withNativeMenu.d.ts +9 -0
  160. package/types/createNativeMenu/withNativeMenu.d.ts.map +1 -0
  161. package/types/index.d.ts +6 -0
  162. package/types/index.d.ts.map +1 -0
@@ -0,0 +1,372 @@
1
+ /**
2
+ * createNativeMenu - provides native menu implementation for React Native
3
+ *
4
+ * On Web: Returns empty stub components (withNativeMenu will use the web components instead)
5
+ * On Native: Uses Zeego for native menus (Credit to nandorojo/Zeego)
6
+ */
7
+
8
+ import { isWeb, withStaticProperties, isIos } from '@tamagui/web'
9
+ import type { FC } from 'react'
10
+ import React from 'react'
11
+ import type {
12
+ ContextMenuPreviewProps,
13
+ MenuArrowProps,
14
+ MenuCheckboxItemProps,
15
+ MenuContentProps,
16
+ MenuGroupProps,
17
+ MenuItemIconProps,
18
+ MenuItemImageProps,
19
+ MenuItemIndicatorProps,
20
+ MenuItemProps,
21
+ MenuItemSubtitleProps,
22
+ MenuItemTitleProps,
23
+ MenuLabelProps,
24
+ MenuProps,
25
+ MenuSeparatorProps,
26
+ MenuSubContentProps,
27
+ MenuSubProps,
28
+ MenuSubTriggerProps,
29
+ MenuTriggerProps,
30
+ } from './createNativeMenuTypes'
31
+
32
+ export type NativeMenuComponents = {
33
+ Menu: FC<MenuProps> & {
34
+ Trigger: FC<MenuTriggerProps>
35
+ Content: FC<MenuContentProps>
36
+ Item: FC<MenuItemProps>
37
+ ItemTitle: FC<MenuItemTitleProps>
38
+ ItemSubtitle: FC<MenuItemSubtitleProps>
39
+ SubTrigger: FC<MenuSubTriggerProps>
40
+ Group: FC<MenuGroupProps>
41
+ ItemIcon: FC<MenuItemIconProps>
42
+ Separator: FC<MenuSeparatorProps>
43
+ CheckboxItem: FC<MenuCheckboxItemProps>
44
+ ItemIndicator: FC<MenuItemIndicatorProps>
45
+ ItemImage: FC<MenuItemImageProps>
46
+ Label: FC<MenuLabelProps>
47
+ Arrow: FC<MenuArrowProps>
48
+ Sub: FC<MenuSubProps>
49
+ SubContent: FC<MenuSubContentProps>
50
+ Preview: FC<ContextMenuPreviewProps>
51
+ Portal: FC<{ children: React.ReactNode }>
52
+ RadioGroup: FC<{ children: React.ReactNode }>
53
+ RadioItem: FC<{ children: React.ReactNode }>
54
+ Auxiliary: FC<any>
55
+ }
56
+ }
57
+
58
+ export const createNativeMenu = (
59
+ MenuType: 'ContextMenu' | 'Menu'
60
+ ): NativeMenuComponents => {
61
+ // On web, return empty stubs - withNativeMenu will use the web components passed to it
62
+ if (isWeb) {
63
+ const Menu = {} as FC<MenuProps>
64
+ const Trigger = {} as FC<MenuTriggerProps>
65
+ const Content = {} as FC<MenuContentProps>
66
+ const Preview = {} as FC<ContextMenuPreviewProps>
67
+ const Item = {} as FC<MenuItemProps>
68
+ const ItemIcon = {} as FC<MenuItemIconProps>
69
+ const ItemImage = {} as FC<MenuItemImageProps>
70
+ const SubTrigger = {} as FC<MenuSubTriggerProps>
71
+ const ItemTitle = {} as FC<MenuItemTitleProps>
72
+ const ItemSubtitle = {} as FC<MenuItemSubtitleProps>
73
+ const Group = {} as FC<MenuGroupProps>
74
+ const Separator = {} as FC<MenuSeparatorProps>
75
+ const CheckboxItem = {} as FC<MenuCheckboxItemProps>
76
+ const ItemIndicator = {} as FC<MenuItemIndicatorProps>
77
+ const Label = {} as FC<MenuLabelProps>
78
+ const Arrow = {} as FC<MenuArrowProps>
79
+ const Sub = {} as FC<MenuSubProps>
80
+ const SubContent = {} as FC<MenuSubContentProps>
81
+ const Portal = {} as FC<{ children: React.ReactNode }>
82
+ const RadioGroup = {} as FC<{ children: React.ReactNode }>
83
+ const RadioItem = {} as FC<{ children: React.ReactNode }>
84
+ const Auxiliary = {} as FC<any>
85
+
86
+ return {
87
+ Menu: withStaticProperties(Menu, {
88
+ Trigger,
89
+ Content,
90
+ Item,
91
+ ItemTitle,
92
+ ItemSubtitle,
93
+ SubTrigger,
94
+ Group,
95
+ ItemIcon,
96
+ Separator,
97
+ CheckboxItem,
98
+ ItemIndicator,
99
+ ItemImage,
100
+ Label,
101
+ Arrow,
102
+ Sub,
103
+ SubContent,
104
+ Preview,
105
+ Portal,
106
+ RadioGroup,
107
+ RadioItem,
108
+ Auxiliary,
109
+ }),
110
+ }
111
+ }
112
+
113
+ // ===========================================
114
+ // Native implementation using Zeego
115
+ // ===========================================
116
+
117
+ const ZeegoDropdownMenu = require('zeego/dropdown-menu')
118
+ const ZeegoContextMenu = require('zeego/context-menu')
119
+
120
+ const isContextMenu = MenuType === 'ContextMenu'
121
+ const ZeegoMenu = isContextMenu ? ZeegoContextMenu : ZeegoDropdownMenu
122
+
123
+ // Map displayName patterns to Zeego components
124
+ const COMPONENT_MAP: Record<string, any> = {
125
+ SubContent: ZeegoMenu.SubContent,
126
+ Content: ZeegoMenu.Content,
127
+ Sub: ZeegoMenu.Sub,
128
+ Group: ZeegoMenu.Group,
129
+ SubTrigger: ZeegoMenu.SubTrigger,
130
+ }
131
+
132
+ // Components that need children transformation (containers)
133
+ const CONTAINER_TYPES = ['SubContent', 'Content', 'Sub', 'Group']
134
+
135
+ /**
136
+ * Get component type from displayName (handles styled wrappers)
137
+ */
138
+ const getComponentType = (displayName: string): string | null => {
139
+ // Check in specific order (SubContent before Content, SubTrigger before Trigger)
140
+ for (const type of [
141
+ 'SubContent',
142
+ 'SubTrigger',
143
+ 'Content',
144
+ 'Sub',
145
+ 'Group',
146
+ 'CheckboxItem',
147
+ ]) {
148
+ if (displayName === type || displayName.includes(`(${type})`)) {
149
+ return type
150
+ }
151
+ }
152
+ return null
153
+ }
154
+
155
+ /**
156
+ * Check if component looks like a menu Item (has onSelect/textValue but isn't a special component)
157
+ */
158
+ const isItemLike = (props: Record<string, any>, displayName: string): boolean => {
159
+ // If it matches a known component type, it's not a generic Item
160
+ if (getComponentType(displayName)) {
161
+ return false
162
+ }
163
+ return 'onSelect' in props || 'textValue' in props
164
+ }
165
+
166
+ /**
167
+ * Check if displayName matches Portal
168
+ */
169
+ const isPortal = (displayName: string): boolean => {
170
+ return displayName === 'Portal' || displayName.includes('Portal')
171
+ }
172
+
173
+ /**
174
+ * Transform children tree for Zeego compatibility:
175
+ * - Flatten Portal wrappers
176
+ * - Recurse into containers (Content, Sub, Group, SubContent)
177
+ * - Convert styled Items to Zeego Items
178
+ * - Reverse children on iOS only for DropdownMenu at Content/SubContent level
179
+ */
180
+ const transformForZeego = (
181
+ children: React.ReactNode,
182
+ shouldReverseOnIos = false
183
+ ): React.ReactNode => {
184
+ const result: React.ReactNode[] = []
185
+
186
+ React.Children.forEach(children, (child) => {
187
+ if (!React.isValidElement(child)) {
188
+ result.push(child)
189
+ return
190
+ }
191
+
192
+ const displayName = (child.type as any)?.displayName || ''
193
+ const props = child.props as Record<string, any>
194
+
195
+ // Flatten Portal
196
+ if (isPortal(displayName)) {
197
+ const portalChildren = transformForZeego(props.children, false)
198
+ React.Children.forEach(portalChildren, (c) => result.push(c))
199
+ return
200
+ }
201
+
202
+ // Handle known component types (containers, SubTrigger, CheckboxItem)
203
+ const componentType = getComponentType(displayName)
204
+
205
+ // normalizing checked/value props
206
+ if (componentType === 'CheckboxItem') {
207
+ const { checked, onCheckedChange, value, onValueChange, children, ...rest } =
208
+ props
209
+
210
+ const finalValue = value ?? (checked ? 'on' : 'off')
211
+ const finalOnValueChange =
212
+ onValueChange ??
213
+ (onCheckedChange && ((v: string) => onCheckedChange(v === 'on')))
214
+
215
+ const cleanChildren = React.Children.map(children, (child) => {
216
+ if (!React.isValidElement(child)) return child
217
+
218
+ const childDisplayName = (child.type as any)?.displayName || ''
219
+ // If it's an ItemIndicator, remove it (return null) so we don't double render the checkmark
220
+ if (childDisplayName.includes('ItemIndicator')) {
221
+ return null
222
+ }
223
+ return child
224
+ })
225
+
226
+ result.push(
227
+ React.createElement(
228
+ ZeegoMenu.CheckboxItem,
229
+ {
230
+ ...rest,
231
+ key: child.key,
232
+ value: finalValue,
233
+ onValueChange: finalOnValueChange,
234
+ },
235
+ cleanChildren
236
+ )
237
+ )
238
+ return
239
+ }
240
+
241
+ if (componentType) {
242
+ const { children: childChildren, ...restProps } = props
243
+ const isContainer = CONTAINER_TYPES.includes(componentType)
244
+ // Only reverse children of Content and SubContent (not Group or Sub)
245
+ const shouldReverseChildren =
246
+ componentType === 'Content' || componentType === 'SubContent'
247
+ result.push(
248
+ React.createElement(
249
+ COMPONENT_MAP[componentType],
250
+ { ...restProps, key: child.key },
251
+ isContainer
252
+ ? transformForZeego(childChildren, shouldReverseChildren)
253
+ : childChildren
254
+ )
255
+ )
256
+ return
257
+ }
258
+
259
+ // Convert Item-like components to Zeego Items
260
+ if (isItemLike(props, displayName)) {
261
+ const { children: itemChildren, ...itemProps } = props
262
+ result.push(
263
+ React.createElement(
264
+ ZeegoMenu.Item,
265
+ { ...itemProps, key: child.key },
266
+ itemChildren
267
+ )
268
+ )
269
+ return
270
+ }
271
+
272
+ // Pass through everything else
273
+ result.push(child)
274
+ })
275
+
276
+ // iOS DropdownMenu (not ContextMenu) displays menu items in reverse order
277
+ // Only reverse for Menu component, not ContextMenu
278
+ if (isIos && shouldReverseOnIos && !isContextMenu) {
279
+ result.reverse()
280
+ }
281
+
282
+ return result
283
+ }
284
+
285
+ // ===========================================
286
+ // Component definitions (typed wrappers around Zeego)
287
+ // ===========================================
288
+
289
+ // Direct Zeego pass-throughs with proper types
290
+ const Trigger: FC<MenuTriggerProps> = ZeegoMenu.Trigger
291
+ const Content: FC<MenuContentProps> = ZeegoMenu.Content
292
+ const Item: FC<MenuItemProps> = ZeegoMenu.Item
293
+ const ItemTitle: FC<MenuItemTitleProps> = ZeegoMenu.ItemTitle
294
+ const ItemSubtitle: FC<MenuItemSubtitleProps> = ZeegoMenu.ItemSubtitle
295
+ const ItemIcon: FC<MenuItemIconProps> = ZeegoMenu.ItemIcon
296
+ const ItemImage: FC<MenuItemImageProps> = ZeegoMenu.ItemImage
297
+ const ItemIndicator: FC<MenuItemIndicatorProps> = ZeegoMenu.ItemIndicator
298
+ const Group: FC<MenuGroupProps> = ZeegoMenu.Group
299
+ const Label: FC<MenuLabelProps> = ZeegoMenu.Label
300
+ const Separator: FC<MenuSeparatorProps> = ZeegoMenu.Separator
301
+ const Sub: FC<MenuSubProps> = ZeegoMenu.Sub
302
+ const SubTrigger: FC<MenuSubTriggerProps> = ZeegoMenu.SubTrigger
303
+ const SubContent: FC<MenuSubContentProps> = ZeegoMenu.SubContent
304
+
305
+ // Custom components
306
+ const Portal: FC<{ children: React.ReactNode }> = ({ children }) => <>{children}</>
307
+ Portal.displayName = 'Portal'
308
+
309
+ const Arrow: FC<MenuArrowProps> = () => null
310
+ Arrow.displayName = 'Arrow'
311
+
312
+ const RadioGroup: FC<{ children: React.ReactNode }> = ({ children }) => <>{children}</>
313
+ RadioGroup.displayName = `${MenuType}RadioGroup`
314
+
315
+ const RadioItem: FC<{ children: React.ReactNode }> = ({ children }) => <>{children}</>
316
+ RadioItem.displayName = `${MenuType}RadioItem`
317
+ // CheckboxItem wrapper to normalize checked/value props
318
+ const CheckboxItem: FC<MenuCheckboxItemProps> = (props) => null
319
+ CheckboxItem.displayName = 'CheckboxItem'
320
+
321
+ // Context menu specific
322
+ const Preview: FC<ContextMenuPreviewProps> = isContextMenu
323
+ ? ZeegoContextMenu.Preview
324
+ : () => null
325
+ Preview.displayName = `${MenuType}Preview`
326
+
327
+ const Auxiliary: FC<ContextMenuPreviewProps> = isContextMenu
328
+ ? ZeegoContextMenu.Auxiliary
329
+ : () => null
330
+ Auxiliary.displayName = `${MenuType}Auxiliary`
331
+
332
+ // Main Menu component
333
+ const Menu: FC<MenuProps> = ({ children, onOpenChange, onOpenWillChange }) => {
334
+ const rootProps: Record<string, unknown> = { onOpenChange }
335
+ if (isContextMenu && onOpenWillChange) {
336
+ rootProps.onOpenWillChange = onOpenWillChange
337
+ }
338
+
339
+ return <ZeegoMenu.Root {...rootProps}>{transformForZeego(children)}</ZeegoMenu.Root>
340
+ }
341
+ Menu.displayName = MenuType
342
+
343
+ // ===========================================
344
+ // Export
345
+ // ===========================================
346
+
347
+ return {
348
+ Menu: withStaticProperties(Menu, {
349
+ Trigger,
350
+ Content,
351
+ Item,
352
+ ItemTitle,
353
+ ItemSubtitle,
354
+ ItemIcon,
355
+ ItemImage,
356
+ ItemIndicator,
357
+ Group,
358
+ Label,
359
+ Separator,
360
+ Sub,
361
+ SubTrigger,
362
+ SubContent,
363
+ CheckboxItem,
364
+ Portal,
365
+ RadioGroup,
366
+ RadioItem,
367
+ Arrow,
368
+ Preview,
369
+ Auxiliary,
370
+ }),
371
+ }
372
+ }
@@ -0,0 +1,214 @@
1
+ import type { ImageProps } from 'react-native'
2
+ import type { SFSymbol } from 'sf-symbols-typescript'
3
+
4
+ type ImageOptions = {
5
+ tint?: string
6
+ }
7
+
8
+ export type MenuProps = {
9
+ children: React.ReactNode
10
+ native?: boolean
11
+ onOpenChange?: (isOpen: boolean) => void
12
+ /**
13
+ * Callback function indicating that the menu intends to open or close. Passes a `willOpen` boolean argument indicating whether it is opening or closing.
14
+ * Unlike `onOpenChange`, this is called before the animation begins.
15
+ * @platform `ios`
16
+ */
17
+ onOpenWillChange?: (willOpen: boolean) => void
18
+ }
19
+
20
+ /**
21
+ * Props for the auxiliary view that can be shown alongside a context menu on iOS
22
+ * @platform ios
23
+ */
24
+ export type ContextMenuAuxiliaryProps = {
25
+ height?: number
26
+ width?: number
27
+ anchorPosition?: 'top' | 'bottom' | 'automatic'
28
+ children: React.ReactNode | ((options: { dismissMenu: () => void }) => React.ReactNode)
29
+ onDidShow?: () => void
30
+ marginWithScreenEdge?: number
31
+ onWillShow?: () => void
32
+ }
33
+
34
+ export type MenuTriggerProps = {
35
+ children: React.ReactElement
36
+ asChild?: boolean
37
+ /**
38
+ * Determine whether the menu should open on `press` or `longPress`. Defaults to `press` for `Menu` and `longPress` for `ContextMenu`.
39
+ *
40
+ * Only applies for `ios` and `android`.
41
+ */
42
+ action?: 'press' | 'longPress'
43
+ }
44
+
45
+ export type MenuContentProps = {
46
+ children: React.ReactNode
47
+ }
48
+ export type ContextMenuContentProps = MenuContentProps
49
+
50
+ export type MenuGroupProps = {
51
+ children: React.ReactNode
52
+ }
53
+
54
+ export type MenuItemProps = {
55
+ children: React.ReactNode
56
+ /**
57
+ * If you want to pass a React text node to `<ItemTitle />`, then you need to use this prop. This gets used on iOS and Android.
58
+ */
59
+ textValue?: string
60
+ /**
61
+ * Callback when the item is selected
62
+ */
63
+ onSelect?: (event?: Event) => void
64
+ } & {
65
+ disabled?: boolean
66
+ hidden?: boolean
67
+ destructive?: boolean
68
+ key: string
69
+ }
70
+
71
+ export interface MenuItemCommonProps {
72
+ /**
73
+ * React elements to render as fallback icon (typically for web)
74
+ */
75
+ children?: React.ReactNode
76
+ /**
77
+ * The name of an iOS-only SF Symbol. For a full list, see https://developer.apple.com/sf-symbols/.
78
+ * @deprecated Please use the `name` inside of the `ios` prop instead.
79
+ * @platform ios
80
+ */
81
+ iosIconName?: string
82
+ /**
83
+ * Icon configuration to be used on iOS. You can pass a SF Symbol icon using the `name` prop.
84
+ * Additionally, you can configure the SF Symbol's features like weight, scale, color etc. by passing
85
+ * the corresponding props. Note that some of those features require iOS 15+.
86
+ *
87
+ * @platform ios
88
+ */
89
+ ios?: {
90
+ name: SFSymbol
91
+ weight?:
92
+ | 'ultraLight'
93
+ | 'thin'
94
+ | 'light'
95
+ | 'regular'
96
+ | 'medium'
97
+ | 'semibold'
98
+ | 'bold'
99
+ | 'heavy'
100
+ | 'black'
101
+ scale?: 'small' | 'medium' | 'large'
102
+ hierarchicalColor?: string
103
+ paletteColors?: string[]
104
+ }
105
+ /**
106
+ * The name of an android-only resource drawable. For a full list, see https://developer.android.com/reference/android/R.drawable.html.
107
+ *
108
+ * @platform android
109
+ */
110
+ androidIconName?: string
111
+ }
112
+
113
+ export type MenuItemIconProps = MenuItemCommonProps
114
+
115
+ export type MenuItemImageProps = MenuItemCommonProps & {
116
+ /**
117
+ * `source={require('path/to/image')}`
118
+ */
119
+ source: ImageProps['source']
120
+ ios?: {
121
+ style?: ImageOptions
122
+ lazy?: boolean
123
+ }
124
+ }
125
+
126
+ export type MenuArrowProps = {}
127
+
128
+ export type MenuSubTriggerProps = MenuItemProps & {
129
+ key: string
130
+ }
131
+
132
+ export type MenuSubProps = {
133
+ children?: React.ReactNode
134
+ }
135
+
136
+ export type MenuSubContentProps = {
137
+ children: React.ReactNode
138
+ }
139
+ export type ContextMenuSubContentProps = ContextMenuContentProps
140
+
141
+ export type MenuItemTitleProps = {
142
+ children: string | React.ReactNode
143
+ }
144
+ export type MenuItemSubtitleProps = {
145
+ children: string
146
+ }
147
+ export type MenuSeparatorProps = {}
148
+ export type MenuCheckboxItemProps = Omit<MenuItemProps, 'onSelect'> & {
149
+ /**
150
+ * The controlled checked state of the checkbox item.
151
+ * Use this with `onCheckedChange` for the web-style API.
152
+ */
153
+ checked?: boolean
154
+ /**
155
+ * Callback when the checked state changes.
156
+ * Use this with `checked` for the web-style API.
157
+ */
158
+ onCheckedChange?: (checked: boolean) => void
159
+ /**
160
+ * The controlled value state for native platforms.
161
+ * Use this with `onValueChange` for the native-style API.
162
+ * @platform ios, android
163
+ */
164
+ value?: 'mixed' | 'on' | 'off' | boolean
165
+ /**
166
+ * Callback when the value changes on native platforms.
167
+ * Use this with `value` for the native-style API.
168
+ * @platform ios, android
169
+ */
170
+ onValueChange?: (
171
+ state: 'mixed' | 'on' | 'off',
172
+ prevState: 'mixed' | 'on' | 'off'
173
+ ) => void
174
+ key: string
175
+ }
176
+
177
+ export type MenuItemIndicatorProps = {
178
+ children?: React.ReactNode
179
+ }
180
+
181
+ export type MenuLabelProps = {
182
+ children: string
183
+ /**
184
+ * If you want to pass a React text node to `<Lable />`, then you need to use this prop. This gets used on iOS and Android.
185
+ */
186
+ textValue?: string
187
+ }
188
+
189
+ export type ContextMenuPreviewProps = {
190
+ children: React.ReactNode | (() => React.ReactNode)
191
+ /**
192
+ * Size of the preview
193
+ * @platform ios
194
+ */
195
+ size?: {
196
+ width?: number
197
+ height?: number
198
+ }
199
+ /**
200
+ * Called when the preview is pressed
201
+ * @platform ios
202
+ */
203
+ onPress?: () => void
204
+ /**
205
+ * Background color of the preview
206
+ * @platform ios
207
+ */
208
+ backgroundColor?: string
209
+ /**
210
+ * Border radius of the preview
211
+ * @platform ios
212
+ */
213
+ borderRadius?: number
214
+ }
@@ -0,0 +1,7 @@
1
+ export * from './createNativeMenu'
2
+ export * from './withNativeMenu'
3
+ // only export these types to fix a ts issue for ContextMenu
4
+ export type {
5
+ MenuItemIconProps as NativeMenuItemIconProps,
6
+ MenuSubTriggerProps as NativeMenuSubTriggerProps,
7
+ } from './createNativeMenuTypes'