@himakarinv/nativex 1.0.0

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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/images.d.ts +14 -0
  4. package/index.js +8 -0
  5. package/nativewind-preset.js +18 -0
  6. package/package.json +120 -0
  7. package/src/assets/branding/logo.jpg +0 -0
  8. package/src/assets/branding/softech-logo.png +0 -0
  9. package/src/assets/icons/2-layers.svg +3 -0
  10. package/src/assets/icons/Forbidden.svg +211 -0
  11. package/src/assets/icons/Internal-server-error.svg +119 -0
  12. package/src/assets/icons/Log-out-nav.svg +4 -0
  13. package/src/assets/icons/Not-Found.svg +282 -0
  14. package/src/assets/icons/Unauthorized.svg +314 -0
  15. package/src/assets/icons/User-Frame.svg +5 -0
  16. package/src/assets/icons/alert.svg +4 -0
  17. package/src/assets/icons/arrow-right.svg +3 -0
  18. package/src/assets/icons/avatar-female.svg +10 -0
  19. package/src/assets/icons/avatar-male.svg +10 -0
  20. package/src/assets/icons/bell.svg +3 -0
  21. package/src/assets/icons/calendar-event.svg +11 -0
  22. package/src/assets/icons/calendar.svg +6 -0
  23. package/src/assets/icons/card.svg +4 -0
  24. package/src/assets/icons/caret-right.svg +3 -0
  25. package/src/assets/icons/chat.svg +11 -0
  26. package/src/assets/icons/check.svg +3 -0
  27. package/src/assets/icons/checkbox-minus.svg +3 -0
  28. package/src/assets/icons/checkmark.svg +3 -0
  29. package/src/assets/icons/chevron-down.svg +3 -0
  30. package/src/assets/icons/chevron-left.svg +9 -0
  31. package/src/assets/icons/chevron-right.svg +9 -0
  32. package/src/assets/icons/circle-radio-active.svg +10 -0
  33. package/src/assets/icons/circle-radio.svg +10 -0
  34. package/src/assets/icons/clock.svg +3 -0
  35. package/src/assets/icons/close.svg +3 -0
  36. package/src/assets/icons/code.svg +3 -0
  37. package/src/assets/icons/country.svg +20 -0
  38. package/src/assets/icons/dot.svg +3 -0
  39. package/src/assets/icons/download.svg +1 -0
  40. package/src/assets/icons/dropdown-arrow.svg +3 -0
  41. package/src/assets/icons/dropdown-avatar.svg +3 -0
  42. package/src/assets/icons/email.svg +3 -0
  43. package/src/assets/icons/error.svg +3 -0
  44. package/src/assets/icons/eye-off.svg +1 -0
  45. package/src/assets/icons/eye.svg +1 -0
  46. package/src/assets/icons/hashtag-icon.svg +3 -0
  47. package/src/assets/icons/help-circle.svg +10 -0
  48. package/src/assets/icons/help.svg +4 -0
  49. package/src/assets/icons/hide-checkbox.svg +3 -0
  50. package/src/assets/icons/home-smile.svg +3 -0
  51. package/src/assets/icons/home.svg +3 -0
  52. package/src/assets/icons/info.svg +5 -0
  53. package/src/assets/icons/left-arrow.svg +3 -0
  54. package/src/assets/icons/log-out.svg +3 -0
  55. package/src/assets/icons/notification-box.svg +4 -0
  56. package/src/assets/icons/pencil.svg +1 -0
  57. package/src/assets/icons/plus.svg +3 -0
  58. package/src/assets/icons/radio-dot.svg +3 -0
  59. package/src/assets/icons/right-arrow.svg +3 -0
  60. package/src/assets/icons/search.svg +3 -0
  61. package/src/assets/icons/settings.svg +11 -0
  62. package/src/assets/icons/slack.svg +17 -0
  63. package/src/assets/icons/slash.svg +3 -0
  64. package/src/assets/icons/success.svg +3 -0
  65. package/src/assets/icons/successicon.svg +5 -0
  66. package/src/assets/icons/three-dot-vertical.svg +5 -0
  67. package/src/assets/icons/trash.svg +1 -0
  68. package/src/assets/icons/trend-down-01.svg +3 -0
  69. package/src/assets/icons/trend-up-01.svg +3 -0
  70. package/src/assets/icons/up-arrow.svg +3 -0
  71. package/src/assets/icons/user-plus.svg +10 -0
  72. package/src/assets/icons/user.svg +3 -0
  73. package/src/assets/icons/users.svg +3 -0
  74. package/src/assets/icons/vertical-dots-true-icon.svg +5 -0
  75. package/src/assets/icons/vertical-line.svg +3 -0
  76. package/src/assets/icons/vertical-three-dots-icon.svg +5 -0
  77. package/src/assets/icons/warning.svg +3 -0
  78. package/src/assets/icons/zap.svg +3 -0
  79. package/src/components/ActionsMenu/ActionsMenu.tsx +314 -0
  80. package/src/components/ActionsMenu/index.ts +2 -0
  81. package/src/components/Alert/Alert.tsx +291 -0
  82. package/src/components/Alert/index.ts +2 -0
  83. package/src/components/Badge/Badge.tsx +230 -0
  84. package/src/components/Badge/index.ts +2 -0
  85. package/src/components/Breadcrumb/Breadcrumb.tsx +364 -0
  86. package/src/components/Breadcrumb/index.ts +7 -0
  87. package/src/components/Button/Button.tsx +584 -0
  88. package/src/components/Button/index.ts +9 -0
  89. package/src/components/Checkbox/Checkbox.tsx +336 -0
  90. package/src/components/Checkbox/index.ts +2 -0
  91. package/src/components/CreatePassword/CreatePassword.tsx +161 -0
  92. package/src/components/CreatePassword/index.ts +2 -0
  93. package/src/components/DataTable/DataTable.tsx +822 -0
  94. package/src/components/DataTable/index.ts +10 -0
  95. package/src/components/Datepicker/Datepicker.tsx +797 -0
  96. package/src/components/Datepicker/index.ts +2 -0
  97. package/src/components/Dropdown/Dropdown.tsx +277 -0
  98. package/src/components/Dropdown/index.ts +7 -0
  99. package/src/components/DropdownMenu/DropdownMenu.tsx +471 -0
  100. package/src/components/DropdownMenu/index.ts +11 -0
  101. package/src/components/DynamicForm/DynamicForm.tsx +741 -0
  102. package/src/components/DynamicForm/index.ts +13 -0
  103. package/src/components/ErrorPages/ErrorPages.tsx +135 -0
  104. package/src/components/ErrorPages/index.ts +2 -0
  105. package/src/components/ForgotPassword/ForgotPassword.tsx +121 -0
  106. package/src/components/ForgotPassword/index.ts +2 -0
  107. package/src/components/HintError/HintError.tsx +37 -0
  108. package/src/components/HintError/index.ts +2 -0
  109. package/src/components/Icon/Icon.tsx +43 -0
  110. package/src/components/Icon/icon-registry.ts +227 -0
  111. package/src/components/Icon/index.ts +3 -0
  112. package/src/components/InputDropdown/InputDropdown.tsx +662 -0
  113. package/src/components/InputDropdown/index.ts +9 -0
  114. package/src/components/InputField/InputField.tsx +527 -0
  115. package/src/components/InputField/index.ts +2 -0
  116. package/src/components/Label/Label.tsx +88 -0
  117. package/src/components/Label/index.ts +2 -0
  118. package/src/components/LoginForm/LoginForm.tsx +158 -0
  119. package/src/components/LoginForm/index.ts +2 -0
  120. package/src/components/LoginShell/LoginShell.tsx +97 -0
  121. package/src/components/LoginShell/RoleCard.tsx +24 -0
  122. package/src/components/LoginShell/SoftechLogo.tsx +24 -0
  123. package/src/components/LoginShell/branding-assets.ts +2 -0
  124. package/src/components/LoginShell/index.ts +20 -0
  125. package/src/components/LoginShell/login-copy.ts +45 -0
  126. package/src/components/LoginShell/loginPageStyles.ts +210 -0
  127. package/src/components/Modals/Modals.tsx +313 -0
  128. package/src/components/Modals/index.ts +2 -0
  129. package/src/components/Offcanvas/Offcanvas.tsx +404 -0
  130. package/src/components/Offcanvas/index.ts +13 -0
  131. package/src/components/PageHeader/PageHeader.tsx +128 -0
  132. package/src/components/PageHeader/index.ts +2 -0
  133. package/src/components/Pagination/Pagination.tsx +540 -0
  134. package/src/components/Pagination/index.ts +8 -0
  135. package/src/components/ResetPassword/ResetPassword.tsx +172 -0
  136. package/src/components/ResetPassword/index.ts +2 -0
  137. package/src/components/RoleSelection/RoleSelection.tsx +111 -0
  138. package/src/components/RoleSelection/index.ts +2 -0
  139. package/src/components/SendOtp/SendOtp.tsx +149 -0
  140. package/src/components/SendOtp/index.ts +2 -0
  141. package/src/components/Sidenavbar/Sidenavbar.tsx +358 -0
  142. package/src/components/Sidenavbar/index.ts +2 -0
  143. package/src/components/StatCard/StatCard.tsx +393 -0
  144. package/src/components/StatCard/index.ts +6 -0
  145. package/src/components/Tabs/Tabs.tsx +239 -0
  146. package/src/components/Tabs/index.ts +2 -0
  147. package/src/components/Textarea/Textarea.tsx +217 -0
  148. package/src/components/Textarea/index.ts +2 -0
  149. package/src/components/Timepicker/Timepicker.tsx +384 -0
  150. package/src/components/Timepicker/index.ts +2 -0
  151. package/src/components/Toast/Toast.tsx +278 -0
  152. package/src/components/Toast/index.ts +2 -0
  153. package/src/components/Toggle/Toggle.tsx +296 -0
  154. package/src/components/Toggle/index.ts +2 -0
  155. package/src/components/Typeahead/Typeahead.tsx +521 -0
  156. package/src/components/Typeahead/index.ts +2 -0
  157. package/src/components/Verification/Verification.tsx +374 -0
  158. package/src/components/Verification/index.ts +2 -0
  159. package/src/index.ts +39 -0
  160. package/src/theme/borders.ts +19 -0
  161. package/src/theme/button.ts +41 -0
  162. package/src/theme/colors.ts +273 -0
  163. package/src/theme/index.ts +14 -0
  164. package/src/theme/nativewind-theme.js +182 -0
  165. package/src/theme/radius.ts +12 -0
  166. package/src/theme/shadows.ts +40 -0
  167. package/src/theme/spacing.ts +18 -0
  168. package/src/theme/typography.ts +35 -0
  169. package/src/utils/a11y.ts +21 -0
  170. package/svg.d.ts +7 -0
@@ -0,0 +1,471 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ Dimensions,
4
+ Modal,
5
+ Platform,
6
+ Pressable,
7
+ ScrollView,
8
+ StyleSheet,
9
+ Text,
10
+ View,
11
+ type StyleProp,
12
+ type ViewStyle,
13
+ } from 'react-native';
14
+
15
+ import { borders, colors, radius, shadows, spacing, typography } from '../../theme';
16
+ import {
17
+ Button,
18
+ ButtonSize,
19
+ ButtonVariant,
20
+ IconPosition,
21
+ dismissButtonFocus,
22
+ } from '../Button';
23
+ import { Checkbox, CheckboxSize } from '../Checkbox';
24
+ import { Icon, IconName } from '../Icon';
25
+
26
+ export const DropdownMenuVariant = {
27
+ Default: 'default',
28
+ WithHeader: 'with-header',
29
+ WithShortcuts: 'with-shortcuts',
30
+ WithIcons: 'with-icons',
31
+ Complete: 'complete',
32
+ } as const;
33
+
34
+ export type DropdownMenuVariant = (typeof DropdownMenuVariant)[keyof typeof DropdownMenuVariant];
35
+
36
+ export const DropdownMenuPlacement = {
37
+ TopStart: 'top-start',
38
+ TopEnd: 'top-end',
39
+ BottomStart: 'bottom-start',
40
+ BottomEnd: 'bottom-end',
41
+ } as const;
42
+
43
+ export type DropdownMenuPlacement =
44
+ (typeof DropdownMenuPlacement)[keyof typeof DropdownMenuPlacement];
45
+
46
+ export const DropdownMenuTrigger = {
47
+ Button: 'button',
48
+ VerticalDots: 'verticaldots',
49
+ AvatarIcon: 'avataricon',
50
+ } as const;
51
+
52
+ export type DropdownMenuTrigger = (typeof DropdownMenuTrigger)[keyof typeof DropdownMenuTrigger];
53
+
54
+ export type DropdownMenuAutoClose = boolean | 'inside' | 'outside';
55
+
56
+ export type DropdownMenuItem = {
57
+ id: string;
58
+ label: string;
59
+ icon?: IconName | string;
60
+ shortcut?: string;
61
+ disabled?: boolean;
62
+ divider?: boolean;
63
+ hasCheckbox?: boolean;
64
+ checked?: boolean;
65
+ };
66
+
67
+ export type DropdownMenuProps = {
68
+ trigger?: DropdownMenuTrigger;
69
+ triggerLabel?: string;
70
+ triggerVariant?: ButtonVariant | null;
71
+ triggerSize?: ButtonSize | null;
72
+ placement?: DropdownMenuPlacement;
73
+ autoClose?: DropdownMenuAutoClose;
74
+ variant?: DropdownMenuVariant;
75
+ headerName?: string;
76
+ headerText?: string;
77
+ showShortcuts?: boolean;
78
+ showIcons?: boolean;
79
+ showCheckboxes?: boolean;
80
+ items?: DropdownMenuItem[];
81
+ onItemClick?: (item: DropdownMenuItem) => void;
82
+ onCheckboxChange?: (payload: { item: DropdownMenuItem; checked: boolean }) => void;
83
+ style?: StyleProp<ViewStyle>;
84
+ };
85
+
86
+ const isNative = Platform.OS !== 'web';
87
+ const MENU_MIN_WIDTH = spacing['7xl'] + spacing['7xl'] + spacing['7xl'] + spacing['3xl'];
88
+ const MENU_MAX_WIDTH = MENU_MIN_WIDTH + MENU_MIN_WIDTH;
89
+ const MENU_MAX_HEIGHT = MENU_MIN_WIDTH + MENU_MIN_WIDTH;
90
+ const MENU_GAP = spacing.xs;
91
+ const FOCUS_CLEAR_MS = 220;
92
+
93
+ function webMenuShadow(): ViewStyle {
94
+ return {
95
+ boxShadow: `0 ${shadows.boxLight.offsetY}px ${shadows.boxLight.radius}px ${colors.boxShadowLight}`,
96
+ } as ViewStyle;
97
+ }
98
+
99
+ function closesOnOutside(autoClose: DropdownMenuAutoClose) {
100
+ return autoClose === true || autoClose === 'outside';
101
+ }
102
+
103
+ function closesOnInside(autoClose: DropdownMenuAutoClose) {
104
+ return autoClose === true || autoClose === 'inside';
105
+ }
106
+
107
+ function menuPosition(
108
+ placement: DropdownMenuPlacement,
109
+ trigger: { x: number; y: number; width: number; height: number },
110
+ menu: { width: number; height: number },
111
+ ) {
112
+ const window = Dimensions.get('window');
113
+ const pad = spacing.lg;
114
+ const alignEnd = placement === DropdownMenuPlacement.TopEnd || placement === DropdownMenuPlacement.BottomEnd;
115
+ const placeTop = placement === DropdownMenuPlacement.TopStart || placement === DropdownMenuPlacement.TopEnd;
116
+
117
+ let top = placeTop ? trigger.y - menu.height - MENU_GAP : trigger.y + trigger.height + MENU_GAP;
118
+ let left = alignEnd ? trigger.x + trigger.width - menu.width : trigger.x;
119
+
120
+ left = Math.min(Math.max(pad, left), window.width - menu.width - pad);
121
+ top = Math.min(Math.max(pad, top), window.height - menu.height - pad);
122
+
123
+ return { top, left };
124
+ }
125
+
126
+ function checkedMapFrom(items: DropdownMenuItem[]) {
127
+ return Object.fromEntries(items.map((item) => [item.id, Boolean(item.checked)]));
128
+ }
129
+
130
+ function compactTriggerStyle(size: ButtonSize): ViewStyle {
131
+ if (size === ButtonSize.Large || size === ButtonSize.ExtraLarge || size === ButtonSize.ExtraExtraLarge) {
132
+ return {
133
+ height: spacing['6xl'],
134
+ minHeight: spacing['6xl'],
135
+ paddingVertical: spacing.sm,
136
+ paddingHorizontal: spacing.base,
137
+ };
138
+ }
139
+
140
+ return {
141
+ height: spacing['4xl'],
142
+ minHeight: spacing['4xl'],
143
+ paddingVertical: spacing.xs,
144
+ paddingHorizontal: spacing.md,
145
+ };
146
+ }
147
+
148
+ export function DropdownMenu({
149
+ trigger = DropdownMenuTrigger.Button,
150
+ triggerLabel = 'Account',
151
+ triggerVariant = null,
152
+ triggerSize = null,
153
+ placement = DropdownMenuPlacement.BottomEnd,
154
+ autoClose = true,
155
+ variant: _variant = DropdownMenuVariant.Default,
156
+ headerName = '',
157
+ headerText = '',
158
+ showShortcuts = false,
159
+ showIcons = false,
160
+ showCheckboxes = false,
161
+ items = [],
162
+ onItemClick,
163
+ onCheckboxChange,
164
+ style,
165
+ }: DropdownMenuProps) {
166
+ const triggerRef = useRef<View>(null);
167
+ const [open, setOpen] = useState(false);
168
+ const [hoveredItem, setHoveredItem] = useState<string | null>(null);
169
+ const [triggerBox, setTriggerBox] = useState({ x: 0, y: 0, width: 0, height: 0 });
170
+ const [menuSize, setMenuSize] = useState({ width: MENU_MIN_WIDTH, height: 0 });
171
+ const [checkedById, setCheckedById] = useState(() => checkedMapFrom(items));
172
+ const position = menuPosition(placement, triggerBox, menuSize);
173
+ const hasHeader = Boolean(headerName) || Boolean(headerText);
174
+ const hasHeaderAndText = Boolean(headerName) && Boolean(headerText);
175
+ const isButtonTrigger = trigger === DropdownMenuTrigger.Button;
176
+ const isAvatarTrigger = trigger === DropdownMenuTrigger.AvatarIcon;
177
+ const effectiveVariant =
178
+ triggerVariant ?? (isButtonTrigger ? ButtonVariant.SecondaryGray : ButtonVariant.TertiaryGray);
179
+ const effectiveSize = triggerSize ?? ButtonSize.Small;
180
+ const prefixIconName =
181
+ trigger === DropdownMenuTrigger.VerticalDots
182
+ ? open
183
+ ? IconName.VerticalDotsActive
184
+ : IconName.VerticalThreeDots
185
+ : IconName.DropdownAvatar;
186
+
187
+ useEffect(() => {
188
+ setCheckedById(checkedMapFrom(items));
189
+ }, [items]);
190
+
191
+ const close = () => {
192
+ setOpen(false);
193
+ setHoveredItem(null);
194
+ dismissButtonFocus();
195
+ setTimeout(() => dismissButtonFocus(), FOCUS_CLEAR_MS);
196
+ };
197
+
198
+ const toggle = () => {
199
+ if (open) {
200
+ close();
201
+ return;
202
+ }
203
+
204
+ triggerRef.current?.measureInWindow((x, y, width, measuredHeight) => {
205
+ setTriggerBox({ x, y, width, height: measuredHeight });
206
+ setOpen(true);
207
+ });
208
+ };
209
+
210
+ const select = (item: DropdownMenuItem) => {
211
+ if (item.disabled || item.divider) {
212
+ return;
213
+ }
214
+ onItemClick?.(item);
215
+ if (closesOnInside(autoClose)) {
216
+ close();
217
+ }
218
+ };
219
+
220
+ const toggleChecked = (item: DropdownMenuItem) => {
221
+ if (item.disabled) {
222
+ return;
223
+ }
224
+ const next = !checkedById[item.id];
225
+ setCheckedById((current) => ({ ...current, [item.id]: next }));
226
+ onCheckboxChange?.({ item: { ...item, checked: next }, checked: next });
227
+ };
228
+
229
+ return (
230
+ <View ref={triggerRef} collapsable={false} style={[styles.host, style]}>
231
+ <Button
232
+ label={isButtonTrigger ? triggerLabel : ''}
233
+ variant={effectiveVariant}
234
+ size={effectiveSize}
235
+ iconPosition={isButtonTrigger ? IconPosition.After : IconPosition.Only}
236
+ iconName={isButtonTrigger ? IconName.ChevronDown : prefixIconName}
237
+ iconDecorative
238
+ accessibilityLabel={open ? 'Close menu' : 'Open menu'}
239
+ onPress={toggle}
240
+ style={isAvatarTrigger ? styles.avatarTrigger : undefined}
241
+ contentStyle={
242
+ isAvatarTrigger
243
+ ? styles.avatarContent
244
+ : trigger === DropdownMenuTrigger.VerticalDots
245
+ ? styles.dotsContent
246
+ : compactTriggerStyle(effectiveSize)
247
+ }
248
+ />
249
+
250
+ <Modal visible={open} transparent animationType="none" onRequestClose={close}>
251
+ <Pressable
252
+ accessible={false}
253
+ style={styles.backdrop}
254
+ onPress={() => {
255
+ if (closesOnOutside(autoClose)) {
256
+ close();
257
+ }
258
+ }}>
259
+ <Pressable
260
+ accessible={false}
261
+ accessibilityRole="menu"
262
+ onPress={(event) => {
263
+ if ('stopPropagation' in event && typeof event.stopPropagation === 'function') {
264
+ event.stopPropagation();
265
+ }
266
+ }}
267
+ onLayout={(event) => {
268
+ const { width, height: nextHeight } = event.nativeEvent.layout;
269
+ if (width !== menuSize.width || nextHeight !== menuSize.height) {
270
+ setMenuSize({ width, height: nextHeight });
271
+ }
272
+ }}
273
+ style={[styles.menu, { top: position.top, left: position.left }, !isNative && webMenuShadow()]}>
274
+ {hasHeader ? (
275
+ <View style={[styles.header, hasHeaderAndText && styles.headerCentered]}>
276
+ {headerName ? <Text style={styles.headerName}>{headerName}</Text> : null}
277
+ {headerText ? (
278
+ <View style={styles.headerMeta}>
279
+ <View style={styles.onlineDot} />
280
+ <Text style={styles.headerText}>{headerText}</Text>
281
+ </View>
282
+ ) : null}
283
+ </View>
284
+ ) : null}
285
+
286
+ <ScrollView
287
+ style={styles.list}
288
+ contentContainerStyle={styles.listContent}
289
+ keyboardShouldPersistTaps="handled">
290
+ {items.map((item, index) => {
291
+ if (item.divider) {
292
+ return <View key={`divider-${item.id}-${index}`} style={styles.divider} />;
293
+ }
294
+
295
+ const disabled = Boolean(item.disabled);
296
+ const hovered = hoveredItem === item.id && !disabled;
297
+ const checked = Boolean(checkedById[item.id]);
298
+ const showCheckbox = showCheckboxes || Boolean(item.hasCheckbox);
299
+
300
+ return (
301
+ <Pressable
302
+ key={item.id}
303
+ accessibilityRole="menuitem"
304
+ accessibilityState={{ disabled, checked: showCheckbox ? checked : undefined }}
305
+ accessibilityLabel={item.label}
306
+ disabled={disabled}
307
+ onHoverIn={() => setHoveredItem(item.id)}
308
+ onHoverOut={() => setHoveredItem((current) => (current === item.id ? null : current))}
309
+ onPress={() => select(item)}
310
+ style={[styles.item, hovered && styles.itemHovered, disabled && styles.itemDisabled]}>
311
+ <View style={styles.itemLeft}>
312
+ {showCheckbox ? (
313
+ <Pressable
314
+ accessible={false}
315
+ disabled={disabled}
316
+ hitSlop={spacing.sm}
317
+ onPress={(event) => {
318
+ if ('stopPropagation' in event && typeof event.stopPropagation === 'function') {
319
+ event.stopPropagation();
320
+ }
321
+ toggleChecked(item);
322
+ }}>
323
+ <View pointerEvents="none">
324
+ <Checkbox checked={checked} disabled={disabled} size={CheckboxSize.Small} />
325
+ </View>
326
+ </Pressable>
327
+ ) : null}
328
+ {showIcons && item.icon ? (
329
+ <Icon name={item.icon} size={spacing.lg} color={colors.gray.darker} decorative />
330
+ ) : null}
331
+ <Text style={[styles.itemLabel, disabled && styles.itemLabelDisabled]}>{item.label}</Text>
332
+ </View>
333
+ {showShortcuts && item.shortcut ? <Text style={styles.shortcut}>{item.shortcut}</Text> : null}
334
+ </Pressable>
335
+ );
336
+ })}
337
+ </ScrollView>
338
+ </Pressable>
339
+ </Pressable>
340
+ </Modal>
341
+ </View>
342
+ );
343
+ }
344
+
345
+ const styles = StyleSheet.create({
346
+ host: {
347
+ alignSelf: 'flex-start',
348
+ },
349
+ dotsContent: {
350
+ width: spacing['4xl'],
351
+ height: spacing['4xl'],
352
+ borderWidth: borders.width.none,
353
+ padding: spacing.none,
354
+ },
355
+ avatarTrigger: {
356
+ borderRadius: radius.full,
357
+ },
358
+ avatarContent: {
359
+ width: spacing['4xl'],
360
+ height: spacing['4xl'],
361
+ padding: spacing.none,
362
+ borderWidth: borders.width.none,
363
+ borderRadius: radius.full,
364
+ overflow: 'hidden',
365
+ },
366
+ backdrop: {
367
+ flex: 1,
368
+ },
369
+ menu: {
370
+ position: 'absolute',
371
+ minWidth: MENU_MIN_WIDTH,
372
+ maxWidth: MENU_MAX_WIDTH,
373
+ maxHeight: MENU_MAX_HEIGHT,
374
+ backgroundColor: colors.white,
375
+ borderWidth: borders.width.thin,
376
+ borderColor: colors.surfaceMuted,
377
+ borderRadius: radius.md,
378
+ overflow: 'hidden',
379
+ },
380
+ header: {
381
+ paddingVertical: spacing.md,
382
+ paddingHorizontal: spacing.base,
383
+ backgroundColor: colors.white,
384
+ borderBottomWidth: borders.width.thin,
385
+ borderBottomColor: colors.surfaceMuted,
386
+ alignItems: 'flex-start',
387
+ gap: spacing.xs,
388
+ },
389
+ headerCentered: {
390
+ alignItems: 'center',
391
+ },
392
+ headerName: {
393
+ fontWeight: typography.fontWeight.bold,
394
+ fontSize: typography.fontSize.sm,
395
+ lineHeight: typography.buttonLineHeight.sm,
396
+ color: colors.gray.darker,
397
+ ...Platform.select({
398
+ android: {},
399
+ default: { fontFamily: typography.fontFamily.base },
400
+ }),
401
+ },
402
+ headerMeta: {
403
+ flexDirection: 'row',
404
+ alignItems: 'center',
405
+ gap: spacing.xs,
406
+ },
407
+ onlineDot: {
408
+ width: spacing.sm,
409
+ height: spacing.sm,
410
+ borderRadius: radius.full,
411
+ backgroundColor: colors.success.base,
412
+ },
413
+ headerText: {
414
+ fontFamily: typography.fontFamily.base,
415
+ fontWeight: typography.fontWeight.regular,
416
+ fontSize: typography.fontSize.sm,
417
+ lineHeight: typography.buttonLineHeight.sm,
418
+ color: colors.gray.dark,
419
+ },
420
+ list: {
421
+ maxHeight: MENU_MAX_HEIGHT,
422
+ },
423
+ listContent: {
424
+ paddingTop: spacing.xs,
425
+ paddingBottom: spacing.base,
426
+ },
427
+ item: {
428
+ minHeight: spacing['5xl'],
429
+ paddingHorizontal: spacing.base,
430
+ flexDirection: 'row',
431
+ alignItems: 'center',
432
+ justifyContent: 'space-between',
433
+ gap: spacing.md,
434
+ },
435
+ itemHovered: {
436
+ backgroundColor: colors.gray.light,
437
+ },
438
+ itemDisabled: {
439
+ opacity: 0.5,
440
+ },
441
+ itemLeft: {
442
+ flex: 1,
443
+ minWidth: spacing.none,
444
+ flexDirection: 'row',
445
+ alignItems: 'center',
446
+ gap: spacing.md,
447
+ },
448
+ itemLabel: {
449
+ flexShrink: 1,
450
+ fontFamily: typography.fontFamily.base,
451
+ fontWeight: typography.fontWeight.medium,
452
+ fontSize: typography.fontSize.sm,
453
+ lineHeight: typography.buttonLineHeight.sm,
454
+ color: colors.gray.darker,
455
+ },
456
+ itemLabelDisabled: {
457
+ color: colors.gray.dark,
458
+ },
459
+ shortcut: {
460
+ fontFamily: typography.fontFamily.base,
461
+ fontWeight: typography.fontWeight.regular,
462
+ fontSize: typography.fontSize.sm,
463
+ lineHeight: typography.buttonLineHeight.sm,
464
+ color: colors.text.muted,
465
+ },
466
+ divider: {
467
+ height: borders.width.thin,
468
+ backgroundColor: colors.borderSubtle,
469
+ marginVertical: spacing.sm,
470
+ },
471
+ });
@@ -0,0 +1,11 @@
1
+ export {
2
+ DropdownMenu,
3
+ DropdownMenuVariant,
4
+ DropdownMenuPlacement,
5
+ DropdownMenuTrigger,
6
+ } from './DropdownMenu';
7
+ export type {
8
+ DropdownMenuProps,
9
+ DropdownMenuItem,
10
+ DropdownMenuAutoClose,
11
+ } from './DropdownMenu';