@yomologic/react-ui 0.6.2 → 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.d.mts CHANGED
@@ -20,6 +20,42 @@ type ButtonAsLink = ButtonBaseProps & Omit<React.AnchorHTMLAttributes<HTMLAnchor
20
20
  type ButtonProps = ButtonAsButton | ButtonAsLink;
21
21
  declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
22
22
 
23
+ /**
24
+ * Input formatting utilities
25
+ */
26
+ type FormatType = "phone" | "phone-intl" | "credit-card" | "date" | "datetime";
27
+ /**
28
+ * Format US phone number: (123) 456-7890
29
+ */
30
+ declare const formatPhoneUS: (value: string) => string;
31
+ /**
32
+ * Format international phone number: +1 (123) 456-7890
33
+ */
34
+ declare const formatPhoneIntl: (value: string) => string;
35
+ /**
36
+ * Format credit card number: 1234 5678 9012 3456
37
+ */
38
+ declare const formatCreditCard: (value: string) => string;
39
+ /**
40
+ * Format date: MM/DD/YYYY
41
+ */
42
+ declare const formatDate: (value: string) => string;
43
+ /**
44
+ * Format datetime: MM/DD/YYYY HH:MM AM/PM
45
+ */
46
+ declare const formatDateTime: (value: string) => string;
47
+ /**
48
+ * Get raw value from formatted string
49
+ * - For phone/credit-card: returns digits only
50
+ * - For date: returns YYYY-MM-DD format (ISO 8601)
51
+ * - For datetime: returns ISO 8601 with timezone offset
52
+ */
53
+ declare const getRawValue: (value: string, format?: FormatType) => string;
54
+ /**
55
+ * Apply format based on format type
56
+ */
57
+ declare const applyFormat: (value: string, format: FormatType) => string;
58
+
23
59
  interface FormState {
24
60
  values: Record<string, any>;
25
61
  errors: Record<string, string>;
@@ -62,6 +98,8 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
62
98
  onValidationError?: (error: string | undefined) => void;
63
99
  /** Regex pattern for validation (string or RegExp) */
64
100
  pattern?: RegExp | string;
101
+ /** Format type for auto-formatting input value (phone, credit-card, date, etc.) */
102
+ format?: FormatType | ((value: string) => string);
65
103
  /** Custom error messages for built-in validations */
66
104
  errorMessages?: {
67
105
  required?: string;
@@ -72,6 +110,7 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
72
110
  pattern?: string;
73
111
  email?: string;
74
112
  url?: string;
113
+ date?: string;
75
114
  };
76
115
  }
77
116
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
@@ -1107,4 +1146,45 @@ type ThemeId = keyof typeof themes;
1107
1146
 
1108
1147
  declare function cn(...inputs: ClassValue[]): string;
1109
1148
 
1110
- export { Alert, Badge, Button, Card, CardActionArea, CardActions, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, CodeSnippet, Container, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Divider, Drawer, type NavItem$1 as DrawerNavItem, type NavSection$1 as DrawerNavSection, type DrawerProps, EmptyState, Form, type FormContextValue, FormControl, type FormControlContextValue, FormControlLabel, type FormControlProps, type FormControlState, type FormFieldProps, FormHelperText, type FormState, Input, NativeSelect, type NativeSelectProps, Nav, type NavItem$2 as NavItem, type NavProps, type NavSection, RadioGroup, Rating, SectionLayout, Select, type SelectOption, type SelectProps, SidebarNav, type NavItem as SidebarNavItem, Slider, type SliderMark, type SliderProps, Spinner, Switch, type SwitchProps, Textarea, type TextareaProps, type ThemeId, ThemeProvider, type ValidationFunction, type ValidationRule, cn, themes, useForm, useFormContext, useFormControl, useFormControlContext, useFormField, useTheme };
1149
+ /**
1150
+ * Validation constants and regex patterns
1151
+ */
1152
+ /**
1153
+ * RFC 5322 compliant email validation regex (simplified)
1154
+ * Matches standard email formats like: user@example.com
1155
+ */
1156
+ declare const EMAIL_REGEX: RegExp;
1157
+ /**
1158
+ * URL validation regex
1159
+ * Matches http(s) URLs
1160
+ */
1161
+ declare const URL_REGEX: RegExp;
1162
+ /**
1163
+ * Phone number validation regex (US format)
1164
+ * Matches formats like: (123) 456-7890, 123-456-7890, 1234567890
1165
+ */
1166
+ declare const PHONE_REGEX: RegExp;
1167
+ /**
1168
+ * Validate email format
1169
+ */
1170
+ declare const isValidEmail: (email: string) => boolean;
1171
+ /**
1172
+ * Validate URL format
1173
+ */
1174
+ declare const isValidUrl: (url: string) => boolean;
1175
+ /**
1176
+ * Date validation regex (MM/DD/YYYY)
1177
+ * Matches formats like: 12/31/2024, 01/01/2024
1178
+ */
1179
+ declare const DATE_REGEX: RegExp;
1180
+ /**
1181
+ * Validate phone number format
1182
+ */
1183
+ declare const isValidPhone: (phone: string) => boolean;
1184
+ /**
1185
+ * Validate date format and value
1186
+ * Checks if date is in MM/DD/YYYY format and is a valid calendar date
1187
+ */
1188
+ declare const isValidDate: (date: string) => boolean;
1189
+
1190
+ export { Alert, Badge, Button, Card, CardActionArea, CardActions, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, CodeSnippet, Container, DATE_REGEX, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Divider, Drawer, type NavItem$1 as DrawerNavItem, type NavSection$1 as DrawerNavSection, type DrawerProps, EMAIL_REGEX, EmptyState, Form, type FormContextValue, FormControl, type FormControlContextValue, FormControlLabel, type FormControlProps, type FormControlState, type FormFieldProps, FormHelperText, type FormState, type FormatType, Input, NativeSelect, type NativeSelectProps, Nav, type NavItem$2 as NavItem, type NavProps, type NavSection, PHONE_REGEX, RadioGroup, Rating, SectionLayout, Select, type SelectOption, type SelectProps, SidebarNav, type NavItem as SidebarNavItem, Slider, type SliderMark, type SliderProps, Spinner, Switch, type SwitchProps, Textarea, type TextareaProps, type ThemeId, ThemeProvider, URL_REGEX, type ValidationFunction, type ValidationRule, applyFormat, cn, formatCreditCard, formatDate, formatDateTime, formatPhoneIntl, formatPhoneUS, getRawValue, isValidDate, isValidEmail, isValidPhone, isValidUrl, themes, useForm, useFormContext, useFormControl, useFormControlContext, useFormField, useTheme };
package/dist/index.d.ts CHANGED
@@ -20,6 +20,42 @@ type ButtonAsLink = ButtonBaseProps & Omit<React.AnchorHTMLAttributes<HTMLAnchor
20
20
  type ButtonProps = ButtonAsButton | ButtonAsLink;
21
21
  declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
22
22
 
23
+ /**
24
+ * Input formatting utilities
25
+ */
26
+ type FormatType = "phone" | "phone-intl" | "credit-card" | "date" | "datetime";
27
+ /**
28
+ * Format US phone number: (123) 456-7890
29
+ */
30
+ declare const formatPhoneUS: (value: string) => string;
31
+ /**
32
+ * Format international phone number: +1 (123) 456-7890
33
+ */
34
+ declare const formatPhoneIntl: (value: string) => string;
35
+ /**
36
+ * Format credit card number: 1234 5678 9012 3456
37
+ */
38
+ declare const formatCreditCard: (value: string) => string;
39
+ /**
40
+ * Format date: MM/DD/YYYY
41
+ */
42
+ declare const formatDate: (value: string) => string;
43
+ /**
44
+ * Format datetime: MM/DD/YYYY HH:MM AM/PM
45
+ */
46
+ declare const formatDateTime: (value: string) => string;
47
+ /**
48
+ * Get raw value from formatted string
49
+ * - For phone/credit-card: returns digits only
50
+ * - For date: returns YYYY-MM-DD format (ISO 8601)
51
+ * - For datetime: returns ISO 8601 with timezone offset
52
+ */
53
+ declare const getRawValue: (value: string, format?: FormatType) => string;
54
+ /**
55
+ * Apply format based on format type
56
+ */
57
+ declare const applyFormat: (value: string, format: FormatType) => string;
58
+
23
59
  interface FormState {
24
60
  values: Record<string, any>;
25
61
  errors: Record<string, string>;
@@ -62,6 +98,8 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
62
98
  onValidationError?: (error: string | undefined) => void;
63
99
  /** Regex pattern for validation (string or RegExp) */
64
100
  pattern?: RegExp | string;
101
+ /** Format type for auto-formatting input value (phone, credit-card, date, etc.) */
102
+ format?: FormatType | ((value: string) => string);
65
103
  /** Custom error messages for built-in validations */
66
104
  errorMessages?: {
67
105
  required?: string;
@@ -72,6 +110,7 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
72
110
  pattern?: string;
73
111
  email?: string;
74
112
  url?: string;
113
+ date?: string;
75
114
  };
76
115
  }
77
116
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
@@ -1107,4 +1146,45 @@ type ThemeId = keyof typeof themes;
1107
1146
 
1108
1147
  declare function cn(...inputs: ClassValue[]): string;
1109
1148
 
1110
- export { Alert, Badge, Button, Card, CardActionArea, CardActions, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, CodeSnippet, Container, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Divider, Drawer, type NavItem$1 as DrawerNavItem, type NavSection$1 as DrawerNavSection, type DrawerProps, EmptyState, Form, type FormContextValue, FormControl, type FormControlContextValue, FormControlLabel, type FormControlProps, type FormControlState, type FormFieldProps, FormHelperText, type FormState, Input, NativeSelect, type NativeSelectProps, Nav, type NavItem$2 as NavItem, type NavProps, type NavSection, RadioGroup, Rating, SectionLayout, Select, type SelectOption, type SelectProps, SidebarNav, type NavItem as SidebarNavItem, Slider, type SliderMark, type SliderProps, Spinner, Switch, type SwitchProps, Textarea, type TextareaProps, type ThemeId, ThemeProvider, type ValidationFunction, type ValidationRule, cn, themes, useForm, useFormContext, useFormControl, useFormControlContext, useFormField, useTheme };
1149
+ /**
1150
+ * Validation constants and regex patterns
1151
+ */
1152
+ /**
1153
+ * RFC 5322 compliant email validation regex (simplified)
1154
+ * Matches standard email formats like: user@example.com
1155
+ */
1156
+ declare const EMAIL_REGEX: RegExp;
1157
+ /**
1158
+ * URL validation regex
1159
+ * Matches http(s) URLs
1160
+ */
1161
+ declare const URL_REGEX: RegExp;
1162
+ /**
1163
+ * Phone number validation regex (US format)
1164
+ * Matches formats like: (123) 456-7890, 123-456-7890, 1234567890
1165
+ */
1166
+ declare const PHONE_REGEX: RegExp;
1167
+ /**
1168
+ * Validate email format
1169
+ */
1170
+ declare const isValidEmail: (email: string) => boolean;
1171
+ /**
1172
+ * Validate URL format
1173
+ */
1174
+ declare const isValidUrl: (url: string) => boolean;
1175
+ /**
1176
+ * Date validation regex (MM/DD/YYYY)
1177
+ * Matches formats like: 12/31/2024, 01/01/2024
1178
+ */
1179
+ declare const DATE_REGEX: RegExp;
1180
+ /**
1181
+ * Validate phone number format
1182
+ */
1183
+ declare const isValidPhone: (phone: string) => boolean;
1184
+ /**
1185
+ * Validate date format and value
1186
+ * Checks if date is in MM/DD/YYYY format and is a valid calendar date
1187
+ */
1188
+ declare const isValidDate: (date: string) => boolean;
1189
+
1190
+ export { Alert, Badge, Button, Card, CardActionArea, CardActions, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, CardTitle, Checkbox, CheckboxGroup, CodeSnippet, Container, DATE_REGEX, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Divider, Drawer, type NavItem$1 as DrawerNavItem, type NavSection$1 as DrawerNavSection, type DrawerProps, EMAIL_REGEX, EmptyState, Form, type FormContextValue, FormControl, type FormControlContextValue, FormControlLabel, type FormControlProps, type FormControlState, type FormFieldProps, FormHelperText, type FormState, type FormatType, Input, NativeSelect, type NativeSelectProps, Nav, type NavItem$2 as NavItem, type NavProps, type NavSection, PHONE_REGEX, RadioGroup, Rating, SectionLayout, Select, type SelectOption, type SelectProps, SidebarNav, type NavItem as SidebarNavItem, Slider, type SliderMark, type SliderProps, Spinner, Switch, type SwitchProps, Textarea, type TextareaProps, type ThemeId, ThemeProvider, URL_REGEX, type ValidationFunction, type ValidationRule, applyFormat, cn, formatCreditCard, formatDate, formatDateTime, formatPhoneIntl, formatPhoneUS, getRawValue, isValidDate, isValidEmail, isValidPhone, isValidUrl, themes, useForm, useFormContext, useFormControl, useFormControlContext, useFormField, useTheme };
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __export = (target, all) => {
10
13
  for (var name in all)
11
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -28,6 +31,59 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
31
  ));
29
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
33
 
34
+ // src/constants/validation.ts
35
+ var validation_exports = {};
36
+ __export(validation_exports, {
37
+ DATE_REGEX: () => DATE_REGEX,
38
+ EMAIL_REGEX: () => EMAIL_REGEX,
39
+ PHONE_REGEX: () => PHONE_REGEX,
40
+ URL_REGEX: () => URL_REGEX,
41
+ isValidDate: () => isValidDate,
42
+ isValidEmail: () => isValidEmail,
43
+ isValidPhone: () => isValidPhone,
44
+ isValidUrl: () => isValidUrl
45
+ });
46
+ var EMAIL_REGEX, URL_REGEX, PHONE_REGEX, isValidEmail, isValidUrl, DATE_REGEX, isValidPhone, isValidDate;
47
+ var init_validation = __esm({
48
+ "src/constants/validation.ts"() {
49
+ "use strict";
50
+ 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])?)*$/;
51
+ URL_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
52
+ PHONE_REGEX = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
53
+ isValidEmail = (email) => {
54
+ return EMAIL_REGEX.test(email);
55
+ };
56
+ isValidUrl = (url) => {
57
+ return URL_REGEX.test(url);
58
+ };
59
+ DATE_REGEX = /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/;
60
+ isValidPhone = (phone) => {
61
+ return PHONE_REGEX.test(phone);
62
+ };
63
+ isValidDate = (date) => {
64
+ if (!DATE_REGEX.test(date)) {
65
+ return false;
66
+ }
67
+ const [month, day, year] = date.split("/").map(Number);
68
+ if (year < 1900 || year > 2100) {
69
+ return false;
70
+ }
71
+ if (month < 1 || month > 12) {
72
+ return false;
73
+ }
74
+ const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
75
+ const isLeapYear = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
76
+ if (isLeapYear && month === 2) {
77
+ daysInMonth[1] = 29;
78
+ }
79
+ if (day < 1 || day > daysInMonth[month - 1]) {
80
+ return false;
81
+ }
82
+ return true;
83
+ };
84
+ }
85
+ });
86
+
31
87
  // src/index.ts
32
88
  var index_exports = {};
33
89
  __export(index_exports, {
@@ -47,6 +103,7 @@ __export(index_exports, {
47
103
  CheckboxGroup: () => CheckboxGroup,
48
104
  CodeSnippet: () => CodeSnippet,
49
105
  Container: () => Container,
106
+ DATE_REGEX: () => DATE_REGEX,
50
107
  Dialog: () => Dialog,
51
108
  DialogContent: () => DialogContent,
52
109
  DialogDescription: () => DialogDescription,
@@ -55,6 +112,7 @@ __export(index_exports, {
55
112
  DialogTitle: () => DialogTitle,
56
113
  Divider: () => Divider,
57
114
  Drawer: () => Drawer,
115
+ EMAIL_REGEX: () => EMAIL_REGEX,
58
116
  EmptyState: () => EmptyState,
59
117
  Form: () => Form,
60
118
  FormControl: () => FormControl,
@@ -63,6 +121,7 @@ __export(index_exports, {
63
121
  Input: () => Input,
64
122
  NativeSelect: () => NativeSelect,
65
123
  Nav: () => Nav,
124
+ PHONE_REGEX: () => PHONE_REGEX,
66
125
  RadioGroup: () => RadioGroup,
67
126
  Rating: () => Rating,
68
127
  SectionLayout: () => SectionLayout,
@@ -73,7 +132,19 @@ __export(index_exports, {
73
132
  Switch: () => Switch,
74
133
  Textarea: () => Textarea,
75
134
  ThemeProvider: () => ThemeProvider,
135
+ URL_REGEX: () => URL_REGEX,
136
+ applyFormat: () => applyFormat,
76
137
  cn: () => cn,
138
+ formatCreditCard: () => formatCreditCard,
139
+ formatDate: () => formatDate,
140
+ formatDateTime: () => formatDateTime,
141
+ formatPhoneIntl: () => formatPhoneIntl,
142
+ formatPhoneUS: () => formatPhoneUS,
143
+ getRawValue: () => getRawValue,
144
+ isValidDate: () => isValidDate,
145
+ isValidEmail: () => isValidEmail,
146
+ isValidPhone: () => isValidPhone,
147
+ isValidUrl: () => isValidUrl,
77
148
  themes: () => themes_default,
78
149
  useForm: () => useForm,
79
150
  useFormContext: () => useFormContext,
@@ -234,8 +305,113 @@ Button.displayName = "Button";
234
305
  // src/ui/input.tsx
235
306
  var import_react5 = __toESM(require("react"));
236
307
 
308
+ // src/lib/formatting.ts
309
+ var formatPhoneUS = (value) => {
310
+ const digits = value.replace(/\D/g, "");
311
+ const limited = digits.slice(0, 10);
312
+ if (limited.length === 0) return "";
313
+ if (limited.length <= 3) return `(${limited}`;
314
+ if (limited.length <= 6)
315
+ return `(${limited.slice(0, 3)}) ${limited.slice(3)}`;
316
+ return `(${limited.slice(0, 3)}) ${limited.slice(3, 6)}-${limited.slice(6)}`;
317
+ };
318
+ var formatPhoneIntl = (value) => {
319
+ let cleaned = value.replace(/[^\d+]/g, "");
320
+ if (!cleaned.startsWith("+")) {
321
+ cleaned = "+" + cleaned;
322
+ }
323
+ cleaned = cleaned.slice(0, 16);
324
+ const digits = cleaned.slice(1);
325
+ if (digits.length === 0) return "+";
326
+ if (digits.length <= 1) return `+${digits}`;
327
+ if (digits.length <= 4) return `+${digits.slice(0, 1)} (${digits.slice(1)}`;
328
+ if (digits.length <= 7)
329
+ return `+${digits.slice(0, 1)} (${digits.slice(1, 4)}) ${digits.slice(4)}`;
330
+ return `+${digits.slice(0, 1)} (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
331
+ };
332
+ var formatCreditCard = (value) => {
333
+ const digits = value.replace(/\D/g, "");
334
+ const limited = digits.slice(0, 16);
335
+ return limited.replace(/(\d{4})/g, "$1 ").trim();
336
+ };
337
+ var formatDate = (value) => {
338
+ const digits = value.replace(/\D/g, "");
339
+ const limited = digits.slice(0, 8);
340
+ if (limited.length === 0) return "";
341
+ if (limited.length <= 2) return limited;
342
+ if (limited.length <= 4)
343
+ return `${limited.slice(0, 2)}/${limited.slice(2)}`;
344
+ return `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4)}`;
345
+ };
346
+ var formatDateTime = (value) => {
347
+ const digits = value.replace(/\D/g, "");
348
+ const limited = digits.slice(0, 12);
349
+ if (limited.length === 0) return "";
350
+ if (limited.length <= 2) return limited;
351
+ if (limited.length <= 4)
352
+ return `${limited.slice(0, 2)}/${limited.slice(2)}`;
353
+ if (limited.length <= 8)
354
+ return `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4)}`;
355
+ const datePart = `${limited.slice(0, 2)}/${limited.slice(2, 4)}/${limited.slice(4, 8)}`;
356
+ if (limited.length <= 10) return `${datePart} ${limited.slice(8)}`;
357
+ let hours = parseInt(limited.slice(8, 10));
358
+ const minutes = limited.slice(10, 12);
359
+ const ampm = hours >= 12 ? "PM" : "AM";
360
+ hours = hours % 12 || 12;
361
+ return `${datePart} ${hours}:${minutes} ${ampm}`;
362
+ };
363
+ var getRawValue = (value, format) => {
364
+ if (format === "date") {
365
+ const digits = value.replace(/\D/g, "");
366
+ if (digits.length === 8) {
367
+ const month = digits.slice(0, 2);
368
+ const day = digits.slice(2, 4);
369
+ const year = digits.slice(4, 8);
370
+ return `${year}-${month}-${day}`;
371
+ }
372
+ return digits;
373
+ }
374
+ if (format === "datetime") {
375
+ const digits = value.replace(/\D/g, "");
376
+ if (digits.length === 12) {
377
+ const month = digits.slice(0, 2);
378
+ const day = digits.slice(2, 4);
379
+ const year = digits.slice(4, 8);
380
+ const hours = digits.slice(8, 10);
381
+ const minutes = digits.slice(10, 12);
382
+ const date = new Date(
383
+ parseInt(year),
384
+ parseInt(month) - 1,
385
+ parseInt(day),
386
+ parseInt(hours),
387
+ parseInt(minutes)
388
+ );
389
+ return date.toISOString();
390
+ }
391
+ return digits;
392
+ }
393
+ return value.replace(/\D/g, "");
394
+ };
395
+ var applyFormat = (value, format) => {
396
+ switch (format) {
397
+ case "phone":
398
+ return formatPhoneUS(value);
399
+ case "phone-intl":
400
+ return formatPhoneIntl(value);
401
+ case "credit-card":
402
+ return formatCreditCard(value);
403
+ case "date":
404
+ return formatDate(value);
405
+ case "datetime":
406
+ return formatDateTime(value);
407
+ default:
408
+ return value;
409
+ }
410
+ };
411
+
237
412
  // src/ui/hooks/useFormField.ts
238
413
  var import_react4 = require("react");
414
+ init_validation();
239
415
 
240
416
  // src/ui/form.tsx
241
417
  var import_react2 = require("react");
@@ -807,7 +983,7 @@ function useFormField2(options) {
807
983
  return errorMessages?.required || "This field is required";
808
984
  }
809
985
  if (value) {
810
- if (type === "email" && !value.includes("@")) {
986
+ if (type === "email" && !EMAIL_REGEX.test(value)) {
811
987
  return errorMessages?.email || "Please enter a valid email address";
812
988
  }
813
989
  if (type === "url") {
@@ -864,7 +1040,7 @@ function useFormField2(options) {
864
1040
  return errorMessages?.required || "This field is required";
865
1041
  }
866
1042
  if (value) {
867
- if (type === "email" && !value.includes("@")) {
1043
+ if (type === "email" && !EMAIL_REGEX.test(value)) {
868
1044
  return errorMessages?.email || "Please enter a valid email address";
869
1045
  }
870
1046
  if (type === "url") {
@@ -981,12 +1157,31 @@ var Input = import_react5.default.forwardRef(
981
1157
  validate,
982
1158
  onValidationError,
983
1159
  pattern,
1160
+ format,
984
1161
  errorMessages,
985
1162
  ...props
986
1163
  }, ref) => {
1164
+ const [internalValue, setInternalValue] = import_react5.default.useState("");
1165
+ const dateValidate = import_react5.default.useCallback(
1166
+ async (value) => {
1167
+ if (validate) {
1168
+ const customError = await validate(value);
1169
+ if (customError) return customError;
1170
+ }
1171
+ if (format === "date" && value && value.length === 8) {
1172
+ const { isValidDate: isValidDate2 } = await Promise.resolve().then(() => (init_validation(), validation_exports));
1173
+ const formatted = `${value.slice(0, 2)}/${value.slice(2, 4)}/${value.slice(4, 8)}`;
1174
+ if (!isValidDate2(formatted)) {
1175
+ return errorMessages?.date || "Please enter a valid date";
1176
+ }
1177
+ }
1178
+ return void 0;
1179
+ },
1180
+ [validate, format, errorMessages]
1181
+ );
987
1182
  const {
988
1183
  fieldId,
989
- value: inputValue,
1184
+ value: hookValue,
990
1185
  error: inputError,
991
1186
  isDisabled,
992
1187
  isRequired,
@@ -1008,19 +1203,71 @@ var Input = import_react5.default.forwardRef(
1008
1203
  min: props.min,
1009
1204
  max: props.max,
1010
1205
  pattern,
1011
- validate,
1206
+ validate: format === "date" ? dateValidate : validate,
1012
1207
  onValidationError,
1013
1208
  errorMessages,
1014
1209
  idPrefix: "input"
1015
1210
  });
1211
+ const inputValue = hookValue !== void 0 ? hookValue : internalValue;
1212
+ const [cursorPosition, setCursorPosition] = import_react5.default.useState(null);
1016
1213
  const handleChange = (e) => {
1017
- hookHandleChange(e.target.value);
1214
+ const input = e.target;
1215
+ const newValue = input.value;
1216
+ const cursorPos = input.selectionStart || 0;
1217
+ if (format && typeof format === "string") {
1218
+ const cleaned = newValue.replace(/\D/g, "");
1219
+ const formatted = applyFormat(cleaned, format);
1220
+ if (hookValue !== void 0) {
1221
+ hookHandleChange(cleaned);
1222
+ } else {
1223
+ setInternalValue(cleaned);
1224
+ }
1225
+ let formattedPos = 0;
1226
+ let digitCount = 0;
1227
+ const targetDigits = cleaned.slice(
1228
+ 0,
1229
+ Math.min(cleaned.length, cursorPos)
1230
+ );
1231
+ for (let i = 0; i < formatted.length && digitCount < targetDigits.length; i++) {
1232
+ if (/\d/.test(formatted[i])) {
1233
+ digitCount++;
1234
+ }
1235
+ formattedPos = i + 1;
1236
+ }
1237
+ setCursorPosition(formattedPos);
1238
+ } else {
1239
+ if (hookValue !== void 0) {
1240
+ hookHandleChange(newValue);
1241
+ } else {
1242
+ setInternalValue(newValue);
1243
+ }
1244
+ }
1018
1245
  onChange?.(e);
1019
1246
  };
1020
1247
  const handleBlur = (e) => {
1021
- hookHandleBlur(e.target.value);
1248
+ const value = e.target.value;
1249
+ const blurValue = format && typeof format === "string" ? value.replace(/\D/g, "") : value;
1250
+ hookHandleBlur(blurValue);
1022
1251
  onBlur?.(e);
1023
1252
  };
1253
+ const displayValue = import_react5.default.useMemo(() => {
1254
+ if (format && inputValue) {
1255
+ if (typeof format === "function") {
1256
+ return format(inputValue);
1257
+ }
1258
+ return applyFormat(inputValue, format);
1259
+ }
1260
+ return inputValue;
1261
+ }, [format, inputValue]);
1262
+ import_react5.default.useEffect(() => {
1263
+ if (cursorPosition !== null && internalRef.current) {
1264
+ internalRef.current.setSelectionRange(
1265
+ cursorPosition,
1266
+ cursorPosition
1267
+ );
1268
+ setCursorPosition(null);
1269
+ }
1270
+ }, [cursorPosition, displayValue]);
1024
1271
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1025
1272
  "div",
1026
1273
  {
@@ -1053,7 +1300,7 @@ var Input = import_react5.default.forwardRef(
1053
1300
  },
1054
1301
  type,
1055
1302
  id: fieldId,
1056
- value: inputValue,
1303
+ value: displayValue,
1057
1304
  onChange: handleChange,
1058
1305
  onBlur: handleBlur,
1059
1306
  disabled: isDisabled,
@@ -5247,6 +5494,9 @@ function useTheme() {
5247
5494
  }
5248
5495
  return context;
5249
5496
  }
5497
+
5498
+ // src/index.ts
5499
+ init_validation();
5250
5500
  // Annotate the CommonJS export names for ESM import in node:
5251
5501
  0 && (module.exports = {
5252
5502
  Alert,
@@ -5265,6 +5515,7 @@ function useTheme() {
5265
5515
  CheckboxGroup,
5266
5516
  CodeSnippet,
5267
5517
  Container,
5518
+ DATE_REGEX,
5268
5519
  Dialog,
5269
5520
  DialogContent,
5270
5521
  DialogDescription,
@@ -5273,6 +5524,7 @@ function useTheme() {
5273
5524
  DialogTitle,
5274
5525
  Divider,
5275
5526
  Drawer,
5527
+ EMAIL_REGEX,
5276
5528
  EmptyState,
5277
5529
  Form,
5278
5530
  FormControl,
@@ -5281,6 +5533,7 @@ function useTheme() {
5281
5533
  Input,
5282
5534
  NativeSelect,
5283
5535
  Nav,
5536
+ PHONE_REGEX,
5284
5537
  RadioGroup,
5285
5538
  Rating,
5286
5539
  SectionLayout,
@@ -5291,7 +5544,19 @@ function useTheme() {
5291
5544
  Switch,
5292
5545
  Textarea,
5293
5546
  ThemeProvider,
5547
+ URL_REGEX,
5548
+ applyFormat,
5294
5549
  cn,
5550
+ formatCreditCard,
5551
+ formatDate,
5552
+ formatDateTime,
5553
+ formatPhoneIntl,
5554
+ formatPhoneUS,
5555
+ getRawValue,
5556
+ isValidDate,
5557
+ isValidEmail,
5558
+ isValidPhone,
5559
+ isValidUrl,
5295
5560
  themes,
5296
5561
  useForm,
5297
5562
  useFormContext,