@trackunit/react-form-components 1.22.16 → 1.22.18
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
|
@@ -623,6 +623,50 @@ const dateFieldStoredValueToDisplayString = (stored, locale) => {
|
|
|
623
623
|
return stored;
|
|
624
624
|
};
|
|
625
625
|
|
|
626
|
+
/**
|
|
627
|
+
* Converts a Date instant to the canonical YYYY-MM-DD for a specific IANA time zone.
|
|
628
|
+
* This preserves the calendar day the user selected in their local zone.
|
|
629
|
+
*/
|
|
630
|
+
const dateToCalendarDayString = ({ date, timeZoneId }) => {
|
|
631
|
+
if (!date || Number.isNaN(date.getTime()))
|
|
632
|
+
return "";
|
|
633
|
+
const resolvedTimeZoneId = timeZoneId ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
634
|
+
return dateAndTimeUtils.toZonedDateTimeUtil(date, resolvedTimeZoneId).toPlainDate().toString();
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* Clamps a date to [minDate, maxDate] by comparing calendar days in a specific timezone.
|
|
638
|
+
* Returns the original `date` when it's in range, or the relevant boundary date when out of range.
|
|
639
|
+
*/
|
|
640
|
+
const clampDateToCalendarDayRange = ({ date, minDate, maxDate, timeZoneId, }) => {
|
|
641
|
+
if (date === null || date === undefined)
|
|
642
|
+
return null;
|
|
643
|
+
const day = dateToCalendarDayString({ date, timeZoneId });
|
|
644
|
+
if (day === "")
|
|
645
|
+
return null;
|
|
646
|
+
if (minDate !== undefined) {
|
|
647
|
+
const minDay = dateToCalendarDayString({ date: minDate, timeZoneId });
|
|
648
|
+
if (minDay !== "" && day < minDay)
|
|
649
|
+
return minDate;
|
|
650
|
+
}
|
|
651
|
+
if (maxDate !== undefined) {
|
|
652
|
+
const maxDay = dateToCalendarDayString({ date: maxDate, timeZoneId });
|
|
653
|
+
if (maxDay !== "" && day > maxDay)
|
|
654
|
+
return maxDate;
|
|
655
|
+
}
|
|
656
|
+
return date;
|
|
657
|
+
};
|
|
658
|
+
/**
|
|
659
|
+
* Returns true when a date falls outside [minDate, maxDate] by calendar day in a specific timezone.
|
|
660
|
+
*/
|
|
661
|
+
const isCalendarDayOutOfRange = ({ date, minDate, maxDate, timeZoneId, }) => {
|
|
662
|
+
if (!date)
|
|
663
|
+
return false;
|
|
664
|
+
const clamped = clampDateToCalendarDayRange({ date, minDate, maxDate, timeZoneId });
|
|
665
|
+
if (!clamped)
|
|
666
|
+
return false;
|
|
667
|
+
return clamped.getTime() !== date.getTime();
|
|
668
|
+
};
|
|
669
|
+
|
|
626
670
|
function parseToDate(v) {
|
|
627
671
|
if (v === undefined || v === "")
|
|
628
672
|
return undefined;
|
|
@@ -639,20 +683,6 @@ function parseToDate(v) {
|
|
|
639
683
|
const fallback = new Date(str);
|
|
640
684
|
return Number.isNaN(fallback.getTime()) ? undefined : fallback;
|
|
641
685
|
}
|
|
642
|
-
function startOfDayMs(d) {
|
|
643
|
-
return dateAndTimeUtils.toDateUtil(dateAndTimeUtils.startOfDayUtil(d)).getTime();
|
|
644
|
-
}
|
|
645
|
-
/** Clamp a date to [minDate, maxDate]; returns the same date if in range or no bounds. */
|
|
646
|
-
function clampToRange(date, minDate, maxDate) {
|
|
647
|
-
if (date === null || date === undefined)
|
|
648
|
-
return null;
|
|
649
|
-
const dayStart = startOfDayMs(date);
|
|
650
|
-
if (minDate !== undefined && dayStart < startOfDayMs(minDate))
|
|
651
|
-
return minDate;
|
|
652
|
-
if (maxDate !== undefined && dayStart > startOfDayMs(maxDate))
|
|
653
|
-
return maxDate;
|
|
654
|
-
return date;
|
|
655
|
-
}
|
|
656
686
|
/**
|
|
657
687
|
* A wrapper around BaseInput with a pop-up day picker using the same calendar UI as DayPicker.
|
|
658
688
|
*
|
|
@@ -662,8 +692,9 @@ function clampToRange(date, minDate, maxDate) {
|
|
|
662
692
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
663
693
|
*/
|
|
664
694
|
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
695
|
+
const timeZoneId = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
665
696
|
const isControlled = value !== undefined;
|
|
666
|
-
const [internalValue, setInternalValue] = react.useState(() =>
|
|
697
|
+
const [internalValue, setInternalValue] = react.useState(() => dateToCalendarDayString({ date: parseToDate(defaultValue), timeZoneId }));
|
|
667
698
|
const [pendingDate, setPendingDate] = react.useState(null);
|
|
668
699
|
const [t, i18n] = useTranslation();
|
|
669
700
|
const locale = i18n.resolvedLanguage ?? i18n.language;
|
|
@@ -671,7 +702,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
671
702
|
const resolvedValue = isControlled
|
|
672
703
|
? typeof value === "string"
|
|
673
704
|
? dateFieldStoredValueToDisplayString(value, locale)
|
|
674
|
-
: dateFieldStoredValueToDisplayString(
|
|
705
|
+
: dateFieldStoredValueToDisplayString(dateToCalendarDayString({ date: parseToDate(value), timeZoneId }), locale)
|
|
675
706
|
: dateFieldStoredValueToDisplayString(internalValue, locale);
|
|
676
707
|
const selectedDate = isControlled && typeof value === "string"
|
|
677
708
|
? (dateAndTimeUtils.parseYYYYMMDDUtil(value) ?? undefined)
|
|
@@ -686,13 +717,8 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
686
717
|
return false;
|
|
687
718
|
const minDate = parseToDate(min);
|
|
688
719
|
const maxDate = parseToDate(max);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
return true;
|
|
692
|
-
if (maxDate !== undefined && dayStart > startOfDayMs(maxDate))
|
|
693
|
-
return true;
|
|
694
|
-
return false;
|
|
695
|
-
}, [min, max]);
|
|
720
|
+
return isCalendarDayOutOfRange({ date, minDate, maxDate, timeZoneId });
|
|
721
|
+
}, [min, max, timeZoneId]);
|
|
696
722
|
const handleCalendarChange = react.useCallback((next) => {
|
|
697
723
|
setPendingDate(next);
|
|
698
724
|
}, []);
|
|
@@ -709,21 +735,21 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
709
735
|
const handleApply = react.useCallback((closePopover) => {
|
|
710
736
|
const minDate = parseToDate(min);
|
|
711
737
|
const maxDate = parseToDate(max);
|
|
712
|
-
const clamped =
|
|
713
|
-
const str = clamped ?
|
|
738
|
+
const clamped = clampDateToCalendarDayRange({ date: pendingDate, minDate, maxDate, timeZoneId });
|
|
739
|
+
const str = clamped ? dateToCalendarDayString({ date: clamped, timeZoneId }) : "";
|
|
714
740
|
if (!isControlled)
|
|
715
741
|
setInternalValue(str);
|
|
716
742
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
717
743
|
closePopover();
|
|
718
|
-
}, [isControlled, min, max, onChange, pendingDate]);
|
|
744
|
+
}, [isControlled, min, max, onChange, pendingDate, timeZoneId]);
|
|
719
745
|
const handleInputChange = react.useCallback((e) => {
|
|
720
746
|
const raw = e.target.value;
|
|
721
747
|
const parsed = parseDateFieldInputForChange(raw, locale);
|
|
722
748
|
const minDate = parseToDate(min);
|
|
723
749
|
const maxDate = parseToDate(max);
|
|
724
750
|
if (parsed !== null) {
|
|
725
|
-
const clamped =
|
|
726
|
-
const str = clamped ?
|
|
751
|
+
const clamped = clampDateToCalendarDayRange({ date: parsed, minDate, maxDate, timeZoneId });
|
|
752
|
+
const str = clamped ? dateToCalendarDayString({ date: clamped, timeZoneId }) : "";
|
|
727
753
|
if (!isControlled)
|
|
728
754
|
setInternalValue(str);
|
|
729
755
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -733,7 +759,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
733
759
|
setInternalValue(raw);
|
|
734
760
|
onChange?.(e);
|
|
735
761
|
}
|
|
736
|
-
}, [isControlled, locale, min, max, onChange]);
|
|
762
|
+
}, [isControlled, locale, min, max, onChange, timeZoneId]);
|
|
737
763
|
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 => {
|
|
738
764
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
739
765
|
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 => {
|
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 { parseYYYYMMDDUtil, formatShortDateUtil, parseValidDate, toDateUtil, startOfDayUtil,
|
|
3
|
+
import { parseYYYYMMDDUtil, formatShortDateUtil, parseValidDate, toDateUtil, startOfDayUtil, toZonedDateTimeUtil } 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';
|
|
@@ -622,6 +622,50 @@ const dateFieldStoredValueToDisplayString = (stored, locale) => {
|
|
|
622
622
|
return stored;
|
|
623
623
|
};
|
|
624
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Converts a Date instant to the canonical YYYY-MM-DD for a specific IANA time zone.
|
|
627
|
+
* This preserves the calendar day the user selected in their local zone.
|
|
628
|
+
*/
|
|
629
|
+
const dateToCalendarDayString = ({ date, timeZoneId }) => {
|
|
630
|
+
if (!date || Number.isNaN(date.getTime()))
|
|
631
|
+
return "";
|
|
632
|
+
const resolvedTimeZoneId = timeZoneId ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
633
|
+
return toZonedDateTimeUtil(date, resolvedTimeZoneId).toPlainDate().toString();
|
|
634
|
+
};
|
|
635
|
+
/**
|
|
636
|
+
* Clamps a date to [minDate, maxDate] by comparing calendar days in a specific timezone.
|
|
637
|
+
* Returns the original `date` when it's in range, or the relevant boundary date when out of range.
|
|
638
|
+
*/
|
|
639
|
+
const clampDateToCalendarDayRange = ({ date, minDate, maxDate, timeZoneId, }) => {
|
|
640
|
+
if (date === null || date === undefined)
|
|
641
|
+
return null;
|
|
642
|
+
const day = dateToCalendarDayString({ date, timeZoneId });
|
|
643
|
+
if (day === "")
|
|
644
|
+
return null;
|
|
645
|
+
if (minDate !== undefined) {
|
|
646
|
+
const minDay = dateToCalendarDayString({ date: minDate, timeZoneId });
|
|
647
|
+
if (minDay !== "" && day < minDay)
|
|
648
|
+
return minDate;
|
|
649
|
+
}
|
|
650
|
+
if (maxDate !== undefined) {
|
|
651
|
+
const maxDay = dateToCalendarDayString({ date: maxDate, timeZoneId });
|
|
652
|
+
if (maxDay !== "" && day > maxDay)
|
|
653
|
+
return maxDate;
|
|
654
|
+
}
|
|
655
|
+
return date;
|
|
656
|
+
};
|
|
657
|
+
/**
|
|
658
|
+
* Returns true when a date falls outside [minDate, maxDate] by calendar day in a specific timezone.
|
|
659
|
+
*/
|
|
660
|
+
const isCalendarDayOutOfRange = ({ date, minDate, maxDate, timeZoneId, }) => {
|
|
661
|
+
if (!date)
|
|
662
|
+
return false;
|
|
663
|
+
const clamped = clampDateToCalendarDayRange({ date, minDate, maxDate, timeZoneId });
|
|
664
|
+
if (!clamped)
|
|
665
|
+
return false;
|
|
666
|
+
return clamped.getTime() !== date.getTime();
|
|
667
|
+
};
|
|
668
|
+
|
|
625
669
|
function parseToDate(v) {
|
|
626
670
|
if (v === undefined || v === "")
|
|
627
671
|
return undefined;
|
|
@@ -638,20 +682,6 @@ function parseToDate(v) {
|
|
|
638
682
|
const fallback = new Date(str);
|
|
639
683
|
return Number.isNaN(fallback.getTime()) ? undefined : fallback;
|
|
640
684
|
}
|
|
641
|
-
function startOfDayMs(d) {
|
|
642
|
-
return toDateUtil(startOfDayUtil(d)).getTime();
|
|
643
|
-
}
|
|
644
|
-
/** Clamp a date to [minDate, maxDate]; returns the same date if in range or no bounds. */
|
|
645
|
-
function clampToRange(date, minDate, maxDate) {
|
|
646
|
-
if (date === null || date === undefined)
|
|
647
|
-
return null;
|
|
648
|
-
const dayStart = startOfDayMs(date);
|
|
649
|
-
if (minDate !== undefined && dayStart < startOfDayMs(minDate))
|
|
650
|
-
return minDate;
|
|
651
|
-
if (maxDate !== undefined && dayStart > startOfDayMs(maxDate))
|
|
652
|
-
return maxDate;
|
|
653
|
-
return date;
|
|
654
|
-
}
|
|
655
685
|
/**
|
|
656
686
|
* A wrapper around BaseInput with a pop-up day picker using the same calendar UI as DayPicker.
|
|
657
687
|
*
|
|
@@ -661,8 +691,9 @@ function clampToRange(date, minDate, maxDate) {
|
|
|
661
691
|
* NOTE: If shown with a label, please use the `DateField` component instead.
|
|
662
692
|
*/
|
|
663
693
|
const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: suffixProp, "data-testid": dataTestId, ...rest }) => {
|
|
694
|
+
const timeZoneId = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
664
695
|
const isControlled = value !== undefined;
|
|
665
|
-
const [internalValue, setInternalValue] = useState(() =>
|
|
696
|
+
const [internalValue, setInternalValue] = useState(() => dateToCalendarDayString({ date: parseToDate(defaultValue), timeZoneId }));
|
|
666
697
|
const [pendingDate, setPendingDate] = useState(null);
|
|
667
698
|
const [t, i18n] = useTranslation();
|
|
668
699
|
const locale = i18n.resolvedLanguage ?? i18n.language;
|
|
@@ -670,7 +701,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
670
701
|
const resolvedValue = isControlled
|
|
671
702
|
? typeof value === "string"
|
|
672
703
|
? dateFieldStoredValueToDisplayString(value, locale)
|
|
673
|
-
: dateFieldStoredValueToDisplayString(
|
|
704
|
+
: dateFieldStoredValueToDisplayString(dateToCalendarDayString({ date: parseToDate(value), timeZoneId }), locale)
|
|
674
705
|
: dateFieldStoredValueToDisplayString(internalValue, locale);
|
|
675
706
|
const selectedDate = isControlled && typeof value === "string"
|
|
676
707
|
? (parseYYYYMMDDUtil(value) ?? undefined)
|
|
@@ -685,13 +716,8 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
685
716
|
return false;
|
|
686
717
|
const minDate = parseToDate(min);
|
|
687
718
|
const maxDate = parseToDate(max);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
return true;
|
|
691
|
-
if (maxDate !== undefined && dayStart > startOfDayMs(maxDate))
|
|
692
|
-
return true;
|
|
693
|
-
return false;
|
|
694
|
-
}, [min, max]);
|
|
719
|
+
return isCalendarDayOutOfRange({ date, minDate, maxDate, timeZoneId });
|
|
720
|
+
}, [min, max, timeZoneId]);
|
|
695
721
|
const handleCalendarChange = useCallback((next) => {
|
|
696
722
|
setPendingDate(next);
|
|
697
723
|
}, []);
|
|
@@ -708,21 +734,21 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
708
734
|
const handleApply = useCallback((closePopover) => {
|
|
709
735
|
const minDate = parseToDate(min);
|
|
710
736
|
const maxDate = parseToDate(max);
|
|
711
|
-
const clamped =
|
|
712
|
-
const str = clamped ?
|
|
737
|
+
const clamped = clampDateToCalendarDayRange({ date: pendingDate, minDate, maxDate, timeZoneId });
|
|
738
|
+
const str = clamped ? dateToCalendarDayString({ date: clamped, timeZoneId }) : "";
|
|
713
739
|
if (!isControlled)
|
|
714
740
|
setInternalValue(str);
|
|
715
741
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
716
742
|
closePopover();
|
|
717
|
-
}, [isControlled, min, max, onChange, pendingDate]);
|
|
743
|
+
}, [isControlled, min, max, onChange, pendingDate, timeZoneId]);
|
|
718
744
|
const handleInputChange = useCallback((e) => {
|
|
719
745
|
const raw = e.target.value;
|
|
720
746
|
const parsed = parseDateFieldInputForChange(raw, locale);
|
|
721
747
|
const minDate = parseToDate(min);
|
|
722
748
|
const maxDate = parseToDate(max);
|
|
723
749
|
if (parsed !== null) {
|
|
724
|
-
const clamped =
|
|
725
|
-
const str = clamped ?
|
|
750
|
+
const clamped = clampDateToCalendarDayRange({ date: parsed, minDate, maxDate, timeZoneId });
|
|
751
|
+
const str = clamped ? dateToCalendarDayString({ date: clamped, timeZoneId }) : "";
|
|
726
752
|
if (!isControlled)
|
|
727
753
|
setInternalValue(str);
|
|
728
754
|
onChange?.(createInputChangeEvent(str, inputRef.current));
|
|
@@ -732,7 +758,7 @@ const DateBaseInput = ({ min, max, defaultValue, value, ref, onChange, suffix: s
|
|
|
732
758
|
setInternalValue(raw);
|
|
733
759
|
onChange?.(e);
|
|
734
760
|
}
|
|
735
|
-
}, [isControlled, locale, min, max, onChange]);
|
|
761
|
+
}, [isControlled, locale, min, max, onChange, timeZoneId]);
|
|
736
762
|
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 => {
|
|
737
763
|
const displayDate = pendingDate ?? selectedDate ?? null;
|
|
738
764
|
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 => {
|
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.18",
|
|
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.
|
|
12
|
+
"@trackunit/date-and-time-utils": "1.11.111",
|
|
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.
|
|
18
|
-
"@trackunit/react-components": "1.22.
|
|
19
|
-
"@trackunit/ui-icons": "1.11.
|
|
20
|
-
"@trackunit/shared-utils": "1.13.
|
|
21
|
-
"@trackunit/ui-design-tokens": "1.11.
|
|
22
|
-
"@trackunit/i18n-library-translation": "1.18.
|
|
17
|
+
"@trackunit/css-class-variance-utilities": "1.11.108",
|
|
18
|
+
"@trackunit/react-components": "1.22.14",
|
|
19
|
+
"@trackunit/ui-icons": "1.11.104",
|
|
20
|
+
"@trackunit/shared-utils": "1.13.108",
|
|
21
|
+
"@trackunit/ui-design-tokens": "1.11.105",
|
|
22
|
+
"@trackunit/i18n-library-translation": "1.18.14",
|
|
23
23
|
"string-ts": "^2.0.0",
|
|
24
24
|
"es-toolkit": "^1.39.10"
|
|
25
25
|
},
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface DateToCalendarDayStringParams {
|
|
2
|
+
readonly date: Date | undefined;
|
|
3
|
+
readonly timeZoneId: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Converts a Date instant to the canonical YYYY-MM-DD for a specific IANA time zone.
|
|
7
|
+
* This preserves the calendar day the user selected in their local zone.
|
|
8
|
+
*/
|
|
9
|
+
export declare const dateToCalendarDayString: ({ date, timeZoneId }: DateToCalendarDayStringParams) => string;
|
|
10
|
+
interface DateRangeByCalendarDayParams {
|
|
11
|
+
readonly date: Date | null | undefined;
|
|
12
|
+
readonly minDate: Date | undefined;
|
|
13
|
+
readonly maxDate: Date | undefined;
|
|
14
|
+
readonly timeZoneId: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Clamps a date to [minDate, maxDate] by comparing calendar days in a specific timezone.
|
|
18
|
+
* Returns the original `date` when it's in range, or the relevant boundary date when out of range.
|
|
19
|
+
*/
|
|
20
|
+
export declare const clampDateToCalendarDayRange: ({ date, minDate, maxDate, timeZoneId, }: DateRangeByCalendarDayParams) => Date | null;
|
|
21
|
+
/**
|
|
22
|
+
* Returns true when a date falls outside [minDate, maxDate] by calendar day in a specific timezone.
|
|
23
|
+
*/
|
|
24
|
+
export declare const isCalendarDayOutOfRange: ({ date, minDate, maxDate, timeZoneId, }: DateRangeByCalendarDayParams) => boolean;
|
|
25
|
+
export {};
|