@jaeungkim/gantt-chart 0.3.0 β†’ 0.4.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -101
  3. package/dist/components/GanttBar.d.ts +23 -0
  4. package/dist/components/GanttChartHeader.d.ts +17 -0
  5. package/dist/components/GanttDependencyArrows.d.ts +15 -0
  6. package/dist/components/GanttDragGuides.d.ts +9 -0
  7. package/dist/components/GanttGridSplitter.d.ts +14 -0
  8. package/dist/components/GanttMarkers.d.ts +18 -0
  9. package/dist/components/GanttTaskGrid.d.ts +42 -0
  10. package/dist/components/ScaleSelector.d.ts +11 -0
  11. package/dist/constants/gantt.d.ts +47 -0
  12. package/dist/core/calendar.d.ts +45 -0
  13. package/dist/core/criticalPath.d.ts +67 -0
  14. package/dist/core/dates.d.ts +32 -0
  15. package/dist/core/index.d.ts +16 -0
  16. package/dist/core/scheduling.d.ts +104 -0
  17. package/dist/core/tree.d.ts +42 -0
  18. package/dist/core/types.d.ts +76 -0
  19. package/dist/gantt-chart.css +1 -1
  20. package/dist/hooks/useGanttBarDrag.d.ts +35 -0
  21. package/dist/hooks/useGanttDrawCreate.d.ts +31 -0
  22. package/dist/hooks/useGanttExportApi.d.ts +30 -0
  23. package/dist/hooks/useGanttHistoryApi.d.ts +28 -0
  24. package/dist/hooks/useGanttLinkDrag.d.ts +31 -0
  25. package/dist/hooks/useGanttProgressDrag.d.ts +16 -0
  26. package/dist/hooks/useGanttRowDrag.d.ts +33 -0
  27. package/dist/hooks/useGanttScrollApi.d.ts +63 -0
  28. package/dist/hooks/useGanttSelectors.d.ts +23 -0
  29. package/dist/hooks/useGanttVirtualization.d.ts +32 -0
  30. package/dist/hooks/useResolvedTheme.d.ts +15 -0
  31. package/dist/index.cjs +4 -0
  32. package/dist/index.d.cts +13 -0
  33. package/dist/index.d.ts +13 -51
  34. package/dist/index.js +5819 -0
  35. package/dist/pages/Gantt.d.ts +306 -0
  36. package/dist/stores/context.d.ts +10 -0
  37. package/dist/stores/store.d.ts +118 -0
  38. package/dist/types/gantt.d.ts +283 -0
  39. package/dist/types/task.d.ts +111 -0
  40. package/dist/utils/a11y.d.ts +141 -0
  41. package/dist/utils/arrowPath.d.ts +66 -0
  42. package/dist/utils/dependency.d.ts +42 -0
  43. package/dist/utils/grouping.d.ts +81 -0
  44. package/dist/utils/headerUtils.d.ts +6 -0
  45. package/dist/utils/history.d.ts +56 -0
  46. package/dist/utils/i18n.d.ts +16 -0
  47. package/dist/utils/mutation.d.ts +47 -0
  48. package/dist/utils/pngExport.d.ts +67 -0
  49. package/dist/utils/pointerGesture.d.ts +31 -0
  50. package/dist/utils/rowDrag.d.ts +69 -0
  51. package/dist/utils/timeline.d.ts +161 -0
  52. package/dist/utils/transformData.d.ts +15 -0
  53. package/dist/utils/viewport.d.ts +95 -0
  54. package/package.json +47 -32
  55. package/dist/index.cjs.js +0 -4
  56. package/dist/index.es.js +0 -2357
  57. package/dist/readmeImg.png +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 jaeungkim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,62 +1,49 @@
1
1
  # @jaeungkim/gantt-chart
2
2
 
3
- <!-- ![React Gantt Chart](https://raw.githubusercontent.com/jaeungkim/gantt-chart/main/public/readmeImg.png) -->
3
+ [![npm version](https://img.shields.io/npm/v/@jaeungkim/gantt-chart)](https://www.npmjs.com/package/@jaeungkim/gantt-chart)
4
+ [![CI](https://github.com/jaeungkim/gantt-chart/actions/workflows/ci.yml/badge.svg)](https://github.com/jaeungkim/gantt-chart/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/@jaeungkim/gantt-chart)](LICENSE)
4
6
 
5
- Lightweight, high-performance Gantt chart component for React applications. Designed for fast rendering with virtualization and clean, minimal aesthetics.
7
+ A Gantt chart for React: virtualized rows, editable bars, dependency arrows, and a scheduling
8
+ engine that runs without a DOM.
6
9
 
7
- ## 🎯 Motivation
10
+ **[Live demo](https://jaeungkim.com/gantt-chart)** Β· **[Documentation](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/README.md)** Β· **[ν•œκ΅­μ–΄ λ¬Έμ„œ](https://github.com/jaeungkim/gantt-chart/blob/main/docs/ko/README.md)**
8
11
 
9
- I originally wanted to use Microsoft Project's Gantt Chart for personal project management, but it required a subscription πŸ˜”. Thus, I decided to build my own Gantt chart, referencing various open-source projects and examples, including MS Project, DHTMLX, Frappe Gantt Chart, and etc.
12
+ ## Motivation
10
13
 
11
- Since there aren't many open-source Gantt chart solutions available, I hope this project will be useful for others as well. I am very open to feedback, feature requests, and contributions to make this Gantt chart as robust and versatile as possible.
14
+ I wanted Microsoft Project's Gantt chart for my own project planning, and it wanted a
15
+ subscription. So I built one, borrowing ideas from MS Project, DHTMLX and Frappe Gantt.
12
16
 
13
- Currently, this project is built specifically for React due to my development background, but in the future, I may explore making it available for other frameworks as well. Since this is my first open-source project, I look forward to learning and improving it with the community!
17
+ There are not many open-source Gantt charts, so I hope this is useful to someone else too.
18
+ Feedback, feature requests and pull requests are all welcome β€” this is my first open-source
19
+ project and I would like to keep improving it with whoever shows up.
14
20
 
15
- ## ✨ Features
16
-
17
- - πŸ“† Multiple timeline scales: Day, Week, Month, Year
18
- - πŸ”„ Drag-and-drop support:
19
- - Move entire task bars
20
- - Resize from left/right edges
21
- - Snap to configured intervals
22
- - 🧲 Smart dependency arrows (FS, SS, FF, SF)
23
- - ⚑ Virtualized rendering for performance
24
- - πŸŒ™ Light/Dark/System theme support
25
- - πŸ“ Today marker indicator
26
- - πŸ’¬ Drag tooltip showing date changes
27
- - πŸ“¦ Lightweight with minimal dependencies
28
-
29
- ## πŸ“Ί [Demo](https://jaeungkim.com/gantt-chart)
30
-
31
- ## πŸš€ Getting Started
32
-
33
- ### Installation
21
+ ## Install
34
22
 
35
23
  ```bash
36
- npm install @jaeungkim/gantt-chart
37
- # or
38
- yarn add @jaeungkim/gantt-chart
24
+ pnpm add @jaeungkim/gantt-chart
39
25
  ```
40
26
 
41
- ### Basic Usage
27
+ `react` and `react-dom` (`^18` or `^19`) are peer dependencies.
28
+
29
+ ## Usage
42
30
 
43
31
  ```tsx
44
- import { ReactGanttChart } from '@jaeungkim/gantt-chart';
45
- import type { Task } from '@jaeungkim/gantt-chart';
32
+ import { ReactGanttChart, type Task } from '@jaeungkim/gantt-chart';
33
+ import '@jaeungkim/gantt-chart/style.css';
46
34
 
47
35
  const tasks: Task[] = [
48
36
  {
49
37
  id: '1',
50
- name: 'Project Kickoff',
38
+ name: 'Project kickoff',
51
39
  startDate: '2024-06-01T09:00:00Z',
52
40
  endDate: '2024-06-03T17:00:00Z',
53
41
  parentId: null,
54
42
  sequence: '1',
55
- dependencies: [],
56
43
  },
57
44
  {
58
45
  id: '2',
59
- name: 'Requirements Gathering',
46
+ name: 'Requirements',
60
47
  startDate: '2024-06-04T09:00:00Z',
61
48
  endDate: '2024-06-10T17:00:00Z',
62
49
  parentId: null,
@@ -69,92 +56,64 @@ export default function App() {
69
56
  return (
70
57
  <ReactGanttChart
71
58
  tasks={tasks}
72
- height="100vh"
73
- width="100%"
59
+ height={600}
74
60
  theme="system"
75
61
  defaultScale="month"
76
- onTasksChange={(updated) => console.log('Tasks updated:', updated)}
62
+ onTasksChange={(updated) => console.log(updated)}
77
63
  />
78
64
  );
79
65
  }
80
66
  ```
81
67
 
82
- ## Props
83
-
84
- | Prop | Type | Default | Description |
85
- |------|------|---------|-------------|
86
- | `tasks` | `Task[]` | `[]` | Array of task objects to render |
87
- | `onTasksChange` | `(tasks: Task[]) => void` | - | Callback when tasks are moved or resized |
88
- | `height` | `number \| string` | `600` | Chart height (px or CSS value) |
89
- | `width` | `number \| string` | `"100%"` | Chart width (px or CSS value) |
90
- | `theme` | `"light" \| "dark" \| "system"` | - | Theme mode |
91
- | `defaultScale` | `"day" \| "week" \| "month" \| "year"` | `"month"` | Initial timeline scale |
92
- | `className` | `string` | - | Additional CSS class for the container |
93
-
94
- ## Task Format
95
-
96
- All dates must be in **UTC ISO string format**: `"2024-06-01T09:00:00Z"`
97
-
98
- ```ts
99
- interface Task {
100
- id: string;
101
- name: string;
102
- startDate: string; // UTC ISO string
103
- endDate: string; // UTC ISO string
104
- parentId: string | null;
105
- sequence: string;
106
- dependencies?: TaskDependency[];
107
- }
68
+ The chart never stores your data. Every committed gesture ends in one `onTasksChange` call with a
69
+ new array, and it is up to you to keep it.
108
70
 
109
- interface TaskDependency {
110
- targetId: string;
111
- type: DependencyType;
112
- }
71
+ Full walkthrough: **[Quick start](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/quick-start.md)**.
113
72
 
114
- type DependencyType = 'FS' | 'SS' | 'FF' | 'SF';
115
- // FS = Finish-to-Start
116
- // SS = Start-to-Start
117
- // FF = Finish-to-Finish
118
- // SF = Start-to-Finish
119
- ```
73
+ ## What it does
120
74
 
121
- ## Timeline Scales
75
+ **Rendering** β€” virtualized rows, a configurable task list pane with a draggable splitter, six
76
+ timeline scales from hour to year, elbow-routed dependency arrows, date markers, range bands,
77
+ non-working-day shading and baseline bars.
122
78
 
123
- | Scale | Header Label | Tick Unit | Drag Step |
124
- |-------|-------------|-----------|-----------|
125
- | `day` | Day | Hour | 1 hour |
126
- | `week` | Week | Day | 6 hours |
127
- | `month` | Month | Day | 1 day |
128
- | `year` | Year | Month | 7 days |
79
+ **Editing** β€” move, resize and set progress by dragging; draw a new task on empty row space; draw
80
+ and delete dependency arrows; reorder, indent and outdent rows; undo and redo.
129
81
 
130
- Switch scales using the dropdown at the top-right of the chart.
82
+ **Scheduling** β€” successors reschedule on a drag under a policy you choose, a working-day calendar
83
+ makes weekends and holidays stop counting, and the critical path comes with total and free slack.
84
+ The same functions are exported as plain functions you can call on a server or in a worker.
131
85
 
132
- ## Theming
86
+ **Accessibility** β€” one ARIA treegrid with a roving tab stop; bars move, resize and step their
87
+ progress from the keyboard.
133
88
 
134
- The chart supports three theme modes:
89
+ **Theming** β€” `--gantt-*` custom properties scoped to the chart container, a light / dark / system
90
+ theme prop, per-task colors, and four render props for replacing elements outright.
135
91
 
136
- - **`light`** - Light background with dark text
137
- - **`dark`** - Dark background with light text
138
- - **`system`** - Follows system preference (uses `prefers-color-scheme`)
92
+ Each of these, and the honest list of what the library does **not** do, is in
93
+ **[Introduction](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/introduction.md)**.
139
94
 
140
- ```tsx
141
- <ReactGanttChart theme="dark" ... />
142
- ```
95
+ ## Documentation
143
96
 
144
- ## Roadmap
97
+ | Page | |
98
+ |---|---|
99
+ | [Quick start](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/quick-start.md) | install to a working, editable chart |
100
+ | [Task data](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/task-data.md) | the `Task` shape and how the `tasks` prop is compared |
101
+ | [Editing tasks](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/editing.md) | gestures, permissions, touch |
102
+ | [Dependencies](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/dependencies.md) | the four link types and lag |
103
+ | [Scheduling](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/scheduling.md) | policies, working calendar, critical path, baselines |
104
+ | [Keyboard and screen readers](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/accessibility.md) | the key map, the ARIA tree, and the gaps |
105
+ | [Theming](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/theming.md) | the CSS custom properties |
106
+ | [Props](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/ref/props.md) | every prop, in one table |
145
107
 
146
- - [ ] Left sidebar for task names
147
- - [ ] Right sidebar for task details
148
- - [ ] Collapsible parent-child rows
149
- - [ ] Inline editing for task names
150
- - [ ] Export to PNG/SVG
151
- - [ ] Custom bar colors
108
+ All 35 pages: **[English](https://github.com/jaeungkim/gantt-chart/blob/main/docs/en/README.md)** Β· **[ν•œκ΅­μ–΄](https://github.com/jaeungkim/gantt-chart/blob/main/docs/ko/README.md)**
152
109
 
153
- ## 🀝 Contributing
110
+ ## Contributing
154
111
 
155
- Pull requests are welcome!
156
- If you find bugs or have suggestions, feel free to open an issue or contribute directly.
112
+ Setup, the checks CI runs, and the branch and PR conventions are in
113
+ [CONTRIBUTING.md](CONTRIBUTING.md). Questions and ideas go in
114
+ [Discussions](https://github.com/jaeungkim/gantt-chart/discussions); issues are for bugs and
115
+ concrete feature requests.
157
116
 
158
- ## πŸ“„ License
117
+ ## License
159
118
 
160
- MIT Β© [jaeungkim](https://github.com/jaeungkim)
119
+ [MIT](LICENSE)
@@ -0,0 +1,23 @@
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 {};
@@ -0,0 +1,17 @@
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;
@@ -0,0 +1,15 @@
1
+ import { GanttDependencyChange } from '../hooks/useGanttLinkDrag';
2
+ import { GanttInteractionConfig, Task, TaskTransformed } from '../types/task';
3
+ interface Props {
4
+ transformedTasks: TaskTransformed[];
5
+ /** Row count of the chart - a lane row can carry several tasks, so it is not the task count */
6
+ rowCount: number;
7
+ /** Link keys on the critical path (from computeCriticalPath) - undefined when it is off */
8
+ criticalLinkIds?: Set<string>;
9
+ interaction?: GanttInteractionConfig;
10
+ onTasksChange?: (updatedTasks: Task[]) => void;
11
+ /** Returning false keeps the dependency */
12
+ onDependencyDelete?: (change: GanttDependencyChange) => boolean | void;
13
+ }
14
+ export default function GanttDependencyArrows({ transformedTasks, rowCount, criticalLinkIds, interaction, onTasksChange, onDependencyDelete, }: Props): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,9 @@
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 {};
@@ -0,0 +1,14 @@
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 {};
@@ -0,0 +1,18 @@
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;
@@ -0,0 +1,42 @@
1
+ import { VirtualItem } from '@tanstack/react-virtual';
2
+ import { GanttColumn, GanttReorderChange } from '../types/gantt';
3
+ import { GanttInteractionConfig, Task, TaskTransformed } from '../types/task';
4
+ import { GanttFocus } from '../utils/a11y';
5
+ import { GanttRow } from '../utils/grouping';
6
+ interface GanttTaskGridProps {
7
+ /** The rows on screen (collapsed subtrees and groups are already filtered out) */
8
+ rows: GanttRow[];
9
+ columns: GanttColumn[];
10
+ /** The timeline's own virtualization result - leaves no room for the rows to drift apart */
11
+ virtualItems: VirtualItem[];
12
+ totalHeight: number;
13
+ width: number;
14
+ hierarchy: boolean;
15
+ collapsedIds: Set<string>;
16
+ onToggleCollapse: (rowId: string) => void;
17
+ /** Which cell currently holds the chart's single tab stop */
18
+ focus: GanttFocus;
19
+ /** Whether rows can be dragged to reorder and re-parent */
20
+ allowRowReorder: boolean;
21
+ /** The same guards the bars use - a row is draggable only where the task can move */
22
+ interaction: GanttInteractionConfig;
23
+ onReorder?: (change: GanttReorderChange) => void | boolean;
24
+ onTasksChange?: (updatedTasks: Task[]) => void;
25
+ /** The selected row, highlighted in step with its bar */
26
+ selectedTaskId?: string | null;
27
+ onRowClick?: (task: TaskTransformed, event: React.MouseEvent) => void;
28
+ onRowDoubleClick?: (task: TaskTransformed, event: React.MouseEvent) => void;
29
+ }
30
+ /**
31
+ * The task grid on the left
32
+ *
33
+ * A sticky column inside the timeline's own scroll container, so vertical scrolling is
34
+ * locked to the rows by construction.
35
+ * (Syncing two panes through scroll events drifts the moment virtualization kicks in)
36
+ *
37
+ * These rows are the treegrid's `row` elements: each one owns its bars in the
38
+ * timeline through `aria-owns`, which is what makes the two panes read as a
39
+ * single widget rather than two unrelated lists.
40
+ */
41
+ export default function GanttTaskGrid({ rows, columns, virtualItems, totalHeight, width, hierarchy, collapsedIds, onToggleCollapse, focus, allowRowReorder, interaction, onReorder, onTasksChange, selectedTaskId, onRowClick, onRowDoubleClick, }: GanttTaskGridProps): import("react").JSX.Element;
42
+ export {};
@@ -0,0 +1,11 @@
1
+ import { GanttScaleKey } from '../types/gantt';
2
+ interface ScaleSelectorProps {
3
+ selectedScale: GanttScaleKey;
4
+ onScaleChange: (scale: GanttScaleKey) => void;
5
+ }
6
+ /**
7
+ * Segmented control for choosing the Gantt chart scale
8
+ * Uses a pill-style button group instead of a dropdown
9
+ */
10
+ export default function ScaleSelector({ selectedScale, onScaleChange, }: ScaleSelectorProps): import("react").JSX.Element;
11
+ export {};
@@ -0,0 +1,47 @@
1
+ import { GanttColumn, GanttScaleConfig, GanttScaleKey } from '../types/gantt';
2
+ export declare const NODE_HEIGHT = 38;
3
+ /** Full timeline header height (44 top group + 28 bottom cell + 1 border) - the grid header matches it */
4
+ export declare const HEADER_HEIGHT = 73;
5
+ /** Default grid column width (px) */
6
+ export declare const DEFAULT_COLUMN_WIDTH = 120;
7
+ /** Grid pane width limits (px) */
8
+ export declare const MIN_GRID_WIDTH = 120;
9
+ export declare const MAX_GRID_WIDTH = 800;
10
+ /** Indentation per tree level (px) */
11
+ export declare const TREE_INDENT = 16;
12
+ /**
13
+ * Default task grid columns
14
+ * Replaceable wholesale through the columns prop, so no header label is baked into the library.
15
+ */
16
+ export declare const DEFAULT_COLUMNS: GanttColumn[];
17
+ export declare const TIMELINE_SHIFT_BUFFER = 5;
18
+ /** Bars render at least this wide, however narrow they are (px) - keeps short tasks grabbable */
19
+ export declare const MIN_BAR_WIDTH = 14;
20
+ /** Below this width the task name is shown outside the bar (px) */
21
+ export declare const MIN_LABEL_INSIDE_WIDTH = 56;
22
+ /** Size of the resize edge hit area (px) */
23
+ export declare const EDGE_THRESHOLD = 8;
24
+ /**
25
+ * Size of the resize edge hit area for touch and pen (px)
26
+ *
27
+ * The 44px accessibility guideline, applied to the axis the bar can grow along. A bar
28
+ * is half a row tall, so the target cannot also be 44px high without covering the row
29
+ * next to it - what keeps a mistimed tap harmless instead is the long press: a touch
30
+ * has to rest on the edge before anything is lifted.
31
+ */
32
+ export declare const TOUCH_EDGE_THRESHOLD = 44;
33
+ /** Below this bar width there is no edge resizing and the whole bar is the move handle (px) */
34
+ export declare const MIN_RESIZABLE_WIDTH: number;
35
+ /** Same rule for touch - below this a bar is move-only, so the edges cannot swallow it (px) */
36
+ export declare const MIN_TOUCH_RESIZABLE_WIDTH: number;
37
+ /** Side length of the milestone diamond (px, before the 45-degree rotation) */
38
+ export declare const MILESTONE_SIZE = 16;
39
+ /** Horizontal distance from the diamond's center to its vertex (px) */
40
+ export declare const MILESTONE_HALF_DIAGONAL: number;
41
+ /**
42
+ * Date display format per scale (shared by the tooltip and the drag guides) - year included, 24-hour clock
43
+ * The chart is drawn in UTC, so the zone is spelled out only on the day scale, where the time is visible
44
+ */
45
+ export declare const DATE_FORMATS: Record<GanttScaleKey, string>;
46
+ /** Declaration order is the order the scale selector lists the scales in - finest first */
47
+ export declare const GANTT_SCALE_CONFIG: Record<GanttScaleKey, GanttScaleConfig>;
@@ -0,0 +1,45 @@
1
+ import { Dayjs } from 'dayjs';
2
+ /**
3
+ * The calendar every piece of date arithmetic in the core routes through.
4
+ *
5
+ * There is exactly one notion of "a day" in the engine: whatever this object says.
6
+ * The default calendar counts every day, so the plain calendar-date behaviour is not a
7
+ * separate code path - it is the same code with a calendar that never skips anything.
8
+ * Turning the working-day calendar on swaps the object; nothing else changes.
9
+ */
10
+ export interface WorkingCalendar {
11
+ /** False for the default calendar (every day counts) - lets callers take the cheap path */
12
+ readonly skipsNonWorkingDays: boolean;
13
+ isWorkingDay(date: Dayjs): boolean;
14
+ /** Moves `days` days forward (or backward), skipping non-working days */
15
+ addDays(date: Dayjs, days: number): Dayjs;
16
+ /** Days from `from` to `to`, counted the same way `addDays` moves. Signed. */
17
+ daysBetween(from: Dayjs, to: Dayjs): number;
18
+ /** Smallest d where `addDays(from, d) >= target` - how far a task must move to clear a date */
19
+ daysUntil(from: Dayjs, target: Dayjs): number;
20
+ /** Largest d where `addDays(from, d) <= target` - how far a task may slip before it breaks one */
21
+ daysUpTo(from: Dayjs, target: Dayjs): number;
22
+ /** The date itself when it is a working day, otherwise the next one (time of day kept) */
23
+ snapForward(date: Dayjs): Dayjs;
24
+ }
25
+ export interface WorkingCalendarOptions {
26
+ /** Working weekdays as UTC day numbers, 0 = Sunday (default Mon-Fri) */
27
+ workingWeekdays?: number[];
28
+ /** Non-working dates as UTC `YYYY-MM-DD` strings */
29
+ holidays?: string[];
30
+ /** Replaces the weekday + holiday check entirely */
31
+ isNonWorkingDay?: (date: Dayjs) => boolean;
32
+ }
33
+ /**
34
+ * The default calendar: every day counts.
35
+ * Date arithmetic through it is plain calendar arithmetic, so it is what keeps the
36
+ * scheduling features behaviour-neutral until a host opts into working days.
37
+ */
38
+ export declare const CALENDAR_DAYS: WorkingCalendar;
39
+ /**
40
+ * A calendar that skips weekends and holidays.
41
+ *
42
+ * Takes the same configuration the chart already uses to shade non-working days
43
+ * (`holidays` / `isNonWorkingDay`), so what is shaded and what is skipped cannot drift.
44
+ */
45
+ export declare function createWorkingCalendar(options?: WorkingCalendarOptions): WorkingCalendar;
@@ -0,0 +1,67 @@
1
+ import { Dayjs } from 'dayjs';
2
+ import { WorkingCalendar } from './calendar';
3
+ import { TaskGraph } from './scheduling';
4
+ import { Task } from './types';
5
+ /**
6
+ * Critical path method over the dependency graph.
7
+ *
8
+ * Every task carries real dates, so its own start acts as a "no earlier than" constraint:
9
+ * the forward pass moves a task later when a predecessor demands it and never earlier, and
10
+ * the backward pass works out how much later each task could still finish without pushing
11
+ * the project's end out. Zero difference between the two is zero slack - the critical path.
12
+ *
13
+ * Everything is measured as a whole-day shift of the task's own dates, so times of day
14
+ * survive untouched and the numbers are working days whenever the calendar says so.
15
+ */
16
+ export interface EarlyDates {
17
+ start: Dayjs;
18
+ finish: Dayjs;
19
+ /** Days later than the task's own dates */
20
+ shift: number;
21
+ }
22
+ export interface LateDates {
23
+ start: Dayjs;
24
+ finish: Dayjs;
25
+ /** Days later than the task's own dates the task could still run */
26
+ shift: number;
27
+ }
28
+ export interface TaskScheduleMetrics {
29
+ earlyStart: string;
30
+ earlyFinish: string;
31
+ lateStart: string;
32
+ lateFinish: string;
33
+ /** Days a task can slip before the project's finish moves */
34
+ totalSlack: number;
35
+ /** Days a task can slip before any successor's early start moves */
36
+ freeSlack: number;
37
+ critical: boolean;
38
+ /** Calendar days, or working days when the working-day calendar is on */
39
+ duration: number;
40
+ }
41
+ export interface CriticalPathResult {
42
+ metrics: Map<string, TaskScheduleMetrics>;
43
+ criticalTaskIds: Set<string>;
44
+ /** Keys from `linkKey` for the links that lie along the critical path */
45
+ criticalLinkIds: Set<string>;
46
+ /** Ids caught in a dependency cycle - they get no metrics */
47
+ cycle: string[] | null;
48
+ /** The project's earliest finish (UTC ISO string), or null with no tasks */
49
+ projectFinish: string | null;
50
+ }
51
+ export interface CriticalPathOptions {
52
+ calendar?: WorkingCalendar;
53
+ }
54
+ /**
55
+ * Earliest each task can run given its predecessors, walked predecessors-first.
56
+ * A task with no predecessor stays on its own dates.
57
+ */
58
+ export declare function forwardPass(tasks: Task[], calendar?: WorkingCalendar, graph?: TaskGraph): Map<string, EarlyDates>;
59
+ /**
60
+ * Latest each task can run without moving the project's finish, walked successors-first.
61
+ *
62
+ * Takes the forward pass's output rather than recomputing it, so it can be exercised on
63
+ * its own with hand-written early dates.
64
+ */
65
+ export declare function backwardPass(tasks: Task[], early: Map<string, EarlyDates>, calendar?: WorkingCalendar, graph?: TaskGraph, projectFinish?: Dayjs): Map<string, LateDates>;
66
+ /** Forward pass, backward pass, and the slack numbers that fall out of the two */
67
+ export declare function computeCriticalPath(tasks: Task[], options?: CriticalPathOptions): CriticalPathResult;
@@ -0,0 +1,32 @@
1
+ import { default as dayjs, Dayjs } from 'dayjs';
2
+ /**
3
+ * The chart's own dayjs - always parses and displays in UTC mode.
4
+ *
5
+ * The contract for task dates is "UTC ISO string" (README > Task Format), so
6
+ * positioning and labels follow UTC too. Parsing in local mode would draw the same
7
+ * data in different date cells depending on where the viewer is (#84), and local
8
+ * calendar DST days (23/25 hours) would make cell widths wobble as well (#28).
9
+ *
10
+ * - A string carrying a zone ('...Z', '+09:00') displays that instant as a UTC time
11
+ * - A string without a zone ('2025-06-01', '2025-06-01T09:00') is read as a UTC wall
12
+ * clock, so it displays exactly as written, whatever the viewer's time zone
13
+ */
14
+ declare const ganttDayjs: typeof dayjs.utc;
15
+ export default ganttDayjs;
16
+ /**
17
+ * Calendar quarter of the date, 1-4
18
+ *
19
+ * Written out instead of pulling in dayjs' quarterOfYear plugin - the quarter scale
20
+ * needs exactly these two lines of it, and the plugin would grow the bundle for every
21
+ * consumer, quarter scale in use or not.
22
+ */
23
+ export declare function quarterOfYear(date: Dayjs): number;
24
+ /** First moment of the calendar quarter the date falls in */
25
+ export declare function startOfQuarter(date: Dayjs): Dayjs;
26
+ /**
27
+ * First moment of the week the date falls in
28
+ *
29
+ * `firstDayOfWeek` is 0 = Sunday .. 6 = Saturday. dayjs' own `startOf('week')` is fixed
30
+ * to the locale dayjs was loaded with (Sunday), so the week boundary is computed here.
31
+ */
32
+ export declare function startOfWeek(date: Dayjs, firstDayOfWeek?: number): Dayjs;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The headless scheduling core.
3
+ *
4
+ * Everything under `src/core/` is plain data and pure functions - no React, no DOM, no
5
+ * pixels - so it runs in Node, is unit-testable on its own, and could be published as a
6
+ * separate entry point without dragging the renderer along. The boundary is enforced by an
7
+ * eslint rule in `eslint.config.js`; keep anything that touches refs, elements or bar
8
+ * geometry in `src/utils/` instead.
9
+ */
10
+ export { default as dayjs } from './dates';
11
+ export type { DependencyType, Task, TaskDependency, TaskType, } from './types';
12
+ export { isMilestoneTask, normalizeProgress } from './types';
13
+ export { CALENDAR_DAYS, createWorkingCalendar, type WorkingCalendar, type WorkingCalendarOptions, } from './calendar';
14
+ export { buildTaskGraph, canLink, findPath, linkDelta, linkKey, scheduleTasks, shiftTask, taskEnd, taskStart, type ScheduleOptions, type ScheduleResult, type SchedulingLink, type SchedulingPolicy, type TaskGraph, } from './scheduling';
15
+ export { backwardPass, computeCriticalPath, forwardPass, type CriticalPathOptions, type CriticalPathResult, type EarlyDates, type LateDates, type TaskScheduleMetrics, } from './criticalPath';
16
+ export { buildTaskTree, collectSubtreeIds, getVisibleTasks, rollUpTasks, type TaskTree, } from './tree';