@jaeungkim/gantt-chart 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -53
- package/dist/Gantt.d.ts +5 -0
- package/dist/bars/components/GanttBar.d.ts +20 -0
- package/dist/bars/components/GanttBarsLayer.d.ts +24 -0
- package/dist/bars/components/GanttDragGuides.d.ts +1 -0
- package/dist/bars/hooks/useGanttBarDrag.d.ts +16 -0
- package/dist/bars/hooks/useGanttDrawCreate.d.ts +25 -0
- package/dist/{hooks → bars/hooks}/useGanttProgressDrag.d.ts +3 -8
- package/dist/core/calendar.d.ts +4 -22
- package/dist/core/dates.d.ts +5 -21
- package/dist/core/index.d.ts +1 -14
- package/dist/core/reorder.d.ts +55 -0
- package/dist/core/tree.d.ts +4 -12
- package/dist/core/types.d.ts +4 -37
- package/dist/{components → dependencies/components}/GanttDependencyArrows.d.ts +4 -6
- package/dist/{hooks → dependencies/hooks}/useGanttLinkDrag.d.ts +2 -13
- package/dist/dependencies/utils/arrowPath.d.ts +20 -0
- package/dist/dependencies/utils/link.d.ts +17 -0
- package/dist/detail/components/GanttDetailPanel.d.ts +21 -0
- package/dist/detail/hooks/useGanttDetail.d.ts +42 -0
- package/dist/detail/utils/edit.d.ts +21 -0
- package/dist/gantt-chart.css +1 -1
- package/dist/index.cjs +1 -4
- package/dist/index.d.cts +11 -13
- package/dist/index.d.ts +11 -13
- package/dist/index.js +4071 -5141
- package/dist/interaction/hooks/useGanttInteraction.d.ts +2 -0
- package/dist/interaction/hooks/useGanttKeyboardNav.d.ts +33 -0
- package/dist/interaction/hooks/useGanttSelection.d.ts +12 -0
- package/dist/interaction/utils/a11y.d.ts +84 -0
- package/dist/props.d.ts +121 -0
- package/dist/rows/components/GanttRowsLayer.d.ts +13 -0
- package/dist/rows/hooks/useGanttCollapse.d.ts +18 -0
- package/dist/rows/hooks/useGanttRowModel.d.ts +19 -0
- package/dist/rows/utils/rows.d.ts +21 -0
- package/dist/shared/constants.d.ts +24 -0
- package/dist/{stores → shared}/context.d.ts +1 -7
- package/dist/shared/hooks/useLatestRef.d.ts +2 -0
- package/dist/shared/hooks/useResolvedTheme.d.ts +8 -0
- package/dist/shared/store.d.ts +81 -0
- package/dist/shared/task.d.ts +55 -0
- package/dist/shared/types.d.ts +115 -0
- package/dist/shared/utils/holidays.d.ts +12 -0
- package/dist/shared/utils/i18n.d.ts +5 -0
- package/dist/shared/utils/pointerGesture.d.ts +11 -0
- package/dist/shared/virtual/axis.d.ts +13 -0
- package/dist/shared/virtual/useVirtualWindow.d.ts +16 -0
- package/dist/shared/virtual/window.d.ts +30 -0
- package/dist/task-list/components/GanttGridSplitter.d.ts +6 -0
- package/dist/task-list/components/GanttTaskAddRow.d.ts +7 -0
- package/dist/task-list/components/GanttTaskGrid.d.ts +24 -0
- package/dist/task-list/hooks/useGanttRowDrag.d.ts +17 -0
- package/dist/task-list/hooks/useGanttTaskListPane.d.ts +11 -0
- package/dist/task-list/hooks/useGanttTaskMove.d.ts +16 -0
- package/dist/timeline/components/GanttChartHeader.d.ts +10 -0
- package/dist/timeline/components/GanttHolidayLabels.d.ts +6 -0
- package/dist/timeline/components/GanttNonWorkingLayer.d.ts +6 -0
- package/dist/timeline/components/GanttTodayLine.d.ts +6 -0
- package/dist/{hooks → timeline/hooks}/useGanttScrollApi.d.ts +22 -23
- package/dist/timeline/hooks/useGanttViewport.d.ts +47 -0
- package/dist/timeline/hooks/useGanttVirtualization.d.ts +28 -0
- package/dist/timeline/utils/geometry.d.ts +52 -0
- package/dist/timeline/utils/header.d.ts +8 -0
- package/dist/timeline/utils/transform.d.ts +4 -0
- package/dist/timeline/utils/viewport.d.ts +31 -0
- package/dist/useGanttSelectors.d.ts +11 -0
- package/package.json +12 -12
- package/dist/components/GanttBar.d.ts +0 -23
- package/dist/components/GanttChartHeader.d.ts +0 -17
- package/dist/components/GanttDragGuides.d.ts +0 -9
- package/dist/components/GanttGridSplitter.d.ts +0 -14
- package/dist/components/GanttMarkers.d.ts +0 -18
- package/dist/components/GanttTaskGrid.d.ts +0 -42
- package/dist/components/ScaleSelector.d.ts +0 -11
- package/dist/constants/gantt.d.ts +0 -47
- package/dist/core/criticalPath.d.ts +0 -67
- package/dist/core/scheduling.d.ts +0 -104
- package/dist/hooks/useGanttBarDrag.d.ts +0 -35
- package/dist/hooks/useGanttDrawCreate.d.ts +0 -31
- package/dist/hooks/useGanttExportApi.d.ts +0 -30
- package/dist/hooks/useGanttHistoryApi.d.ts +0 -28
- package/dist/hooks/useGanttRowDrag.d.ts +0 -33
- package/dist/hooks/useGanttSelectors.d.ts +0 -23
- package/dist/hooks/useGanttVirtualization.d.ts +0 -32
- package/dist/hooks/useResolvedTheme.d.ts +0 -15
- package/dist/pages/Gantt.d.ts +0 -306
- package/dist/stores/store.d.ts +0 -118
- package/dist/types/gantt.d.ts +0 -283
- package/dist/types/task.d.ts +0 -111
- package/dist/utils/a11y.d.ts +0 -141
- package/dist/utils/arrowPath.d.ts +0 -66
- package/dist/utils/dependency.d.ts +0 -42
- package/dist/utils/grouping.d.ts +0 -81
- package/dist/utils/headerUtils.d.ts +0 -6
- package/dist/utils/history.d.ts +0 -56
- package/dist/utils/i18n.d.ts +0 -16
- package/dist/utils/mutation.d.ts +0 -47
- package/dist/utils/pngExport.d.ts +0 -67
- package/dist/utils/pointerGesture.d.ts +0 -31
- package/dist/utils/rowDrag.d.ts +0 -69
- package/dist/utils/timeline.d.ts +0 -161
- package/dist/utils/transformData.d.ts +0 -15
- package/dist/utils/viewport.d.ts +0 -95
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { GanttFormatters, GanttLabelUnit, GanttLocaleOptions, GanttScaleKey } from '../types';
|
|
2
|
+
export declare function resolveLabelUnit(scale: GanttScaleKey, options?: GanttLocaleOptions): GanttLabelUnit;
|
|
3
|
+
export declare function resolveFormatters(scale: GanttScaleKey, options?: GanttLocaleOptions): GanttFormatters;
|
|
4
|
+
/** Span label shared by the hover tooltip and the detail panel - hours under a day, whole days from there */
|
|
5
|
+
export declare function formatDuration(durationMs: number): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const TOUCH_LONG_PRESS_MS = 400;
|
|
2
|
+
export declare const TOUCH_SLOP_PX = 10;
|
|
3
|
+
interface PointerGestureStart {
|
|
4
|
+
pointerType: string;
|
|
5
|
+
pointerId: number;
|
|
6
|
+
clientX: number;
|
|
7
|
+
clientY: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function armPointerGesture(start: PointerGestureStart, onStart: (clientX: number, clientY: number) => void, target?: EventTarget): (() => void) | null;
|
|
10
|
+
export declare function suppressTouchScroll(): () => void;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface VirtualAxis {
|
|
2
|
+
count: number;
|
|
3
|
+
/** Size of the whole axis (px) */
|
|
4
|
+
total: number;
|
|
5
|
+
sizeAt: (index: number) => number;
|
|
6
|
+
/** Pixels before `index` starts */
|
|
7
|
+
offsetAt: (index: number) => number;
|
|
8
|
+
/** Index of the item covering `px`, clamped to the axis */
|
|
9
|
+
indexAt: (px: number) => number;
|
|
10
|
+
}
|
|
11
|
+
export declare function fixedAxis(count: number, size: number): VirtualAxis;
|
|
12
|
+
export declare function variableAxis(count: number, sizeAt: (index: number) => number): VirtualAxis;
|
|
13
|
+
export declare function axisOf(count: number, size: number | ArrayLike<number>, fallback?: number): VirtualAxis;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { VirtualAxis } from './axis';
|
|
3
|
+
import { VirtualWindow } from './window';
|
|
4
|
+
export type ScrollAlign = 'start' | 'center' | 'end' | 'auto';
|
|
5
|
+
interface UseVirtualWindowParams {
|
|
6
|
+
scrollRef: RefObject<HTMLElement | null>;
|
|
7
|
+
row: VirtualAxis;
|
|
8
|
+
col: VirtualAxis;
|
|
9
|
+
}
|
|
10
|
+
interface VirtualWindows {
|
|
11
|
+
row: VirtualWindow;
|
|
12
|
+
col: VirtualWindow;
|
|
13
|
+
scrollToRow: (index: number, align?: ScrollAlign) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function useVirtualWindow({ scrollRef, row, col, }: UseVirtualWindowParams): VirtualWindows;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { VirtualAxis } from './axis';
|
|
2
|
+
export declare const MIN_VIRTUAL_COUNT = 24;
|
|
3
|
+
export interface VirtualWindow {
|
|
4
|
+
/** First index to render */
|
|
5
|
+
start: number;
|
|
6
|
+
/** Last index to render, inclusive - `-1` when the axis is empty */
|
|
7
|
+
end: number;
|
|
8
|
+
/** Pixels before `start` */
|
|
9
|
+
padStart: number;
|
|
10
|
+
/** Pixels after `end` */
|
|
11
|
+
padEnd: number;
|
|
12
|
+
/** False when the whole axis is being rendered */
|
|
13
|
+
virtualized: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface VirtualItem {
|
|
16
|
+
index: number;
|
|
17
|
+
key: number;
|
|
18
|
+
start: number;
|
|
19
|
+
end: number;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
export type ScrollDirection = -1 | 0 | 1;
|
|
23
|
+
export declare function fullWindow(count: number): VirtualWindow;
|
|
24
|
+
export declare function windowOf(axis: VirtualAxis, scroll: number, viewport: number, overscan?: number, direction?: ScrollDirection): VirtualWindow;
|
|
25
|
+
export declare function virtualItemsOf(axis: VirtualAxis, window: VirtualWindow): VirtualItem[];
|
|
26
|
+
export declare function windowBounds(axis: VirtualAxis, window: VirtualWindow): {
|
|
27
|
+
startPx: number;
|
|
28
|
+
endPx: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function sameWindow(a: VirtualWindow, b: VirtualWindow): boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface GanttTaskAddRowProps {
|
|
2
|
+
width: number;
|
|
3
|
+
/** Proposes the new task - the same thing `addTask()` on the chart ref calls */
|
|
4
|
+
onAdd: () => void;
|
|
5
|
+
}
|
|
6
|
+
export default function GanttTaskAddRow({ width, onAdd, }: GanttTaskAddRowProps): import("react").JSX.Element;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { VirtualItem } from '../../shared/virtual/window';
|
|
2
|
+
import { GanttTaskMoveApi } from '../hooks/useGanttTaskMove';
|
|
3
|
+
import { GanttInteractionConfig, TaskTransformed } from '../../shared/task';
|
|
4
|
+
import { GanttFocus } from '../../interaction/utils/a11y';
|
|
5
|
+
import { GanttRow } from '../../rows/utils/rows';
|
|
6
|
+
interface GanttTaskGridProps {
|
|
7
|
+
rows: GanttRow[];
|
|
8
|
+
virtualItems: VirtualItem[];
|
|
9
|
+
totalHeight: number;
|
|
10
|
+
width: number;
|
|
11
|
+
showRowNumbers: boolean;
|
|
12
|
+
hierarchy: boolean;
|
|
13
|
+
collapsedIds: ReadonlySet<string>;
|
|
14
|
+
onToggleCollapse: (rowId: string) => void;
|
|
15
|
+
focus: GanttFocus;
|
|
16
|
+
reorderEnabled: boolean;
|
|
17
|
+
interaction: GanttInteractionConfig;
|
|
18
|
+
move: GanttTaskMoveApi;
|
|
19
|
+
selectedTaskId?: string | null;
|
|
20
|
+
onRowClick?: (task: TaskTransformed, event: React.MouseEvent) => void;
|
|
21
|
+
onRowDoubleClick?: (task: TaskTransformed, event: React.MouseEvent) => void;
|
|
22
|
+
}
|
|
23
|
+
export default function GanttTaskGrid({ rows, virtualItems, totalHeight, width, showRowNumbers, hierarchy, collapsedIds, onToggleCollapse, focus, reorderEnabled, interaction, move, selectedTaskId, onRowClick, onRowDoubleClick, }: GanttTaskGridProps): import("react").JSX.Element;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { VirtualItem } from '../../shared/virtual/window';
|
|
2
|
+
import { RefObject } from 'react';
|
|
3
|
+
import { GanttTaskMoveApi } from './useGanttTaskMove';
|
|
4
|
+
import { GanttReorderDraft } from '../../shared/store';
|
|
5
|
+
import { GanttRow } from '../../rows/utils/rows';
|
|
6
|
+
interface UseGanttRowDragParams {
|
|
7
|
+
rows: GanttRow[];
|
|
8
|
+
virtualItems: VirtualItem[];
|
|
9
|
+
bodyRef: RefObject<HTMLDivElement | null>;
|
|
10
|
+
hierarchy: boolean;
|
|
11
|
+
move: GanttTaskMoveApi;
|
|
12
|
+
}
|
|
13
|
+
export declare function useGanttRowDrag({ rows, virtualItems, bodyRef, hierarchy, move, }: UseGanttRowDragParams): {
|
|
14
|
+
onGripPointerDown: (rowIndex: number, event: React.PointerEvent) => void;
|
|
15
|
+
draft: GanttReorderDraft | null;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface UseGanttTaskListPaneParams {
|
|
2
|
+
showTaskList?: boolean;
|
|
3
|
+
}
|
|
4
|
+
interface GanttTaskListPane {
|
|
5
|
+
width: number;
|
|
6
|
+
setWidth: (width: number) => void;
|
|
7
|
+
visible: boolean;
|
|
8
|
+
inset: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function useGanttTaskListPane({ showTaskList, }: UseGanttTaskListPaneParams): GanttTaskListPane;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GanttMoveRejection, GanttTaskMove, GanttTaskMoveChange } from '../../core/reorder';
|
|
2
|
+
import { GanttInteractionConfig, Task } from '../../shared/task';
|
|
3
|
+
interface UseGanttTaskMoveParams {
|
|
4
|
+
hierarchy: boolean;
|
|
5
|
+
interaction: GanttInteractionConfig;
|
|
6
|
+
collapsedIds: ReadonlySet<string>;
|
|
7
|
+
onTasksChange?: (tasks: Task[]) => void;
|
|
8
|
+
onTaskMove?: (change: GanttTaskMoveChange) => boolean | void;
|
|
9
|
+
onExpand?: (rowId: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface GanttTaskMoveApi {
|
|
12
|
+
validate: (move: GanttTaskMove) => GanttMoveRejection | null;
|
|
13
|
+
apply: (move: GanttTaskMove) => boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function useGanttTaskMove({ hierarchy, interaction, collapsedIds, onTasksChange, onTaskMove, onExpand, }: UseGanttTaskMoveParams): GanttTaskMoveApi;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GanttBottomRowCell, GanttScaleKey } from '../../shared/types';
|
|
2
|
+
import { GanttVirtualization } from '../hooks/useGanttVirtualization';
|
|
3
|
+
interface GanttChartHeaderProps {
|
|
4
|
+
bottomRowCells: GanttBottomRowCell[];
|
|
5
|
+
selectedScale: GanttScaleKey;
|
|
6
|
+
width: number;
|
|
7
|
+
virtual: GanttVirtualization;
|
|
8
|
+
}
|
|
9
|
+
declare function GanttChartHeader({ bottomRowCells, selectedScale, width, virtual, }: GanttChartHeaderProps): import("react").JSX.Element;
|
|
10
|
+
export default GanttChartHeader;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Dayjs } from 'dayjs';
|
|
2
2
|
import { RefObject } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { GanttBottomRowCell, GanttScaleKey } from '../types/gantt';
|
|
6
|
-
import { TaskTransformed } from '../types/task';
|
|
3
|
+
import { GanttBottomRowCell, GanttScaleKey } from '../../shared/types';
|
|
4
|
+
import { TaskTransformed } from '../../shared/task';
|
|
7
5
|
/** Options for the scrollTo* methods */
|
|
8
6
|
export interface GanttScrollOptions {
|
|
9
7
|
/** Whether to animate the scroll (default true) */
|
|
@@ -25,17 +23,27 @@ export interface GanttScrollApi {
|
|
|
25
23
|
scrollToToday: (options?: GanttScrollOptions) => void;
|
|
26
24
|
/** Scroll horizontally and vertically to a given task */
|
|
27
25
|
scrollToTask: (taskId: string, options?: GanttScrollOptions) => void;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* Also scrolls the project into view. Does nothing while there are no tasks.
|
|
32
|
-
*/
|
|
26
|
+
/** Switches the scale, keeping the centre date centred; an unknown key is ignored */
|
|
27
|
+
setScale: (scale: GanttScaleKey) => void;
|
|
28
|
+
/** Switches to the finest scale the whole project fits at and scrolls it into view (no-op with no tasks) */
|
|
33
29
|
zoomToFit: () => void;
|
|
34
30
|
/** The scroll container DOM node (null when unavailable) */
|
|
35
31
|
getScrollElement: () => HTMLDivElement | null;
|
|
36
32
|
}
|
|
33
|
+
/** Opening and closing the detail panel from outside the chart */
|
|
34
|
+
export interface GanttDetailApi {
|
|
35
|
+
/** Opens the detail panel on a task; unknown ids and a panel-less chart (no `renderDetail`/`showDetail`) are ignored */
|
|
36
|
+
openDetail: (taskId: string) => void;
|
|
37
|
+
/** Closes the detail panel */
|
|
38
|
+
closeDetail: () => void;
|
|
39
|
+
}
|
|
40
|
+
/** Proposing a new task from outside the chart */
|
|
41
|
+
export interface GanttTaskCreateApi {
|
|
42
|
+
/** Sends a one-tick draft at today to `onTaskCreate`, as the "Add task" button does; no-op without `onTaskCreate` or with `allowTaskCreate` false */
|
|
43
|
+
addTask: () => void;
|
|
44
|
+
}
|
|
37
45
|
/** Imperative API exposed through the ref */
|
|
38
|
-
export interface GanttHandle extends GanttScrollApi,
|
|
46
|
+
export interface GanttHandle extends GanttScrollApi, GanttDetailApi, GanttTaskCreateApi {
|
|
39
47
|
}
|
|
40
48
|
interface UseGanttScrollApiParams {
|
|
41
49
|
scrollRef: RefObject<HTMLDivElement | null>;
|
|
@@ -43,21 +51,12 @@ interface UseGanttScrollApiParams {
|
|
|
43
51
|
transformedTasks: TaskTransformed[];
|
|
44
52
|
selectedScale: GanttScaleKey;
|
|
45
53
|
rowHeight: number;
|
|
46
|
-
/**
|
|
47
|
-
* How much width the pinned task list on the left covers (default 0)
|
|
48
|
-
*
|
|
49
|
-
* The timeline starts that far to the right, so centering has to measure against the
|
|
50
|
-
* narrowed viewport or the target lands behind the pane.
|
|
51
|
-
*/
|
|
54
|
+
/** Width of the pinned task list (default 0) - centering measures against the narrowed viewport */
|
|
52
55
|
viewportInsetPx?: number;
|
|
53
56
|
/** Switches scale while keeping the anchor date where it is on screen */
|
|
54
57
|
zoomTo: (scale: GanttScaleKey, anchor: GanttZoomAnchor) => void;
|
|
58
|
+
/** Sets the scale with no anchor - the fallback when there is nothing on screen to pin */
|
|
59
|
+
setSelectedScale: (scale: GanttScaleKey) => void;
|
|
55
60
|
}
|
|
56
|
-
|
|
57
|
-
* Imperative scroll API
|
|
58
|
-
*
|
|
59
|
-
* Dates outside the timeline and unknown task ids are ignored silently - so that
|
|
60
|
-
* the common case of calling while data is still loading does not throw.
|
|
61
|
-
*/
|
|
62
|
-
export declare function useGanttScrollApi({ scrollRef, bottomRowCells, transformedTasks, selectedScale, rowHeight, viewportInsetPx, zoomTo, }: UseGanttScrollApiParams): GanttScrollApi;
|
|
61
|
+
export declare function useGanttScrollApi({ scrollRef, bottomRowCells, transformedTasks, selectedScale, rowHeight, viewportInsetPx, zoomTo, setSelectedScale, }: UseGanttScrollApiParams): GanttScrollApi;
|
|
63
62
|
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { GanttScrollApi, GanttZoomAnchor } from './useGanttScrollApi';
|
|
3
|
+
import { GanttBottomRowCell, GanttDateRange, GanttRangeExtension, GanttScaleKey, GanttVisibleRange } from '../../shared/types';
|
|
4
|
+
import { Task } from '../../shared/task';
|
|
5
|
+
interface UseGanttRangeExtensionParams {
|
|
6
|
+
/** Off (the default `infiniteScroll`), the timeline never grows past its tasks */
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
9
|
+
selectedScale: GanttScaleKey;
|
|
10
|
+
bottomRowCells: GanttBottomRowCell[];
|
|
11
|
+
totalWidth: number;
|
|
12
|
+
/** Width of the pinned task list, which the viewport does not extend into */
|
|
13
|
+
viewportInsetPx: number;
|
|
14
|
+
/** A pinned end is where the host put it - growing past it would be undone on every recompute */
|
|
15
|
+
pinnedStart: boolean;
|
|
16
|
+
pinnedEnd: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function useGanttRangeExtension({ enabled, scrollRef, selectedScale, bottomRowCells, totalWidth, viewportInsetPx, pinnedStart, pinnedEnd, }: UseGanttRangeExtensionParams): GanttRangeExtension;
|
|
19
|
+
interface UseGanttTimelineSyncParams {
|
|
20
|
+
rawTasks: Task[];
|
|
21
|
+
selectedScale: GanttScaleKey;
|
|
22
|
+
/** Pinned window, or undefined to fit the timeline to the tasks */
|
|
23
|
+
visibleRange: GanttVisibleRange | undefined;
|
|
24
|
+
hierarchy: boolean;
|
|
25
|
+
extension: GanttRangeExtension;
|
|
26
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
27
|
+
bottomRowCells: GanttBottomRowCell[];
|
|
28
|
+
}
|
|
29
|
+
export declare function useGanttTimelineSync({ rawTasks, selectedScale, visibleRange, hierarchy, extension, scrollRef, bottomRowCells, }: UseGanttTimelineSyncParams): (scale: GanttScaleKey, anchor: GanttZoomAnchor) => void;
|
|
30
|
+
interface UseGanttWheelZoomParams {
|
|
31
|
+
/** Off (the default `zoomOnWheel`), ctrl/cmd + wheel is left to the browser */
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
34
|
+
selectedScale: GanttScaleKey;
|
|
35
|
+
bottomRowCells: GanttBottomRowCell[];
|
|
36
|
+
/** Width of the pinned task list, which the timeline's own left edge starts after */
|
|
37
|
+
viewportInsetPx: number;
|
|
38
|
+
zoomTo: (scale: GanttScaleKey, anchor: GanttZoomAnchor) => void;
|
|
39
|
+
}
|
|
40
|
+
/** Ctrl/Cmd + wheel steps through the scale ladder, keeping the date under the cursor */
|
|
41
|
+
export declare function useGanttWheelZoom({ enabled, scrollRef, selectedScale, bottomRowCells, viewportInsetPx, zoomTo, }: UseGanttWheelZoomParams): void;
|
|
42
|
+
export declare function useGanttScaleReport(selectedScale: GanttScaleKey, onScaleChange?: (scale: GanttScaleKey) => void): void;
|
|
43
|
+
/** Reports the rendered timeline range - the hook a host lazy-loads tasks from */
|
|
44
|
+
export declare function useGanttRangeReport(bottomRowCells: GanttBottomRowCell[], selectedScale: GanttScaleKey, onRangeChange?: (range: GanttDateRange) => void): void;
|
|
45
|
+
/** Scrolls to `initialScrollTo` once, when the timeline first becomes ready */
|
|
46
|
+
export declare function useGanttInitialScroll(initialScrollTo: "today" | string | undefined, bottomRowCells: GanttBottomRowCell[], scrollApi: GanttScrollApi): void;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { GanttBottomRowCell } from '../../shared/types';
|
|
3
|
+
import { ScrollAlign } from '../../shared/virtual/useVirtualWindow';
|
|
4
|
+
import { VirtualItem } from '../../shared/virtual/window';
|
|
5
|
+
interface UseGanttVirtualizationParams {
|
|
6
|
+
/** Number of rows on screen - not the task count, since a lane can share one row */
|
|
7
|
+
rowCount: number;
|
|
8
|
+
bottomRowCells: GanttBottomRowCell[];
|
|
9
|
+
scrollRef: RefObject<HTMLDivElement | null>;
|
|
10
|
+
}
|
|
11
|
+
export interface GanttVirtualization {
|
|
12
|
+
/** Rows to render, already positioned */
|
|
13
|
+
virtualRows: VirtualItem[];
|
|
14
|
+
/** Height of all rows, culled ones included - the scrollable content height */
|
|
15
|
+
totalHeight: number;
|
|
16
|
+
/** Time cells to render, already positioned */
|
|
17
|
+
virtualCells: VirtualItem[];
|
|
18
|
+
/** Width of the cells skipped before the first rendered one (px) */
|
|
19
|
+
leadingCellPx: number;
|
|
20
|
+
/** Vertical bounds of the row window (px) - what the arrows cull against */
|
|
21
|
+
rowStartPx: number;
|
|
22
|
+
rowEndPx: number;
|
|
23
|
+
/** Horizontal culling, shared by the header, the bars and the arrows */
|
|
24
|
+
isBarVisible: (barLeft: number, barWidth: number) => boolean;
|
|
25
|
+
scrollToRow: (index: number, align?: ScrollAlign) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare function useGanttVirtualization({ rowCount, bottomRowCells, scrollRef, }: UseGanttVirtualizationParams): GanttVirtualization;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Dayjs } from 'dayjs';
|
|
2
|
+
import { GanttBottomRowCell, GanttDateRange, GanttDragBounds, GanttDragMode, GanttLocaleOptions, GanttRangeExtension, GanttScaleKey, GanttTopHeaderGroup, GanttVisibleRange } from '../../shared/types';
|
|
3
|
+
import { Task, TaskTransformed } from '../../shared/task';
|
|
4
|
+
interface TimelineData {
|
|
5
|
+
bottomCells: GanttBottomRowCell[];
|
|
6
|
+
transformedTasks: TaskTransformed[];
|
|
7
|
+
}
|
|
8
|
+
/** The identity of a day that is off with nothing else said about it - no name, no colour. */
|
|
9
|
+
export declare const OFF_DAY_KEY = "off";
|
|
10
|
+
/** What one non-working day is, as far as the shading is concerned. */
|
|
11
|
+
export interface NonWorkingDay {
|
|
12
|
+
/** Adjacent days merge only when this matches - a named holiday must not fuse with a Saturday */
|
|
13
|
+
key: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
color?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface NonWorkingRange {
|
|
18
|
+
left: number;
|
|
19
|
+
width: number;
|
|
20
|
+
label?: string;
|
|
21
|
+
color?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function originShiftPx(prevTicks: GanttBottomRowCell[], nextTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): number;
|
|
24
|
+
export declare function computeNonWorkingRanges(timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey, nonWorkingDayAt: (date: Dayjs) => NonWorkingDay | null): NonWorkingRange[];
|
|
25
|
+
export declare function shiftByDragSteps(date: Dayjs, steps: number, scaleKey: GanttScaleKey): Dayjs;
|
|
26
|
+
export declare function pxBetweenDates(from: Dayjs, to: Dayjs, scaleKey: GanttScaleKey): number;
|
|
27
|
+
export declare function clampDragDates(mode: GanttDragMode, startDate: Dayjs, endDate: Dayjs, bounds: GanttDragBounds, scaleKey: GanttScaleKey): {
|
|
28
|
+
startDate: Dayjs;
|
|
29
|
+
endDate: Dayjs;
|
|
30
|
+
};
|
|
31
|
+
export declare function clampMoveDelta(members: {
|
|
32
|
+
start: Dayjs;
|
|
33
|
+
end: Dayjs;
|
|
34
|
+
bounds: GanttDragBounds;
|
|
35
|
+
}[], requestedMs: number, scaleKey: GanttScaleKey): number;
|
|
36
|
+
export declare function calculateDateOffsets(startDate: Dayjs, endDate: Dayjs, timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): {
|
|
37
|
+
barMarginLeftAmount: number;
|
|
38
|
+
barWidthSize: number;
|
|
39
|
+
};
|
|
40
|
+
export declare function calculateDateOffsetPx(date: Dayjs, timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): number | null;
|
|
41
|
+
export declare function dateAtOffsetPx(offsetPx: number, timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): Dayjs | null;
|
|
42
|
+
export declare function timelineRange(timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): GanttDateRange | null;
|
|
43
|
+
interface DrawnRange {
|
|
44
|
+
startDate: Dayjs;
|
|
45
|
+
endDate: Dayjs;
|
|
46
|
+
leftPx: number;
|
|
47
|
+
widthPx: number;
|
|
48
|
+
}
|
|
49
|
+
export declare function snapDrawnRange(startPx: number, endPx: number, timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): DrawnRange | null;
|
|
50
|
+
export declare function createTopHeaderGroups(bottomCells: GanttBottomRowCell[], selectedScale: GanttScaleKey, localeOptions?: GanttLocaleOptions): GanttTopHeaderGroup[];
|
|
51
|
+
export declare function computeTimelineData(rawTasks: Task[], selectedScale: GanttScaleKey, visibleRange?: GanttVisibleRange, hierarchy?: boolean, extension?: GanttRangeExtension): TimelineData;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { GanttBottomRowCell, GanttTopHeaderGroup } from '../../shared/types';
|
|
2
|
+
export declare function mergeHeaderGroups(groups: GanttTopHeaderGroup[]): GanttTopHeaderGroup[];
|
|
3
|
+
export declare function tickBoundaries(cells: GanttBottomRowCell[]): number[];
|
|
4
|
+
export declare function tickCellAt(boundaries: number[], x: number): {
|
|
5
|
+
index: number;
|
|
6
|
+
left: number;
|
|
7
|
+
width: number;
|
|
8
|
+
} | null;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { GanttBottomRowCell, GanttScaleKey } from '../../shared/types';
|
|
2
|
+
import { Task, TaskTransformed } from '../../shared/task';
|
|
3
|
+
import { TaskTree } from '../../core/tree';
|
|
4
|
+
export declare function transformTasks(tasks: Task[], timelineTicks: GanttBottomRowCell[], selectedScale: GanttScaleKey, tree?: TaskTree): TaskTransformed[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { GanttRangeExtension, GanttScaleKey } from '../../shared/types';
|
|
2
|
+
export declare const SCALE_LADDER: GanttScaleKey[];
|
|
3
|
+
export declare function pxPerMs(scale: GanttScaleKey): number;
|
|
4
|
+
export declare function stepScale(scale: GanttScaleKey, direction: number): GanttScaleKey;
|
|
5
|
+
export declare function fitScale(durationMs: number, viewportPx: number): GanttScaleKey;
|
|
6
|
+
interface ZoomAccumulator {
|
|
7
|
+
delta: number;
|
|
8
|
+
lastEventAt: number;
|
|
9
|
+
locked: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const INITIAL_ZOOM_ACCUMULATOR: ZoomAccumulator;
|
|
12
|
+
export declare function accumulateZoom(state: ZoomAccumulator, deltaY: number, now: number): {
|
|
13
|
+
state: ZoomAccumulator;
|
|
14
|
+
step: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function edgeScrollVelocity(clientX: number, left: number, right: number): number;
|
|
17
|
+
export declare const NO_RANGE_EXTENSION: GanttRangeExtension;
|
|
18
|
+
export declare const MAX_RANGE_EXTENSION_TICKS = 2000;
|
|
19
|
+
interface ExtendRangeParams {
|
|
20
|
+
current: GanttRangeExtension;
|
|
21
|
+
scrollLeft: number;
|
|
22
|
+
viewportPx: number;
|
|
23
|
+
totalPx: number;
|
|
24
|
+
pxPerTick: number;
|
|
25
|
+
canExtend?: {
|
|
26
|
+
before: boolean;
|
|
27
|
+
after: boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function extendRangeForScroll({ current, scrollLeft, viewportPx, totalPx, pxPerTick, canExtend, }: ExtendRangeParams): GanttRangeExtension | null;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function useGanttSelectors(): {
|
|
2
|
+
rawTasks: import('.').Task[];
|
|
3
|
+
transformedTasks: import('.').TaskTransformed[];
|
|
4
|
+
bottomRowCells: import('./shared/types').GanttBottomRowCell[];
|
|
5
|
+
selectedScale: import('.').GanttScaleKey;
|
|
6
|
+
selectedTaskId: string | null;
|
|
7
|
+
syncTasksFromProps: (rawTasks: import('.').Task[]) => void;
|
|
8
|
+
setSelectedScale: (scale: import('.').GanttScaleKey) => void;
|
|
9
|
+
setLocaleOptions: (options: import('./shared/types').GanttLocaleOptions | undefined) => void;
|
|
10
|
+
getTotalWidth: () => number;
|
|
11
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaeungkim/gantt-chart",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -25,12 +25,15 @@
|
|
|
25
25
|
"README.md",
|
|
26
26
|
"LICENSE"
|
|
27
27
|
],
|
|
28
|
-
"description": "
|
|
28
|
+
"description": "React Gantt chart with editable bars, dependency arrows, and headless date utilities",
|
|
29
29
|
"keywords": [
|
|
30
30
|
"gantt",
|
|
31
|
+
"gantt-chart",
|
|
31
32
|
"chart",
|
|
33
|
+
"project-management",
|
|
32
34
|
"react",
|
|
33
|
-
"timeline"
|
|
35
|
+
"timeline",
|
|
36
|
+
"virtualized"
|
|
34
37
|
],
|
|
35
38
|
"author": "jaeungkim",
|
|
36
39
|
"license": "MIT",
|
|
@@ -38,25 +41,24 @@
|
|
|
38
41
|
"type": "git",
|
|
39
42
|
"url": "git+https://github.com/jaeungkim/gantt-chart.git"
|
|
40
43
|
},
|
|
41
|
-
"homepage": "https://jaeungkim.com
|
|
44
|
+
"homepage": "https://gantt.jaeungkim.com",
|
|
42
45
|
"bugs": {
|
|
43
46
|
"url": "https://github.com/jaeungkim/gantt-chart/issues"
|
|
44
47
|
},
|
|
45
48
|
"scripts": {
|
|
46
|
-
"dev": "
|
|
49
|
+
"dev": "pnpm --filter @gantt-chart/site dev",
|
|
47
50
|
"build": "vite build && node -e \"require('fs').copyFileSync('dist/index.d.ts','dist/index.d.cts')\"",
|
|
48
|
-
"
|
|
49
|
-
"lint": "eslint
|
|
50
|
-
"lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"",
|
|
51
|
+
"lint": "eslint .",
|
|
52
|
+
"lint:fix": "eslint . --fix",
|
|
51
53
|
"type-check": "tsc --noEmit",
|
|
52
|
-
"test": "vitest run"
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"docs:build": "pnpm build && pnpm --filter @gantt-chart/site build"
|
|
53
56
|
},
|
|
54
57
|
"peerDependencies": {
|
|
55
58
|
"react": "^18.0.0 || ^19.0.0",
|
|
56
59
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
57
60
|
},
|
|
58
61
|
"dependencies": {
|
|
59
|
-
"@tanstack/react-virtual": "^3.14.10",
|
|
60
62
|
"dayjs": "^1.11.23",
|
|
61
63
|
"zustand": "^5.0.15"
|
|
62
64
|
},
|
|
@@ -64,9 +66,7 @@
|
|
|
64
66
|
"@eslint/js": "^9.39.5",
|
|
65
67
|
"@types/node": "^22.20.1",
|
|
66
68
|
"@types/react": "^19.2.18",
|
|
67
|
-
"@types/react-dom": "^19.2.5",
|
|
68
69
|
"@vitejs/plugin-react": "^4.7.0",
|
|
69
|
-
"agentation": "^3.0.2",
|
|
70
70
|
"eslint": "^9.39.5",
|
|
71
71
|
"eslint-plugin-react": "^7.37.5",
|
|
72
72
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { GanttDependencyChange } from '../hooks/useGanttLinkDrag';
|
|
2
|
-
import { GanttBarOptions, GanttScheduling } from '../types/gantt';
|
|
3
|
-
import { GanttInteractionConfig, TaskTransformed } from '../types/task';
|
|
4
|
-
interface GanttBarProps {
|
|
5
|
-
currentTask: TaskTransformed;
|
|
6
|
-
options?: GanttBarOptions;
|
|
7
|
-
interaction?: GanttInteractionConfig;
|
|
8
|
-
/**
|
|
9
|
-
* Roving tabindex of the treegrid (default -1)
|
|
10
|
-
*
|
|
11
|
-
* Exactly one cell in the chart carries 0, so Tab enters and leaves the whole
|
|
12
|
-
* grid once and the arrow keys move within it.
|
|
13
|
-
*/
|
|
14
|
-
tabIndex?: number;
|
|
15
|
-
/** `row:column` coordinate the chart's focus manager looks the cell up by */
|
|
16
|
-
cellCoord?: string;
|
|
17
|
-
scheduling?: GanttScheduling;
|
|
18
|
-
/** Scroll the timeline when the drag reaches a viewport edge (default true) */
|
|
19
|
-
autoScrollOnDrag?: boolean;
|
|
20
|
-
onDependencyCreate?: (change: GanttDependencyChange) => boolean | void;
|
|
21
|
-
}
|
|
22
|
-
export default function GanttBar({ currentTask, options, interaction, tabIndex, cellCoord, scheduling, autoScrollOnDrag, onDependencyCreate, }: GanttBarProps): import("react").JSX.Element;
|
|
23
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
|
-
import { GanttBottomRowCell, GanttHeaderCellRenderer, GanttScaleKey } from '../types/gantt';
|
|
3
|
-
interface GanttChartHeaderProps {
|
|
4
|
-
bottomRowCells: GanttBottomRowCell[];
|
|
5
|
-
selectedScale: GanttScaleKey;
|
|
6
|
-
width: number;
|
|
7
|
-
/** Scroll container used to virtualize the bottom time cells (pinning the top group labels is done with CSS sticky) */
|
|
8
|
-
scrollRef: React.RefObject<HTMLDivElement | null>;
|
|
9
|
-
/** Replaces a header cell wholesale - both rows go through it */
|
|
10
|
-
renderHeaderCell?: GanttHeaderCellRenderer;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Gantt chart header component
|
|
14
|
-
* Renders the top group labels and the bottom time cells
|
|
15
|
-
*/
|
|
16
|
-
declare function GanttChartHeader({ bottomRowCells, selectedScale, width, scrollRef, renderHeaderCell, }: GanttChartHeaderProps): React.JSX.Element;
|
|
17
|
-
export default GanttChartHeader;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
interface GanttDragGuidesProps {
|
|
2
|
-
width: number;
|
|
3
|
-
}
|
|
4
|
-
/**
|
|
5
|
-
* Shows the start/end points during a drag as vertical guides running up through the header
|
|
6
|
-
* Each guide carries the current date label at its top, so the moment can be read straight off the header
|
|
7
|
-
*/
|
|
8
|
-
export default function GanttDragGuides({ width }: GanttDragGuidesProps): import("react").JSX.Element | null;
|
|
9
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
interface GanttGridSplitterProps {
|
|
2
|
-
width: number;
|
|
3
|
-
onWidthChange: (width: number) => void;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Drag handle between the task list and the timeline
|
|
7
|
-
*
|
|
8
|
-
* Rendered outside the scroll container rather than inside the grid pane: the
|
|
9
|
-
* pane sits inside the treegrid, whose only children may be rows, and a
|
|
10
|
-
* separator there would also be a second tab stop in a widget that is meant to
|
|
11
|
-
* have exactly one.
|
|
12
|
-
*/
|
|
13
|
-
export default function GanttGridSplitter({ width, onWidthChange, }: GanttGridSplitterProps): import("react").JSX.Element;
|
|
14
|
-
export {};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { PositionedBand, PositionedMarker } from '../utils/timeline';
|
|
2
|
-
/**
|
|
3
|
-
* Shaded date-range bands (sprints, phases)
|
|
4
|
-
*
|
|
5
|
-
* Drawn on the background layer, below the rows, arrows and bars.
|
|
6
|
-
*/
|
|
7
|
-
export declare function GanttRangeBands({ bands }: {
|
|
8
|
-
bands: PositionedBand[];
|
|
9
|
-
}): import("react").JSX.Element | null;
|
|
10
|
-
/**
|
|
11
|
-
* Vertical date markers (deadlines, releases, and the chart's own today line)
|
|
12
|
-
*
|
|
13
|
-
* `data-warning` is set when a task the marker watches ends past its date, so the warning
|
|
14
|
-
* look is a plain CSS attribute selector the host can restyle.
|
|
15
|
-
*/
|
|
16
|
-
export declare function GanttMarkers({ markers }: {
|
|
17
|
-
markers: PositionedMarker[];
|
|
18
|
-
}): import("react").JSX.Element | null;
|