@yomologic/react-ui 0.6.0 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,66 @@
1
1
  "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/constants/validation.ts
13
+ var validation_exports = {};
14
+ __export(validation_exports, {
15
+ DATE_REGEX: () => DATE_REGEX,
16
+ EMAIL_REGEX: () => EMAIL_REGEX,
17
+ PHONE_REGEX: () => PHONE_REGEX,
18
+ URL_REGEX: () => URL_REGEX,
19
+ isValidDate: () => isValidDate,
20
+ isValidEmail: () => isValidEmail,
21
+ isValidPhone: () => isValidPhone,
22
+ isValidUrl: () => isValidUrl
23
+ });
24
+ var EMAIL_REGEX, URL_REGEX, PHONE_REGEX, isValidEmail, isValidUrl, DATE_REGEX, isValidPhone, isValidDate;
25
+ var init_validation = __esm({
26
+ "src/constants/validation.ts"() {
27
+ "use strict";
28
+ EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
29
+ URL_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
30
+ PHONE_REGEX = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
31
+ isValidEmail = (email) => {
32
+ return EMAIL_REGEX.test(email);
33
+ };
34
+ isValidUrl = (url) => {
35
+ return URL_REGEX.test(url);
36
+ };
37
+ DATE_REGEX = /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/;
38
+ isValidPhone = (phone) => {
39
+ return PHONE_REGEX.test(phone);
40
+ };
41
+ isValidDate = (date) => {
42
+ if (!DATE_REGEX.test(date)) {
43
+ return false;
44
+ }
45
+ const [month, day, year] = date.split("/").map(Number);
46
+ if (year < 1900 || year > 2100) {
47
+ return false;
48
+ }
49
+ if (month < 1 || month > 12) {
50
+ return false;
51
+ }
52
+ const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
53
+ const isLeapYear = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
54
+ if (isLeapYear && month === 2) {
55
+ daysInMonth[1] = 29;
56
+ }
57
+ if (day < 1 || day > daysInMonth[month - 1]) {
58
+ return false;
59
+ }
60
+ return true;
61
+ };
62
+ }
63
+ });
2
64
 
3
65
  // src/ui/button.tsx
4
66
  import React from "react";
@@ -150,7 +212,112 @@ Button.displayName = "Button";
150
212
  // src/ui/input.tsx
151
213
  import React2 from "react";
152
214
 
215
+ // src/lib/formatting.ts
216
+ var formatPhoneUS = (value) => {
217
+ const digits = value.replace(/\D/g, "");
218
+ const limited = digits.slice(0, 10);
219
+ if (limited.length === 0) return "";
220
+ if (limited.length <= 3) return `(${limited}`;
221
+ if (limited.length <= 6)
222
+ return `(${limited.slice(0, 3)}) ${limited.slice(3)}`;
223
+ return `(${limited.slice(0, 3)}) ${limited.slice(3, 6)}-${limited.slice(6)}`;
224
+ };
225
+ var formatPhoneIntl = (value) => {
226
+ let cleaned = value.replace(/[^\d+]/g, "");
227
+ if (!cleaned.startsWith("+")) {
228
+ cleaned = "+" + cleaned;
229
+ }
230
+ cleaned = cleaned.slice(0, 16);
231
+ const digits = cleaned.slice(1);
232
+ if (digits.length === 0) return "+";
233
+ if (digits.length <= 1) return `+${digits}`;
234
+ if (digits.length <= 4) return `+${digits.slice(0, 1)} (${digits.slice(1)}`;
235
+ if (digits.length <= 7)
236
+ return `+${digits.slice(0, 1)} (${digits.slice(1, 4)}) ${digits.slice(4)}`;
237
+ return `+${digits.slice(0, 1)} (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
238
+ };
239
+ var formatCreditCard = (value) => {
240
+ const digits = value.replace(/\D/g, "");
241
+ const limited = digits.slice(0, 16);
242
+ return limited.replace(/(\d{4})/g, "$1 ").trim();
243
+ };
244
+ var formatDate = (value) => {
245
+ const digits = value.replace(/\D/g, "");
246
+ const limited = digits.slice(0, 8);
247
+ if (limited.length === 0) return "";
248
+ if (limited.length <= 2) return limited;
249
+ if (limited.length <= 4)
250
+ return `${limited.slice(0, 2)}/${limited.slice(2)}`;
251
+ return `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4)}`;
252
+ };
253
+ var formatDateTime = (value) => {
254
+ const digits = value.replace(/\D/g, "");
255
+ const limited = digits.slice(0, 12);
256
+ if (limited.length === 0) return "";
257
+ if (limited.length <= 2) return limited;
258
+ if (limited.length <= 4)
259
+ return `${limited.slice(0, 2)}/${limited.slice(2)}`;
260
+ if (limited.length <= 8)
261
+ return `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4)}`;
262
+ const datePart = `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4, 8)}`;
263
+ if (limited.length <= 10) return `${datePart} ${limited.slice(8)}`;
264
+ let hours = parseInt(limited.slice(8, 10));
265
+ const minutes = limited.slice(10, 12);
266
+ const ampm = hours >= 12 ? "PM" : "AM";
267
+ hours = hours % 12 || 12;
268
+ return `${datePart} ${hours}:${minutes} ${ampm}`;
269
+ };
270
+ var getRawValue = (value, format) => {
271
+ if (format === "date") {
272
+ const digits = value.replace(/\D/g, "");
273
+ if (digits.length === 8) {
274
+ const month = digits.slice(0, 2);
275
+ const day = digits.slice(2, 4);
276
+ const year = digits.slice(4, 8);
277
+ return `${year}-${month}-${day}`;
278
+ }
279
+ return digits;
280
+ }
281
+ if (format === "datetime") {
282
+ const digits = value.replace(/\D/g, "");
283
+ if (digits.length === 12) {
284
+ const month = digits.slice(0, 2);
285
+ const day = digits.slice(2, 4);
286
+ const year = digits.slice(4, 8);
287
+ const hours = digits.slice(8, 10);
288
+ const minutes = digits.slice(10, 12);
289
+ const date = new Date(
290
+ parseInt(year),
291
+ parseInt(month) - 1,
292
+ parseInt(day),
293
+ parseInt(hours),
294
+ parseInt(minutes)
295
+ );
296
+ return date.toISOString();
297
+ }
298
+ return digits;
299
+ }
300
+ return value.replace(/\D/g, "");
301
+ };
302
+ var applyFormat = (value, format) => {
303
+ switch (format) {
304
+ case "phone":
305
+ return formatPhoneUS(value);
306
+ case "phone-intl":
307
+ return formatPhoneIntl(value);
308
+ case "credit-card":
309
+ return formatCreditCard(value);
310
+ case "date":
311
+ return formatDate(value);
312
+ case "datetime":
313
+ return formatDateTime(value);
314
+ default:
315
+ return value;
316
+ }
317
+ };
318
+
153
319
  // src/ui/hooks/useFormField.ts
320
+ init_validation();
154
321
  import { useEffect, useId as useId2, useRef as useRef2, useState as useState3 } from "react";
155
322
 
156
323
  // src/ui/form.tsx
@@ -607,7 +774,7 @@ function FormControl({
607
774
  {
608
775
  className: cn(
609
776
  "text-small",
610
- currentError ? "text-error" : "text-(--color-muted-foreground)"
777
+ currentError ? "text-(--color-error)" : "text-(--color-muted-foreground)"
611
778
  ),
612
779
  id: `${fieldId}-message`,
613
780
  role: currentError ? "alert" : void 0,
@@ -679,7 +846,7 @@ function FormHelperText({
679
846
  {
680
847
  className: cn(
681
848
  "text-small",
682
- isError ? "text-error" : "text-(--color-muted-foreground)",
849
+ isError ? "text-(--color-error)" : "text-(--color-muted-foreground)",
683
850
  className
684
851
  ),
685
852
  role: isError ? "alert" : void 0,
@@ -738,7 +905,7 @@ function useFormField2(options) {
738
905
  return errorMessages?.required || "This field is required";
739
906
  }
740
907
  if (value) {
741
- if (type === "email" && !value.includes("@")) {
908
+ if (type === "email" && !EMAIL_REGEX.test(value)) {
742
909
  return errorMessages?.email || "Please enter a valid email address";
743
910
  }
744
911
  if (type === "url") {
@@ -795,7 +962,7 @@ function useFormField2(options) {
795
962
  return errorMessages?.required || "This field is required";
796
963
  }
797
964
  if (value) {
798
- if (type === "email" && !value.includes("@")) {
965
+ if (type === "email" && !EMAIL_REGEX.test(value)) {
799
966
  return errorMessages?.email || "Please enter a valid email address";
800
967
  }
801
968
  if (type === "url") {
@@ -912,12 +1079,31 @@ var Input = React2.forwardRef(
912
1079
  validate,
913
1080
  onValidationError,
914
1081
  pattern,
1082
+ format,
915
1083
  errorMessages,
916
1084
  ...props
917
1085
  }, ref) => {
1086
+ const [internalValue, setInternalValue] = React2.useState("");
1087
+ const dateValidate = React2.useCallback(
1088
+ async (value) => {
1089
+ if (validate) {
1090
+ const customError = await validate(value);
1091
+ if (customError) return customError;
1092
+ }
1093
+ if (format === "date" && value && value.length === 8) {
1094
+ const { isValidDate: isValidDate2 } = await Promise.resolve().then(() => (init_validation(), validation_exports));
1095
+ const formatted = `${value.slice(0, 2)}/${value.slice(2, 4)}/${value.slice(4, 8)}`;
1096
+ if (!isValidDate2(formatted)) {
1097
+ return errorMessages?.date || "Please enter a valid date";
1098
+ }
1099
+ }
1100
+ return void 0;
1101
+ },
1102
+ [validate, format, errorMessages]
1103
+ );
918
1104
  const {
919
1105
  fieldId,
920
- value: inputValue,
1106
+ value: hookValue,
921
1107
  error: inputError,
922
1108
  isDisabled,
923
1109
  isRequired,
@@ -939,19 +1125,71 @@ var Input = React2.forwardRef(
939
1125
  min: props.min,
940
1126
  max: props.max,
941
1127
  pattern,
942
- validate,
1128
+ validate: format === "date" ? dateValidate : validate,
943
1129
  onValidationError,
944
1130
  errorMessages,
945
1131
  idPrefix: "input"
946
1132
  });
1133
+ const inputValue = hookValue !== void 0 ? hookValue : internalValue;
1134
+ const [cursorPosition, setCursorPosition] = React2.useState(null);
947
1135
  const handleChange = (e) => {
948
- hookHandleChange(e.target.value);
1136
+ const input = e.target;
1137
+ const newValue = input.value;
1138
+ const cursorPos = input.selectionStart || 0;
1139
+ if (format && typeof format === "string") {
1140
+ const cleaned = newValue.replace(/\D/g, "");
1141
+ const formatted = applyFormat(cleaned, format);
1142
+ if (hookValue !== void 0) {
1143
+ hookHandleChange(cleaned);
1144
+ } else {
1145
+ setInternalValue(cleaned);
1146
+ }
1147
+ let formattedPos = 0;
1148
+ let digitCount = 0;
1149
+ const targetDigits = cleaned.slice(
1150
+ 0,
1151
+ Math.min(cleaned.length, cursorPos)
1152
+ );
1153
+ for (let i = 0; i < formatted.length && digitCount < targetDigits.length; i++) {
1154
+ if (/\d/.test(formatted[i])) {
1155
+ digitCount++;
1156
+ }
1157
+ formattedPos = i + 1;
1158
+ }
1159
+ setCursorPosition(formattedPos);
1160
+ } else {
1161
+ if (hookValue !== void 0) {
1162
+ hookHandleChange(newValue);
1163
+ } else {
1164
+ setInternalValue(newValue);
1165
+ }
1166
+ }
949
1167
  onChange?.(e);
950
1168
  };
951
1169
  const handleBlur = (e) => {
952
- hookHandleBlur(e.target.value);
1170
+ const value = e.target.value;
1171
+ const blurValue = format && typeof format === "string" ? value.replace(/\D/g, "") : value;
1172
+ hookHandleBlur(blurValue);
953
1173
  onBlur?.(e);
954
1174
  };
1175
+ const displayValue = React2.useMemo(() => {
1176
+ if (format && inputValue) {
1177
+ if (typeof format === "function") {
1178
+ return format(inputValue);
1179
+ }
1180
+ return applyFormat(inputValue, format);
1181
+ }
1182
+ return inputValue;
1183
+ }, [format, inputValue]);
1184
+ React2.useEffect(() => {
1185
+ if (cursorPosition !== null && internalRef.current) {
1186
+ internalRef.current.setSelectionRange(
1187
+ cursorPosition,
1188
+ cursorPosition
1189
+ );
1190
+ setCursorPosition(null);
1191
+ }
1192
+ }, [cursorPosition, displayValue]);
955
1193
  return /* @__PURE__ */ jsxs3(
956
1194
  "div",
957
1195
  {
@@ -984,7 +1222,7 @@ var Input = React2.forwardRef(
984
1222
  },
985
1223
  type,
986
1224
  id: fieldId,
987
- value: inputValue,
1225
+ value: displayValue,
988
1226
  onChange: handleChange,
989
1227
  onBlur: handleBlur,
990
1228
  disabled: isDisabled,
@@ -997,7 +1235,7 @@ var Input = React2.forwardRef(
997
1235
  "text-(--color-foreground) placeholder-gray-400",
998
1236
  "focus:outline-none",
999
1237
  "disabled:bg-(--color-muted) disabled:cursor-not-allowed disabled:text-(--color-muted-foreground)",
1000
- inputError ? "border-error focus:ring-2 focus:ring-error focus:border-error active:border-error" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) active:border-(--color-primary)",
1238
+ inputError ? "border-(--color-error) focus:ring-2 focus:ring-(--color-error) focus:border-(--color-error) active:border-(--color-error)" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) active:border-(--color-primary)",
1001
1239
  leftIcon && "pl-10",
1002
1240
  rightIcon && "pr-10",
1003
1241
  className
@@ -1011,7 +1249,7 @@ var Input = React2.forwardRef(
1011
1249
  shouldRenderError && inputError && /* @__PURE__ */ jsx4(
1012
1250
  "p",
1013
1251
  {
1014
- className: "text-small text-error",
1252
+ className: "text-small text-(--color-error)",
1015
1253
  id: `${fieldId}-error`,
1016
1254
  role: "alert",
1017
1255
  children: inputError
@@ -1241,7 +1479,7 @@ var Textarea = React3.forwardRef(
1241
1479
  "text-(--color-foreground) placeholder-gray-400",
1242
1480
  "focus:outline-none",
1243
1481
  "disabled:bg-(--color-muted) disabled:cursor-not-allowed disabled:text-(--color-muted-foreground)",
1244
- textareaError ? "border-error focus:ring-2 focus:ring-error focus:border-error active:border-error" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) active:border-(--color-primary)",
1482
+ textareaError ? "border-(--color-error) focus:ring-2 focus:ring-(--color-error) focus:border-(--color-error) active:border-(--color-error)" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) active:border-(--color-primary)",
1245
1483
  resizeClasses[resize],
1246
1484
  autoResize && "overflow-hidden",
1247
1485
  !autoResize && "overflow-auto",
@@ -1720,7 +1958,7 @@ function Checkbox({
1720
1958
  }
1721
1959
  )
1722
1960
  ] }),
1723
- /* @__PURE__ */ jsx8("div", { className: "h-5 mt-1.5", children: displayError && /* @__PURE__ */ jsx8("p", { className: "text-small text-error", role: "alert", children: displayError }) })
1961
+ /* @__PURE__ */ jsx8("div", { className: "h-5 mt-1.5", children: displayError && /* @__PURE__ */ jsx8("p", { className: "text-small text-(--color-error)", role: "alert", children: displayError }) })
1724
1962
  ] });
1725
1963
  }
1726
1964
  function CheckboxGroup({
@@ -1870,7 +2108,7 @@ function CheckboxGroup({
1870
2108
  /* @__PURE__ */ jsx8("div", { className: "h-5 mt-1.5", children: (error || helperText) && /* @__PURE__ */ jsx8(
1871
2109
  "p",
1872
2110
  {
1873
- className: `text-small ${error ? "text-error" : "text-(--color-muted-foreground)"}`,
2111
+ className: `text-small ${error ? "text-(--color-error)" : "text-(--color-muted-foreground)"}`,
1874
2112
  role: error ? "alert" : void 0,
1875
2113
  children: error || helperText
1876
2114
  }
@@ -2049,7 +2287,7 @@ function RadioGroup({
2049
2287
  /* @__PURE__ */ jsx9("div", { className: "h-5 mt-1.5", children: (displayError || helperText) && /* @__PURE__ */ jsx9(
2050
2288
  "p",
2051
2289
  {
2052
- className: `text-small ${displayError ? "text-error" : "text-(--color-muted-foreground)"}`,
2290
+ className: `text-small ${displayError ? "text-(--color-error)" : "text-(--color-muted-foreground)"}`,
2053
2291
  role: displayError ? "alert" : void 0,
2054
2292
  children: displayError || helperText
2055
2293
  }
@@ -2278,7 +2516,7 @@ function Select({
2278
2516
  flex items-center justify-between
2279
2517
  transition-all duration-200
2280
2518
  outline-none
2281
- ${displayError ? "border-error focus:ring-2 focus:ring-error focus:border-error focus-visible:ring-2 focus-visible:ring-error focus-visible:border-error" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) focus-visible:ring-2 focus-visible:ring-(--color-primary)/30 focus-visible:border-(--color-primary)"}
2519
+ ${displayError ? "border-(--color-error) focus:ring-2 focus:ring-(--color-error) focus:border-(--color-error) focus-visible:ring-2 focus-visible:ring-(--color-error) focus-visible:border-(--color-error)" : "border-(--color-border) focus:ring-2 focus:ring-(--color-primary)/30 focus:border-(--color-primary) focus-visible:ring-2 focus-visible:ring-(--color-primary)/30 focus-visible:border-(--color-primary)"}
2282
2520
  ${disabled ? "bg-(--color-muted) cursor-not-allowed opacity-60" : "hover:border-(--color-primary)"}
2283
2521
  ${!value ? "text-(--color-placeholder)" : "text-(--color-foreground)"}
2284
2522
  `,
@@ -2367,7 +2605,7 @@ function Select({
2367
2605
  /* @__PURE__ */ jsx10("div", { className: "h-5 mt-1.5", children: (helperText || displayError) && /* @__PURE__ */ jsx10(
2368
2606
  "p",
2369
2607
  {
2370
- className: `text-small ${displayError ? "text-error" : "text-(--color-muted-foreground)"}`,
2608
+ className: `text-small ${displayError ? "text-(--color-error)" : "text-(--color-muted-foreground)"}`,
2371
2609
  children: displayError || helperText
2372
2610
  }
2373
2611
  ) })
@@ -2446,7 +2684,7 @@ function NativeSelect({
2446
2684
  style: { color: "var(--color-muted-foreground)" },
2447
2685
  children: [
2448
2686
  label,
2449
- required && /* @__PURE__ */ jsx11("span", { className: "ml-1 text-error", children: "*" })
2687
+ required && /* @__PURE__ */ jsx11("span", { className: "ml-1 text-(--color-error)", children: "*" })
2450
2688
  ]
2451
2689
  }
2452
2690
  ),
@@ -2466,7 +2704,7 @@ function NativeSelect({
2466
2704
  appearance-none
2467
2705
  cursor-pointer
2468
2706
  outline-none
2469
- ${displayError ? "border-error focus:border-error active:border-error" : "border-(--color-border) focus:border-(--color-primary) active:border-(--color-primary)"}
2707
+ ${displayError ? "border-(--color-error) focus:border-(--color-error) active:border-(--color-error)" : "border-(--color-border) focus:border-(--color-primary) active:border-(--color-primary)"}
2470
2708
  ${disabled ? "bg-(--color-muted) cursor-not-allowed opacity-60" : "hover:border-(--color-primary)"}
2471
2709
  ${!value ? "text-(--color-placeholder)" : "text-(--color-foreground)"}
2472
2710
  pr-10
@@ -2482,7 +2720,7 @@ function NativeSelect({
2482
2720
  /* @__PURE__ */ jsx11("div", { className: "h-5 mt-1.5", children: (helperText || displayError) && /* @__PURE__ */ jsx11(
2483
2721
  "p",
2484
2722
  {
2485
- className: `text-small ${displayError ? "text-error" : "text-(--color-muted-foreground)"}`,
2723
+ className: `text-small ${displayError ? "text-(--color-error)" : "text-(--color-muted-foreground)"}`,
2486
2724
  children: displayError || helperText
2487
2725
  }
2488
2726
  ) })
@@ -5183,6 +5421,9 @@ function useTheme() {
5183
5421
  }
5184
5422
  return context;
5185
5423
  }
5424
+
5425
+ // src/index.ts
5426
+ init_validation();
5186
5427
  export {
5187
5428
  Alert,
5188
5429
  Badge,
@@ -5200,6 +5441,7 @@ export {
5200
5441
  CheckboxGroup,
5201
5442
  CodeSnippet,
5202
5443
  Container,
5444
+ DATE_REGEX,
5203
5445
  Dialog,
5204
5446
  DialogContent,
5205
5447
  DialogDescription,
@@ -5208,6 +5450,7 @@ export {
5208
5450
  DialogTitle,
5209
5451
  Divider,
5210
5452
  Drawer,
5453
+ EMAIL_REGEX,
5211
5454
  EmptyState,
5212
5455
  Form,
5213
5456
  FormControl,
@@ -5216,6 +5459,7 @@ export {
5216
5459
  Input,
5217
5460
  NativeSelect,
5218
5461
  Nav,
5462
+ PHONE_REGEX,
5219
5463
  RadioGroup,
5220
5464
  Rating,
5221
5465
  SectionLayout,
@@ -5226,7 +5470,19 @@ export {
5226
5470
  Switch,
5227
5471
  Textarea,
5228
5472
  ThemeProvider,
5473
+ URL_REGEX,
5474
+ applyFormat,
5229
5475
  cn,
5476
+ formatCreditCard,
5477
+ formatDate,
5478
+ formatDateTime,
5479
+ formatPhoneIntl,
5480
+ formatPhoneUS,
5481
+ getRawValue,
5482
+ isValidDate,
5483
+ isValidEmail,
5484
+ isValidPhone,
5485
+ isValidUrl,
5230
5486
  themes_default as themes,
5231
5487
  useForm,
5232
5488
  useFormContext,