@trackunit/react-date-and-time-components 2.1.0 → 2.1.2

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
@@ -858,6 +858,7 @@ const cvaTimelineElementTime = cssClassVarianceUtilities.cvaMerge(["min-h-6", "c
858
858
  variants: {
859
859
  width: {
860
860
  large: "min-w-16",
861
+ medium: "min-w-11",
861
862
  small: "min-w-10",
862
863
  },
863
864
  },
@@ -925,6 +926,11 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
925
926
  }, 50); // Small delay to ensure DOM has updated
926
927
  });
927
928
  }, [isLoadingMore, middleChildren.length, visibleCount]);
929
+ const timestampWidth = childProps.timestampFormat === "date" || childProps.timestampFormat === "date-time"
930
+ ? "medium"
931
+ : hourCycle === "h12" || hourCycle === "h11"
932
+ ? "large"
933
+ : "small";
928
934
  // Reset visible count when toggling open/closed
929
935
  react.useEffect(() => {
930
936
  if (isOpen) {
@@ -933,7 +939,7 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
933
939
  }
934
940
  }, [isOpen]);
935
941
  const renderToggleButton = () => (jsxRuntime.jsxs("div", { className: cvaTimelineElement(), children: [childProps.date !== undefined ? (jsxRuntime.jsx("div", { className: cvaTimelineElementTime({
936
- width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
942
+ width: timestampWidth,
937
943
  }) })) : null, jsxRuntime.jsx("div", { className: cvaDotWrapper(), children: jsxRuntime.jsx("div", { className: cvaLine({ lineStyle: childProps.lineStyle }) }) }), jsxRuntime.jsxs("div", { className: "min-h-8 flex cursor-pointer items-center text-sm text-neutral-500 hover:text-neutral-600", "data-testid": "timeline-toggle-btn", onClick: () => {
938
944
  if (toggleButton?.onClick) {
939
945
  toggleButton.onClick();
@@ -956,6 +962,7 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
956
962
  }, children: jsxRuntime.jsx(reactComponents.Text, { className: "cursor-pointer text-neutral-500 hover:text-neutral-600", "data-testid": "load-more-text", size: "small", type: "span", children: t("timeline.loadMore") }) })) : null, jsxRuntime.jsx("div", {})] }), lastChild] })) : (jsxRuntime.jsx("div", { children: children }))] }));
957
963
  };
958
964
 
965
+ const timeTemporalFormat = { selectFormat: "timeOnly", timeFormat: "short" };
959
966
  /**
960
967
  * TimelineElement - entry on a timeline - rendered with an icon on the timeline
961
968
  * - a date as the header and the children provided as body.
@@ -963,11 +970,22 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
963
970
  * @param {TimeLineElementProps} props the props
964
971
  * @returns {ReactElement} component
965
972
  */
966
- const TimelineElement = ({ date, children, className, style, "data-testid": dataTestId = "timeline-element", header, onClick, actionButton, selected = false, customDot, lineStyle = "solid", hoverBehavior = false, }) => {
973
+ const TimelineElement = ({ date, children, className, style, "data-testid": dataTestId = "timeline-element", header, onClick, actionButton, selected = false, customDot, lineStyle = "solid", hoverBehavior = false, timestampFormat = "time", }) => {
967
974
  const [isHovered, setIsHovered] = react.useState(false);
968
975
  const { formatDate } = reactDateAndTimeHooks.useDateAndTime();
969
976
  const locale = reactDateAndTimeHooks.useLocale();
970
- const formattedDate = date ? formatDate(date, { selectFormat: "timeOnly", timeFormat: "short" }) : null;
977
+ const { current } = reactDateAndTimeHooks.useTimezone();
978
+ const dateFormatter = react.useMemo(() => new Intl.DateTimeFormat(locale, {
979
+ day: "numeric",
980
+ month: "short",
981
+ timeZone: current.id,
982
+ }), [current.id, locale]);
983
+ const formattedDate = date
984
+ ? {
985
+ date: timestampFormat === "date" || timestampFormat === "date-time" ? dateFormatter.format(date) : null,
986
+ time: timestampFormat === "time" || timestampFormat === "date-time" ? formatDate(date, timeTemporalFormat) : null,
987
+ }
988
+ : null;
971
989
  const handleMouseEnter = () => {
972
990
  if (hoverBehavior) {
973
991
  setIsHovered(true);
@@ -978,13 +996,13 @@ const TimelineElement = ({ date, children, className, style, "data-testid": data
978
996
  setIsHovered(false);
979
997
  }
980
998
  };
981
- return (jsxRuntime.jsxs("div", { className: cvaTimelineElement({ className, selected, hoverBehavior }), "data-date": date, "data-testid": dataTestId, onClick: onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: style, children: [renderDate(formattedDate, locale), jsxRuntime.jsxs("div", { className: cvaDotWrapper(), children: [renderDot(customDot, isHovered, selected), jsxRuntime.jsx("div", { className: cvaLine({ lineStyle }) })] }), jsxRuntime.jsxs("div", { className: "pb-2 pt-2", children: [renderHeader(header, dataTestId), renderChildren(children), renderActionButton(actionButton)] })] }));
999
+ return (jsxRuntime.jsxs("div", { className: cvaTimelineElement({ className, selected, hoverBehavior }), "data-date": date, "data-testid": dataTestId, onClick: onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: style, children: [renderDate(formattedDate, locale, timestampFormat), jsxRuntime.jsxs("div", { className: cvaDotWrapper(), children: [renderDot(customDot, isHovered, selected), jsxRuntime.jsx("div", { className: cvaLine({ lineStyle }) })] }), jsxRuntime.jsxs("div", { className: "pb-2 pt-2", children: [renderHeader(header, dataTestId), renderChildren(children), renderActionButton(actionButton)] })] }));
982
1000
  };
983
- const renderDate = (formattedDate, locale) => {
1001
+ const renderDate = (formattedDate, locale, timestampFormat) => {
984
1002
  if (!formattedDate) {
985
1003
  return null;
986
1004
  }
987
- return jsxRuntime.jsx("div", { className: "items-center pt-2", children: timelineElementTime(formattedDate, locale) });
1005
+ return jsxRuntime.jsx("div", { className: "items-center pt-2", children: timelineElementTime(formattedDate, locale, timestampFormat) });
988
1006
  };
989
1007
  const renderDot = (customDot, isHovered, selected) => {
990
1008
  return customDot?.name
@@ -1012,11 +1030,14 @@ const renderActionButton = (actionButton) => {
1012
1030
  }
1013
1031
  return (jsxRuntime.jsx("div", { className: "pt-2", children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { name: actionButton.iconName, size: "small" }), size: "small", variant: "secondary", children: actionButton.label }) }));
1014
1032
  };
1015
- const timelineElementTime = (formattedDate, locale) => {
1033
+ const timelineElementTime = (formattedDate, locale, timestampFormat) => {
1016
1034
  const hourCycle = dateAndTimeUtils.getHourCycle(locale);
1017
- return (jsxRuntime.jsx(reactComponents.Text, { align: "right", className: cvaTimelineElementTime({
1018
- width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
1019
- }), size: "small", subtle: true, children: formattedDate }));
1035
+ const width = timestampFormat === "time" ? (hourCycle === "h12" || hourCycle === "h11" ? "large" : "small") : "medium";
1036
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formattedDate.date ? (jsxRuntime.jsx(reactComponents.Text, { align: "right", className: cvaTimelineElementTime({
1037
+ width,
1038
+ }), size: "small", subtle: true, children: formattedDate.date })) : null, formattedDate.time ? (jsxRuntime.jsx(reactComponents.Text, { align: "right", className: cvaTimelineElementTime({
1039
+ width,
1040
+ }), size: "small", subtle: true, children: formattedDate.time })) : null] }));
1020
1041
  };
1021
1042
  const CircleIcon = ({ selected = false, hovered }) => (jsxRuntime.jsxs("svg", { className: "relative z-[2]", "data-testid": "timeline-circle-icon", height: "24", viewBox: "0 0 24 24", width: "24", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", fill: selected ? "#EFF6FF" : hovered ? "#F9FAFB" : "white", r: "10" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", fill: "#2563EB", r: "8" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", fill: "white", r: "3" })] }));
1022
1043
  const DotIcon = () => (jsxRuntime.jsxs("svg", { className: "relative z-[2]", "data-testid": "timeline-dot-icon", height: "24", viewBox: "0 0 24 24", width: "24", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", fill: "white", r: "6" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", fill: "#2563EB", r: "4" })] }));
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 } 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';
@@ -856,6 +856,7 @@ const cvaTimelineElementTime = cvaMerge(["min-h-6", "content-center"], {
856
856
  variants: {
857
857
  width: {
858
858
  large: "min-w-16",
859
+ medium: "min-w-11",
859
860
  small: "min-w-10",
860
861
  },
861
862
  },
@@ -923,6 +924,11 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
923
924
  }, 50); // Small delay to ensure DOM has updated
924
925
  });
925
926
  }, [isLoadingMore, middleChildren.length, visibleCount]);
927
+ const timestampWidth = childProps.timestampFormat === "date" || childProps.timestampFormat === "date-time"
928
+ ? "medium"
929
+ : hourCycle === "h12" || hourCycle === "h11"
930
+ ? "large"
931
+ : "small";
926
932
  // Reset visible count when toggling open/closed
927
933
  useEffect(() => {
928
934
  if (isOpen) {
@@ -931,7 +937,7 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
931
937
  }
932
938
  }, [isOpen]);
933
939
  const renderToggleButton = () => (jsxs("div", { className: cvaTimelineElement(), children: [childProps.date !== undefined ? (jsx("div", { className: cvaTimelineElementTime({
934
- width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
940
+ width: timestampWidth,
935
941
  }) })) : null, jsx("div", { className: cvaDotWrapper(), children: jsx("div", { className: cvaLine({ lineStyle: childProps.lineStyle }) }) }), jsxs("div", { className: "min-h-8 flex cursor-pointer items-center text-sm text-neutral-500 hover:text-neutral-600", "data-testid": "timeline-toggle-btn", onClick: () => {
936
942
  if (toggleButton?.onClick) {
937
943
  toggleButton.onClick();
@@ -954,6 +960,7 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
954
960
  }, children: jsx(Text, { className: "cursor-pointer text-neutral-500 hover:text-neutral-600", "data-testid": "load-more-text", size: "small", type: "span", children: t("timeline.loadMore") }) })) : null, jsx("div", {})] }), lastChild] })) : (jsx("div", { children: children }))] }));
955
961
  };
956
962
 
963
+ const timeTemporalFormat = { selectFormat: "timeOnly", timeFormat: "short" };
957
964
  /**
958
965
  * TimelineElement - entry on a timeline - rendered with an icon on the timeline
959
966
  * - a date as the header and the children provided as body.
@@ -961,11 +968,22 @@ const Timeline = ({ className, style, "data-testid": dataTestId, children, dateH
961
968
  * @param {TimeLineElementProps} props the props
962
969
  * @returns {ReactElement} component
963
970
  */
964
- const TimelineElement = ({ date, children, className, style, "data-testid": dataTestId = "timeline-element", header, onClick, actionButton, selected = false, customDot, lineStyle = "solid", hoverBehavior = false, }) => {
971
+ const TimelineElement = ({ date, children, className, style, "data-testid": dataTestId = "timeline-element", header, onClick, actionButton, selected = false, customDot, lineStyle = "solid", hoverBehavior = false, timestampFormat = "time", }) => {
965
972
  const [isHovered, setIsHovered] = useState(false);
966
973
  const { formatDate } = useDateAndTime();
967
974
  const locale = useLocale();
968
- const formattedDate = date ? formatDate(date, { selectFormat: "timeOnly", timeFormat: "short" }) : null;
975
+ const { current } = useTimezone();
976
+ const dateFormatter = useMemo(() => new Intl.DateTimeFormat(locale, {
977
+ day: "numeric",
978
+ month: "short",
979
+ timeZone: current.id,
980
+ }), [current.id, locale]);
981
+ const formattedDate = date
982
+ ? {
983
+ date: timestampFormat === "date" || timestampFormat === "date-time" ? dateFormatter.format(date) : null,
984
+ time: timestampFormat === "time" || timestampFormat === "date-time" ? formatDate(date, timeTemporalFormat) : null,
985
+ }
986
+ : null;
969
987
  const handleMouseEnter = () => {
970
988
  if (hoverBehavior) {
971
989
  setIsHovered(true);
@@ -976,13 +994,13 @@ const TimelineElement = ({ date, children, className, style, "data-testid": data
976
994
  setIsHovered(false);
977
995
  }
978
996
  };
979
- return (jsxs("div", { className: cvaTimelineElement({ className, selected, hoverBehavior }), "data-date": date, "data-testid": dataTestId, onClick: onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: style, children: [renderDate(formattedDate, locale), jsxs("div", { className: cvaDotWrapper(), children: [renderDot(customDot, isHovered, selected), jsx("div", { className: cvaLine({ lineStyle }) })] }), jsxs("div", { className: "pb-2 pt-2", children: [renderHeader(header, dataTestId), renderChildren(children), renderActionButton(actionButton)] })] }));
997
+ return (jsxs("div", { className: cvaTimelineElement({ className, selected, hoverBehavior }), "data-date": date, "data-testid": dataTestId, onClick: onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: style, children: [renderDate(formattedDate, locale, timestampFormat), jsxs("div", { className: cvaDotWrapper(), children: [renderDot(customDot, isHovered, selected), jsx("div", { className: cvaLine({ lineStyle }) })] }), jsxs("div", { className: "pb-2 pt-2", children: [renderHeader(header, dataTestId), renderChildren(children), renderActionButton(actionButton)] })] }));
980
998
  };
981
- const renderDate = (formattedDate, locale) => {
999
+ const renderDate = (formattedDate, locale, timestampFormat) => {
982
1000
  if (!formattedDate) {
983
1001
  return null;
984
1002
  }
985
- return jsx("div", { className: "items-center pt-2", children: timelineElementTime(formattedDate, locale) });
1003
+ return jsx("div", { className: "items-center pt-2", children: timelineElementTime(formattedDate, locale, timestampFormat) });
986
1004
  };
987
1005
  const renderDot = (customDot, isHovered, selected) => {
988
1006
  return customDot?.name
@@ -1010,11 +1028,14 @@ const renderActionButton = (actionButton) => {
1010
1028
  }
1011
1029
  return (jsx("div", { className: "pt-2", children: jsx(Button, { prefix: jsx(Icon, { name: actionButton.iconName, size: "small" }), size: "small", variant: "secondary", children: actionButton.label }) }));
1012
1030
  };
1013
- const timelineElementTime = (formattedDate, locale) => {
1031
+ const timelineElementTime = (formattedDate, locale, timestampFormat) => {
1014
1032
  const hourCycle = getHourCycle(locale);
1015
- return (jsx(Text, { align: "right", className: cvaTimelineElementTime({
1016
- width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
1017
- }), size: "small", subtle: true, children: formattedDate }));
1033
+ const width = timestampFormat === "time" ? (hourCycle === "h12" || hourCycle === "h11" ? "large" : "small") : "medium";
1034
+ return (jsxs(Fragment, { children: [formattedDate.date ? (jsx(Text, { align: "right", className: cvaTimelineElementTime({
1035
+ width,
1036
+ }), size: "small", subtle: true, children: formattedDate.date })) : null, formattedDate.time ? (jsx(Text, { align: "right", className: cvaTimelineElementTime({
1037
+ width,
1038
+ }), size: "small", subtle: true, children: formattedDate.time })) : null] }));
1018
1039
  };
1019
1040
  const CircleIcon = ({ selected = false, hovered }) => (jsxs("svg", { className: "relative z-[2]", "data-testid": "timeline-circle-icon", height: "24", viewBox: "0 0 24 24", width: "24", children: [jsx("circle", { cx: "12", cy: "12", fill: selected ? "#EFF6FF" : hovered ? "#F9FAFB" : "white", r: "10" }), jsx("circle", { cx: "12", cy: "12", fill: "#2563EB", r: "8" }), jsx("circle", { cx: "12", cy: "12", fill: "white", r: "3" })] }));
1020
1041
  const DotIcon = () => (jsxs("svg", { className: "relative z-[2]", "data-testid": "timeline-dot-icon", height: "24", viewBox: "0 0 24 24", width: "24", children: [jsx("circle", { cx: "12", cy: "12", fill: "white", r: "6" }), jsx("circle", { cx: "12", cy: "12", fill: "#2563EB", r: "4" })] }));
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@trackunit/react-date-and-time-components",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
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.0",
11
- "@trackunit/date-and-time-utils": "1.13.11",
12
- "@trackunit/react-date-and-time-hooks": "2.1.0",
13
- "@trackunit/css-class-variance-utilities": "1.13.11",
14
- "@trackunit/ui-icons": "1.13.11",
15
- "@trackunit/shared-utils": "1.15.11",
16
- "@trackunit/i18n-library-translation": "2.0.2",
17
- "@trackunit/react-form-components": "2.1.0",
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",
18
18
  "string-ts": "^2.0.0",
19
19
  "tailwind-merge": "^2.0.0",
20
20
  "react-calendar": "^6.0.0"
@@ -11,5 +11,5 @@ export declare const cvaToggleBtnIcon: (props?: ({
11
11
  rotated?: boolean | null | undefined;
12
12
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
13
  export declare const cvaTimelineElementTime: (props?: ({
14
- width?: "small" | "large" | null | undefined;
14
+ width?: "small" | "medium" | "large" | null | undefined;
15
15
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -1,8 +1,10 @@
1
1
  import { CommonProps, IconColors, type Styleable } from "@trackunit/react-components";
2
2
  import { IconName } from "@trackunit/ui-icons";
3
3
  import { MouseEvent, ReactNode } from "react";
4
+ type TimelineElementTimestampFormat = "time" | "date" | "date-time";
4
5
  interface TimeLineElementProps extends CommonProps, Styleable {
5
6
  date?: Date;
7
+ timestampFormat?: TimelineElementTimestampFormat;
6
8
  header?: ReactNode;
7
9
  children?: ReactNode;
8
10
  customDot?: {
@@ -26,5 +28,5 @@ interface TimeLineElementProps extends CommonProps, Styleable {
26
28
  * @param {TimeLineElementProps} props the props
27
29
  * @returns {ReactElement} component
28
30
  */
29
- export declare const TimelineElement: ({ date, children, className, style, "data-testid": dataTestId, header, onClick, actionButton, selected, customDot, lineStyle, hoverBehavior, }: TimeLineElementProps) => import("react/jsx-runtime").JSX.Element;
31
+ export declare const TimelineElement: ({ date, children, className, style, "data-testid": dataTestId, header, onClick, actionButton, selected, customDot, lineStyle, hoverBehavior, timestampFormat, }: TimeLineElementProps) => import("react/jsx-runtime").JSX.Element;
30
32
  export {};