@trackunit/react-form-components 1.22.28 → 1.23.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
|
@@ -696,7 +696,7 @@ function parseToDate(v) {
|
|
|
696
696
|
*
|
|
697
697
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
698
698
|
*/
|
|
699
|
-
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
699
|
+
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, onBlur, ...rest }) => {
|
|
700
700
|
const timeZoneId = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
701
701
|
const isControlled = value !== undefined;
|
|
702
702
|
const [internalValue, setInternalValue] = react.useState(() => dateToCalendarDayString({ date: parseToDate(defaultValue), timeZoneId }));
|
|
@@ -766,7 +766,27 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
766
766
|
onChange?.(e);
|
|
767
767
|
}
|
|
768
768
|
}, [createInputChangeEvent, isControlled, locale, min, max, onChange, timeZoneId]);
|
|
769
|
-
|
|
769
|
+
const handleBlur = react.useCallback((e) => {
|
|
770
|
+
if (!onBlur)
|
|
771
|
+
return;
|
|
772
|
+
const storedValue = isControlled
|
|
773
|
+
? typeof value === "string"
|
|
774
|
+
? value
|
|
775
|
+
: dateToCalendarDayString({ date: parseToDate(value), timeZoneId })
|
|
776
|
+
: internalValue;
|
|
777
|
+
// When the stored value is a committed calendar day (YYYY-MM-DD) we expose it on blur, even though the
|
|
778
|
+
// displayed input value is localized.
|
|
779
|
+
const shouldExposeStoredValue = storedValue === "" || dateAndTimeUtils.parseYYYYMMDDUtil(storedValue) !== null;
|
|
780
|
+
if (!shouldExposeStoredValue) {
|
|
781
|
+
onBlur(e);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const prev = e.currentTarget.value;
|
|
785
|
+
e.currentTarget.value = storedValue;
|
|
786
|
+
onBlur(e);
|
|
787
|
+
e.currentTarget.value = prev;
|
|
788
|
+
}, [internalValue, isControlled, onBlur, timeZoneId, value]);
|
|
789
|
+
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, onBlur: handleBlur, 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 => {
|
|
770
790
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
771
791
|
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 => {
|
|
772
792
|
const next = val instanceof Date ? val : Array.isArray(val) ? (val[0] instanceof Date ? val[0] : null) : null;
|
|
@@ -2551,10 +2571,9 @@ ColorField.displayName = "ColorField";
|
|
|
2551
2571
|
|
|
2552
2572
|
/**
|
|
2553
2573
|
* The date field component is used for entering date values with a calendar picker (same UI as DayPicker).
|
|
2554
|
-
* The input shows a localized short date; when the user commits a valid day, `onChange`
|
|
2555
|
-
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
2556
|
-
* `Date`).
|
|
2557
|
-
* `onChange` stays canonical.
|
|
2574
|
+
* The input shows a localized short date; when the user commits a valid day, both `onChange` and `onBlur`
|
|
2575
|
+
* expose `YYYY-MM-DD` on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
2576
|
+
* for a local-midnight `Date`).
|
|
2558
2577
|
*
|
|
2559
2578
|
* ### When to use
|
|
2560
2579
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
package/index.esm.js
CHANGED
|
@@ -695,7 +695,7 @@ function parseToDate(v) {
|
|
|
695
695
|
*
|
|
696
696
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
697
697
|
*/
|
|
698
|
-
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
698
|
+
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, onBlur, ...rest }) => {
|
|
699
699
|
const timeZoneId = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
700
700
|
const isControlled = value !== undefined;
|
|
701
701
|
const [internalValue, setInternalValue] = useState(() => dateToCalendarDayString({ date: parseToDate(defaultValue), timeZoneId }));
|
|
@@ -765,7 +765,27 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
765
765
|
onChange?.(e);
|
|
766
766
|
}
|
|
767
767
|
}, [createInputChangeEvent, isControlled, locale, min, max, onChange, timeZoneId]);
|
|
768
|
-
|
|
768
|
+
const handleBlur = useCallback((e) => {
|
|
769
|
+
if (!onBlur)
|
|
770
|
+
return;
|
|
771
|
+
const storedValue = isControlled
|
|
772
|
+
? typeof value === "string"
|
|
773
|
+
? value
|
|
774
|
+
: dateToCalendarDayString({ date: parseToDate(value), timeZoneId })
|
|
775
|
+
: internalValue;
|
|
776
|
+
// When the stored value is a committed calendar day (YYYY-MM-DD) we expose it on blur, even though the
|
|
777
|
+
// displayed input value is localized.
|
|
778
|
+
const shouldExposeStoredValue = storedValue === "" || parseYYYYMMDDUtil(storedValue) !== null;
|
|
779
|
+
if (!shouldExposeStoredValue) {
|
|
780
|
+
onBlur(e);
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
const prev = e.currentTarget.value;
|
|
784
|
+
e.currentTarget.value = storedValue;
|
|
785
|
+
onBlur(e);
|
|
786
|
+
e.currentTarget.value = prev;
|
|
787
|
+
}, [internalValue, isControlled, onBlur, timeZoneId, value]);
|
|
788
|
+
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, onBlur: handleBlur, 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 => {
|
|
769
789
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
770
790
|
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 => {
|
|
771
791
|
const next = val instanceof Date ? val : Array.isArray(val) ? (val[0] instanceof Date ? val[0] : null) : null;
|
|
@@ -2550,10 +2570,9 @@ ColorField.displayName = "ColorField";
|
|
|
2550
2570
|
|
|
2551
2571
|
/**
|
|
2552
2572
|
* The date field component is used for entering date values with a calendar picker (same UI as DayPicker).
|
|
2553
|
-
* The input shows a localized short date; when the user commits a valid day, `onChange`
|
|
2554
|
-
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
2555
|
-
* `Date`).
|
|
2556
|
-
* `onChange` stays canonical.
|
|
2573
|
+
* The input shows a localized short date; when the user commits a valid day, both `onChange` and `onBlur`
|
|
2574
|
+
* expose `YYYY-MM-DD` on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
2575
|
+
* for a local-midnight `Date`).
|
|
2557
2576
|
*
|
|
2558
2577
|
* ### When to use
|
|
2559
2578
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-form-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@trackunit/ui-icons": "1.11.111",
|
|
20
20
|
"@trackunit/shared-utils": "1.13.115",
|
|
21
21
|
"@trackunit/ui-design-tokens": "1.11.112",
|
|
22
|
-
"@trackunit/i18n-library-translation": "1.
|
|
22
|
+
"@trackunit/i18n-library-translation": "1.19.0",
|
|
23
23
|
"string-ts": "^2.0.0",
|
|
24
24
|
"es-toolkit": "^1.39.10"
|
|
25
25
|
},
|
|
@@ -27,5 +27,5 @@ export interface DateBaseInputProps extends BaseInputExposedProps {
|
|
|
27
27
|
*
|
|
28
28
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
29
29
|
*/
|
|
30
|
-
export declare const DateBaseInput: ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }: DateBaseInputProps) => ReactElement;
|
|
30
|
+
export declare const DateBaseInput: ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, onBlur, ...rest }: DateBaseInputProps) => ReactElement;
|
|
31
31
|
export {};
|
|
@@ -10,10 +10,9 @@ 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`
|
|
14
|
-
* on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
15
|
-
* `Date`).
|
|
16
|
-
* `onChange` stays canonical.
|
|
13
|
+
* The input shows a localized short date; when the user commits a valid day, both `onChange` and `onBlur`
|
|
14
|
+
* expose `YYYY-MM-DD` on `event.target.value` (use `parseYYYYMMDDUtil` from `@trackunit/date-and-time-utils`
|
|
15
|
+
* for a local-midnight `Date`).
|
|
17
16
|
*
|
|
18
17
|
* ### When to use
|
|
19
18
|
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|