@samline/formatter 1.0.0 → 1.1.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.
@@ -111,7 +111,93 @@ declare const format: (value: unknown, formatType: FormatType, options?: FormatO
111
111
  */
112
112
  declare const formatPhone: (value: string, country?: string, delimiter?: string) => string;
113
113
 
114
- declare const regex: {
114
+ /**
115
+ * # Regex Module
116
+ *
117
+ * Validation patterns exposed as public API for form consumers that pair
118
+ * formatting with validation. Each entry bundles the regex with a ready-to-use
119
+ * error message so consumers do not have to keep them in sync.
120
+ *
121
+ * ## Usage
122
+ *
123
+ * **Static (backward compatible):**
124
+ * ```ts
125
+ * regex.phone.pattern.test('5512345678') // true
126
+ * regex.email.errorMessage // 'Please enter a valid email address.'
127
+ * ```
128
+ *
129
+ * **Parametric (dynamic):**
130
+ * ```ts
131
+ * regex.digits(10).pattern.test('1234567890') // true
132
+ * regex.digits(7).pattern.test('1234567') // true
133
+ * regex.phone({ length: 10 }).pattern.test('1234567890')
134
+ * regex.phone({ length: 7 }).pattern.test('1234567')
135
+ * ```
136
+ *
137
+ * **Custom regex:**
138
+ * ```ts
139
+ * regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO')
140
+ * ```
141
+ *
142
+ * ## Available Patterns
143
+ *
144
+ * | Key | Static | Parametric | Description |
145
+ * | --- | --- | --- | --- |
146
+ * | `phone` | ✅ | ✅ `({ length })` | Phone numbers |
147
+ * | `email` | ✅ | — | Email addresses |
148
+ * | `rfc` | ✅ | — | Mexican RFC |
149
+ * | `curp` | ✅ | — | Mexican CURP |
150
+ * | `cp` | ✅ | — | Mexican postal code (5 digits) |
151
+ * | `numeral` | ✅ | — | Numbers with separators |
152
+ * | `onlyNumbers` | ✅ | ✅ `({ length })` | Digits only |
153
+ * | `digits` | — | ✅ `({ length, min, max })` | Variable digit count |
154
+ * | `creditCard` | ✅ | ✅ `({ min, max })` | Card numbers |
155
+ * | `expirationDate` | ✅ | — | MM/YY format |
156
+ * | `cardCvc` | ✅ | — | 3-4 digit CVC |
157
+ * | `onlyLetters` | ✅ | — | Letters only |
158
+ * | `onlyAlphanumeric` | ✅ | — | Letters and numbers |
159
+ * | `url` | ✅ | ✅ `({ protocol })` | URLs |
160
+ * | `ipv4` | ✅ | — | IPv4 addresses |
161
+ * | `ipv6` | ✅ | — | IPv6 addresses |
162
+ * | `uuid` | ✅ | — | UUID v4 |
163
+ * | `hexColor` | ✅ | — | Hex color codes |
164
+ * | `hashtag` | ✅ | — | Social media hashtags |
165
+ * | `mention` | ✅ | — | Social media mentions |
166
+ * | `password` | — | ✅ `({ min, max, rules })` | Password strength |
167
+ * | `custom` | — | ✅ `({ pattern, errorMessage })` | User-defined regex |
168
+ */
169
+ interface RegexEntry {
170
+ pattern: RegExp;
171
+ errorMessage: string;
172
+ }
173
+ interface PhoneParams {
174
+ length?: number;
175
+ }
176
+ interface DigitsParams {
177
+ length?: number;
178
+ min?: number;
179
+ max?: number;
180
+ }
181
+ interface CreditCardParams {
182
+ min?: number;
183
+ max?: number;
184
+ }
185
+ interface UrlParams {
186
+ protocol?: 'http' | 'https' | 'ftp' | 'all';
187
+ }
188
+ interface PasswordParams {
189
+ min?: number;
190
+ max?: number;
191
+ uppercase?: boolean;
192
+ lowercase?: boolean;
193
+ numbers?: boolean;
194
+ special?: boolean;
195
+ }
196
+ interface CustomParams {
197
+ pattern: RegExp;
198
+ errorMessage: string;
199
+ }
200
+ declare const _regex: {
115
201
  readonly phone: {
116
202
  readonly pattern: RegExp;
117
203
  readonly errorMessage: "Please enter a valid 10-digit phone number.";
@@ -124,6 +210,14 @@ declare const regex: {
124
210
  readonly pattern: RegExp;
125
211
  readonly errorMessage: "Please enter a valid RFC.";
126
212
  };
213
+ readonly curp: {
214
+ readonly pattern: RegExp;
215
+ readonly errorMessage: "Please enter a valid CURP.";
216
+ };
217
+ readonly cp: {
218
+ readonly pattern: RegExp;
219
+ readonly errorMessage: "Please enter a valid 5-digit postal code.";
220
+ };
127
221
  readonly numeral: {
128
222
  readonly pattern: RegExp;
129
223
  readonly errorMessage: "Please enter a valid number.";
@@ -134,15 +228,174 @@ declare const regex: {
134
228
  };
135
229
  readonly creditCard: {
136
230
  readonly pattern: RegExp;
137
- readonly errorMessage: "Please enter a valid card number.";
231
+ readonly errorMessage: "Please enter a valid card number (15-16 digits).";
232
+ };
233
+ readonly expirationDate: {
234
+ readonly pattern: RegExp;
235
+ readonly errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY).";
236
+ };
237
+ readonly cardCvc: {
238
+ readonly pattern: RegExp;
239
+ readonly errorMessage: "Please enter a valid CVC (3-4 digits).";
240
+ };
241
+ readonly onlyLetters: {
242
+ readonly pattern: RegExp;
243
+ readonly errorMessage: "Please enter only letters.";
244
+ };
245
+ readonly onlyAlphanumeric: {
246
+ readonly pattern: RegExp;
247
+ readonly errorMessage: "Please enter only letters and numbers.";
248
+ };
249
+ readonly url: {
250
+ readonly pattern: RegExp;
251
+ readonly errorMessage: "Please enter a valid URL.";
252
+ };
253
+ readonly ipv4: {
254
+ readonly pattern: RegExp;
255
+ readonly errorMessage: "Please enter a valid IPv4 address.";
256
+ };
257
+ readonly ipv6: {
258
+ readonly pattern: RegExp;
259
+ readonly errorMessage: "Please enter a valid IPv6 address.";
260
+ };
261
+ readonly uuid: {
262
+ readonly pattern: RegExp;
263
+ readonly errorMessage: "Please enter a valid UUID.";
264
+ };
265
+ readonly hexColor: {
266
+ readonly pattern: RegExp;
267
+ readonly errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF).";
268
+ };
269
+ readonly hashtag: {
270
+ readonly pattern: RegExp;
271
+ readonly errorMessage: "Please enter a valid hashtag (e.g., #example).";
272
+ };
273
+ readonly mention: {
274
+ readonly pattern: RegExp;
275
+ readonly errorMessage: "Please enter a valid mention (e.g., @username).";
276
+ };
277
+ readonly postalCode: {
278
+ readonly pattern: RegExp;
279
+ readonly errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234).";
280
+ };
281
+ readonly time24: {
282
+ readonly pattern: RegExp;
283
+ readonly errorMessage: "Please enter a valid 24-hour time (HH:MM).";
284
+ };
285
+ readonly date: {
286
+ readonly pattern: RegExp;
287
+ readonly errorMessage: "Please enter a valid date (YYYY-MM-DD).";
288
+ };
289
+ readonly slug: {
290
+ readonly pattern: RegExp;
291
+ readonly errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces).";
292
+ };
293
+ readonly username: {
294
+ readonly pattern: RegExp;
295
+ readonly errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -).";
296
+ };
297
+ readonly macAddress: {
298
+ readonly pattern: RegExp;
299
+ readonly errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7).";
300
+ };
301
+ readonly semver: {
302
+ readonly pattern: RegExp;
303
+ readonly errorMessage: "Please enter a valid semantic version (e.g., 1.2.3).";
304
+ };
305
+ readonly base64: {
306
+ readonly pattern: RegExp;
307
+ readonly errorMessage: "Please enter a valid Base64 encoded string.";
308
+ };
309
+ };
310
+ /**
311
+ * Digits with configurable length.
312
+ * @example
313
+ * regex.digits(10).pattern.test('1234567890') // true
314
+ * regex.digits({ length: 7 }).pattern.test('1234567') // true
315
+ * regex.digits({ min: 3, max: 10 }).pattern.test('12345') // true
316
+ */
317
+ declare function digits(params?: number | DigitsParams): RegexEntry;
318
+ /**
319
+ * Phone with configurable digit count.
320
+ *
321
+ * Also available as static entry: regex.phone.pattern (10 digits)
322
+ * @example
323
+ * regex.phone().pattern.test('5512345678') // true (10 digits)
324
+ * regex.phone({ length: 7 }).pattern.test('1234567') // true (7 digits)
325
+ */
326
+ declare function _phoneFn(params?: PhoneParams): RegexEntry;
327
+ /**
328
+ * Credit card with configurable digit range.
329
+ *
330
+ * Also available as static entry: regex.creditCard.pattern (15-16 digits)
331
+ * @example
332
+ * regex.creditCard().pattern.test('4111111111111111') // true (15-16)
333
+ * regex.creditCard({ min: 13, max: 19 }).pattern.test('1234567890123') // true
334
+ */
335
+ declare function _creditCardFn(params?: CreditCardParams): RegexEntry;
336
+ /**
337
+ * URL with configurable protocol.
338
+ *
339
+ * Also available as static entry: regex.url.pattern (any protocol)
340
+ * @example
341
+ * regex.url().pattern.test('https://example.com') // true
342
+ * regex.url({ protocol: 'https' }).pattern.test('https://example.com') // true
343
+ * regex.url({ protocol: 'https' }).pattern.test('ftp://example.com') // false
344
+ */
345
+ declare function _urlFn(params?: UrlParams): RegexEntry;
346
+ /**
347
+ * Password with configurable strength rules.
348
+ * @example
349
+ * regex.password().pattern.test('Passw0rd!') // true (default: 8+ chars, upper, lower, number)
350
+ * regex.password({ min: 12, special: true }).pattern.test('MyP@ssw0rd!') // true
351
+ */
352
+ declare function _passwordFn(params?: PasswordParams): RegexEntry;
353
+ /**
354
+ * Custom regex provided by the user.
355
+ * @example
356
+ * regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO') // true
357
+ * regex.custom({ pattern: /^\d+$/, errorMessage: 'Numbers only' }).pattern.test('123') // true
358
+ */
359
+ declare function _customFn(pattern: RegExp, errorMessage?: string): RegexEntry;
360
+ declare function _customFn(params: CustomParams): RegexEntry;
361
+ declare const regex: {
362
+ readonly digits: typeof digits & RegexEntry;
363
+ readonly phone: typeof _phoneFn & RegexEntry;
364
+ readonly creditCard: typeof _creditCardFn & RegexEntry;
365
+ readonly url: typeof _urlFn & RegexEntry;
366
+ readonly password: typeof _passwordFn & RegexEntry;
367
+ readonly custom: typeof _customFn & RegexEntry;
368
+ readonly email: {
369
+ readonly pattern: RegExp;
370
+ readonly errorMessage: "Please enter a valid email address.";
371
+ };
372
+ readonly rfc: {
373
+ readonly pattern: RegExp;
374
+ readonly errorMessage: "Please enter a valid RFC.";
375
+ };
376
+ readonly curp: {
377
+ readonly pattern: RegExp;
378
+ readonly errorMessage: "Please enter a valid CURP.";
379
+ };
380
+ readonly cp: {
381
+ readonly pattern: RegExp;
382
+ readonly errorMessage: "Please enter a valid 5-digit postal code.";
383
+ };
384
+ readonly numeral: {
385
+ readonly pattern: RegExp;
386
+ readonly errorMessage: "Please enter a valid number.";
387
+ };
388
+ readonly onlyNumbers: {
389
+ readonly pattern: RegExp;
390
+ readonly errorMessage: "Please enter only numbers.";
138
391
  };
139
392
  readonly expirationDate: {
140
393
  readonly pattern: RegExp;
141
- readonly errorMessage: "Please enter a valid expiration date.";
394
+ readonly errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY).";
142
395
  };
143
396
  readonly cardCvc: {
144
397
  readonly pattern: RegExp;
145
- readonly errorMessage: "Please enter a valid CVC.";
398
+ readonly errorMessage: "Please enter a valid CVC (3-4 digits).";
146
399
  };
147
400
  readonly onlyLetters: {
148
401
  readonly pattern: RegExp;
@@ -152,7 +405,64 @@ declare const regex: {
152
405
  readonly pattern: RegExp;
153
406
  readonly errorMessage: "Please enter only letters and numbers.";
154
407
  };
408
+ readonly ipv4: {
409
+ readonly pattern: RegExp;
410
+ readonly errorMessage: "Please enter a valid IPv4 address.";
411
+ };
412
+ readonly ipv6: {
413
+ readonly pattern: RegExp;
414
+ readonly errorMessage: "Please enter a valid IPv6 address.";
415
+ };
416
+ readonly uuid: {
417
+ readonly pattern: RegExp;
418
+ readonly errorMessage: "Please enter a valid UUID.";
419
+ };
420
+ readonly hexColor: {
421
+ readonly pattern: RegExp;
422
+ readonly errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF).";
423
+ };
424
+ readonly hashtag: {
425
+ readonly pattern: RegExp;
426
+ readonly errorMessage: "Please enter a valid hashtag (e.g., #example).";
427
+ };
428
+ readonly mention: {
429
+ readonly pattern: RegExp;
430
+ readonly errorMessage: "Please enter a valid mention (e.g., @username).";
431
+ };
432
+ readonly postalCode: {
433
+ readonly pattern: RegExp;
434
+ readonly errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234).";
435
+ };
436
+ readonly time24: {
437
+ readonly pattern: RegExp;
438
+ readonly errorMessage: "Please enter a valid 24-hour time (HH:MM).";
439
+ };
440
+ readonly date: {
441
+ readonly pattern: RegExp;
442
+ readonly errorMessage: "Please enter a valid date (YYYY-MM-DD).";
443
+ };
444
+ readonly slug: {
445
+ readonly pattern: RegExp;
446
+ readonly errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces).";
447
+ };
448
+ readonly username: {
449
+ readonly pattern: RegExp;
450
+ readonly errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -).";
451
+ };
452
+ readonly macAddress: {
453
+ readonly pattern: RegExp;
454
+ readonly errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7).";
455
+ };
456
+ readonly semver: {
457
+ readonly pattern: RegExp;
458
+ readonly errorMessage: "Please enter a valid semantic version (e.g., 1.2.3).";
459
+ };
460
+ readonly base64: {
461
+ readonly pattern: RegExp;
462
+ readonly errorMessage: "Please enter a valid Base64 encoded string.";
463
+ };
155
464
  };
156
- type RegexKey = keyof typeof regex;
465
+ type RegexKey = keyof typeof _regex;
466
+ type Regex = typeof regex;
157
467
 
158
- export { FORMAT_TYPES, type FormatOptions, type FormatType, type FormatterResult, type RegexKey, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };
468
+ export { FORMAT_TYPES, type FormatOptions, type FormatType, type FormatterResult, type Regex, type RegexEntry, type RegexKey, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };
@@ -4,9 +4,9 @@ import { AsYouType } from 'libphonenumber-js';
4
4
  // src/core/format.ts
5
5
  var formatPhone = (value, country = "MX", delimiter = " ") => {
6
6
  if (!value) return "";
7
- const digits = value.replace(/[^\d+]/g, "");
7
+ const digits2 = value.replace(/[^\d+]/g, "");
8
8
  const formatter = new AsYouType(country);
9
- const formatted = formatter.input(digits);
9
+ const formatted = formatter.input(digits2);
10
10
  if (delimiter !== " ") {
11
11
  return formatted.replace(/ /g, delimiter);
12
12
  }
@@ -41,12 +41,12 @@ var normalizeDateSegment = (segment, unit) => {
41
41
  }
42
42
  };
43
43
  var getDateSegments = (value, pattern) => {
44
- const digits = value.replace(/[^\d]/g, "");
44
+ const digits2 = value.replace(/[^\d]/g, "");
45
45
  const segments = {};
46
46
  let start = 0;
47
47
  for (const unit of pattern) {
48
48
  const end = start + getDateUnitLength(unit);
49
- const segment = digits.slice(start, end);
49
+ const segment = digits2.slice(start, end);
50
50
  if (segment) {
51
51
  segments[getDateSegmentKey(unit)] = segment;
52
52
  }
@@ -68,12 +68,12 @@ var getTimeSegmentKey = (unit) => {
68
68
  }
69
69
  };
70
70
  var getTimeSegments = (value, pattern) => {
71
- const digits = value.replace(/[^\d]/g, "");
71
+ const digits2 = value.replace(/[^\d]/g, "");
72
72
  const segments = {};
73
73
  let start = 0;
74
74
  for (const unit of pattern) {
75
75
  const end = start + 2;
76
- const segment = digits.slice(start, end);
76
+ const segment = digits2.slice(start, end);
77
77
  if (segment) {
78
78
  segments[getTimeSegmentKey(unit)] = segment;
79
79
  }
@@ -239,21 +239,81 @@ var format = (value, formatType, options = {}) => {
239
239
  };
240
240
 
241
241
  // src/core/regex.ts
242
- var regex = {
242
+ function createDigits(min, max, errorMsg) {
243
+ return {
244
+ pattern: new RegExp(`^\\d{${min},${max}}$`),
245
+ errorMessage: errorMsg
246
+ };
247
+ }
248
+ function createPhone(length) {
249
+ return {
250
+ pattern: new RegExp(`^(?:\\D*\\d){${length}}\\D*$`),
251
+ errorMessage: `Please enter a valid ${length}-digit phone number.`
252
+ };
253
+ }
254
+ function createCreditCard(min, max) {
255
+ return {
256
+ pattern: new RegExp(`^(?:\\D*\\d){${min},${max}}\\D*$`),
257
+ errorMessage: `Please enter a valid card number (${min}-${max} digits).`
258
+ };
259
+ }
260
+ function createUrl(requireProtocol) {
261
+ const protocol = requireProtocol === "all" ? "https?" : requireProtocol;
262
+ return {
263
+ pattern: new RegExp(`^${protocol}://[^\\s]+$`),
264
+ errorMessage: `Please enter a valid URL${requireProtocol !== "all" ? ` (${requireProtocol}://...)` : ""}.`
265
+ };
266
+ }
267
+ function createPassword(params) {
268
+ const {
269
+ min = 8,
270
+ max = 128,
271
+ uppercase = true,
272
+ lowercase = true,
273
+ numbers = true,
274
+ special = false
275
+ } = params;
276
+ let chars = "";
277
+ if (uppercase) chars += "A-Z";
278
+ if (lowercase) chars += "a-z";
279
+ if (numbers) chars += "0-9";
280
+ if (special) chars += `!@#$%^&*()_+\\-=\\[\\]{}|;:'",.<>?/`;
281
+ const ruleParts = [];
282
+ if (uppercase) ruleParts.push("uppercase letter");
283
+ if (lowercase) ruleParts.push("lowercase letter");
284
+ if (numbers) ruleParts.push("number");
285
+ if (special) ruleParts.push("special character");
286
+ const rulesText = ruleParts.length > 2 ? ruleParts.slice(0, -1).join(", ") + " and " + ruleParts.slice(-1) : ruleParts.join(" and ");
287
+ return {
288
+ pattern: new RegExp(`^[${chars}]{${min},${max}}$`),
289
+ errorMessage: `Password must be ${min}-${max} characters with at least one ${rulesText}.`
290
+ };
291
+ }
292
+ var _regex = {
243
293
  phone: {
244
- // 10 digit phone numbers, allowing for optional country code and delimiters
245
294
  pattern: /^(?:\D*\d){10}\D*$/,
246
295
  errorMessage: "Please enter a valid 10-digit phone number."
247
296
  },
248
297
  email: {
298
+ // Simple but effective email validation
249
299
  pattern: /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/,
250
300
  errorMessage: "Please enter a valid email address."
251
301
  },
252
302
  rfc: {
253
- // Mexican RFC format (simplified)
303
+ // Mexican RFC ( Personas Morales y Físicas )
254
304
  pattern: /^([A-ZÑ&]{3,4})\d{6}([A-Z0-9]{0,3})$/i,
255
305
  errorMessage: "Please enter a valid RFC."
256
306
  },
307
+ curp: {
308
+ // Mexican CURP (18 characters)
309
+ pattern: /^[A-Z]{4}\d{6}[A-Z]{6}[0-9A-Z]\d$/i,
310
+ errorMessage: "Please enter a valid CURP."
311
+ },
312
+ cp: {
313
+ // Mexican postal code (5 digits)
314
+ pattern: /^\d{5}$/,
315
+ errorMessage: "Please enter a valid 5-digit postal code."
316
+ },
257
317
  numeral: {
258
318
  // Numbers with optional thousand separators and decimal points
259
319
  pattern: /\d{1,3}(,\d{3})*(\.\d+)?/,
@@ -266,17 +326,17 @@ var regex = {
266
326
  creditCard: {
267
327
  // 15 or 16 digits, allowing spaces or delimiters
268
328
  pattern: /^(?:\D*\d){15,16}\D*$/,
269
- errorMessage: "Please enter a valid card number."
329
+ errorMessage: "Please enter a valid card number (15-16 digits)."
270
330
  },
271
331
  expirationDate: {
272
- // MM/YY format
273
- pattern: /^(0[1-9]|1[0-2])\/\d{2}$/,
274
- errorMessage: "Please enter a valid expiration date."
332
+ // MM/YY or MM/YYYY format
333
+ pattern: /^(0[1-9]|1[0-2])\/(\d{2}|\d{4})$/,
334
+ errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY)."
275
335
  },
276
336
  cardCvc: {
277
337
  // 3 or 4 digit card security codes
278
338
  pattern: /^\d{3,4}$/,
279
- errorMessage: "Please enter a valid CVC."
339
+ errorMessage: "Please enter a valid CVC (3-4 digits)."
280
340
  },
281
341
  onlyLetters: {
282
342
  // Letters only (including accented characters and spaces)
@@ -287,7 +347,142 @@ var regex = {
287
347
  // Letters and numbers (including accented characters and spaces)
288
348
  pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ0-9\s]+$/,
289
349
  errorMessage: "Please enter only letters and numbers."
350
+ },
351
+ url: {
352
+ // Accepts http, https, ftp
353
+ pattern: /^(?:https?|ftp):\/\/[^\s]+$/,
354
+ errorMessage: "Please enter a valid URL."
355
+ },
356
+ ipv4: {
357
+ // IPv4 addresses (0-255 per octet)
358
+ pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
359
+ errorMessage: "Please enter a valid IPv4 address."
360
+ },
361
+ ipv6: {
362
+ // IPv6 addresses (simplified)
363
+ pattern: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/,
364
+ errorMessage: "Please enter a valid IPv6 address."
365
+ },
366
+ uuid: {
367
+ // UUID v4
368
+ pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
369
+ errorMessage: "Please enter a valid UUID."
370
+ },
371
+ hexColor: {
372
+ // Hex color codes (#RGB or #RRGGBB)
373
+ pattern: /^#(?:[0-9a-fA-F]{3}){1,2}$/,
374
+ errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF)."
375
+ },
376
+ hashtag: {
377
+ // Social media hashtags
378
+ pattern: /^#[a-zA-Z_][a-zA-Z0-9_]*$/,
379
+ errorMessage: "Please enter a valid hashtag (e.g., #example)."
380
+ },
381
+ mention: {
382
+ // Social media mentions
383
+ pattern: /^@[a-zA-Z_][a-zA-Z0-9_]*$/,
384
+ errorMessage: "Please enter a valid mention (e.g., @username)."
385
+ },
386
+ postalCode: {
387
+ // Generic 5-digit postal code (US-style ZIP / MX CP)
388
+ pattern: /^\d{5}(?:-\d{4})?$/,
389
+ errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234)."
390
+ },
391
+ time24: {
392
+ // 24-hour time HH:MM
393
+ pattern: /^([01]\d|2[0-3]):([0-5]\d)$/,
394
+ errorMessage: "Please enter a valid 24-hour time (HH:MM)."
395
+ },
396
+ date: {
397
+ // ISO-like date YYYY-MM-DD (loose)
398
+ pattern: /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,
399
+ errorMessage: "Please enter a valid date (YYYY-MM-DD)."
400
+ },
401
+ slug: {
402
+ // URL slug (lowercase, hyphens, no spaces)
403
+ pattern: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
404
+ errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces)."
405
+ },
406
+ username: {
407
+ // Username: 3-20 chars, alphanumeric, underscore, hyphen
408
+ pattern: /^[a-zA-Z0-9_-]{3,20}$/,
409
+ errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -)."
410
+ },
411
+ macAddress: {
412
+ // MAC address (colon or hyphen separated)
413
+ pattern: /^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/,
414
+ errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7)."
415
+ },
416
+ semver: {
417
+ // Semantic version (X.Y.Z with optional -prerelease)
418
+ pattern: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[a-zA-Z0-9.-]+)?$/,
419
+ errorMessage: "Please enter a valid semantic version (e.g., 1.2.3)."
420
+ },
421
+ base64: {
422
+ // Base64 encoded string
423
+ pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,
424
+ errorMessage: "Please enter a valid Base64 encoded string."
425
+ }
426
+ };
427
+ function digits(params) {
428
+ if (typeof params === "number") {
429
+ return createDigits(params, params, `Please enter exactly ${params} digits.`);
290
430
  }
431
+ const { length, min = 1, max = 20 } = params ?? {};
432
+ const actualMin = length ?? min;
433
+ const actualMax = length ?? max;
434
+ if (actualMin === actualMax) {
435
+ return createDigits(actualMin, actualMax, `Please enter exactly ${actualMin} digits.`);
436
+ }
437
+ return createDigits(actualMin, actualMax, `Please enter ${actualMin}-${actualMax} digits.`);
438
+ }
439
+ function _phoneFn(params) {
440
+ const length = params?.length ?? 10;
441
+ return createPhone(length);
442
+ }
443
+ function _creditCardFn(params) {
444
+ const min = params?.min ?? 15;
445
+ const max = params?.max ?? 16;
446
+ return createCreditCard(min, max);
447
+ }
448
+ function _urlFn(params) {
449
+ const protocol = params?.protocol ?? "all";
450
+ return createUrl(protocol);
451
+ }
452
+ function _passwordFn(params) {
453
+ return createPassword(params ?? {});
454
+ }
455
+ function _customFn(arg1, arg2) {
456
+ if (arg1 instanceof RegExp) {
457
+ return { pattern: arg1, errorMessage: arg2 ?? "Invalid value." };
458
+ }
459
+ return { pattern: arg1.pattern, errorMessage: arg1.errorMessage };
460
+ }
461
+ var phoneFn = _phoneFn;
462
+ phoneFn.pattern = _regex.phone.pattern;
463
+ phoneFn.errorMessage = _regex.phone.errorMessage;
464
+ var creditCardFn = _creditCardFn;
465
+ creditCardFn.pattern = _regex.creditCard.pattern;
466
+ creditCardFn.errorMessage = _regex.creditCard.errorMessage;
467
+ var urlFn = _urlFn;
468
+ urlFn.pattern = _regex.url.pattern;
469
+ urlFn.errorMessage = _regex.url.errorMessage;
470
+ var digitsFn = digits;
471
+ digitsFn.errorMessage = "Please enter a valid number.";
472
+ var passwordFn = _passwordFn;
473
+ passwordFn.errorMessage = "Please enter a valid password.";
474
+ var customFn = _customFn;
475
+ customFn.errorMessage = "Please enter a valid value.";
476
+ var regex = {
477
+ // Static entries (backward compatible - spread first)
478
+ ..._regex,
479
+ // Parametric functions
480
+ digits: digitsFn,
481
+ phone: phoneFn,
482
+ creditCard: creditCardFn,
483
+ url: urlFn,
484
+ password: passwordFn,
485
+ custom: customFn
291
486
  };
292
487
 
293
488
  export { FORMAT_TYPES, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };