@bsol-oss/react-datatable5 13.0.1-beta.33 → 13.0.1-beta.35
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/dist/index.d.ts +31 -3
- package/dist/index.js +109 -72
- package/dist/index.mjs +109 -72
- package/dist/types/components/DatePicker/TimeRangeZoom.d.ts +30 -2
- package/dist/types/components/DatePicker/index.d.ts +1 -1
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -1057,6 +1057,10 @@ interface TimeViewportGridProps {
|
|
|
1057
1057
|
viewportStart?: TimeInput;
|
|
1058
1058
|
viewportEnd?: TimeInput;
|
|
1059
1059
|
tickCount?: number;
|
|
1060
|
+
tickStrategy?: 'count' | 'timeUnit';
|
|
1061
|
+
tickUnit?: 'minute' | 'hour' | 'day';
|
|
1062
|
+
tickStep?: number;
|
|
1063
|
+
format?: string;
|
|
1060
1064
|
minorDivisions?: number;
|
|
1061
1065
|
majorLineColor?: string;
|
|
1062
1066
|
minorLineColor?: string;
|
|
@@ -1065,6 +1069,20 @@ interface TimeViewportGridProps {
|
|
|
1065
1069
|
animationDurationMs?: number;
|
|
1066
1070
|
animationEasing?: string;
|
|
1067
1071
|
}
|
|
1072
|
+
interface TimeViewportBlockRenderArgs {
|
|
1073
|
+
block: TimeViewportBlockItem;
|
|
1074
|
+
geometry: {
|
|
1075
|
+
leftPercent: number;
|
|
1076
|
+
widthPercent: number;
|
|
1077
|
+
};
|
|
1078
|
+
index: number;
|
|
1079
|
+
}
|
|
1080
|
+
interface TimeViewportTrackRenderArgs {
|
|
1081
|
+
trackIndex: number;
|
|
1082
|
+
trackKey?: string | number;
|
|
1083
|
+
trackBlocks: TimeViewportBlockItem[];
|
|
1084
|
+
defaultContent: ReactNode;
|
|
1085
|
+
}
|
|
1068
1086
|
interface TimeViewportBlocksProps {
|
|
1069
1087
|
blocks: TimeViewportBlockItem[];
|
|
1070
1088
|
viewportStart?: TimeInput;
|
|
@@ -1089,7 +1107,17 @@ interface TimeViewportBlocksProps {
|
|
|
1089
1107
|
trackBlocks: TimeViewportBlockItem[];
|
|
1090
1108
|
trackKey?: string | number;
|
|
1091
1109
|
}) => ReactNode;
|
|
1110
|
+
/** Custom render function for block content. The returned node is placed inside a positioning wrapper that handles translateX and transitions. */
|
|
1111
|
+
renderBlock?: (args: TimeViewportBlockRenderArgs) => ReactNode;
|
|
1112
|
+
/** Custom render function for an entire track row. Receives the default rendered content so you can wrap or replace it. */
|
|
1113
|
+
renderTrack?: (args: TimeViewportTrackRenderArgs) => ReactNode;
|
|
1092
1114
|
onBlockClick?: (block: TimeViewportBlockItem) => void;
|
|
1115
|
+
/** Enable virtual scrolling for large track lists. */
|
|
1116
|
+
virtualize?: boolean;
|
|
1117
|
+
/** Fixed pixel height of the scroll container when virtualize is true. Defaults to 400. */
|
|
1118
|
+
virtualHeight?: number;
|
|
1119
|
+
/** Number of off-screen rows to render above/below the visible area. Defaults to 5. */
|
|
1120
|
+
overscan?: number;
|
|
1093
1121
|
}
|
|
1094
1122
|
interface TimeViewportRootProps {
|
|
1095
1123
|
viewportStart: TimeInput;
|
|
@@ -1172,8 +1200,8 @@ declare function TimeViewportHeader({ viewportStart, viewportEnd, tickCount, tic
|
|
|
1172
1200
|
* Vertical grid lines for measuring block positions in the viewport.
|
|
1173
1201
|
* Render inside a relative container that also contains blocks.
|
|
1174
1202
|
*/
|
|
1175
|
-
declare function TimeViewportGrid({ viewportStart, viewportEnd, tickCount, minorDivisions, majorLineColor, minorLineColor, showMinorLines, zIndex, animationDurationMs, animationEasing, }: TimeViewportGridProps): react_jsx_runtime.JSX.Element | null;
|
|
1176
|
-
declare function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height, minWidthPx, borderRadius, defaultColorPalette, showLabel, hideWhenOutOfView, hideEmptyTracks, gap, allowOverlap, overlapOpacity, renderTrackPrefix, renderTrackSuffix, onBlockClick, }: TimeViewportBlocksProps): react_jsx_runtime.JSX.Element;
|
|
1203
|
+
declare function TimeViewportGrid({ viewportStart, viewportEnd, tickCount, tickStrategy, tickUnit, tickStep, format, minorDivisions, majorLineColor, minorLineColor, showMinorLines, zIndex, animationDurationMs, animationEasing, }: TimeViewportGridProps): react_jsx_runtime.JSX.Element | null;
|
|
1204
|
+
declare function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height, minWidthPx, borderRadius, defaultColorPalette, showLabel, hideWhenOutOfView, hideEmptyTracks, gap, allowOverlap, overlapOpacity, renderTrackPrefix, renderTrackSuffix, renderBlock, renderTrack, onBlockClick, virtualize, virtualHeight, overscan, }: TimeViewportBlocksProps): react_jsx_runtime.JSX.Element;
|
|
1177
1205
|
declare function TimeRangeZoom({ range, onRangeChange, minDurationMs, maxDurationMs, zoomFactor, resetDurationMs, showResetButton, disabled, labels, }: TimeRangeZoomProps): react_jsx_runtime.JSX.Element;
|
|
1178
1206
|
declare function useTimeRangeZoom({ range, onRangeChange, minDurationMs, maxDurationMs, zoomFactor, resetDurationMs, disabled, labels, }: TimeRangeZoomProps): UseTimeRangeZoomResult;
|
|
1179
1207
|
|
|
@@ -1450,4 +1478,4 @@ declare module '@tanstack/react-table' {
|
|
|
1450
1478
|
}
|
|
1451
1479
|
}
|
|
1452
1480
|
|
|
1453
|
-
export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, type CustomQueryFn, type CustomQueryFnParams, type CustomQueryFnResponse, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerContext, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, type LoadInitialValuesParams, type LoadInitialValuesResult, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, type TableFilterTagsProps, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, TextCell, type TextCellProps, type TimePickerLabels, TimeRangeZoom, type TimeRangeZoomLabels, type TimeRangeZoomProps, TimeViewportBlock, type TimeViewportBlockItem, type TimeViewportBlockProps, TimeViewportBlocks, type TimeViewportBlocksProps, TimeViewportGrid, type TimeViewportGridProps, TimeViewportHeader, type TimeViewportHeaderProps, type TimeViewportHeaderTick, TimeViewportMarkerLine, type TimeViewportMarkerLineProps, TimeViewportRoot, type TimeViewportRootProps, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type UseTimeRangeZoomResult, type UseTimeViewportBlockGeometryResult, type UseTimeViewportDerivedResult, type UseTimeViewportTicksResult, type ValidationErrorType, ViewDialog, type ViewableTimeRange, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm, useTimeRangeZoom, useTimeViewport, useTimeViewportBlockGeometry, useTimeViewportHeader, useTimeViewportTicks };
|
|
1481
|
+
export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, type CustomQueryFn, type CustomQueryFnParams, type CustomQueryFnResponse, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerContext, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, type LoadInitialValuesParams, type LoadInitialValuesResult, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, type TableFilterTagsProps, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, TextCell, type TextCellProps, type TimePickerLabels, TimeRangeZoom, type TimeRangeZoomLabels, type TimeRangeZoomProps, TimeViewportBlock, type TimeViewportBlockItem, type TimeViewportBlockProps, type TimeViewportBlockRenderArgs, TimeViewportBlocks, type TimeViewportBlocksProps, TimeViewportGrid, type TimeViewportGridProps, TimeViewportHeader, type TimeViewportHeaderProps, type TimeViewportHeaderTick, TimeViewportMarkerLine, type TimeViewportMarkerLineProps, TimeViewportRoot, type TimeViewportRootProps, type TimeViewportTrackRenderArgs, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type UseTimeRangeZoomResult, type UseTimeViewportBlockGeometryResult, type UseTimeViewportDerivedResult, type UseTimeViewportTicksResult, type ValidationErrorType, ViewDialog, type ViewableTimeRange, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm, useTimeRangeZoom, useTimeViewport, useTimeViewportBlockGeometry, useTimeViewportHeader, useTimeViewportTicks };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var timezone = require('dayjs/plugin/timezone');
|
|
|
32
32
|
var utc = require('dayjs/plugin/utc');
|
|
33
33
|
var ti = require('react-icons/ti');
|
|
34
34
|
var ajv = require('@hookform/resolvers/ajv');
|
|
35
|
+
var reactVirtual = require('@tanstack/react-virtual');
|
|
35
36
|
var matchSorterUtils = require('@tanstack/match-sorter-utils');
|
|
36
37
|
|
|
37
38
|
function _interopNamespaceDefault(e) {
|
|
@@ -8095,7 +8096,7 @@ function TimeViewportRoot({ viewportStart, viewportEnd, children, onViewportChan
|
|
|
8095
8096
|
return (jsxRuntime.jsx(TimeViewportContext.Provider, { value: { viewportStart, viewportEnd }, children: jsxRuntime.jsx(react.Box, { ref: containerRef, position: "relative", width: "100%", cursor: enableDragPan ? (isDragging ? 'grabbing' : 'grab') : 'default', userSelect: enableDragPan ? 'none' : undefined, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: stopDragging, onPointerCancel: stopDragging, onWheel: handleWheel, children: children }) }));
|
|
8096
8097
|
}
|
|
8097
8098
|
function TimeViewportTrackRow({ trackKey, blocks, resolvedHeight, prefix, suffix, renderBlockNode, }) {
|
|
8098
|
-
return (jsxRuntime.jsxs(react.
|
|
8099
|
+
return (jsxRuntime.jsxs(react.Box, { width: "100%", overflowX: 'hidden', position: "relative", height: resolvedHeight, children: [jsxRuntime.jsx(react.Box, { position: "relative", width: "100%", height: "100%", children: blocks.map((item, index) => renderBlockNode(item, index)) }), prefix ? (jsxRuntime.jsx(react.Box, { position: "absolute", top: 0, insetInlineStart: 0, zIndex: 2, pointerEvents: "auto", children: prefix })) : null, suffix ? (jsxRuntime.jsx(react.Box, { position: "absolute", top: 0, insetInlineEnd: 0, zIndex: 2, pointerEvents: "auto", children: suffix })) : null] }, trackKey));
|
|
8099
8100
|
}
|
|
8100
8101
|
const defaultLabels = {
|
|
8101
8102
|
zoomIn: 'Zoom in',
|
|
@@ -8333,7 +8334,7 @@ function TimeViewportMarkerLine({ timestamp, viewportStart, viewportEnd, height
|
|
|
8333
8334
|
return null;
|
|
8334
8335
|
if (hideWhenOutOfView && !marker.inView)
|
|
8335
8336
|
return null;
|
|
8336
|
-
return (jsxRuntime.jsx(react.Box, { position: "absolute", insetInlineStart: 0, insetInlineEnd: 0, top: 0, bottom: 0, pointerEvents: "none", zIndex: 100, height: height, children: jsxRuntime.jsxs(react.Box, { width: "100%", height: "100%", transform: `translateX(${marker.percent}%)`, transition: VIEWPORT_TRANSITION, transformOrigin: "left center", children: [jsxRuntime.jsx(react.Box, { width: `${lineWidthPx}px`, height: "100%", bg: color ?? `${colorPalette}.500`, _dark: { bg: color ?? `${colorPalette}.
|
|
8337
|
+
return (jsxRuntime.jsx(react.Box, { position: "absolute", insetInlineStart: 0, insetInlineEnd: 0, top: 0, bottom: 0, pointerEvents: "none", zIndex: 100, height: height, children: jsxRuntime.jsxs(react.Box, { width: "100%", height: "100%", transform: `translateX(${marker.percent}%)`, transition: VIEWPORT_TRANSITION, transformOrigin: "left center", children: [jsxRuntime.jsx(react.Box, { width: `${lineWidthPx}px`, height: "100%", bg: color ?? `${colorPalette}.500`, _dark: { bg: color ?? `${colorPalette}.500` }, transform: "translateX(-50%)" }), showLabel && label ? (jsxRuntime.jsx(react.Text, { position: "absolute", insetInlineStart: 0, top: "100%", mt: 1, display: "inline-block", fontSize: "xs", whiteSpace: "nowrap", color: color ?? `${colorPalette}.700`, _dark: { color: color ?? `${colorPalette}.500` }, transform: "translateX(-50%)", children: label })) : null] }) }));
|
|
8337
8338
|
}
|
|
8338
8339
|
/**
|
|
8339
8340
|
* Header labels for timeline viewport time scale.
|
|
@@ -8357,35 +8358,64 @@ function TimeViewportHeader({ viewportStart, viewportEnd, tickCount = 7, tickStr
|
|
|
8357
8358
|
* Vertical grid lines for measuring block positions in the viewport.
|
|
8358
8359
|
* Render inside a relative container that also contains blocks.
|
|
8359
8360
|
*/
|
|
8360
|
-
function TimeViewportGrid({ viewportStart, viewportEnd, tickCount = 8, minorDivisions = 2, majorLineColor = 'gray.300', minorLineColor = 'gray.200', showMinorLines = true, zIndex = 0, animationDurationMs = VIEWPORT_TRANSITION_DURATION_MS, animationEasing = VIEWPORT_TRANSITION_EASING, }) {
|
|
8361
|
-
const
|
|
8362
|
-
const
|
|
8363
|
-
|
|
8364
|
-
if (!start || !end || !end.isAfter(start))
|
|
8361
|
+
function TimeViewportGrid({ viewportStart, viewportEnd, tickCount = 8, tickStrategy = 'count', tickUnit = 'hour', tickStep = 1, format, minorDivisions = 2, majorLineColor = 'gray.300', minorLineColor = 'gray.200', showMinorLines = true, zIndex = 0, animationDurationMs = VIEWPORT_TRANSITION_DURATION_MS, animationEasing = VIEWPORT_TRANSITION_EASING, }) {
|
|
8362
|
+
const { isValidViewport, getTicks } = useTimeViewport(viewportStart, viewportEnd, format);
|
|
8363
|
+
const majorTicks = getTicks({ tickStrategy, tickCount, tickUnit, tickStep });
|
|
8364
|
+
if (!isValidViewport || majorTicks.length < 2)
|
|
8365
8365
|
return null;
|
|
8366
|
-
const safeTickCount = Math.max(2, tickCount);
|
|
8367
|
-
const majorTicks = Array.from({ length: safeTickCount }, (_, index) => ({
|
|
8368
|
-
index,
|
|
8369
|
-
percent: (index / (safeTickCount - 1)) * 100,
|
|
8370
|
-
}));
|
|
8371
8366
|
const safeMinorDivisions = Math.max(1, minorDivisions);
|
|
8372
8367
|
const transitionValue = animationDurationMs > 0
|
|
8373
8368
|
? `transform ${animationDurationMs}ms ${animationEasing}, opacity ${animationDurationMs}ms ${animationEasing}`
|
|
8374
8369
|
: undefined;
|
|
8375
8370
|
const minorTicks = showMinorLines
|
|
8376
|
-
?
|
|
8377
|
-
const base =
|
|
8378
|
-
const next =
|
|
8371
|
+
? majorTicks.slice(0, -1).flatMap((tick, segmentIndex) => {
|
|
8372
|
+
const base = tick.percent;
|
|
8373
|
+
const next = majorTicks[segmentIndex + 1].percent;
|
|
8379
8374
|
const segment = [];
|
|
8380
8375
|
for (let step = 1; step < safeMinorDivisions; step += 1) {
|
|
8381
8376
|
segment.push(base + ((next - base) * step) / safeMinorDivisions);
|
|
8382
8377
|
}
|
|
8383
8378
|
return segment;
|
|
8384
|
-
})
|
|
8379
|
+
})
|
|
8385
8380
|
: [];
|
|
8386
8381
|
return (jsxRuntime.jsxs(react.Box, { position: "absolute", inset: 0, pointerEvents: "none", zIndex: zIndex, children: [minorTicks.map((percent, index) => (jsxRuntime.jsx(react.Box, { position: "absolute", inset: 0, transform: `translateX(${percent}%)`, transition: transitionValue, children: jsxRuntime.jsx(react.Box, { position: "absolute", insetInlineStart: 0, top: 0, bottom: 0, width: "1px", bg: minorLineColor, _dark: { bg: 'gray.700' } }) }, `minor-grid-${index}`))), majorTicks.map((tick) => (jsxRuntime.jsx(react.Box, { position: "absolute", inset: 0, transform: `translateX(${tick.percent}%)`, transition: transitionValue, children: jsxRuntime.jsx(react.Box, { position: "absolute", insetInlineStart: 0, top: 0, bottom: 0, width: "1px", bg: majorLineColor, _dark: { bg: 'gray.600' } }) }, `major-grid-${tick.index}`)))] }));
|
|
8387
8382
|
}
|
|
8388
|
-
function
|
|
8383
|
+
function VirtualizedTrackList({ tracks, resolvedHeight, gap, virtualHeight, overscan, renderTrackPrefix, renderTrackSuffix, renderTrack, renderBlockNode, }) {
|
|
8384
|
+
const parentRef = React.useRef(null);
|
|
8385
|
+
const rowHeightPx = parseInt(resolvedHeight, 10) || 28;
|
|
8386
|
+
const gapPx = gap * 4; // Chakra spacing token to px (1 unit = 4px)
|
|
8387
|
+
const virtualizer = reactVirtual.useVirtualizer({
|
|
8388
|
+
count: tracks.length,
|
|
8389
|
+
getScrollElement: () => parentRef.current,
|
|
8390
|
+
estimateSize: () => rowHeightPx + gapPx,
|
|
8391
|
+
overscan,
|
|
8392
|
+
});
|
|
8393
|
+
return (jsxRuntime.jsx(react.Box, { ref: parentRef, overflowY: "auto", height: `${virtualHeight}px`, children: jsxRuntime.jsx(react.Box, { height: `${virtualizer.getTotalSize()}px`, position: "relative", children: virtualizer.getVirtualItems().map((virtualRow) => {
|
|
8394
|
+
const track = tracks[virtualRow.index];
|
|
8395
|
+
const trackBlocks = track.blocks.map((item) => item.block);
|
|
8396
|
+
const prefix = renderTrackPrefix?.({
|
|
8397
|
+
trackIndex: virtualRow.index,
|
|
8398
|
+
trackBlocks,
|
|
8399
|
+
trackKey: track.trackKeyRaw,
|
|
8400
|
+
});
|
|
8401
|
+
const suffix = renderTrackSuffix?.({
|
|
8402
|
+
trackIndex: virtualRow.index,
|
|
8403
|
+
trackBlocks,
|
|
8404
|
+
trackKey: track.trackKeyRaw,
|
|
8405
|
+
});
|
|
8406
|
+
const defaultContent = (jsxRuntime.jsx(TimeViewportTrackRow, { trackKey: track.trackKey, blocks: track.blocks, resolvedHeight: resolvedHeight, prefix: prefix, suffix: suffix, renderBlockNode: renderBlockNode }));
|
|
8407
|
+
const trackContent = renderTrack
|
|
8408
|
+
? renderTrack({
|
|
8409
|
+
trackIndex: virtualRow.index,
|
|
8410
|
+
trackKey: track.trackKeyRaw,
|
|
8411
|
+
trackBlocks,
|
|
8412
|
+
defaultContent,
|
|
8413
|
+
})
|
|
8414
|
+
: defaultContent;
|
|
8415
|
+
return (jsxRuntime.jsx(react.Box, { position: "absolute", top: 0, left: 0, width: "100%", transform: `translateY(${virtualRow.start}px)`, children: trackContent }, track.trackKey));
|
|
8416
|
+
}) }) }));
|
|
8417
|
+
}
|
|
8418
|
+
function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height = '28px', minWidthPx = 2, borderRadius = 'sm', defaultColorPalette = 'blue', showLabel = true, hideWhenOutOfView = true, hideEmptyTracks = true, gap = 2, allowOverlap = false, overlapOpacity = 0.9, renderTrackPrefix, renderTrackSuffix, renderBlock, renderTrack, onBlockClick, virtualize = false, virtualHeight = 400, overscan = 5, }) {
|
|
8389
8419
|
const { getGeometry, toTimeMs } = useTimeViewportBlockGeometry(viewportStart, viewportEnd);
|
|
8390
8420
|
const resolvedHeight = typeof height === 'number' ? `${height}px` : height;
|
|
8391
8421
|
const expandedBlocks = flattenTrackBlocks(blocks);
|
|
@@ -8420,74 +8450,81 @@ function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height = '28px
|
|
|
8420
8450
|
onBlockClick?.(block);
|
|
8421
8451
|
};
|
|
8422
8452
|
const isBlockClickable = Boolean(block.onClick || onBlockClick);
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8453
|
+
const content = renderBlock ? (renderBlock({ block, geometry, index: indexInLayer })) : (jsxRuntime.jsx(react.Box, { width: `max(${geometry.widthPercent}%, ${minWidthPx}px)`, height: "100%", borderRadius: borderRadius, bg: block.background ?? `${block.colorPalette ?? defaultColorPalette}.500`, _dark: {
|
|
8454
|
+
bg: block.background ??
|
|
8455
|
+
`${block.colorPalette ?? defaultColorPalette}.900`,
|
|
8456
|
+
}, display: "flex", alignItems: "center", justifyContent: "center", px: 2, overflow: "hidden", opacity: allowOverlap ? overlapOpacity : 1, zIndex: indexInLayer + 1, pointerEvents: "auto", onClick: isBlockClickable ? handleBlockClick : undefined, cursor: isBlockClickable ? 'pointer' : 'default', children: showLabel && block.label ? (jsxRuntime.jsx(react.Text, { fontSize: "xs", lineClamp: 1, children: block.label })) : null }));
|
|
8457
|
+
return (jsxRuntime.jsx(react.Box, { height: "100%", position: "absolute", inset: 0, pointerEvents: "none", transform: `translateX(${geometry.leftPercent}%)`, transition: VIEWPORT_TRANSITION, children: content }, block.id));
|
|
8428
8458
|
};
|
|
8459
|
+
// ---------- Resolve tracks ----------
|
|
8429
8460
|
const explicitTrackKeys = Array.from(new Set(expandedBlocks
|
|
8430
8461
|
.map((item) => item.track)
|
|
8431
8462
|
.filter((track) => track !== undefined)));
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8463
|
+
const resolvedTracks = React.useMemo(() => {
|
|
8464
|
+
if (explicitTrackKeys.length > 0) {
|
|
8465
|
+
return explicitTrackKeys
|
|
8466
|
+
.map((trackKey) => ({
|
|
8467
|
+
trackKey: `track-keyed-${String(trackKey)}`,
|
|
8468
|
+
trackKeyRaw: trackKey,
|
|
8469
|
+
blocks: parsedBlocks.filter((item) => item.block.track === trackKey),
|
|
8470
|
+
}))
|
|
8471
|
+
.filter((track) => !hideEmptyTracks || track.blocks.length > 0);
|
|
8472
|
+
}
|
|
8473
|
+
const autoPackedTracks = (() => {
|
|
8474
|
+
const sortedBlocks = [...parsedBlocks]
|
|
8475
|
+
.filter(({ startMs, endMs }) => Number.isFinite(startMs) && Number.isFinite(endMs))
|
|
8476
|
+
.sort((a, b) => {
|
|
8477
|
+
if (a.startMs === b.startMs)
|
|
8478
|
+
return a.endMs - b.endMs;
|
|
8479
|
+
return a.startMs - b.startMs;
|
|
8480
|
+
});
|
|
8481
|
+
const trackLastEndTimes = [];
|
|
8482
|
+
const tracks = [];
|
|
8483
|
+
sortedBlocks.forEach((item) => {
|
|
8484
|
+
const trackIndex = trackLastEndTimes.findIndex((endMs) => item.startMs >= endMs);
|
|
8485
|
+
if (trackIndex === -1) {
|
|
8486
|
+
trackLastEndTimes.push(item.endMs);
|
|
8487
|
+
tracks.push([item]);
|
|
8488
|
+
}
|
|
8489
|
+
else {
|
|
8490
|
+
trackLastEndTimes[trackIndex] = item.endMs;
|
|
8491
|
+
tracks[trackIndex].push(item);
|
|
8492
|
+
}
|
|
8493
|
+
});
|
|
8494
|
+
return tracks;
|
|
8495
|
+
})();
|
|
8496
|
+
const packed = allowOverlap ? [parsedBlocks] : autoPackedTracks;
|
|
8497
|
+
return packed.map((track, trackIndex) => ({
|
|
8498
|
+
trackKey: `track-row-${trackIndex}`,
|
|
8499
|
+
trackKeyRaw: undefined,
|
|
8500
|
+
blocks: track,
|
|
8501
|
+
}));
|
|
8502
|
+
}, [allowOverlap, explicitTrackKeys, hideEmptyTracks, parsedBlocks]);
|
|
8503
|
+
// ---------- Render ----------
|
|
8504
|
+
if (virtualize) {
|
|
8505
|
+
return (jsxRuntime.jsx(VirtualizedTrackList, { tracks: resolvedTracks, resolvedHeight: resolvedHeight, gap: gap, virtualHeight: virtualHeight, overscan: overscan, renderTrackPrefix: renderTrackPrefix, renderTrackSuffix: renderTrackSuffix, renderTrack: renderTrack, renderBlockNode: renderBlockNode }));
|
|
8453
8506
|
}
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
.filter(({ startMs, endMs }) => Number.isFinite(startMs) && Number.isFinite(endMs))
|
|
8457
|
-
.sort((a, b) => {
|
|
8458
|
-
if (a.startMs === b.startMs)
|
|
8459
|
-
return a.endMs - b.endMs;
|
|
8460
|
-
return a.startMs - b.startMs;
|
|
8461
|
-
});
|
|
8462
|
-
const trackLastEndTimes = [];
|
|
8463
|
-
const tracks = [];
|
|
8464
|
-
sortedBlocks.forEach((item) => {
|
|
8465
|
-
const trackIndex = trackLastEndTimes.findIndex((endMs) => item.startMs >= endMs);
|
|
8466
|
-
if (trackIndex === -1) {
|
|
8467
|
-
trackLastEndTimes.push(item.endMs);
|
|
8468
|
-
tracks.push([item]);
|
|
8469
|
-
}
|
|
8470
|
-
else {
|
|
8471
|
-
trackLastEndTimes[trackIndex] = item.endMs;
|
|
8472
|
-
tracks[trackIndex].push(item);
|
|
8473
|
-
}
|
|
8474
|
-
});
|
|
8475
|
-
return tracks;
|
|
8476
|
-
})();
|
|
8477
|
-
const tracks = allowOverlap ? [parsedBlocks] : autoPackedTracks;
|
|
8478
|
-
return (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: gap, children: tracks.map((track, trackIndex) => {
|
|
8479
|
-
const trackBlocks = track.map((item) => item.block);
|
|
8507
|
+
return (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: gap, children: resolvedTracks.map((track, trackIndex) => {
|
|
8508
|
+
const trackBlocks = track.blocks.map((item) => item.block);
|
|
8480
8509
|
const prefix = renderTrackPrefix?.({
|
|
8481
8510
|
trackIndex,
|
|
8482
8511
|
trackBlocks,
|
|
8483
|
-
trackKey:
|
|
8512
|
+
trackKey: track.trackKeyRaw,
|
|
8484
8513
|
});
|
|
8485
8514
|
const suffix = renderTrackSuffix?.({
|
|
8486
8515
|
trackIndex,
|
|
8487
8516
|
trackBlocks,
|
|
8488
|
-
trackKey:
|
|
8517
|
+
trackKey: track.trackKeyRaw,
|
|
8489
8518
|
});
|
|
8490
|
-
|
|
8519
|
+
const defaultContent = (jsxRuntime.jsx(TimeViewportTrackRow, { trackKey: track.trackKey, blocks: track.blocks, resolvedHeight: resolvedHeight, prefix: prefix, suffix: suffix, renderBlockNode: renderBlockNode }));
|
|
8520
|
+
return renderTrack
|
|
8521
|
+
? renderTrack({
|
|
8522
|
+
trackIndex,
|
|
8523
|
+
trackKey: track.trackKeyRaw,
|
|
8524
|
+
trackBlocks,
|
|
8525
|
+
defaultContent,
|
|
8526
|
+
})
|
|
8527
|
+
: defaultContent;
|
|
8491
8528
|
}) }));
|
|
8492
8529
|
}
|
|
8493
8530
|
function TimeRangeZoom({ range, onRangeChange, minDurationMs = DEFAULT_MIN_DURATION_MS, maxDurationMs = DEFAULT_MAX_DURATION_MS, zoomFactor = DEFAULT_ZOOM_FACTOR, resetDurationMs, showResetButton = true, disabled = false, labels, }) {
|
package/dist/index.mjs
CHANGED
|
@@ -31,6 +31,7 @@ import timezone from 'dayjs/plugin/timezone';
|
|
|
31
31
|
import utc from 'dayjs/plugin/utc';
|
|
32
32
|
import { TiDeleteOutline } from 'react-icons/ti';
|
|
33
33
|
import { ajvResolver } from '@hookform/resolvers/ajv';
|
|
34
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
34
35
|
import { rankItem } from '@tanstack/match-sorter-utils';
|
|
35
36
|
|
|
36
37
|
const DataTableContext = createContext({
|
|
@@ -8075,7 +8076,7 @@ function TimeViewportRoot({ viewportStart, viewportEnd, children, onViewportChan
|
|
|
8075
8076
|
return (jsx(TimeViewportContext.Provider, { value: { viewportStart, viewportEnd }, children: jsx(Box, { ref: containerRef, position: "relative", width: "100%", cursor: enableDragPan ? (isDragging ? 'grabbing' : 'grab') : 'default', userSelect: enableDragPan ? 'none' : undefined, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: stopDragging, onPointerCancel: stopDragging, onWheel: handleWheel, children: children }) }));
|
|
8076
8077
|
}
|
|
8077
8078
|
function TimeViewportTrackRow({ trackKey, blocks, resolvedHeight, prefix, suffix, renderBlockNode, }) {
|
|
8078
|
-
return (jsxs(
|
|
8079
|
+
return (jsxs(Box, { width: "100%", overflowX: 'hidden', position: "relative", height: resolvedHeight, children: [jsx(Box, { position: "relative", width: "100%", height: "100%", children: blocks.map((item, index) => renderBlockNode(item, index)) }), prefix ? (jsx(Box, { position: "absolute", top: 0, insetInlineStart: 0, zIndex: 2, pointerEvents: "auto", children: prefix })) : null, suffix ? (jsx(Box, { position: "absolute", top: 0, insetInlineEnd: 0, zIndex: 2, pointerEvents: "auto", children: suffix })) : null] }, trackKey));
|
|
8079
8080
|
}
|
|
8080
8081
|
const defaultLabels = {
|
|
8081
8082
|
zoomIn: 'Zoom in',
|
|
@@ -8313,7 +8314,7 @@ function TimeViewportMarkerLine({ timestamp, viewportStart, viewportEnd, height
|
|
|
8313
8314
|
return null;
|
|
8314
8315
|
if (hideWhenOutOfView && !marker.inView)
|
|
8315
8316
|
return null;
|
|
8316
|
-
return (jsx(Box, { position: "absolute", insetInlineStart: 0, insetInlineEnd: 0, top: 0, bottom: 0, pointerEvents: "none", zIndex: 100, height: height, children: jsxs(Box, { width: "100%", height: "100%", transform: `translateX(${marker.percent}%)`, transition: VIEWPORT_TRANSITION, transformOrigin: "left center", children: [jsx(Box, { width: `${lineWidthPx}px`, height: "100%", bg: color ?? `${colorPalette}.500`, _dark: { bg: color ?? `${colorPalette}.
|
|
8317
|
+
return (jsx(Box, { position: "absolute", insetInlineStart: 0, insetInlineEnd: 0, top: 0, bottom: 0, pointerEvents: "none", zIndex: 100, height: height, children: jsxs(Box, { width: "100%", height: "100%", transform: `translateX(${marker.percent}%)`, transition: VIEWPORT_TRANSITION, transformOrigin: "left center", children: [jsx(Box, { width: `${lineWidthPx}px`, height: "100%", bg: color ?? `${colorPalette}.500`, _dark: { bg: color ?? `${colorPalette}.500` }, transform: "translateX(-50%)" }), showLabel && label ? (jsx(Text, { position: "absolute", insetInlineStart: 0, top: "100%", mt: 1, display: "inline-block", fontSize: "xs", whiteSpace: "nowrap", color: color ?? `${colorPalette}.700`, _dark: { color: color ?? `${colorPalette}.500` }, transform: "translateX(-50%)", children: label })) : null] }) }));
|
|
8317
8318
|
}
|
|
8318
8319
|
/**
|
|
8319
8320
|
* Header labels for timeline viewport time scale.
|
|
@@ -8337,35 +8338,64 @@ function TimeViewportHeader({ viewportStart, viewportEnd, tickCount = 7, tickStr
|
|
|
8337
8338
|
* Vertical grid lines for measuring block positions in the viewport.
|
|
8338
8339
|
* Render inside a relative container that also contains blocks.
|
|
8339
8340
|
*/
|
|
8340
|
-
function TimeViewportGrid({ viewportStart, viewportEnd, tickCount = 8, minorDivisions = 2, majorLineColor = 'gray.300', minorLineColor = 'gray.200', showMinorLines = true, zIndex = 0, animationDurationMs = VIEWPORT_TRANSITION_DURATION_MS, animationEasing = VIEWPORT_TRANSITION_EASING, }) {
|
|
8341
|
-
const
|
|
8342
|
-
const
|
|
8343
|
-
|
|
8344
|
-
if (!start || !end || !end.isAfter(start))
|
|
8341
|
+
function TimeViewportGrid({ viewportStart, viewportEnd, tickCount = 8, tickStrategy = 'count', tickUnit = 'hour', tickStep = 1, format, minorDivisions = 2, majorLineColor = 'gray.300', minorLineColor = 'gray.200', showMinorLines = true, zIndex = 0, animationDurationMs = VIEWPORT_TRANSITION_DURATION_MS, animationEasing = VIEWPORT_TRANSITION_EASING, }) {
|
|
8342
|
+
const { isValidViewport, getTicks } = useTimeViewport(viewportStart, viewportEnd, format);
|
|
8343
|
+
const majorTicks = getTicks({ tickStrategy, tickCount, tickUnit, tickStep });
|
|
8344
|
+
if (!isValidViewport || majorTicks.length < 2)
|
|
8345
8345
|
return null;
|
|
8346
|
-
const safeTickCount = Math.max(2, tickCount);
|
|
8347
|
-
const majorTicks = Array.from({ length: safeTickCount }, (_, index) => ({
|
|
8348
|
-
index,
|
|
8349
|
-
percent: (index / (safeTickCount - 1)) * 100,
|
|
8350
|
-
}));
|
|
8351
8346
|
const safeMinorDivisions = Math.max(1, minorDivisions);
|
|
8352
8347
|
const transitionValue = animationDurationMs > 0
|
|
8353
8348
|
? `transform ${animationDurationMs}ms ${animationEasing}, opacity ${animationDurationMs}ms ${animationEasing}`
|
|
8354
8349
|
: undefined;
|
|
8355
8350
|
const minorTicks = showMinorLines
|
|
8356
|
-
?
|
|
8357
|
-
const base =
|
|
8358
|
-
const next =
|
|
8351
|
+
? majorTicks.slice(0, -1).flatMap((tick, segmentIndex) => {
|
|
8352
|
+
const base = tick.percent;
|
|
8353
|
+
const next = majorTicks[segmentIndex + 1].percent;
|
|
8359
8354
|
const segment = [];
|
|
8360
8355
|
for (let step = 1; step < safeMinorDivisions; step += 1) {
|
|
8361
8356
|
segment.push(base + ((next - base) * step) / safeMinorDivisions);
|
|
8362
8357
|
}
|
|
8363
8358
|
return segment;
|
|
8364
|
-
})
|
|
8359
|
+
})
|
|
8365
8360
|
: [];
|
|
8366
8361
|
return (jsxs(Box, { position: "absolute", inset: 0, pointerEvents: "none", zIndex: zIndex, children: [minorTicks.map((percent, index) => (jsx(Box, { position: "absolute", inset: 0, transform: `translateX(${percent}%)`, transition: transitionValue, children: jsx(Box, { position: "absolute", insetInlineStart: 0, top: 0, bottom: 0, width: "1px", bg: minorLineColor, _dark: { bg: 'gray.700' } }) }, `minor-grid-${index}`))), majorTicks.map((tick) => (jsx(Box, { position: "absolute", inset: 0, transform: `translateX(${tick.percent}%)`, transition: transitionValue, children: jsx(Box, { position: "absolute", insetInlineStart: 0, top: 0, bottom: 0, width: "1px", bg: majorLineColor, _dark: { bg: 'gray.600' } }) }, `major-grid-${tick.index}`)))] }));
|
|
8367
8362
|
}
|
|
8368
|
-
function
|
|
8363
|
+
function VirtualizedTrackList({ tracks, resolvedHeight, gap, virtualHeight, overscan, renderTrackPrefix, renderTrackSuffix, renderTrack, renderBlockNode, }) {
|
|
8364
|
+
const parentRef = useRef(null);
|
|
8365
|
+
const rowHeightPx = parseInt(resolvedHeight, 10) || 28;
|
|
8366
|
+
const gapPx = gap * 4; // Chakra spacing token to px (1 unit = 4px)
|
|
8367
|
+
const virtualizer = useVirtualizer({
|
|
8368
|
+
count: tracks.length,
|
|
8369
|
+
getScrollElement: () => parentRef.current,
|
|
8370
|
+
estimateSize: () => rowHeightPx + gapPx,
|
|
8371
|
+
overscan,
|
|
8372
|
+
});
|
|
8373
|
+
return (jsx(Box, { ref: parentRef, overflowY: "auto", height: `${virtualHeight}px`, children: jsx(Box, { height: `${virtualizer.getTotalSize()}px`, position: "relative", children: virtualizer.getVirtualItems().map((virtualRow) => {
|
|
8374
|
+
const track = tracks[virtualRow.index];
|
|
8375
|
+
const trackBlocks = track.blocks.map((item) => item.block);
|
|
8376
|
+
const prefix = renderTrackPrefix?.({
|
|
8377
|
+
trackIndex: virtualRow.index,
|
|
8378
|
+
trackBlocks,
|
|
8379
|
+
trackKey: track.trackKeyRaw,
|
|
8380
|
+
});
|
|
8381
|
+
const suffix = renderTrackSuffix?.({
|
|
8382
|
+
trackIndex: virtualRow.index,
|
|
8383
|
+
trackBlocks,
|
|
8384
|
+
trackKey: track.trackKeyRaw,
|
|
8385
|
+
});
|
|
8386
|
+
const defaultContent = (jsx(TimeViewportTrackRow, { trackKey: track.trackKey, blocks: track.blocks, resolvedHeight: resolvedHeight, prefix: prefix, suffix: suffix, renderBlockNode: renderBlockNode }));
|
|
8387
|
+
const trackContent = renderTrack
|
|
8388
|
+
? renderTrack({
|
|
8389
|
+
trackIndex: virtualRow.index,
|
|
8390
|
+
trackKey: track.trackKeyRaw,
|
|
8391
|
+
trackBlocks,
|
|
8392
|
+
defaultContent,
|
|
8393
|
+
})
|
|
8394
|
+
: defaultContent;
|
|
8395
|
+
return (jsx(Box, { position: "absolute", top: 0, left: 0, width: "100%", transform: `translateY(${virtualRow.start}px)`, children: trackContent }, track.trackKey));
|
|
8396
|
+
}) }) }));
|
|
8397
|
+
}
|
|
8398
|
+
function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height = '28px', minWidthPx = 2, borderRadius = 'sm', defaultColorPalette = 'blue', showLabel = true, hideWhenOutOfView = true, hideEmptyTracks = true, gap = 2, allowOverlap = false, overlapOpacity = 0.9, renderTrackPrefix, renderTrackSuffix, renderBlock, renderTrack, onBlockClick, virtualize = false, virtualHeight = 400, overscan = 5, }) {
|
|
8369
8399
|
const { getGeometry, toTimeMs } = useTimeViewportBlockGeometry(viewportStart, viewportEnd);
|
|
8370
8400
|
const resolvedHeight = typeof height === 'number' ? `${height}px` : height;
|
|
8371
8401
|
const expandedBlocks = flattenTrackBlocks(blocks);
|
|
@@ -8400,74 +8430,81 @@ function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height = '28px
|
|
|
8400
8430
|
onBlockClick?.(block);
|
|
8401
8431
|
};
|
|
8402
8432
|
const isBlockClickable = Boolean(block.onClick || onBlockClick);
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8433
|
+
const content = renderBlock ? (renderBlock({ block, geometry, index: indexInLayer })) : (jsx(Box, { width: `max(${geometry.widthPercent}%, ${minWidthPx}px)`, height: "100%", borderRadius: borderRadius, bg: block.background ?? `${block.colorPalette ?? defaultColorPalette}.500`, _dark: {
|
|
8434
|
+
bg: block.background ??
|
|
8435
|
+
`${block.colorPalette ?? defaultColorPalette}.900`,
|
|
8436
|
+
}, display: "flex", alignItems: "center", justifyContent: "center", px: 2, overflow: "hidden", opacity: allowOverlap ? overlapOpacity : 1, zIndex: indexInLayer + 1, pointerEvents: "auto", onClick: isBlockClickable ? handleBlockClick : undefined, cursor: isBlockClickable ? 'pointer' : 'default', children: showLabel && block.label ? (jsx(Text, { fontSize: "xs", lineClamp: 1, children: block.label })) : null }));
|
|
8437
|
+
return (jsx(Box, { height: "100%", position: "absolute", inset: 0, pointerEvents: "none", transform: `translateX(${geometry.leftPercent}%)`, transition: VIEWPORT_TRANSITION, children: content }, block.id));
|
|
8408
8438
|
};
|
|
8439
|
+
// ---------- Resolve tracks ----------
|
|
8409
8440
|
const explicitTrackKeys = Array.from(new Set(expandedBlocks
|
|
8410
8441
|
.map((item) => item.track)
|
|
8411
8442
|
.filter((track) => track !== undefined)));
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8443
|
+
const resolvedTracks = useMemo(() => {
|
|
8444
|
+
if (explicitTrackKeys.length > 0) {
|
|
8445
|
+
return explicitTrackKeys
|
|
8446
|
+
.map((trackKey) => ({
|
|
8447
|
+
trackKey: `track-keyed-${String(trackKey)}`,
|
|
8448
|
+
trackKeyRaw: trackKey,
|
|
8449
|
+
blocks: parsedBlocks.filter((item) => item.block.track === trackKey),
|
|
8450
|
+
}))
|
|
8451
|
+
.filter((track) => !hideEmptyTracks || track.blocks.length > 0);
|
|
8452
|
+
}
|
|
8453
|
+
const autoPackedTracks = (() => {
|
|
8454
|
+
const sortedBlocks = [...parsedBlocks]
|
|
8455
|
+
.filter(({ startMs, endMs }) => Number.isFinite(startMs) && Number.isFinite(endMs))
|
|
8456
|
+
.sort((a, b) => {
|
|
8457
|
+
if (a.startMs === b.startMs)
|
|
8458
|
+
return a.endMs - b.endMs;
|
|
8459
|
+
return a.startMs - b.startMs;
|
|
8460
|
+
});
|
|
8461
|
+
const trackLastEndTimes = [];
|
|
8462
|
+
const tracks = [];
|
|
8463
|
+
sortedBlocks.forEach((item) => {
|
|
8464
|
+
const trackIndex = trackLastEndTimes.findIndex((endMs) => item.startMs >= endMs);
|
|
8465
|
+
if (trackIndex === -1) {
|
|
8466
|
+
trackLastEndTimes.push(item.endMs);
|
|
8467
|
+
tracks.push([item]);
|
|
8468
|
+
}
|
|
8469
|
+
else {
|
|
8470
|
+
trackLastEndTimes[trackIndex] = item.endMs;
|
|
8471
|
+
tracks[trackIndex].push(item);
|
|
8472
|
+
}
|
|
8473
|
+
});
|
|
8474
|
+
return tracks;
|
|
8475
|
+
})();
|
|
8476
|
+
const packed = allowOverlap ? [parsedBlocks] : autoPackedTracks;
|
|
8477
|
+
return packed.map((track, trackIndex) => ({
|
|
8478
|
+
trackKey: `track-row-${trackIndex}`,
|
|
8479
|
+
trackKeyRaw: undefined,
|
|
8480
|
+
blocks: track,
|
|
8481
|
+
}));
|
|
8482
|
+
}, [allowOverlap, explicitTrackKeys, hideEmptyTracks, parsedBlocks]);
|
|
8483
|
+
// ---------- Render ----------
|
|
8484
|
+
if (virtualize) {
|
|
8485
|
+
return (jsx(VirtualizedTrackList, { tracks: resolvedTracks, resolvedHeight: resolvedHeight, gap: gap, virtualHeight: virtualHeight, overscan: overscan, renderTrackPrefix: renderTrackPrefix, renderTrackSuffix: renderTrackSuffix, renderTrack: renderTrack, renderBlockNode: renderBlockNode }));
|
|
8433
8486
|
}
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
.filter(({ startMs, endMs }) => Number.isFinite(startMs) && Number.isFinite(endMs))
|
|
8437
|
-
.sort((a, b) => {
|
|
8438
|
-
if (a.startMs === b.startMs)
|
|
8439
|
-
return a.endMs - b.endMs;
|
|
8440
|
-
return a.startMs - b.startMs;
|
|
8441
|
-
});
|
|
8442
|
-
const trackLastEndTimes = [];
|
|
8443
|
-
const tracks = [];
|
|
8444
|
-
sortedBlocks.forEach((item) => {
|
|
8445
|
-
const trackIndex = trackLastEndTimes.findIndex((endMs) => item.startMs >= endMs);
|
|
8446
|
-
if (trackIndex === -1) {
|
|
8447
|
-
trackLastEndTimes.push(item.endMs);
|
|
8448
|
-
tracks.push([item]);
|
|
8449
|
-
}
|
|
8450
|
-
else {
|
|
8451
|
-
trackLastEndTimes[trackIndex] = item.endMs;
|
|
8452
|
-
tracks[trackIndex].push(item);
|
|
8453
|
-
}
|
|
8454
|
-
});
|
|
8455
|
-
return tracks;
|
|
8456
|
-
})();
|
|
8457
|
-
const tracks = allowOverlap ? [parsedBlocks] : autoPackedTracks;
|
|
8458
|
-
return (jsx(VStack, { align: "stretch", gap: gap, children: tracks.map((track, trackIndex) => {
|
|
8459
|
-
const trackBlocks = track.map((item) => item.block);
|
|
8487
|
+
return (jsx(VStack, { align: "stretch", gap: gap, children: resolvedTracks.map((track, trackIndex) => {
|
|
8488
|
+
const trackBlocks = track.blocks.map((item) => item.block);
|
|
8460
8489
|
const prefix = renderTrackPrefix?.({
|
|
8461
8490
|
trackIndex,
|
|
8462
8491
|
trackBlocks,
|
|
8463
|
-
trackKey:
|
|
8492
|
+
trackKey: track.trackKeyRaw,
|
|
8464
8493
|
});
|
|
8465
8494
|
const suffix = renderTrackSuffix?.({
|
|
8466
8495
|
trackIndex,
|
|
8467
8496
|
trackBlocks,
|
|
8468
|
-
trackKey:
|
|
8497
|
+
trackKey: track.trackKeyRaw,
|
|
8469
8498
|
});
|
|
8470
|
-
|
|
8499
|
+
const defaultContent = (jsx(TimeViewportTrackRow, { trackKey: track.trackKey, blocks: track.blocks, resolvedHeight: resolvedHeight, prefix: prefix, suffix: suffix, renderBlockNode: renderBlockNode }));
|
|
8500
|
+
return renderTrack
|
|
8501
|
+
? renderTrack({
|
|
8502
|
+
trackIndex,
|
|
8503
|
+
trackKey: track.trackKeyRaw,
|
|
8504
|
+
trackBlocks,
|
|
8505
|
+
defaultContent,
|
|
8506
|
+
})
|
|
8507
|
+
: defaultContent;
|
|
8471
8508
|
}) }));
|
|
8472
8509
|
}
|
|
8473
8510
|
function TimeRangeZoom({ range, onRangeChange, minDurationMs = DEFAULT_MIN_DURATION_MS, maxDurationMs = DEFAULT_MAX_DURATION_MS, zoomFactor = DEFAULT_ZOOM_FACTOR, resetDurationMs, showResetButton = true, disabled = false, labels, }) {
|
|
@@ -105,6 +105,10 @@ export interface TimeViewportGridProps {
|
|
|
105
105
|
viewportStart?: TimeInput;
|
|
106
106
|
viewportEnd?: TimeInput;
|
|
107
107
|
tickCount?: number;
|
|
108
|
+
tickStrategy?: 'count' | 'timeUnit';
|
|
109
|
+
tickUnit?: 'minute' | 'hour' | 'day';
|
|
110
|
+
tickStep?: number;
|
|
111
|
+
format?: string;
|
|
108
112
|
minorDivisions?: number;
|
|
109
113
|
majorLineColor?: string;
|
|
110
114
|
minorLineColor?: string;
|
|
@@ -113,6 +117,20 @@ export interface TimeViewportGridProps {
|
|
|
113
117
|
animationDurationMs?: number;
|
|
114
118
|
animationEasing?: string;
|
|
115
119
|
}
|
|
120
|
+
export interface TimeViewportBlockRenderArgs {
|
|
121
|
+
block: TimeViewportBlockItem;
|
|
122
|
+
geometry: {
|
|
123
|
+
leftPercent: number;
|
|
124
|
+
widthPercent: number;
|
|
125
|
+
};
|
|
126
|
+
index: number;
|
|
127
|
+
}
|
|
128
|
+
export interface TimeViewportTrackRenderArgs {
|
|
129
|
+
trackIndex: number;
|
|
130
|
+
trackKey?: string | number;
|
|
131
|
+
trackBlocks: TimeViewportBlockItem[];
|
|
132
|
+
defaultContent: ReactNode;
|
|
133
|
+
}
|
|
116
134
|
export interface TimeViewportBlocksProps {
|
|
117
135
|
blocks: TimeViewportBlockItem[];
|
|
118
136
|
viewportStart?: TimeInput;
|
|
@@ -137,7 +155,17 @@ export interface TimeViewportBlocksProps {
|
|
|
137
155
|
trackBlocks: TimeViewportBlockItem[];
|
|
138
156
|
trackKey?: string | number;
|
|
139
157
|
}) => ReactNode;
|
|
158
|
+
/** Custom render function for block content. The returned node is placed inside a positioning wrapper that handles translateX and transitions. */
|
|
159
|
+
renderBlock?: (args: TimeViewportBlockRenderArgs) => ReactNode;
|
|
160
|
+
/** Custom render function for an entire track row. Receives the default rendered content so you can wrap or replace it. */
|
|
161
|
+
renderTrack?: (args: TimeViewportTrackRenderArgs) => ReactNode;
|
|
140
162
|
onBlockClick?: (block: TimeViewportBlockItem) => void;
|
|
163
|
+
/** Enable virtual scrolling for large track lists. */
|
|
164
|
+
virtualize?: boolean;
|
|
165
|
+
/** Fixed pixel height of the scroll container when virtualize is true. Defaults to 400. */
|
|
166
|
+
virtualHeight?: number;
|
|
167
|
+
/** Number of off-screen rows to render above/below the visible area. Defaults to 5. */
|
|
168
|
+
overscan?: number;
|
|
141
169
|
}
|
|
142
170
|
export interface TimeViewportRootProps {
|
|
143
171
|
viewportStart: TimeInput;
|
|
@@ -220,8 +248,8 @@ export declare function TimeViewportHeader({ viewportStart, viewportEnd, tickCou
|
|
|
220
248
|
* Vertical grid lines for measuring block positions in the viewport.
|
|
221
249
|
* Render inside a relative container that also contains blocks.
|
|
222
250
|
*/
|
|
223
|
-
export declare function TimeViewportGrid({ viewportStart, viewportEnd, tickCount, minorDivisions, majorLineColor, minorLineColor, showMinorLines, zIndex, animationDurationMs, animationEasing, }: TimeViewportGridProps): import("react/jsx-runtime").JSX.Element | null;
|
|
224
|
-
export declare function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height, minWidthPx, borderRadius, defaultColorPalette, showLabel, hideWhenOutOfView, hideEmptyTracks, gap, allowOverlap, overlapOpacity, renderTrackPrefix, renderTrackSuffix, onBlockClick, }: TimeViewportBlocksProps): import("react/jsx-runtime").JSX.Element;
|
|
251
|
+
export declare function TimeViewportGrid({ viewportStart, viewportEnd, tickCount, tickStrategy, tickUnit, tickStep, format, minorDivisions, majorLineColor, minorLineColor, showMinorLines, zIndex, animationDurationMs, animationEasing, }: TimeViewportGridProps): import("react/jsx-runtime").JSX.Element | null;
|
|
252
|
+
export declare function TimeViewportBlocks({ blocks, viewportStart, viewportEnd, height, minWidthPx, borderRadius, defaultColorPalette, showLabel, hideWhenOutOfView, hideEmptyTracks, gap, allowOverlap, overlapOpacity, renderTrackPrefix, renderTrackSuffix, renderBlock, renderTrack, onBlockClick, virtualize, virtualHeight, overscan, }: TimeViewportBlocksProps): import("react/jsx-runtime").JSX.Element;
|
|
225
253
|
export declare function TimeRangeZoom({ range, onRangeChange, minDurationMs, maxDurationMs, zoomFactor, resetDurationMs, showResetButton, disabled, labels, }: TimeRangeZoomProps): import("react/jsx-runtime").JSX.Element;
|
|
226
254
|
export declare function useTimeRangeZoom({ range, onRangeChange, minDurationMs, maxDurationMs, zoomFactor, resetDurationMs, disabled, labels, }: TimeRangeZoomProps): UseTimeRangeZoomResult;
|
|
227
255
|
export {};
|
|
@@ -6,4 +6,4 @@ export { TimeRangeZoom, TimeViewportRoot, TimeViewportBlock, TimeViewportBlocks,
|
|
|
6
6
|
export { UniversalPicker } from './UniversalPicker';
|
|
7
7
|
export { DatePickerInput } from './DatePicker';
|
|
8
8
|
export type { DatePickerProps, CalendarProps, GetDateColorProps, GetVariantProps, } from './DatePicker';
|
|
9
|
-
export type { ViewableTimeRange, TimeRangeZoomLabels, TimeRangeZoomProps, TimeViewportRootProps, TimeViewportBlockProps, TimeViewportBlockItem, TimeViewportBlocksProps, TimeViewportGridProps, TimeViewportHeaderProps, TimeViewportMarkerLineProps, } from './TimeRangeZoom';
|
|
9
|
+
export type { ViewableTimeRange, TimeRangeZoomLabels, TimeRangeZoomProps, TimeViewportRootProps, TimeViewportBlockProps, TimeViewportBlockItem, TimeViewportBlocksProps, TimeViewportBlockRenderArgs, TimeViewportTrackRenderArgs, TimeViewportGridProps, TimeViewportHeaderProps, TimeViewportMarkerLineProps, } from './TimeRangeZoom';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsol-oss/react-datatable5",
|
|
3
|
-
"version": "13.0.1-beta.
|
|
3
|
+
"version": "13.0.1-beta.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@tanstack/match-sorter-utils": "^8.15.1",
|
|
46
46
|
"@tanstack/react-query": "^5.66.9",
|
|
47
47
|
"@tanstack/react-table": "^8.21.2",
|
|
48
|
+
"@tanstack/react-virtual": "^3.13.0",
|
|
48
49
|
"@uidotdev/usehooks": "^2.4.1",
|
|
49
50
|
"ajv": "^8.12.0",
|
|
50
51
|
"ajv-errors": "^3.0.0",
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
"@storybook/addon-docs": "^10.0.7",
|
|
65
66
|
"@storybook/addon-onboarding": "^10.0.7",
|
|
66
67
|
"@storybook/react-vite": "^10.0.7",
|
|
68
|
+
"@tanstack/react-virtual": "^3.13.18",
|
|
67
69
|
"@types/ajv-errors": "^2.0.0",
|
|
68
70
|
"@types/json-schema": "^7.0.15",
|
|
69
71
|
"@types/react": "19.0.2",
|