@trackunit/react-form-components 1.22.2 → 1.22.4
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 +74 -102
- package/index.esm.js +76 -101
- package/package.json +2 -2
- package/src/components/DateField/DateBaseInput/DateBaseInput.d.ts +2 -1
- package/src/components/DateField/DateField.d.ts +7 -1
- package/src/components/DateField/dateFieldInputUtils.d.ts +22 -0
- package/src/index.d.ts +0 -1
- package/translation.cjs.js +0 -1
- package/translation.cjs10.js +0 -1
- package/translation.cjs11.js +0 -1
- package/translation.cjs12.js +0 -1
- package/translation.cjs13.js +0 -1
- package/translation.cjs14.js +0 -1
- package/translation.cjs15.js +0 -1
- package/translation.cjs16.js +0 -1
- package/translation.cjs17.js +0 -1
- package/translation.cjs2.js +0 -1
- package/translation.cjs3.js +0 -1
- package/translation.cjs4.js +0 -1
- package/translation.cjs5.js +0 -1
- package/translation.cjs6.js +0 -1
- package/translation.cjs7.js +0 -1
- package/translation.cjs8.js +0 -1
- package/translation.cjs9.js +0 -1
- package/translation.esm.js +0 -1
- package/translation.esm10.js +0 -1
- package/translation.esm11.js +0 -1
- package/translation.esm12.js +0 -1
- package/translation.esm13.js +0 -1
- package/translation.esm14.js +0 -1
- package/translation.esm15.js +0 -1
- package/translation.esm16.js +0 -1
- package/translation.esm17.js +0 -1
- package/translation.esm2.js +0 -1
- package/translation.esm3.js +0 -1
- package/translation.esm4.js +0 -1
- package/translation.esm5.js +0 -1
- package/translation.esm6.js +0 -1
- package/translation.esm7.js +0 -1
- package/translation.esm8.js +0 -1
- package/translation.esm9.js +0 -1
- package/src/utilities/parseDateFieldValue.d.ts +0 -26
package/index.cjs.js
CHANGED
|
@@ -30,7 +30,7 @@ var defaultTranslations = {
|
|
|
30
30
|
"dateField.actions.apply": "Apply",
|
|
31
31
|
"dateField.actions.cancel": "Cancel",
|
|
32
32
|
"dateField.actions.clear": "Clear",
|
|
33
|
-
"dateField.placeholder": "
|
|
33
|
+
"dateField.placeholder": "mm dd, yyyy",
|
|
34
34
|
"dropzone.input.title": "Drag-and-drop file input",
|
|
35
35
|
"dropzone.label.default": "<clickable>Browse</clickable> or drag files here...",
|
|
36
36
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
|
@@ -141,76 +141,6 @@ function createInputChangeEvent(value, sourceInput) {
|
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
const ISO_DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
145
|
-
function parseAndValidateYYYYMMDD(value) {
|
|
146
|
-
if (value === "")
|
|
147
|
-
return null;
|
|
148
|
-
const isoMatch = ISO_DATE_REGEX.exec(value);
|
|
149
|
-
if (!isoMatch)
|
|
150
|
-
return null;
|
|
151
|
-
const [, y, m, d] = isoMatch;
|
|
152
|
-
if (y === undefined || m === undefined || d === undefined)
|
|
153
|
-
return null;
|
|
154
|
-
const year = Number.parseInt(y, 10);
|
|
155
|
-
const month = Number.parseInt(m, 10) - 1;
|
|
156
|
-
const day = Number.parseInt(d, 10);
|
|
157
|
-
if (month < 0 || month > 11 || day < 1 || day > 31)
|
|
158
|
-
return null;
|
|
159
|
-
const local = new Date(year, month, day);
|
|
160
|
-
if (Number.isNaN(local.getTime()))
|
|
161
|
-
return null;
|
|
162
|
-
if (local.getFullYear() !== year || local.getMonth() !== month || local.getDate() !== day) {
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
return { year, month: month + 1, day };
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Parses the value from a DateField change event (YYYY-MM-DD string) to a Date at local midnight.
|
|
169
|
-
* Use this when you need a Date from event.target.value to avoid timezone shifts that occur
|
|
170
|
-
* with `new Date(value)` (which interprets the string as UTC).
|
|
171
|
-
*
|
|
172
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
173
|
-
* @returns {Date | null} - Date at local midnight for the given day, or null if value is empty or invalid
|
|
174
|
-
*/
|
|
175
|
-
function parseDateFieldValue(value) {
|
|
176
|
-
const parsed = parseAndValidateYYYYMMDD(value);
|
|
177
|
-
if (!parsed)
|
|
178
|
-
return null;
|
|
179
|
-
return new Date(parsed.year, parsed.month - 1, parsed.day);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Converts a YYYY-MM-DD string (e.g. from DateField) to an ISO string at UTC midnight for that calendar day.
|
|
183
|
-
* Use this when storing or sending date-only values so that the calendar day is preserved regardless of
|
|
184
|
-
* user timezone (unlike calling .toISOString() on a local-midnight Date, which shifts the day for UTC+).
|
|
185
|
-
*
|
|
186
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
187
|
-
* @returns {string | null} - "YYYY-MM-DDT00:00:00.000Z" or null if value is empty or invalid
|
|
188
|
-
*/
|
|
189
|
-
function toISODateStringUTC(value) {
|
|
190
|
-
const parsed = parseAndValidateYYYYMMDD(value);
|
|
191
|
-
if (!parsed)
|
|
192
|
-
return null;
|
|
193
|
-
const { year, month, day } = parsed;
|
|
194
|
-
const mm = String(month).padStart(2, "0");
|
|
195
|
-
const dd = String(day).padStart(2, "0");
|
|
196
|
-
return `${year}-${mm}-${dd}T00:00:00.000Z`;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Converts a Date (e.g. at local midnight) to an ISO string at UTC midnight for the same calendar day.
|
|
200
|
-
* Use when sending a date-only value to an API that expects UTC midnight (e.g. booking date).
|
|
201
|
-
*
|
|
202
|
-
* @param date - A Date instance (typically local midnight from a date picker)
|
|
203
|
-
* @returns {string} "YYYY-MM-DDT00:00:00.000Z" for that calendar day
|
|
204
|
-
*/
|
|
205
|
-
function dateToISODateUTC(date) {
|
|
206
|
-
const year = date.getFullYear();
|
|
207
|
-
const month = date.getMonth() + 1;
|
|
208
|
-
const day = date.getDate();
|
|
209
|
-
const mm = String(month).padStart(2, "0");
|
|
210
|
-
const dd = String(day).padStart(2, "0");
|
|
211
|
-
return `${year}-${mm}-${dd}T00:00:00.000Z`;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
144
|
const cvaInputBase = cssClassVarianceUtilities.cvaMerge([
|
|
215
145
|
"component-baseInput-shadow",
|
|
216
146
|
"component-baseInput-border",
|
|
@@ -596,6 +526,57 @@ const BaseInput = ({ className, isInvalid = false, "data-testid": dataTestId, pr
|
|
|
596
526
|
};
|
|
597
527
|
BaseInput.displayName = "BaseInput";
|
|
598
528
|
|
|
529
|
+
const normalizeDisplayCompare = (value) => value
|
|
530
|
+
.normalize("NFKC")
|
|
531
|
+
.replace(/[\u202f\u00a0]/g, " ")
|
|
532
|
+
.replace(/\s+/g, " ")
|
|
533
|
+
.trim();
|
|
534
|
+
/**
|
|
535
|
+
* Parses date-field keyboard input to a local-midnight {@link Date}.
|
|
536
|
+
*
|
|
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`.
|
|
541
|
+
*
|
|
542
|
+
* @param value - Raw text from the input.
|
|
543
|
+
* @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.
|
|
544
|
+
*/
|
|
545
|
+
const parseDateFieldInputForChange = (value, locale) => {
|
|
546
|
+
const fromIso = dateAndTimeUtils.parseYYYYMMDDUtil(value);
|
|
547
|
+
if (fromIso !== null)
|
|
548
|
+
return fromIso;
|
|
549
|
+
const trimmed = value.trim();
|
|
550
|
+
if (trimmed === "")
|
|
551
|
+
return null;
|
|
552
|
+
const parsed = dateAndTimeUtils.parseValidDate(trimmed);
|
|
553
|
+
if (parsed === null)
|
|
554
|
+
return null;
|
|
555
|
+
const localMidnight = dateAndTimeUtils.toDateUtil(dateAndTimeUtils.startOfDayUtil(parsed));
|
|
556
|
+
const formatted = dateAndTimeUtils.formatShortDateUtil(localMidnight, locale);
|
|
557
|
+
if (normalizeDisplayCompare(formatted) === normalizeDisplayCompare(trimmed)) {
|
|
558
|
+
return localMidnight;
|
|
559
|
+
}
|
|
560
|
+
return null;
|
|
561
|
+
};
|
|
562
|
+
/**
|
|
563
|
+
* Renders the stored date-field value for display:
|
|
564
|
+
* - empty string → empty
|
|
565
|
+
* - full canonical `YYYY-MM-DD` → locale-aware short date
|
|
566
|
+
* - partial input (e.g. `"2025-03"`) → returned as-is so the user can keep typing
|
|
567
|
+
*
|
|
568
|
+
* @param stored - The current canonical value (typically from `event.target.value`).
|
|
569
|
+
* @param locale - Locale for the display format.
|
|
570
|
+
*/
|
|
571
|
+
const dateFieldStoredValueToDisplayString = (stored, locale) => {
|
|
572
|
+
if (stored === "")
|
|
573
|
+
return "";
|
|
574
|
+
const parsed = dateAndTimeUtils.parseYYYYMMDDUtil(stored);
|
|
575
|
+
if (parsed !== null)
|
|
576
|
+
return dateAndTimeUtils.formatShortDateUtil(parsed, locale);
|
|
577
|
+
return stored;
|
|
578
|
+
};
|
|
579
|
+
|
|
599
580
|
function parseToDate(v) {
|
|
600
581
|
if (v === undefined || v === "")
|
|
601
582
|
return undefined;
|
|
@@ -606,23 +587,12 @@ function parseToDate(v) {
|
|
|
606
587
|
return Number.isNaN(d.getTime()) ? undefined : d;
|
|
607
588
|
}
|
|
608
589
|
const str = String(v);
|
|
609
|
-
const fromField =
|
|
590
|
+
const fromField = dateAndTimeUtils.parseYYYYMMDDUtil(str);
|
|
610
591
|
if (fromField !== null)
|
|
611
592
|
return fromField;
|
|
612
593
|
const fallback = new Date(str);
|
|
613
594
|
return Number.isNaN(fallback.getTime()) ? undefined : fallback;
|
|
614
595
|
}
|
|
615
|
-
function formatToInputString(d) {
|
|
616
|
-
if (!d)
|
|
617
|
-
return "";
|
|
618
|
-
return dateAndTimeUtils.Temporal.PlainDateTime.from({
|
|
619
|
-
year: d.getFullYear(),
|
|
620
|
-
month: d.getMonth() + 1,
|
|
621
|
-
day: d.getDate(),
|
|
622
|
-
})
|
|
623
|
-
.toPlainDate()
|
|
624
|
-
.toString();
|
|
625
|
-
}
|
|
626
596
|
function startOfDayMs(d) {
|
|
627
597
|
return dateAndTimeUtils.toDateUtil(dateAndTimeUtils.startOfDayUtil(d)).getTime();
|
|
628
598
|
}
|
|
@@ -640,28 +610,27 @@ function clampToRange(date, minDate, maxDate) {
|
|
|
640
610
|
/**
|
|
641
611
|
* A wrapper around BaseInput with a pop-up day picker using the same calendar UI as DayPicker.
|
|
642
612
|
*
|
|
643
|
-
* The
|
|
613
|
+
* The input shows a locale-aware date (short month, numeric day and year, e.g. "Mar 23, 2026" in English).
|
|
614
|
+
* `onChange` still emits the canonical YYYY-MM-DD string for form parsing.
|
|
644
615
|
*
|
|
645
616
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
646
617
|
*/
|
|
647
618
|
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
648
619
|
const isControlled = value !== undefined;
|
|
649
|
-
const [internalValue, setInternalValue] = react.useState(() =>
|
|
620
|
+
const [internalValue, setInternalValue] = react.useState(() => dateAndTimeUtils.dateToYYYYMMDDUtil(parseToDate(defaultValue)));
|
|
650
621
|
const [pendingDate, setPendingDate] = react.useState(null);
|
|
622
|
+
const [t, i18n] = useTranslation();
|
|
623
|
+
const locale = i18n.resolvedLanguage ?? i18n.language;
|
|
651
624
|
// For controlled string value, only normalize when it's strict YYYY-MM-DD so partial input (e.g. "2025-03") is preserved.
|
|
652
625
|
const resolvedValue = isControlled
|
|
653
626
|
? typeof value === "string"
|
|
654
|
-
? (
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
})()
|
|
658
|
-
: formatToInputString(parseToDate(value))
|
|
659
|
-
: internalValue;
|
|
627
|
+
? dateFieldStoredValueToDisplayString(value, locale)
|
|
628
|
+
: dateFieldStoredValueToDisplayString(dateAndTimeUtils.dateToYYYYMMDDUtil(parseToDate(value)), locale)
|
|
629
|
+
: dateFieldStoredValueToDisplayString(internalValue, locale);
|
|
660
630
|
const selectedDate = isControlled && typeof value === "string"
|
|
661
|
-
? (
|
|
631
|
+
? (dateAndTimeUtils.parseYYYYMMDDUtil(value) ?? undefined)
|
|
662
632
|
: parseToDate(isControlled ? value : internalValue);
|
|
663
633
|
const inputRef = react.useRef(null);
|
|
664
|
-
const [t] = useTranslation();
|
|
665
634
|
react.useImperativeHandle(ref, () => inputRef.current ?? document.createElement("input"), []);
|
|
666
635
|
const syncPendingFromValue = react.useCallback(() => {
|
|
667
636
|
setPendingDate(selectedDate ?? null);
|
|
@@ -695,7 +664,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
695
664
|
const minDate = parseToDate(min);
|
|
696
665
|
const maxDate = parseToDate(max);
|
|
697
666
|
const clamped = clampToRange(pendingDate, minDate, maxDate);
|
|
698
|
-
const str = clamped ?
|
|
667
|
+
const str = clamped ? dateAndTimeUtils.dateToYYYYMMDDUtil(clamped) : "";
|
|
699
668
|
if (!isControlled)
|
|
700
669
|
setInternalValue(str);
|
|
701
670
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -703,12 +672,12 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
703
672
|
}, [isControlled, min, max, onChange, pendingDate]);
|
|
704
673
|
const handleInputChange = react.useCallback((e) => {
|
|
705
674
|
const raw = e.target.value;
|
|
706
|
-
const parsed =
|
|
675
|
+
const parsed = parseDateFieldInputForChange(raw, locale);
|
|
707
676
|
const minDate = parseToDate(min);
|
|
708
677
|
const maxDate = parseToDate(max);
|
|
709
678
|
if (parsed !== null) {
|
|
710
679
|
const clamped = clampToRange(parsed, minDate, maxDate);
|
|
711
|
-
const str = clamped ?
|
|
680
|
+
const str = clamped ? dateAndTimeUtils.dateToYYYYMMDDUtil(clamped) : "";
|
|
712
681
|
if (!isControlled)
|
|
713
682
|
setInternalValue(str);
|
|
714
683
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -718,10 +687,10 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
718
687
|
setInternalValue(raw);
|
|
719
688
|
onChange?.(e);
|
|
720
689
|
}
|
|
721
|
-
}, [isControlled, min, max, onChange]);
|
|
690
|
+
}, [isControlled, locale, min, max, onChange]);
|
|
722
691
|
return (jsxRuntime.jsxs(reactComponents.Popover, { onOpenStateChange: open => open && syncPendingFromValue(), placement: "bottom-start", children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("flex w-full min-w-0 cursor-pointer items-center", (Boolean(rest.disabled) || Boolean(rest.readOnly)) && "pointer-events-none"), children: jsxRuntime.jsx(BaseInput, { ...rest, "aria-readonly": true, className: tailwindMerge.twMerge("w-full min-w-0", rest.className), "data-testid": dataTestId ? `${dataTestId}-input` : undefined, onChange: handleInputChange, placeholder: rest.placeholder ?? t("dateField.placeholder"), ref: inputRef, suffix: suffixProp ?? (jsxRuntime.jsx(reactComponents.Icon, { "aria-label": undefined, className: Boolean(rest.disabled) || Boolean(rest.readOnly) ? "text-neutral-500" : undefined, "data-testid": dataTestId ? `${dataTestId}-calendar` : "calendar", name: "Calendar", size: "medium", type: "solid" })), type: "text", value: resolvedValue }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: closePopover => {
|
|
723
692
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
724
|
-
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsxRuntime.jsx(ReactCalendar, { allowPartialRange: true, className: tailwindMerge.twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", onChange: val => {
|
|
693
|
+
return (jsxRuntime.jsxs("div", { className: tailwindMerge.twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsxRuntime.jsx(ReactCalendar, { allowPartialRange: true, className: tailwindMerge.twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", locale: locale, onChange: val => {
|
|
725
694
|
const next = val instanceof Date ? val : Array.isArray(val) ? (val[0] instanceof Date ? val[0] : null) : null;
|
|
726
695
|
handleCalendarChange(next);
|
|
727
696
|
}, selectRange: false, tileDisabled: tileDisabled, value: displayDate }), jsxRuntime.jsx("hr", {}), jsxRuntime.jsxs("div", { className: "flex w-full justify-between gap-2 px-4 py-3", children: [jsxRuntime.jsx(reactComponents.Button, { className: "mr-auto", "data-testid": dataTestId ? `${dataTestId}-clear-button` : undefined, onClick: () => handleClear(closePopover), size: "small", variant: "secondary", children: t("dateField.actions.clear") }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(reactComponents.Button, { "data-testid": dataTestId ? `${dataTestId}-cancel-button` : undefined, onClick: () => handleCancel(closePopover), size: "small", variant: "ghost-neutral", children: t("dateField.actions.cancel") }), jsxRuntime.jsx(reactComponents.Button, { "data-testid": dataTestId ? `${dataTestId}-apply-button` : undefined, onClick: () => handleApply(closePopover), size: "small", children: t("dateField.actions.apply") })] })] })] }));
|
|
@@ -2504,6 +2473,10 @@ ColorField.displayName = "ColorField";
|
|
|
2504
2473
|
|
|
2505
2474
|
/**
|
|
2506
2475
|
* The date field component is used for entering date values with a calendar picker (same UI as DayPicker).
|
|
2476
|
+
* The input shows a localized short date; when the user commits a valid day, `onChange` provides `YYYY-MM-DD`
|
|
2477
|
+
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils` for a local-midnight
|
|
2478
|
+
* `Date`). Do not parse `event.target.value` from `onBlur` — the visible string may be localized while
|
|
2479
|
+
* `onChange` stays canonical.
|
|
2507
2480
|
*
|
|
2508
2481
|
* ### When to use
|
|
2509
2482
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
|
@@ -2531,11 +2504,13 @@ ColorField.displayName = "ColorField";
|
|
|
2531
2504
|
* @example Date field with constraints
|
|
2532
2505
|
* ```tsx
|
|
2533
2506
|
* import { DateField } from "@trackunit/react-form-components";
|
|
2507
|
+
* import { dateToYYYYMMDDUtil } from "@trackunit/date-and-time-utils";
|
|
2534
2508
|
* import { useState } from "react";
|
|
2535
2509
|
*
|
|
2536
2510
|
* const BookingForm = () => {
|
|
2537
2511
|
* const [checkIn, setCheckIn] = useState("");
|
|
2538
|
-
*
|
|
2512
|
+
* // Use the local calendar day, not UTC (avoids day-shift in non-UTC zones).
|
|
2513
|
+
* const today = dateToYYYYMMDDUtil(new Date());
|
|
2539
2514
|
*
|
|
2540
2515
|
* return (
|
|
2541
2516
|
* <DateField
|
|
@@ -5009,17 +4984,14 @@ exports.cvaSelectPlaceholder = cvaSelectPlaceholder;
|
|
|
5009
4984
|
exports.cvaSelectPrefixSuffix = cvaSelectPrefixSuffix;
|
|
5010
4985
|
exports.cvaSelectSingleValue = cvaSelectSingleValue;
|
|
5011
4986
|
exports.cvaSelectValueContainer = cvaSelectValueContainer;
|
|
5012
|
-
exports.dateToISODateUTC = dateToISODateUTC;
|
|
5013
4987
|
exports.getCountryAbbreviation = getCountryAbbreviation;
|
|
5014
4988
|
exports.getPhoneNumberWithPlus = getPhoneNumberWithPlus;
|
|
5015
4989
|
exports.isInvalidCountryCode = isInvalidCountryCode;
|
|
5016
4990
|
exports.isInvalidPhoneNumber = isInvalidPhoneNumber;
|
|
5017
4991
|
exports.isValidHEXColor = isValidHEXColor;
|
|
5018
|
-
exports.parseDateFieldValue = parseDateFieldValue;
|
|
5019
4992
|
exports.parseSchedule = parseSchedule;
|
|
5020
4993
|
exports.phoneErrorMessage = phoneErrorMessage;
|
|
5021
4994
|
exports.serializeSchedule = serializeSchedule;
|
|
5022
|
-
exports.toISODateStringUTC = toISODateStringUTC;
|
|
5023
4995
|
exports.useCreatableSelect = useCreatableSelect;
|
|
5024
4996
|
exports.useCustomComponents = useCustomComponents;
|
|
5025
4997
|
exports.useGetPhoneValidationRules = useGetPhoneValidationRules;
|
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation, NamespaceTrans } from '@trackunit/i18n-library-translation';
|
|
3
|
-
import {
|
|
3
|
+
import { parseYYYYMMDDUtil, formatShortDateUtil, parseValidDate, toDateUtil, startOfDayUtil, dateToYYYYMMDDUtil } from '@trackunit/date-and-time-utils';
|
|
4
4
|
import { IconButton, Icon, Tooltip, Popover, PopoverTrigger, PopoverContent, Button, cvaMenu, cvaMenuList, Tag, useIsTextTruncated, ZStack, MenuItem, useMeasure, useDebounce, useMergeRefs, Spinner, useScrollBlock, Text, Heading, useIsFirstRender } from '@trackunit/react-components';
|
|
5
5
|
import { useRef, useEffect, useImperativeHandle, useState, useCallback, cloneElement, isValidElement, useLayoutEffect, useMemo, useReducer, createContext, useContext, useId } from 'react';
|
|
6
6
|
import ReactCalendar from 'react-calendar';
|
|
@@ -29,7 +29,7 @@ var defaultTranslations = {
|
|
|
29
29
|
"dateField.actions.apply": "Apply",
|
|
30
30
|
"dateField.actions.cancel": "Cancel",
|
|
31
31
|
"dateField.actions.clear": "Clear",
|
|
32
|
-
"dateField.placeholder": "
|
|
32
|
+
"dateField.placeholder": "mm dd, yyyy",
|
|
33
33
|
"dropzone.input.title": "Drag-and-drop file input",
|
|
34
34
|
"dropzone.label.default": "<clickable>Browse</clickable> or drag files here...",
|
|
35
35
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
|
@@ -140,76 +140,6 @@ function createInputChangeEvent(value, sourceInput) {
|
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
const ISO_DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
144
|
-
function parseAndValidateYYYYMMDD(value) {
|
|
145
|
-
if (value === "")
|
|
146
|
-
return null;
|
|
147
|
-
const isoMatch = ISO_DATE_REGEX.exec(value);
|
|
148
|
-
if (!isoMatch)
|
|
149
|
-
return null;
|
|
150
|
-
const [, y, m, d] = isoMatch;
|
|
151
|
-
if (y === undefined || m === undefined || d === undefined)
|
|
152
|
-
return null;
|
|
153
|
-
const year = Number.parseInt(y, 10);
|
|
154
|
-
const month = Number.parseInt(m, 10) - 1;
|
|
155
|
-
const day = Number.parseInt(d, 10);
|
|
156
|
-
if (month < 0 || month > 11 || day < 1 || day > 31)
|
|
157
|
-
return null;
|
|
158
|
-
const local = new Date(year, month, day);
|
|
159
|
-
if (Number.isNaN(local.getTime()))
|
|
160
|
-
return null;
|
|
161
|
-
if (local.getFullYear() !== year || local.getMonth() !== month || local.getDate() !== day) {
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
return { year, month: month + 1, day };
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Parses the value from a DateField change event (YYYY-MM-DD string) to a Date at local midnight.
|
|
168
|
-
* Use this when you need a Date from event.target.value to avoid timezone shifts that occur
|
|
169
|
-
* with `new Date(value)` (which interprets the string as UTC).
|
|
170
|
-
*
|
|
171
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
172
|
-
* @returns {Date | null} - Date at local midnight for the given day, or null if value is empty or invalid
|
|
173
|
-
*/
|
|
174
|
-
function parseDateFieldValue(value) {
|
|
175
|
-
const parsed = parseAndValidateYYYYMMDD(value);
|
|
176
|
-
if (!parsed)
|
|
177
|
-
return null;
|
|
178
|
-
return new Date(parsed.year, parsed.month - 1, parsed.day);
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Converts a YYYY-MM-DD string (e.g. from DateField) to an ISO string at UTC midnight for that calendar day.
|
|
182
|
-
* Use this when storing or sending date-only values so that the calendar day is preserved regardless of
|
|
183
|
-
* user timezone (unlike calling .toISOString() on a local-midnight Date, which shifts the day for UTC+).
|
|
184
|
-
*
|
|
185
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
186
|
-
* @returns {string | null} - "YYYY-MM-DDT00:00:00.000Z" or null if value is empty or invalid
|
|
187
|
-
*/
|
|
188
|
-
function toISODateStringUTC(value) {
|
|
189
|
-
const parsed = parseAndValidateYYYYMMDD(value);
|
|
190
|
-
if (!parsed)
|
|
191
|
-
return null;
|
|
192
|
-
const { year, month, day } = parsed;
|
|
193
|
-
const mm = String(month).padStart(2, "0");
|
|
194
|
-
const dd = String(day).padStart(2, "0");
|
|
195
|
-
return `${year}-${mm}-${dd}T00:00:00.000Z`;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Converts a Date (e.g. at local midnight) to an ISO string at UTC midnight for the same calendar day.
|
|
199
|
-
* Use when sending a date-only value to an API that expects UTC midnight (e.g. booking date).
|
|
200
|
-
*
|
|
201
|
-
* @param date - A Date instance (typically local midnight from a date picker)
|
|
202
|
-
* @returns {string} "YYYY-MM-DDT00:00:00.000Z" for that calendar day
|
|
203
|
-
*/
|
|
204
|
-
function dateToISODateUTC(date) {
|
|
205
|
-
const year = date.getFullYear();
|
|
206
|
-
const month = date.getMonth() + 1;
|
|
207
|
-
const day = date.getDate();
|
|
208
|
-
const mm = String(month).padStart(2, "0");
|
|
209
|
-
const dd = String(day).padStart(2, "0");
|
|
210
|
-
return `${year}-${mm}-${dd}T00:00:00.000Z`;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
143
|
const cvaInputBase = cvaMerge([
|
|
214
144
|
"component-baseInput-shadow",
|
|
215
145
|
"component-baseInput-border",
|
|
@@ -595,6 +525,57 @@ const BaseInput = ({ className, isInvalid = false, "data-testid": dataTestId, pr
|
|
|
595
525
|
};
|
|
596
526
|
BaseInput.displayName = "BaseInput";
|
|
597
527
|
|
|
528
|
+
const normalizeDisplayCompare = (value) => value
|
|
529
|
+
.normalize("NFKC")
|
|
530
|
+
.replace(/[\u202f\u00a0]/g, " ")
|
|
531
|
+
.replace(/\s+/g, " ")
|
|
532
|
+
.trim();
|
|
533
|
+
/**
|
|
534
|
+
* Parses date-field keyboard input to a local-midnight {@link Date}.
|
|
535
|
+
*
|
|
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`.
|
|
540
|
+
*
|
|
541
|
+
* @param value - Raw text from the input.
|
|
542
|
+
* @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.
|
|
543
|
+
*/
|
|
544
|
+
const parseDateFieldInputForChange = (value, locale) => {
|
|
545
|
+
const fromIso = parseYYYYMMDDUtil(value);
|
|
546
|
+
if (fromIso !== null)
|
|
547
|
+
return fromIso;
|
|
548
|
+
const trimmed = value.trim();
|
|
549
|
+
if (trimmed === "")
|
|
550
|
+
return null;
|
|
551
|
+
const parsed = parseValidDate(trimmed);
|
|
552
|
+
if (parsed === null)
|
|
553
|
+
return null;
|
|
554
|
+
const localMidnight = toDateUtil(startOfDayUtil(parsed));
|
|
555
|
+
const formatted = formatShortDateUtil(localMidnight, locale);
|
|
556
|
+
if (normalizeDisplayCompare(formatted) === normalizeDisplayCompare(trimmed)) {
|
|
557
|
+
return localMidnight;
|
|
558
|
+
}
|
|
559
|
+
return null;
|
|
560
|
+
};
|
|
561
|
+
/**
|
|
562
|
+
* Renders the stored date-field value for display:
|
|
563
|
+
* - empty string → empty
|
|
564
|
+
* - full canonical `YYYY-MM-DD` → locale-aware short date
|
|
565
|
+
* - partial input (e.g. `"2025-03"`) → returned as-is so the user can keep typing
|
|
566
|
+
*
|
|
567
|
+
* @param stored - The current canonical value (typically from `event.target.value`).
|
|
568
|
+
* @param locale - Locale for the display format.
|
|
569
|
+
*/
|
|
570
|
+
const dateFieldStoredValueToDisplayString = (stored, locale) => {
|
|
571
|
+
if (stored === "")
|
|
572
|
+
return "";
|
|
573
|
+
const parsed = parseYYYYMMDDUtil(stored);
|
|
574
|
+
if (parsed !== null)
|
|
575
|
+
return formatShortDateUtil(parsed, locale);
|
|
576
|
+
return stored;
|
|
577
|
+
};
|
|
578
|
+
|
|
598
579
|
function parseToDate(v) {
|
|
599
580
|
if (v === undefined || v === "")
|
|
600
581
|
return undefined;
|
|
@@ -605,23 +586,12 @@ function parseToDate(v) {
|
|
|
605
586
|
return Number.isNaN(d.getTime()) ? undefined : d;
|
|
606
587
|
}
|
|
607
588
|
const str = String(v);
|
|
608
|
-
const fromField =
|
|
589
|
+
const fromField = parseYYYYMMDDUtil(str);
|
|
609
590
|
if (fromField !== null)
|
|
610
591
|
return fromField;
|
|
611
592
|
const fallback = new Date(str);
|
|
612
593
|
return Number.isNaN(fallback.getTime()) ? undefined : fallback;
|
|
613
594
|
}
|
|
614
|
-
function formatToInputString(d) {
|
|
615
|
-
if (!d)
|
|
616
|
-
return "";
|
|
617
|
-
return Temporal.PlainDateTime.from({
|
|
618
|
-
year: d.getFullYear(),
|
|
619
|
-
month: d.getMonth() + 1,
|
|
620
|
-
day: d.getDate(),
|
|
621
|
-
})
|
|
622
|
-
.toPlainDate()
|
|
623
|
-
.toString();
|
|
624
|
-
}
|
|
625
595
|
function startOfDayMs(d) {
|
|
626
596
|
return toDateUtil(startOfDayUtil(d)).getTime();
|
|
627
597
|
}
|
|
@@ -639,28 +609,27 @@ function clampToRange(date, minDate, maxDate) {
|
|
|
639
609
|
/**
|
|
640
610
|
* A wrapper around BaseInput with a pop-up day picker using the same calendar UI as DayPicker.
|
|
641
611
|
*
|
|
642
|
-
* The
|
|
612
|
+
* The input shows a locale-aware date (short month, numeric day and year, e.g. "Mar 23, 2026" in English).
|
|
613
|
+
* `onChange` still emits the canonical YYYY-MM-DD string for form parsing.
|
|
643
614
|
*
|
|
644
615
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
645
616
|
*/
|
|
646
617
|
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
647
618
|
const isControlled = value !== undefined;
|
|
648
|
-
const [internalValue, setInternalValue] = useState(() =>
|
|
619
|
+
const [internalValue, setInternalValue] = useState(() => dateToYYYYMMDDUtil(parseToDate(defaultValue)));
|
|
649
620
|
const [pendingDate, setPendingDate] = useState(null);
|
|
621
|
+
const [t, i18n] = useTranslation();
|
|
622
|
+
const locale = i18n.resolvedLanguage ?? i18n.language;
|
|
650
623
|
// For controlled string value, only normalize when it's strict YYYY-MM-DD so partial input (e.g. "2025-03") is preserved.
|
|
651
624
|
const resolvedValue = isControlled
|
|
652
625
|
? typeof value === "string"
|
|
653
|
-
? (
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
})()
|
|
657
|
-
: formatToInputString(parseToDate(value))
|
|
658
|
-
: internalValue;
|
|
626
|
+
? dateFieldStoredValueToDisplayString(value, locale)
|
|
627
|
+
: dateFieldStoredValueToDisplayString(dateToYYYYMMDDUtil(parseToDate(value)), locale)
|
|
628
|
+
: dateFieldStoredValueToDisplayString(internalValue, locale);
|
|
659
629
|
const selectedDate = isControlled && typeof value === "string"
|
|
660
|
-
? (
|
|
630
|
+
? (parseYYYYMMDDUtil(value) ?? undefined)
|
|
661
631
|
: parseToDate(isControlled ? value : internalValue);
|
|
662
632
|
const inputRef = useRef(null);
|
|
663
|
-
const [t] = useTranslation();
|
|
664
633
|
useImperativeHandle(ref, () => inputRef.current ?? document.createElement("input"), []);
|
|
665
634
|
const syncPendingFromValue = useCallback(() => {
|
|
666
635
|
setPendingDate(selectedDate ?? null);
|
|
@@ -694,7 +663,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
694
663
|
const minDate = parseToDate(min);
|
|
695
664
|
const maxDate = parseToDate(max);
|
|
696
665
|
const clamped = clampToRange(pendingDate, minDate, maxDate);
|
|
697
|
-
const str = clamped ?
|
|
666
|
+
const str = clamped ? dateToYYYYMMDDUtil(clamped) : "";
|
|
698
667
|
if (!isControlled)
|
|
699
668
|
setInternalValue(str);
|
|
700
669
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -702,12 +671,12 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
702
671
|
}, [isControlled, min, max, onChange, pendingDate]);
|
|
703
672
|
const handleInputChange = useCallback((e) => {
|
|
704
673
|
const raw = e.target.value;
|
|
705
|
-
const parsed =
|
|
674
|
+
const parsed = parseDateFieldInputForChange(raw, locale);
|
|
706
675
|
const minDate = parseToDate(min);
|
|
707
676
|
const maxDate = parseToDate(max);
|
|
708
677
|
if (parsed !== null) {
|
|
709
678
|
const clamped = clampToRange(parsed, minDate, maxDate);
|
|
710
|
-
const str = clamped ?
|
|
679
|
+
const str = clamped ? dateToYYYYMMDDUtil(clamped) : "";
|
|
711
680
|
if (!isControlled)
|
|
712
681
|
setInternalValue(str);
|
|
713
682
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -717,10 +686,10 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
717
686
|
setInternalValue(raw);
|
|
718
687
|
onChange?.(e);
|
|
719
688
|
}
|
|
720
|
-
}, [isControlled, min, max, onChange]);
|
|
689
|
+
}, [isControlled, locale, min, max, onChange]);
|
|
721
690
|
return (jsxs(Popover, { onOpenStateChange: open => open && syncPendingFromValue(), placement: "bottom-start", children: [jsx(PopoverTrigger, { children: jsx("div", { className: twMerge("flex w-full min-w-0 cursor-pointer items-center", (Boolean(rest.disabled) || Boolean(rest.readOnly)) && "pointer-events-none"), children: jsx(BaseInput, { ...rest, "aria-readonly": true, className: twMerge("w-full min-w-0", rest.className), "data-testid": dataTestId ? `${dataTestId}-input` : undefined, onChange: handleInputChange, placeholder: rest.placeholder ?? t("dateField.placeholder"), ref: inputRef, suffix: suffixProp ?? (jsx(Icon, { "aria-label": undefined, className: Boolean(rest.disabled) || Boolean(rest.readOnly) ? "text-neutral-500" : undefined, "data-testid": dataTestId ? `${dataTestId}-calendar` : "calendar", name: "Calendar", size: "medium", type: "solid" })), type: "text", value: resolvedValue }) }) }), jsx(PopoverContent, { children: closePopover => {
|
|
722
691
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
723
|
-
return (jsxs("div", { className: twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsx(ReactCalendar, { allowPartialRange: true, className: twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", onChange: val => {
|
|
692
|
+
return (jsxs("div", { className: twMerge("flex w-min flex-col overflow-hidden rounded-md border border-neutral-300 bg-white p-0"), children: [jsx(ReactCalendar, { allowPartialRange: true, className: twMerge("custom-day-picker", "range-picker", "p-0"), defaultActiveStartDate: displayDate ?? undefined, defaultView: "month", locale: locale, onChange: val => {
|
|
724
693
|
const next = val instanceof Date ? val : Array.isArray(val) ? (val[0] instanceof Date ? val[0] : null) : null;
|
|
725
694
|
handleCalendarChange(next);
|
|
726
695
|
}, selectRange: false, tileDisabled: tileDisabled, value: displayDate }), jsx("hr", {}), jsxs("div", { className: "flex w-full justify-between gap-2 px-4 py-3", children: [jsx(Button, { className: "mr-auto", "data-testid": dataTestId ? `${dataTestId}-clear-button` : undefined, onClick: () => handleClear(closePopover), size: "small", variant: "secondary", children: t("dateField.actions.clear") }), jsxs("div", { className: "flex gap-2", children: [jsx(Button, { "data-testid": dataTestId ? `${dataTestId}-cancel-button` : undefined, onClick: () => handleCancel(closePopover), size: "small", variant: "ghost-neutral", children: t("dateField.actions.cancel") }), jsx(Button, { "data-testid": dataTestId ? `${dataTestId}-apply-button` : undefined, onClick: () => handleApply(closePopover), size: "small", children: t("dateField.actions.apply") })] })] })] }));
|
|
@@ -2503,6 +2472,10 @@ ColorField.displayName = "ColorField";
|
|
|
2503
2472
|
|
|
2504
2473
|
/**
|
|
2505
2474
|
* The date field component is used for entering date values with a calendar picker (same UI as DayPicker).
|
|
2475
|
+
* The input shows a localized short date; when the user commits a valid day, `onChange` provides `YYYY-MM-DD`
|
|
2476
|
+
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils` for a local-midnight
|
|
2477
|
+
* `Date`). Do not parse `event.target.value` from `onBlur` — the visible string may be localized while
|
|
2478
|
+
* `onChange` stays canonical.
|
|
2506
2479
|
*
|
|
2507
2480
|
* ### When to use
|
|
2508
2481
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
|
@@ -2530,11 +2503,13 @@ ColorField.displayName = "ColorField";
|
|
|
2530
2503
|
* @example Date field with constraints
|
|
2531
2504
|
* ```tsx
|
|
2532
2505
|
* import { DateField } from "@trackunit/react-form-components";
|
|
2506
|
+
* import { dateToYYYYMMDDUtil } from "@trackunit/date-and-time-utils";
|
|
2533
2507
|
* import { useState } from "react";
|
|
2534
2508
|
*
|
|
2535
2509
|
* const BookingForm = () => {
|
|
2536
2510
|
* const [checkIn, setCheckIn] = useState("");
|
|
2537
|
-
*
|
|
2511
|
+
* // Use the local calendar day, not UTC (avoids day-shift in non-UTC zones).
|
|
2512
|
+
* const today = dateToYYYYMMDDUtil(new Date());
|
|
2538
2513
|
*
|
|
2539
2514
|
* return (
|
|
2540
2515
|
* <DateField
|
|
@@ -4930,4 +4905,4 @@ const useZodValidators = () => {
|
|
|
4930
4905
|
*/
|
|
4931
4906
|
setupLibraryTranslations();
|
|
4932
4907
|
|
|
4933
|
-
export { ActionButton, BaseInput, BaseSelect, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DEFAULT_TIME, DateBaseInput, DateField, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, FormFieldSelectAdapter, FormGroup, Label, MultiSelectField, NumberBaseInput, NumberField, OptionCard, PasswordBaseInput, PasswordField, PhoneBaseInput, PhoneField, PhoneFieldWithController, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, SelectField, TextAreaBaseInput, TextAreaField, TextBaseInput, TextField, TimeRange, TimeRangeField, ToggleSwitch, ToggleSwitchOption, UploadField, UploadInput, UrlField, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaAccessoriesContainer, cvaActionButton, cvaActionContainer, cvaInput$1 as cvaInput, cvaInputAddon, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputBaseReadOnly, cvaInputBaseSize, cvaInputElement, cvaInputGroup, cvaInputItemPlacementManager, cvaInputPrefix, cvaInputSuffix, cvaLabel, cvaRadioItem, cvaSelectClearIndicator, cvaSelectContainer, cvaSelectControl, cvaSelectDropdownIconContainer, cvaSelectDropdownIndicator, cvaSelectIndicatorsContainer, cvaSelectLoadingMessage, cvaSelectMenu, cvaSelectMenuList, cvaSelectMultiValue, cvaSelectNoOptionsMessage, cvaSelectPlaceholder, cvaSelectPrefixSuffix, cvaSelectSingleValue, cvaSelectValueContainer,
|
|
4908
|
+
export { ActionButton, BaseInput, BaseSelect, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DEFAULT_TIME, DateBaseInput, DateField, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, FormFieldSelectAdapter, FormGroup, Label, MultiSelectField, NumberBaseInput, NumberField, OptionCard, PasswordBaseInput, PasswordField, PhoneBaseInput, PhoneField, PhoneFieldWithController, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, SelectField, TextAreaBaseInput, TextAreaField, TextBaseInput, TextField, TimeRange, TimeRangeField, ToggleSwitch, ToggleSwitchOption, UploadField, UploadInput, UrlField, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaAccessoriesContainer, cvaActionButton, cvaActionContainer, cvaInput$1 as cvaInput, cvaInputAddon, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputBaseReadOnly, cvaInputBaseSize, cvaInputElement, cvaInputGroup, cvaInputItemPlacementManager, cvaInputPrefix, cvaInputSuffix, cvaLabel, cvaRadioItem, cvaSelectClearIndicator, cvaSelectContainer, cvaSelectControl, cvaSelectDropdownIconContainer, cvaSelectDropdownIndicator, cvaSelectIndicatorsContainer, cvaSelectLoadingMessage, cvaSelectMenu, cvaSelectMenuList, cvaSelectMultiValue, cvaSelectNoOptionsMessage, cvaSelectPlaceholder, cvaSelectPrefixSuffix, cvaSelectSingleValue, cvaSelectValueContainer, getCountryAbbreviation, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isValidHEXColor, parseSchedule, phoneErrorMessage, serializeSchedule, useCreatableSelect, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useRadioItemChecked, useSelect, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-form-components",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.4",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -9,7 +9,7 @@
|
|
|
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.
|
|
12
|
+
"@trackunit/date-and-time-utils": "1.11.102",
|
|
13
13
|
"usehooks-ts": "^3.1.0",
|
|
14
14
|
"libphonenumber-js": "^1.12.22",
|
|
15
15
|
"zod": "^3.25.76",
|
|
@@ -22,7 +22,8 @@ export interface DateBaseInputProps extends BaseInputExposedProps {
|
|
|
22
22
|
/**
|
|
23
23
|
* A wrapper around BaseInput with a pop-up day picker using the same calendar UI as DayPicker.
|
|
24
24
|
*
|
|
25
|
-
* The
|
|
25
|
+
* The input shows a locale-aware date (short month, numeric day and year, e.g. "Mar 23, 2026" in English).
|
|
26
|
+
* `onChange` still emits the canonical YYYY-MM-DD string for form parsing.
|
|
26
27
|
*
|
|
27
28
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
28
29
|
*/
|
|
@@ -10,6 +10,10 @@ export interface DateFieldProps extends DateBaseInputProps, FormGroupExposedProp
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* The date field component is used for entering date values with a calendar picker (same UI as DayPicker).
|
|
13
|
+
* The input shows a localized short date; when the user commits a valid day, `onChange` provides `YYYY-MM-DD`
|
|
14
|
+
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils` for a local-midnight
|
|
15
|
+
* `Date`). Do not parse `event.target.value` from `onBlur` — the visible string may be localized while
|
|
16
|
+
* `onChange` stays canonical.
|
|
13
17
|
*
|
|
14
18
|
* ### When to use
|
|
15
19
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
|
@@ -37,11 +41,13 @@ export interface DateFieldProps extends DateBaseInputProps, FormGroupExposedProp
|
|
|
37
41
|
* @example Date field with constraints
|
|
38
42
|
* ```tsx
|
|
39
43
|
* import { DateField } from "@trackunit/react-form-components";
|
|
44
|
+
* import { dateToYYYYMMDDUtil } from "@trackunit/date-and-time-utils";
|
|
40
45
|
* import { useState } from "react";
|
|
41
46
|
*
|
|
42
47
|
* const BookingForm = () => {
|
|
43
48
|
* const [checkIn, setCheckIn] = useState("");
|
|
44
|
-
*
|
|
49
|
+
* // Use the local calendar day, not UTC (avoids day-shift in non-UTC zones).
|
|
50
|
+
* const today = dateToYYYYMMDDUtil(new Date());
|
|
45
51
|
*
|
|
46
52
|
* return (
|
|
47
53
|
* <DateField
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses date-field keyboard input to a local-midnight {@link Date}.
|
|
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`.
|
|
8
|
+
*
|
|
9
|
+
* @param value - Raw text from the input.
|
|
10
|
+
* @param locale - Locale to compare against when the input is not `YYYY-MM-DD`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const parseDateFieldInputForChange: (value: string, locale: string | undefined) => Date | null;
|
|
13
|
+
/**
|
|
14
|
+
* Renders the stored date-field value for display:
|
|
15
|
+
* - empty string → empty
|
|
16
|
+
* - full canonical `YYYY-MM-DD` → locale-aware short date
|
|
17
|
+
* - partial input (e.g. `"2025-03"`) → returned as-is so the user can keep typing
|
|
18
|
+
*
|
|
19
|
+
* @param stored - The current canonical value (typically from `event.target.value`).
|
|
20
|
+
* @param locale - Locale for the display format.
|
|
21
|
+
*/
|
|
22
|
+
export declare const dateFieldStoredValueToDisplayString: (stored: string, locale: string | undefined) => string;
|
package/src/index.d.ts
CHANGED
|
@@ -53,7 +53,6 @@ export * from "./components/UploadField/UploadField";
|
|
|
53
53
|
export * from "./components/UploadInput/UploadInput";
|
|
54
54
|
export * from "./components/UrlField/UrlField";
|
|
55
55
|
export * from "./utilities/emailUtils";
|
|
56
|
-
export * from "./utilities/parseDateFieldValue";
|
|
57
56
|
export * from "./utilities/useGetPhoneValidationRules";
|
|
58
57
|
export * from "./utilities/usePhoneInput";
|
|
59
58
|
export * from "./utilities/useZodValidators";
|
package/translation.cjs.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Anwenden",
|
|
10
10
|
"dateField.actions.cancel": "Abbrechen",
|
|
11
11
|
"dateField.actions.clear": "Löschen",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Dateien per Drag & Drop hinzufügen",
|
|
14
13
|
"dropzone.label.default": "<clickable>Ordner durchsuchen</clickable> oder Dateien per Drag & Drop einfügen …",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
|
package/translation.cjs10.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Zastosuj",
|
|
10
10
|
"dateField.actions.cancel": "Anuluj",
|
|
11
11
|
"dateField.actions.clear": "Wyczyść",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Przeciągnij i upuść dane pliku",
|
|
14
13
|
"dropzone.label.default": "<clickable>Przeglądaj</clickable> lub przeciągnij pliki tutaj...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Wprowadź poprawny adres e-mail",
|
package/translation.cjs11.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Aplicar",
|
|
10
10
|
"dateField.actions.cancel": "Cancelar",
|
|
11
11
|
"dateField.actions.clear": "Apagar",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Arrastar-e-soltar entrada de ficheiro",
|
|
14
13
|
"dropzone.label.default": "<clickable>Procure</clickable> ou arraste os ficheiros aqui...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Introduza um endereço de e-mail válido",
|
package/translation.cjs12.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Применить",
|
|
10
10
|
"dateField.actions.cancel": "Отмена",
|
|
11
11
|
"dateField.actions.clear": "Очистить",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Перетаскивание ввода файла",
|
|
14
13
|
"dropzone.label.default": "<clickable>Просмотрите</clickable> или перетащите файлы сюда...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Введите действительный адрес эл. почты",
|
package/translation.cjs13.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Aplicare",
|
|
10
10
|
"dateField.actions.cancel": "Anulare",
|
|
11
11
|
"dateField.actions.clear": "Ștergere",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Intrare fișier drag-and-drop",
|
|
14
13
|
"dropzone.label.default": "<clickable>Răsfoiți</clickable> sau trageți fișiere aici...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Vă rugăm să introduceți o adresă de e-mail valabilă",
|
package/translation.cjs14.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Aplicar",
|
|
10
10
|
"dateField.actions.cancel": "Cancelar",
|
|
11
11
|
"dateField.actions.clear": "Restablecer",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Entrada Arrastrar y soltar archivo",
|
|
14
13
|
"dropzone.label.default": "<clickable>Explore</clickable> o arrastre archivos aquí...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Introduzca una dirección de correo electrónico válida",
|
package/translation.cjs15.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Tillämpa",
|
|
10
10
|
"dateField.actions.cancel": "Avbryt",
|
|
11
11
|
"dateField.actions.clear": "Rensa",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Dra och släpp fil",
|
|
14
13
|
"dropzone.label.default": "<clickable>Bläddra</clickable> bland filerna eller dra dem hit...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Ange en giltig e-postadress",
|
package/translation.cjs16.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "適用",
|
|
10
10
|
"dateField.actions.cancel": "キャンセル",
|
|
11
11
|
"dateField.actions.clear": "クリア",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "ドラッグ&ドロップによるファイル入力",
|
|
14
13
|
"dropzone.label.default": "<clickable>ファイルを選択</clickable>またはここにファイルをドラッグ",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "有効なメールアドレスを入力してください",
|
package/translation.cjs17.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "นำไปใช้",
|
|
10
10
|
"dateField.actions.cancel": "ยกเลิก",
|
|
11
11
|
"dateField.actions.clear": "ล้าง",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "ลากและวางอินพุตไฟล์",
|
|
14
13
|
"dropzone.label.default": "<clickable>เรียกดู</clickable> หรือลากไฟล์มาที่นี่...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "โปรดป้อนที่อยู่อีเมลที่ถูกต้อง",
|
package/translation.cjs2.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Anvend",
|
|
10
10
|
"dateField.actions.cancel": "Annuller",
|
|
11
11
|
"dateField.actions.clear": "Ryd",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Filinput via drag-and-drop",
|
|
14
13
|
"dropzone.label.default": "<clickable>Gennemse</clickable> eller træk filer her...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.cjs3.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Použít",
|
|
10
10
|
"dateField.actions.cancel": "Zrušit",
|
|
11
11
|
"dateField.actions.clear": "Vymazat",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Přetažení vstupu do souboru",
|
|
14
13
|
"dropzone.label.default": "<clickable>Procházejte</clickable> nebo přetáhněte soubory zde...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Zadejte platnou e-mailovou adresu",
|
package/translation.cjs4.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Toepassen",
|
|
10
10
|
"dateField.actions.cancel": "Annuleren",
|
|
11
11
|
"dateField.actions.clear": "Wissen",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Drag-en-drop bestandsinvoer",
|
|
14
13
|
"dropzone.label.default": "<clickable>Bladeren</clickable> of sleep bestanden hier naartoe...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.cjs5.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Appliquer",
|
|
10
10
|
"dateField.actions.cancel": "Annuler",
|
|
11
11
|
"dateField.actions.clear": "Effacer",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Ajout de fichiers par glisser-déposer",
|
|
14
13
|
"dropzone.label.default": "<clickable>Parcourir</clickable> ou faire glisser les fichiers ici...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Veuillez saisir une adresse e-mail valide",
|
package/translation.cjs6.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Käytä",
|
|
10
10
|
"dateField.actions.cancel": "Peruuta",
|
|
11
11
|
"dateField.actions.clear": "Tyhjennä",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Vedä ja pudota tiedostosyöte",
|
|
14
13
|
"dropzone.label.default": "<clickable>Selaa</clickable> tai vedä tiedostoja täältä...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.cjs7.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Alkalmaz",
|
|
10
10
|
"dateField.actions.cancel": "Mégse",
|
|
11
11
|
"dateField.actions.clear": "Törlés",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Húzza ide a fájl(oka)t",
|
|
14
13
|
"dropzone.label.default": "<clickable>Keresse meg</clickable> vagy húza ide a fájlokat…",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.cjs8.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Applica",
|
|
10
10
|
"dateField.actions.cancel": "Annulla",
|
|
11
11
|
"dateField.actions.clear": "Cancella",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Inserimento di file tramite Trascina e rilascia",
|
|
14
13
|
"dropzone.label.default": "<clickable>Sfoglia</clickable> o trascina i file qui...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Inserisci un indirizzo email valido",
|
package/translation.cjs9.js
CHANGED
|
@@ -9,7 +9,6 @@ var translation = {
|
|
|
9
9
|
"dateField.actions.apply": "Bruk",
|
|
10
10
|
"dateField.actions.cancel": "Avbryt",
|
|
11
11
|
"dateField.actions.clear": "Tøm",
|
|
12
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
13
12
|
"dropzone.input.title": "Dra og slipp for å legge inn fil",
|
|
14
13
|
"dropzone.label.default": "<clickable>Bla gjennom</clickable> eller dra filer hit...",
|
|
15
14
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.esm.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Anwenden",
|
|
8
8
|
"dateField.actions.cancel": "Abbrechen",
|
|
9
9
|
"dateField.actions.clear": "Löschen",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Dateien per Drag & Drop hinzufügen",
|
|
12
11
|
"dropzone.label.default": "<clickable>Ordner durchsuchen</clickable> oder Dateien per Drag & Drop einfügen …",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
|
package/translation.esm10.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Zastosuj",
|
|
8
8
|
"dateField.actions.cancel": "Anuluj",
|
|
9
9
|
"dateField.actions.clear": "Wyczyść",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Przeciągnij i upuść dane pliku",
|
|
12
11
|
"dropzone.label.default": "<clickable>Przeglądaj</clickable> lub przeciągnij pliki tutaj...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Wprowadź poprawny adres e-mail",
|
package/translation.esm11.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Aplicar",
|
|
8
8
|
"dateField.actions.cancel": "Cancelar",
|
|
9
9
|
"dateField.actions.clear": "Apagar",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Arrastar-e-soltar entrada de ficheiro",
|
|
12
11
|
"dropzone.label.default": "<clickable>Procure</clickable> ou arraste os ficheiros aqui...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Introduza um endereço de e-mail válido",
|
package/translation.esm12.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Применить",
|
|
8
8
|
"dateField.actions.cancel": "Отмена",
|
|
9
9
|
"dateField.actions.clear": "Очистить",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Перетаскивание ввода файла",
|
|
12
11
|
"dropzone.label.default": "<clickable>Просмотрите</clickable> или перетащите файлы сюда...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Введите действительный адрес эл. почты",
|
package/translation.esm13.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Aplicare",
|
|
8
8
|
"dateField.actions.cancel": "Anulare",
|
|
9
9
|
"dateField.actions.clear": "Ștergere",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Intrare fișier drag-and-drop",
|
|
12
11
|
"dropzone.label.default": "<clickable>Răsfoiți</clickable> sau trageți fișiere aici...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Vă rugăm să introduceți o adresă de e-mail valabilă",
|
package/translation.esm14.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Aplicar",
|
|
8
8
|
"dateField.actions.cancel": "Cancelar",
|
|
9
9
|
"dateField.actions.clear": "Restablecer",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Entrada Arrastrar y soltar archivo",
|
|
12
11
|
"dropzone.label.default": "<clickable>Explore</clickable> o arrastre archivos aquí...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Introduzca una dirección de correo electrónico válida",
|
package/translation.esm15.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Tillämpa",
|
|
8
8
|
"dateField.actions.cancel": "Avbryt",
|
|
9
9
|
"dateField.actions.clear": "Rensa",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Dra och släpp fil",
|
|
12
11
|
"dropzone.label.default": "<clickable>Bläddra</clickable> bland filerna eller dra dem hit...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Ange en giltig e-postadress",
|
package/translation.esm16.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "適用",
|
|
8
8
|
"dateField.actions.cancel": "キャンセル",
|
|
9
9
|
"dateField.actions.clear": "クリア",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "ドラッグ&ドロップによるファイル入力",
|
|
12
11
|
"dropzone.label.default": "<clickable>ファイルを選択</clickable>またはここにファイルをドラッグ",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "有効なメールアドレスを入力してください",
|
package/translation.esm17.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "นำไปใช้",
|
|
8
8
|
"dateField.actions.cancel": "ยกเลิก",
|
|
9
9
|
"dateField.actions.clear": "ล้าง",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "ลากและวางอินพุตไฟล์",
|
|
12
11
|
"dropzone.label.default": "<clickable>เรียกดู</clickable> หรือลากไฟล์มาที่นี่...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "โปรดป้อนที่อยู่อีเมลที่ถูกต้อง",
|
package/translation.esm2.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Anvend",
|
|
8
8
|
"dateField.actions.cancel": "Annuller",
|
|
9
9
|
"dateField.actions.clear": "Ryd",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Filinput via drag-and-drop",
|
|
12
11
|
"dropzone.label.default": "<clickable>Gennemse</clickable> eller træk filer her...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.esm3.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Použít",
|
|
8
8
|
"dateField.actions.cancel": "Zrušit",
|
|
9
9
|
"dateField.actions.clear": "Vymazat",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Přetažení vstupu do souboru",
|
|
12
11
|
"dropzone.label.default": "<clickable>Procházejte</clickable> nebo přetáhněte soubory zde...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Zadejte platnou e-mailovou adresu",
|
package/translation.esm4.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Toepassen",
|
|
8
8
|
"dateField.actions.cancel": "Annuleren",
|
|
9
9
|
"dateField.actions.clear": "Wissen",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Drag-en-drop bestandsinvoer",
|
|
12
11
|
"dropzone.label.default": "<clickable>Bladeren</clickable> of sleep bestanden hier naartoe...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.esm5.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Appliquer",
|
|
8
8
|
"dateField.actions.cancel": "Annuler",
|
|
9
9
|
"dateField.actions.clear": "Effacer",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Ajout de fichiers par glisser-déposer",
|
|
12
11
|
"dropzone.label.default": "<clickable>Parcourir</clickable> ou faire glisser les fichiers ici...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Veuillez saisir une adresse e-mail valide",
|
package/translation.esm6.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Käytä",
|
|
8
8
|
"dateField.actions.cancel": "Peruuta",
|
|
9
9
|
"dateField.actions.clear": "Tyhjennä",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Vedä ja pudota tiedostosyöte",
|
|
12
11
|
"dropzone.label.default": "<clickable>Selaa</clickable> tai vedä tiedostoja täältä...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.esm7.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Alkalmaz",
|
|
8
8
|
"dateField.actions.cancel": "Mégse",
|
|
9
9
|
"dateField.actions.clear": "Törlés",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Húzza ide a fájl(oka)t",
|
|
12
11
|
"dropzone.label.default": "<clickable>Keresse meg</clickable> vagy húza ide a fájlokat…",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
package/translation.esm8.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Applica",
|
|
8
8
|
"dateField.actions.cancel": "Annulla",
|
|
9
9
|
"dateField.actions.clear": "Cancella",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Inserimento di file tramite Trascina e rilascia",
|
|
12
11
|
"dropzone.label.default": "<clickable>Sfoglia</clickable> o trascina i file qui...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Inserisci un indirizzo email valido",
|
package/translation.esm9.js
CHANGED
|
@@ -7,7 +7,6 @@ var translation = {
|
|
|
7
7
|
"dateField.actions.apply": "Bruk",
|
|
8
8
|
"dateField.actions.cancel": "Avbryt",
|
|
9
9
|
"dateField.actions.clear": "Tøm",
|
|
10
|
-
"dateField.placeholder": "yyyy-mm-dd",
|
|
11
10
|
"dropzone.input.title": "Dra og slipp for å legge inn fil",
|
|
12
11
|
"dropzone.label.default": "<clickable>Bla gjennom</clickable> eller dra filer hit...",
|
|
13
12
|
"emailField.error.INVALID_EMAIL": "Please enter a valid email address",
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parses the value from a DateField change event (YYYY-MM-DD string) to a Date at local midnight.
|
|
3
|
-
* Use this when you need a Date from event.target.value to avoid timezone shifts that occur
|
|
4
|
-
* with `new Date(value)` (which interprets the string as UTC).
|
|
5
|
-
*
|
|
6
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
7
|
-
* @returns {Date | null} - Date at local midnight for the given day, or null if value is empty or invalid
|
|
8
|
-
*/
|
|
9
|
-
export declare function parseDateFieldValue(value: string): Date | null;
|
|
10
|
-
/**
|
|
11
|
-
* Converts a YYYY-MM-DD string (e.g. from DateField) to an ISO string at UTC midnight for that calendar day.
|
|
12
|
-
* Use this when storing or sending date-only values so that the calendar day is preserved regardless of
|
|
13
|
-
* user timezone (unlike calling .toISOString() on a local-midnight Date, which shifts the day for UTC+).
|
|
14
|
-
*
|
|
15
|
-
* @param value - The string from event.target.value (e.g. "2025-03-07" or "")
|
|
16
|
-
* @returns {string | null} - "YYYY-MM-DDT00:00:00.000Z" or null if value is empty or invalid
|
|
17
|
-
*/
|
|
18
|
-
export declare function toISODateStringUTC(value: string): string | null;
|
|
19
|
-
/**
|
|
20
|
-
* Converts a Date (e.g. at local midnight) to an ISO string at UTC midnight for the same calendar day.
|
|
21
|
-
* Use when sending a date-only value to an API that expects UTC midnight (e.g. booking date).
|
|
22
|
-
*
|
|
23
|
-
* @param date - A Date instance (typically local midnight from a date picker)
|
|
24
|
-
* @returns {string} "YYYY-MM-DDT00:00:00.000Z" for that calendar day
|
|
25
|
-
*/
|
|
26
|
-
export declare function dateToISODateUTC(date: Date): string;
|