@trackunit/react-date-and-time-components 2.1.5 → 2.1.7-alpha-ecf53e535f3.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
@@ -96,7 +96,7 @@ const MS_PER_HOUR = 60 * 60 * 1000;
96
96
  /**
97
97
  * DateTime renders a locale-aware, formatted date and/or time inside a semantic `<time>` element.
98
98
  * It supports absolute formatting via `TemporalFormat` presets (e.g., `DateTimeFormat.DATE`, `DateTimeFormat.DATE_LONG_TIME`)
99
- * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
99
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is available through the `timezone` prop.
100
100
  *
101
101
  * ### When to use
102
102
  * Use DateTime whenever you need to display a date, time, or relative timestamp in the UI — for example, "Last seen 3 hours ago" or "Feb 17, 2026".
@@ -124,22 +124,20 @@ const MS_PER_HOUR = 60 * 60 * 1000;
124
124
  * ```
125
125
  * @param {DateTimeProps} props - The props for the DateTime component
126
126
  */
127
- const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone: timezoneProp, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
127
+ const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
128
128
  const { t } = useTranslation();
129
129
  const locale = reactDateAndTimeHooks.useLocale();
130
- const { preferred: preferredTimezone } = reactDateAndTimeHooks.useTimezone();
131
- const timezone = timezoneProp ?? preferredTimezone;
132
130
  const nowDate = react.useMemo(() => new Date(), []);
133
131
  const date = sharedUtils.truthy(value) ? dateAndTimeUtils.toDateUtil(value) : nowDate;
134
- const newDateTime = dateAndTimeUtils.formatDateUtil(date, format, timezone.id, locale);
135
- const titleDateTime = withTitle ? dateAndTimeUtils.formatDateUtil(date, titleFormat, timezone.id, locale) : undefined;
132
+ const newDateTime = dateAndTimeUtils.formatDateUtil(date, format, timezone?.id, locale);
133
+ const titleDateTime = withTitle ? dateAndTimeUtils.formatDateUtil(date, titleFormat, timezone?.id, locale) : undefined;
136
134
  const getTimeSince = react.useCallback((from, to) => {
137
135
  const same = dateAndTimeUtils.isEqualUtil(from, to);
138
136
  if (same) {
139
137
  return t("dateTime.instant.now");
140
138
  }
141
- return dateAndTimeUtils.timeSinceAuto(from, to, timezone.id, locale);
142
- }, [locale, t, timezone.id]);
139
+ return dateAndTimeUtils.timeSinceAuto(from, to, timezone?.id, locale);
140
+ }, [locale, t, timezone?.id]);
143
141
  const dateValue = react.useMemo(() => {
144
142
  return fromNow ? getTimeSince(date, nowDate) : newDateTime;
145
143
  }, [date, fromNow, getTimeSince, newDateTime, nowDate]);
@@ -268,7 +266,7 @@ const DayPicker = ({ onDaySelect, disabledDays, selectedDay, language, className
268
266
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
269
267
  * @returns {ReactElement} DayRangePicker component
270
268
  */
271
- const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }) => {
269
+ const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }) => {
272
270
  const [newRange, setNewRange] = react.useState(selectedDays ?? { start: undefined, end: undefined });
273
271
  const [t] = useTranslation();
274
272
  const { subtract } = reactDateAndTimeHooks.useDateAndTime();
@@ -690,7 +688,7 @@ const isTemporalDirection = (direction) => {
690
688
  * ```
691
689
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
692
690
  */
693
- const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false, selectedDateRange, onRangeSelect, allowedDirection = undefined, initialDateRangeOptions, showDateRangeSearch = true, showCustomDateRangeOption = true, maxDaysInRange, disabledDays, size = "medium", fullWidth = false, actionButton, popoverPlacement = "bottom-start", }) => {
691
+ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false, selectedDateRange, onRangeSelect, allowedDirection = undefined, initialDateRangeOptions, showDateRangeSearch = true, showCustomDateRangeOption = true, timezone, maxDaysInRange, disabledDays, size = "medium", fullWidth = false, actionButton, popoverPlacement = "bottom-start", }) => {
694
692
  const [t] = useTranslation();
695
693
  const parseTemporalPeriodFromText = useParseTemporalPeriodFromText();
696
694
  const filterTemporalPeriodsInRange = useFilterTemporalPeriodsInRange();
@@ -792,7 +790,7 @@ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false
792
790
  start: dateRange.start ?? undefined,
793
791
  end: dateRange.end ?? undefined,
794
792
  }
795
- : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange }) }));
793
+ : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange, timezone: timezone }) }));
796
794
  } })] }));
797
795
  };
798
796
 
package/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
3
3
  import { toDateUtil, formatDateUtil, isEqualUtil, timeSinceAuto, getHourCycle } from '@trackunit/date-and-time-utils';
4
- import { useLocale, useTimezone, useDateAndTime } from '@trackunit/react-date-and-time-hooks';
4
+ import { useLocale, useDateAndTime, useTimezone } from '@trackunit/react-date-and-time-hooks';
5
5
  import { truthy, DateTimeFormat, nonNullable, objectKeys } from '@trackunit/shared-utils';
6
6
  import { useMemo, useCallback, useState, useEffect, useRef, Children, isValidElement } from 'react';
7
7
  import { twMerge } from 'tailwind-merge';
@@ -94,7 +94,7 @@ const MS_PER_HOUR = 60 * 60 * 1000;
94
94
  /**
95
95
  * DateTime renders a locale-aware, formatted date and/or time inside a semantic `<time>` element.
96
96
  * It supports absolute formatting via `TemporalFormat` presets (e.g., `DateTimeFormat.DATE`, `DateTimeFormat.DATE_LONG_TIME`)
97
- * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
97
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is available through the `timezone` prop.
98
98
  *
99
99
  * ### When to use
100
100
  * Use DateTime whenever you need to display a date, time, or relative timestamp in the UI — for example, "Last seen 3 hours ago" or "Feb 17, 2026".
@@ -122,22 +122,20 @@ const MS_PER_HOUR = 60 * 60 * 1000;
122
122
  * ```
123
123
  * @param {DateTimeProps} props - The props for the DateTime component
124
124
  */
125
- const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone: timezoneProp, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
125
+ const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
126
126
  const { t } = useTranslation();
127
127
  const locale = useLocale();
128
- const { preferred: preferredTimezone } = useTimezone();
129
- const timezone = timezoneProp ?? preferredTimezone;
130
128
  const nowDate = useMemo(() => new Date(), []);
131
129
  const date = truthy(value) ? toDateUtil(value) : nowDate;
132
- const newDateTime = formatDateUtil(date, format, timezone.id, locale);
133
- const titleDateTime = withTitle ? formatDateUtil(date, titleFormat, timezone.id, locale) : undefined;
130
+ const newDateTime = formatDateUtil(date, format, timezone?.id, locale);
131
+ const titleDateTime = withTitle ? formatDateUtil(date, titleFormat, timezone?.id, locale) : undefined;
134
132
  const getTimeSince = useCallback((from, to) => {
135
133
  const same = isEqualUtil(from, to);
136
134
  if (same) {
137
135
  return t("dateTime.instant.now");
138
136
  }
139
- return timeSinceAuto(from, to, timezone.id, locale);
140
- }, [locale, t, timezone.id]);
137
+ return timeSinceAuto(from, to, timezone?.id, locale);
138
+ }, [locale, t, timezone?.id]);
141
139
  const dateValue = useMemo(() => {
142
140
  return fromNow ? getTimeSince(date, nowDate) : newDateTime;
143
141
  }, [date, fromNow, getTimeSince, newDateTime, nowDate]);
@@ -266,7 +264,7 @@ const DayPicker = ({ onDaySelect, disabledDays, selectedDay, language, className
266
264
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
267
265
  * @returns {ReactElement} DayRangePicker component
268
266
  */
269
- const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }) => {
267
+ const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }) => {
270
268
  const [newRange, setNewRange] = useState(selectedDays ?? { start: undefined, end: undefined });
271
269
  const [t] = useTranslation();
272
270
  const { subtract } = useDateAndTime();
@@ -688,7 +686,7 @@ const isTemporalDirection = (direction) => {
688
686
  * ```
689
687
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
690
688
  */
691
- const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false, selectedDateRange, onRangeSelect, allowedDirection = undefined, initialDateRangeOptions, showDateRangeSearch = true, showCustomDateRangeOption = true, maxDaysInRange, disabledDays, size = "medium", fullWidth = false, actionButton, popoverPlacement = "bottom-start", }) => {
689
+ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false, selectedDateRange, onRangeSelect, allowedDirection = undefined, initialDateRangeOptions, showDateRangeSearch = true, showCustomDateRangeOption = true, timezone, maxDaysInRange, disabledDays, size = "medium", fullWidth = false, actionButton, popoverPlacement = "bottom-start", }) => {
692
690
  const [t] = useTranslation();
693
691
  const parseTemporalPeriodFromText = useParseTemporalPeriodFromText();
694
692
  const filterTemporalPeriodsInRange = useFilterTemporalPeriodsInRange();
@@ -790,7 +788,7 @@ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false
790
788
  start: dateRange.start ?? undefined,
791
789
  end: dateRange.end ?? undefined,
792
790
  }
793
- : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange }) }));
791
+ : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange, timezone: timezone }) }));
794
792
  } })] }));
795
793
  };
796
794
 
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@trackunit/react-date-and-time-components",
3
- "version": "2.1.5",
3
+ "version": "2.1.7-alpha-ecf53e535f3.0",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
7
7
  "node": ">=24.x"
8
8
  },
9
9
  "dependencies": {
10
- "@trackunit/react-components": "2.1.3",
11
- "@trackunit/date-and-time-utils": "1.13.14",
12
- "@trackunit/react-date-and-time-hooks": "2.1.4",
13
- "@trackunit/css-class-variance-utilities": "1.13.13",
14
- "@trackunit/ui-icons": "1.13.14",
15
- "@trackunit/shared-utils": "1.15.13",
16
- "@trackunit/i18n-library-translation": "2.0.5",
17
- "@trackunit/react-form-components": "2.1.4",
10
+ "@trackunit/react-components": "2.1.5-alpha-ecf53e535f3.0",
11
+ "@trackunit/date-and-time-utils": "1.13.16-alpha-ecf53e535f3.0",
12
+ "@trackunit/react-date-and-time-hooks": "2.1.6-alpha-ecf53e535f3.0",
13
+ "@trackunit/css-class-variance-utilities": "1.13.15-alpha-ecf53e535f3.0",
14
+ "@trackunit/ui-icons": "1.13.16-alpha-ecf53e535f3.0",
15
+ "@trackunit/shared-utils": "1.15.15-alpha-ecf53e535f3.0",
16
+ "@trackunit/i18n-library-translation": "2.0.7-alpha-ecf53e535f3.0",
17
+ "@trackunit/react-form-components": "2.1.6-alpha-ecf53e535f3.0",
18
18
  "string-ts": "^2.0.0",
19
19
  "tailwind-merge": "^2.0.0",
20
20
  "react-calendar": "^6.0.0"
@@ -1,6 +1,7 @@
1
1
  import { CommonProps, Refable, type Styleable } from "@trackunit/react-components";
2
2
  import { DateRange } from "@trackunit/date-and-time-utils";
3
3
  import { ReactElement } from "react";
4
+ import { TimeZone } from "../TimeZone";
4
5
  import { DisabledDaysMatcher } from "./DayPicker";
5
6
  export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement>, Styleable {
6
7
  /**
@@ -19,6 +20,10 @@ export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement
19
20
  * Set the language
20
21
  */
21
22
  language: string;
23
+ /**
24
+ * Shown time ranges will take timezone into consideration
25
+ */
26
+ timezone?: TimeZone;
22
27
  /**
23
28
  * The label for the cancel button
24
29
  */
@@ -59,4 +64,4 @@ export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement
59
64
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
60
65
  * @returns {ReactElement} DayRangePicker component
61
66
  */
62
- export declare const DayRangePicker: ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }: DayRangePickerProps) => ReactElement;
67
+ export declare const DayRangePicker: ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }: DayRangePickerProps) => ReactElement;
@@ -35,6 +35,10 @@ export type DayRangeSelectProps = CommonProps & {
35
35
  * Whether to show the custom date range option with a calendar picker.
36
36
  */
37
37
  showCustomDateRangeOption?: boolean;
38
+ /**
39
+ * The timezone for the date range picker.
40
+ */
41
+ timezone?: DayRangePickerProps["timezone"];
38
42
  /**
39
43
  * The maximum amount of days that can be selected
40
44
  */
@@ -88,4 +92,4 @@ export type DayRangeSelectProps = CommonProps & {
88
92
  * ```
89
93
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
90
94
  */
91
- export declare const DayRangeSelect: ({ className, "data-testid": dataTestId, disabled, selectedDateRange, onRangeSelect, allowedDirection, initialDateRangeOptions, showDateRangeSearch, showCustomDateRangeOption, maxDaysInRange, disabledDays, size, fullWidth, actionButton, popoverPlacement, }: DayRangeSelectProps) => import("react/jsx-runtime").JSX.Element;
95
+ export declare const DayRangeSelect: ({ className, "data-testid": dataTestId, disabled, selectedDateRange, onRangeSelect, allowedDirection, initialDateRangeOptions, showDateRangeSearch, showCustomDateRangeOption, timezone, maxDaysInRange, disabledDays, size, fullWidth, actionButton, popoverPlacement, }: DayRangeSelectProps) => import("react/jsx-runtime").JSX.Element;
@@ -28,27 +28,22 @@ export interface DateTimeProps extends CommonProps, Refable<HTMLTimeElement>, St
28
28
  * Custom `TemporalFormat` for the hover `title` attribute. Only used when `withTitle` is true.
29
29
  */
30
30
  titleFormat?: TemporalFormat;
31
+ /**
32
+ * A `TimeZone` object to format the date in a specific timezone rather than the user's local timezone.
33
+ */
34
+ timezone?: TimeZone;
31
35
  /**
32
36
  * When true, renders the text in a muted neutral color for less visual emphasis.
33
37
  *
34
38
  * @default false
35
39
  */
36
40
  subtle?: boolean;
37
- /**
38
- * Explicit timezone override. When provided, this takes precedence over the automatically resolved
39
- * timezone from the user's preference context. Useful for showing a date in a fixed timezone
40
- * regardless of user settings (e.g. a contract's original timezone).
41
- *
42
- * In most cases you do not need this — the component resolves the correct timezone automatically
43
- * via `AssetTimezoneProvider` and user preference context.
44
- */
45
- timezone?: TimeZone;
46
41
  }
47
42
  export declare const MS_PER_HOUR: number;
48
43
  /**
49
44
  * DateTime renders a locale-aware, formatted date and/or time inside a semantic `<time>` element.
50
45
  * It supports absolute formatting via `TemporalFormat` presets (e.g., `DateTimeFormat.DATE`, `DateTimeFormat.DATE_LONG_TIME`)
51
- * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
46
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is available through the `timezone` prop.
52
47
  *
53
48
  * ### When to use
54
49
  * Use DateTime whenever you need to display a date, time, or relative timestamp in the UI — for example, "Last seen 3 hours ago" or "Feb 17, 2026".
@@ -76,4 +71,4 @@ export declare const MS_PER_HOUR: number;
76
71
  * ```
77
72
  * @param {DateTimeProps} props - The props for the DateTime component
78
73
  */
79
- export declare const DateTime: ({ value, format, className, style, fromNow, withTitle, titleFormat, timezone: timezoneProp, "data-testid": dataTestId, subtle, ref, ...rest }: DateTimeProps) => import("react/jsx-runtime").JSX.Element;
74
+ export declare const DateTime: ({ value, format, className, style, fromNow, withTitle, titleFormat, timezone, "data-testid": dataTestId, subtle, ref, ...rest }: DateTimeProps) => import("react/jsx-runtime").JSX.Element;