@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,527 @@
1
+ import { useState } from 'react';
2
+ import {
3
+ Platform,
4
+ StyleSheet,
5
+ Text,
6
+ TextInput,
7
+ View,
8
+ type StyleProp,
9
+ type TextInputProps,
10
+ type TextStyle,
11
+ type ViewStyle,
12
+ } from 'react-native';
13
+
14
+ import { borders, button as buttonTokens, colors, radius, shadows, spacing, typography } from '../../theme';
15
+ import { Button, ButtonSize, ButtonVariant } from '../Button';
16
+ import { HintError } from '../HintError';
17
+ import { Icon, IconName } from '../Icon';
18
+ import { Label } from '../Label';
19
+
20
+ export const InputVariant = {
21
+ Default: 'default',
22
+ Email: 'email',
23
+ Card: 'card',
24
+ Currency: 'currency',
25
+ PhoneDropdown: 'phone-dropdown',
26
+ Addon: 'addon',
27
+ } as const;
28
+
29
+ export type InputVariant = (typeof InputVariant)[keyof typeof InputVariant];
30
+
31
+ export const InputState = {
32
+ Default: 'default',
33
+ Error: 'error',
34
+ Help: 'help',
35
+ } as const;
36
+
37
+ export type InputState = (typeof InputState)[keyof typeof InputState];
38
+
39
+ export type InputFieldProps = {
40
+ label?: string;
41
+ required?: boolean;
42
+ fullWidth?: boolean;
43
+ placeholder?: string;
44
+ hint?: string;
45
+ error?: string;
46
+ value?: string;
47
+ variant?: InputVariant;
48
+ state?: InputState;
49
+ disabled?: boolean;
50
+ fieldType?: 'text' | 'password';
51
+ readOnly?: boolean;
52
+ inputId?: string;
53
+ showPasswordToggle?: boolean;
54
+ suppressLabel?: boolean;
55
+ suppressHintError?: boolean;
56
+ datepickerFieldNativeLook?: boolean;
57
+ leftIconName?: string;
58
+ rightIconName?: string;
59
+ addonPrefix?: string;
60
+ inputType?: string;
61
+ autoComplete?: TextInputProps['autoComplete'];
62
+ accessibilityLabel?: string;
63
+ onValueChange?: (value: string) => void;
64
+ onBlur?: () => void;
65
+ onFocus?: () => void;
66
+ onKeyPress?: TextInputProps['onKeyPress'];
67
+ style?: StyleProp<ViewStyle>;
68
+ };
69
+
70
+ const isNative = Platform.OS !== 'web';
71
+ const FIELD_WIDTH = isNative ? 255 : 320;
72
+ const FIELD_HEIGHT = isNative ? buttonTokens.height.sm : buttonTokens.height.md;
73
+
74
+ function fieldElevation(): ViewStyle {
75
+ if (Platform.OS !== 'web') {
76
+ return {};
77
+ }
78
+
79
+ return {
80
+ boxShadow: `0 ${shadows.boxLight.offsetY}px ${shadows.boxLight.radius}px ${colors.boxShadowLight}`,
81
+ } as ViewStyle;
82
+ }
83
+
84
+ function webFocusChrome(isAlert: boolean): ViewStyle {
85
+ return {
86
+ outline: `solid ${colors.focus}`,
87
+ boxShadow: isAlert
88
+ ? `0 ${shadows.boxLight.offsetY}px ${shadows.boxLight.radius}px ${colors.boxShadowLight}, 0 0 0 ${borders.width.thick}px ${colors.danger.light}`
89
+ : `0 ${shadows.boxLight.offsetY}px ${shadows.boxLight.radius}px ${colors.boxShadowLight}, 0 0 0 ${borders.width.thick}px ${colors.primary.background}`,
90
+ } as ViewStyle;
91
+ }
92
+
93
+ function nativeRingStyle(offset: number, width: number, color: string): ViewStyle {
94
+ const spread = offset + width;
95
+ return {
96
+ position: 'absolute',
97
+ top: -spread,
98
+ right: -spread,
99
+ bottom: -spread,
100
+ left: -spread,
101
+ borderRadius: radius.md + spread,
102
+ borderWidth: width,
103
+ borderColor: color,
104
+ zIndex: 0,
105
+ };
106
+ }
107
+
108
+ export function InputField({
109
+ label,
110
+ required = false,
111
+ fullWidth = false,
112
+ placeholder,
113
+ hint,
114
+ error,
115
+ value,
116
+ variant = InputVariant.Default,
117
+ state = InputState.Default,
118
+ disabled = false,
119
+ fieldType = 'text',
120
+ readOnly = false,
121
+ inputId,
122
+ showPasswordToggle = true,
123
+ suppressLabel = false,
124
+ suppressHintError = false,
125
+ datepickerFieldNativeLook = false,
126
+ leftIconName,
127
+ rightIconName,
128
+ addonPrefix,
129
+ inputType = 'text',
130
+ autoComplete,
131
+ accessibilityLabel,
132
+ onValueChange,
133
+ onBlur,
134
+ onFocus,
135
+ onKeyPress,
136
+ style,
137
+ }: InputFieldProps) {
138
+ const [internalValue, setInternalValue] = useState(value ?? '');
139
+ const [focused, setFocused] = useState(false);
140
+ const [passwordVisible, setPasswordVisible] = useState(false);
141
+
142
+ const text = value !== undefined ? value : internalValue;
143
+ const isPassword = fieldType === 'password';
144
+ const showToggle = isPassword && showPasswordToggle && !readOnly;
145
+ const isAlert = state === InputState.Error;
146
+ const isHelp = state === InputState.Help;
147
+ const isAddon = variant === InputVariant.Addon;
148
+ const isCurrency = variant === InputVariant.Currency;
149
+ const isPhone = variant === InputVariant.PhoneDropdown;
150
+ const showFocusChrome = focused && !datepickerFieldNativeLook;
151
+
152
+ const effectiveLeftIcon =
153
+ leftIconName ||
154
+ (variant === InputVariant.Email ? IconName.Email : variant === InputVariant.Card ? IconName.Card : '');
155
+
156
+ const effectiveRightIcon = showToggle
157
+ ? ''
158
+ : rightIconName || (isAlert ? IconName.Alert : isHelp ? IconName.Help : '');
159
+
160
+ const resolvedType = isPassword ? (passwordVisible ? 'text' : 'password') : inputType;
161
+ const secure = isPassword && !passwordVisible;
162
+ const showLabel = !suppressLabel && Boolean(label);
163
+ const showAddonStatusIcon = isAddon && (isAlert || isHelp) && Boolean(effectiveRightIcon);
164
+ const showDefaultRightIcon = !isAddon && !showToggle && Boolean(effectiveRightIcon);
165
+
166
+ const paddingLeft = isAddon
167
+ ? spacing['7xl'] + spacing['5xl'] - spacing.xs
168
+ : isPhone
169
+ ? spacing['7xl'] + spacing['4xl'] - spacing.sm
170
+ : isCurrency
171
+ ? spacing['6xl']
172
+ : effectiveLeftIcon === IconName.Card
173
+ ? spacing['7xl'] + spacing.base
174
+ : effectiveLeftIcon
175
+ ? spacing['7xl']
176
+ : spacing.base + spacing.xs;
177
+
178
+ const paddingRight = showToggle
179
+ ? spacing['7xl']
180
+ : isCurrency && isAlert
181
+ ? spacing['7xl'] + spacing['7xl'] + spacing['4xl']
182
+ : isCurrency
183
+ ? spacing['6xl'] + spacing['6xl'] + spacing.base
184
+ : showDefaultRightIcon || showAddonStatusIcon
185
+ ? spacing['7xl']
186
+ : spacing.base + spacing.xs;
187
+
188
+ const setText = (next: string) => {
189
+ if (value === undefined) {
190
+ setInternalValue(next);
191
+ }
192
+ onValueChange?.(next);
193
+ };
194
+
195
+ const fieldBorder = isAlert ? colors.danger.background : colors.input.border;
196
+ const keyboardType: TextInputProps['keyboardType'] =
197
+ resolvedType === 'email' || variant === InputVariant.Email
198
+ ? 'email-address'
199
+ : isPhone
200
+ ? 'phone-pad'
201
+ : 'default';
202
+
203
+ return (
204
+ <View
205
+ style={[
206
+ styles.wrapper,
207
+ fullWidth && !datepickerFieldNativeLook && styles.fullWidth,
208
+ datepickerFieldNativeLook && styles.datepickerWrapper,
209
+ style,
210
+ ]}>
211
+ {showLabel ? <Label text={label} required={required} /> : null}
212
+
213
+ <View
214
+ style={[
215
+ styles.fieldHost,
216
+ (fullWidth || datepickerFieldNativeLook) && styles.fieldHostFullWidth,
217
+ datepickerFieldNativeLook && styles.datepickerHost,
218
+ ]}>
219
+ {showFocusChrome && isNative ? (
220
+ <>
221
+ <View
222
+ pointerEvents="none"
223
+ style={nativeRingStyle(
224
+ spacing.none,
225
+ borders.width.thick,
226
+ isAlert ? colors.danger.light : colors.primary.background,
227
+ )}
228
+ />
229
+ <View
230
+ pointerEvents="none"
231
+ style={nativeRingStyle(spacing.none, borders.focusRing.width, colors.focus)}
232
+ />
233
+ </>
234
+ ) : null}
235
+
236
+ <View
237
+ style={[
238
+ datepickerFieldNativeLook ? styles.datepickerShell : isAddon ? styles.addonShell : styles.fieldShell,
239
+ fullWidth && !datepickerFieldNativeLook && styles.fullWidth,
240
+ !datepickerFieldNativeLook && fieldElevation(),
241
+ !datepickerFieldNativeLook && {
242
+ borderColor: showFocusChrome && isNative ? colors.focus : fieldBorder,
243
+ },
244
+ showFocusChrome && !isNative && webFocusChrome(isAlert),
245
+ disabled && styles.disabled,
246
+ ]}>
247
+ {effectiveLeftIcon && !isAddon && !datepickerFieldNativeLook ? (
248
+ <View style={styles.leftIcon} pointerEvents="none">
249
+ <Icon name={effectiveLeftIcon} size={spacing.xl} decorative />
250
+ </View>
251
+ ) : null}
252
+
253
+ {isCurrency ? (
254
+ <Text style={styles.currencyPrefix} pointerEvents="none">
255
+ $
256
+ </Text>
257
+ ) : null}
258
+
259
+ {isPhone ? (
260
+ <View style={styles.phonePrefix} pointerEvents="none">
261
+ <Text style={styles.phoneCode}>US</Text>
262
+ <Icon name={IconName.DropdownArrow} size={spacing.base} decorative />
263
+ </View>
264
+ ) : null}
265
+
266
+ {isAddon && addonPrefix ? <Text style={styles.addonPrefix}>{addonPrefix}</Text> : null}
267
+ {isAddon ? <View style={styles.addonRule} pointerEvents="none" /> : null}
268
+
269
+ {showDefaultRightIcon || showAddonStatusIcon ? (
270
+ <View
271
+ style={[styles.rightIcon, isCurrency && isAlert && styles.rightIconCurrencyAlert]}
272
+ pointerEvents={isHelp ? 'auto' : 'none'}>
273
+ <Icon name={effectiveRightIcon} size={spacing.lg} decorative={isAlert} />
274
+ </View>
275
+ ) : null}
276
+
277
+ {isCurrency ? (
278
+ <View style={[styles.currencySuffix, isAlert && styles.currencySuffixAlert]} pointerEvents="none">
279
+ <Text style={styles.currencyCode}>USD</Text>
280
+ <Icon name={IconName.DropdownArrow} size={spacing.base} decorative />
281
+ </View>
282
+ ) : null}
283
+
284
+ {showToggle ? (
285
+ <View style={styles.passwordToggle}>
286
+ <Button
287
+ label=""
288
+ variant={ButtonVariant.LinkGray}
289
+ size={ButtonSize.Small}
290
+ disabled={disabled}
291
+ iconName={passwordVisible ? IconName.EyeOff : IconName.Eye}
292
+ iconDecorative
293
+ accessibilityLabel={passwordVisible ? 'Hide password' : 'Show password'}
294
+ onPress={() => {
295
+ if (!disabled) {
296
+ setPasswordVisible((visible) => !visible);
297
+ }
298
+ }}
299
+ />
300
+ </View>
301
+ ) : null}
302
+
303
+ <TextInput
304
+ nativeID={inputId}
305
+ value={text}
306
+ onChangeText={setText}
307
+ onFocus={() => {
308
+ setFocused(true);
309
+ onFocus?.();
310
+ }}
311
+ onKeyPress={onKeyPress}
312
+ onBlur={() => {
313
+ setFocused(false);
314
+ onBlur?.();
315
+ }}
316
+ placeholder={placeholder}
317
+ placeholderTextColor={
318
+ datepickerFieldNativeLook ? colors.datepicker.fieldLabelMuted : colors.input.placeholder
319
+ }
320
+ editable={!disabled && !readOnly}
321
+ secureTextEntry={secure}
322
+ autoComplete={autoComplete}
323
+ accessibilityLabel={accessibilityLabel || label}
324
+ keyboardType={keyboardType}
325
+ cursorColor={colors.focus}
326
+ selectionColor={colors.focus}
327
+ underlineColorAndroid="transparent"
328
+ style={[
329
+ styles.input,
330
+ isAddon && styles.addonInput,
331
+ datepickerFieldNativeLook && styles.datepickerInput,
332
+ fullWidth && !datepickerFieldNativeLook && styles.fullWidth,
333
+ !datepickerFieldNativeLook && { paddingLeft, paddingRight },
334
+ Platform.OS === 'web' ? webInputReset : null,
335
+ ]}
336
+ />
337
+ </View>
338
+ </View>
339
+
340
+ {suppressHintError ? null : <HintError hint={hint} error={error} />}
341
+ </View>
342
+ );
343
+ }
344
+
345
+ const webInputReset = {
346
+ outlineStyle: 'solid',
347
+ outlineWidth: borders.width.none,
348
+ outlineColor: colors.transparent,
349
+ } as TextStyle;
350
+
351
+ const styles = StyleSheet.create({
352
+ wrapper: {
353
+ width: FIELD_WIDTH + (borders.width.thick + borders.focusRing.width) * 2,
354
+ position: 'relative',
355
+ overflow: 'visible',
356
+ },
357
+ fullWidth: {
358
+ width: '100%',
359
+ maxWidth: '100%',
360
+ paddingHorizontal: borders.width.thick + borders.focusRing.width,
361
+ },
362
+ fieldHost: {
363
+ position: 'relative',
364
+ width: FIELD_WIDTH,
365
+ marginHorizontal: borders.width.thick + borders.focusRing.width,
366
+ overflow: 'visible',
367
+ },
368
+ fieldHostFullWidth: {
369
+ width: '100%',
370
+ marginHorizontal: spacing.none,
371
+ },
372
+ datepickerWrapper: {
373
+ width: '100%',
374
+ maxWidth: '100%',
375
+ },
376
+ datepickerHost: {
377
+ width: '100%',
378
+ height: FIELD_HEIGHT,
379
+ marginHorizontal: spacing.none,
380
+ },
381
+ fieldShell: {
382
+ position: 'relative',
383
+ width: FIELD_WIDTH,
384
+ height: FIELD_HEIGHT,
385
+ borderWidth: borders.width.thin,
386
+ borderRadius: radius.md,
387
+ backgroundColor: colors.white,
388
+ zIndex: 1,
389
+ overflow: 'visible',
390
+ },
391
+ addonShell: {
392
+ position: 'relative',
393
+ width: FIELD_WIDTH,
394
+ height: FIELD_HEIGHT,
395
+ borderWidth: borders.width.thin,
396
+ borderRadius: radius.md,
397
+ backgroundColor: colors.white,
398
+ overflow: 'hidden',
399
+ zIndex: 1,
400
+ },
401
+ datepickerShell: {
402
+ position: 'relative',
403
+ width: '100%',
404
+ height: FIELD_HEIGHT,
405
+ minWidth: spacing.none,
406
+ justifyContent: 'center',
407
+ backgroundColor: colors.transparent,
408
+ },
409
+ input: {
410
+ width: '100%',
411
+ height: FIELD_HEIGHT,
412
+ paddingVertical: buttonTokens.paddingY.xl,
413
+ fontSize: typography.fontSize.base,
414
+ lineHeight: typography.fontSize.base * typography.lineHeight.normal,
415
+ color: colors.input.text,
416
+ fontFamily: typography.fontFamily.base,
417
+ },
418
+ addonInput: {
419
+ borderWidth: borders.width.none,
420
+ },
421
+ datepickerInput: {
422
+ width: '100%',
423
+ minWidth: spacing.none,
424
+ height: FIELD_HEIGHT,
425
+ minHeight: FIELD_HEIGHT,
426
+ paddingVertical: spacing.none,
427
+ paddingHorizontal: spacing.none,
428
+ borderWidth: borders.width.none,
429
+ borderRadius: radius.none,
430
+ backgroundColor: colors.transparent,
431
+ textAlignVertical: 'center',
432
+ },
433
+ disabled: {
434
+ opacity: 0.7,
435
+ },
436
+ leftIcon: {
437
+ position: 'absolute',
438
+ left: spacing.base + spacing.xs,
439
+ top: spacing.none,
440
+ bottom: spacing.none,
441
+ justifyContent: 'center',
442
+ zIndex: 1,
443
+ },
444
+ rightIcon: {
445
+ position: 'absolute',
446
+ right: spacing.base + spacing.xs,
447
+ top: spacing.none,
448
+ bottom: spacing.none,
449
+ justifyContent: 'center',
450
+ zIndex: 2,
451
+ },
452
+ rightIconCurrencyAlert: {
453
+ right: spacing['7xl'] + spacing['6xl'],
454
+ },
455
+ passwordToggle: {
456
+ position: 'absolute',
457
+ right: buttonTokens.paddingY.xl,
458
+ top: spacing.none,
459
+ bottom: spacing.none,
460
+ justifyContent: 'center',
461
+ zIndex: 2,
462
+ },
463
+ currencyPrefix: {
464
+ position: 'absolute',
465
+ left: spacing.base + spacing.xs,
466
+ top: spacing.none,
467
+ bottom: spacing.none,
468
+ textAlignVertical: 'center',
469
+ fontSize: typography.fontSize.base,
470
+ lineHeight: FIELD_HEIGHT,
471
+ color: colors.input.placeholder,
472
+ zIndex: 1,
473
+ },
474
+ currencySuffix: {
475
+ position: 'absolute',
476
+ right: spacing.base + spacing.xs,
477
+ top: spacing.none,
478
+ bottom: spacing.none,
479
+ flexDirection: 'row',
480
+ alignItems: 'center',
481
+ gap: spacing.sm,
482
+ zIndex: 1,
483
+ },
484
+ currencySuffixAlert: {
485
+ right: spacing['6xl'],
486
+ },
487
+ currencyCode: {
488
+ fontSize: typography.fontSize.base,
489
+ color: colors.input.text,
490
+ },
491
+ phonePrefix: {
492
+ position: 'absolute',
493
+ left: spacing.base + spacing.xs,
494
+ top: spacing.none,
495
+ bottom: spacing.none,
496
+ flexDirection: 'row',
497
+ alignItems: 'center',
498
+ gap: spacing.sm + spacing.xs,
499
+ zIndex: 1,
500
+ },
501
+ phoneCode: {
502
+ fontSize: typography.fontSize.base,
503
+ color: colors.input.text,
504
+ },
505
+ addonPrefix: {
506
+ position: 'absolute',
507
+ left: spacing.base + spacing.xs,
508
+ top: spacing.none,
509
+ bottom: spacing.none,
510
+ textAlignVertical: 'center',
511
+ lineHeight: FIELD_HEIGHT,
512
+ fontSize: typography.fontSize.base,
513
+ color: colors.input.placeholder,
514
+ zIndex: 2,
515
+ backgroundColor: colors.white,
516
+ paddingRight: spacing.md,
517
+ },
518
+ addonRule: {
519
+ position: 'absolute',
520
+ left: spacing['7xl'] + spacing['2xl'],
521
+ top: spacing.none,
522
+ bottom: spacing.none,
523
+ width: borders.width.thin,
524
+ backgroundColor: colors.input.border,
525
+ zIndex: 1,
526
+ },
527
+ });
@@ -0,0 +1,2 @@
1
+ export { InputField, InputVariant, InputState } from './InputField';
2
+ export type { InputFieldProps } from './InputField';
@@ -0,0 +1,88 @@
1
+ import { StyleSheet, Text, View, type StyleProp, type TextStyle, type ViewStyle } from 'react-native';
2
+
3
+ import { colors, typography } from '../../theme';
4
+ import { a11yHiddenProps } from '../../utils/a11y';
5
+
6
+ export type LabelProps = {
7
+ text?: string;
8
+ supportingText?: string;
9
+ required?: boolean;
10
+ embedded?: boolean;
11
+ htmlFor?: string;
12
+ style?: StyleProp<ViewStyle>;
13
+ labelStyle?: StyleProp<TextStyle>;
14
+ supportingStyle?: StyleProp<TextStyle>;
15
+ };
16
+
17
+ function RequiredMark() {
18
+ return (
19
+ <Text style={styles.required} {...a11yHiddenProps()}>
20
+ *
21
+ </Text>
22
+ );
23
+ }
24
+
25
+ export function Label({
26
+ text,
27
+ supportingText,
28
+ required = false,
29
+ embedded = false,
30
+ htmlFor,
31
+ style,
32
+ labelStyle,
33
+ supportingStyle,
34
+ }: LabelProps) {
35
+ const showMain = Boolean(text) && (!embedded || Boolean(htmlFor) || !htmlFor);
36
+ const showSupporting = Boolean(supportingText) && (!embedded || Boolean(htmlFor) || !htmlFor);
37
+
38
+ if (!showMain && !showSupporting) {
39
+ return null;
40
+ }
41
+
42
+ return (
43
+ <View
44
+ style={[styles.host, embedded && htmlFor && styles.ghost, style]}
45
+ nativeID={htmlFor ? `${htmlFor}-label` : undefined}>
46
+ {showMain ? (
47
+ <Text style={[styles.label, embedded && styles.embeddedLabel, labelStyle]}>
48
+ {text}
49
+ {required ? <RequiredMark /> : null}
50
+ </Text>
51
+ ) : null}
52
+ {showSupporting ? <Text style={[styles.supporting, supportingStyle]}>{supportingText}</Text> : null}
53
+ </View>
54
+ );
55
+ }
56
+
57
+ const styles = StyleSheet.create({
58
+ host: {
59
+ flexDirection: 'column',
60
+ alignItems: 'flex-start',
61
+ gap: 2,
62
+ minWidth: 0,
63
+ },
64
+ ghost: {
65
+ gap: 2,
66
+ },
67
+ label: {
68
+ fontSize: typography.fontSize.sm,
69
+ lineHeight: typography.fontSize.sm * typography.lineHeight.tight,
70
+ color: colors.input.label,
71
+ marginBottom: 6,
72
+ fontFamily: typography.fontFamily.base,
73
+ },
74
+ embeddedLabel: {
75
+ marginBottom: 0,
76
+ },
77
+ required: {
78
+ color: colors.danger.dark,
79
+ fontWeight: typography.fontWeight.semibold,
80
+ paddingLeft: 2,
81
+ },
82
+ supporting: {
83
+ fontSize: typography.fontSize.sm,
84
+ lineHeight: typography.fontSize.sm * typography.lineHeight.tight,
85
+ color: colors.input.label,
86
+ fontFamily: typography.fontFamily.base,
87
+ },
88
+ });
@@ -0,0 +1,2 @@
1
+ export { Label } from './Label';
2
+ export type { LabelProps } from './Label';