@scripso-homepad/ui 0.4.2 → 0.4.4

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 (81) hide show
  1. package/dist/{chunk-WDSMJWKC.js → chunk-66WR57JJ.js} +35 -3
  2. package/dist/chunk-66WR57JJ.js.map +1 -0
  3. package/dist/index.cjs +2258 -384
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +134 -1
  6. package/dist/index.d.ts +134 -1
  7. package/dist/index.js +1959 -97
  8. package/dist/index.js.map +1 -1
  9. package/dist/web/index.cjs +30650 -1009
  10. package/dist/web/index.cjs.map +1 -1
  11. package/dist/web/index.css +78 -0
  12. package/dist/web/index.css.map +1 -0
  13. package/dist/web/index.d.cts +267 -6
  14. package/dist/web/index.d.ts +267 -6
  15. package/dist/web/index.js +30179 -601
  16. package/dist/web/index.js.map +1 -1
  17. package/package.json +5 -4
  18. package/src/components/Calendar.stories.tsx +337 -0
  19. package/src/components/Calendar.tsx +441 -0
  20. package/src/components/DatePicker.stories.tsx +219 -0
  21. package/src/components/DatePicker.tsx +366 -0
  22. package/src/components/Select.stories.tsx +134 -0
  23. package/src/components/Select.tsx +465 -0
  24. package/src/css.d.ts +1 -0
  25. package/src/icons/CalendarIcon.tsx +28 -0
  26. package/src/icons/CalendarIcon.web.tsx +34 -0
  27. package/src/icons/ChevronDownIcon.tsx +11 -4
  28. package/src/icons/ChevronDownIcon.web.tsx +6 -4
  29. package/src/icons/ChevronNavIcons.tsx +44 -0
  30. package/src/icons/ChevronNavIcons.web.tsx +57 -0
  31. package/src/icons/calendarIconPaths.ts +2 -0
  32. package/src/icons/chevronDownPath.ts +1 -0
  33. package/src/icons/chevronNavPaths.ts +2 -0
  34. package/src/index.ts +41 -0
  35. package/src/theme/calendar.ts +357 -0
  36. package/src/theme/select.ts +247 -0
  37. package/src/utils/calendarDays.ts +273 -0
  38. package/src/utils/calendarLocaleContext.tsx +95 -0
  39. package/src/utils/calendarLocalization.ts +187 -0
  40. package/src/utils/countryDropdownScrollStyles.ts +53 -13
  41. package/src/utils/formatMultiSelectDisplay.ts +56 -0
  42. package/src/web/components/Badge.stories.tsx +43 -0
  43. package/src/web/components/Badge.tsx +35 -0
  44. package/src/web/components/Pagination.stories.tsx +78 -0
  45. package/src/web/components/Pagination.tsx +153 -0
  46. package/src/web/components/StatusBadge.tsx +20 -0
  47. package/src/web/components/Table.stories.tsx +415 -0
  48. package/src/web/components/Table.tsx +3 -0
  49. package/src/web/components/TableActionButton.tsx +67 -0
  50. package/src/web/components/TableActionsMenu.tsx +208 -0
  51. package/src/web/components/TableIconText.tsx +23 -0
  52. package/src/web/components/TableRowStatusActions.tsx +33 -0
  53. package/src/web/components/TableStatusActionsCell.tsx +29 -0
  54. package/src/web/components/pagination-utils.ts +39 -0
  55. package/src/web/components/table/DataTable.tsx +123 -0
  56. package/src/web/components/table/TablePrimitives.tsx +214 -0
  57. package/src/web/components/table/TableScrollArea.tsx +51 -0
  58. package/src/web/components/table/constants.ts +59 -0
  59. package/src/web/components/table/data-table-class-names.ts +26 -0
  60. package/src/web/components/table/index.ts +44 -0
  61. package/src/web/components/table/table-row-context.tsx +19 -0
  62. package/src/web/components/table/use-horizontal-scroll-state.ts +72 -0
  63. package/src/web/components/table-scroll.css +81 -0
  64. package/src/web/hooks/useOnClickOutside.ts +20 -5
  65. package/src/web/icons/TableMenuActivateIcon.tsx +27 -0
  66. package/src/web/icons/TableMenuCheckIcon.tsx +27 -0
  67. package/src/web/icons/TableMenuCloseIcon.tsx +27 -0
  68. package/src/web/icons/TableMenuEditIcon.tsx +27 -0
  69. package/src/web/icons/TableMenuInfoIcon.tsx +27 -0
  70. package/src/web/icons/TableMenuRefreshIcon.tsx +27 -0
  71. package/src/web/icons/TableMenuSuspendIcon.tsx +34 -0
  72. package/src/web/icons/TableMenuTrashIcon.tsx +27 -0
  73. package/src/web/icons/TableMoreIcon.tsx +41 -0
  74. package/src/web/icons/TableSortIcon.tsx +37 -0
  75. package/src/web/index.ts +74 -0
  76. package/src/web/layout/AppHeader.stories.tsx +2 -0
  77. package/src/web/layout/AppHeader.tsx +18 -14
  78. package/src/web/layout/DashboardLayout.stories.tsx +1 -0
  79. package/src/web/layout/DashboardLayout.tsx +4 -4
  80. package/src/web/layout/story-helpers.tsx +10 -2
  81. package/dist/chunk-WDSMJWKC.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  var react = require('react');
4
4
  var reactNative = require('react-native');
5
- var Svg = require('react-native-svg');
5
+ var Svg5 = require('react-native-svg');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
- var Svg__default = /*#__PURE__*/_interopDefault(Svg);
10
+ var Svg5__default = /*#__PURE__*/_interopDefault(Svg5);
11
11
 
12
12
  // src/components/Button.tsx
13
13
 
@@ -18,8 +18,8 @@ function ArrowUpRightIcon({
18
18
  color = "#08275d",
19
19
  strokeWidth = 2
20
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,
21
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
22
+ Svg5.Path,
23
23
  {
24
24
  d: ARROW_UP_RIGHT_PATH,
25
25
  stroke: color,
@@ -467,9 +467,9 @@ function EyeIcon({
467
467
  color = "#c7cdd1",
468
468
  strokeWidth = 2
469
469
  }) {
470
- return /* @__PURE__ */ jsxRuntime.jsxs(Svg__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: [
470
+ return /* @__PURE__ */ jsxRuntime.jsxs(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: [
471
471
  /* @__PURE__ */ jsxRuntime.jsx(
472
- Svg.Path,
472
+ Svg5.Path,
473
473
  {
474
474
  d: EYE_OPEN_OUTLINE_PATH,
475
475
  stroke: color,
@@ -479,7 +479,7 @@ function EyeIcon({
479
479
  }
480
480
  ),
481
481
  /* @__PURE__ */ jsxRuntime.jsx(
482
- Svg.Path,
482
+ Svg5.Path,
483
483
  {
484
484
  d: EYE_OPEN_PUPIL_PATH,
485
485
  stroke: color,
@@ -495,8 +495,8 @@ function EyeOffIcon({
495
495
  color = "#c7cdd1",
496
496
  strokeWidth = 2
497
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,
498
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
499
+ Svg5.Path,
500
500
  {
501
501
  d: EYE_OFF_PATH,
502
502
  stroke: color,
@@ -817,354 +817,642 @@ var styles3 = reactNative.StyleSheet.create({
817
817
  }
818
818
  });
819
819
 
820
- // src/data/countries.ts
821
- var defaultCountry = {
822
- code: "AM",
823
- name: "Armenia",
824
- dialCode: "+374"
825
- };
826
- var countries = [
827
- defaultCountry,
828
- { code: "AF", name: "Afghanistan", dialCode: "+93" },
829
- { code: "AL", name: "Albania", dialCode: "+355" },
830
- { code: "DZ", name: "Algeria", dialCode: "+213" },
831
- { code: "AR", name: "Argentina", dialCode: "+54" },
832
- { code: "AU", name: "Australia", dialCode: "+61" },
833
- { code: "AT", name: "Austria", dialCode: "+43" },
834
- { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
835
- { code: "BH", name: "Bahrain", dialCode: "+973" },
836
- { code: "BY", name: "Belarus", dialCode: "+375" },
837
- { code: "BE", name: "Belgium", dialCode: "+32" },
838
- { code: "BR", name: "Brazil", dialCode: "+55" },
839
- { code: "BG", name: "Bulgaria", dialCode: "+359" },
840
- { code: "CA", name: "Canada", dialCode: "+1" },
841
- { code: "CL", name: "Chile", dialCode: "+56" },
842
- { code: "CN", name: "China", dialCode: "+86" },
843
- { code: "CO", name: "Colombia", dialCode: "+57" },
844
- { code: "HR", name: "Croatia", dialCode: "+385" },
845
- { code: "CY", name: "Cyprus", dialCode: "+357" },
846
- { code: "CZ", name: "Czech Republic", dialCode: "+420" },
847
- { code: "DK", name: "Denmark", dialCode: "+45" },
848
- { code: "EG", name: "Egypt", dialCode: "+20" },
849
- { code: "EE", name: "Estonia", dialCode: "+372" },
850
- { code: "FI", name: "Finland", dialCode: "+358" },
851
- { code: "FR", name: "France", dialCode: "+33" },
852
- { code: "GE", name: "Georgia", dialCode: "+995" },
853
- { code: "DE", name: "Germany", dialCode: "+49" },
854
- { code: "GR", name: "Greece", dialCode: "+30" },
855
- { code: "HK", name: "Hong Kong", dialCode: "+852" },
856
- { code: "HU", name: "Hungary", dialCode: "+36" },
857
- { code: "IN", name: "India", dialCode: "+91" },
858
- { code: "ID", name: "Indonesia", dialCode: "+62" },
859
- { code: "IR", name: "Iran", dialCode: "+98" },
860
- { code: "IQ", name: "Iraq", dialCode: "+964" },
861
- { code: "IE", name: "Ireland", dialCode: "+353" },
862
- { code: "IL", name: "Israel", dialCode: "+972" },
863
- { code: "IT", name: "Italy", dialCode: "+39" },
864
- { code: "JP", name: "Japan", dialCode: "+81" },
865
- { code: "JO", name: "Jordan", dialCode: "+962" },
866
- { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
867
- { code: "KW", name: "Kuwait", dialCode: "+965" },
868
- { code: "LV", name: "Latvia", dialCode: "+371" },
869
- { code: "LB", name: "Lebanon", dialCode: "+961" },
870
- { code: "LT", name: "Lithuania", dialCode: "+370" },
871
- { code: "LU", name: "Luxembourg", dialCode: "+352" },
872
- { code: "MY", name: "Malaysia", dialCode: "+60" },
873
- { code: "MX", name: "Mexico", dialCode: "+52" },
874
- { code: "MD", name: "Moldova", dialCode: "+373" },
875
- { code: "NL", name: "Netherlands", dialCode: "+31" },
876
- { code: "NZ", name: "New Zealand", dialCode: "+64" },
877
- { code: "NG", name: "Nigeria", dialCode: "+234" },
878
- { code: "NO", name: "Norway", dialCode: "+47" },
879
- { code: "PK", name: "Pakistan", dialCode: "+92" },
880
- { code: "PS", name: "Palestine", dialCode: "+970" },
881
- { code: "PH", name: "Philippines", dialCode: "+63" },
882
- { code: "PL", name: "Poland", dialCode: "+48" },
883
- { code: "PT", name: "Portugal", dialCode: "+351" },
884
- { code: "QA", name: "Qatar", dialCode: "+974" },
885
- { code: "RO", name: "Romania", dialCode: "+40" },
886
- { code: "RU", name: "Russia", dialCode: "+7" },
887
- { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
888
- { code: "RS", name: "Serbia", dialCode: "+381" },
889
- { code: "SG", name: "Singapore", dialCode: "+65" },
890
- { code: "SK", name: "Slovakia", dialCode: "+421" },
891
- { code: "SI", name: "Slovenia", dialCode: "+386" },
892
- { code: "ZA", name: "South Africa", dialCode: "+27" },
893
- { code: "KR", name: "South Korea", dialCode: "+82" },
894
- { code: "ES", name: "Spain", dialCode: "+34" },
895
- { code: "SE", name: "Sweden", dialCode: "+46" },
896
- { code: "CH", name: "Switzerland", dialCode: "+41" },
897
- { code: "SY", name: "Syria", dialCode: "+963" },
898
- { code: "TW", name: "Taiwan", dialCode: "+886" },
899
- { code: "TH", name: "Thailand", dialCode: "+66" },
900
- { code: "TR", name: "Turkey", dialCode: "+90" },
901
- { code: "UA", name: "Ukraine", dialCode: "+380" },
902
- { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
903
- { code: "GB", name: "United Kingdom", dialCode: "+44" },
904
- { code: "US", name: "United States", dialCode: "+1" },
905
- { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
906
- { code: "VN", name: "Vietnam", dialCode: "+84" }
907
- ];
908
- function findCountry(code) {
909
- return countries.find((country) => country.code === code) ?? defaultCountry;
910
- }
911
-
912
820
  // src/icons/chevronDownPath.ts
913
821
  var CHEVRON_DOWN_PATH = "M4 6L8 10L12 6";
822
+ var CHEVRON_DOWN_PATH_20 = "M5 7.5L10 12.5L15 7.5";
914
823
  function ChevronDownIcon({
915
824
  size = 16,
916
825
  color = "#dadde0",
917
826
  strokeWidth = 2
918
827
  }) {
919
- return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
920
- Svg.Path,
828
+ const useLarge = size >= 20;
829
+ return /* @__PURE__ */ jsxRuntime.jsx(
830
+ Svg5__default.default,
921
831
  {
922
- d: CHEVRON_DOWN_PATH,
923
- stroke: color,
924
- strokeWidth,
925
- strokeLinecap: "round",
926
- strokeLinejoin: "round"
832
+ width: size,
833
+ height: size,
834
+ viewBox: useLarge ? "0 0 20 20" : "0 0 16 16",
835
+ fill: "none",
836
+ children: /* @__PURE__ */ jsxRuntime.jsx(
837
+ Svg5.Path,
838
+ {
839
+ d: useLarge ? CHEVRON_DOWN_PATH_20 : CHEVRON_DOWN_PATH,
840
+ stroke: color,
841
+ strokeWidth,
842
+ strokeLinecap: "round",
843
+ strokeLinejoin: "round"
844
+ }
845
+ )
927
846
  }
928
- ) });
929
- }
930
-
931
- // src/utils/countryFlag.ts
932
- function countryCodeToFlagEmoji(code) {
933
- const upper = code.trim().toUpperCase();
934
- if (upper.length !== 2) return "";
935
- return String.fromCodePoint(
936
- ...upper.split("").map((char) => 127462 - 65 + char.charCodeAt(0))
937
847
  );
938
848
  }
849
+ var SELECT_HEIGHT = 52;
850
+ var SELECT_PADDING = 16;
851
+ var SELECT_INNER_GAP = 10;
852
+ var SELECT_ICON_SIZE = 20;
853
+ var SELECT_LABEL_GAP = spacing.sm;
854
+ var SELECT_DROPDOWN_GAP = spacing.sm;
855
+ var SELECT_DROPDOWN_PADDING = spacing.sm;
856
+ var SELECT_DROPDOWN_MAX_HEIGHT = 317;
857
+ var SELECT_OPTION_HEIGHT = 43;
858
+ var SELECT_OPTION_GAP = spacing.sm;
859
+ var SELECT_CHEVRON_SIZE = 20;
860
+ var SELECT_CHEVRON_COLOR = colors.stormGray150;
861
+ var SELECT_CHEVRON_ROTATION_MS = 200;
862
+ var selectLabelTypography = {
863
+ fontFamily: fonts.sans,
864
+ fontSize: fontSize.sm,
865
+ fontWeight: fontWeight.medium,
866
+ lineHeight: fontSize.sm,
867
+ letterSpacing: 0,
868
+ color: colors.slateBlue
869
+ };
870
+ var selectValueTypography = {
871
+ fontFamily: fonts.sans,
872
+ fontSize: fontSize.md,
873
+ fontWeight: fontWeight.regular,
874
+ lineHeight: fontSize.md,
875
+ letterSpacing: 0,
876
+ textAlign: "left"
877
+ };
878
+ var INPUT_OUTLINE_WIDTH2 = 2;
879
+ function createOutlineStyle2(ringColor) {
880
+ return {
881
+ borderRadius: radii.lg + INPUT_OUTLINE_WIDTH2,
882
+ borderWidth: INPUT_OUTLINE_WIDTH2,
883
+ borderColor: ringColor,
884
+ padding: 0,
885
+ backgroundColor: colors.transparent,
886
+ width: "100%",
887
+ alignSelf: "stretch",
888
+ ...reactNative.Platform.OS !== "web" ? { overflow: "hidden" } : null
889
+ };
890
+ }
891
+ var defaultOutline2 = createOutlineStyle2(colors.transparent);
892
+ function getSelectFieldStyles(state) {
893
+ const containerBase = {
894
+ borderRadius: radii.lg,
895
+ ...reactNative.Platform.OS !== "web" ? { overflow: "hidden" } : null
896
+ };
897
+ const valueBase = {
898
+ ...selectValueTypography,
899
+ color: colors.slateBlue
900
+ };
901
+ switch (state) {
902
+ case "disabled":
903
+ return {
904
+ outline: defaultOutline2,
905
+ container: {
906
+ ...containerBase,
907
+ borderWidth: 1,
908
+ borderColor: colors.stormGray50,
909
+ backgroundColor: colors.stormGray50
910
+ },
911
+ value: { ...valueBase, color: colors.stormGray300 },
912
+ placeholder: colors.stormGray300,
913
+ icon: colors.stormGray150
914
+ };
915
+ case "error":
916
+ return {
917
+ outline: createOutlineStyle2(colors.inputOutlineError),
918
+ container: {
919
+ ...containerBase,
920
+ borderWidth: 1,
921
+ borderColor: colors.inputError,
922
+ backgroundColor: colors.white
923
+ },
924
+ value: { ...valueBase, color: colors.inputError },
925
+ placeholder: colors.stormGray200,
926
+ icon: colors.inputError
927
+ };
928
+ case "focused":
929
+ return {
930
+ outline: createOutlineStyle2(colors.inputOutlineFocus),
931
+ container: {
932
+ ...containerBase,
933
+ borderWidth: 1,
934
+ borderColor: colors.navy,
935
+ backgroundColor: colors.white
936
+ },
937
+ value: valueBase,
938
+ placeholder: colors.stormGray200,
939
+ icon: colors.navy
940
+ };
941
+ default:
942
+ return {
943
+ outline: defaultOutline2,
944
+ container: {
945
+ ...containerBase,
946
+ borderWidth: 1,
947
+ borderColor: colors.stormGray50,
948
+ backgroundColor: colors.white
949
+ },
950
+ value: valueBase,
951
+ placeholder: colors.stormGray200,
952
+ icon: colors.stormGray150
953
+ };
954
+ }
955
+ }
956
+ var selectFieldMetrics = reactNative.StyleSheet.create({
957
+ container: {
958
+ flexDirection: "row",
959
+ alignItems: "center",
960
+ height: SELECT_HEIGHT,
961
+ borderRadius: radii.lg,
962
+ padding: SELECT_PADDING,
963
+ gap: SELECT_INNER_GAP,
964
+ ...reactNative.Platform.OS === "web" ? {
965
+ boxSizing: "border-box"
966
+ } : null
967
+ },
968
+ value: {
969
+ flex: 1,
970
+ minWidth: 0,
971
+ ...selectValueTypography,
972
+ paddingVertical: 0,
973
+ paddingHorizontal: 0,
974
+ margin: 0,
975
+ ...reactNative.Platform.OS === "android" ? { includeFontPadding: false } : null,
976
+ ...reactNative.Platform.OS === "web" ? {
977
+ outlineStyle: "none"
978
+ } : null
979
+ }
980
+ });
981
+ var selectDropdownMetrics = reactNative.StyleSheet.create({
982
+ menu: {
983
+ borderRadius: radii.lg,
984
+ borderWidth: 1,
985
+ borderColor: colors.stormGray50,
986
+ backgroundColor: colors.white,
987
+ padding: SELECT_DROPDOWN_PADDING,
988
+ overflow: "hidden"
989
+ },
990
+ option: {
991
+ width: "100%",
992
+ height: SELECT_OPTION_HEIGHT,
993
+ minHeight: SELECT_OPTION_HEIGHT,
994
+ maxHeight: SELECT_OPTION_HEIGHT,
995
+ paddingTop: 12,
996
+ paddingRight: spacing.sm,
997
+ paddingBottom: 12,
998
+ paddingLeft: spacing.sm,
999
+ justifyContent: "center",
1000
+ alignItems: "flex-start"
1001
+ },
1002
+ optionLabel: {
1003
+ fontFamily: fonts.sans,
1004
+ fontSize: fontSize.md,
1005
+ fontWeight: fontWeight.regular,
1006
+ lineHeight: fontSize.md,
1007
+ letterSpacing: 0,
1008
+ textAlign: "left",
1009
+ color: colors.slateBlue,
1010
+ width: "100%"
1011
+ },
1012
+ optionLabelSelected: {
1013
+ fontWeight: fontWeight.medium,
1014
+ color: colors.slateBlue
1015
+ },
1016
+ optionSelected: {
1017
+ opacity: 1,
1018
+ borderRadius: radii.sm,
1019
+ paddingTop: 12,
1020
+ paddingRight: spacing.sm,
1021
+ paddingBottom: 12,
1022
+ paddingLeft: spacing.sm,
1023
+ backgroundColor: colors.countrySelectorSelectedBg
1024
+ },
1025
+ optionHighlighted: {
1026
+ backgroundColor: colors.stormGray0
1027
+ }
1028
+ });
1029
+ function resolveSelectDropdownHeight(optionCount) {
1030
+ const contentHeight = optionCount * SELECT_OPTION_HEIGHT + Math.max(0, optionCount - 1) * SELECT_OPTION_GAP + SELECT_DROPDOWN_PADDING * 2;
1031
+ return Math.min(contentHeight, SELECT_DROPDOWN_MAX_HEIGHT);
1032
+ }
1033
+ function resolveSelectDropdownTop(anchor, dropdownHeight) {
1034
+ const windowHeight = reactNative.Dimensions.get("window").height;
1035
+ const spaceBelow = windowHeight - (anchor.y + anchor.height + SELECT_DROPDOWN_GAP);
1036
+ const spaceAbove = anchor.y - SELECT_DROPDOWN_GAP;
1037
+ const topBelow = anchor.y + anchor.height + SELECT_DROPDOWN_GAP;
1038
+ const topAbove = anchor.y - SELECT_DROPDOWN_GAP - dropdownHeight;
1039
+ if (spaceBelow >= dropdownHeight) {
1040
+ return topBelow;
1041
+ }
1042
+ if (spaceAbove >= dropdownHeight) {
1043
+ return topAbove;
1044
+ }
1045
+ if (spaceAbove > spaceBelow) {
1046
+ return Math.max(0, topAbove);
1047
+ }
1048
+ return Math.max(0, Math.min(topBelow, windowHeight - dropdownHeight));
1049
+ }
939
1050
  var COUNTRY_DROPDOWN_SCROLL_CLASS = "hp-country-dropdown-scroll";
940
- var STYLE_ID = "hp-country-dropdown-scroll-styles";
941
- var countryDropdownScrollCss = `
942
- .${COUNTRY_DROPDOWN_SCROLL_CLASS} {
1051
+ var SELECT_DROPDOWN_SCROLL_CLASS = "hp-select-dropdown-scroll";
1052
+ var STYLE_ID = "hp-dropdown-scroll-styles";
1053
+ function createDropdownScrollCss(className) {
1054
+ return `
1055
+ .${className} {
943
1056
  scrollbar-width: thin;
944
1057
  scrollbar-color: ${colors.stormGray300} transparent;
945
1058
  overflow-y: auto;
946
1059
  }
947
1060
 
948
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar {
1061
+ .${className}::-webkit-scrollbar {
949
1062
  width: 4px;
1063
+ -webkit-appearance: none;
1064
+ appearance: none;
950
1065
  }
951
1066
 
952
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-corner {
1067
+ .${className}::-webkit-scrollbar-corner {
953
1068
  background: transparent;
954
1069
  }
955
1070
 
956
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button,
957
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:single-button,
958
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:vertical:start:decrement,
959
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-button:vertical:end:increment {
1071
+ .${className}::-webkit-scrollbar-button,
1072
+ .${className}::-webkit-scrollbar-button:single-button,
1073
+ .${className}::-webkit-scrollbar-button:double-button,
1074
+ .${className}::-webkit-scrollbar-button:horizontal:decrement,
1075
+ .${className}::-webkit-scrollbar-button:horizontal:increment,
1076
+ .${className}::-webkit-scrollbar-button:horizontal:start:decrement,
1077
+ .${className}::-webkit-scrollbar-button:horizontal:end:increment,
1078
+ .${className}::-webkit-scrollbar-button:vertical:decrement,
1079
+ .${className}::-webkit-scrollbar-button:vertical:increment,
1080
+ .${className}::-webkit-scrollbar-button:vertical:start:decrement,
1081
+ .${className}::-webkit-scrollbar-button:vertical:end:increment,
1082
+ .${className}::-webkit-scrollbar-button:start:decrement,
1083
+ .${className}::-webkit-scrollbar-button:end:increment,
1084
+ .${className}::-webkit-scrollbar-button:decrement,
1085
+ .${className}::-webkit-scrollbar-button:increment {
960
1086
  display: none;
961
1087
  width: 0;
962
1088
  height: 0;
1089
+ max-width: 0;
1090
+ max-height: 0;
1091
+ min-width: 0;
1092
+ min-height: 0;
1093
+ padding: 0;
1094
+ margin: 0;
1095
+ border: 0;
1096
+ background: transparent;
963
1097
  -webkit-appearance: none;
964
1098
  appearance: none;
965
1099
  }
966
1100
 
967
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-track {
1101
+ .${className}::-webkit-scrollbar-track {
968
1102
  background: transparent;
969
1103
  }
970
1104
 
971
- .${COUNTRY_DROPDOWN_SCROLL_CLASS}::-webkit-scrollbar-thumb {
1105
+ .${className}::-webkit-scrollbar-thumb {
972
1106
  background-color: ${colors.stormGray300};
973
1107
  border-radius: 9999px;
974
1108
  }
975
1109
  `;
976
- function ensureCountryDropdownScrollStyles() {
1110
+ }
1111
+ var dropdownScrollCss = [
1112
+ createDropdownScrollCss(COUNTRY_DROPDOWN_SCROLL_CLASS),
1113
+ createDropdownScrollCss(SELECT_DROPDOWN_SCROLL_CLASS)
1114
+ ].join("\n");
1115
+ function ensureDropdownScrollStyles() {
977
1116
  if (reactNative.Platform.OS !== "web" || typeof document === "undefined") return;
978
1117
  if (document.getElementById(STYLE_ID)) return;
979
1118
  const style = document.createElement("style");
980
1119
  style.id = STYLE_ID;
981
- style.textContent = countryDropdownScrollCss;
1120
+ style.textContent = dropdownScrollCss;
982
1121
  document.head.appendChild(style);
983
1122
  }
984
- var DROPDOWN_GAP = 10;
985
- var DROPDOWN_HEIGHT = 186;
986
- var DROPDOWN_PADDING = 8;
987
- var OPTION_GAP = 10;
988
- var OPTION_HEIGHT = 35;
989
- var TRIGGER_HEIGHT = 52;
990
- var CHEVRON_SIZE = 16;
991
- function resolveDropdownTop(anchor) {
992
- const windowHeight = reactNative.Dimensions.get("window").height;
993
- const topBelow = anchor.y + anchor.height + DROPDOWN_GAP;
994
- const topAbove = anchor.y - DROPDOWN_GAP - DROPDOWN_HEIGHT;
995
- const fitsBelow = topBelow + DROPDOWN_HEIGHT <= windowHeight;
996
- if (fitsBelow) return topBelow;
997
- if (topAbove >= 0) return topAbove;
998
- return Math.max(0, Math.min(topBelow, windowHeight - DROPDOWN_HEIGHT));
1123
+ function ensureCountryDropdownScrollStyles() {
1124
+ ensureDropdownScrollStyles();
999
1125
  }
1000
- function CountryCodeSelector({
1001
- value = defaultCountry.code,
1002
- onValueChange,
1003
- options = countries,
1004
- disabled = false,
1005
- style,
1006
- className
1007
- }) {
1126
+ function ensureSelectDropdownScrollStyles() {
1127
+ ensureDropdownScrollStyles();
1128
+ }
1129
+
1130
+ // src/utils/formatMultiSelectDisplay.ts
1131
+ var MULTI_SELECT_SUFFIX = " ... + ";
1132
+ var MULTI_SELECT_SUFFIX_UNIT = " items";
1133
+ function estimateTextWidth(text, size = fontSize.md) {
1134
+ return text.length * size * 0.58;
1135
+ }
1136
+ function formatMultiSelectDisplay(labels, maxWidth, textSize = fontSize.md) {
1137
+ if (labels.length === 0) {
1138
+ return "";
1139
+ }
1140
+ if (labels.length === 1) {
1141
+ return labels[0];
1142
+ }
1143
+ const fits = (text) => estimateTextWidth(text, textSize) <= maxWidth;
1144
+ const fullText = labels.join(", ");
1145
+ if (fits(fullText)) {
1146
+ return fullText;
1147
+ }
1148
+ for (let visibleCount = labels.length - 1; visibleCount >= 1; visibleCount -= 1) {
1149
+ const hiddenCount = labels.length - visibleCount;
1150
+ const truncatedText = `${labels.slice(0, visibleCount).join(", ")}${MULTI_SELECT_SUFFIX}${hiddenCount}${MULTI_SELECT_SUFFIX_UNIT}`;
1151
+ if (fits(truncatedText)) {
1152
+ return truncatedText;
1153
+ }
1154
+ }
1155
+ return `... + ${labels.length}${MULTI_SELECT_SUFFIX_UNIT}`;
1156
+ }
1157
+ function resolveSelectedLabels(options, selectedValues) {
1158
+ if (selectedValues.length === 0) {
1159
+ return [];
1160
+ }
1161
+ const labelByValue = new Map(options.map((option) => [option.value, option.label]));
1162
+ return selectedValues.map((value) => labelByValue.get(value)).filter((label) => Boolean(label));
1163
+ }
1164
+ function renderSelectIcon(icon, color) {
1165
+ if (!icon) return null;
1166
+ if (react.isValidElement(icon)) {
1167
+ return react.cloneElement(icon, {
1168
+ size: icon.props.size ?? SELECT_ICON_SIZE,
1169
+ color: icon.props.color ?? color
1170
+ });
1171
+ }
1172
+ return icon;
1173
+ }
1174
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
1175
+ function normalizeSelectedValues(multiple, value) {
1176
+ if (multiple) {
1177
+ if (Array.isArray(value)) {
1178
+ return value;
1179
+ }
1180
+ return value ? [value] : [];
1181
+ }
1182
+ return typeof value === "string" && value.length > 0 ? [value] : [];
1183
+ }
1184
+ function Select({
1185
+ label,
1186
+ placeholder = "placeholder",
1187
+ value,
1188
+ onValueChange,
1189
+ options,
1190
+ leftIcon,
1191
+ multiple = false,
1192
+ disabled = false,
1193
+ error,
1194
+ invalid,
1195
+ hint,
1196
+ containerStyle,
1197
+ fieldStyle,
1198
+ className,
1199
+ fieldClassName,
1200
+ menuClassName,
1201
+ labelClassName,
1202
+ errorClassName,
1203
+ hintClassName
1204
+ }) {
1008
1205
  const wrapperRef = react.useRef(null);
1009
1206
  const triggerRef = react.useRef(null);
1207
+ const menuRef = react.useRef(null);
1010
1208
  const scrollRef = react.useRef(null);
1209
+ const helperRef = react.useRef(null);
1210
+ const chevronRotation = react.useRef(new reactNative.Animated.Value(0)).current;
1011
1211
  const [open, setOpen] = react.useState(false);
1012
1212
  const [anchor, setAnchor] = react.useState(null);
1213
+ const [highlightedIndex, setHighlightedIndex] = react.useState(-1);
1214
+ const [valueContainerWidth, setValueContainerWidth] = react.useState(0);
1013
1215
  useApplyWebClassName(wrapperRef, className);
1014
- useApplyWebClassName(
1015
- scrollRef,
1016
- COUNTRY_DROPDOWN_SCROLL_CLASS,
1017
- open && Boolean(anchor)
1018
- );
1019
- react.useLayoutEffect(() => {
1020
- ensureCountryDropdownScrollStyles();
1216
+ useApplyWebClassName(triggerRef, fieldClassName);
1217
+ useApplyWebClassName(menuRef, menuClassName);
1218
+ useApplyWebClassName(scrollRef, SELECT_DROPDOWN_SCROLL_CLASS, open && Boolean(anchor));
1219
+ useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
1220
+ useIsomorphicLayoutEffect(() => {
1221
+ ensureSelectDropdownScrollStyles();
1021
1222
  }, []);
1022
- const selected = findCountry(value);
1023
- const textColor = disabled ? colors.stormGray200 : colors.slateBlue;
1024
- function closeDropdown() {
1223
+ react.useEffect(() => {
1224
+ reactNative.Animated.timing(chevronRotation, {
1225
+ toValue: open ? 1 : 0,
1226
+ duration: SELECT_CHEVRON_ROTATION_MS,
1227
+ easing: reactNative.Easing.out(reactNative.Easing.ease),
1228
+ useNativeDriver: reactNative.Platform.OS !== "web"
1229
+ }).start();
1230
+ }, [chevronRotation, open]);
1231
+ const chevronRotate = chevronRotation.interpolate({
1232
+ inputRange: [0, 1],
1233
+ outputRange: ["0deg", "180deg"]
1234
+ });
1235
+ const hasError = Boolean(error) || Boolean(invalid);
1236
+ const visualState = resolveInputVisualState({
1237
+ focused: open,
1238
+ error: hasError,
1239
+ disabled
1240
+ });
1241
+ const fieldStyles = getSelectFieldStyles(visualState);
1242
+ const selectedValues = react.useMemo(
1243
+ () => normalizeSelectedValues(multiple, value),
1244
+ [multiple, value]
1245
+ );
1246
+ const selectedValueSet = react.useMemo(() => new Set(selectedValues), [selectedValues]);
1247
+ const selectedLabels = react.useMemo(
1248
+ () => resolveSelectedLabels(options, selectedValues),
1249
+ [options, selectedValues]
1250
+ );
1251
+ const selectableOptions = react.useMemo(
1252
+ () => options.filter((option) => !option.disabled),
1253
+ [options]
1254
+ );
1255
+ const selectableIndexByValue = react.useMemo(
1256
+ () => new Map(
1257
+ selectableOptions.map((option, index) => [option.value, index])
1258
+ ),
1259
+ [selectableOptions]
1260
+ );
1261
+ const displayLabel = react.useMemo(() => {
1262
+ if (selectedLabels.length === 0) {
1263
+ return placeholder;
1264
+ }
1265
+ if (!multiple) {
1266
+ return selectedLabels[0];
1267
+ }
1268
+ if (valueContainerWidth <= 0) {
1269
+ return selectedLabels.join(", ");
1270
+ }
1271
+ return formatMultiSelectDisplay(selectedLabels, valueContainerWidth);
1272
+ }, [multiple, placeholder, selectedLabels, valueContainerWidth]);
1273
+ const isPlaceholder = selectedLabels.length === 0;
1274
+ const dropdownHeight = resolveSelectDropdownHeight(options.length);
1275
+ const helperMessage = error ?? hint;
1276
+ function closeMenu() {
1025
1277
  setOpen(false);
1026
1278
  setAnchor(null);
1279
+ setHighlightedIndex(-1);
1027
1280
  }
1028
- function handleOpen() {
1029
- if (disabled) return;
1281
+ function openMenu() {
1282
+ if (disabled || selectableOptions.length === 0) {
1283
+ return;
1284
+ }
1030
1285
  triggerRef.current?.measureInWindow((x, y, width, height) => {
1286
+ const selectedIndex = selectableOptions.findIndex(
1287
+ (option) => selectedValueSet.has(option.value)
1288
+ );
1289
+ setHighlightedIndex(selectedIndex >= 0 ? selectedIndex : 0);
1031
1290
  setAnchor({ x, y, width, height });
1032
1291
  setOpen(true);
1033
1292
  });
1034
1293
  }
1035
- function handleSelect(code) {
1036
- onValueChange?.(code);
1037
- closeDropdown();
1294
+ function handleSelect(nextValue) {
1295
+ if (multiple) {
1296
+ const nextValues = selectedValues.includes(nextValue) ? selectedValues.filter((item) => item !== nextValue) : [...selectedValues, nextValue];
1297
+ onValueChange?.(nextValues);
1298
+ return;
1299
+ }
1300
+ onValueChange?.(nextValue);
1301
+ closeMenu();
1038
1302
  }
1039
- const dropdownTop = anchor ? resolveDropdownTop(anchor) : 0;
1040
- const optionList = options.map((item, index) => {
1041
- const isSelected = item.code === selected.code;
1303
+ const optionList = options.map((option, index) => {
1304
+ const selectableIndex = selectableIndexByValue.get(option.value) ?? -1;
1305
+ const isSelected = selectedValueSet.has(option.value);
1306
+ const isHighlighted = selectableIndex === highlightedIndex;
1042
1307
  const isLast = index === options.length - 1;
1043
- return /* @__PURE__ */ jsxRuntime.jsxs(
1308
+ return /* @__PURE__ */ jsxRuntime.jsx(
1044
1309
  reactNative.Pressable,
1045
1310
  {
1046
1311
  accessibilityRole: "button",
1047
- onPress: () => handleSelect(item.code),
1312
+ accessibilityState: { disabled: option.disabled, selected: isSelected },
1313
+ disabled: option.disabled,
1314
+ onPress: () => {
1315
+ if (!option.disabled) {
1316
+ handleSelect(option.value);
1317
+ }
1318
+ },
1319
+ onHoverIn: () => {
1320
+ if (!option.disabled && selectableIndex >= 0) {
1321
+ setHighlightedIndex(selectableIndex);
1322
+ }
1323
+ },
1048
1324
  style: [
1049
- styles4.option,
1050
- isSelected && styles4.optionSelected,
1051
- !isLast && styles4.optionSpacing
1325
+ selectDropdownMetrics.option,
1326
+ isSelected && selectDropdownMetrics.optionSelected,
1327
+ isHighlighted && !isSelected && !option.disabled ? selectDropdownMetrics.optionHighlighted : null,
1328
+ !isLast && styles4.optionSpacing,
1329
+ option.disabled && styles4.optionDisabled
1052
1330
  ],
1053
- children: [
1054
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.flag, children: countryCodeToFlagEmoji(item.code) }),
1055
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.optionDialCode, children: item.dialCode })
1056
- ]
1331
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1332
+ reactNative.Text,
1333
+ {
1334
+ style: [
1335
+ selectDropdownMetrics.optionLabel,
1336
+ isSelected && selectDropdownMetrics.optionLabelSelected,
1337
+ option.disabled && styles4.optionLabelDisabled
1338
+ ],
1339
+ numberOfLines: 1,
1340
+ children: option.label
1341
+ }
1342
+ )
1057
1343
  },
1058
- item.code
1344
+ option.value
1059
1345
  );
1060
1346
  });
1061
- const dropdownList = /* @__PURE__ */ jsxRuntime.jsx(
1062
- reactNative.ScrollView,
1063
- {
1064
- ref: scrollRef,
1065
- style: styles4.dropdownScroll,
1066
- contentContainerStyle: styles4.dropdownContent,
1067
- keyboardShouldPersistTaps: "handled",
1068
- showsVerticalScrollIndicator: true,
1069
- bounces: false,
1070
- nestedScrollEnabled: true,
1071
- children: optionList
1072
- }
1073
- );
1074
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles4.root, style], children: [
1075
- /* @__PURE__ */ jsxRuntime.jsxs(
1347
+ const dropdownTop = anchor ? resolveSelectDropdownTop(anchor, dropdownHeight) : 0;
1348
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles4.wrapper, containerStyle], children: [
1349
+ label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled, style: styles4.label, className: labelClassName, children: label }) : null,
1350
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: fieldStyles.outline, children: /* @__PURE__ */ jsxRuntime.jsxs(
1076
1351
  reactNative.Pressable,
1077
1352
  {
1078
1353
  ref: triggerRef,
1079
1354
  accessibilityRole: "button",
1355
+ accessibilityState: { disabled, expanded: open },
1080
1356
  disabled,
1081
- onPress: handleOpen,
1082
- style: [
1083
- styles4.trigger,
1084
- disabled ? styles4.triggerDisabled : styles4.triggerEnabled,
1085
- reactNative.Platform.OS === "web" ? styles4.triggerWeb : null
1086
- ],
1357
+ onPress: open ? closeMenu : openMenu,
1358
+ style: [selectFieldMetrics.container, fieldStyles.container, fieldStyle],
1087
1359
  children: [
1088
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.flag, children: countryCodeToFlagEmoji(selected.code) }),
1089
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.dialCode, { color: textColor }], children: selected.dialCode }),
1090
- /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { size: CHEVRON_SIZE, color: colors.stormGray100 })
1360
+ leftIcon ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.iconSlot, children: renderSelectIcon(leftIcon, fieldStyles.icon) }) : null,
1361
+ /* @__PURE__ */ jsxRuntime.jsx(
1362
+ reactNative.View,
1363
+ {
1364
+ style: styles4.valueContainer,
1365
+ onLayout: (event) => {
1366
+ setValueContainerWidth(event.nativeEvent.layout.width);
1367
+ },
1368
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1369
+ reactNative.Text,
1370
+ {
1371
+ style: [
1372
+ selectFieldMetrics.value,
1373
+ fieldStyles.value,
1374
+ isPlaceholder && { color: fieldStyles.placeholder }
1375
+ ],
1376
+ numberOfLines: 1,
1377
+ children: displayLabel
1378
+ }
1379
+ )
1380
+ }
1381
+ ),
1382
+ /* @__PURE__ */ jsxRuntime.jsx(
1383
+ reactNative.Animated.View,
1384
+ {
1385
+ style: [styles4.iconSlot, { transform: [{ rotate: chevronRotate }] }],
1386
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1387
+ ChevronDownIcon,
1388
+ {
1389
+ size: SELECT_CHEVRON_SIZE,
1390
+ color: disabled ? colors.stormGray200 : SELECT_CHEVRON_COLOR
1391
+ }
1392
+ )
1393
+ }
1394
+ )
1091
1395
  ]
1092
1396
  }
1093
- ),
1094
- /* @__PURE__ */ jsxRuntime.jsx(
1095
- reactNative.Modal,
1397
+ ) }),
1398
+ helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles4.error : styles4.hint, children: helperMessage }) : null,
1399
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible: open, transparent: true, animationType: "fade", onRequestClose: closeMenu, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles4.overlay, onPress: closeMenu, children: anchor ? /* @__PURE__ */ jsxRuntime.jsx(
1400
+ reactNative.View,
1096
1401
  {
1097
- visible: open,
1098
- transparent: true,
1099
- animationType: "fade",
1100
- onRequestClose: closeDropdown,
1101
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles4.overlay, onPress: closeDropdown, children: anchor ? /* @__PURE__ */ jsxRuntime.jsx(
1102
- reactNative.View,
1402
+ ref: menuRef,
1403
+ style: [
1404
+ selectDropdownMetrics.menu,
1405
+ styles4.dropdown,
1103
1406
  {
1104
- style: [
1105
- styles4.dropdown,
1106
- {
1107
- top: dropdownTop,
1108
- left: anchor.x,
1109
- width: anchor.width
1110
- }
1111
- ],
1112
- children: dropdownList
1407
+ top: dropdownTop,
1408
+ left: anchor.x,
1409
+ width: anchor.width,
1410
+ height: dropdownHeight
1113
1411
  }
1114
- ) : null })
1412
+ ],
1413
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1414
+ reactNative.ScrollView,
1415
+ {
1416
+ ref: scrollRef,
1417
+ style: styles4.dropdownScroll,
1418
+ contentContainerStyle: styles4.dropdownContent,
1419
+ keyboardShouldPersistTaps: "handled",
1420
+ showsVerticalScrollIndicator: true,
1421
+ bounces: false,
1422
+ nestedScrollEnabled: true,
1423
+ children: optionList
1424
+ }
1425
+ )
1115
1426
  }
1116
- )
1427
+ ) : null }) })
1117
1428
  ] });
1118
1429
  }
1119
1430
  var styles4 = reactNative.StyleSheet.create({
1120
- root: {
1121
- alignSelf: "flex-start",
1122
- flexShrink: 0
1123
- },
1124
- trigger: {
1125
- flexDirection: "row",
1126
- alignItems: "center",
1127
- alignSelf: "flex-start",
1128
- flexGrow: 0,
1129
- flexShrink: 0,
1130
- height: TRIGGER_HEIGHT,
1131
- borderRadius: radii.lg,
1132
- borderWidth: 1,
1133
- padding: spacing.lg,
1134
- gap: spacing.sm
1135
- },
1136
- triggerEnabled: {
1137
- borderColor: colors.stormGray50,
1138
- backgroundColor: colors.white
1139
- },
1140
- triggerDisabled: {
1141
- borderColor: colors.stormGray50,
1142
- backgroundColor: colors.stormGray50
1431
+ wrapper: {
1432
+ width: "100%",
1433
+ gap: SELECT_LABEL_GAP
1143
1434
  },
1144
- triggerWeb: {
1145
- width: "max-content"
1435
+ label: {
1436
+ ...selectLabelTypography
1146
1437
  },
1147
- flag: {
1148
- fontSize: 18,
1149
- lineHeight: 22
1438
+ iconSlot: {
1439
+ width: SELECT_ICON_SIZE,
1440
+ height: SELECT_ICON_SIZE,
1441
+ alignItems: "center",
1442
+ justifyContent: "center",
1443
+ flexShrink: 0
1150
1444
  },
1151
- dialCode: {
1152
- fontSize: fontSize.md,
1153
- fontWeight: fontWeight.medium
1445
+ valueContainer: {
1446
+ flex: 1,
1447
+ minWidth: 0,
1448
+ justifyContent: "center"
1154
1449
  },
1155
1450
  overlay: {
1156
1451
  flex: 1,
1157
- backgroundColor: "transparent"
1452
+ backgroundColor: colors.transparent
1158
1453
  },
1159
1454
  dropdown: {
1160
- position: "absolute",
1161
- height: DROPDOWN_HEIGHT,
1162
- borderRadius: radii.lg,
1163
- borderWidth: 1,
1164
- borderColor: colors.stormGray50,
1165
- backgroundColor: colors.white,
1166
- padding: DROPDOWN_PADDING,
1167
- overflow: "hidden"
1455
+ position: "absolute"
1168
1456
  },
1169
1457
  dropdownScroll: {
1170
1458
  flex: 1
@@ -1172,149 +1460,1723 @@ var styles4 = reactNative.StyleSheet.create({
1172
1460
  dropdownContent: {
1173
1461
  flexGrow: 1
1174
1462
  },
1175
- option: {
1176
- flexDirection: "row",
1177
- alignItems: "center",
1178
- height: OPTION_HEIGHT,
1179
- borderRadius: radii.sm,
1180
- padding: spacing.sm,
1181
- gap: spacing.sm
1182
- },
1183
1463
  optionSpacing: {
1184
- marginBottom: OPTION_GAP
1464
+ marginBottom: SELECT_OPTION_GAP
1185
1465
  },
1186
- optionSelected: {
1187
- backgroundColor: colors.countrySelectorSelectedBg
1466
+ optionDisabled: {
1467
+ opacity: 0.5
1188
1468
  },
1189
- optionDialCode: {
1190
- fontFamily: fonts.sans,
1191
- fontSize: fontSize.md,
1192
- fontWeight: fontWeight.regular,
1193
- lineHeight: fontSize.md,
1194
- letterSpacing: 0,
1195
- textAlign: "center",
1196
- color: colors.slateBlue
1469
+ optionLabelDisabled: {
1470
+ color: colors.stormGray300
1471
+ },
1472
+ error: {
1473
+ fontSize: 12,
1474
+ lineHeight: 12,
1475
+ color: colors.inputError
1476
+ },
1477
+ hint: {
1478
+ fontSize: 12,
1479
+ lineHeight: 12,
1480
+ color: colors.stormGray300
1197
1481
  }
1198
1482
  });
1199
- function PhoneInput({
1200
- label,
1201
- countryCode,
1202
- onCountryCodeChange,
1203
- error,
1204
- hint,
1205
- containerStyle,
1206
- style,
1207
- className,
1208
- labelClassName,
1209
- inputClassName,
1210
- errorClassName,
1211
- hintClassName,
1212
- editable = true,
1213
- onFocus,
1214
- onBlur,
1215
- ...props
1216
- }) {
1217
- const wrapperRef = react.useRef(null);
1218
- const inputRef = react.useRef(null);
1219
- const helperRef = react.useRef(null);
1220
- const [focused, setFocused] = react.useState(false);
1221
- useApplyWebClassName(wrapperRef, className);
1222
- useApplyWebClassName(inputRef, inputClassName);
1223
- useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
1224
- const isDisabled = editable === false;
1225
- const phoneVisualState = resolveInputVisualState({
1226
- focused,
1227
- error: Boolean(error),
1228
- disabled: isDisabled
1229
- });
1230
- const phoneFieldStyles = getInputFieldStyles(phoneVisualState);
1231
- function handleFocus(event) {
1232
- setFocused(true);
1233
- onFocus?.(event);
1234
- }
1235
- function handleBlur(event) {
1236
- setFocused(false);
1237
- onBlur?.(event);
1238
- }
1239
- const helperMessage = error ?? hint;
1240
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles5.wrapper, containerStyle], children: [
1241
- label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled: isDisabled, className: labelClassName, children: label }) : null,
1242
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.row, children: [
1243
- /* @__PURE__ */ jsxRuntime.jsx(
1244
- CountryCodeSelector,
1245
- {
1483
+
1484
+ // src/data/countries.ts
1485
+ var defaultCountry = {
1486
+ code: "AM",
1487
+ name: "Armenia",
1488
+ dialCode: "+374"
1489
+ };
1490
+ var countries = [
1491
+ defaultCountry,
1492
+ { code: "AF", name: "Afghanistan", dialCode: "+93" },
1493
+ { code: "AL", name: "Albania", dialCode: "+355" },
1494
+ { code: "DZ", name: "Algeria", dialCode: "+213" },
1495
+ { code: "AR", name: "Argentina", dialCode: "+54" },
1496
+ { code: "AU", name: "Australia", dialCode: "+61" },
1497
+ { code: "AT", name: "Austria", dialCode: "+43" },
1498
+ { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
1499
+ { code: "BH", name: "Bahrain", dialCode: "+973" },
1500
+ { code: "BY", name: "Belarus", dialCode: "+375" },
1501
+ { code: "BE", name: "Belgium", dialCode: "+32" },
1502
+ { code: "BR", name: "Brazil", dialCode: "+55" },
1503
+ { code: "BG", name: "Bulgaria", dialCode: "+359" },
1504
+ { code: "CA", name: "Canada", dialCode: "+1" },
1505
+ { code: "CL", name: "Chile", dialCode: "+56" },
1506
+ { code: "CN", name: "China", dialCode: "+86" },
1507
+ { code: "CO", name: "Colombia", dialCode: "+57" },
1508
+ { code: "HR", name: "Croatia", dialCode: "+385" },
1509
+ { code: "CY", name: "Cyprus", dialCode: "+357" },
1510
+ { code: "CZ", name: "Czech Republic", dialCode: "+420" },
1511
+ { code: "DK", name: "Denmark", dialCode: "+45" },
1512
+ { code: "EG", name: "Egypt", dialCode: "+20" },
1513
+ { code: "EE", name: "Estonia", dialCode: "+372" },
1514
+ { code: "FI", name: "Finland", dialCode: "+358" },
1515
+ { code: "FR", name: "France", dialCode: "+33" },
1516
+ { code: "GE", name: "Georgia", dialCode: "+995" },
1517
+ { code: "DE", name: "Germany", dialCode: "+49" },
1518
+ { code: "GR", name: "Greece", dialCode: "+30" },
1519
+ { code: "HK", name: "Hong Kong", dialCode: "+852" },
1520
+ { code: "HU", name: "Hungary", dialCode: "+36" },
1521
+ { code: "IN", name: "India", dialCode: "+91" },
1522
+ { code: "ID", name: "Indonesia", dialCode: "+62" },
1523
+ { code: "IR", name: "Iran", dialCode: "+98" },
1524
+ { code: "IQ", name: "Iraq", dialCode: "+964" },
1525
+ { code: "IE", name: "Ireland", dialCode: "+353" },
1526
+ { code: "IL", name: "Israel", dialCode: "+972" },
1527
+ { code: "IT", name: "Italy", dialCode: "+39" },
1528
+ { code: "JP", name: "Japan", dialCode: "+81" },
1529
+ { code: "JO", name: "Jordan", dialCode: "+962" },
1530
+ { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
1531
+ { code: "KW", name: "Kuwait", dialCode: "+965" },
1532
+ { code: "LV", name: "Latvia", dialCode: "+371" },
1533
+ { code: "LB", name: "Lebanon", dialCode: "+961" },
1534
+ { code: "LT", name: "Lithuania", dialCode: "+370" },
1535
+ { code: "LU", name: "Luxembourg", dialCode: "+352" },
1536
+ { code: "MY", name: "Malaysia", dialCode: "+60" },
1537
+ { code: "MX", name: "Mexico", dialCode: "+52" },
1538
+ { code: "MD", name: "Moldova", dialCode: "+373" },
1539
+ { code: "NL", name: "Netherlands", dialCode: "+31" },
1540
+ { code: "NZ", name: "New Zealand", dialCode: "+64" },
1541
+ { code: "NG", name: "Nigeria", dialCode: "+234" },
1542
+ { code: "NO", name: "Norway", dialCode: "+47" },
1543
+ { code: "PK", name: "Pakistan", dialCode: "+92" },
1544
+ { code: "PS", name: "Palestine", dialCode: "+970" },
1545
+ { code: "PH", name: "Philippines", dialCode: "+63" },
1546
+ { code: "PL", name: "Poland", dialCode: "+48" },
1547
+ { code: "PT", name: "Portugal", dialCode: "+351" },
1548
+ { code: "QA", name: "Qatar", dialCode: "+974" },
1549
+ { code: "RO", name: "Romania", dialCode: "+40" },
1550
+ { code: "RU", name: "Russia", dialCode: "+7" },
1551
+ { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
1552
+ { code: "RS", name: "Serbia", dialCode: "+381" },
1553
+ { code: "SG", name: "Singapore", dialCode: "+65" },
1554
+ { code: "SK", name: "Slovakia", dialCode: "+421" },
1555
+ { code: "SI", name: "Slovenia", dialCode: "+386" },
1556
+ { code: "ZA", name: "South Africa", dialCode: "+27" },
1557
+ { code: "KR", name: "South Korea", dialCode: "+82" },
1558
+ { code: "ES", name: "Spain", dialCode: "+34" },
1559
+ { code: "SE", name: "Sweden", dialCode: "+46" },
1560
+ { code: "CH", name: "Switzerland", dialCode: "+41" },
1561
+ { code: "SY", name: "Syria", dialCode: "+963" },
1562
+ { code: "TW", name: "Taiwan", dialCode: "+886" },
1563
+ { code: "TH", name: "Thailand", dialCode: "+66" },
1564
+ { code: "TR", name: "Turkey", dialCode: "+90" },
1565
+ { code: "UA", name: "Ukraine", dialCode: "+380" },
1566
+ { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
1567
+ { code: "GB", name: "United Kingdom", dialCode: "+44" },
1568
+ { code: "US", name: "United States", dialCode: "+1" },
1569
+ { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
1570
+ { code: "VN", name: "Vietnam", dialCode: "+84" }
1571
+ ];
1572
+ function findCountry(code) {
1573
+ return countries.find((country) => country.code === code) ?? defaultCountry;
1574
+ }
1575
+
1576
+ // src/utils/countryFlag.ts
1577
+ function countryCodeToFlagEmoji(code) {
1578
+ const upper = code.trim().toUpperCase();
1579
+ if (upper.length !== 2) return "";
1580
+ return String.fromCodePoint(
1581
+ ...upper.split("").map((char) => 127462 - 65 + char.charCodeAt(0))
1582
+ );
1583
+ }
1584
+ var DROPDOWN_GAP = 10;
1585
+ var DROPDOWN_HEIGHT = 186;
1586
+ var DROPDOWN_PADDING = 8;
1587
+ var OPTION_GAP = 10;
1588
+ var OPTION_HEIGHT = 35;
1589
+ var TRIGGER_HEIGHT = 52;
1590
+ var CHEVRON_SIZE = 16;
1591
+ function resolveDropdownTop(anchor) {
1592
+ const windowHeight = reactNative.Dimensions.get("window").height;
1593
+ const topBelow = anchor.y + anchor.height + DROPDOWN_GAP;
1594
+ const topAbove = anchor.y - DROPDOWN_GAP - DROPDOWN_HEIGHT;
1595
+ const fitsBelow = topBelow + DROPDOWN_HEIGHT <= windowHeight;
1596
+ if (fitsBelow) return topBelow;
1597
+ if (topAbove >= 0) return topAbove;
1598
+ return Math.max(0, Math.min(topBelow, windowHeight - DROPDOWN_HEIGHT));
1599
+ }
1600
+ function CountryCodeSelector({
1601
+ value = defaultCountry.code,
1602
+ onValueChange,
1603
+ options = countries,
1604
+ disabled = false,
1605
+ style,
1606
+ className
1607
+ }) {
1608
+ const wrapperRef = react.useRef(null);
1609
+ const triggerRef = react.useRef(null);
1610
+ const scrollRef = react.useRef(null);
1611
+ const [open, setOpen] = react.useState(false);
1612
+ const [anchor, setAnchor] = react.useState(null);
1613
+ useApplyWebClassName(wrapperRef, className);
1614
+ useApplyWebClassName(
1615
+ scrollRef,
1616
+ COUNTRY_DROPDOWN_SCROLL_CLASS,
1617
+ open && Boolean(anchor)
1618
+ );
1619
+ react.useLayoutEffect(() => {
1620
+ ensureCountryDropdownScrollStyles();
1621
+ }, []);
1622
+ const selected = findCountry(value);
1623
+ const textColor = disabled ? colors.stormGray200 : colors.slateBlue;
1624
+ function closeDropdown() {
1625
+ setOpen(false);
1626
+ setAnchor(null);
1627
+ }
1628
+ function handleOpen() {
1629
+ if (disabled) return;
1630
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
1631
+ setAnchor({ x, y, width, height });
1632
+ setOpen(true);
1633
+ });
1634
+ }
1635
+ function handleSelect(code) {
1636
+ onValueChange?.(code);
1637
+ closeDropdown();
1638
+ }
1639
+ const dropdownTop = anchor ? resolveDropdownTop(anchor) : 0;
1640
+ const optionList = options.map((item, index) => {
1641
+ const isSelected = item.code === selected.code;
1642
+ const isLast = index === options.length - 1;
1643
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1644
+ reactNative.Pressable,
1645
+ {
1646
+ accessibilityRole: "button",
1647
+ onPress: () => handleSelect(item.code),
1648
+ style: [
1649
+ styles5.option,
1650
+ isSelected && styles5.optionSelected,
1651
+ !isLast && styles5.optionSpacing
1652
+ ],
1653
+ children: [
1654
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles5.flag, children: countryCodeToFlagEmoji(item.code) }),
1655
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles5.optionDialCode, children: item.dialCode })
1656
+ ]
1657
+ },
1658
+ item.code
1659
+ );
1660
+ });
1661
+ const dropdownList = /* @__PURE__ */ jsxRuntime.jsx(
1662
+ reactNative.ScrollView,
1663
+ {
1664
+ ref: scrollRef,
1665
+ style: styles5.dropdownScroll,
1666
+ contentContainerStyle: styles5.dropdownContent,
1667
+ keyboardShouldPersistTaps: "handled",
1668
+ showsVerticalScrollIndicator: true,
1669
+ bounces: false,
1670
+ nestedScrollEnabled: true,
1671
+ children: optionList
1672
+ }
1673
+ );
1674
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles5.root, style], children: [
1675
+ /* @__PURE__ */ jsxRuntime.jsxs(
1676
+ reactNative.Pressable,
1677
+ {
1678
+ ref: triggerRef,
1679
+ accessibilityRole: "button",
1680
+ disabled,
1681
+ onPress: handleOpen,
1682
+ style: [
1683
+ styles5.trigger,
1684
+ disabled ? styles5.triggerDisabled : styles5.triggerEnabled,
1685
+ reactNative.Platform.OS === "web" ? styles5.triggerWeb : null
1686
+ ],
1687
+ children: [
1688
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles5.flag, children: countryCodeToFlagEmoji(selected.code) }),
1689
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.dialCode, { color: textColor }], children: selected.dialCode }),
1690
+ /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, { size: CHEVRON_SIZE, color: colors.stormGray100 })
1691
+ ]
1692
+ }
1693
+ ),
1694
+ /* @__PURE__ */ jsxRuntime.jsx(
1695
+ reactNative.Modal,
1696
+ {
1697
+ visible: open,
1698
+ transparent: true,
1699
+ animationType: "fade",
1700
+ onRequestClose: closeDropdown,
1701
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles5.overlay, onPress: closeDropdown, children: anchor ? /* @__PURE__ */ jsxRuntime.jsx(
1702
+ reactNative.View,
1703
+ {
1704
+ style: [
1705
+ styles5.dropdown,
1706
+ {
1707
+ top: dropdownTop,
1708
+ left: anchor.x,
1709
+ width: anchor.width
1710
+ }
1711
+ ],
1712
+ children: dropdownList
1713
+ }
1714
+ ) : null })
1715
+ }
1716
+ )
1717
+ ] });
1718
+ }
1719
+ var styles5 = reactNative.StyleSheet.create({
1720
+ root: {
1721
+ alignSelf: "flex-start",
1722
+ flexShrink: 0
1723
+ },
1724
+ trigger: {
1725
+ flexDirection: "row",
1726
+ alignItems: "center",
1727
+ alignSelf: "flex-start",
1728
+ flexGrow: 0,
1729
+ flexShrink: 0,
1730
+ height: TRIGGER_HEIGHT,
1731
+ borderRadius: radii.lg,
1732
+ borderWidth: 1,
1733
+ padding: spacing.lg,
1734
+ gap: spacing.sm
1735
+ },
1736
+ triggerEnabled: {
1737
+ borderColor: colors.stormGray50,
1738
+ backgroundColor: colors.white
1739
+ },
1740
+ triggerDisabled: {
1741
+ borderColor: colors.stormGray50,
1742
+ backgroundColor: colors.stormGray50
1743
+ },
1744
+ triggerWeb: {
1745
+ width: "max-content"
1746
+ },
1747
+ flag: {
1748
+ fontSize: 18,
1749
+ lineHeight: 22
1750
+ },
1751
+ dialCode: {
1752
+ fontSize: fontSize.md,
1753
+ fontWeight: fontWeight.medium
1754
+ },
1755
+ overlay: {
1756
+ flex: 1,
1757
+ backgroundColor: "transparent"
1758
+ },
1759
+ dropdown: {
1760
+ position: "absolute",
1761
+ height: DROPDOWN_HEIGHT,
1762
+ borderRadius: radii.lg,
1763
+ borderWidth: 1,
1764
+ borderColor: colors.stormGray50,
1765
+ backgroundColor: colors.white,
1766
+ padding: DROPDOWN_PADDING,
1767
+ overflow: "hidden"
1768
+ },
1769
+ dropdownScroll: {
1770
+ flex: 1
1771
+ },
1772
+ dropdownContent: {
1773
+ flexGrow: 1
1774
+ },
1775
+ option: {
1776
+ flexDirection: "row",
1777
+ alignItems: "center",
1778
+ height: OPTION_HEIGHT,
1779
+ borderRadius: radii.sm,
1780
+ padding: spacing.sm,
1781
+ gap: spacing.sm
1782
+ },
1783
+ optionSpacing: {
1784
+ marginBottom: OPTION_GAP
1785
+ },
1786
+ optionSelected: {
1787
+ backgroundColor: colors.countrySelectorSelectedBg
1788
+ },
1789
+ optionDialCode: {
1790
+ fontFamily: fonts.sans,
1791
+ fontSize: fontSize.md,
1792
+ fontWeight: fontWeight.regular,
1793
+ lineHeight: fontSize.md,
1794
+ letterSpacing: 0,
1795
+ textAlign: "center",
1796
+ color: colors.slateBlue
1797
+ }
1798
+ });
1799
+ function PhoneInput({
1800
+ label,
1801
+ countryCode,
1802
+ onCountryCodeChange,
1803
+ error,
1804
+ hint,
1805
+ containerStyle,
1806
+ style,
1807
+ className,
1808
+ labelClassName,
1809
+ inputClassName,
1810
+ errorClassName,
1811
+ hintClassName,
1812
+ editable = true,
1813
+ onFocus,
1814
+ onBlur,
1815
+ ...props
1816
+ }) {
1817
+ const wrapperRef = react.useRef(null);
1818
+ const inputRef = react.useRef(null);
1819
+ const helperRef = react.useRef(null);
1820
+ const [focused, setFocused] = react.useState(false);
1821
+ useApplyWebClassName(wrapperRef, className);
1822
+ useApplyWebClassName(inputRef, inputClassName);
1823
+ useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
1824
+ const isDisabled = editable === false;
1825
+ const phoneVisualState = resolveInputVisualState({
1826
+ focused,
1827
+ error: Boolean(error),
1828
+ disabled: isDisabled
1829
+ });
1830
+ const phoneFieldStyles = getInputFieldStyles(phoneVisualState);
1831
+ function handleFocus(event) {
1832
+ setFocused(true);
1833
+ onFocus?.(event);
1834
+ }
1835
+ function handleBlur(event) {
1836
+ setFocused(false);
1837
+ onBlur?.(event);
1838
+ }
1839
+ const helperMessage = error ?? hint;
1840
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles6.wrapper, containerStyle], children: [
1841
+ label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled: isDisabled, className: labelClassName, children: label }) : null,
1842
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.row, children: [
1843
+ /* @__PURE__ */ jsxRuntime.jsx(
1844
+ CountryCodeSelector,
1845
+ {
1246
1846
  value: countryCode,
1247
1847
  onValueChange: onCountryCodeChange,
1248
1848
  disabled: isDisabled,
1249
- style: styles5.countrySelector
1849
+ style: styles6.countrySelector
1850
+ }
1851
+ ),
1852
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.phoneColumn, children: [
1853
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [phoneFieldStyles.outline, styles6.phoneOutline], children: /* @__PURE__ */ jsxRuntime.jsx(
1854
+ reactNative.View,
1855
+ {
1856
+ style: [
1857
+ inputFieldMetrics.container,
1858
+ phoneFieldStyles.container,
1859
+ styles6.phoneField
1860
+ ],
1861
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1862
+ reactNative.TextInput,
1863
+ {
1864
+ ref: inputRef,
1865
+ style: [
1866
+ inputFieldMetrics.input,
1867
+ phoneFieldStyles.text,
1868
+ style
1869
+ ],
1870
+ keyboardType: "phone-pad",
1871
+ placeholderTextColor: phoneFieldStyles.placeholder,
1872
+ editable,
1873
+ onFocus: handleFocus,
1874
+ onBlur: handleBlur,
1875
+ accessibilityState: { disabled: isDisabled },
1876
+ ...props
1877
+ }
1878
+ )
1879
+ }
1880
+ ) }),
1881
+ helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles6.error : styles6.hint, children: helperMessage }) : null
1882
+ ] })
1883
+ ] })
1884
+ ] });
1885
+ }
1886
+ var styles6 = reactNative.StyleSheet.create({
1887
+ wrapper: {
1888
+ width: "100%",
1889
+ gap: spacing.sm
1890
+ },
1891
+ row: {
1892
+ flexDirection: "row",
1893
+ alignItems: "flex-start",
1894
+ gap: INPUT_ICON_GAP
1895
+ },
1896
+ countrySelector: {
1897
+ flexShrink: 0,
1898
+ alignSelf: "flex-start"
1899
+ },
1900
+ phoneColumn: {
1901
+ flex: 1,
1902
+ gap: spacing.sm
1903
+ },
1904
+ phoneOutline: {
1905
+ width: "100%"
1906
+ },
1907
+ phoneField: {
1908
+ flex: 1
1909
+ },
1910
+ error: {
1911
+ fontSize: 12,
1912
+ lineHeight: 16,
1913
+ color: colors.inputError
1914
+ },
1915
+ hint: {
1916
+ fontSize: 12,
1917
+ lineHeight: 16,
1918
+ color: colors.stormGray300
1919
+ }
1920
+ });
1921
+
1922
+ // src/icons/chevronNavPaths.ts
1923
+ var CHEVRON_LEFT_PATH = "M12.5 15L7.5 10L12.5 5";
1924
+ var CHEVRON_RIGHT_PATH = "M7.5 15L12.5 10L7.5 5";
1925
+ function ChevronLeftIcon({
1926
+ size = 20,
1927
+ color = "#151a1e",
1928
+ strokeWidth = 2
1929
+ }) {
1930
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
1931
+ Svg5.Path,
1932
+ {
1933
+ d: CHEVRON_LEFT_PATH,
1934
+ stroke: color,
1935
+ strokeWidth,
1936
+ strokeLinecap: "round",
1937
+ strokeLinejoin: "round"
1938
+ }
1939
+ ) });
1940
+ }
1941
+ function ChevronRightIcon({
1942
+ size = 20,
1943
+ color = "#151a1e",
1944
+ strokeWidth = 2
1945
+ }) {
1946
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
1947
+ Svg5.Path,
1948
+ {
1949
+ d: CHEVRON_RIGHT_PATH,
1950
+ stroke: color,
1951
+ strokeWidth,
1952
+ strokeLinecap: "round",
1953
+ strokeLinejoin: "round"
1954
+ }
1955
+ ) });
1956
+ }
1957
+ var CALENDAR_DROPDOWN_GAP = spacing.sm;
1958
+ var CALENDAR_PANEL_WIDTH = 296;
1959
+ var CALENDAR_PANEL_PADDING = spacing.md;
1960
+ var CALENDAR_PANEL_GAP = spacing.md;
1961
+ var CALENDAR_CONTENT_WIDTH = CALENDAR_PANEL_WIDTH - CALENDAR_PANEL_PADDING * 2;
1962
+ var CALENDAR_HEADER_HEIGHT = 20;
1963
+ var CALENDAR_WEEKDAY_CELL_SIZE = 32;
1964
+ var CALENDAR_WEEKDAY_GAP = spacing.sm;
1965
+ var CALENDAR_WEEKDAY_RADIUS = 6;
1966
+ var CALENDAR_DAY_SIZE = CALENDAR_WEEKDAY_CELL_SIZE;
1967
+ var CALENDAR_DAY_GRID_WIDTH = CALENDAR_CONTENT_WIDTH;
1968
+ var CALENDAR_DAY_GAP_X = spacing.sm;
1969
+ var CALENDAR_DAY_GAP_Y = spacing.lg;
1970
+ var CALENDAR_DAY_ROWS = 6;
1971
+ var CALENDAR_DAY_GRID_HEIGHT = CALENDAR_DAY_SIZE * CALENDAR_DAY_ROWS + CALENDAR_DAY_GAP_Y * (CALENDAR_DAY_ROWS - 1);
1972
+ var CALENDAR_PICKER_COLUMNS = 3;
1973
+ var CALENDAR_YEARS_PER_PAGE = 12;
1974
+ var CALENDAR_PICKER_CELL_WIDTH = (CALENDAR_DAY_GRID_WIDTH - CALENDAR_DAY_GAP_X * (CALENDAR_PICKER_COLUMNS - 1)) / CALENDAR_PICKER_COLUMNS;
1975
+ var CALENDAR_PICKER_CELL_HEIGHT = 36;
1976
+ var CALENDAR_PICKER_BODY_HEIGHT = CALENDAR_WEEKDAY_CELL_SIZE + CALENDAR_WEEKDAY_GAP + CALENDAR_DAY_GRID_HEIGHT;
1977
+ var CALENDAR_DAY_DOT_SIZE = 3;
1978
+ var CALENDAR_TODAY_TEXT_COLOR = "#082640";
1979
+ var CALENDAR_TODAY_DOT_COLOR = "#0033A0";
1980
+ var CALENDAR_NAV_ICON_SIZE = 20;
1981
+ var CALENDAR_NAV_ICON_COLOR = colors.stormGray850;
1982
+ var CALENDAR_FIELD_ICON_SIZE = 20;
1983
+ var CALENDAR_FIELD_WIDTH = CALENDAR_PANEL_WIDTH;
1984
+ var CALENDAR_FIELD_HEIGHT = 52;
1985
+ var CALENDAR_FIELD_PADDING = spacing.lg;
1986
+ var CALENDAR_FIELD_GAP = spacing.sm;
1987
+ var CALENDAR_FIELD_PLACEHOLDER_COLOR = colors.stormGray200;
1988
+ var CALENDAR_PANEL_TOTAL_HEIGHT = CALENDAR_PANEL_PADDING * 2 + CALENDAR_HEADER_HEIGHT + CALENDAR_PANEL_GAP * 2 + CALENDAR_WEEKDAY_CELL_SIZE + CALENDAR_DAY_GRID_HEIGHT;
1989
+ var CALENDAR_PANEL_HEIGHT = CALENDAR_PANEL_TOTAL_HEIGHT;
1990
+ var calendarLabelTypography = {
1991
+ fontFamily: fonts.sans,
1992
+ fontSize: fontSize.sm,
1993
+ fontWeight: fontWeight.medium,
1994
+ lineHeight: fontSize.sm,
1995
+ letterSpacing: 0,
1996
+ color: colors.slateBlue
1997
+ };
1998
+ var calendarFieldTypography = {
1999
+ fontFamily: fonts.sans,
2000
+ fontSize: fontSize.md,
2001
+ fontWeight: fontWeight.regular,
2002
+ lineHeight: fontSize.md,
2003
+ letterSpacing: 0,
2004
+ textAlign: "left"
2005
+ };
2006
+ var calendarFieldPlaceholderTypography = {
2007
+ ...calendarFieldTypography,
2008
+ color: CALENDAR_FIELD_PLACEHOLDER_COLOR
2009
+ };
2010
+ var calendarDropdownMetrics = reactNative.StyleSheet.create({
2011
+ panel: {
2012
+ width: CALENDAR_PANEL_WIDTH,
2013
+ height: CALENDAR_PANEL_HEIGHT,
2014
+ borderRadius: radii.lg,
2015
+ borderWidth: 1,
2016
+ borderColor: colors.stormGray50,
2017
+ backgroundColor: colors.white,
2018
+ padding: CALENDAR_PANEL_PADDING,
2019
+ gap: CALENDAR_PANEL_GAP,
2020
+ overflow: "hidden",
2021
+ flexDirection: "column",
2022
+ opacity: 1,
2023
+ ...reactNative.Platform.OS === "web" ? {
2024
+ boxSizing: "border-box"
2025
+ } : null
2026
+ },
2027
+ header: {
2028
+ flexDirection: "row",
2029
+ alignItems: "center",
2030
+ justifyContent: "space-between",
2031
+ height: CALENDAR_HEADER_HEIGHT,
2032
+ minHeight: CALENDAR_HEADER_HEIGHT,
2033
+ maxHeight: CALENDAR_HEADER_HEIGHT
2034
+ },
2035
+ headerTitle: {
2036
+ textAlign: "center",
2037
+ fontFamily: fonts.sans,
2038
+ fontSize: fontSize.md,
2039
+ fontWeight: fontWeight.bold,
2040
+ lineHeight: 18,
2041
+ letterSpacing: 0,
2042
+ color: colors.stormGray850
2043
+ },
2044
+ headerTitlePressable: {
2045
+ flex: 1,
2046
+ alignItems: "center",
2047
+ justifyContent: "center",
2048
+ minHeight: CALENDAR_HEADER_HEIGHT
2049
+ },
2050
+ navButton: {
2051
+ width: CALENDAR_NAV_ICON_SIZE,
2052
+ height: CALENDAR_NAV_ICON_SIZE,
2053
+ alignItems: "center",
2054
+ justifyContent: "center"
2055
+ },
2056
+ weekdayRow: {
2057
+ flexDirection: "row",
2058
+ gap: CALENDAR_WEEKDAY_GAP,
2059
+ height: CALENDAR_WEEKDAY_CELL_SIZE,
2060
+ minHeight: CALENDAR_WEEKDAY_CELL_SIZE,
2061
+ maxHeight: CALENDAR_WEEKDAY_CELL_SIZE,
2062
+ opacity: 1
2063
+ },
2064
+ weekdayCell: {
2065
+ width: CALENDAR_WEEKDAY_CELL_SIZE,
2066
+ height: CALENDAR_WEEKDAY_CELL_SIZE,
2067
+ borderRadius: CALENDAR_WEEKDAY_RADIUS,
2068
+ padding: spacing.xs,
2069
+ backgroundColor: colors.stormGray0,
2070
+ alignItems: "center",
2071
+ justifyContent: "center",
2072
+ opacity: 1,
2073
+ ...reactNative.Platform.OS === "web" ? {
2074
+ boxSizing: "border-box"
2075
+ } : null
2076
+ },
2077
+ weekdayLabel: {
2078
+ fontFamily: fonts.sans,
2079
+ fontSize: fontSize.sm,
2080
+ fontWeight: fontWeight.regular,
2081
+ lineHeight: fontSize.sm,
2082
+ letterSpacing: 0,
2083
+ textAlign: "center",
2084
+ color: colors.stormGray300,
2085
+ textTransform: "uppercase"
2086
+ },
2087
+ dayGrid: {
2088
+ width: CALENDAR_DAY_GRID_WIDTH,
2089
+ height: CALENDAR_DAY_GRID_HEIGHT,
2090
+ flexDirection: "row",
2091
+ flexWrap: "wrap",
2092
+ columnGap: CALENDAR_DAY_GAP_X,
2093
+ rowGap: CALENDAR_DAY_GAP_Y,
2094
+ alignContent: "flex-start",
2095
+ opacity: 1
2096
+ },
2097
+ dayCell: {
2098
+ width: CALENDAR_DAY_SIZE,
2099
+ height: CALENDAR_DAY_SIZE,
2100
+ minHeight: CALENDAR_DAY_SIZE,
2101
+ maxHeight: CALENDAR_DAY_SIZE,
2102
+ alignItems: "center",
2103
+ justifyContent: "center",
2104
+ borderRadius: CALENDAR_WEEKDAY_RADIUS,
2105
+ padding: spacing.xs,
2106
+ backgroundColor: colors.white,
2107
+ opacity: 1,
2108
+ position: "relative",
2109
+ ...reactNative.Platform.OS === "web" ? {
2110
+ boxSizing: "border-box"
2111
+ } : null
2112
+ },
2113
+ dayCellPast: {
2114
+ backgroundColor: colors.stormGray50
2115
+ },
2116
+ dayCellSelected: {
2117
+ backgroundColor: colors.navy
2118
+ },
2119
+ dayLabel: {
2120
+ fontFamily: fonts.sans,
2121
+ fontSize: fontSize.md,
2122
+ fontWeight: fontWeight.regular,
2123
+ lineHeight: 18,
2124
+ letterSpacing: 0,
2125
+ textAlign: "center",
2126
+ color: colors.navy,
2127
+ includeFontPadding: false,
2128
+ textAlignVertical: "center"
2129
+ },
2130
+ dayLabelToday: {
2131
+ color: CALENDAR_TODAY_TEXT_COLOR
2132
+ },
2133
+ dayLabelSelected: {
2134
+ fontWeight: fontWeight.semibold,
2135
+ color: colors.white
2136
+ },
2137
+ dayLabelFuture: {
2138
+ color: colors.navy
2139
+ },
2140
+ dayLabelMuted: {
2141
+ color: colors.stormGray300
2142
+ },
2143
+ dayLabelOutsideMonth: {
2144
+ color: colors.stormGray300
2145
+ },
2146
+ dayLabelDisabled: {
2147
+ color: colors.stormGray300,
2148
+ opacity: 0.5
2149
+ },
2150
+ todayDot: {
2151
+ position: "absolute",
2152
+ bottom: 5,
2153
+ left: "50%",
2154
+ width: CALENDAR_DAY_DOT_SIZE,
2155
+ height: CALENDAR_DAY_DOT_SIZE,
2156
+ borderRadius: 15,
2157
+ backgroundColor: CALENDAR_TODAY_DOT_COLOR,
2158
+ marginLeft: -1.5,
2159
+ zIndex: 1
2160
+ },
2161
+ pickerBody: {
2162
+ width: CALENDAR_DAY_GRID_WIDTH,
2163
+ height: CALENDAR_PICKER_BODY_HEIGHT,
2164
+ justifyContent: "center"
2165
+ },
2166
+ pickerGrid: {
2167
+ width: CALENDAR_DAY_GRID_WIDTH,
2168
+ flexDirection: "row",
2169
+ flexWrap: "wrap",
2170
+ columnGap: CALENDAR_DAY_GAP_X,
2171
+ rowGap: CALENDAR_DAY_GAP_Y,
2172
+ alignContent: "flex-start"
2173
+ },
2174
+ pickerCell: {
2175
+ width: CALENDAR_PICKER_CELL_WIDTH,
2176
+ minHeight: CALENDAR_PICKER_CELL_HEIGHT,
2177
+ alignItems: "center",
2178
+ justifyContent: "center",
2179
+ borderRadius: CALENDAR_WEEKDAY_RADIUS,
2180
+ paddingHorizontal: spacing.xs,
2181
+ paddingVertical: spacing.xs,
2182
+ backgroundColor: colors.white,
2183
+ ...reactNative.Platform.OS === "web" ? {
2184
+ boxSizing: "border-box"
2185
+ } : null
2186
+ },
2187
+ pickerCellSelected: {
2188
+ backgroundColor: colors.navy
2189
+ },
2190
+ pickerLabel: {
2191
+ fontFamily: fonts.sans,
2192
+ fontSize: fontSize.md,
2193
+ fontWeight: fontWeight.regular,
2194
+ lineHeight: 18,
2195
+ letterSpacing: 0,
2196
+ textAlign: "center",
2197
+ color: colors.navy,
2198
+ includeFontPadding: false,
2199
+ ...reactNative.Platform.OS === "android" ? { textAlignVertical: "center" } : null
2200
+ },
2201
+ pickerLabelSelected: {
2202
+ fontWeight: fontWeight.semibold,
2203
+ color: colors.white
2204
+ },
2205
+ pickerLabelDisabled: {
2206
+ color: colors.stormGray300,
2207
+ opacity: 0.5
2208
+ },
2209
+ pickerLabelCurrent: {
2210
+ color: CALENDAR_TODAY_TEXT_COLOR
2211
+ }
2212
+ });
2213
+ function resolveCalendarDropdownTop(anchor, panelHeight = CALENDAR_PANEL_HEIGHT) {
2214
+ const windowHeight = reactNative.Dimensions.get("window").height;
2215
+ const spaceBelow = windowHeight - (anchor.y + anchor.height + CALENDAR_DROPDOWN_GAP);
2216
+ const spaceAbove = anchor.y - CALENDAR_DROPDOWN_GAP;
2217
+ const topBelow = anchor.y + anchor.height + CALENDAR_DROPDOWN_GAP;
2218
+ const topAbove = anchor.y - CALENDAR_DROPDOWN_GAP - panelHeight;
2219
+ if (spaceBelow >= panelHeight) {
2220
+ return topBelow;
2221
+ }
2222
+ if (spaceAbove >= panelHeight) {
2223
+ return topAbove;
2224
+ }
2225
+ if (spaceAbove > spaceBelow) {
2226
+ return Math.max(0, topAbove);
2227
+ }
2228
+ return Math.max(0, Math.min(topBelow, windowHeight - panelHeight));
2229
+ }
2230
+ function resolveCalendarDropdownLeft(anchor, panelWidth = CALENDAR_PANEL_WIDTH) {
2231
+ const windowWidth = reactNative.Dimensions.get("window").width;
2232
+ const maxLeft = Math.max(0, windowWidth - panelWidth);
2233
+ return Math.max(0, Math.min(anchor.x, maxLeft));
2234
+ }
2235
+ var calendarFieldMetrics = reactNative.StyleSheet.create({
2236
+ container: {
2237
+ flexDirection: "row",
2238
+ alignItems: "center",
2239
+ width: CALENDAR_FIELD_WIDTH,
2240
+ minWidth: CALENDAR_FIELD_WIDTH,
2241
+ maxWidth: CALENDAR_FIELD_WIDTH,
2242
+ height: CALENDAR_FIELD_HEIGHT,
2243
+ minHeight: CALENDAR_FIELD_HEIGHT,
2244
+ maxHeight: CALENDAR_FIELD_HEIGHT,
2245
+ borderRadius: radii.lg,
2246
+ padding: CALENDAR_FIELD_PADDING,
2247
+ gap: CALENDAR_FIELD_GAP,
2248
+ opacity: 1,
2249
+ ...reactNative.Platform.OS === "web" ? {
2250
+ boxSizing: "border-box"
2251
+ } : null
2252
+ },
2253
+ value: {
2254
+ flex: 1,
2255
+ minWidth: 0,
2256
+ ...calendarFieldTypography,
2257
+ paddingVertical: 0,
2258
+ paddingHorizontal: 0,
2259
+ margin: 0,
2260
+ ...reactNative.Platform.OS === "android" ? { includeFontPadding: false } : null,
2261
+ ...reactNative.Platform.OS === "web" ? {
2262
+ outlineStyle: "none"
2263
+ } : null
2264
+ }
2265
+ });
2266
+
2267
+ // src/utils/calendarDays.ts
2268
+ function stripTime(date) {
2269
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
2270
+ }
2271
+ function normalizeDateRange(range) {
2272
+ if (!range?.start) {
2273
+ return {};
2274
+ }
2275
+ const start = stripTime(range.start);
2276
+ if (!range.end) {
2277
+ return { start };
2278
+ }
2279
+ const end = stripTime(range.end);
2280
+ if (isBeforeDay(end, start)) {
2281
+ return { start: end, end: start };
2282
+ }
2283
+ return { start, end };
2284
+ }
2285
+ function isInDateRange(date, start, end) {
2286
+ if (!start) {
2287
+ return false;
2288
+ }
2289
+ const day = stripTime(date);
2290
+ if (!end) {
2291
+ return isSameDay(day, start);
2292
+ }
2293
+ return !isBeforeDay(day, start) && !isAfterDay(day, end);
2294
+ }
2295
+ function selectRangeDate(clicked, current) {
2296
+ const clickedDate = stripTime(clicked);
2297
+ if (!current?.start || current.end) {
2298
+ return { start: clickedDate };
2299
+ }
2300
+ const start = stripTime(current.start);
2301
+ if (isSameDay(clickedDate, start)) {
2302
+ return { start, end: clickedDate };
2303
+ }
2304
+ if (isBeforeDay(clickedDate, start)) {
2305
+ return { start: clickedDate };
2306
+ }
2307
+ return { start, end: clickedDate };
2308
+ }
2309
+ function isSameDay(left, right) {
2310
+ return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
2311
+ }
2312
+ function isBeforeDay(left, right) {
2313
+ return stripTime(left).getTime() < stripTime(right).getTime();
2314
+ }
2315
+ function isAfterDay(left, right) {
2316
+ return stripTime(left).getTime() > stripTime(right).getTime();
2317
+ }
2318
+ function addMonths(date, amount) {
2319
+ return new Date(date.getFullYear(), date.getMonth() + amount, 1);
2320
+ }
2321
+ function isDateDisabled(date, minDate, maxDate) {
2322
+ if (minDate && isBeforeDay(date, minDate)) {
2323
+ return true;
2324
+ }
2325
+ if (maxDate && isAfterDay(date, maxDate)) {
2326
+ return true;
2327
+ }
2328
+ return false;
2329
+ }
2330
+ var CALENDAR_VISIBLE_DAY_COUNT = 42;
2331
+ var MONDAY_WEEK_START = 1;
2332
+ function buildCalendarDays({
2333
+ viewDate,
2334
+ selectedDate,
2335
+ selectedRange,
2336
+ today,
2337
+ minDate,
2338
+ maxDate
2339
+ }) {
2340
+ const { start: rangeStart, end: rangeEnd } = normalizeDateRange(selectedRange);
2341
+ const year = viewDate.getFullYear();
2342
+ const month = viewDate.getMonth();
2343
+ const firstOfMonth = new Date(year, month, 1);
2344
+ const startOffset = (firstOfMonth.getDay() - MONDAY_WEEK_START + 7) % 7;
2345
+ const gridStart = new Date(year, month, 1 - startOffset);
2346
+ const days = [];
2347
+ for (let index = 0; index < CALENDAR_VISIBLE_DAY_COUNT; index += 1) {
2348
+ const date = new Date(
2349
+ gridStart.getFullYear(),
2350
+ gridStart.getMonth(),
2351
+ gridStart.getDate() + index
2352
+ );
2353
+ const inCurrentMonth = date.getMonth() === month;
2354
+ const isPast = inCurrentMonth && isBeforeDay(date, today);
2355
+ const isDisabled = isDateDisabled(date, minDate, maxDate);
2356
+ const isRangeStart = rangeStart ? isSameDay(date, rangeStart) : false;
2357
+ const isRangeEnd = rangeEnd ? isSameDay(date, rangeEnd) : false;
2358
+ const inSelectedRange = rangeStart && rangeEnd ? isInDateRange(date, rangeStart, rangeEnd) : false;
2359
+ const isInRange = inSelectedRange && !isRangeStart && !isRangeEnd;
2360
+ const isSelected = selectedDate ? isSameDay(date, selectedDate) : inSelectedRange || Boolean(rangeStart && !rangeEnd && isRangeStart);
2361
+ days.push({
2362
+ date,
2363
+ inCurrentMonth,
2364
+ isToday: isSameDay(date, today),
2365
+ isSelected,
2366
+ isRangeStart,
2367
+ isRangeEnd,
2368
+ isInRange,
2369
+ isPast,
2370
+ isDisabled
2371
+ });
2372
+ }
2373
+ return days;
2374
+ }
2375
+ function formatCalendarYear(year, locale) {
2376
+ return new Intl.DateTimeFormat(locale, { year: "numeric" }).format(new Date(year, 0, 1));
2377
+ }
2378
+ function getYearPageStart(year, yearsPerPage = 12) {
2379
+ return Math.floor(year / yearsPerPage) * yearsPerPage;
2380
+ }
2381
+ function isMonthDisabled(year, month, minDate, maxDate) {
2382
+ const firstDay = new Date(year, month, 1);
2383
+ const lastDay = new Date(year, month + 1, 0);
2384
+ if (minDate && isBeforeDay(lastDay, minDate)) {
2385
+ return true;
2386
+ }
2387
+ if (maxDate && isAfterDay(firstDay, maxDate)) {
2388
+ return true;
2389
+ }
2390
+ return false;
2391
+ }
2392
+ function isYearDisabled(year, minDate, maxDate) {
2393
+ const firstDay = new Date(year, 0, 1);
2394
+ const lastDay = new Date(year, 11, 31);
2395
+ if (minDate && isBeforeDay(lastDay, minDate)) {
2396
+ return true;
2397
+ }
2398
+ if (maxDate && isAfterDay(firstDay, maxDate)) {
2399
+ return true;
2400
+ }
2401
+ return false;
2402
+ }
2403
+ function formatCalendarDate(date, locale) {
2404
+ return new Intl.DateTimeFormat(locale, {
2405
+ day: "numeric",
2406
+ month: "long",
2407
+ year: "numeric"
2408
+ }).format(date);
2409
+ }
2410
+ function formatCalendarDateRange(range, locale, separator = " \u2013 ") {
2411
+ const { start, end } = normalizeDateRange(range);
2412
+ if (!start) {
2413
+ return "";
2414
+ }
2415
+ if (!end) {
2416
+ return formatCalendarDate(start, locale);
2417
+ }
2418
+ return `${formatCalendarDate(start, locale)}${separator}${formatCalendarDate(end, locale)}`;
2419
+ }
2420
+
2421
+ // src/utils/calendarLocalization.ts
2422
+ var calendarTranslations = {
2423
+ "hy-AM": {
2424
+ weekdays: ["\u0535\u0550", "\u0535\u0554", "\u0549\u0550", "\u0540\u0546", "\u0548\u0552\u0550", "\u0547\u0532", "\u053F\u0550"],
2425
+ monthsShort: [
2426
+ "\u0540\u0576\u057E",
2427
+ "\u0553\u057F\u057E",
2428
+ "\u0544\u0580\u057F",
2429
+ "\u0531\u057A\u0580",
2430
+ "\u0544\u0575\u057D",
2431
+ "\u0540\u0578\u0582\u0576",
2432
+ "\u0540\u0578\u0582\u056C",
2433
+ "\u0555\u0563\u057D",
2434
+ "\u054D\u0565\u057A",
2435
+ "\u0540\u0578\u056F",
2436
+ "\u0546\u0578\u0575",
2437
+ "\u0534\u0565\u056F"
2438
+ ],
2439
+ monthsLong: [
2440
+ "\u0540\u0578\u0582\u0576\u057E\u0561\u0580",
2441
+ "\u0553\u0565\u057F\u0580\u057E\u0561\u0580",
2442
+ "\u0544\u0561\u0580\u057F",
2443
+ "\u0531\u057A\u0580\u056B\u056C",
2444
+ "\u0544\u0561\u0575\u056B\u057D",
2445
+ "\u0540\u0578\u0582\u0576\u056B\u057D",
2446
+ "\u0540\u0578\u0582\u056C\u056B\u057D",
2447
+ "\u0555\u0563\u0578\u057D\u057F\u0578\u057D",
2448
+ "\u054D\u0565\u057A\u057F\u0565\u0574\u0562\u0565\u0580",
2449
+ "\u0540\u0578\u056F\u057F\u0565\u0574\u0562\u0565\u0580",
2450
+ "\u0546\u0578\u0575\u0565\u0574\u0562\u0565\u0580",
2451
+ "\u0534\u0565\u056F\u057F\u0565\u0574\u0562\u0565\u0580"
2452
+ ],
2453
+ datePlaceholder: "\u0538\u0576\u057F\u0580\u0565\u056C \u0561\u0574\u057D\u0561\u0569\u056B\u057E",
2454
+ rangePlaceholder: "\u0538\u0576\u057F\u0580\u0565\u056C \u056A\u0561\u0574\u0561\u0576\u0561\u056F\u0561\u0570\u0561\u057F\u057E\u0561\u056E",
2455
+ previousMonth: "\u0546\u0561\u056D\u0578\u0580\u0564 \u0561\u0574\u056B\u057D",
2456
+ nextMonth: "\u0540\u0561\u057B\u0578\u0580\u0564 \u0561\u0574\u056B\u057D",
2457
+ previousYear: "\u0546\u0561\u056D\u0578\u0580\u0564 \u057F\u0561\u0580\u056B",
2458
+ nextYear: "\u0540\u0561\u057B\u0578\u0580\u0564 \u057F\u0561\u0580\u056B",
2459
+ previousYears: "\u0546\u0561\u056D\u0578\u0580\u0564 \u057F\u0561\u0580\u056B\u0576\u0565\u0580",
2460
+ nextYears: "\u0540\u0561\u057B\u0578\u0580\u0564 \u057F\u0561\u0580\u056B\u0576\u0565\u0580",
2461
+ selectMonth: "\u0538\u0576\u057F\u0580\u0565\u056C \u0561\u0574\u056B\u057D",
2462
+ selectYear: "\u0538\u0576\u057F\u0580\u0565\u056C \u057F\u0561\u0580\u056B",
2463
+ closeCalendar: "\u0553\u0561\u056F\u0565\u056C \u0585\u0580\u0561\u0581\u0578\u0582\u0575\u0581\u0568"
2464
+ },
2465
+ "en-US": {
2466
+ weekdays: ["MO", "TU", "WE", "TH", "FR", "SA", "SU"],
2467
+ monthsShort: [
2468
+ "Jan",
2469
+ "Feb",
2470
+ "Mar",
2471
+ "Apr",
2472
+ "May",
2473
+ "Jun",
2474
+ "Jul",
2475
+ "Aug",
2476
+ "Sep",
2477
+ "Oct",
2478
+ "Nov",
2479
+ "Dec"
2480
+ ],
2481
+ monthsLong: [
2482
+ "January",
2483
+ "February",
2484
+ "March",
2485
+ "April",
2486
+ "May",
2487
+ "June",
2488
+ "July",
2489
+ "August",
2490
+ "September",
2491
+ "October",
2492
+ "November",
2493
+ "December"
2494
+ ],
2495
+ datePlaceholder: "Select date",
2496
+ rangePlaceholder: "Select date range",
2497
+ previousMonth: "Previous month",
2498
+ nextMonth: "Next month",
2499
+ previousYear: "Previous year",
2500
+ nextYear: "Next year",
2501
+ previousYears: "Previous years",
2502
+ nextYears: "Next years",
2503
+ selectMonth: "Select month",
2504
+ selectYear: "Select year",
2505
+ closeCalendar: "Close calendar"
2506
+ },
2507
+ "ru-RU": {
2508
+ weekdays: ["\u041F\u041D", "\u0412\u0422", "\u0421\u0420", "\u0427\u0422", "\u041F\u0422", "\u0421\u0411", "\u0412\u0421"],
2509
+ monthsShort: [
2510
+ "\u042F\u043D\u0432",
2511
+ "\u0424\u0435\u0432",
2512
+ "\u041C\u0430\u0440",
2513
+ "\u0410\u043F\u0440",
2514
+ "\u041C\u0430\u0439",
2515
+ "\u0418\u044E\u043D",
2516
+ "\u0418\u044E\u043B",
2517
+ "\u0410\u0432\u0433",
2518
+ "\u0421\u0435\u043D",
2519
+ "\u041E\u043A\u0442",
2520
+ "\u041D\u043E\u044F",
2521
+ "\u0414\u0435\u043A"
2522
+ ],
2523
+ monthsLong: [
2524
+ "\u042F\u043D\u0432\u0430\u0440\u044C",
2525
+ "\u0424\u0435\u0432\u0440\u0430\u043B\u044C",
2526
+ "\u041C\u0430\u0440\u0442",
2527
+ "\u0410\u043F\u0440\u0435\u043B\u044C",
2528
+ "\u041C\u0430\u0439",
2529
+ "\u0418\u044E\u043D\u044C",
2530
+ "\u0418\u044E\u043B\u044C",
2531
+ "\u0410\u0432\u0433\u0443\u0441\u0442",
2532
+ "\u0421\u0435\u043D\u0442\u044F\u0431\u0440\u044C",
2533
+ "\u041E\u043A\u0442\u044F\u0431\u0440\u044C",
2534
+ "\u041D\u043E\u044F\u0431\u0440\u044C",
2535
+ "\u0414\u0435\u043A\u0430\u0431\u0440\u044C"
2536
+ ],
2537
+ datePlaceholder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0434\u0430\u0442\u0443",
2538
+ rangePlaceholder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0435\u0440\u0438\u043E\u0434",
2539
+ previousMonth: "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u043C\u0435\u0441\u044F\u0446",
2540
+ nextMonth: "\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u043C\u0435\u0441\u044F\u0446",
2541
+ previousYear: "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u0433\u043E\u0434",
2542
+ nextYear: "\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0433\u043E\u0434",
2543
+ previousYears: "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0435 \u0433\u043E\u0434\u044B",
2544
+ nextYears: "\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u0433\u043E\u0434\u044B",
2545
+ selectMonth: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043C\u0435\u0441\u044F\u0446",
2546
+ selectYear: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0433\u043E\u0434",
2547
+ closeCalendar: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u044C"
2548
+ }
2549
+ };
2550
+ function resolveCalendarLocale(locale) {
2551
+ const normalizedLocale = locale.toLowerCase();
2552
+ if (normalizedLocale.startsWith("hy")) {
2553
+ return "hy-AM";
2554
+ }
2555
+ if (normalizedLocale.startsWith("ru")) {
2556
+ return "ru-RU";
2557
+ }
2558
+ return "en-US";
2559
+ }
2560
+ function getCalendarTranslations(locale) {
2561
+ return calendarTranslations[resolveCalendarLocale(locale)];
2562
+ }
2563
+ function resolveWeekdayLabels(locale) {
2564
+ return getCalendarTranslations(locale).weekdays;
2565
+ }
2566
+ function getCalendarMonthLabels(locale, width = "short") {
2567
+ const translations = getCalendarTranslations(locale);
2568
+ return width === "short" ? translations.monthsShort : translations.monthsLong;
2569
+ }
2570
+ function formatLocalizedCalendarMonthYear(date, locale) {
2571
+ return `${getCalendarMonthLabels(locale)[date.getMonth()]} ${date.getFullYear()}`;
2572
+ }
2573
+ var LOCALE_STORAGE_KEY = "homepad.locale";
2574
+ var LOCALE_CHANGE_EVENT = "homepad:locale-change";
2575
+ var DEFAULT_CALENDAR_LOCALE = "hy-AM";
2576
+ var CalendarLocaleContext = react.createContext(void 0);
2577
+ function CalendarLocaleProvider({ locale, children }) {
2578
+ return /* @__PURE__ */ jsxRuntime.jsx(CalendarLocaleContext.Provider, { value: locale, children });
2579
+ }
2580
+ function normalizeProjectLocale(locale) {
2581
+ if (!locale) {
2582
+ return null;
2583
+ }
2584
+ return resolveCalendarLocale(locale);
2585
+ }
2586
+ function readBrowserLocale() {
2587
+ if (typeof window === "undefined") {
2588
+ return null;
2589
+ }
2590
+ let storedLocale = null;
2591
+ try {
2592
+ storedLocale = normalizeProjectLocale(window.localStorage.getItem(LOCALE_STORAGE_KEY));
2593
+ } catch {
2594
+ storedLocale = null;
2595
+ }
2596
+ if (storedLocale) {
2597
+ return storedLocale;
2598
+ }
2599
+ const documentLocale = normalizeProjectLocale(window.document?.documentElement.lang);
2600
+ if (documentLocale) {
2601
+ return documentLocale;
2602
+ }
2603
+ return normalizeProjectLocale(window.navigator.language);
2604
+ }
2605
+ function useCalendarLocale(locale) {
2606
+ const contextLocale = react.useContext(CalendarLocaleContext);
2607
+ const controlledLocale = locale ?? contextLocale;
2608
+ const [browserLocale, setBrowserLocale] = react.useState(
2609
+ () => readBrowserLocale() ?? DEFAULT_CALENDAR_LOCALE
2610
+ );
2611
+ react.useEffect(() => {
2612
+ if (controlledLocale !== void 0 || typeof window === "undefined") {
2613
+ return;
2614
+ }
2615
+ const syncLocale = () => {
2616
+ setBrowserLocale(readBrowserLocale() ?? DEFAULT_CALENDAR_LOCALE);
2617
+ };
2618
+ const handleLocaleChange = (event) => {
2619
+ const customEvent = event;
2620
+ const nextLocale = normalizeProjectLocale(customEvent.detail);
2621
+ if (nextLocale) {
2622
+ setBrowserLocale(nextLocale);
2623
+ return;
2624
+ }
2625
+ syncLocale();
2626
+ };
2627
+ window.addEventListener(LOCALE_CHANGE_EVENT, handleLocaleChange);
2628
+ window.addEventListener("storage", syncLocale);
2629
+ return () => {
2630
+ window.removeEventListener(LOCALE_CHANGE_EVENT, handleLocaleChange);
2631
+ window.removeEventListener("storage", syncLocale);
2632
+ };
2633
+ }, [controlledLocale]);
2634
+ return react.useMemo(
2635
+ () => normalizeProjectLocale(controlledLocale) ?? browserLocale,
2636
+ [browserLocale, controlledLocale]
2637
+ );
2638
+ }
2639
+ function resolveDayCellStyle(day) {
2640
+ if (day.isDisabled) {
2641
+ return [calendarDropdownMetrics.dayCell];
2642
+ }
2643
+ if (day.isSelected) {
2644
+ return [calendarDropdownMetrics.dayCell, calendarDropdownMetrics.dayCellSelected];
2645
+ }
2646
+ return [
2647
+ calendarDropdownMetrics.dayCell,
2648
+ day.inCurrentMonth && day.isPast && !day.isToday ? calendarDropdownMetrics.dayCellPast : null
2649
+ ];
2650
+ }
2651
+ function resolveDayLabelStyle(day) {
2652
+ if (day.isDisabled) {
2653
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelDisabled];
2654
+ }
2655
+ if (day.isSelected) {
2656
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelSelected];
2657
+ }
2658
+ if (!day.inCurrentMonth) {
2659
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelOutsideMonth];
2660
+ }
2661
+ if (day.isToday) {
2662
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelToday];
2663
+ }
2664
+ if (day.isPast) {
2665
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelMuted];
2666
+ }
2667
+ return [calendarDropdownMetrics.dayLabel, calendarDropdownMetrics.dayLabelFuture];
2668
+ }
2669
+ function Calendar(props) {
2670
+ const rangeProps = props.mode === "range" ? props : null;
2671
+ const singleProps = props.mode === "range" ? null : props;
2672
+ const {
2673
+ viewDate,
2674
+ defaultViewDate,
2675
+ onViewDateChange,
2676
+ locale,
2677
+ labels,
2678
+ minDate,
2679
+ maxDate,
2680
+ today = /* @__PURE__ */ new Date(),
2681
+ style,
2682
+ className
2683
+ } = props;
2684
+ const rootRef = react.useRef(null);
2685
+ const [internalViewDate, setInternalViewDate] = react.useState(() => {
2686
+ if (defaultViewDate) {
2687
+ return defaultViewDate;
2688
+ }
2689
+ if (rangeProps) {
2690
+ return rangeProps.value?.start ?? today;
2691
+ }
2692
+ return singleProps?.value ?? today;
2693
+ });
2694
+ const activeViewDate = viewDate ?? internalViewDate;
2695
+ const [pickerView, setPickerView] = react.useState("days");
2696
+ const [pickerYear, setPickerYear] = react.useState(() => activeViewDate.getFullYear());
2697
+ const [yearPageStart, setYearPageStart] = react.useState(
2698
+ () => getYearPageStart(activeViewDate.getFullYear(), CALENDAR_YEARS_PER_PAGE)
2699
+ );
2700
+ const customWeekdayLabels = labels?.weekdays;
2701
+ const formatMonthYearLabel = labels?.formatMonthYear;
2702
+ const resolvedLocale = useCalendarLocale(locale);
2703
+ const translations = react.useMemo(
2704
+ () => getCalendarTranslations(resolvedLocale),
2705
+ [resolvedLocale]
2706
+ );
2707
+ useApplyWebClassName(rootRef, className);
2708
+ const weekdayLabels = react.useMemo(
2709
+ () => customWeekdayLabels ?? resolveWeekdayLabels(resolvedLocale),
2710
+ [customWeekdayLabels, resolvedLocale]
2711
+ );
2712
+ const monthLabels = react.useMemo(() => getCalendarMonthLabels(resolvedLocale), [resolvedLocale]);
2713
+ const monthYearLabel = react.useMemo(() => {
2714
+ if (formatMonthYearLabel) {
2715
+ return formatMonthYearLabel(activeViewDate);
2716
+ }
2717
+ return formatLocalizedCalendarMonthYear(activeViewDate, resolvedLocale);
2718
+ }, [activeViewDate, formatMonthYearLabel, resolvedLocale]);
2719
+ const headerLabel = react.useMemo(() => {
2720
+ if (pickerView === "months") {
2721
+ return formatCalendarYear(pickerYear, resolvedLocale);
2722
+ }
2723
+ if (pickerView === "years") {
2724
+ const endYear = yearPageStart + CALENDAR_YEARS_PER_PAGE - 1;
2725
+ return `${yearPageStart} \u2013 ${endYear}`;
2726
+ }
2727
+ return monthYearLabel;
2728
+ }, [monthYearLabel, pickerView, pickerYear, resolvedLocale, yearPageStart]);
2729
+ const days = react.useMemo(
2730
+ () => buildCalendarDays({
2731
+ viewDate: activeViewDate,
2732
+ selectedDate: singleProps?.value,
2733
+ selectedRange: rangeProps?.value,
2734
+ today,
2735
+ minDate,
2736
+ maxDate
2737
+ }),
2738
+ [activeViewDate, maxDate, minDate, rangeProps?.value, singleProps?.value, today]
2739
+ );
2740
+ const yearOptions = react.useMemo(
2741
+ () => Array.from({ length: CALENDAR_YEARS_PER_PAGE }, (_, index) => yearPageStart + index),
2742
+ [yearPageStart]
2743
+ );
2744
+ function getLabel(key) {
2745
+ return labels?.[key] ?? translations[key];
2746
+ }
2747
+ function setViewDate(nextDate) {
2748
+ if (viewDate === void 0) {
2749
+ setInternalViewDate(nextDate);
2750
+ }
2751
+ onViewDateChange?.(nextDate);
2752
+ }
2753
+ function handlePrevious() {
2754
+ if (pickerView === "months") {
2755
+ setPickerYear((year) => year - 1);
2756
+ return;
2757
+ }
2758
+ if (pickerView === "years") {
2759
+ setYearPageStart((start) => start - CALENDAR_YEARS_PER_PAGE);
2760
+ return;
2761
+ }
2762
+ setViewDate(addMonths(activeViewDate, -1));
2763
+ }
2764
+ function handleNext() {
2765
+ if (pickerView === "months") {
2766
+ setPickerYear((year) => year + 1);
2767
+ return;
2768
+ }
2769
+ if (pickerView === "years") {
2770
+ setYearPageStart((start) => start + CALENDAR_YEARS_PER_PAGE);
2771
+ return;
2772
+ }
2773
+ setViewDate(addMonths(activeViewDate, 1));
2774
+ }
2775
+ function handleHeaderPress() {
2776
+ if (pickerView === "days") {
2777
+ setPickerYear(activeViewDate.getFullYear());
2778
+ setPickerView("months");
2779
+ return;
2780
+ }
2781
+ if (pickerView === "months") {
2782
+ setYearPageStart(getYearPageStart(pickerYear, CALENDAR_YEARS_PER_PAGE));
2783
+ setPickerView("years");
2784
+ }
2785
+ }
2786
+ function handleMonthSelect(month) {
2787
+ setViewDate(new Date(pickerYear, month, 1));
2788
+ setPickerView("days");
2789
+ }
2790
+ function handleYearSelect(year) {
2791
+ setPickerYear(year);
2792
+ setPickerView("months");
2793
+ }
2794
+ function handleDayPress(date) {
2795
+ if (rangeProps) {
2796
+ rangeProps.onChange?.(selectRangeDate(date, rangeProps.value));
2797
+ return;
2798
+ }
2799
+ singleProps?.onChange?.(date);
2800
+ }
2801
+ const headerIsPressable = pickerView === "days" || pickerView === "months";
2802
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: rootRef, style: [calendarDropdownMetrics.panel, style], children: [
2803
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: calendarDropdownMetrics.header, children: [
2804
+ /* @__PURE__ */ jsxRuntime.jsx(
2805
+ reactNative.Pressable,
2806
+ {
2807
+ accessibilityRole: "button",
2808
+ accessibilityLabel: pickerView === "months" ? getLabel("previousYear") : pickerView === "years" ? getLabel("previousYears") : getLabel("previousMonth"),
2809
+ onPress: handlePrevious,
2810
+ style: calendarDropdownMetrics.navButton,
2811
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeftIcon, { size: CALENDAR_NAV_ICON_SIZE, color: CALENDAR_NAV_ICON_COLOR })
1250
2812
  }
1251
2813
  ),
1252
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.phoneColumn, children: [
1253
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [phoneFieldStyles.outline, styles5.phoneOutline], children: /* @__PURE__ */ jsxRuntime.jsx(
1254
- reactNative.View,
1255
- {
1256
- style: [
1257
- inputFieldMetrics.container,
1258
- phoneFieldStyles.container,
1259
- styles5.phoneField
1260
- ],
1261
- children: /* @__PURE__ */ jsxRuntime.jsx(
1262
- reactNative.TextInput,
1263
- {
1264
- ref: inputRef,
1265
- style: [
1266
- inputFieldMetrics.input,
1267
- phoneFieldStyles.text,
1268
- style
1269
- ],
1270
- keyboardType: "phone-pad",
1271
- placeholderTextColor: phoneFieldStyles.placeholder,
1272
- editable,
1273
- onFocus: handleFocus,
1274
- onBlur: handleBlur,
1275
- accessibilityState: { disabled: isDisabled },
1276
- ...props
1277
- }
1278
- )
1279
- }
1280
- ) }),
1281
- helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles5.error : styles5.hint, children: helperMessage }) : null
1282
- ] })
1283
- ] })
2814
+ headerIsPressable ? /* @__PURE__ */ jsxRuntime.jsx(
2815
+ reactNative.Pressable,
2816
+ {
2817
+ accessibilityRole: "button",
2818
+ accessibilityLabel: pickerView === "days" ? getLabel("selectMonth") : getLabel("selectYear"),
2819
+ onPress: handleHeaderPress,
2820
+ style: calendarDropdownMetrics.headerTitlePressable,
2821
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: calendarDropdownMetrics.headerTitle, children: headerLabel })
2822
+ }
2823
+ ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.headerTitlePressable, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: calendarDropdownMetrics.headerTitle, children: headerLabel }) }),
2824
+ /* @__PURE__ */ jsxRuntime.jsx(
2825
+ reactNative.Pressable,
2826
+ {
2827
+ accessibilityRole: "button",
2828
+ accessibilityLabel: pickerView === "months" ? getLabel("nextYear") : pickerView === "years" ? getLabel("nextYears") : getLabel("nextMonth"),
2829
+ onPress: handleNext,
2830
+ style: calendarDropdownMetrics.navButton,
2831
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, { size: CALENDAR_NAV_ICON_SIZE, color: CALENDAR_NAV_ICON_COLOR })
2832
+ }
2833
+ )
2834
+ ] }),
2835
+ pickerView === "days" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2836
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.weekdayRow, children: weekdayLabels.map((weekday) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.weekdayCell, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: calendarDropdownMetrics.weekdayLabel, children: weekday }) }, weekday)) }),
2837
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.dayGrid, children: days.map((day) => /* @__PURE__ */ jsxRuntime.jsxs(
2838
+ reactNative.Pressable,
2839
+ {
2840
+ accessibilityRole: "button",
2841
+ accessibilityState: {
2842
+ selected: day.isSelected,
2843
+ disabled: day.isDisabled
2844
+ },
2845
+ disabled: day.isDisabled,
2846
+ onPress: () => handleDayPress(day.date),
2847
+ style: resolveDayCellStyle(day),
2848
+ children: [
2849
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: resolveDayLabelStyle(day), children: day.date.getDate() }),
2850
+ day.isToday && day.inCurrentMonth && !day.isSelected ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.todayDot }) : null
2851
+ ]
2852
+ },
2853
+ day.date.toISOString()
2854
+ )) })
2855
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.pickerBody, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: calendarDropdownMetrics.pickerGrid, children: pickerView === "months" ? monthLabels.map((monthLabel, month) => {
2856
+ const isSelected = activeViewDate.getFullYear() === pickerYear && activeViewDate.getMonth() === month;
2857
+ const isCurrent = today.getFullYear() === pickerYear && today.getMonth() === month;
2858
+ const disabled = isMonthDisabled(pickerYear, month, minDate, maxDate);
2859
+ return /* @__PURE__ */ jsxRuntime.jsx(
2860
+ reactNative.Pressable,
2861
+ {
2862
+ accessibilityRole: "button",
2863
+ accessibilityState: { selected: isSelected, disabled },
2864
+ disabled,
2865
+ onPress: () => handleMonthSelect(month),
2866
+ style: [
2867
+ calendarDropdownMetrics.pickerCell,
2868
+ isSelected ? calendarDropdownMetrics.pickerCellSelected : null
2869
+ ],
2870
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2871
+ reactNative.Text,
2872
+ {
2873
+ style: [
2874
+ calendarDropdownMetrics.pickerLabel,
2875
+ isSelected ? calendarDropdownMetrics.pickerLabelSelected : null,
2876
+ !isSelected && isCurrent ? calendarDropdownMetrics.pickerLabelCurrent : null,
2877
+ disabled ? calendarDropdownMetrics.pickerLabelDisabled : null
2878
+ ],
2879
+ children: monthLabel
2880
+ }
2881
+ )
2882
+ },
2883
+ monthLabel
2884
+ );
2885
+ }) : yearOptions.map((year) => {
2886
+ const isSelected = activeViewDate.getFullYear() === year;
2887
+ const isCurrent = today.getFullYear() === year;
2888
+ const disabled = isYearDisabled(year, minDate, maxDate);
2889
+ return /* @__PURE__ */ jsxRuntime.jsx(
2890
+ reactNative.Pressable,
2891
+ {
2892
+ accessibilityRole: "button",
2893
+ accessibilityState: { selected: isSelected, disabled },
2894
+ disabled,
2895
+ onPress: () => handleYearSelect(year),
2896
+ style: [
2897
+ calendarDropdownMetrics.pickerCell,
2898
+ isSelected ? calendarDropdownMetrics.pickerCellSelected : null
2899
+ ],
2900
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2901
+ reactNative.Text,
2902
+ {
2903
+ style: [
2904
+ calendarDropdownMetrics.pickerLabel,
2905
+ isSelected ? calendarDropdownMetrics.pickerLabelSelected : null,
2906
+ !isSelected && isCurrent ? calendarDropdownMetrics.pickerLabelCurrent : null,
2907
+ disabled ? calendarDropdownMetrics.pickerLabelDisabled : null
2908
+ ],
2909
+ children: year
2910
+ }
2911
+ )
2912
+ },
2913
+ year
2914
+ );
2915
+ }) }) })
1284
2916
  ] });
1285
2917
  }
1286
- var styles5 = reactNative.StyleSheet.create({
2918
+
2919
+ // src/icons/calendarIconPaths.ts
2920
+ var CALENDAR_ICON_BODY_PATH = "M6.66667 1.6665V4.99984M13.3333 1.6665V4.99984M2.5 8.33317H17.5M4.16667 3.33317H15.8333C16.7538 3.33317 17.5 4.07936 17.5 4.99984V16.6665C17.5 17.587 16.7538 18.3332 15.8333 18.3332H4.16667C3.24619 18.3332 2.5 17.587 2.5 16.6665V4.99984C2.5 4.07936 3.24619 3.33317 4.16667 3.33317Z";
2921
+ function CalendarIcon({
2922
+ size = 20,
2923
+ color = "#C7CDD1",
2924
+ strokeWidth = 2
2925
+ }) {
2926
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
2927
+ Svg5.Path,
2928
+ {
2929
+ d: CALENDAR_ICON_BODY_PATH,
2930
+ stroke: color,
2931
+ strokeWidth,
2932
+ strokeLinecap: "round",
2933
+ strokeLinejoin: "round"
2934
+ }
2935
+ ) });
2936
+ }
2937
+ function DatePicker(props) {
2938
+ const {
2939
+ label,
2940
+ placeholder,
2941
+ locale,
2942
+ labels,
2943
+ minDate,
2944
+ maxDate,
2945
+ today,
2946
+ viewDate,
2947
+ defaultViewDate,
2948
+ onViewDateChange,
2949
+ disabled = false,
2950
+ error,
2951
+ invalid,
2952
+ hint,
2953
+ containerStyle,
2954
+ className,
2955
+ fieldClassName,
2956
+ panelClassName,
2957
+ labelClassName,
2958
+ errorClassName,
2959
+ hintClassName,
2960
+ defaultOpen = false
2961
+ } = props;
2962
+ const mode = props.mode ?? "single";
2963
+ const closeOnRangeComplete = props.mode === "range" ? props.closeOnRangeComplete ?? true : false;
2964
+ const resolvedLocale = useCalendarLocale(locale);
2965
+ const translations = getCalendarTranslations(resolvedLocale);
2966
+ const resolvedPlaceholder = placeholder ?? (mode === "range" ? translations.rangePlaceholder : translations.datePlaceholder);
2967
+ const wrapperRef = react.useRef(null);
2968
+ const triggerRef = react.useRef(null);
2969
+ const helperRef = react.useRef(null);
2970
+ const [open, setOpen] = react.useState(defaultOpen);
2971
+ const [anchor, setAnchor] = react.useState(null);
2972
+ useApplyWebClassName(wrapperRef, className);
2973
+ useApplyWebClassName(triggerRef, fieldClassName);
2974
+ useApplyWebClassName(helperRef, error ? errorClassName : hintClassName);
2975
+ react.useEffect(() => {
2976
+ if (!defaultOpen || disabled) {
2977
+ return;
2978
+ }
2979
+ const frame = requestAnimationFrame(() => {
2980
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
2981
+ setAnchor({ x, y, width, height });
2982
+ setOpen(true);
2983
+ });
2984
+ });
2985
+ return () => cancelAnimationFrame(frame);
2986
+ }, [defaultOpen, disabled]);
2987
+ const hasError = Boolean(error) || Boolean(invalid);
2988
+ const fieldStyles = getSelectFieldStyles(
2989
+ resolveInputVisualState({
2990
+ error: hasError,
2991
+ disabled
2992
+ })
2993
+ );
2994
+ const hasValue = mode === "single" ? Boolean(props.value) : Boolean(props.mode === "range" && props.value?.start);
2995
+ const displayValue = (() => {
2996
+ if (props.mode === "range") {
2997
+ if (!props.value?.start) {
2998
+ return resolvedPlaceholder;
2999
+ }
3000
+ return props.formatRange?.(props.value) ?? formatCalendarDateRange(props.value, resolvedLocale, props.rangeSeparator);
3001
+ }
3002
+ if (props.value) {
3003
+ return props.formatDate?.(props.value) ?? formatCalendarDate(props.value, resolvedLocale);
3004
+ }
3005
+ return resolvedPlaceholder;
3006
+ })();
3007
+ const isPlaceholder = !hasValue;
3008
+ const valueTextStyle = isPlaceholder ? {
3009
+ ...calendarFieldPlaceholderTypography,
3010
+ color: disabled ? colors.stormGray300 : calendarFieldPlaceholderTypography.color
3011
+ } : {
3012
+ ...calendarFieldTypography,
3013
+ color: fieldStyles.value.color
3014
+ };
3015
+ const helperMessage = error ?? hint;
3016
+ const panelWidth = CALENDAR_PANEL_WIDTH;
3017
+ const panelLeft = anchor ? resolveCalendarDropdownLeft(anchor, panelWidth) : 0;
3018
+ const dropdownTop = anchor ? resolveCalendarDropdownTop(anchor) : 0;
3019
+ const resolvedDefaultViewDate = defaultViewDate ?? (props.mode === "range" ? props.value?.start : props.value) ?? today;
3020
+ function closePicker() {
3021
+ setOpen(false);
3022
+ setAnchor(null);
3023
+ }
3024
+ function openPicker() {
3025
+ if (disabled) {
3026
+ return;
3027
+ }
3028
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
3029
+ setAnchor({ x, y, width, height });
3030
+ setOpen(true);
3031
+ });
3032
+ }
3033
+ function handleSingleSelect(date) {
3034
+ if (props.mode === "range") {
3035
+ return;
3036
+ }
3037
+ props.onChange?.(date);
3038
+ closePicker();
3039
+ }
3040
+ function handleRangeSelect(range) {
3041
+ if (props.mode !== "range") {
3042
+ return;
3043
+ }
3044
+ props.onChange?.(range);
3045
+ if (closeOnRangeComplete && range.end) {
3046
+ closePicker();
3047
+ }
3048
+ }
3049
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ref: wrapperRef, style: [styles7.wrapper, containerStyle], children: [
3050
+ label ? /* @__PURE__ */ jsxRuntime.jsx(Label, { disabled, style: styles7.label, className: labelClassName, children: label }) : null,
3051
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [fieldStyles.outline, styles7.fieldOutline], children: /* @__PURE__ */ jsxRuntime.jsxs(
3052
+ reactNative.Pressable,
3053
+ {
3054
+ ref: triggerRef,
3055
+ accessibilityRole: "button",
3056
+ accessibilityState: { disabled, expanded: open },
3057
+ disabled,
3058
+ onPress: openPicker,
3059
+ style: [calendarFieldMetrics.container, fieldStyles.container],
3060
+ children: [
3061
+ /* @__PURE__ */ jsxRuntime.jsx(
3062
+ reactNative.Text,
3063
+ {
3064
+ style: [calendarFieldMetrics.value, valueTextStyle],
3065
+ numberOfLines: 1,
3066
+ children: displayValue
3067
+ }
3068
+ ),
3069
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.iconSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
3070
+ CalendarIcon,
3071
+ {
3072
+ size: CALENDAR_FIELD_ICON_SIZE,
3073
+ color: disabled ? colors.stormGray200 : colors.stormGray150
3074
+ }
3075
+ ) })
3076
+ ]
3077
+ }
3078
+ ) }),
3079
+ helperMessage ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { ref: helperRef, style: error ? styles7.error : styles7.hint, children: helperMessage }) : null,
3080
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible: open, transparent: true, animationType: "fade", onRequestClose: closePicker, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.modalRoot, children: [
3081
+ /* @__PURE__ */ jsxRuntime.jsx(
3082
+ reactNative.Pressable,
3083
+ {
3084
+ style: styles7.backdrop,
3085
+ onPress: closePicker,
3086
+ accessibilityRole: "button",
3087
+ accessibilityLabel: labels?.closeCalendar ?? translations.closeCalendar
3088
+ }
3089
+ ),
3090
+ anchor ? /* @__PURE__ */ jsxRuntime.jsx(
3091
+ reactNative.View,
3092
+ {
3093
+ style: [
3094
+ styles7.panelPosition,
3095
+ {
3096
+ top: dropdownTop,
3097
+ left: panelLeft,
3098
+ width: panelWidth,
3099
+ height: CALENDAR_PANEL_HEIGHT
3100
+ }
3101
+ ],
3102
+ children: props.mode === "range" ? /* @__PURE__ */ jsxRuntime.jsx(
3103
+ Calendar,
3104
+ {
3105
+ mode: "range",
3106
+ value: props.value,
3107
+ onChange: handleRangeSelect,
3108
+ viewDate,
3109
+ defaultViewDate: resolvedDefaultViewDate,
3110
+ onViewDateChange,
3111
+ locale: resolvedLocale,
3112
+ labels,
3113
+ minDate,
3114
+ maxDate,
3115
+ today,
3116
+ className: panelClassName
3117
+ }
3118
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3119
+ Calendar,
3120
+ {
3121
+ mode: "single",
3122
+ value: props.value,
3123
+ onChange: handleSingleSelect,
3124
+ viewDate,
3125
+ defaultViewDate: resolvedDefaultViewDate,
3126
+ onViewDateChange,
3127
+ locale: resolvedLocale,
3128
+ labels,
3129
+ minDate,
3130
+ maxDate,
3131
+ today,
3132
+ className: panelClassName
3133
+ }
3134
+ )
3135
+ }
3136
+ ) : null
3137
+ ] }) })
3138
+ ] });
3139
+ }
3140
+ var styles7 = reactNative.StyleSheet.create({
1287
3141
  wrapper: {
1288
- width: "100%",
1289
- gap: spacing.sm
1290
- },
1291
- row: {
1292
- flexDirection: "row",
1293
- alignItems: "flex-start",
1294
- gap: INPUT_ICON_GAP
3142
+ width: CALENDAR_FIELD_WIDTH,
3143
+ maxWidth: "100%",
3144
+ gap: SELECT_LABEL_GAP
1295
3145
  },
1296
- countrySelector: {
1297
- flexShrink: 0,
3146
+ fieldOutline: {
3147
+ width: CALENDAR_FIELD_WIDTH,
3148
+ maxWidth: "100%",
1298
3149
  alignSelf: "flex-start"
1299
3150
  },
1300
- phoneColumn: {
1301
- flex: 1,
1302
- gap: spacing.sm
3151
+ label: {
3152
+ ...calendarLabelTypography
1303
3153
  },
1304
- phoneOutline: {
1305
- width: "100%"
3154
+ iconSlot: {
3155
+ width: CALENDAR_FIELD_ICON_SIZE,
3156
+ height: CALENDAR_FIELD_ICON_SIZE,
3157
+ alignItems: "center",
3158
+ justifyContent: "center",
3159
+ flexShrink: 0
1306
3160
  },
1307
- phoneField: {
3161
+ modalRoot: {
1308
3162
  flex: 1
1309
3163
  },
3164
+ backdrop: {
3165
+ ...reactNative.StyleSheet.absoluteFillObject,
3166
+ backgroundColor: colors.transparent
3167
+ },
3168
+ panelPosition: {
3169
+ position: "absolute",
3170
+ zIndex: 1
3171
+ },
1310
3172
  error: {
1311
3173
  fontSize: 12,
1312
- lineHeight: 16,
3174
+ lineHeight: 12,
1313
3175
  color: colors.inputError
1314
3176
  },
1315
3177
  hint: {
1316
3178
  fontSize: 12,
1317
- lineHeight: 16,
3179
+ lineHeight: 12,
1318
3180
  color: colors.stormGray300
1319
3181
  }
1320
3182
  });
@@ -1326,8 +3188,8 @@ function LockIcon({
1326
3188
  color = "#c7cdd1",
1327
3189
  strokeWidth = 2
1328
3190
  }) {
1329
- return /* @__PURE__ */ jsxRuntime.jsx(Svg__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
1330
- Svg.Path,
3191
+ return /* @__PURE__ */ jsxRuntime.jsx(Svg5__default.default, { width: size, height: size, viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
3192
+ Svg5.Path,
1331
3193
  {
1332
3194
  d: LOCK_ICON_PATH,
1333
3195
  stroke: color,
@@ -1339,13 +3201,19 @@ function LockIcon({
1339
3201
  }
1340
3202
 
1341
3203
  exports.Button = Button;
3204
+ exports.Calendar = Calendar;
3205
+ exports.CalendarIcon = CalendarIcon;
3206
+ exports.CalendarLocaleProvider = CalendarLocaleProvider;
1342
3207
  exports.CountryCodeSelector = CountryCodeSelector;
3208
+ exports.DatePicker = DatePicker;
1343
3209
  exports.Input = Input;
1344
3210
  exports.Label = Label;
1345
3211
  exports.LockIcon = LockIcon;
1346
3212
  exports.PhoneInput = PhoneInput;
3213
+ exports.Select = Select;
1347
3214
  exports.brand = brand;
1348
3215
  exports.buttonTypography = buttonTypography;
3216
+ exports.calendarTranslations = calendarTranslations;
1349
3217
  exports.colors = colors;
1350
3218
  exports.countries = countries;
1351
3219
  exports.defaultCountry = defaultCountry;
@@ -1354,12 +3222,18 @@ exports.findCountry = findCountry;
1354
3222
  exports.fontSize = fontSize;
1355
3223
  exports.fontWeight = fontWeight;
1356
3224
  exports.fonts = fonts;
3225
+ exports.formatLocalizedCalendarMonthYear = formatLocalizedCalendarMonthYear;
3226
+ exports.getCalendarMonthLabels = getCalendarMonthLabels;
3227
+ exports.getCalendarTranslations = getCalendarTranslations;
1357
3228
  exports.labelTypography = labelTypography;
1358
3229
  exports.navy = navy;
1359
3230
  exports.radii = radii;
3231
+ exports.resolveCalendarLocale = resolveCalendarLocale;
3232
+ exports.resolveWeekdayLabels = resolveWeekdayLabels;
1360
3233
  exports.rubyRed = rubyRed;
1361
3234
  exports.shadows = shadows;
1362
3235
  exports.spacing = spacing;
1363
3236
  exports.stormGray = stormGray;
3237
+ exports.useCalendarLocale = useCalendarLocale;
1364
3238
  //# sourceMappingURL=index.cjs.map
1365
3239
  //# sourceMappingURL=index.cjs.map