@scripso-homepad/ui 0.3.6 → 0.3.8

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 (38) hide show
  1. package/README.md +238 -79
  2. package/dist/index.cjs +1225 -85
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +324 -18
  5. package/dist/index.d.ts +324 -18
  6. package/dist/index.js +1204 -89
  7. package/dist/index.js.map +1 -1
  8. package/package.json +18 -6
  9. package/src/components/Button.stories.tsx +77 -57
  10. package/src/components/Button.tsx +154 -123
  11. package/src/components/CountryCodeSelector.stories.tsx +61 -0
  12. package/src/components/CountryCodeSelector.tsx +273 -0
  13. package/src/components/Input.stories.tsx +126 -0
  14. package/src/components/Input.tsx +221 -0
  15. package/src/components/Label.tsx +56 -0
  16. package/src/components/PhoneInput.stories.tsx +85 -0
  17. package/src/components/PhoneInput.tsx +172 -0
  18. package/src/data/countries.ts +98 -0
  19. package/src/icons/ArrowUpRightIcon.tsx +29 -0
  20. package/src/icons/ArrowUpRightIcon.web.tsx +35 -0
  21. package/src/icons/ChevronDownIcon.tsx +29 -0
  22. package/src/icons/ChevronDownIcon.web.tsx +35 -0
  23. package/src/icons/EyeIcon.tsx +36 -0
  24. package/src/icons/EyeIcon.web.tsx +42 -0
  25. package/src/icons/EyeOffIcon.tsx +29 -0
  26. package/src/icons/EyeOffIcon.web.tsx +35 -0
  27. package/src/icons/KeyIcon.tsx +36 -0
  28. package/src/icons/KeyIcon.web.tsx +42 -0
  29. package/src/icons/arrowUpRightPath.ts +2 -0
  30. package/src/icons/chevronDownPath.ts +1 -0
  31. package/src/icons/eyeIconPaths.ts +8 -0
  32. package/src/icons/keyIconPaths.ts +5 -0
  33. package/src/index.ts +42 -0
  34. package/src/theme/input.ts +154 -0
  35. package/src/theme/tokens.ts +272 -0
  36. package/src/utils/countryDropdownScrollStyles.ts +52 -0
  37. package/src/utils/countryFlag.ts +9 -0
  38. package/src/utils/useApplyWebClassName.ts +3 -2
package/dist/index.cjs CHANGED
@@ -2,9 +2,264 @@
2
2
 
3
3
  var react = require('react');
4
4
  var reactNative = require('react-native');
5
+ var Svg = require('react-native-svg');
5
6
  var jsxRuntime = require('react/jsx-runtime');
6
7
 
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var Svg__default = /*#__PURE__*/_interopDefault(Svg);
11
+
7
12
  // src/components/Button.tsx
13
+
14
+ // src/icons/arrowUpRightPath.ts
15
+ var ARROW_UP_RIGHT_PATH = "M14.1667 14.1668V5.8335H5.83333M14.1667 5.8335L5.83333 14.1668";
16
+ function ArrowUpRightIcon({
17
+ size = 20,
18
+ color = "#08275d",
19
+ strokeWidth = 2
20
+ }) {
21
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
22
+ Svg.Path,
23
+ {
24
+ d: ARROW_UP_RIGHT_PATH,
25
+ stroke: color,
26
+ strokeWidth,
27
+ strokeLinecap: "round",
28
+ strokeLinejoin: "round"
29
+ }
30
+ ) });
31
+ }
32
+
33
+ // src/theme/tokens.ts
34
+ var stormGray = {
35
+ "0": "#fbfcfc",
36
+ "0.5": "#eceef0",
37
+ "1": "#dadde0",
38
+ "1.5": "#c7cdd1",
39
+ "2": "#b5bcc1",
40
+ "3": "#8f9aa3",
41
+ "4": "#6a7984",
42
+ "5": "#455765",
43
+ "6": "#374651",
44
+ "7": "#29343d",
45
+ "8": "#1c2328",
46
+ "8.5": "#151a1e"
47
+ };
48
+ var navy = {
49
+ "0": "#f8f9fb",
50
+ "0.5": "#e5e9ef",
51
+ "1": "#cdd3df",
52
+ "1.5": "#b4bece",
53
+ "2": "#9ca8be",
54
+ "3": "#6a7d9e",
55
+ "4": "#39527d",
56
+ "5": "#08275d",
57
+ "6": "#061f4a",
58
+ "7": "#051738",
59
+ "8": "#031025",
60
+ "8.5": "#020c1c"
61
+ };
62
+ var rubyRed = {
63
+ "0": "#fff5f6",
64
+ "0.5": "#f7dddf",
65
+ "1": "#efc4c8",
66
+ "1.5": "#e7acb1",
67
+ "2": "#df939a",
68
+ "3": "#ce626d",
69
+ "4": "#be313f",
70
+ "5": "#ae0011",
71
+ "6": "#8b000e",
72
+ "7": "#68000a",
73
+ "8": "#460007",
74
+ "8.5": "#340005"
75
+ };
76
+ var emeraldGreen = {
77
+ "0": "#f0fbf5",
78
+ "0.5": "#dcf2e5",
79
+ "1": "#c8e8d5",
80
+ "1.5": "#b4dfc5",
81
+ "2": "#a0d5b5",
82
+ "3": "#77c394",
83
+ "4": "#4fb074",
84
+ "5": "#279d54",
85
+ "6": "#1f7e43",
86
+ "7": "#175e32",
87
+ "8": "#103f22",
88
+ "8.5": "#0c2f19"
89
+ };
90
+ var brand = {
91
+ slateBlue: "#182e3c",
92
+ stormGray: stormGray["5"],
93
+ navy: navy["5"],
94
+ rubyRed: rubyRed["5"],
95
+ emeraldGreen: emeraldGreen["5"]
96
+ };
97
+ var colors = {
98
+ // Brand colors
99
+ slateBlue: brand.slateBlue,
100
+ // Emerald Green — Figma scale + brand swatch
101
+ emeraldGreen0: emeraldGreen["0"],
102
+ emeraldGreen50: emeraldGreen["0.5"],
103
+ emeraldGreen100: emeraldGreen["1"],
104
+ emeraldGreen150: emeraldGreen["1.5"],
105
+ emeraldGreen200: emeraldGreen["2"],
106
+ emeraldGreen300: emeraldGreen["3"],
107
+ emeraldGreen400: emeraldGreen["4"],
108
+ emeraldGreen500: emeraldGreen["5"],
109
+ emeraldGreen600: emeraldGreen["6"],
110
+ emeraldGreen700: emeraldGreen["7"],
111
+ emeraldGreen800: emeraldGreen["8"],
112
+ emeraldGreen850: emeraldGreen["8.5"],
113
+ /** Primary brand emerald green — Figma Emerald Green 5 */
114
+ emeraldGreen: brand.emeraldGreen,
115
+ // Ruby Red — Figma scale + brand swatch
116
+ rubyRed0: rubyRed["0"],
117
+ rubyRed50: rubyRed["0.5"],
118
+ rubyRed100: rubyRed["1"],
119
+ rubyRed150: rubyRed["1.5"],
120
+ rubyRed200: rubyRed["2"],
121
+ rubyRed300: rubyRed["3"],
122
+ rubyRed400: rubyRed["4"],
123
+ rubyRed500: rubyRed["5"],
124
+ rubyRed600: rubyRed["6"],
125
+ rubyRed700: rubyRed["7"],
126
+ rubyRed800: rubyRed["8"],
127
+ rubyRed850: rubyRed["8.5"],
128
+ /** Primary brand ruby red — Figma Ruby Red 5 */
129
+ rubyRed: brand.rubyRed,
130
+ // Navy — Figma scale + brand swatch
131
+ navy0: navy["0"],
132
+ navy50: navy["0.5"],
133
+ navy100: navy["1"],
134
+ navy150: navy["1.5"],
135
+ navy200: navy["2"],
136
+ navy300: navy["3"],
137
+ navy400: navy["4"],
138
+ navy500: navy["5"],
139
+ navy600: navy["6"],
140
+ navy700: navy["7"],
141
+ navy800: navy["8"],
142
+ navy850: navy["8.5"],
143
+ /** Primary brand navy — Figma Navy 5 */
144
+ navy: brand.navy,
145
+ // Storm Gray — Figma scale + brand swatch
146
+ stormGray0: stormGray["0"],
147
+ stormGray50: stormGray["0.5"],
148
+ stormGray100: stormGray["1"],
149
+ stormGray150: stormGray["1.5"],
150
+ stormGray200: stormGray["2"],
151
+ stormGray300: stormGray["3"],
152
+ stormGray400: stormGray["4"],
153
+ stormGray500: stormGray["5"],
154
+ /** Figma brand swatch "Storm Gray" — same as `stormGray500` */
155
+ stormGrayBrand: brand.stormGray,
156
+ stormGray600: stormGray["6"],
157
+ stormGray700: stormGray["7"],
158
+ stormGray800: stormGray["8"],
159
+ stormGray850: stormGray["8.5"],
160
+ /** @deprecated Use `stormGray0` */
161
+ storm0: stormGray["0"],
162
+ /** @deprecated Use `stormGray50` */
163
+ storm50: stormGray["0.5"],
164
+ /** @deprecated Use `stormGray200` */
165
+ storm200: stormGray["2"],
166
+ /** @deprecated Use `stormGray300` */
167
+ storm300: stormGray["3"],
168
+ /** @deprecated Use `stormGray500` */
169
+ storm500: stormGray["5"],
170
+ /** @deprecated Use `stormGray700` */
171
+ storm700: stormGray["7"],
172
+ /** @deprecated Use `stormGray850` */
173
+ storm900: stormGray["8.5"],
174
+ countrySelectorSelectedBg: `${stormGray["0.5"]}99`,
175
+ white: "#ffffff",
176
+ error: "#dc2626",
177
+ errorDark: "#b3261e",
178
+ errorLight: "#fee2e2",
179
+ /** @deprecated Use `rubyRed` */
180
+ inputError: brand.rubyRed,
181
+ inputOutlineFocus: navy["0.5"],
182
+ inputOutlineError: rubyRed["0.5"],
183
+ warning: "#92400e",
184
+ warningBg: "#fef3c7",
185
+ success: "#28a745",
186
+ successMuted: "#9fd4a8",
187
+ /** @deprecated Use `emeraldGreen` */
188
+ green: brand.emeraldGreen,
189
+ transparent: "transparent"
190
+ };
191
+ var radii = {
192
+ sm: 8,
193
+ md: 12,
194
+ lg: 16,
195
+ xl: 20,
196
+ full: 9999
197
+ };
198
+ var spacing = {
199
+ xs: 4,
200
+ sm: 8,
201
+ md: 12,
202
+ lg: 16,
203
+ xl: 24,
204
+ xxl: 32
205
+ };
206
+ var fontSize = {
207
+ xs: 11,
208
+ sm: 12,
209
+ md: 14,
210
+ base: 16,
211
+ lg: 18,
212
+ xl: 24,
213
+ xxl: 32
214
+ };
215
+ var fontWeight = {
216
+ regular: "400",
217
+ medium: "500",
218
+ semibold: "600",
219
+ bold: "700"
220
+ };
221
+ var fonts = {
222
+ sans: "Noto Sans Armenian"
223
+ };
224
+ var labelTypography = {
225
+ fontFamily: fonts.sans,
226
+ fontSize: fontSize.sm,
227
+ fontWeight: fontWeight.medium,
228
+ lineHeight: fontSize.sm,
229
+ letterSpacing: 0
230
+ };
231
+ var buttonTypography = {
232
+ lg: {
233
+ fontFamily: fonts.sans,
234
+ fontSize: 14,
235
+ fontWeight: fontWeight.semibold,
236
+ lineHeight: 18,
237
+ letterSpacing: 0
238
+ },
239
+ sm: {
240
+ fontFamily: fonts.sans,
241
+ fontSize: 12,
242
+ fontWeight: fontWeight.semibold,
243
+ lineHeight: 16,
244
+ letterSpacing: 0
245
+ }
246
+ };
247
+ var shadows = {
248
+ card: {
249
+ shadowColor: colors.navy,
250
+ shadowOffset: { width: 0, height: 4 },
251
+ shadowOpacity: 0.05,
252
+ shadowRadius: 20,
253
+ elevation: 2
254
+ },
255
+ cardLg: {
256
+ shadowColor: colors.navy,
257
+ shadowOffset: { width: 0, height: 4 },
258
+ shadowOpacity: 0.1,
259
+ shadowRadius: 20,
260
+ elevation: 4
261
+ }
262
+ };
8
263
  function hasClassList(node) {
9
264
  return typeof node === "object" && node !== null && "classList" in node && typeof node.classList?.add === "function";
10
265
  }
@@ -20,9 +275,9 @@ function resolveWebElement(ref) {
20
275
  }
21
276
  return null;
22
277
  }
23
- function useApplyWebClassName(ref, className) {
278
+ function useApplyWebClassName(ref, className, enabled = true) {
24
279
  react.useLayoutEffect(() => {
25
- if (reactNative.Platform.OS !== "web" || !className?.trim()) return;
280
+ if (!enabled || reactNative.Platform.OS !== "web" || !className?.trim()) return;
26
281
  const element = resolveWebElement(ref);
27
282
  if (!element) return;
28
283
  const classes = className.trim().split(/\s+/);
@@ -30,14 +285,73 @@ function useApplyWebClassName(ref, className) {
30
285
  return () => {
31
286
  element.classList.remove(...classes);
32
287
  };
33
- }, [ref, className]);
288
+ }, [ref, className, enabled]);
34
289
  }
290
+ var variantConfig = {
291
+ white: {
292
+ backgroundColor: colors.white,
293
+ textColor: colors.slateBlue,
294
+ iconBadgeBackgroundColor: colors.stormGray150,
295
+ iconColor: colors.navy
296
+ },
297
+ primary: {
298
+ backgroundColor: colors.navy,
299
+ textColor: colors.stormGray0,
300
+ iconBadgeBackgroundColor: colors.white,
301
+ iconColor: colors.navy
302
+ },
303
+ green: {
304
+ backgroundColor: colors.green,
305
+ textColor: colors.stormGray0,
306
+ iconBadgeBackgroundColor: colors.white,
307
+ iconColor: colors.green
308
+ },
309
+ gray: {
310
+ backgroundColor: colors.stormGray50,
311
+ textColor: colors.slateBlue,
312
+ iconBadgeBackgroundColor: colors.stormGray150,
313
+ iconColor: colors.navy
314
+ }
315
+ };
316
+ var sizeConfig = {
317
+ lg: {
318
+ borderRadius: 16,
319
+ paddingTop: 8,
320
+ paddingRight: 8,
321
+ paddingBottom: 8,
322
+ paddingLeft: 24,
323
+ paddingHorizontalCentered: 24,
324
+ minHeight: 52,
325
+ text: buttonTypography.lg,
326
+ iconContainerSize: 36,
327
+ iconContainerRadius: 12,
328
+ iconContainerPadding: 8,
329
+ iconSize: 20
330
+ },
331
+ sm: {
332
+ borderRadius: 12,
333
+ paddingTop: 8,
334
+ paddingRight: 8,
335
+ paddingBottom: 8,
336
+ paddingLeft: 16,
337
+ paddingHorizontalCentered: 16,
338
+ minHeight: 48,
339
+ text: buttonTypography.sm,
340
+ iconContainerSize: 32,
341
+ iconContainerRadius: 8,
342
+ iconContainerPadding: 8,
343
+ iconSize: 16
344
+ }
345
+ };
35
346
  function Button({
36
347
  title,
348
+ children,
37
349
  onPress,
38
350
  disabled = false,
39
351
  variant = "primary",
40
- size = "medium",
352
+ size = "lg",
353
+ showIcon = false,
354
+ icon,
41
355
  style,
42
356
  textStyle,
43
357
  className,
@@ -45,23 +359,40 @@ function Button({
45
359
  }) {
46
360
  const containerRef = react.useRef(null);
47
361
  const textRef = react.useRef(null);
362
+ const preset = variantConfig[variant];
363
+ const metrics = sizeConfig[size];
48
364
  useApplyWebClassName(containerRef, className);
49
365
  useApplyWebClassName(textRef, textClassName);
366
+ const label = typeof children !== "undefined" ? children : title;
367
+ const hasCustomChildren = typeof children !== "undefined";
368
+ const customIcon = icon != null && typeof icon !== "boolean" ? icon : void 0;
369
+ const hasIcon = showIcon || icon === true || customIcon != null;
370
+ const iconNode = customIcon ?? /* @__PURE__ */ jsxRuntime.jsx(ArrowUpRightIcon, { size: metrics.iconSize, color: preset.iconColor });
50
371
  const containerStyle = [
51
372
  styles.base,
52
- variantStyles[variant],
53
- sizeStyles[size],
54
- disabled && disabledVariantStyles[variant],
373
+ {
374
+ borderRadius: metrics.borderRadius,
375
+ backgroundColor: preset.backgroundColor,
376
+ minHeight: metrics.minHeight,
377
+ paddingTop: metrics.paddingTop,
378
+ paddingBottom: metrics.paddingBottom,
379
+ paddingLeft: hasIcon ? metrics.paddingLeft : metrics.paddingHorizontalCentered,
380
+ paddingRight: hasIcon ? metrics.paddingRight : metrics.paddingHorizontalCentered
381
+ },
382
+ hasIcon ? styles.withIcon : styles.centered,
383
+ disabled && styles.disabled,
55
384
  style
56
385
  ];
57
386
  const labelStyle = [
58
- textBaseStyles.base,
59
- textVariantStyles[variant],
60
- textSizeStyles[size],
61
- disabled && textDisabledStyles[variant],
387
+ styles.label,
388
+ metrics.text,
389
+ { color: preset.textColor },
390
+ reactNative.Platform.OS === "android" ? styles.labelAndroid : null,
391
+ !hasIcon && styles.labelCentered,
392
+ hasIcon && styles.labelWithIcon,
62
393
  textStyle
63
394
  ];
64
- return /* @__PURE__ */ jsxRuntime.jsx(
395
+ return /* @__PURE__ */ jsxRuntime.jsxs(
65
396
  reactNative.TouchableOpacity,
66
397
  {
67
398
  ref: containerRef,
@@ -71,113 +402,922 @@ function Button({
71
402
  activeOpacity: 0.7,
72
403
  accessibilityRole: "button",
73
404
  accessibilityState: { disabled },
74
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: textRef, style: labelStyle, children: title })
405
+ children: [
406
+ hasCustomChildren ? children : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: textRef, style: labelStyle, children: label }),
407
+ hasIcon ? /* @__PURE__ */ jsxRuntime.jsx(
408
+ reactNative.View,
409
+ {
410
+ style: [
411
+ styles.iconContainer,
412
+ {
413
+ width: metrics.iconContainerSize,
414
+ height: metrics.iconContainerSize,
415
+ borderRadius: metrics.iconContainerRadius,
416
+ padding: metrics.iconContainerPadding,
417
+ backgroundColor: preset.iconBadgeBackgroundColor
418
+ }
419
+ ],
420
+ children: iconNode
421
+ }
422
+ ) : null
423
+ ]
75
424
  }
76
425
  );
77
426
  }
78
427
  var styles = reactNative.StyleSheet.create({
79
428
  base: {
429
+ flexDirection: "row",
80
430
  alignItems: "center",
81
- justifyContent: "center",
82
- borderRadius: 8,
83
431
  borderWidth: 0
84
- }
85
- });
86
- var variantStyles = reactNative.StyleSheet.create({
87
- primary: {
88
- backgroundColor: "#2563eb"
89
432
  },
90
- secondary: {
91
- backgroundColor: "#4b5563"
433
+ centered: {
434
+ justifyContent: "center"
92
435
  },
93
- outline: {
94
- backgroundColor: "transparent",
95
- borderWidth: 1,
96
- borderColor: "#2563eb"
436
+ withIcon: {
437
+ justifyContent: "space-between"
97
438
  },
98
- ghost: {
99
- backgroundColor: "transparent"
439
+ disabled: {
440
+ opacity: 0.6
441
+ },
442
+ label: {},
443
+ labelAndroid: {
444
+ includeFontPadding: false
445
+ },
446
+ labelCentered: {
447
+ textAlign: "center"
448
+ },
449
+ labelWithIcon: {
450
+ flex: 1,
451
+ flexShrink: 1,
452
+ marginRight: 8
453
+ },
454
+ iconContainer: {
455
+ alignItems: "center",
456
+ justifyContent: "center",
457
+ flexShrink: 0
100
458
  }
101
459
  });
102
- var sizeStyles = reactNative.StyleSheet.create({
103
- small: {
104
- paddingVertical: 8,
105
- paddingHorizontal: 16,
106
- minWidth: 96
107
- },
108
- medium: {
109
- paddingVertical: 12,
110
- paddingHorizontal: 24,
111
- minWidth: 120
112
- },
113
- large: {
114
- paddingVertical: 16,
115
- paddingHorizontal: 32,
116
- minWidth: 160
460
+
461
+ // src/icons/eyeIconPaths.ts
462
+ var EYE_OPEN_OUTLINE_PATH = "M1.71835 10.2898C1.6489 10.1027 1.6489 9.89691 1.71835 9.70981C2.39476 8.06969 3.54294 6.66735 5.01732 5.68056C6.4917 4.69378 8.22588 4.16699 10 4.16699C11.7741 4.16699 13.5083 4.69378 14.9827 5.68056C16.4571 6.66735 17.6053 8.06969 18.2817 9.70981C18.3511 9.89691 18.3511 10.1027 18.2817 10.2898C17.6053 11.9299 16.4571 13.3323 14.9827 14.3191C13.5083 15.3058 11.7741 15.8326 10 15.8326C8.22588 15.8326 6.4917 15.3058 5.01732 14.3191C3.54294 13.3323 2.39476 11.9299 1.71835 10.2898Z";
463
+ var EYE_OPEN_PUPIL_PATH = "M10 12.4998C11.3807 12.4998 12.5 11.3805 12.5 9.99981C12.5 8.6191 11.3807 7.49981 10 7.49981C8.6193 7.49981 7.50001 8.6191 7.50001 9.99981C7.50001 11.3805 8.6193 12.4998 10 12.4998Z";
464
+ var EYE_OFF_PATH = "M10.733 5.076C13.0624 4.7984 15.4186 5.29082 17.4419 6.47805C19.4651 7.66528 21.0442 9.48208 21.938 11.651C22.0213 11.8755 22.0213 12.1225 21.938 12.347C21.5705 13.238 21.0848 14.0755 20.494 14.837M14.084 14.158C13.5182 14.7045 12.7604 15.0069 11.9738 15C11.1872 14.9932 10.4348 14.6777 9.87854 14.1215C9.32232 13.5652 9.00681 12.8128 8.99998 12.0262C8.99314 11.2396 9.29553 10.4818 9.842 9.916M17.479 17.499C16.1525 18.2848 14.6725 18.776 13.1394 18.9394C11.6063 19.1028 10.056 18.9345 8.59363 18.4459C7.13131 17.9573 5.79119 17.1599 4.66421 16.1077C3.53723 15.0556 2.64975 13.7734 2.062 12.348C1.97866 12.1235 1.97866 11.8765 2.062 11.652C2.94863 9.50186 4.50867 7.69725 6.508 6.509M2 2L22 22";
465
+ function EyeIcon({
466
+ size = 20,
467
+ color = "#c7cdd1",
468
+ strokeWidth = 2
469
+ }) {
470
+ return /* @__PURE__ */ jsxRuntime.jsxs(Svg__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: [
471
+ /* @__PURE__ */ jsxRuntime.jsx(
472
+ Svg.Path,
473
+ {
474
+ d: EYE_OPEN_OUTLINE_PATH,
475
+ stroke: color,
476
+ strokeWidth,
477
+ strokeLinecap: "round",
478
+ strokeLinejoin: "round"
479
+ }
480
+ ),
481
+ /* @__PURE__ */ jsxRuntime.jsx(
482
+ Svg.Path,
483
+ {
484
+ d: EYE_OPEN_PUPIL_PATH,
485
+ stroke: color,
486
+ strokeWidth,
487
+ strokeLinecap: "round",
488
+ strokeLinejoin: "round"
489
+ }
490
+ )
491
+ ] });
492
+ }
493
+ function EyeOffIcon({
494
+ size = 20,
495
+ color = "#c7cdd1",
496
+ strokeWidth = 2
497
+ }) {
498
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
499
+ Svg.Path,
500
+ {
501
+ d: EYE_OFF_PATH,
502
+ stroke: color,
503
+ strokeWidth,
504
+ strokeLinecap: "round",
505
+ strokeLinejoin: "round"
506
+ }
507
+ ) });
508
+ }
509
+ var INPUT_HEIGHT = 52;
510
+ var INPUT_ICON_SIZE = 20;
511
+ var INPUT_ICON_GAP = 10;
512
+ var INPUT_OUTLINE_WIDTH = 2;
513
+ function resolveInputVisualState({
514
+ focused = false,
515
+ error = false,
516
+ disabled = false
517
+ }) {
518
+ if (disabled) return "disabled";
519
+ if (error) return "error";
520
+ if (focused) return "focused";
521
+ return "default";
522
+ }
523
+ function createOutlineStyle(ringColor) {
524
+ return {
525
+ borderRadius: radii.lg + INPUT_OUTLINE_WIDTH,
526
+ borderWidth: INPUT_OUTLINE_WIDTH,
527
+ borderColor: ringColor,
528
+ padding: 0,
529
+ backgroundColor: colors.transparent,
530
+ width: "100%",
531
+ alignSelf: "stretch",
532
+ ...reactNative.Platform.OS !== "web" ? { overflow: "hidden" } : null
533
+ };
534
+ }
535
+ var defaultOutline = createOutlineStyle(colors.transparent);
536
+ function getInputFieldStyles(state) {
537
+ const containerBase = {
538
+ borderRadius: radii.lg,
539
+ ...reactNative.Platform.OS !== "web" ? { overflow: "hidden" } : null
540
+ };
541
+ switch (state) {
542
+ case "disabled":
543
+ return {
544
+ outline: defaultOutline,
545
+ container: {
546
+ ...containerBase,
547
+ borderWidth: 1,
548
+ borderColor: colors.stormGray50,
549
+ backgroundColor: colors.stormGray50
550
+ },
551
+ text: { color: colors.stormGray300 },
552
+ placeholder: colors.stormGray300,
553
+ icon: colors.stormGray150
554
+ };
555
+ case "error":
556
+ return {
557
+ outline: createOutlineStyle(colors.inputOutlineError),
558
+ container: {
559
+ ...containerBase,
560
+ borderWidth: 1,
561
+ borderColor: colors.inputError,
562
+ backgroundColor: colors.white
563
+ },
564
+ text: { color: colors.inputError },
565
+ placeholder: colors.stormGray200,
566
+ icon: colors.inputError
567
+ };
568
+ case "focused":
569
+ return {
570
+ outline: createOutlineStyle(colors.inputOutlineFocus),
571
+ container: {
572
+ ...containerBase,
573
+ borderWidth: 1,
574
+ borderColor: colors.navy,
575
+ backgroundColor: colors.white
576
+ },
577
+ text: { color: colors.slateBlue },
578
+ placeholder: colors.stormGray200,
579
+ icon: colors.navy
580
+ };
581
+ default:
582
+ return {
583
+ outline: defaultOutline,
584
+ container: {
585
+ ...containerBase,
586
+ borderWidth: 1,
587
+ borderColor: colors.stormGray50,
588
+ backgroundColor: colors.white
589
+ },
590
+ text: { color: colors.slateBlue },
591
+ placeholder: colors.stormGray200,
592
+ icon: colors.stormGray150
593
+ };
117
594
  }
118
- });
119
- var disabledVariantStyles = reactNative.StyleSheet.create({
120
- primary: {
121
- backgroundColor: "#93c5fd",
122
- opacity: 0.7
595
+ }
596
+ var inputFieldMetrics = reactNative.StyleSheet.create({
597
+ container: {
598
+ flexDirection: "row",
599
+ alignItems: "center",
600
+ height: INPUT_HEIGHT,
601
+ minHeight: INPUT_HEIGHT,
602
+ maxHeight: INPUT_HEIGHT,
603
+ borderRadius: radii.lg,
604
+ padding: 16,
605
+ gap: INPUT_ICON_GAP,
606
+ ...reactNative.Platform.OS === "web" ? { boxSizing: "border-box" } : null
123
607
  },
124
- secondary: {
125
- backgroundColor: "#9ca3af",
126
- opacity: 0.7
608
+ input: {
609
+ flex: 1,
610
+ alignSelf: "stretch",
611
+ fontFamily: fonts.sans,
612
+ fontSize: fontSize.md,
613
+ fontWeight: fontWeight.medium,
614
+ lineHeight: reactNative.Platform.OS === "web" ? fontSize.md : 20,
615
+ paddingVertical: 0,
616
+ paddingHorizontal: 0,
617
+ margin: 0,
618
+ borderWidth: 0,
619
+ backgroundColor: colors.transparent,
620
+ ...reactNative.Platform.OS === "android" ? { includeFontPadding: false } : null,
621
+ ...reactNative.Platform.OS === "web" ? {
622
+ height: "100%",
623
+ minHeight: 0,
624
+ outlineStyle: "none"
625
+ } : null
626
+ }
627
+ });
628
+ function Label({
629
+ children,
630
+ required = false,
631
+ disabled = false,
632
+ style,
633
+ className,
634
+ ...props
635
+ }) {
636
+ const ref = react.useRef(null);
637
+ useApplyWebClassName(ref, className);
638
+ return /* @__PURE__ */ jsxRuntime.jsxs(
639
+ reactNative.Text,
640
+ {
641
+ ref,
642
+ style: [styles2.label, disabled && styles2.labelDisabled, style],
643
+ accessibilityRole: "text",
644
+ ...props,
645
+ children: [
646
+ children,
647
+ required ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles2.required, children: " *" }) : null
648
+ ]
649
+ }
650
+ );
651
+ }
652
+ var styles2 = reactNative.StyleSheet.create({
653
+ label: {
654
+ ...labelTypography,
655
+ color: colors.slateBlue
127
656
  },
128
- outline: {
129
- borderColor: "#93c5fd",
130
- opacity: 0.7
657
+ labelDisabled: {
658
+ color: colors.stormGray400
131
659
  },
132
- ghost: {
133
- opacity: 0.5
660
+ required: {
661
+ color: colors.inputError
134
662
  }
135
663
  });
136
- var textBaseStyles = reactNative.StyleSheet.create({
137
- base: {
138
- fontWeight: "600"
664
+ function renderInputIcon(icon, color) {
665
+ if (!icon) return null;
666
+ if (react.isValidElement(icon)) {
667
+ return react.cloneElement(icon, {
668
+ size: icon.props.size ?? INPUT_ICON_SIZE,
669
+ color: icon.props.color ?? color
670
+ });
139
671
  }
140
- });
141
- var textVariantStyles = reactNative.StyleSheet.create({
142
- primary: {
143
- color: "#ffffff"
672
+ return icon;
673
+ }
674
+ function Input({
675
+ label,
676
+ leftIcon,
677
+ rightIcon,
678
+ error,
679
+ hint,
680
+ containerStyle,
681
+ style,
682
+ className,
683
+ labelClassName,
684
+ inputClassName,
685
+ errorClassName,
686
+ hintClassName,
687
+ editable = true,
688
+ secureTextEntry,
689
+ showPasswordToggle,
690
+ onFocus,
691
+ onBlur,
692
+ ...props
693
+ }) {
694
+ const wrapperRef = react.useRef(null);
695
+ const inputRef = react.useRef(null);
696
+ const helperRef = react.useRef(null);
697
+ const [focused, setFocused] = react.useState(false);
698
+ const [passwordVisible, setPasswordVisible] = react.useState(false);
699
+ useApplyWebClassName(wrapperRef, className);
700
+ useApplyWebClassName(inputRef, inputClassName);
701
+ useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
702
+ const isDisabled = editable === false;
703
+ const passwordToggleEnabled = secureTextEntry === true && showPasswordToggle !== false && rightIcon == null;
704
+ const effectiveSecureTextEntry = passwordToggleEnabled ? !passwordVisible : secureTextEntry;
705
+ const visualState = resolveInputVisualState({
706
+ focused,
707
+ error: Boolean(error),
708
+ disabled: isDisabled
709
+ });
710
+ const fieldStyles = getInputFieldStyles(visualState);
711
+ const iconColor = fieldStyles.icon;
712
+ function handleFocus(event) {
713
+ setFocused(true);
714
+ onFocus?.(event);
715
+ }
716
+ function handleBlur(event) {
717
+ setFocused(false);
718
+ onBlur?.(event);
719
+ }
720
+ const helperMessage = error ?? hint;
721
+ function togglePasswordVisibility() {
722
+ if (!isDisabled) {
723
+ setPasswordVisible((visible) => !visible);
724
+ }
725
+ }
726
+ const trailingIcon = passwordToggleEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
727
+ reactNative.Pressable,
728
+ {
729
+ onPress: togglePasswordVisibility,
730
+ disabled: isDisabled,
731
+ accessibilityRole: "button",
732
+ accessibilityLabel: passwordVisible ? "Hide password" : "Show password",
733
+ hitSlop: 8,
734
+ style: styles3.iconPressable,
735
+ children: renderInputIcon(
736
+ passwordVisible ? /* @__PURE__ */ jsxRuntime.jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(EyeIcon, {}),
737
+ iconColor
738
+ )
739
+ }
740
+ ) : rightIcon ? renderInputIcon(rightIcon, iconColor) : null;
741
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles3.wrapper, containerStyle], children: [
742
+ label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled: isDisabled, className: labelClassName, children: label }) : null,
743
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: fieldStyles.outline, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [inputFieldMetrics.container, fieldStyles.container], children: [
744
+ leftIcon ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.iconSlot, children: renderInputIcon(leftIcon, iconColor) }) : null,
745
+ /* @__PURE__ */ jsxRuntime.jsx(
746
+ reactNative.TextInput,
747
+ {
748
+ ref: inputRef,
749
+ style: [
750
+ inputFieldMetrics.input,
751
+ fieldStyles.text,
752
+ style
753
+ ],
754
+ placeholderTextColor: fieldStyles.placeholder,
755
+ editable,
756
+ secureTextEntry: effectiveSecureTextEntry,
757
+ onFocus: handleFocus,
758
+ onBlur: handleBlur,
759
+ accessibilityState: { disabled: isDisabled },
760
+ ...props
761
+ }
762
+ ),
763
+ trailingIcon ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.iconSlot, children: trailingIcon }) : null
764
+ ] }) }),
765
+ helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles3.error : styles3.hint, children: helperMessage }) : null
766
+ ] });
767
+ }
768
+ var styles3 = reactNative.StyleSheet.create({
769
+ wrapper: {
770
+ width: "100%",
771
+ gap: spacing.sm
144
772
  },
145
- secondary: {
146
- color: "#ffffff"
773
+ iconSlot: {
774
+ width: INPUT_ICON_SIZE,
775
+ height: INPUT_ICON_SIZE,
776
+ alignItems: "center",
777
+ justifyContent: "center",
778
+ flexShrink: 0
147
779
  },
148
- outline: {
149
- color: "#2563eb"
780
+ iconPressable: {
781
+ width: INPUT_ICON_SIZE,
782
+ height: INPUT_ICON_SIZE,
783
+ alignItems: "center",
784
+ justifyContent: "center"
150
785
  },
151
- ghost: {
152
- color: "#2563eb"
786
+ error: {
787
+ fontSize: 12,
788
+ lineHeight: 16,
789
+ color: colors.inputError
790
+ },
791
+ hint: {
792
+ fontSize: 12,
793
+ lineHeight: 16,
794
+ color: colors.stormGray300
153
795
  }
154
796
  });
155
- var textSizeStyles = reactNative.StyleSheet.create({
156
- small: {
157
- fontSize: 14
797
+
798
+ // src/data/countries.ts
799
+ var defaultCountry = {
800
+ code: "AM",
801
+ name: "Armenia",
802
+ dialCode: "+374"
803
+ };
804
+ var countries = [
805
+ defaultCountry,
806
+ { code: "AF", name: "Afghanistan", dialCode: "+93" },
807
+ { code: "AL", name: "Albania", dialCode: "+355" },
808
+ { code: "DZ", name: "Algeria", dialCode: "+213" },
809
+ { code: "AR", name: "Argentina", dialCode: "+54" },
810
+ { code: "AU", name: "Australia", dialCode: "+61" },
811
+ { code: "AT", name: "Austria", dialCode: "+43" },
812
+ { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
813
+ { code: "BH", name: "Bahrain", dialCode: "+973" },
814
+ { code: "BY", name: "Belarus", dialCode: "+375" },
815
+ { code: "BE", name: "Belgium", dialCode: "+32" },
816
+ { code: "BR", name: "Brazil", dialCode: "+55" },
817
+ { code: "BG", name: "Bulgaria", dialCode: "+359" },
818
+ { code: "CA", name: "Canada", dialCode: "+1" },
819
+ { code: "CL", name: "Chile", dialCode: "+56" },
820
+ { code: "CN", name: "China", dialCode: "+86" },
821
+ { code: "CO", name: "Colombia", dialCode: "+57" },
822
+ { code: "HR", name: "Croatia", dialCode: "+385" },
823
+ { code: "CY", name: "Cyprus", dialCode: "+357" },
824
+ { code: "CZ", name: "Czech Republic", dialCode: "+420" },
825
+ { code: "DK", name: "Denmark", dialCode: "+45" },
826
+ { code: "EG", name: "Egypt", dialCode: "+20" },
827
+ { code: "EE", name: "Estonia", dialCode: "+372" },
828
+ { code: "FI", name: "Finland", dialCode: "+358" },
829
+ { code: "FR", name: "France", dialCode: "+33" },
830
+ { code: "GE", name: "Georgia", dialCode: "+995" },
831
+ { code: "DE", name: "Germany", dialCode: "+49" },
832
+ { code: "GR", name: "Greece", dialCode: "+30" },
833
+ { code: "HK", name: "Hong Kong", dialCode: "+852" },
834
+ { code: "HU", name: "Hungary", dialCode: "+36" },
835
+ { code: "IN", name: "India", dialCode: "+91" },
836
+ { code: "ID", name: "Indonesia", dialCode: "+62" },
837
+ { code: "IR", name: "Iran", dialCode: "+98" },
838
+ { code: "IQ", name: "Iraq", dialCode: "+964" },
839
+ { code: "IE", name: "Ireland", dialCode: "+353" },
840
+ { code: "IL", name: "Israel", dialCode: "+972" },
841
+ { code: "IT", name: "Italy", dialCode: "+39" },
842
+ { code: "JP", name: "Japan", dialCode: "+81" },
843
+ { code: "JO", name: "Jordan", dialCode: "+962" },
844
+ { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
845
+ { code: "KW", name: "Kuwait", dialCode: "+965" },
846
+ { code: "LV", name: "Latvia", dialCode: "+371" },
847
+ { code: "LB", name: "Lebanon", dialCode: "+961" },
848
+ { code: "LT", name: "Lithuania", dialCode: "+370" },
849
+ { code: "LU", name: "Luxembourg", dialCode: "+352" },
850
+ { code: "MY", name: "Malaysia", dialCode: "+60" },
851
+ { code: "MX", name: "Mexico", dialCode: "+52" },
852
+ { code: "MD", name: "Moldova", dialCode: "+373" },
853
+ { code: "NL", name: "Netherlands", dialCode: "+31" },
854
+ { code: "NZ", name: "New Zealand", dialCode: "+64" },
855
+ { code: "NG", name: "Nigeria", dialCode: "+234" },
856
+ { code: "NO", name: "Norway", dialCode: "+47" },
857
+ { code: "PK", name: "Pakistan", dialCode: "+92" },
858
+ { code: "PS", name: "Palestine", dialCode: "+970" },
859
+ { code: "PH", name: "Philippines", dialCode: "+63" },
860
+ { code: "PL", name: "Poland", dialCode: "+48" },
861
+ { code: "PT", name: "Portugal", dialCode: "+351" },
862
+ { code: "QA", name: "Qatar", dialCode: "+974" },
863
+ { code: "RO", name: "Romania", dialCode: "+40" },
864
+ { code: "RU", name: "Russia", dialCode: "+7" },
865
+ { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
866
+ { code: "RS", name: "Serbia", dialCode: "+381" },
867
+ { code: "SG", name: "Singapore", dialCode: "+65" },
868
+ { code: "SK", name: "Slovakia", dialCode: "+421" },
869
+ { code: "SI", name: "Slovenia", dialCode: "+386" },
870
+ { code: "ZA", name: "South Africa", dialCode: "+27" },
871
+ { code: "KR", name: "South Korea", dialCode: "+82" },
872
+ { code: "ES", name: "Spain", dialCode: "+34" },
873
+ { code: "SE", name: "Sweden", dialCode: "+46" },
874
+ { code: "CH", name: "Switzerland", dialCode: "+41" },
875
+ { code: "SY", name: "Syria", dialCode: "+963" },
876
+ { code: "TW", name: "Taiwan", dialCode: "+886" },
877
+ { code: "TH", name: "Thailand", dialCode: "+66" },
878
+ { code: "TR", name: "Turkey", dialCode: "+90" },
879
+ { code: "UA", name: "Ukraine", dialCode: "+380" },
880
+ { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
881
+ { code: "GB", name: "United Kingdom", dialCode: "+44" },
882
+ { code: "US", name: "United States", dialCode: "+1" },
883
+ { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
884
+ { code: "VN", name: "Vietnam", dialCode: "+84" }
885
+ ];
886
+ function findCountry(code) {
887
+ return countries.find((country) => country.code === code) ?? defaultCountry;
888
+ }
889
+
890
+ // src/icons/chevronDownPath.ts
891
+ var CHEVRON_DOWN_PATH = "M4 6L8 10L12 6";
892
+ function ChevronDownIcon({
893
+ size = 16,
894
+ color = "#dadde0",
895
+ strokeWidth = 2
896
+ }) {
897
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
898
+ Svg.Path,
899
+ {
900
+ d: CHEVRON_DOWN_PATH,
901
+ stroke: color,
902
+ strokeWidth,
903
+ strokeLinecap: "round",
904
+ strokeLinejoin: "round"
905
+ }
906
+ ) });
907
+ }
908
+
909
+ // src/utils/countryFlag.ts
910
+ function countryCodeToFlagEmoji(code) {
911
+ const upper = code.trim().toUpperCase();
912
+ if (upper.length !== 2) return "";
913
+ return String.fromCodePoint(
914
+ ...upper.split("").map((char) => 127462 - 65 + char.charCodeAt(0))
915
+ );
916
+ }
917
+ var COUNTRY_DROPDOWN_SCROLL_CLASS = "hp-country-dropdown-scroll";
918
+ var STYLE_ID = "hp-country-dropdown-scroll-styles";
919
+ var countryDropdownScrollCss = `
920
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS} {
921
+ scrollbar-width: thin;
922
+ scrollbar-color: ${colors.stormGray300} transparent;
923
+ overflow-y: auto;
924
+ }
925
+
926
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar {
927
+ width: 4px;
928
+ }
929
+
930
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-corner {
931
+ background: transparent;
932
+ }
933
+
934
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button,
935
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:single-button,
936
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:vertical:start:decrement,
937
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:vertical:end:increment {
938
+ display: none;
939
+ width: 0;
940
+ height: 0;
941
+ -webkit-appearance: none;
942
+ appearance: none;
943
+ }
944
+
945
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-track {
946
+ background: transparent;
947
+ }
948
+
949
+ .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-thumb {
950
+ background-color: ${colors.stormGray300};
951
+ border-radius: 9999px;
952
+ }
953
+ `;
954
+ function ensureCountryDropdownScrollStyles() {
955
+ if (reactNative.Platform.OS !== "web" || typeof document === "undefined") return;
956
+ if (document.getElementById(STYLE_ID)) return;
957
+ const style = document.createElement("style");
958
+ style.id = STYLE_ID;
959
+ style.textContent = countryDropdownScrollCss;
960
+ document.head.appendChild(style);
961
+ }
962
+ var DROPDOWN_GAP = 10;
963
+ var DROPDOWN_HEIGHT = 186;
964
+ var DROPDOWN_PADDING = 8;
965
+ var OPTION_GAP = 10;
966
+ var OPTION_HEIGHT = 35;
967
+ var TRIGGER_HEIGHT = 52;
968
+ var CHEVRON_SIZE = 16;
969
+ function resolveDropdownTop(anchor) {
970
+ const windowHeight = reactNative.Dimensions.get("window").height;
971
+ const topBelow = anchor.y + anchor.height + DROPDOWN_GAP;
972
+ const topAbove = anchor.y - DROPDOWN_GAP - DROPDOWN_HEIGHT;
973
+ const fitsBelow = topBelow + DROPDOWN_HEIGHT <= windowHeight;
974
+ if (fitsBelow) return topBelow;
975
+ if (topAbove >= 0) return topAbove;
976
+ return Math.max(0, Math.min(topBelow, windowHeight - DROPDOWN_HEIGHT));
977
+ }
978
+ function CountryCodeSelector({
979
+ value = defaultCountry.code,
980
+ onValueChange,
981
+ options = countries,
982
+ disabled = false,
983
+ style,
984
+ className
985
+ }) {
986
+ const wrapperRef = react.useRef(null);
987
+ const triggerRef = react.useRef(null);
988
+ const scrollRef = react.useRef(null);
989
+ const [open, setOpen] = react.useState(false);
990
+ const [anchor, setAnchor] = react.useState(null);
991
+ useApplyWebClassName(wrapperRef, className);
992
+ useApplyWebClassName(
993
+ scrollRef,
994
+ COUNTRY_DROPDOWN_SCROLL_CLASS,
995
+ open && Boolean(anchor)
996
+ );
997
+ react.useLayoutEffect(() => {
998
+ ensureCountryDropdownScrollStyles();
999
+ }, []);
1000
+ const selected = findCountry(value);
1001
+ const textColor = disabled ? colors.stormGray200 : colors.slateBlue;
1002
+ function closeDropdown() {
1003
+ setOpen(false);
1004
+ setAnchor(null);
1005
+ }
1006
+ function handleOpen() {
1007
+ if (disabled) return;
1008
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
1009
+ setAnchor({ x, y, width, height });
1010
+ setOpen(true);
1011
+ });
1012
+ }
1013
+ function handleSelect(code) {
1014
+ onValueChange?.(code);
1015
+ closeDropdown();
1016
+ }
1017
+ const dropdownTop = anchor ? resolveDropdownTop(anchor) : 0;
1018
+ const optionList = options.map((item, index) => {
1019
+ const isSelected = item.code === selected.code;
1020
+ const isLast = index === options.length - 1;
1021
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1022
+ reactNative.Pressable,
1023
+ {
1024
+ accessibilityRole: "button",
1025
+ onPress: () => handleSelect(item.code),
1026
+ style: [
1027
+ styles4.option,
1028
+ isSelected && styles4.optionSelected,
1029
+ !isLast && styles4.optionSpacing
1030
+ ],
1031
+ children: [
1032
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.flag, children: countryCodeToFlagEmoji(item.code) }),
1033
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.optionDialCode, children: item.dialCode })
1034
+ ]
1035
+ },
1036
+ item.code
1037
+ );
1038
+ });
1039
+ const dropdownList = /* @__PURE__ */ jsxRuntime.jsx(
1040
+ reactNative.ScrollView,
1041
+ {
1042
+ ref: scrollRef,
1043
+ style: styles4.dropdownScroll,
1044
+ contentContainerStyle: styles4.dropdownContent,
1045
+ keyboardShouldPersistTaps: "handled",
1046
+ showsVerticalScrollIndicator: true,
1047
+ bounces: false,
1048
+ nestedScrollEnabled: true,
1049
+ children: optionList
1050
+ }
1051
+ );
1052
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles4.root, style], children: [
1053
+ /* @__PURE__ */ jsxRuntime.jsxs(
1054
+ reactNative.Pressable,
1055
+ {
1056
+ ref: triggerRef,
1057
+ accessibilityRole: "button",
1058
+ disabled,
1059
+ onPress: handleOpen,
1060
+ style: [
1061
+ styles4.trigger,
1062
+ disabled ? styles4.triggerDisabled : styles4.triggerEnabled,
1063
+ reactNative.Platform.OS === "web" ? styles4.triggerWeb : null
1064
+ ],
1065
+ children: [
1066
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.flag, children: countryCodeToFlagEmoji(selected.code) }),
1067
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.dialCode, { color: textColor }], children: selected.dialCode }),
1068
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { size: CHEVRON_SIZE, color: colors.stormGray100 })
1069
+ ]
1070
+ }
1071
+ ),
1072
+ /* @__PURE__ */ jsxRuntime.jsx(
1073
+ reactNative.Modal,
1074
+ {
1075
+ visible: open,
1076
+ transparent: true,
1077
+ animationType: "fade",
1078
+ onRequestClose: closeDropdown,
1079
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles4.overlay, onPress: closeDropdown, children: anchor ? /* @__PURE__ */ jsxRuntime.jsx(
1080
+ reactNative.View,
1081
+ {
1082
+ style: [
1083
+ styles4.dropdown,
1084
+ {
1085
+ top: dropdownTop,
1086
+ left: anchor.x,
1087
+ width: anchor.width
1088
+ }
1089
+ ],
1090
+ children: dropdownList
1091
+ }
1092
+ ) : null })
1093
+ }
1094
+ )
1095
+ ] });
1096
+ }
1097
+ var styles4 = reactNative.StyleSheet.create({
1098
+ root: {
1099
+ alignSelf: "flex-start",
1100
+ flexShrink: 0
1101
+ },
1102
+ trigger: {
1103
+ flexDirection: "row",
1104
+ alignItems: "center",
1105
+ alignSelf: "flex-start",
1106
+ flexGrow: 0,
1107
+ flexShrink: 0,
1108
+ height: TRIGGER_HEIGHT,
1109
+ borderRadius: radii.lg,
1110
+ borderWidth: 1,
1111
+ padding: spacing.lg,
1112
+ gap: spacing.sm
1113
+ },
1114
+ triggerEnabled: {
1115
+ borderColor: colors.stormGray50,
1116
+ backgroundColor: colors.white
1117
+ },
1118
+ triggerDisabled: {
1119
+ borderColor: colors.stormGray50,
1120
+ backgroundColor: colors.stormGray50
1121
+ },
1122
+ triggerWeb: {
1123
+ width: "max-content"
1124
+ },
1125
+ flag: {
1126
+ fontSize: 18,
1127
+ lineHeight: 22
1128
+ },
1129
+ dialCode: {
1130
+ fontSize: fontSize.md,
1131
+ fontWeight: fontWeight.medium
1132
+ },
1133
+ overlay: {
1134
+ flex: 1,
1135
+ backgroundColor: "transparent"
1136
+ },
1137
+ dropdown: {
1138
+ position: "absolute",
1139
+ height: DROPDOWN_HEIGHT,
1140
+ borderRadius: radii.lg,
1141
+ borderWidth: 1,
1142
+ borderColor: colors.stormGray50,
1143
+ backgroundColor: colors.white,
1144
+ padding: DROPDOWN_PADDING,
1145
+ overflow: "hidden"
1146
+ },
1147
+ dropdownScroll: {
1148
+ flex: 1
1149
+ },
1150
+ dropdownContent: {
1151
+ flexGrow: 1
1152
+ },
1153
+ option: {
1154
+ flexDirection: "row",
1155
+ alignItems: "center",
1156
+ height: OPTION_HEIGHT,
1157
+ borderRadius: radii.sm,
1158
+ padding: spacing.sm,
1159
+ gap: spacing.sm
158
1160
  },
159
- medium: {
160
- fontSize: 16
1161
+ optionSpacing: {
1162
+ marginBottom: OPTION_GAP
161
1163
  },
162
- large: {
163
- fontSize: 18
1164
+ optionSelected: {
1165
+ backgroundColor: colors.countrySelectorSelectedBg
1166
+ },
1167
+ optionDialCode: {
1168
+ fontFamily: fonts.sans,
1169
+ fontSize: fontSize.md,
1170
+ fontWeight: fontWeight.regular,
1171
+ lineHeight: fontSize.md,
1172
+ letterSpacing: 0,
1173
+ textAlign: "center",
1174
+ color: colors.slateBlue
164
1175
  }
165
1176
  });
166
- var textDisabledStyles = reactNative.StyleSheet.create({
167
- primary: {
168
- color: "#e5e7eb"
1177
+ function PhoneInput({
1178
+ label,
1179
+ countryCode,
1180
+ onCountryCodeChange,
1181
+ error,
1182
+ hint,
1183
+ containerStyle,
1184
+ style,
1185
+ className,
1186
+ labelClassName,
1187
+ inputClassName,
1188
+ errorClassName,
1189
+ hintClassName,
1190
+ editable = true,
1191
+ onFocus,
1192
+ onBlur,
1193
+ ...props
1194
+ }) {
1195
+ const wrapperRef = react.useRef(null);
1196
+ const inputRef = react.useRef(null);
1197
+ const helperRef = react.useRef(null);
1198
+ const [focused, setFocused] = react.useState(false);
1199
+ useApplyWebClassName(wrapperRef, className);
1200
+ useApplyWebClassName(inputRef, inputClassName);
1201
+ useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
1202
+ const isDisabled = editable === false;
1203
+ const phoneVisualState = resolveInputVisualState({
1204
+ focused,
1205
+ error: Boolean(error),
1206
+ disabled: isDisabled
1207
+ });
1208
+ const phoneFieldStyles = getInputFieldStyles(phoneVisualState);
1209
+ function handleFocus(event) {
1210
+ setFocused(true);
1211
+ onFocus?.(event);
1212
+ }
1213
+ function handleBlur(event) {
1214
+ setFocused(false);
1215
+ onBlur?.(event);
1216
+ }
1217
+ const helperMessage = error ?? hint;
1218
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles5.wrapper, containerStyle], children: [
1219
+ label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled: isDisabled, className: labelClassName, children: label }) : null,
1220
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.row, children: [
1221
+ /* @__PURE__ */ jsxRuntime.jsx(
1222
+ CountryCodeSelector,
1223
+ {
1224
+ value: countryCode,
1225
+ onValueChange: onCountryCodeChange,
1226
+ disabled: isDisabled,
1227
+ style: styles5.countrySelector
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.phoneColumn, children: [
1231
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [phoneFieldStyles.outline, styles5.phoneOutline], children: /* @__PURE__ */ jsxRuntime.jsx(
1232
+ reactNative.View,
1233
+ {
1234
+ style: [
1235
+ inputFieldMetrics.container,
1236
+ phoneFieldStyles.container,
1237
+ styles5.phoneField
1238
+ ],
1239
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1240
+ reactNative.TextInput,
1241
+ {
1242
+ ref: inputRef,
1243
+ style: [
1244
+ inputFieldMetrics.input,
1245
+ phoneFieldStyles.text,
1246
+ style
1247
+ ],
1248
+ keyboardType: "phone-pad",
1249
+ placeholderTextColor: phoneFieldStyles.placeholder,
1250
+ editable,
1251
+ onFocus: handleFocus,
1252
+ onBlur: handleBlur,
1253
+ accessibilityState: { disabled: isDisabled },
1254
+ ...props
1255
+ }
1256
+ )
1257
+ }
1258
+ ) }),
1259
+ helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles5.error : styles5.hint, children: helperMessage }) : null
1260
+ ] })
1261
+ ] })
1262
+ ] });
1263
+ }
1264
+ var styles5 = reactNative.StyleSheet.create({
1265
+ wrapper: {
1266
+ width: "100%",
1267
+ gap: spacing.sm
1268
+ },
1269
+ row: {
1270
+ flexDirection: "row",
1271
+ alignItems: "flex-start",
1272
+ gap: INPUT_ICON_GAP
1273
+ },
1274
+ countrySelector: {
1275
+ flexShrink: 0,
1276
+ alignSelf: "flex-start"
1277
+ },
1278
+ phoneColumn: {
1279
+ flex: 1,
1280
+ gap: spacing.sm
1281
+ },
1282
+ phoneOutline: {
1283
+ width: "100%"
169
1284
  },
170
- secondary: {
171
- color: "#f3f4f6"
1285
+ phoneField: {
1286
+ flex: 1
172
1287
  },
173
- outline: {
174
- color: "#93c5fd"
1288
+ error: {
1289
+ fontSize: 12,
1290
+ lineHeight: 16,
1291
+ color: colors.inputError
175
1292
  },
176
- ghost: {
177
- color: "#93c5fd"
1293
+ hint: {
1294
+ fontSize: 12,
1295
+ lineHeight: 16,
1296
+ color: colors.stormGray300
178
1297
  }
179
1298
  });
180
1299
 
181
1300
  exports.Button = Button;
1301
+ exports.CountryCodeSelector = CountryCodeSelector;
1302
+ exports.Input = Input;
1303
+ exports.Label = Label;
1304
+ exports.PhoneInput = PhoneInput;
1305
+ exports.brand = brand;
1306
+ exports.buttonTypography = buttonTypography;
1307
+ exports.colors = colors;
1308
+ exports.countries = countries;
1309
+ exports.defaultCountry = defaultCountry;
1310
+ exports.emeraldGreen = emeraldGreen;
1311
+ exports.findCountry = findCountry;
1312
+ exports.fontSize = fontSize;
1313
+ exports.fontWeight = fontWeight;
1314
+ exports.fonts = fonts;
1315
+ exports.labelTypography = labelTypography;
1316
+ exports.navy = navy;
1317
+ exports.radii = radii;
1318
+ exports.rubyRed = rubyRed;
1319
+ exports.shadows = shadows;
1320
+ exports.spacing = spacing;
1321
+ exports.stormGray = stormGray;
182
1322
  //# sourceMappingURL=index.cjs.map
183
1323
  //# sourceMappingURL=index.cjs.map