@ecohouse/ui 0.1.1 → 0.1.3

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 (45) hide show
  1. package/README.md +2 -1
  2. package/dist/index.cjs +1266 -109
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +188 -12
  5. package/dist/index.d.ts +188 -12
  6. package/dist/index.js +1260 -112
  7. package/dist/index.js.map +1 -1
  8. package/package.json +2 -1
  9. package/src/components/Button/Button.tsx +106 -88
  10. package/src/components/Checkbox/Checkbox.stories.tsx +112 -0
  11. package/src/components/Checkbox/Checkbox.tsx +150 -0
  12. package/src/components/Checkbox/index.ts +2 -0
  13. package/src/components/Input/Input.stories.tsx +11 -40
  14. package/src/components/Input/Input.tsx +58 -54
  15. package/src/components/Input/index.ts +1 -1
  16. package/src/components/Select/Select.stories.tsx +196 -0
  17. package/src/components/Select/Select.tsx +851 -0
  18. package/src/components/Select/index.ts +2 -0
  19. package/src/components/Textarea/Textarea.stories.tsx +71 -0
  20. package/src/components/Textarea/Textarea.tsx +241 -0
  21. package/src/components/Textarea/index.ts +2 -0
  22. package/src/components/Toggle/Toggle.stories.tsx +100 -0
  23. package/src/components/Toggle/Toggle.tsx +176 -0
  24. package/src/components/Toggle/index.ts +2 -0
  25. package/src/components/index.ts +13 -1
  26. package/src/icons/Check/CheckIcon.tsx +26 -0
  27. package/src/icons/Check/CheckIcon.web.tsx +32 -0
  28. package/src/icons/Check/checkPath.ts +2 -0
  29. package/src/icons/Check/index.ts +1 -0
  30. package/src/icons/ChevronDown/ChevronDownIcon.tsx +30 -0
  31. package/src/icons/ChevronDown/ChevronDownIcon.web.tsx +36 -0
  32. package/src/icons/ChevronDown/chevronDownPath.ts +2 -0
  33. package/src/icons/ChevronDown/index.ts +1 -0
  34. package/src/icons/Search/SearchIcon.tsx +37 -0
  35. package/src/icons/Search/SearchIcon.web.tsx +43 -0
  36. package/src/icons/Search/index.ts +1 -0
  37. package/src/icons/Search/searchPath.ts +5 -0
  38. package/src/icons/index.ts +3 -0
  39. package/src/icons/registry.ts +8 -2
  40. package/src/index.ts +21 -3
  41. package/src/theme/index.ts +7 -1
  42. package/src/theme/typography.ts +52 -2
  43. package/src/utils/mergeRefs.ts +20 -0
  44. package/src/web/styles/fonts.css +1 -0
  45. package/src/web/styles/typography.css +6 -2
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useRef, useState, useLayoutEffect } from 'react';
2
- import { StyleSheet, Platform, TouchableOpacity, Text, View, TextInput } from 'react-native';
1
+ import { forwardRef, useRef, useMemo, useState, useCallback, useEffect, useLayoutEffect } from 'react';
2
+ import { Platform, TouchableOpacity, Text, View, StyleSheet, Pressable, TextInput, ScrollView, Animated, Easing } from 'react-native';
3
3
  import Svg, { Path } from 'react-native-svg';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
5
 
@@ -77,9 +77,32 @@ var inputTypography = {
77
77
  fontFamily: fonts.sans,
78
78
  fontSize: 12,
79
79
  fontWeight: "500",
80
- lineHeight: 16,
80
+ lineHeight: 12,
81
+ letterSpacing: 0.36
82
+ },
83
+ field: {
84
+ fontFamily: fonts.sans,
85
+ fontSize: 14,
86
+ fontWeight: "400",
87
+ lineHeight: 19,
81
88
  letterSpacing: 0
82
89
  },
90
+ hint: {
91
+ fontFamily: fonts.sans,
92
+ fontSize: 12,
93
+ fontWeight: "400",
94
+ lineHeight: 12,
95
+ letterSpacing: 0.36
96
+ }
97
+ };
98
+ var selectTypography = {
99
+ label: {
100
+ fontFamily: fonts.sans,
101
+ fontSize: 12,
102
+ fontWeight: "500",
103
+ lineHeight: 12,
104
+ letterSpacing: 0.36
105
+ },
83
106
  field: {
84
107
  fontFamily: fonts.sans,
85
108
  fontSize: 14,
@@ -91,8 +114,31 @@ var inputTypography = {
91
114
  fontFamily: fonts.sans,
92
115
  fontSize: 12,
93
116
  fontWeight: "400",
94
- lineHeight: 16,
117
+ lineHeight: 12,
118
+ letterSpacing: 0.36
119
+ }
120
+ };
121
+ var textareaTypography = {
122
+ label: {
123
+ fontFamily: fonts.sans,
124
+ fontSize: 12,
125
+ fontWeight: "500",
126
+ lineHeight: 12,
127
+ letterSpacing: 0.36
128
+ },
129
+ field: {
130
+ fontFamily: fonts.sans,
131
+ fontSize: 14,
132
+ fontWeight: "400",
133
+ lineHeight: 19,
95
134
  letterSpacing: 0
135
+ },
136
+ hint: {
137
+ fontFamily: fonts.sans,
138
+ fontSize: 12,
139
+ fontWeight: "400",
140
+ lineHeight: 12,
141
+ letterSpacing: 0.36
96
142
  }
97
143
  };
98
144
  function ArrowRightIcon({
@@ -172,6 +218,21 @@ function CameraIcon({ size = 24, color = colors.primary, strokeWidth = 2 }) {
172
218
  ) });
173
219
  }
174
220
 
221
+ // src/icons/Check/checkPath.ts
222
+ var CHECK_PATH = "M4.16669 10.8333L7.50002 14.1667L15.8334 5.83334";
223
+ function CheckIcon({ size = 20, color = colors.primary, strokeWidth = 2 }) {
224
+ return /* @__PURE__ */ jsx(Svg, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx(
225
+ Path,
226
+ {
227
+ d: CHECK_PATH,
228
+ stroke: color,
229
+ strokeWidth,
230
+ strokeLinecap: "round",
231
+ strokeLinejoin: "round"
232
+ }
233
+ ) });
234
+ }
235
+
175
236
  // src/icons/CheckBadge/checkBadgePath.ts
176
237
  var CHECK_BADGE_PATH = "M12.5 8.33317L9.16663 11.6665L7.49996 9.99984M11.0384 2.88233L12.0558 3.74941C12.3122 3.96786 12.6305 4.09992 12.9662 4.12671L14.2987 4.23291C15.0822 4.29543 15.7045 4.91733 15.767 5.70077L15.8729 7.03353C15.8997 7.36925 16.0322 7.68799 16.2507 7.94433L17.1174 8.96152C17.6272 9.5597 17.6272 10.4396 17.1175 11.0378L16.2508 12.0551C16.0323 12.3115 15.9 12.6303 15.8732 12.9661L15.7666 14.2986C15.704 15.082 15.0827 15.7043 14.2993 15.7668L12.9663 15.8732C12.6305 15.9 12.312 16.0317 12.0556 16.2502L11.0384 17.1173C10.4402 17.627 9.55973 17.6271 8.96155 17.1174L7.9443 16.2502C7.68796 16.0318 7.36938 15.8998 7.03365 15.8731L5.70064 15.7668C4.9172 15.7043 4.29588 15.0822 4.23336 14.2987L4.12675 12.9661C4.09996 12.6304 3.96759 12.3118 3.74915 12.0555L2.88245 11.0378C2.37268 10.4397 2.37244 9.56002 2.88221 8.96184L3.74969 7.94418C3.96814 7.68784 4.09923 7.36926 4.12602 7.03353L4.23263 5.70093C4.29515 4.91749 4.91826 4.29535 5.70171 4.23283L7.03324 4.12663C7.36897 4.09984 7.68771 3.96788 7.94404 3.74943L8.96164 2.88233C9.55982 2.37256 10.4402 2.37256 11.0384 2.88233Z";
177
238
  function CheckBadgeIcon({ size = 20, color = colors.primary, strokeWidth = 2 }) {
@@ -187,6 +248,25 @@ function CheckBadgeIcon({ size = 20, color = colors.primary, strokeWidth = 2 })
187
248
  ) });
188
249
  }
189
250
 
251
+ // src/icons/ChevronDown/chevronDownPath.ts
252
+ var CHEVRON_DOWN_PATH = "M5 7.5L10 12.5L15 7.5";
253
+ function ChevronDownIcon({
254
+ size = 20,
255
+ color = colors.primary,
256
+ strokeWidth = 2
257
+ }) {
258
+ return /* @__PURE__ */ jsx(Svg, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx(
259
+ Path,
260
+ {
261
+ d: CHEVRON_DOWN_PATH,
262
+ stroke: color,
263
+ strokeWidth,
264
+ strokeLinecap: "round",
265
+ strokeLinejoin: "round"
266
+ }
267
+ ) });
268
+ }
269
+
190
270
  // src/icons/Clock/clockPath.ts
191
271
  var CLOCK_PATH = "M12 7V12H17M12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21Z";
192
272
  function ClockIcon({ size = 24, color = colors.primary, strokeWidth = 2 }) {
@@ -295,6 +375,38 @@ function PhoneIcon({ size = 20, color = colors.primary, strokeWidth = 2 }) {
295
375
  ) });
296
376
  }
297
377
 
378
+ // src/icons/Search/searchPath.ts
379
+ var SEARCH_CIRCLE_PATH = "M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z";
380
+ var SEARCH_HANDLE_PATH = "M17.5 17.5L13.875 13.875";
381
+ function SearchIcon({
382
+ size = 20,
383
+ color = colors.primary,
384
+ strokeWidth = 2
385
+ }) {
386
+ return /* @__PURE__ */ jsxs(Svg, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: [
387
+ /* @__PURE__ */ jsx(
388
+ Path,
389
+ {
390
+ d: SEARCH_CIRCLE_PATH,
391
+ stroke: color,
392
+ strokeWidth,
393
+ strokeLinecap: "round",
394
+ strokeLinejoin: "round"
395
+ }
396
+ ),
397
+ /* @__PURE__ */ jsx(
398
+ Path,
399
+ {
400
+ d: SEARCH_HANDLE_PATH,
401
+ stroke: color,
402
+ strokeWidth,
403
+ strokeLinecap: "round",
404
+ strokeLinejoin: "round"
405
+ }
406
+ )
407
+ ] });
408
+ }
409
+
298
410
  // src/icons/Show/showPath.ts
299
411
  var SHOW_PATH = "M1.66669 10C1.66669 10 4.16669 4.16667 10 4.16667C15.8334 4.16667 18.3334 10 18.3334 10C18.3334 10 15.8334 15.8333 10 15.8333C4.16669 15.8333 1.66669 10 1.66669 10Z";
300
412
  var SHOW_PUPIL_PATH = "M10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z";
@@ -345,7 +457,9 @@ var icons = {
345
457
  bell: BellIcon,
346
458
  building: BuildingIcon,
347
459
  camera: CameraIcon,
460
+ check: CheckIcon,
348
461
  checkBadge: CheckBadgeIcon,
462
+ chevronDown: ChevronDownIcon,
349
463
  clock: ClockIcon,
350
464
  facebook: FacebookIcon,
351
465
  home: HomeIcon,
@@ -355,13 +469,14 @@ var icons = {
355
469
  mail: MailIcon,
356
470
  navigate: NavigateIcon,
357
471
  phone: PhoneIcon,
472
+ search: SearchIcon,
358
473
  show: ShowIcon,
359
474
  user: UserIcon
360
475
  };
361
476
  var iconNames = Object.keys(icons);
362
477
  var iconGroups = {
363
- navigation: ["arrowRight", "home", "navigate"],
364
- actions: ["show", "bell", "camera", "key", "checkBadge"],
478
+ navigation: ["arrowRight", "chevronDown", "home", "navigate"],
479
+ actions: ["show", "bell", "camera", "key", "check", "checkBadge", "search"],
365
480
  objects: ["bag", "building", "clock", "user"],
366
481
  communication: ["mail", "phone"],
367
482
  social: ["facebook", "instagram", "linkedin"]
@@ -374,6 +489,18 @@ function Icon({ name, ...props }) {
374
489
  const Component = icons[name];
375
490
  return /* @__PURE__ */ jsx(Component, { ...props });
376
491
  }
492
+
493
+ // src/utils/mergeRefs.ts
494
+ function mergeRefs(internalRef, forwardedRef) {
495
+ return (node) => {
496
+ internalRef.current = node;
497
+ if (typeof forwardedRef === "function") {
498
+ forwardedRef(node);
499
+ } else if (forwardedRef) {
500
+ forwardedRef.current = node;
501
+ }
502
+ };
503
+ }
377
504
  function hasClassList(node) {
378
505
  return typeof node === "object" && node !== null && "classList" in node && typeof node.classList?.add === "function";
379
506
  }
@@ -454,107 +581,214 @@ var sizeConfig = {
454
581
  iconSize: 12
455
582
  }
456
583
  };
457
- function Button({
458
- title,
459
- children,
460
- onPress,
584
+ var Button = forwardRef(
585
+ function Button2({
586
+ title,
587
+ children,
588
+ onPress,
589
+ disabled = false,
590
+ variant = "primary",
591
+ size = "lg",
592
+ showIcon = false,
593
+ icon,
594
+ style,
595
+ textStyle,
596
+ className,
597
+ textClassName,
598
+ accessibilityLabel,
599
+ ...rest
600
+ }, forwardedRef) {
601
+ const containerRef = useRef(null);
602
+ const textRef = useRef(null);
603
+ const preset = variantConfig[variant];
604
+ const metrics = sizeConfig[size];
605
+ const label = typeof children !== "undefined" ? children : title;
606
+ const hasCustomChildren = typeof children !== "undefined";
607
+ const customIcon = icon != null && typeof icon !== "boolean" ? icon : void 0;
608
+ const hasIcon = showIcon || icon === true || customIcon != null;
609
+ const resolvedContainerClassName = className?.trim() || void 0;
610
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (typeof label === "string" ? label : void 0);
611
+ const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
612
+ useApplyWebClassName(containerRef, resolvedContainerClassName);
613
+ useApplyWebClassName(textRef, textClassName);
614
+ const iconNode = customIcon ?? /* @__PURE__ */ jsx(ArrowRightIcon, { size: metrics.iconSize, color: preset.iconColor });
615
+ const containerStyle = [
616
+ styles.base,
617
+ {
618
+ minHeight: metrics.minHeight,
619
+ borderRadius: metrics.borderRadius,
620
+ backgroundColor: preset.backgroundColor,
621
+ paddingTop: metrics.paddingVertical,
622
+ paddingBottom: metrics.paddingVertical,
623
+ paddingLeft: metrics.paddingLeft,
624
+ paddingRight: hasIcon ? metrics.paddingRightWithIcon : metrics.paddingRight,
625
+ gap: hasIcon ? metrics.gap : 0
626
+ },
627
+ disabled && styles.disabled,
628
+ style
629
+ ];
630
+ const labelStyle = [
631
+ styles.label,
632
+ metrics.text,
633
+ { color: preset.textColor },
634
+ Platform.OS === "android" ? styles.labelAndroid : null,
635
+ !hasIcon && styles.labelCentered,
636
+ textStyle
637
+ ];
638
+ return /* @__PURE__ */ jsxs(
639
+ TouchableOpacity,
640
+ {
641
+ ...rest,
642
+ ref: setContainerRef,
643
+ style: containerStyle,
644
+ onPress,
645
+ disabled,
646
+ activeOpacity: 0.7,
647
+ accessibilityRole: "button",
648
+ accessibilityLabel: resolvedAccessibilityLabel,
649
+ accessibilityState: { disabled },
650
+ children: [
651
+ hasCustomChildren ? children : /* @__PURE__ */ jsx(Text, { ref: textRef, style: labelStyle, children: label }),
652
+ hasIcon ? /* @__PURE__ */ jsx(
653
+ View,
654
+ {
655
+ style: [
656
+ styles.iconContainer,
657
+ {
658
+ width: metrics.iconContainerSize,
659
+ height: metrics.iconContainerSize,
660
+ borderRadius: metrics.iconContainerSize / 2,
661
+ backgroundColor: preset.iconBadgeBackgroundColor
662
+ }
663
+ ],
664
+ children: iconNode
665
+ }
666
+ ) : null
667
+ ]
668
+ }
669
+ );
670
+ }
671
+ );
672
+ var styles = StyleSheet.create({
673
+ base: {
674
+ flexDirection: "row",
675
+ alignItems: "center",
676
+ alignSelf: "flex-start",
677
+ borderWidth: 0
678
+ },
679
+ disabled: {
680
+ opacity: 0.6
681
+ },
682
+ label: {},
683
+ labelAndroid: {
684
+ includeFontPadding: false
685
+ },
686
+ labelCentered: {
687
+ textAlign: "center"
688
+ },
689
+ iconContainer: {
690
+ alignItems: "center",
691
+ justifyContent: "center",
692
+ flexShrink: 0
693
+ }
694
+ });
695
+ var BOX_SIZE = 20;
696
+ var BOX_RADIUS = 6;
697
+ var CHECK_SIZE = 12;
698
+ var CHECK_STROKE = 2.5;
699
+ var variantChrome = {
700
+ default: {
701
+ backgroundColor: colors.dark,
702
+ borderColor: colors.grey700
703
+ },
704
+ light: {
705
+ backgroundColor: colors.grey700,
706
+ borderColor: colors.grey500
707
+ }
708
+ };
709
+ var Checkbox = forwardRef(function Checkbox2({
710
+ value,
711
+ defaultValue = false,
712
+ onValueChange,
461
713
  disabled = false,
462
- variant = "primary",
463
- size = "lg",
464
- showIcon = false,
465
- icon,
714
+ variant = "default",
715
+ label,
716
+ children,
466
717
  style,
467
- textStyle,
718
+ labelStyle,
468
719
  className,
469
- textClassName
470
- }) {
720
+ hitSlop = 8,
721
+ accessibilityLabel,
722
+ ...rest
723
+ }, forwardedRef) {
471
724
  const containerRef = useRef(null);
472
- const textRef = useRef(null);
473
- const preset = variantConfig[variant];
474
- const metrics = sizeConfig[size];
475
- const label = typeof children !== "undefined" ? children : title;
476
- const hasCustomChildren = typeof children !== "undefined";
477
- const customIcon = icon != null && typeof icon !== "boolean" ? icon : void 0;
478
- const hasIcon = showIcon || icon === true || customIcon != null;
479
- const resolvedContainerClassName = className?.trim() || void 0;
480
- useApplyWebClassName(containerRef, resolvedContainerClassName);
481
- useApplyWebClassName(textRef, textClassName);
482
- const iconNode = customIcon ?? /* @__PURE__ */ jsx(ArrowRightIcon, { size: metrics.iconSize, color: preset.iconColor });
483
- const containerStyle = [
484
- styles.base,
485
- {
486
- minHeight: metrics.minHeight,
487
- borderRadius: metrics.borderRadius,
488
- backgroundColor: preset.backgroundColor,
489
- paddingTop: metrics.paddingVertical,
490
- paddingBottom: metrics.paddingVertical,
491
- paddingLeft: metrics.paddingLeft,
492
- paddingRight: hasIcon ? metrics.paddingRightWithIcon : metrics.paddingRight,
493
- gap: hasIcon ? metrics.gap : 0
494
- },
495
- disabled && styles.disabled,
496
- style
497
- ];
498
- const labelStyle = [
499
- styles.label,
500
- metrics.text,
501
- { color: preset.textColor },
502
- Platform.OS === "android" ? styles.labelAndroid : null,
503
- !hasIcon && styles.labelCentered,
504
- textStyle
505
- ];
725
+ const isControlled = typeof value === "boolean";
726
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
727
+ const isActive = isControlled ? value : uncontrolledValue;
728
+ const chrome = variantChrome[variant];
729
+ const labelContent = children ?? label;
730
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (typeof labelContent === "string" ? labelContent : void 0);
731
+ const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
732
+ useApplyWebClassName(containerRef, className);
733
+ const handlePress = () => {
734
+ if (disabled) return;
735
+ const next = !isActive;
736
+ if (!isControlled) setUncontrolledValue(next);
737
+ onValueChange?.(next);
738
+ };
506
739
  return /* @__PURE__ */ jsxs(
507
- TouchableOpacity,
740
+ Pressable,
508
741
  {
509
- ref: containerRef,
510
- style: containerStyle,
511
- onPress,
742
+ ...rest,
743
+ ref: setContainerRef,
744
+ onPress: handlePress,
512
745
  disabled,
513
- activeOpacity: 0.7,
514
- accessibilityRole: "button",
515
- accessibilityState: { disabled },
746
+ hitSlop,
747
+ accessibilityRole: "checkbox",
748
+ accessibilityLabel: resolvedAccessibilityLabel,
749
+ accessibilityState: { checked: isActive, disabled },
750
+ style: [styles2.root, disabled && styles2.disabled, style],
516
751
  children: [
517
- hasCustomChildren ? children : /* @__PURE__ */ jsx(Text, { ref: textRef, style: labelStyle, children: label }),
518
- hasIcon ? /* @__PURE__ */ jsx(
752
+ /* @__PURE__ */ jsx(
519
753
  View,
520
754
  {
521
755
  style: [
522
- styles.iconContainer,
756
+ styles2.box,
523
757
  {
524
- width: metrics.iconContainerSize,
525
- height: metrics.iconContainerSize,
526
- borderRadius: metrics.iconContainerSize / 2,
527
- backgroundColor: preset.iconBadgeBackgroundColor
758
+ backgroundColor: chrome.backgroundColor,
759
+ borderColor: chrome.borderColor
528
760
  }
529
761
  ],
530
- children: iconNode
762
+ children: isActive ? /* @__PURE__ */ jsx(CheckIcon, { size: CHECK_SIZE, color: colors.primary, strokeWidth: CHECK_STROKE }) : null
531
763
  }
532
- ) : null
764
+ ),
765
+ labelContent != null && labelContent !== false ? typeof labelContent === "string" || typeof labelContent === "number" ? /* @__PURE__ */ jsx(Text, { style: [styles2.label, labelStyle], children: labelContent }) : labelContent : null
533
766
  ]
534
767
  }
535
768
  );
536
- }
537
- var styles = StyleSheet.create({
538
- base: {
769
+ });
770
+ var styles2 = StyleSheet.create({
771
+ root: {
539
772
  flexDirection: "row",
540
773
  alignItems: "center",
541
774
  alignSelf: "flex-start",
542
- borderWidth: 0
775
+ gap: 10
543
776
  },
544
777
  disabled: {
545
- opacity: 0.6
778
+ opacity: 0.5
546
779
  },
547
- label: {},
548
- labelAndroid: {
549
- includeFontPadding: false
550
- },
551
- labelCentered: {
552
- textAlign: "center"
553
- },
554
- iconContainer: {
780
+ box: {
781
+ width: BOX_SIZE,
782
+ height: BOX_SIZE,
783
+ borderRadius: BOX_RADIUS,
784
+ borderWidth: 1,
555
785
  alignItems: "center",
556
786
  justifyContent: "center",
557
787
  flexShrink: 0
788
+ },
789
+ label: {
790
+ ...inputTypography.field,
791
+ color: colors.white
558
792
  }
559
793
  });
560
794
  var DEFAULT_WIDTH = 308;
@@ -578,14 +812,12 @@ var sizeConfig2 = {
578
812
  text: inputTypography.hint
579
813
  }
580
814
  };
581
- function resolveState({
582
- state,
815
+ function resolveVisualState({
583
816
  disabled,
584
817
  error,
585
818
  focused,
586
819
  hasValue
587
820
  }) {
588
- if (state) return state;
589
821
  if (disabled) return "disabled";
590
822
  if (error) return "error";
591
823
  if (focused) return "active";
@@ -637,13 +869,12 @@ function chromeFor(state) {
637
869
  return base;
638
870
  }
639
871
  }
640
- function Input({
872
+ var Input = forwardRef(function Input2({
641
873
  label = "Label",
642
874
  showLabel = true,
643
875
  hint = "Hint",
644
876
  showHint = true,
645
877
  placeholder = "placeholder",
646
- state: stateProp,
647
878
  size = "lg",
648
879
  disabled = false,
649
880
  error = false,
@@ -657,43 +888,40 @@ function Input({
657
888
  rightIcon,
658
889
  showRightIcon = false,
659
890
  onRightIconPress,
891
+ rightIconAccessibilityLabel,
660
892
  style,
661
893
  fieldStyle,
662
894
  inputStyle,
663
895
  className,
664
896
  inputClassName,
897
+ accessibilityLabel,
665
898
  ...textInputProps
666
- }) {
899
+ }, forwardedRef) {
667
900
  const rootRef = useRef(null);
668
901
  const inputRef = useRef(null);
902
+ const setInputRef = useMemo(() => mergeRefs(inputRef, forwardedRef), [forwardedRef]);
669
903
  const [focused, setFocused] = useState(false);
670
904
  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? "");
671
905
  const metrics = sizeConfig2[size];
672
906
  const isControlled = typeof value === "string";
673
907
  const currentValue = isControlled ? value : uncontrolledValue;
674
908
  const hasValue = currentValue.length > 0;
675
- const resolvedState = resolveState({
676
- state: stateProp,
677
- disabled,
678
- error,
679
- focused,
680
- hasValue
681
- });
682
- const chrome = chromeFor(resolvedState);
683
- const isDisabled = resolvedState === "disabled" || disabled;
909
+ const visualState = resolveVisualState({ disabled, error, focused, hasValue });
910
+ const chrome = chromeFor(visualState);
911
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (showLabel ? void 0 : label);
684
912
  const hasLeftIcon = showLeftIcon || leftIcon != null;
685
913
  const hasRightIcon = showRightIcon || rightIcon != null;
686
914
  const leftIconNode = leftIcon ?? /* @__PURE__ */ jsx(UserIcon, { size: metrics.iconSize, color: chrome.leftIconColor });
687
915
  const rightIconNode = rightIcon ?? /* @__PURE__ */ jsx(ShowIcon, { size: metrics.iconSize, color: chrome.rightIconColor });
688
916
  useApplyWebClassName(rootRef, className);
689
917
  useApplyWebClassName(inputRef, inputClassName);
690
- return /* @__PURE__ */ jsxs(View, { ref: rootRef, style: [styles2.root, isDisabled && styles2.disabled, style], children: [
691
- showLabel && label ? /* @__PURE__ */ jsx(Text, { style: [styles2.label, { color: chrome.labelColor }], children: label }) : null,
918
+ return /* @__PURE__ */ jsxs(View, { ref: rootRef, style: [styles3.root, disabled && styles3.disabled, style], children: [
919
+ showLabel && label ? /* @__PURE__ */ jsx(Text, { style: [styles3.label, { color: chrome.labelColor }], children: label }) : null,
692
920
  /* @__PURE__ */ jsxs(
693
921
  View,
694
922
  {
695
923
  style: [
696
- styles2.field,
924
+ styles3.field,
697
925
  {
698
926
  height: metrics.height,
699
927
  borderRadius: metrics.borderRadius,
@@ -708,15 +936,15 @@ function Input({
708
936
  fieldStyle
709
937
  ],
710
938
  children: [
711
- hasLeftIcon ? /* @__PURE__ */ jsx(View, { style: [styles2.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }], children: leftIconNode }) : null,
939
+ hasLeftIcon ? /* @__PURE__ */ jsx(View, { style: [styles3.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }], children: leftIconNode }) : null,
712
940
  /* @__PURE__ */ jsx(
713
941
  TextInput,
714
942
  {
715
- ref: inputRef,
943
+ ref: setInputRef,
716
944
  ...textInputProps,
717
945
  value: isControlled ? value : void 0,
718
946
  defaultValue: isControlled ? void 0 : defaultValue,
719
- editable: !isDisabled,
947
+ editable: !disabled,
720
948
  placeholder,
721
949
  placeholderTextColor: chrome.placeholderColor,
722
950
  onChangeText: (text) => {
@@ -732,34 +960,36 @@ function Input({
732
960
  onBlur?.(event);
733
961
  },
734
962
  style: [
735
- styles2.input,
963
+ styles3.input,
736
964
  metrics.text,
737
965
  { color: chrome.textColor },
738
- Platform.OS === "web" ? styles2.inputWeb : null,
739
- Platform.OS === "android" ? styles2.inputAndroid : null,
966
+ Platform.OS === "web" ? styles3.inputWeb : null,
967
+ Platform.OS === "android" ? styles3.inputAndroid : null,
740
968
  inputStyle
741
969
  ],
742
- accessibilityState: { disabled: isDisabled }
970
+ accessibilityLabel: resolvedAccessibilityLabel,
971
+ accessibilityState: { disabled }
743
972
  }
744
973
  ),
745
974
  hasRightIcon ? onRightIconPress ? /* @__PURE__ */ jsx(
746
975
  TouchableOpacity,
747
976
  {
748
977
  onPress: onRightIconPress,
749
- disabled: isDisabled,
750
- style: [styles2.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }],
978
+ disabled,
979
+ style: [styles3.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }],
751
980
  accessibilityRole: "button",
981
+ accessibilityLabel: rightIconAccessibilityLabel,
752
982
  hitSlop: 8,
753
983
  children: rightIconNode
754
984
  }
755
- ) : /* @__PURE__ */ jsx(View, { style: [styles2.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }], children: rightIconNode }) : null
985
+ ) : /* @__PURE__ */ jsx(View, { style: [styles3.iconSlot, { width: metrics.iconSize, height: metrics.iconSize }], children: rightIconNode }) : null
756
986
  ]
757
987
  }
758
988
  ),
759
- showHint && hint ? /* @__PURE__ */ jsx(Text, { style: [styles2.hint, { color: chrome.hintColor }], children: hint }) : null
989
+ showHint && hint ? /* @__PURE__ */ jsx(Text, { style: [styles3.hint, { color: chrome.hintColor }], children: hint }) : null
760
990
  ] });
761
- }
762
- var styles2 = StyleSheet.create({
991
+ });
992
+ var styles3 = StyleSheet.create({
763
993
  root: {
764
994
  width: DEFAULT_WIDTH,
765
995
  gap: 8,
@@ -796,7 +1026,925 @@ var styles2 = StyleSheet.create({
796
1026
  ...inputTypography.hint
797
1027
  }
798
1028
  });
1029
+ var DEFAULT_WIDTH2 = 308;
1030
+ var TRIGGER_HEIGHT = 44;
1031
+ var TRIGGER_RADIUS = 60;
1032
+ var MENU_RADIUS = 24;
1033
+ var MENU_MAX_LIST_HEIGHT = 248;
1034
+ var ITEM_RADIUS = 12;
1035
+ var ICON_SIZE = 20;
1036
+ var CHIP_GAP = 6;
1037
+ var FALLBACK_ELLIPSIS_WIDTH = 20;
1038
+ function itemBackground(state) {
1039
+ switch (state) {
1040
+ case "hover":
1041
+ return colors.grey600;
1042
+ case "selected":
1043
+ return colors.primaryMuted;
1044
+ default:
1045
+ return "transparent";
1046
+ }
1047
+ }
1048
+ function toArray(value) {
1049
+ if (value == null || value === "") return [];
1050
+ return Array.isArray(value) ? value : [value];
1051
+ }
1052
+ function resolveVisibleOptions(options, containerWidth, chipWidths, ellipsisWidth) {
1053
+ if (options.length === 0) return { visible: [], hasOverflow: false };
1054
+ if (containerWidth <= 0) return { visible: options.slice(0, 1), hasOverflow: options.length > 1 };
1055
+ const visible = [];
1056
+ let used = 0;
1057
+ for (let index = 0; index < options.length; index += 1) {
1058
+ const option = options[index];
1059
+ const chipWidth = chipWidths[option.value];
1060
+ if (chipWidth == null) {
1061
+ if (visible.length === 0) visible.push(option);
1062
+ break;
1063
+ }
1064
+ const remainingAfter = options.length - index - 1;
1065
+ const gap = visible.length > 0 ? CHIP_GAP : 0;
1066
+ const reserve = remainingAfter > 0 ? CHIP_GAP + ellipsisWidth : 0;
1067
+ const nextUsed = used + gap + chipWidth;
1068
+ if (visible.length > 0 && nextUsed + reserve > containerWidth) {
1069
+ return { visible, hasOverflow: true };
1070
+ }
1071
+ visible.push(option);
1072
+ used = nextUsed;
1073
+ }
1074
+ return { visible, hasOverflow: visible.length < options.length };
1075
+ }
1076
+ function MultiValueChips({ options, disabled, onRemove }) {
1077
+ const [containerWidth, setContainerWidth] = useState(0);
1078
+ const [chipWidths, setChipWidths] = useState({});
1079
+ const [ellipsisWidth, setEllipsisWidth] = useState(FALLBACK_ELLIPSIS_WIDTH);
1080
+ useEffect(() => {
1081
+ setChipWidths((current) => {
1082
+ const validValues = new Set(options.map((option) => option.value));
1083
+ const keys = Object.keys(current);
1084
+ if (keys.every((key) => validValues.has(key))) return current;
1085
+ const next = {};
1086
+ for (const key of keys) {
1087
+ if (validValues.has(key)) next[key] = current[key];
1088
+ }
1089
+ return next;
1090
+ });
1091
+ }, [options]);
1092
+ const { visible, hasOverflow } = useMemo(
1093
+ () => resolveVisibleOptions(options, containerWidth, chipWidths, ellipsisWidth),
1094
+ [chipWidths, containerWidth, ellipsisWidth, options]
1095
+ );
1096
+ const handleContainerLayout = (event) => {
1097
+ const next = Math.floor(event.nativeEvent.layout.width);
1098
+ setContainerWidth((current) => current === next ? current : next);
1099
+ };
1100
+ const handleChipLayout = (value, event) => {
1101
+ const next = Math.ceil(event.nativeEvent.layout.width);
1102
+ setChipWidths((current) => current[value] === next ? current : { ...current, [value]: next });
1103
+ };
1104
+ const handleEllipsisLayout = (event) => {
1105
+ const next = Math.ceil(event.nativeEvent.layout.width);
1106
+ setEllipsisWidth((current) => current === next ? current : next);
1107
+ };
1108
+ return /* @__PURE__ */ jsxs(View, { style: styles4.multiValueRoot, children: [
1109
+ /* @__PURE__ */ jsxs(View, { pointerEvents: "none", style: styles4.measureRow, children: [
1110
+ options.map((option) => /* @__PURE__ */ jsxs(
1111
+ View,
1112
+ {
1113
+ style: styles4.chip,
1114
+ onLayout: (event) => handleChipLayout(option.value, event),
1115
+ children: [
1116
+ /* @__PURE__ */ jsx(Text, { style: styles4.chipLabel, numberOfLines: 1, children: option.label }),
1117
+ /* @__PURE__ */ jsx(Text, { style: styles4.chipRemove, children: "\xD7" })
1118
+ ]
1119
+ },
1120
+ `measure-${option.value}`
1121
+ )),
1122
+ /* @__PURE__ */ jsx(View, { style: styles4.ellipsis, onLayout: handleEllipsisLayout, children: /* @__PURE__ */ jsx(Text, { style: styles4.ellipsisText, children: "..." }) })
1123
+ ] }),
1124
+ /* @__PURE__ */ jsxs(View, { style: styles4.chipsRow, onLayout: handleContainerLayout, children: [
1125
+ visible.map((option) => /* @__PURE__ */ jsxs(View, { style: styles4.chip, children: [
1126
+ /* @__PURE__ */ jsx(Text, { style: styles4.chipLabel, numberOfLines: 1, children: option.label }),
1127
+ /* @__PURE__ */ jsx(
1128
+ Pressable,
1129
+ {
1130
+ onPress: (event) => {
1131
+ event?.stopPropagation?.();
1132
+ onRemove(option.value);
1133
+ },
1134
+ disabled,
1135
+ hitSlop: 6,
1136
+ accessibilityRole: "button",
1137
+ accessibilityLabel: `Remove ${option.label}`,
1138
+ children: /* @__PURE__ */ jsx(Text, { style: styles4.chipRemove, children: "\xD7" })
1139
+ }
1140
+ )
1141
+ ] }, option.value)),
1142
+ hasOverflow ? /* @__PURE__ */ jsx(View, { style: styles4.ellipsis, children: /* @__PURE__ */ jsx(Text, { style: styles4.ellipsisText, children: "..." }) }) : null
1143
+ ] })
1144
+ ] });
1145
+ }
1146
+ var Select = forwardRef(
1147
+ function Select2(props, forwardedRef) {
1148
+ const {
1149
+ label = "Label",
1150
+ showLabel = true,
1151
+ hint,
1152
+ showHint = false,
1153
+ placeholder = "placeholder",
1154
+ options,
1155
+ open: openProp,
1156
+ defaultOpen = false,
1157
+ onOpenChange,
1158
+ disabled = false,
1159
+ error = false,
1160
+ leftIcon,
1161
+ showLeftIcon = true,
1162
+ showSearch = true,
1163
+ searchPlaceholder = "Search...",
1164
+ onSearchChange,
1165
+ loading = false,
1166
+ emptyText = "No results",
1167
+ style,
1168
+ className,
1169
+ accessibilityLabel,
1170
+ // Pulled out only to keep them off `rest` (which is spread onto the root View);
1171
+ // the real values are read from `props` directly below to preserve discriminated typing.
1172
+ multiple: _multiple,
1173
+ value: _value,
1174
+ defaultValue: _defaultValue,
1175
+ onValueChange: _onValueChange,
1176
+ ...rest
1177
+ } = props;
1178
+ const multiple = props.multiple === true;
1179
+ const valueProp = props.value;
1180
+ const rootRef = useRef(null);
1181
+ const triggerRef = useRef(null);
1182
+ const searchInputRef = useRef(null);
1183
+ const setRootRef = useMemo(() => mergeRefs(rootRef, forwardedRef), [forwardedRef]);
1184
+ const isOpenControlled = typeof openProp === "boolean";
1185
+ const isValueControlled = valueProp !== void 0;
1186
+ const [uncontrolledSingle, setUncontrolledSingle] = useState(
1187
+ !multiple ? props.defaultValue ?? "" : ""
1188
+ );
1189
+ const [uncontrolledMultiple, setUncontrolledMultiple] = useState(
1190
+ multiple ? props.defaultValue ?? [] : []
1191
+ );
1192
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
1193
+ const [searchQuery, setSearchQuery] = useState("");
1194
+ const [hoveredValue, setHoveredValue] = useState(null);
1195
+ const selectedValues = useMemo(() => {
1196
+ const current = isValueControlled ? valueProp : multiple ? uncontrolledMultiple : uncontrolledSingle;
1197
+ return toArray(current);
1198
+ }, [isValueControlled, multiple, valueProp, uncontrolledMultiple, uncontrolledSingle]);
1199
+ const isOpen = isOpenControlled ? openProp : uncontrolledOpen;
1200
+ const selectedOptions = useMemo(
1201
+ () => selectedValues.map((value) => options.find((option) => option.value === value)).filter((option) => option != null),
1202
+ [options, selectedValues]
1203
+ );
1204
+ const hasValue = selectedOptions.length > 0;
1205
+ const isExternalSearch = onSearchChange != null;
1206
+ const filteredOptions = useMemo(() => {
1207
+ if (isExternalSearch) return options;
1208
+ const query = searchQuery.trim().toLowerCase();
1209
+ if (!query) return options;
1210
+ return options.filter((option) => option.label.toLowerCase().includes(query));
1211
+ }, [isExternalSearch, options, searchQuery]);
1212
+ useApplyWebClassName(rootRef, className);
1213
+ const setOpen = useCallback(
1214
+ (next) => {
1215
+ if (!isOpenControlled) setUncontrolledOpen(next);
1216
+ onOpenChange?.(next);
1217
+ if (next) {
1218
+ setHoveredValue(selectedValues[0] ?? null);
1219
+ } else {
1220
+ setSearchQuery("");
1221
+ setHoveredValue(null);
1222
+ onSearchChange?.("");
1223
+ }
1224
+ },
1225
+ [isOpenControlled, onOpenChange, onSearchChange, selectedValues]
1226
+ );
1227
+ const handleSearchChange = (text) => {
1228
+ setSearchQuery(text);
1229
+ onSearchChange?.(text);
1230
+ };
1231
+ useEffect(() => {
1232
+ if (Platform.OS !== "web" || !isOpen) return;
1233
+ const handlePointerDown = (event) => {
1234
+ const root = rootRef.current;
1235
+ const target = event.target;
1236
+ if (root?.contains && target instanceof Node && !root.contains(target)) {
1237
+ setOpen(false);
1238
+ }
1239
+ };
1240
+ document.addEventListener("mousedown", handlePointerDown);
1241
+ document.addEventListener("touchstart", handlePointerDown);
1242
+ return () => {
1243
+ document.removeEventListener("mousedown", handlePointerDown);
1244
+ document.removeEventListener("touchstart", handlePointerDown);
1245
+ };
1246
+ }, [isOpen, setOpen]);
1247
+ const commitValues = useCallback(
1248
+ (nextValues) => {
1249
+ if (multiple) {
1250
+ if (!isValueControlled) setUncontrolledMultiple(nextValues);
1251
+ props.onValueChange?.(nextValues);
1252
+ return;
1253
+ }
1254
+ const nextValue = nextValues[0] ?? "";
1255
+ if (!isValueControlled) setUncontrolledSingle(nextValue);
1256
+ props.onValueChange?.(nextValue);
1257
+ },
1258
+ [isValueControlled, multiple, props]
1259
+ );
1260
+ const handleTriggerPress = () => {
1261
+ if (disabled) return;
1262
+ setOpen(!isOpen);
1263
+ };
1264
+ const handleSelect = useCallback(
1265
+ (optionValue) => {
1266
+ if (disabled) return;
1267
+ if (multiple) {
1268
+ const exists = selectedValues.includes(optionValue);
1269
+ const nextValues = exists ? selectedValues.filter((value) => value !== optionValue) : [...selectedValues, optionValue];
1270
+ commitValues(nextValues);
1271
+ return;
1272
+ }
1273
+ commitValues([optionValue]);
1274
+ setOpen(false);
1275
+ },
1276
+ [commitValues, disabled, multiple, selectedValues, setOpen]
1277
+ );
1278
+ const handleRemoveChip = (optionValue) => {
1279
+ if (disabled || !multiple) return;
1280
+ commitValues(selectedValues.filter((value) => value !== optionValue));
1281
+ };
1282
+ const focusTrigger = useCallback(() => {
1283
+ const node = triggerRef.current;
1284
+ node?.focus?.();
1285
+ }, []);
1286
+ const closeAndFocusTrigger = useCallback(() => {
1287
+ setOpen(false);
1288
+ focusTrigger();
1289
+ }, [focusTrigger, setOpen]);
1290
+ useEffect(() => {
1291
+ if (Platform.OS !== "web") return;
1292
+ const isTriggerFocused = () => document.activeElement === triggerRef.current;
1293
+ const isSearchFocused = () => document.activeElement === searchInputRef.current;
1294
+ const handleKeyDown = (event) => {
1295
+ if (!isOpen) {
1296
+ if (!isTriggerFocused() || disabled) return;
1297
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter") {
1298
+ event.preventDefault();
1299
+ setOpen(true);
1300
+ }
1301
+ return;
1302
+ }
1303
+ if (event.key === "Escape") {
1304
+ event.preventDefault();
1305
+ closeAndFocusTrigger();
1306
+ return;
1307
+ }
1308
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1309
+ event.preventDefault();
1310
+ setHoveredValue((current) => {
1311
+ if (filteredOptions.length === 0) return current;
1312
+ const currentIndex = filteredOptions.findIndex((option) => option.value === current);
1313
+ const delta = event.key === "ArrowDown" ? 1 : -1;
1314
+ const nextIndex = currentIndex === -1 ? delta === 1 ? 0 : filteredOptions.length - 1 : Math.min(Math.max(currentIndex + delta, 0), filteredOptions.length - 1);
1315
+ return filteredOptions[nextIndex]?.value ?? current;
1316
+ });
1317
+ return;
1318
+ }
1319
+ if (isSearchFocused() && (event.key === "Home" || event.key === "End" || event.key === " ")) {
1320
+ return;
1321
+ }
1322
+ if (event.key === "Home" || event.key === "End") {
1323
+ if (filteredOptions.length === 0) return;
1324
+ event.preventDefault();
1325
+ setHoveredValue(
1326
+ event.key === "Home" ? filteredOptions[0].value : filteredOptions[filteredOptions.length - 1].value
1327
+ );
1328
+ return;
1329
+ }
1330
+ if (event.key === "Enter" || event.key === " ") {
1331
+ if (hoveredValue == null) return;
1332
+ event.preventDefault();
1333
+ handleSelect(hoveredValue);
1334
+ if (!multiple) focusTrigger();
1335
+ }
1336
+ };
1337
+ document.addEventListener("keydown", handleKeyDown);
1338
+ return () => document.removeEventListener("keydown", handleKeyDown);
1339
+ }, [
1340
+ isOpen,
1341
+ disabled,
1342
+ filteredOptions,
1343
+ hoveredValue,
1344
+ multiple,
1345
+ closeAndFocusTrigger,
1346
+ focusTrigger,
1347
+ handleSelect,
1348
+ setOpen
1349
+ ]);
1350
+ const leftIconNode = leftIcon ?? /* @__PURE__ */ jsx(
1351
+ UserIcon,
1352
+ {
1353
+ size: ICON_SIZE,
1354
+ color: error ? colors.red : isOpen ? colors.primary : colors.grey100
1355
+ }
1356
+ );
1357
+ const hasLeftIcon = showLeftIcon || leftIcon != null;
1358
+ const triggerBorderColor = error ? colors.redMuted : isOpen ? colors.primaryMuted : colors.grey700;
1359
+ const triggerTextColor = hasValue ? error ? colors.red : colors.white : error ? colors.red : colors.grey100;
1360
+ const labelColor = error ? colors.red : colors.white;
1361
+ const hintColor = error ? colors.red : colors.grey100;
1362
+ const singleLabel = selectedOptions[0]?.label ?? placeholder;
1363
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (typeof label === "string" ? label : void 0);
1364
+ return /* @__PURE__ */ jsxs(
1365
+ View,
1366
+ {
1367
+ ...rest,
1368
+ ref: setRootRef,
1369
+ style: [styles4.root, isOpen && styles4.rootOpen, disabled && styles4.disabled, style],
1370
+ accessibilityState: { disabled, expanded: isOpen },
1371
+ children: [
1372
+ showLabel && label ? /* @__PURE__ */ jsx(Text, { style: [styles4.label, { color: labelColor }], children: label }) : null,
1373
+ /* @__PURE__ */ jsxs(View, { style: [styles4.triggerWrap, isOpen && styles4.triggerWrapOpen], children: [
1374
+ /* @__PURE__ */ jsxs(
1375
+ Pressable,
1376
+ {
1377
+ ref: triggerRef,
1378
+ onPress: handleTriggerPress,
1379
+ disabled,
1380
+ accessibilityRole: "combobox",
1381
+ accessibilityLabel: resolvedAccessibilityLabel,
1382
+ accessibilityState: { disabled, expanded: isOpen },
1383
+ style: [
1384
+ styles4.trigger,
1385
+ {
1386
+ borderColor: triggerBorderColor,
1387
+ backgroundColor: colors.grey700
1388
+ }
1389
+ ],
1390
+ children: [
1391
+ hasLeftIcon ? /* @__PURE__ */ jsx(View, { style: styles4.iconSlot, children: leftIconNode }) : null,
1392
+ /* @__PURE__ */ jsx(View, { style: styles4.triggerContent, children: multiple && hasValue ? /* @__PURE__ */ jsx(
1393
+ MultiValueChips,
1394
+ {
1395
+ options: selectedOptions,
1396
+ disabled,
1397
+ onRemove: handleRemoveChip
1398
+ }
1399
+ ) : /* @__PURE__ */ jsx(Text, { style: [styles4.triggerText, { color: triggerTextColor }], numberOfLines: 1, children: multiple ? placeholder : singleLabel }) }),
1400
+ /* @__PURE__ */ jsx(View, { style: [styles4.iconSlot, isOpen && styles4.chevronOpen], children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: ICON_SIZE, color: colors.grey100 }) })
1401
+ ]
1402
+ }
1403
+ ),
1404
+ isOpen ? /* @__PURE__ */ jsxs(View, { style: styles4.menu, children: [
1405
+ showSearch ? /* @__PURE__ */ jsxs(View, { style: styles4.searchField, children: [
1406
+ /* @__PURE__ */ jsx(View, { style: styles4.iconSlot, children: /* @__PURE__ */ jsx(SearchIcon, { size: ICON_SIZE, color: colors.grey100 }) }),
1407
+ /* @__PURE__ */ jsx(
1408
+ TextInput,
1409
+ {
1410
+ ref: searchInputRef,
1411
+ value: searchQuery,
1412
+ onChangeText: handleSearchChange,
1413
+ editable: !disabled,
1414
+ placeholder: searchPlaceholder,
1415
+ placeholderTextColor: colors.grey100,
1416
+ style: [
1417
+ styles4.searchInput,
1418
+ Platform.OS === "web" ? styles4.searchInputWeb : null,
1419
+ Platform.OS === "android" ? styles4.searchInputAndroid : null
1420
+ ],
1421
+ accessibilityLabel: searchPlaceholder
1422
+ }
1423
+ )
1424
+ ] }) : null,
1425
+ /* @__PURE__ */ jsxs(
1426
+ ScrollView,
1427
+ {
1428
+ style: styles4.optionList,
1429
+ contentContainerStyle: styles4.optionListContent,
1430
+ keyboardShouldPersistTaps: "handled",
1431
+ showsVerticalScrollIndicator: false,
1432
+ children: [
1433
+ loading ? /* @__PURE__ */ jsx(View, { style: styles4.statusRow, children: /* @__PURE__ */ jsx(Text, { style: styles4.statusText, children: "Loading..." }) }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx(View, { style: styles4.statusRow, children: /* @__PURE__ */ jsx(Text, { style: styles4.statusText, children: emptyText }) }) : null,
1434
+ !loading && filteredOptions.map((option) => {
1435
+ const isSelected = selectedValues.includes(option.value);
1436
+ const isHovered = hoveredValue === option.value;
1437
+ const visualState = isSelected ? "selected" : isHovered ? "hover" : "default";
1438
+ return /* @__PURE__ */ jsxs(
1439
+ Pressable,
1440
+ {
1441
+ onPress: () => handleSelect(option.value),
1442
+ disabled,
1443
+ onHoverIn: () => setHoveredValue(option.value),
1444
+ onHoverOut: () => setHoveredValue((current) => current === option.value ? null : current),
1445
+ onPressIn: () => setHoveredValue(option.value),
1446
+ onPressOut: () => setHoveredValue((current) => current === option.value ? null : current),
1447
+ accessibilityRole: multiple ? "checkbox" : "button",
1448
+ accessibilityState: { selected: isSelected, checked: isSelected, disabled },
1449
+ style: [
1450
+ styles4.item,
1451
+ {
1452
+ backgroundColor: itemBackground(visualState)
1453
+ }
1454
+ ],
1455
+ children: [
1456
+ multiple ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: styles4.itemCheckbox, children: /* @__PURE__ */ jsx(Checkbox, { value: isSelected, variant: "light" }) }) : null,
1457
+ /* @__PURE__ */ jsx(Text, { style: styles4.itemLabel, numberOfLines: 1, children: option.label })
1458
+ ]
1459
+ },
1460
+ option.value
1461
+ );
1462
+ })
1463
+ ]
1464
+ }
1465
+ )
1466
+ ] }) : null
1467
+ ] }),
1468
+ showHint && hint ? /* @__PURE__ */ jsx(Text, { style: [styles4.hint, { color: hintColor }], children: hint }) : null
1469
+ ]
1470
+ }
1471
+ );
1472
+ }
1473
+ );
1474
+ var styles4 = StyleSheet.create({
1475
+ root: {
1476
+ width: DEFAULT_WIDTH2,
1477
+ gap: 8,
1478
+ alignSelf: "flex-start"
1479
+ },
1480
+ rootOpen: {
1481
+ zIndex: 30
1482
+ },
1483
+ disabled: {
1484
+ opacity: 0.6
1485
+ },
1486
+ label: {
1487
+ ...selectTypography.label
1488
+ },
1489
+ triggerWrap: {
1490
+ position: "relative",
1491
+ zIndex: 1
1492
+ },
1493
+ triggerWrapOpen: {
1494
+ zIndex: 20
1495
+ },
1496
+ trigger: {
1497
+ height: TRIGGER_HEIGHT,
1498
+ borderRadius: TRIGGER_RADIUS,
1499
+ borderWidth: 1,
1500
+ paddingVertical: 12,
1501
+ paddingHorizontal: 16,
1502
+ flexDirection: "row",
1503
+ alignItems: "center",
1504
+ gap: 10,
1505
+ overflow: "hidden"
1506
+ },
1507
+ triggerContent: {
1508
+ flex: 1,
1509
+ justifyContent: "center",
1510
+ minWidth: 0,
1511
+ overflow: "hidden"
1512
+ },
1513
+ triggerText: {
1514
+ ...selectTypography.field
1515
+ },
1516
+ multiValueRoot: {
1517
+ width: "100%",
1518
+ position: "relative"
1519
+ },
1520
+ measureRow: {
1521
+ position: "absolute",
1522
+ left: 0,
1523
+ top: 0,
1524
+ flexDirection: "row",
1525
+ opacity: 0,
1526
+ zIndex: -1
1527
+ },
1528
+ chipsRow: {
1529
+ flexDirection: "row",
1530
+ alignItems: "center",
1531
+ gap: CHIP_GAP,
1532
+ overflow: "hidden"
1533
+ },
1534
+ chip: {
1535
+ flexDirection: "row",
1536
+ alignItems: "center",
1537
+ gap: 4,
1538
+ paddingVertical: 2,
1539
+ paddingHorizontal: 8,
1540
+ borderRadius: 999,
1541
+ backgroundColor: colors.grey600,
1542
+ flexShrink: 0
1543
+ },
1544
+ chipLabel: {
1545
+ ...selectTypography.hint,
1546
+ color: colors.white,
1547
+ maxWidth: 120
1548
+ },
1549
+ chipRemove: {
1550
+ color: colors.grey100,
1551
+ fontSize: 14,
1552
+ lineHeight: 14
1553
+ },
1554
+ ellipsis: {
1555
+ flexShrink: 0,
1556
+ paddingHorizontal: 2
1557
+ },
1558
+ ellipsisText: {
1559
+ ...selectTypography.field,
1560
+ color: colors.white,
1561
+ lineHeight: 16
1562
+ },
1563
+ iconSlot: {
1564
+ width: ICON_SIZE,
1565
+ height: ICON_SIZE,
1566
+ alignItems: "center",
1567
+ justifyContent: "center",
1568
+ flexShrink: 0
1569
+ },
1570
+ chevronOpen: {
1571
+ transform: [{ rotate: "180deg" }]
1572
+ },
1573
+ menu: {
1574
+ position: "absolute",
1575
+ top: "100%",
1576
+ left: 0,
1577
+ right: 0,
1578
+ marginTop: 8,
1579
+ zIndex: 10,
1580
+ borderRadius: MENU_RADIUS,
1581
+ padding: 12,
1582
+ gap: 8,
1583
+ backgroundColor: colors.grey700,
1584
+ ...Platform.select({
1585
+ web: {
1586
+ boxShadow: `0 8px 24px ${colors.black}73`
1587
+ },
1588
+ default: {
1589
+ elevation: 8
1590
+ }
1591
+ })
1592
+ },
1593
+ optionList: {
1594
+ maxHeight: MENU_MAX_LIST_HEIGHT
1595
+ },
1596
+ optionListContent: {
1597
+ gap: 8
1598
+ },
1599
+ statusRow: {
1600
+ minHeight: 43,
1601
+ padding: 12,
1602
+ justifyContent: "center"
1603
+ },
1604
+ statusText: {
1605
+ ...selectTypography.field,
1606
+ color: colors.grey100
1607
+ },
1608
+ searchField: {
1609
+ height: 40,
1610
+ borderRadius: ITEM_RADIUS,
1611
+ paddingHorizontal: 12,
1612
+ flexDirection: "row",
1613
+ alignItems: "center",
1614
+ gap: 8,
1615
+ backgroundColor: colors.grey800
1616
+ },
1617
+ searchInput: {
1618
+ ...selectTypography.field,
1619
+ flex: 1,
1620
+ color: colors.white,
1621
+ paddingVertical: 0,
1622
+ margin: 0
1623
+ },
1624
+ searchInputWeb: {
1625
+ outlineStyle: "none"
1626
+ },
1627
+ searchInputAndroid: {
1628
+ includeFontPadding: false
1629
+ },
1630
+ item: {
1631
+ minHeight: 43,
1632
+ borderRadius: ITEM_RADIUS,
1633
+ padding: 12,
1634
+ flexDirection: "row",
1635
+ alignItems: "center",
1636
+ gap: 8
1637
+ },
1638
+ itemCheckbox: {
1639
+ flexShrink: 0
1640
+ },
1641
+ itemLabel: {
1642
+ ...selectTypography.field,
1643
+ color: colors.white,
1644
+ flex: 1
1645
+ },
1646
+ hint: {
1647
+ ...selectTypography.hint
1648
+ }
1649
+ });
1650
+ var DEFAULT_WIDTH3 = 308;
1651
+ var FIELD_HEIGHT = 100;
1652
+ var FIELD_RADIUS = 16;
1653
+ var FIELD_PADDING_VERTICAL = 12;
1654
+ var FIELD_PADDING_HORIZONTAL = 16;
1655
+ function resolveVisualState2({
1656
+ disabled,
1657
+ error,
1658
+ focused,
1659
+ hasValue
1660
+ }) {
1661
+ if (disabled) return "disabled";
1662
+ if (error) return "error";
1663
+ if (focused) return "active";
1664
+ if (hasValue) return "filled";
1665
+ return "default";
1666
+ }
1667
+ function chromeFor2(state) {
1668
+ const base = {
1669
+ borderColor: colors.grey700,
1670
+ backgroundColor: colors.grey700,
1671
+ textColor: colors.white,
1672
+ placeholderColor: colors.grey100,
1673
+ labelColor: colors.white,
1674
+ hintColor: colors.grey100
1675
+ };
1676
+ switch (state) {
1677
+ case "active":
1678
+ return {
1679
+ ...base,
1680
+ borderColor: colors.primaryMuted
1681
+ };
1682
+ case "error":
1683
+ return {
1684
+ ...base,
1685
+ borderColor: colors.redMuted,
1686
+ textColor: colors.red,
1687
+ placeholderColor: colors.red,
1688
+ labelColor: colors.red,
1689
+ hintColor: colors.red
1690
+ };
1691
+ case "filled":
1692
+ return base;
1693
+ case "disabled":
1694
+ return {
1695
+ ...base,
1696
+ textColor: colors.grey0
1697
+ };
1698
+ default:
1699
+ return base;
1700
+ }
1701
+ }
1702
+ var Textarea = forwardRef(function Textarea2({
1703
+ label = "Label",
1704
+ showLabel = true,
1705
+ hint = "Hint",
1706
+ showHint = true,
1707
+ placeholder = "placeholder",
1708
+ disabled = false,
1709
+ error = false,
1710
+ value,
1711
+ defaultValue,
1712
+ onChangeText,
1713
+ onFocus,
1714
+ onBlur,
1715
+ style,
1716
+ fieldStyle,
1717
+ inputStyle,
1718
+ className,
1719
+ inputClassName,
1720
+ accessibilityLabel,
1721
+ ...textInputProps
1722
+ }, forwardedRef) {
1723
+ const rootRef = useRef(null);
1724
+ const inputRef = useRef(null);
1725
+ const setInputRef = useMemo(() => mergeRefs(inputRef, forwardedRef), [forwardedRef]);
1726
+ const [focused, setFocused] = useState(false);
1727
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? "");
1728
+ const isControlled = typeof value === "string";
1729
+ const currentValue = isControlled ? value : uncontrolledValue;
1730
+ const hasValue = currentValue.length > 0;
1731
+ const visualState = resolveVisualState2({ disabled, error, focused, hasValue });
1732
+ const chrome = chromeFor2(visualState);
1733
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (showLabel ? void 0 : label);
1734
+ useApplyWebClassName(rootRef, className);
1735
+ useApplyWebClassName(inputRef, inputClassName);
1736
+ return /* @__PURE__ */ jsxs(View, { ref: rootRef, style: [styles5.root, disabled && styles5.disabled, style], children: [
1737
+ showLabel && label ? /* @__PURE__ */ jsx(Text, { style: [styles5.label, { color: chrome.labelColor }], children: label }) : null,
1738
+ /* @__PURE__ */ jsx(
1739
+ View,
1740
+ {
1741
+ style: [
1742
+ styles5.field,
1743
+ {
1744
+ borderColor: chrome.borderColor,
1745
+ backgroundColor: chrome.backgroundColor
1746
+ },
1747
+ fieldStyle
1748
+ ],
1749
+ children: /* @__PURE__ */ jsx(
1750
+ TextInput,
1751
+ {
1752
+ ref: setInputRef,
1753
+ ...textInputProps,
1754
+ multiline: true,
1755
+ textAlignVertical: "top",
1756
+ value: isControlled ? value : void 0,
1757
+ defaultValue: isControlled ? void 0 : defaultValue,
1758
+ editable: !disabled,
1759
+ placeholder,
1760
+ placeholderTextColor: chrome.placeholderColor,
1761
+ onChangeText: (text) => {
1762
+ if (!isControlled) setUncontrolledValue(text);
1763
+ onChangeText?.(text);
1764
+ },
1765
+ onFocus: (event) => {
1766
+ setFocused(true);
1767
+ onFocus?.(event);
1768
+ },
1769
+ onBlur: (event) => {
1770
+ setFocused(false);
1771
+ onBlur?.(event);
1772
+ },
1773
+ style: [
1774
+ styles5.input,
1775
+ textareaTypography.field,
1776
+ { color: chrome.textColor },
1777
+ Platform.OS === "web" ? styles5.inputWeb : null,
1778
+ Platform.OS === "android" ? styles5.inputAndroid : null,
1779
+ inputStyle
1780
+ ],
1781
+ accessibilityLabel: resolvedAccessibilityLabel,
1782
+ accessibilityState: { disabled }
1783
+ }
1784
+ )
1785
+ }
1786
+ ),
1787
+ showHint && hint ? /* @__PURE__ */ jsx(Text, { style: [styles5.hint, { color: chrome.hintColor }], children: hint }) : null
1788
+ ] });
1789
+ });
1790
+ var styles5 = StyleSheet.create({
1791
+ root: {
1792
+ width: DEFAULT_WIDTH3,
1793
+ gap: 8,
1794
+ alignSelf: "flex-start"
1795
+ },
1796
+ disabled: {
1797
+ opacity: 0.6
1798
+ },
1799
+ label: {
1800
+ ...textareaTypography.label
1801
+ },
1802
+ field: {
1803
+ height: FIELD_HEIGHT,
1804
+ borderRadius: FIELD_RADIUS,
1805
+ borderWidth: 1,
1806
+ paddingTop: FIELD_PADDING_VERTICAL,
1807
+ paddingBottom: FIELD_PADDING_VERTICAL,
1808
+ paddingLeft: FIELD_PADDING_HORIZONTAL,
1809
+ paddingRight: FIELD_PADDING_HORIZONTAL
1810
+ },
1811
+ input: {
1812
+ flex: 1,
1813
+ paddingVertical: 0,
1814
+ margin: 0
1815
+ },
1816
+ inputWeb: {
1817
+ outlineStyle: "none",
1818
+ resize: "none"
1819
+ },
1820
+ inputAndroid: {
1821
+ includeFontPadding: false
1822
+ },
1823
+ hint: {
1824
+ ...textareaTypography.hint
1825
+ }
1826
+ });
1827
+ var TRACK_WIDTH = 44;
1828
+ var TRACK_HEIGHT = 24;
1829
+ var TRACK_RADIUS = 43;
1830
+ var TRACK_PADDING = 4;
1831
+ var THUMB_SIZE = TRACK_HEIGHT - TRACK_PADDING * 2;
1832
+ var THUMB_TRAVEL = TRACK_WIDTH - TRACK_PADDING * 2 - THUMB_SIZE;
1833
+ var ANIMATION_DURATION = 300;
1834
+ var Toggle = forwardRef(function Toggle2({
1835
+ value,
1836
+ defaultValue = false,
1837
+ onValueChange,
1838
+ disabled = false,
1839
+ label,
1840
+ children,
1841
+ accessibilityLabel,
1842
+ style,
1843
+ labelStyle,
1844
+ className,
1845
+ hitSlop = 10,
1846
+ ...rest
1847
+ }, forwardedRef) {
1848
+ const containerRef = useRef(null);
1849
+ const isControlled = typeof value === "boolean";
1850
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
1851
+ const isActive = isControlled ? value : uncontrolledValue;
1852
+ const labelContent = children ?? label;
1853
+ const resolvedAccessibilityLabel = accessibilityLabel ?? (typeof labelContent === "string" ? labelContent : void 0);
1854
+ const setContainerRef = useMemo(() => mergeRefs(containerRef, forwardedRef), [forwardedRef]);
1855
+ const progress = useRef(new Animated.Value(isActive ? 1 : 0)).current;
1856
+ useApplyWebClassName(containerRef, className);
1857
+ useEffect(() => {
1858
+ Animated.timing(progress, {
1859
+ toValue: isActive ? 1 : 0,
1860
+ duration: ANIMATION_DURATION,
1861
+ easing: Easing.out(Easing.ease),
1862
+ useNativeDriver: false
1863
+ }).start();
1864
+ }, [isActive, progress]);
1865
+ const handlePress = () => {
1866
+ if (disabled) return;
1867
+ const next = !isActive;
1868
+ if (!isControlled) setUncontrolledValue(next);
1869
+ onValueChange?.(next);
1870
+ };
1871
+ const trackBackgroundColor = progress.interpolate({
1872
+ inputRange: [0, 1],
1873
+ outputRange: [colors.grey700, colors.primary]
1874
+ });
1875
+ const thumbTranslateX = progress.interpolate({
1876
+ inputRange: [0, 1],
1877
+ outputRange: [0, THUMB_TRAVEL]
1878
+ });
1879
+ return /* @__PURE__ */ jsxs(
1880
+ Pressable,
1881
+ {
1882
+ ...rest,
1883
+ ref: setContainerRef,
1884
+ onPress: handlePress,
1885
+ disabled,
1886
+ hitSlop,
1887
+ accessibilityRole: "switch",
1888
+ accessibilityLabel: resolvedAccessibilityLabel,
1889
+ accessibilityState: { checked: isActive, disabled },
1890
+ style: [styles6.pressable, disabled && styles6.disabled, style],
1891
+ children: [
1892
+ /* @__PURE__ */ jsx(
1893
+ Animated.View,
1894
+ {
1895
+ style: [
1896
+ styles6.track,
1897
+ {
1898
+ backgroundColor: trackBackgroundColor
1899
+ }
1900
+ ],
1901
+ children: /* @__PURE__ */ jsx(
1902
+ Animated.View,
1903
+ {
1904
+ style: [
1905
+ styles6.thumb,
1906
+ {
1907
+ transform: [{ translateX: thumbTranslateX }]
1908
+ }
1909
+ ]
1910
+ }
1911
+ )
1912
+ }
1913
+ ),
1914
+ labelContent != null && labelContent !== false ? typeof labelContent === "string" || typeof labelContent === "number" ? /* @__PURE__ */ jsx(Text, { style: [styles6.label, labelStyle], children: labelContent }) : labelContent : null
1915
+ ]
1916
+ }
1917
+ );
1918
+ });
1919
+ var styles6 = StyleSheet.create({
1920
+ pressable: {
1921
+ flexDirection: "row",
1922
+ alignItems: "center",
1923
+ alignSelf: "flex-start",
1924
+ gap: 10
1925
+ },
1926
+ disabled: {
1927
+ opacity: 0.6
1928
+ },
1929
+ track: {
1930
+ width: TRACK_WIDTH,
1931
+ height: TRACK_HEIGHT,
1932
+ borderRadius: TRACK_RADIUS,
1933
+ padding: TRACK_PADDING,
1934
+ justifyContent: "center"
1935
+ },
1936
+ thumb: {
1937
+ width: THUMB_SIZE,
1938
+ height: THUMB_SIZE,
1939
+ borderRadius: THUMB_SIZE / 2,
1940
+ backgroundColor: colors.white
1941
+ },
1942
+ label: {
1943
+ ...inputTypography.field,
1944
+ color: colors.white
1945
+ }
1946
+ });
799
1947
 
800
- export { ArrowRightIcon, BagIcon, BellIcon, BuildingIcon, Button, CameraIcon, CheckBadgeIcon, ClockIcon, FacebookIcon, HomeIcon, Icon, Input, InstagramIcon, KeyIcon, LinkedInIcon, MailIcon, NavigateIcon, PhoneIcon, ShowIcon, UserIcon, buttonTypography, colors, fonts, getIconsByGroup, grey, iconGroupNames, iconGroups, iconNames, icons, inputTypography };
1948
+ export { ArrowRightIcon, BagIcon, BellIcon, BuildingIcon, Button, CameraIcon, CheckBadgeIcon, CheckIcon, Checkbox, ChevronDownIcon, ClockIcon, FacebookIcon, HomeIcon, Icon, Input, InstagramIcon, KeyIcon, LinkedInIcon, MailIcon, NavigateIcon, PhoneIcon, SearchIcon, Select, ShowIcon, Textarea, Toggle, UserIcon, buttonTypography, colors, fonts, getIconsByGroup, grey, iconGroupNames, iconGroups, iconNames, icons, inputTypography, selectTypography, textareaTypography };
801
1949
  //# sourceMappingURL=index.js.map
802
1950
  //# sourceMappingURL=index.js.map