@komensal/ui 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -110,7 +110,55 @@ import * as React2 from "react";
110
110
 
111
111
  // src/components/spinner.tsx
112
112
  import clsx2 from "clsx";
113
- import { useTranslation } from "react-i18next";
113
+
114
+ // src/lib/i18n.ts
115
+ import i18n from "i18next";
116
+ import { initReactI18next, useTranslation } from "react-i18next";
117
+
118
+ // src/locales/es/ui.json
119
+ var ui_default = {
120
+ otpField: {
121
+ description: "Se ha enviado un c\xF3digo OTP a tu correo . Revisa tu bandeja de entrada."
122
+ },
123
+ inputField: {
124
+ showPassword: "Mostrar contrase\xF1a",
125
+ hidePassword: "Ocultar contrase\xF1a",
126
+ clear: "Limpiar"
127
+ },
128
+ dialog: {
129
+ close: "Cerrar"
130
+ },
131
+ selectInput: {
132
+ placeholder: "Selecciona...",
133
+ loading: "Cargando...",
134
+ search: "Buscar...",
135
+ noResults: "Sin resultados."
136
+ },
137
+ passwordChecklist: {
138
+ minLength: "M\xEDnimo {{min}} caracteres",
139
+ hasUpperAndLower: "Una may\xFAscula y min\xFAscula",
140
+ hasNumber: "Un n\xFAmero",
141
+ hasSpecialChar: "Un car\xE1cter especial"
142
+ },
143
+ spinner: {
144
+ loading: "Cargando..."
145
+ }
146
+ };
147
+
148
+ // src/lib/i18n.ts
149
+ var uiI18n = i18n.createInstance();
150
+ void uiI18n.use(initReactI18next).init({
151
+ defaultNS: "ui",
152
+ fallbackLng: "es",
153
+ interpolation: { escapeValue: false },
154
+ lng: "es",
155
+ ns: ["ui"],
156
+ resources: { es: { ui: ui_default } }
157
+ });
158
+ var setUiLanguage = (lng) => uiI18n.changeLanguage(lng);
159
+ var useUiT = () => useTranslation("ui", { i18n: uiI18n }).t;
160
+
161
+ // src/components/spinner.tsx
114
162
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
115
163
  var sizes = {
116
164
  lg: "70",
@@ -124,8 +172,8 @@ var variants = {
124
172
  primary: "var(--color-spinner-primary)",
125
173
  secondary: "var(--color-spinner-secondary)"
126
174
  };
127
- var Spinner = ({ className = "", size = "md", variant = "primary" }) => {
128
- const { t } = useTranslation("ui");
175
+ var Spinner = ({ className = "", loadingLabel, size = "md", variant = "primary" }) => {
176
+ const t = useUiT();
129
177
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
130
178
  /* @__PURE__ */ jsx3(
131
179
  "svg",
@@ -164,7 +212,7 @@ var Spinner = ({ className = "", size = "md", variant = "primary" }) => {
164
212
  ] })
165
213
  }
166
214
  ),
167
- /* @__PURE__ */ jsx3("span", { className: "sr-only", children: t("spinner.loading") })
215
+ /* @__PURE__ */ jsx3("span", { className: "sr-only", children: loadingLabel ?? t("spinner.loading") })
168
216
  ] });
169
217
  };
170
218
 
@@ -292,7 +340,6 @@ import * as React4 from "react";
292
340
  import * as DialogPrimitive from "@radix-ui/react-dialog";
293
341
  import { Cross2Icon } from "@radix-ui/react-icons";
294
342
  import * as React3 from "react";
295
- import { useTranslation as useTranslation2 } from "react-i18next";
296
343
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
297
344
  var Dialog = DialogPrimitive.Root;
298
345
  var DialogTrigger = DialogPrimitive.Trigger;
@@ -312,8 +359,8 @@ var DialogOverlay = React3.forwardRef(({ className, isAbsolute = false, ...props
312
359
  ));
313
360
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
314
361
  var DialogContent = React3.forwardRef(
315
- ({ children, className, container, isAbsolute = false, isCloseIcon = false, overlayClassName, ...props }, ref) => {
316
- const { t } = useTranslation2("ui");
362
+ ({ children, className, closeLabel, container, isAbsolute = false, isCloseIcon = false, overlayClassName, ...props }, ref) => {
363
+ const t = useUiT();
317
364
  return /* @__PURE__ */ jsxs6(DialogPortal, { container, children: [
318
365
  /* @__PURE__ */ jsx6(DialogOverlay, { className: overlayClassName, isAbsolute }),
319
366
  /* @__PURE__ */ jsxs6(
@@ -330,7 +377,7 @@ var DialogContent = React3.forwardRef(
330
377
  children,
331
378
  isCloseIcon && /* @__PURE__ */ jsxs6(DialogPrimitive.Close, { className: "data-[state=open]:text-muted ring-offset-surface focus:ring-ring data-[state=open]:bg-hover border-border bg-border absolute top-11 right-8 flex h-8 w-8 min-w-8 cursor-pointer items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none", children: [
332
379
  /* @__PURE__ */ jsx6(Cross2Icon, { className: "text-body hover:text-primary-dark h-4 w-4" }),
333
- /* @__PURE__ */ jsx6("span", { className: "sr-only", children: t("dialog.close") })
380
+ /* @__PURE__ */ jsx6("span", { className: "sr-only", children: closeLabel ?? t("dialog.close") })
334
381
  ] })
335
382
  ]
336
383
  }
@@ -529,7 +576,6 @@ FormMessage.displayName = "FormMessage";
529
576
 
530
577
  // src/components/form-fields/input-field.tsx
531
578
  import { useState } from "react";
532
- import { useTranslation as useTranslation3 } from "react-i18next";
533
579
  import { FaRegEye, FaRegEyeSlash } from "react-icons/fa6";
534
580
  import { RxCross2 } from "react-icons/rx";
535
581
 
@@ -590,8 +636,10 @@ var LabelField = ({ label, labelClassName, name, visualRequired }) => {
590
636
  // src/components/form-fields/input-field.tsx
591
637
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
592
638
  var InputField = ({
639
+ clearLabel,
593
640
  control,
594
641
  disabled,
642
+ hidePasswordLabel,
595
643
  inputClassName,
596
644
  isClearable,
597
645
  label,
@@ -600,10 +648,11 @@ var InputField = ({
600
648
  name,
601
649
  onClear,
602
650
  placeholder,
651
+ showPasswordLabel,
603
652
  type = "text",
604
653
  visualRequired
605
654
  }) => {
606
- const { t } = useTranslation3("ui");
655
+ const t = useUiT();
607
656
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
608
657
  const togglePasswordVisibility = () => {
609
658
  setIsPasswordVisible((prev) => !prev);
@@ -662,7 +711,7 @@ var InputField = ({
662
711
  {
663
712
  className: "focus:outline-none",
664
713
  onClick: onClear,
665
- title: t("inputField.clear"),
714
+ title: clearLabel ?? t("inputField.clear"),
666
715
  type: "button",
667
716
  children: /* @__PURE__ */ jsx12(RxCross2, { size: 18 })
668
717
  }
@@ -672,7 +721,7 @@ var InputField = ({
672
721
  {
673
722
  className: "focus:outline-none",
674
723
  onClick: togglePasswordVisibility,
675
- title: isPasswordVisible ? t("inputField.hidePassword") : t("inputField.showPassword"),
724
+ title: isPasswordVisible ? hidePasswordLabel ?? t("inputField.hidePassword") : showPasswordLabel ?? t("inputField.showPassword"),
676
725
  type: "button",
677
726
  children: isPasswordVisible ? /* @__PURE__ */ jsx12(FaRegEye, { size: 18 }) : /* @__PURE__ */ jsx12(FaRegEyeSlash, { size: 20 })
678
727
  }
@@ -694,13 +743,27 @@ var DEFAULT_CENTER = { lat: 4.711, lng: -74.0721 };
694
743
  var PICKER_MAP_ID = "komensal-restaurant-map";
695
744
  var SELECTED_ZOOM = 15;
696
745
  var DEBOUNCE_MS = 300;
746
+ var parseComponents = (components) => {
747
+ const find = (type) => components.find((c) => c.types.includes(type));
748
+ const country = find("country");
749
+ const department = find("administrative_area_level_1");
750
+ const city = find("locality") ?? find("administrative_area_level_2");
751
+ return {
752
+ city: city?.long ?? null,
753
+ country: country?.short ?? null,
754
+ countryName: country?.long ?? null,
755
+ department: department?.long ?? null
756
+ };
757
+ };
697
758
  var CITY_ZOOM = 12;
698
759
  var MapPickerContent = ({
699
760
  centerOn,
761
+ countryCode,
700
762
  disabled,
701
763
  hasError,
702
764
  locationQuery,
703
765
  locationZoom,
766
+ onAddressResolved,
704
767
  onChange,
705
768
  placeholder,
706
769
  value
@@ -709,6 +772,7 @@ var MapPickerContent = ({
709
772
  const geocodingLib = useMapsLibrary("geocoding");
710
773
  const map = useMap(PICKER_MAP_ID);
711
774
  const onChangeRef = useRef(onChange);
775
+ const onResolvedRef = useRef(onAddressResolved);
712
776
  const geocoder = useMemo(
713
777
  () => geocodingLib ? new geocodingLib.Geocoder() : null,
714
778
  [geocodingLib]
@@ -721,6 +785,7 @@ var MapPickerContent = ({
721
785
  const [position, setPosition] = useState2(null);
722
786
  useEffect(() => {
723
787
  onChangeRef.current = onChange;
788
+ onResolvedRef.current = onAddressResolved;
724
789
  });
725
790
  useEffect(() => {
726
791
  setInputValue(value);
@@ -768,6 +833,7 @@ var MapPickerContent = ({
768
833
  }
769
834
  try {
770
835
  const result = await placesLib.AutocompleteSuggestion.fetchAutocompleteSuggestions({
836
+ includedRegionCodes: countryCode ? [countryCode.toLowerCase()] : void 0,
771
837
  input,
772
838
  sessionToken
773
839
  });
@@ -777,7 +843,7 @@ var MapPickerContent = ({
777
843
  setSuggestions([]);
778
844
  }
779
845
  },
780
- [placesLib, sessionToken]
846
+ [placesLib, sessionToken, countryCode]
781
847
  );
782
848
  const reverseGeocode = useCallback(
783
849
  async (latLng) => {
@@ -785,9 +851,14 @@ var MapPickerContent = ({
785
851
  try {
786
852
  const { results } = await geocoder.geocode({ location: latLng });
787
853
  if (results.length > 0) {
788
- const address = results[0].formatted_address;
854
+ const result = results[0];
855
+ const address = result.formatted_address;
789
856
  setInputValue(address);
790
857
  onChangeRef.current(address);
858
+ const parts = parseComponents(
859
+ result.address_components.map((c) => ({ long: c.long_name, short: c.short_name, types: c.types }))
860
+ );
861
+ onResolvedRef.current?.({ address, lat: latLng.lat, lng: latLng.lng, ...parts });
791
862
  }
792
863
  } catch {
793
864
  return;
@@ -806,15 +877,21 @@ var MapPickerContent = ({
806
877
  const prediction = suggestion.placePrediction;
807
878
  if (!prediction) return;
808
879
  const place = prediction.toPlace();
809
- await place.fetchFields({ fields: ["formattedAddress", "location"] });
880
+ await place.fetchFields({ fields: ["formattedAddress", "location", "addressComponents"] });
810
881
  const address = place.formattedAddress ?? prediction.text.text;
811
882
  setInputValue(address);
812
883
  onChangeRef.current(address);
813
884
  setSuggestions([]);
814
885
  setShowDropdown(false);
886
+ const lat = place.location?.lat() ?? null;
887
+ const lng = place.location?.lng() ?? null;
815
888
  if (place.location) {
816
889
  setPosition({ lat: place.location.lat(), lng: place.location.lng() });
817
890
  }
891
+ const parts = parseComponents(
892
+ (place.addressComponents ?? []).map((c) => ({ long: c.longText, short: c.shortText, types: c.types }))
893
+ );
894
+ onResolvedRef.current?.({ address, lat, lng, ...parts });
818
895
  if (placesLib) setSessionToken(new placesLib.AutocompleteSessionToken());
819
896
  };
820
897
  const handleBlur = () => {
@@ -1018,7 +1095,6 @@ function OTPField({
1018
1095
  // src/components/select-input.tsx
1019
1096
  import { ChevronDown, ChevronUp, Clock, XIcon } from "lucide-react";
1020
1097
  import { cloneElement, useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
1021
- import { useTranslation as useTranslation4 } from "react-i18next";
1022
1098
 
1023
1099
  // src/components/popover.tsx
1024
1100
  import * as PopoverPrimitive from "@radix-ui/react-popover";
@@ -1045,7 +1121,7 @@ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
1045
1121
  // src/components/select-input.tsx
1046
1122
  import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1047
1123
  var SelectInput = (props) => {
1048
- const { t } = useTranslation4("ui");
1124
+ const t = useUiT();
1049
1125
  const {
1050
1126
  ableDeleteOption,
1051
1127
  className,
@@ -1055,12 +1131,15 @@ var SelectInput = (props) => {
1055
1131
  labelKey = "label",
1056
1132
  leftIcon,
1057
1133
  loading = false,
1134
+ loadingLabel,
1135
+ noResultsLabel,
1058
1136
  onBlur,
1059
1137
  onChange,
1060
1138
  onValueChangeCallBack = () => void 0,
1061
1139
  placeholder,
1062
1140
  placeholderClassName = "",
1063
1141
  search = false,
1142
+ searchPlaceholder,
1064
1143
  timeField = false,
1065
1144
  value = "",
1066
1145
  valueKey = "value"
@@ -1138,7 +1217,7 @@ var SelectInput = (props) => {
1138
1217
  role: "combobox",
1139
1218
  variant: "primary",
1140
1219
  children: loading ? /* @__PURE__ */ jsxs14(Fragment3, { children: [
1141
- t("selectInput.loading"),
1220
+ loadingLabel ?? t("selectInput.loading"),
1142
1221
  " ",
1143
1222
  /* @__PURE__ */ jsx18(Spinner, {})
1144
1223
  ] }) : /* @__PURE__ */ jsxs14("div", { className: "relative flex h-5 w-full items-center", children: [
@@ -1179,11 +1258,11 @@ var SelectInput = (props) => {
1179
1258
  {
1180
1259
  className: "mb-1 rounded-sm",
1181
1260
  onChange: (e) => setQuery(e.target.value),
1182
- placeholder: t("selectInput.search"),
1261
+ placeholder: searchPlaceholder ?? t("selectInput.search"),
1183
1262
  value: query
1184
1263
  }
1185
1264
  ),
1186
- /* @__PURE__ */ jsx18(CommandEmpty, { className: "text-center", children: t("selectInput.noResults") }),
1265
+ /* @__PURE__ */ jsx18(CommandEmpty, { className: "text-center", children: noResultsLabel ?? t("selectInput.noResults") }),
1187
1266
  /* @__PURE__ */ jsx18(CommandList, { children: /* @__PURE__ */ jsx18(CommandGroup, { className: "p-0", children: filteredOptions.map((item) => {
1188
1267
  const labelValue = item[labelKey];
1189
1268
  const valueValue = item[valueKey];
@@ -1704,7 +1783,9 @@ export {
1704
1783
  inputFocus,
1705
1784
  inputPlaceholder,
1706
1785
  registerToastEmitter,
1786
+ setUiLanguage,
1707
1787
  toast,
1788
+ uiI18n,
1708
1789
  useFormField
1709
1790
  };
1710
1791
  //# sourceMappingURL=index.js.map