@trackunit/react-date-and-time-components 1.3.45 → 1.3.47
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 +38 -2
- package/index.esm.js +38 -2
- package/package.json +10 -10
- package/src/Timeline/Timeline.stories.d.ts +1 -0
- package/src/translation.d.ts +2 -2
package/index.cjs.js
CHANGED
|
@@ -28,7 +28,8 @@ var defaultTranslations = {
|
|
|
28
28
|
"shared.timePeriods.months_plural": "{{count}} months",
|
|
29
29
|
"shared.timePeriods.today": "Today",
|
|
30
30
|
"shared.timePeriods.weeks": "{{count}} week",
|
|
31
|
-
"shared.timePeriods.weeks_plural": "{{count}} weeks"
|
|
31
|
+
"shared.timePeriods.weeks_plural": "{{count}} weeks",
|
|
32
|
+
"timeline.loadMore": "Click for more..."
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
/** The translation namespace for this library */
|
|
@@ -371,6 +372,8 @@ const cvaTimelineElementTime = cssClassVarianceUtilities.cvaMerge([
|
|
|
371
372
|
},
|
|
372
373
|
});
|
|
373
374
|
|
|
375
|
+
// Constants for pagination
|
|
376
|
+
const ITEMS_PER_PAGE = 20;
|
|
374
377
|
/**
|
|
375
378
|
* The Timeline component offers a visual representation of events or milestones in chronological order, helping users easily follow the progression of activities, tasks, or data points over time.
|
|
376
379
|
*
|
|
@@ -380,19 +383,49 @@ const cvaTimelineElementTime = cssClassVarianceUtilities.cvaMerge([
|
|
|
380
383
|
const Timeline = ({ className, dataTestId, children, dateHeader, customHeader, toggleButton, }) => {
|
|
381
384
|
const ref = react.useRef(null);
|
|
382
385
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
386
|
+
const [visibleCount, setVisibleCount] = react.useState(ITEMS_PER_PAGE);
|
|
387
|
+
const [isLoadingMore, setIsLoadingMore] = react.useState(false);
|
|
383
388
|
const { formatDate, formatRange } = reactDateAndTimeHooks.useDateAndTime();
|
|
384
389
|
const locale = reactDateAndTimeHooks.useLocale();
|
|
385
390
|
const hourCycle = dateAndTimeUtils.getHourCycle(locale);
|
|
391
|
+
const { t } = useTranslation();
|
|
386
392
|
const childrenArray = react.useMemo(() => react.Children.toArray(children), [children]);
|
|
387
393
|
const [firstChild, ...remainingChildren] = childrenArray;
|
|
388
394
|
const childProps = react.isValidElement(firstChild) ? firstChild.props : {};
|
|
389
395
|
const lastChild = remainingChildren.pop();
|
|
390
396
|
const middleChildren = remainingChildren;
|
|
397
|
+
// Slice middleChildren to only render the visible count
|
|
398
|
+
const visibleMiddleChildren = react.useMemo(() => middleChildren.slice(0, visibleCount), [middleChildren, visibleCount]);
|
|
391
399
|
react.useEffect(() => {
|
|
392
400
|
// Set maxHeight dynamically for smooth animation
|
|
393
401
|
if (ref.current) {
|
|
394
402
|
ref.current.style.maxHeight = isOpen ? `${ref.current.scrollHeight}px` : "0px";
|
|
395
403
|
}
|
|
404
|
+
}, [isOpen, visibleCount]);
|
|
405
|
+
const loadMoreItems = react.useCallback(() => {
|
|
406
|
+
if (isLoadingMore || visibleCount >= middleChildren.length) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
setIsLoadingMore(true);
|
|
410
|
+
// Use requestAnimationFrame to avoid layout thrashing
|
|
411
|
+
requestAnimationFrame(() => {
|
|
412
|
+
const scrollPos = ref.current?.scrollTop || 0;
|
|
413
|
+
setVisibleCount(prev => Math.min(prev + ITEMS_PER_PAGE, middleChildren.length));
|
|
414
|
+
// After state update, preserve scroll position
|
|
415
|
+
setTimeout(() => {
|
|
416
|
+
if (ref.current) {
|
|
417
|
+
ref.current.scrollTop = scrollPos;
|
|
418
|
+
}
|
|
419
|
+
setIsLoadingMore(false);
|
|
420
|
+
}, 50); // Small delay to ensure DOM has updated
|
|
421
|
+
});
|
|
422
|
+
}, [isLoadingMore, middleChildren.length, visibleCount]);
|
|
423
|
+
// Reset visible count when toggling open/closed
|
|
424
|
+
react.useEffect(() => {
|
|
425
|
+
if (isOpen) {
|
|
426
|
+
setVisibleCount(ITEMS_PER_PAGE);
|
|
427
|
+
setIsLoadingMore(false);
|
|
428
|
+
}
|
|
396
429
|
}, [isOpen]);
|
|
397
430
|
const renderToggleButton = () => (jsxRuntime.jsxs("div", { className: cvaTimelineElement(), children: [childProps.date ? (jsxRuntime.jsx("div", { className: cvaTimelineElementTime({
|
|
398
431
|
width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
|
|
@@ -410,7 +443,10 @@ const Timeline = ({ className, dataTestId, children, dateHeader, customHeader, t
|
|
|
410
443
|
const { date, dateRange, showTime } = dateHeader;
|
|
411
444
|
return (jsxRuntime.jsx("div", { className: "pb-4", "data-testid": "timeline-date-header", children: date ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.Text, { size: "medium", type: "span", weight: "thick", children: formatDate(date, { selectFormat: !showTime ? "dateOnly" : undefined }) }), jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-500", size: "medium", type: "span", weight: "thick", children: ` (${dateAndTimeUtils.timeSinceAuto(date, new Date(), undefined, locale)})` })] })) : (jsxRuntime.jsx(reactComponents.Text, { className: "pr-1", size: "medium", type: "span", weight: "thick", children: formatRange(dateRange, { dateStyle: !showTime ? "medium" : undefined }) })) }));
|
|
412
445
|
}, [dateHeader, formatDate, formatRange, customHeader, locale]);
|
|
413
|
-
return (jsxRuntime.jsxs("div", { className: className, "data-testid": dataTestId, children: [renderDateHeader(), customHeader ? jsxRuntime.jsx("div", { className: "text-sm font-semibold", children: customHeader }) : null, toggleButton && middleChildren.length > 0 ? (jsxRuntime.jsxs("div", { children: [firstChild, middleChildren.length > 0 ? renderToggleButton() : null, jsxRuntime.jsxs("div", { "aria-hidden": !isOpen, className: "overflow-hidden transition-all duration-300", ref: ref, children: [jsxRuntime.jsx("div", {}),
|
|
446
|
+
return (jsxRuntime.jsxs("div", { className: className, "data-testid": dataTestId, children: [renderDateHeader(), customHeader ? jsxRuntime.jsx("div", { className: "text-sm font-semibold", children: customHeader }) : null, toggleButton && middleChildren.length > 0 ? (jsxRuntime.jsxs("div", { children: [firstChild, middleChildren.length > 0 ? renderToggleButton() : null, jsxRuntime.jsxs("div", { "aria-hidden": !isOpen, className: "overflow-hidden overflow-y-auto transition-all duration-300", ref: ref, children: [jsxRuntime.jsx("div", {}), visibleMiddleChildren, isOpen && visibleCount < middleChildren.length ? (jsxRuntime.jsx("div", { className: "flex justify-center py-2", onClick: e => {
|
|
447
|
+
e.stopPropagation(); // Prevent parent handlers from firing
|
|
448
|
+
loadMoreItems();
|
|
449
|
+
}, children: jsxRuntime.jsx(reactComponents.Text, { className: "text-secondary-500 hover:text-secondary-600 cursor-pointer", "data-testid": "load-more-text", size: "small", type: "span", children: t("timeline.loadMore") }) })) : null, jsxRuntime.jsx("div", {})] }), lastChild] })) : (jsxRuntime.jsx("div", { children: children }))] }));
|
|
414
450
|
};
|
|
415
451
|
|
|
416
452
|
/**
|
package/index.esm.js
CHANGED
|
@@ -26,7 +26,8 @@ var defaultTranslations = {
|
|
|
26
26
|
"shared.timePeriods.months_plural": "{{count}} months",
|
|
27
27
|
"shared.timePeriods.today": "Today",
|
|
28
28
|
"shared.timePeriods.weeks": "{{count}} week",
|
|
29
|
-
"shared.timePeriods.weeks_plural": "{{count}} weeks"
|
|
29
|
+
"shared.timePeriods.weeks_plural": "{{count}} weeks",
|
|
30
|
+
"timeline.loadMore": "Click for more..."
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
/** The translation namespace for this library */
|
|
@@ -369,6 +370,8 @@ const cvaTimelineElementTime = cvaMerge([
|
|
|
369
370
|
},
|
|
370
371
|
});
|
|
371
372
|
|
|
373
|
+
// Constants for pagination
|
|
374
|
+
const ITEMS_PER_PAGE = 20;
|
|
372
375
|
/**
|
|
373
376
|
* The Timeline component offers a visual representation of events or milestones in chronological order, helping users easily follow the progression of activities, tasks, or data points over time.
|
|
374
377
|
*
|
|
@@ -378,19 +381,49 @@ const cvaTimelineElementTime = cvaMerge([
|
|
|
378
381
|
const Timeline = ({ className, dataTestId, children, dateHeader, customHeader, toggleButton, }) => {
|
|
379
382
|
const ref = useRef(null);
|
|
380
383
|
const [isOpen, setIsOpen] = useState(false);
|
|
384
|
+
const [visibleCount, setVisibleCount] = useState(ITEMS_PER_PAGE);
|
|
385
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
381
386
|
const { formatDate, formatRange } = useDateAndTime();
|
|
382
387
|
const locale = useLocale$1();
|
|
383
388
|
const hourCycle = getHourCycle(locale);
|
|
389
|
+
const { t } = useTranslation();
|
|
384
390
|
const childrenArray = useMemo(() => Children.toArray(children), [children]);
|
|
385
391
|
const [firstChild, ...remainingChildren] = childrenArray;
|
|
386
392
|
const childProps = isValidElement(firstChild) ? firstChild.props : {};
|
|
387
393
|
const lastChild = remainingChildren.pop();
|
|
388
394
|
const middleChildren = remainingChildren;
|
|
395
|
+
// Slice middleChildren to only render the visible count
|
|
396
|
+
const visibleMiddleChildren = useMemo(() => middleChildren.slice(0, visibleCount), [middleChildren, visibleCount]);
|
|
389
397
|
useEffect(() => {
|
|
390
398
|
// Set maxHeight dynamically for smooth animation
|
|
391
399
|
if (ref.current) {
|
|
392
400
|
ref.current.style.maxHeight = isOpen ? `${ref.current.scrollHeight}px` : "0px";
|
|
393
401
|
}
|
|
402
|
+
}, [isOpen, visibleCount]);
|
|
403
|
+
const loadMoreItems = useCallback(() => {
|
|
404
|
+
if (isLoadingMore || visibleCount >= middleChildren.length) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
setIsLoadingMore(true);
|
|
408
|
+
// Use requestAnimationFrame to avoid layout thrashing
|
|
409
|
+
requestAnimationFrame(() => {
|
|
410
|
+
const scrollPos = ref.current?.scrollTop || 0;
|
|
411
|
+
setVisibleCount(prev => Math.min(prev + ITEMS_PER_PAGE, middleChildren.length));
|
|
412
|
+
// After state update, preserve scroll position
|
|
413
|
+
setTimeout(() => {
|
|
414
|
+
if (ref.current) {
|
|
415
|
+
ref.current.scrollTop = scrollPos;
|
|
416
|
+
}
|
|
417
|
+
setIsLoadingMore(false);
|
|
418
|
+
}, 50); // Small delay to ensure DOM has updated
|
|
419
|
+
});
|
|
420
|
+
}, [isLoadingMore, middleChildren.length, visibleCount]);
|
|
421
|
+
// Reset visible count when toggling open/closed
|
|
422
|
+
useEffect(() => {
|
|
423
|
+
if (isOpen) {
|
|
424
|
+
setVisibleCount(ITEMS_PER_PAGE);
|
|
425
|
+
setIsLoadingMore(false);
|
|
426
|
+
}
|
|
394
427
|
}, [isOpen]);
|
|
395
428
|
const renderToggleButton = () => (jsxs("div", { className: cvaTimelineElement(), children: [childProps.date ? (jsx("div", { className: cvaTimelineElementTime({
|
|
396
429
|
width: hourCycle === "h12" || hourCycle === "h11" ? "large" : "small",
|
|
@@ -408,7 +441,10 @@ const Timeline = ({ className, dataTestId, children, dateHeader, customHeader, t
|
|
|
408
441
|
const { date, dateRange, showTime } = dateHeader;
|
|
409
442
|
return (jsx("div", { className: "pb-4", "data-testid": "timeline-date-header", children: date ? (jsxs(Fragment, { children: [jsx(Text, { size: "medium", type: "span", weight: "thick", children: formatDate(date, { selectFormat: !showTime ? "dateOnly" : undefined }) }), jsx(Text, { className: "text-secondary-500", size: "medium", type: "span", weight: "thick", children: ` (${timeSinceAuto(date, new Date(), undefined, locale)})` })] })) : (jsx(Text, { className: "pr-1", size: "medium", type: "span", weight: "thick", children: formatRange(dateRange, { dateStyle: !showTime ? "medium" : undefined }) })) }));
|
|
410
443
|
}, [dateHeader, formatDate, formatRange, customHeader, locale]);
|
|
411
|
-
return (jsxs("div", { className: className, "data-testid": dataTestId, children: [renderDateHeader(), customHeader ? jsx("div", { className: "text-sm font-semibold", children: customHeader }) : null, toggleButton && middleChildren.length > 0 ? (jsxs("div", { children: [firstChild, middleChildren.length > 0 ? renderToggleButton() : null, jsxs("div", { "aria-hidden": !isOpen, className: "overflow-hidden transition-all duration-300", ref: ref, children: [jsx("div", {}),
|
|
444
|
+
return (jsxs("div", { className: className, "data-testid": dataTestId, children: [renderDateHeader(), customHeader ? jsx("div", { className: "text-sm font-semibold", children: customHeader }) : null, toggleButton && middleChildren.length > 0 ? (jsxs("div", { children: [firstChild, middleChildren.length > 0 ? renderToggleButton() : null, jsxs("div", { "aria-hidden": !isOpen, className: "overflow-hidden overflow-y-auto transition-all duration-300", ref: ref, children: [jsx("div", {}), visibleMiddleChildren, isOpen && visibleCount < middleChildren.length ? (jsx("div", { className: "flex justify-center py-2", onClick: e => {
|
|
445
|
+
e.stopPropagation(); // Prevent parent handlers from firing
|
|
446
|
+
loadMoreItems();
|
|
447
|
+
}, children: jsx(Text, { className: "text-secondary-500 hover:text-secondary-600 cursor-pointer", "data-testid": "load-more-text", size: "small", type: "span", children: t("timeline.loadMore") }) })) : null, jsx("div", {})] }), lastChild] })) : (jsx("div", { children: children }))] }));
|
|
412
448
|
};
|
|
413
449
|
|
|
414
450
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-date-and-time-components",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.47",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
"tailwind-merge": "^2.0.0",
|
|
12
12
|
"react-day-picker": "9.5.1",
|
|
13
13
|
"react": "19.0.0",
|
|
14
|
-
"@trackunit/react-components": "1.4.
|
|
15
|
-
"@trackunit/react-date-and-time-hooks": "1.3.
|
|
16
|
-
"@trackunit/react-core-hooks": "1.3.
|
|
17
|
-
"@trackunit/date-and-time-utils": "1.3.
|
|
18
|
-
"@trackunit/css-class-variance-utilities": "1.3.
|
|
19
|
-
"@trackunit/ui-icons": "1.3.
|
|
20
|
-
"@trackunit/ui-design-tokens": "1.3.
|
|
21
|
-
"@trackunit/shared-utils": "1.5.
|
|
22
|
-
"@trackunit/i18n-library-translation": "1.3.
|
|
14
|
+
"@trackunit/react-components": "1.4.42",
|
|
15
|
+
"@trackunit/react-date-and-time-hooks": "1.3.41",
|
|
16
|
+
"@trackunit/react-core-hooks": "1.3.40",
|
|
17
|
+
"@trackunit/date-and-time-utils": "1.3.38",
|
|
18
|
+
"@trackunit/css-class-variance-utilities": "1.3.38",
|
|
19
|
+
"@trackunit/ui-icons": "1.3.38",
|
|
20
|
+
"@trackunit/ui-design-tokens": "1.3.38",
|
|
21
|
+
"@trackunit/shared-utils": "1.5.38",
|
|
22
|
+
"@trackunit/i18n-library-translation": "1.3.41"
|
|
23
23
|
},
|
|
24
24
|
"module": "./index.esm.js",
|
|
25
25
|
"main": "./index.cjs.js",
|
|
@@ -11,3 +11,4 @@ export declare const CustomTimestamp: () => import("react/jsx-runtime").JSX.Elem
|
|
|
11
11
|
export declare const CustomDot: () => import("react/jsx-runtime").JSX.Element;
|
|
12
12
|
export declare const IncorrectUse: () => import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
export declare const HoverAndSelectBehavior: () => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const PaginatedTimeline: () => import("react/jsx-runtime").JSX.Element;
|
package/src/translation.d.ts
CHANGED
|
@@ -14,8 +14,8 @@ export declare const translations: TranslationResource<TranslationKeys>;
|
|
|
14
14
|
/**
|
|
15
15
|
* Local useTranslation for this specific library
|
|
16
16
|
*/
|
|
17
|
-
export declare const useTranslation: () => [TransForLibs<"dateTime.instant.now" | "dayRangePickerPopover.icon.tooltip.calendar" | "layout.actions.apply" | "layout.actions.cancel" | "layout.actions.clear" | "shared.timePeriods.days" | "shared.timePeriods.days_plural" | "shared.timePeriods.hours" | "shared.timePeriods.hours_plural" | "shared.timePeriods.months" | "shared.timePeriods.months_plural" | "shared.timePeriods.today" | "shared.timePeriods.weeks" | "shared.timePeriods.weeks_plural">, import("i18next").i18n, boolean] & {
|
|
18
|
-
t: TransForLibs<"dateTime.instant.now" | "dayRangePickerPopover.icon.tooltip.calendar" | "layout.actions.apply" | "layout.actions.cancel" | "layout.actions.clear" | "shared.timePeriods.days" | "shared.timePeriods.days_plural" | "shared.timePeriods.hours" | "shared.timePeriods.hours_plural" | "shared.timePeriods.months" | "shared.timePeriods.months_plural" | "shared.timePeriods.today" | "shared.timePeriods.weeks" | "shared.timePeriods.weeks_plural">;
|
|
17
|
+
export declare const useTranslation: () => [TransForLibs<"dateTime.instant.now" | "dayRangePickerPopover.icon.tooltip.calendar" | "layout.actions.apply" | "layout.actions.cancel" | "layout.actions.clear" | "shared.timePeriods.days" | "shared.timePeriods.days_plural" | "shared.timePeriods.hours" | "shared.timePeriods.hours_plural" | "shared.timePeriods.months" | "shared.timePeriods.months_plural" | "shared.timePeriods.today" | "shared.timePeriods.weeks" | "shared.timePeriods.weeks_plural" | "timeline.loadMore">, import("i18next").i18n, boolean] & {
|
|
18
|
+
t: TransForLibs<"dateTime.instant.now" | "dayRangePickerPopover.icon.tooltip.calendar" | "layout.actions.apply" | "layout.actions.cancel" | "layout.actions.clear" | "shared.timePeriods.days" | "shared.timePeriods.days_plural" | "shared.timePeriods.hours" | "shared.timePeriods.hours_plural" | "shared.timePeriods.months" | "shared.timePeriods.months_plural" | "shared.timePeriods.today" | "shared.timePeriods.weeks" | "shared.timePeriods.weeks_plural" | "timeline.loadMore">;
|
|
19
19
|
i18n: import("i18next").i18n;
|
|
20
20
|
ready: boolean;
|
|
21
21
|
};
|