@trackunit/react-form-components 1.22.10 → 1.22.12-alpha-71bd6bc448a.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/index.cjs.js CHANGED
@@ -531,19 +531,65 @@ const normalizeDisplayCompare = (value) => value
531
531
  .replace(/[\u202f\u00a0]/g, " ")
532
532
  .replace(/\s+/g, " ")
533
533
  .trim();
534
+ const COMPACT_DATE_REGEX = /^\d{8}$/;
535
+ const localePartOrderCache = new Map();
536
+ /**
537
+ * Returns the date-part display order (month/day/year) for the given locale by inspecting
538
+ * `Intl.DateTimeFormat.formatToParts`. Results are cached after the first call per locale.
539
+ * Falls back to MDY (English/US convention) on any error.
540
+ */
541
+ function getLocaleDatePartOrder(locale) {
542
+ const cached = localePartOrderCache.get(locale);
543
+ if (cached !== undefined)
544
+ return cached;
545
+ try {
546
+ const parts = new Intl.DateTimeFormat(locale, { year: "numeric", month: "2-digit", day: "2-digit" })
547
+ .formatToParts(new Date(2000, 0, 15))
548
+ .filter(p => p.type === "month" || p.type === "day" || p.type === "year")
549
+ .map(p => p.type.charAt(0).toUpperCase())
550
+ .join("");
551
+ const order = parts === "DMY" ? "DMY" : parts === "YMD" ? "YMD" : "MDY";
552
+ localePartOrderCache.set(locale, order);
553
+ return order;
554
+ }
555
+ catch {
556
+ return "MDY";
557
+ }
558
+ }
559
+ /**
560
+ * Converts a locale-ordered 8-digit compact string to `YYYY-MM-DD`.
561
+ *
562
+ * The split follows the locale's field order:
563
+ * - MDY (e.g. `en`): `MMDDYYYY` → `YYYY-MM-DD`
564
+ * - DMY (e.g. `de`): `DDMMYYYY` → `YYYY-MM-DD`
565
+ * - YMD (e.g. `ja`): `YYYYMMDD` → `YYYY-MM-DD`
566
+ *
567
+ * Returns the original value unchanged for non-8-digit inputs.
568
+ */
569
+ const normalizeCompactDateInput = (value, locale) => {
570
+ if (!COMPACT_DATE_REGEX.test(value))
571
+ return value;
572
+ const order = getLocaleDatePartOrder(locale ?? "en");
573
+ if (order === "MDY")
574
+ return `${value.slice(4, 8)}-${value.slice(0, 2)}-${value.slice(2, 4)}`;
575
+ if (order === "DMY")
576
+ return `${value.slice(4, 8)}-${value.slice(2, 4)}-${value.slice(0, 2)}`;
577
+ return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`;
578
+ };
534
579
  /**
535
580
  * Parses date-field keyboard input to a local-midnight {@link Date}.
536
581
  *
537
- * Strict `YYYY-MM-DD` is accepted first; otherwise the string must round-trip with
538
- * {@link formatShortDateUtil} for the given `locale` (i.e. equal the canonical localized
539
- * display the field would render). Arbitrary `new Date(string)`-parseable inputs that don't
540
- * match the locale's format return `null` to avoid accepting confusable formats like `03/07/2025`.
582
+ * Strict `YYYY-MM-DD` is accepted first; a locale-ordered compact 8-digit string (e.g. `04132026`
583
+ * in English for April 13 2026) is normalised to `YYYY-MM-DD` before that check. Otherwise the
584
+ * string must round-trip with {@link formatShortDateUtil} for the given `locale`. Arbitrary
585
+ * `new Date(string)`-parseable inputs that don't match the locale's format return `null` to avoid
586
+ * accepting confusable formats like `03/07/2025`.
541
587
  *
542
588
  * @param value - Raw text from the input.
543
589
  * @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.
544
590
  */
545
591
  const parseDateFieldInputForChange = (value, locale) => {
546
- const fromIso = dateAndTimeUtils.parseYYYYMMDDUtil(value);
592
+ const fromIso = dateAndTimeUtils.parseYYYYMMDDUtil(normalizeCompactDateInput(value, locale));
547
593
  if (fromIso !== null)
548
594
  return fromIso;
549
595
  const trimmed = value.trim();
package/index.esm.js CHANGED
@@ -530,19 +530,65 @@ const normalizeDisplayCompare = (value) => value
530
530
  .replace(/[\u202f\u00a0]/g, " ")
531
531
  .replace(/\s+/g, " ")
532
532
  .trim();
533
+ const COMPACT_DATE_REGEX = /^\d{8}$/;
534
+ const localePartOrderCache = new Map();
535
+ /**
536
+ * Returns the date-part display order (month/day/year) for the given locale by inspecting
537
+ * `Intl.DateTimeFormat.formatToParts`. Results are cached after the first call per locale.
538
+ * Falls back to MDY (English/US convention) on any error.
539
+ */
540
+ function getLocaleDatePartOrder(locale) {
541
+ const cached = localePartOrderCache.get(locale);
542
+ if (cached !== undefined)
543
+ return cached;
544
+ try {
545
+ const parts = new Intl.DateTimeFormat(locale, { year: "numeric", month: "2-digit", day: "2-digit" })
546
+ .formatToParts(new Date(2000, 0, 15))
547
+ .filter(p => p.type === "month" || p.type === "day" || p.type === "year")
548
+ .map(p => p.type.charAt(0).toUpperCase())
549
+ .join("");
550
+ const order = parts === "DMY" ? "DMY" : parts === "YMD" ? "YMD" : "MDY";
551
+ localePartOrderCache.set(locale, order);
552
+ return order;
553
+ }
554
+ catch {
555
+ return "MDY";
556
+ }
557
+ }
558
+ /**
559
+ * Converts a locale-ordered 8-digit compact string to `YYYY-MM-DD`.
560
+ *
561
+ * The split follows the locale's field order:
562
+ * - MDY (e.g. `en`): `MMDDYYYY` → `YYYY-MM-DD`
563
+ * - DMY (e.g. `de`): `DDMMYYYY` → `YYYY-MM-DD`
564
+ * - YMD (e.g. `ja`): `YYYYMMDD` → `YYYY-MM-DD`
565
+ *
566
+ * Returns the original value unchanged for non-8-digit inputs.
567
+ */
568
+ const normalizeCompactDateInput = (value, locale) => {
569
+ if (!COMPACT_DATE_REGEX.test(value))
570
+ return value;
571
+ const order = getLocaleDatePartOrder(locale ?? "en");
572
+ if (order === "MDY")
573
+ return `${value.slice(4, 8)}-${value.slice(0, 2)}-${value.slice(2, 4)}`;
574
+ if (order === "DMY")
575
+ return `${value.slice(4, 8)}-${value.slice(2, 4)}-${value.slice(0, 2)}`;
576
+ return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`;
577
+ };
533
578
  /**
534
579
  * Parses date-field keyboard input to a local-midnight {@link Date}.
535
580
  *
536
- * Strict `YYYY-MM-DD` is accepted first; otherwise the string must round-trip with
537
- * {@link formatShortDateUtil} for the given `locale` (i.e. equal the canonical localized
538
- * display the field would render). Arbitrary `new Date(string)`-parseable inputs that don't
539
- * match the locale's format return `null` to avoid accepting confusable formats like `03/07/2025`.
581
+ * Strict `YYYY-MM-DD` is accepted first; a locale-ordered compact 8-digit string (e.g. `04132026`
582
+ * in English for April 13 2026) is normalised to `YYYY-MM-DD` before that check. Otherwise the
583
+ * string must round-trip with {@link formatShortDateUtil} for the given `locale`. Arbitrary
584
+ * `new Date(string)`-parseable inputs that don't match the locale's format return `null` to avoid
585
+ * accepting confusable formats like `03/07/2025`.
540
586
  *
541
587
  * @param value - Raw text from the input.
542
588
  * @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.
543
589
  */
544
590
  const parseDateFieldInputForChange = (value, locale) => {
545
- const fromIso = parseYYYYMMDDUtil(value);
591
+ const fromIso = parseYYYYMMDDUtil(normalizeCompactDateInput(value, locale));
546
592
  if (fromIso !== null)
547
593
  return fromIso;
548
594
  const trimmed = value.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "1.22.10",
3
+ "version": "1.22.12-alpha-71bd6bc448a.0",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -9,17 +9,17 @@
9
9
  "dependencies": {
10
10
  "react-calendar": "^6.0.0",
11
11
  "react-select": "^5.10.2",
12
- "@trackunit/date-and-time-utils": "1.11.105",
12
+ "@trackunit/date-and-time-utils": "1.11.106-alpha-71bd6bc448a.0",
13
13
  "usehooks-ts": "^3.1.0",
14
14
  "libphonenumber-js": "^1.12.22",
15
15
  "zod": "^3.25.76",
16
16
  "tailwind-merge": "^2.0.0",
17
- "@trackunit/css-class-variance-utilities": "1.11.102",
18
- "@trackunit/react-components": "1.22.7",
19
- "@trackunit/ui-icons": "1.11.98",
20
- "@trackunit/shared-utils": "1.13.102",
21
- "@trackunit/ui-design-tokens": "1.11.99",
22
- "@trackunit/i18n-library-translation": "1.18.8",
17
+ "@trackunit/css-class-variance-utilities": "1.11.103-alpha-71bd6bc448a.0",
18
+ "@trackunit/react-components": "1.22.8-alpha-71bd6bc448a.0",
19
+ "@trackunit/ui-icons": "1.11.99-alpha-71bd6bc448a.0",
20
+ "@trackunit/shared-utils": "1.13.103-alpha-71bd6bc448a.0",
21
+ "@trackunit/ui-design-tokens": "1.11.100-alpha-71bd6bc448a.0",
22
+ "@trackunit/i18n-library-translation": "1.18.9-alpha-71bd6bc448a.0",
23
23
  "string-ts": "^2.0.0",
24
24
  "es-toolkit": "^1.39.10"
25
25
  },
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Parses date-field keyboard input to a local-midnight {@link Date}.
3
3
  *
4
- * Strict `YYYY-MM-DD` is accepted first; otherwise the string must round-trip with
5
- * {@link formatShortDateUtil} for the given `locale` (i.e. equal the canonical localized
6
- * display the field would render). Arbitrary `new Date(string)`-parseable inputs that don't
7
- * match the locale's format return `null` to avoid accepting confusable formats like `03/07/2025`.
4
+ * Strict `YYYY-MM-DD` is accepted first; a locale-ordered compact 8-digit string (e.g. `04132026`
5
+ * in English for April 13 2026) is normalised to `YYYY-MM-DD` before that check. Otherwise the
6
+ * string must round-trip with {@link formatShortDateUtil} for the given `locale`. Arbitrary
7
+ * `new Date(string)`-parseable inputs that don't match the locale's format return `null` to avoid
8
+ * accepting confusable formats like `03/07/2025`.
8
9
  *
9
10
  * @param value - Raw text from the input.
10
11
  * @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.