@trackunit/react-date-and-time-components 2.1.3 → 2.1.5

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 available through the `timezone` prop.
99
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
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,20 +124,22 @@ 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, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
127
+ const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone: timezoneProp, "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;
130
132
  const nowDate = react.useMemo(() => new Date(), []);
131
133
  const date = sharedUtils.truthy(value) ? dateAndTimeUtils.toDateUtil(value) : nowDate;
132
- const newDateTime = dateAndTimeUtils.formatDateUtil(date, format, timezone?.id, locale);
133
- const titleDateTime = withTitle ? dateAndTimeUtils.formatDateUtil(date, titleFormat, timezone?.id, locale) : undefined;
134
+ const newDateTime = dateAndTimeUtils.formatDateUtil(date, format, timezone.id, locale);
135
+ const titleDateTime = withTitle ? dateAndTimeUtils.formatDateUtil(date, titleFormat, timezone.id, locale) : undefined;
134
136
  const getTimeSince = react.useCallback((from, to) => {
135
137
  const same = dateAndTimeUtils.isEqualUtil(from, to);
136
138
  if (same) {
137
139
  return t("dateTime.instant.now");
138
140
  }
139
- return dateAndTimeUtils.timeSinceAuto(from, to, timezone?.id, locale);
140
- }, [locale, t, timezone?.id]);
141
+ return dateAndTimeUtils.timeSinceAuto(from, to, timezone.id, locale);
142
+ }, [locale, t, timezone.id]);
141
143
  const dateValue = react.useMemo(() => {
142
144
  return fromNow ? getTimeSince(date, nowDate) : newDateTime;
143
145
  }, [date, fromNow, getTimeSince, newDateTime, nowDate]);
@@ -266,7 +268,7 @@ const DayPicker = ({ onDaySelect, disabledDays, selectedDay, language, className
266
268
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
267
269
  * @returns {ReactElement} DayRangePicker component
268
270
  */
269
- const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }) => {
271
+ const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }) => {
270
272
  const [newRange, setNewRange] = react.useState(selectedDays ?? { start: undefined, end: undefined });
271
273
  const [t] = useTranslation();
272
274
  const { subtract } = reactDateAndTimeHooks.useDateAndTime();
@@ -688,7 +690,7 @@ const isTemporalDirection = (direction) => {
688
690
  * ```
689
691
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
690
692
  */
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", }) => {
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", }) => {
692
694
  const [t] = useTranslation();
693
695
  const parseTemporalPeriodFromText = useParseTemporalPeriodFromText();
694
696
  const filterTemporalPeriodsInRange = useFilterTemporalPeriodsInRange();
@@ -790,7 +792,7 @@ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false
790
792
  start: dateRange.start ?? undefined,
791
793
  end: dateRange.end ?? undefined,
792
794
  }
793
- : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange, timezone: timezone }) }));
795
+ : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange }) }));
794
796
  } })] }));
795
797
  };
796
798
 
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, useDateAndTime, useTimezone } from '@trackunit/react-date-and-time-hooks';
4
+ import { useLocale, useTimezone, useDateAndTime } 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 available through the `timezone` prop.
97
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
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,20 +122,22 @@ 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, "data-testid": dataTestId, subtle = false, ref, ...rest }) => {
125
+ const DateTime = ({ value, format, className, style, fromNow = false, withTitle = false, titleFormat, timezone: timezoneProp, "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;
128
130
  const nowDate = useMemo(() => new Date(), []);
129
131
  const date = truthy(value) ? toDateUtil(value) : nowDate;
130
- const newDateTime = formatDateUtil(date, format, timezone?.id, locale);
131
- const titleDateTime = withTitle ? formatDateUtil(date, titleFormat, timezone?.id, locale) : undefined;
132
+ const newDateTime = formatDateUtil(date, format, timezone.id, locale);
133
+ const titleDateTime = withTitle ? formatDateUtil(date, titleFormat, timezone.id, locale) : undefined;
132
134
  const getTimeSince = useCallback((from, to) => {
133
135
  const same = isEqualUtil(from, to);
134
136
  if (same) {
135
137
  return t("dateTime.instant.now");
136
138
  }
137
- return timeSinceAuto(from, to, timezone?.id, locale);
138
- }, [locale, t, timezone?.id]);
139
+ return timeSinceAuto(from, to, timezone.id, locale);
140
+ }, [locale, t, timezone.id]);
139
141
  const dateValue = useMemo(() => {
140
142
  return fromNow ? getTimeSince(date, nowDate) : newDateTime;
141
143
  }, [date, fromNow, getTimeSince, newDateTime, nowDate]);
@@ -264,7 +266,7 @@ const DayPicker = ({ onDaySelect, disabledDays, selectedDay, language, className
264
266
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
265
267
  * @returns {ReactElement} DayRangePicker component
266
268
  */
267
- const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }) => {
269
+ const DayRangePicker = ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }) => {
268
270
  const [newRange, setNewRange] = useState(selectedDays ?? { start: undefined, end: undefined });
269
271
  const [t] = useTranslation();
270
272
  const { subtract } = useDateAndTime();
@@ -686,7 +688,7 @@ const isTemporalDirection = (direction) => {
686
688
  * ```
687
689
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
688
690
  */
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", }) => {
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", }) => {
690
692
  const [t] = useTranslation();
691
693
  const parseTemporalPeriodFromText = useParseTemporalPeriodFromText();
692
694
  const filterTemporalPeriodsInRange = useFilterTemporalPeriodsInRange();
@@ -788,7 +790,7 @@ const DayRangeSelect = ({ className, "data-testid": dataTestId, disabled = false
788
790
  start: dateRange.start ?? undefined,
789
791
  end: dateRange.end ?? undefined,
790
792
  }
791
- : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange, timezone: timezone }) }));
793
+ : undefined, closeMenu), selectedDays: currentSelectedRange?.dateRange }) }));
792
794
  } })] }));
793
795
  };
794
796
 
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@trackunit/react-date-and-time-components",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
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.1",
11
- "@trackunit/date-and-time-utils": "1.13.13",
12
- "@trackunit/react-date-and-time-hooks": "2.1.2",
13
- "@trackunit/css-class-variance-utilities": "1.13.12",
14
- "@trackunit/ui-icons": "1.13.12",
15
- "@trackunit/shared-utils": "1.15.12",
16
- "@trackunit/i18n-library-translation": "2.0.3",
17
- "@trackunit/react-form-components": "2.1.2",
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",
18
18
  "string-ts": "^2.0.0",
19
19
  "tailwind-merge": "^2.0.0",
20
20
  "react-calendar": "^6.0.0"
@@ -1,7 +1,6 @@
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";
5
4
  import { DisabledDaysMatcher } from "./DayPicker";
6
5
  export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement>, Styleable {
7
6
  /**
@@ -20,10 +19,6 @@ export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement
20
19
  * Set the language
21
20
  */
22
21
  language: string;
23
- /**
24
- * Shown time ranges will take timezone into consideration
25
- */
26
- timezone?: TimeZone;
27
22
  /**
28
23
  * The label for the cancel button
29
24
  */
@@ -64,4 +59,4 @@ export interface DayRangePickerProps extends CommonProps, Refable<HTMLDivElement
64
59
  * @param {DayRangePickerProps} props - The props for the DayRangePicker component
65
60
  * @returns {ReactElement} DayRangePicker component
66
61
  */
67
- export declare const DayRangePicker: ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, timezone, cancelButtonLabel, onClose, ref, }: DayRangePickerProps) => ReactElement;
62
+ export declare const DayRangePicker: ({ onRangeSelect, selectedDays, disabledDays, "data-testid": dataTestId, language, className, style, classNameCalendar, cancelButtonLabel, onClose, ref, }: DayRangePickerProps) => ReactElement;
@@ -35,10 +35,6 @@ 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"];
42
38
  /**
43
39
  * The maximum amount of days that can be selected
44
40
  */
@@ -92,4 +88,4 @@ export type DayRangeSelectProps = CommonProps & {
92
88
  * ```
93
89
  * @param {DayRangeSelectProps} props - The props for the DayRangeSelect component
94
90
  */
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;
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;
@@ -28,22 +28,27 @@ 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;
35
31
  /**
36
32
  * When true, renders the text in a muted neutral color for less visual emphasis.
37
33
  *
38
34
  * @default false
39
35
  */
40
36
  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;
41
46
  }
42
47
  export declare const MS_PER_HOUR: number;
43
48
  /**
44
49
  * DateTime renders a locale-aware, formatted date and/or time inside a semantic `<time>` element.
45
50
  * It supports absolute formatting via `TemporalFormat` presets (e.g., `DateTimeFormat.DATE`, `DateTimeFormat.DATE_LONG_TIME`)
46
- * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is available through the `timezone` prop.
51
+ * and relative "time ago" display via the `fromNow` prop. Timezone-aware formatting is handled automatically via the user's preferred timezone.
47
52
  *
48
53
  * ### When to use
49
54
  * 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".
@@ -71,4 +76,4 @@ export declare const MS_PER_HOUR: number;
71
76
  * ```
72
77
  * @param {DateTimeProps} props - The props for the DateTime component
73
78
  */
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;
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;