@jaeungkim/gantt-chart 0.3.1 → 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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +222 -124
  3. package/dist/Gantt.d.ts +5 -0
  4. package/dist/bars/components/GanttBar.d.ts +20 -0
  5. package/dist/bars/components/GanttBarsLayer.d.ts +24 -0
  6. package/dist/bars/components/GanttDragGuides.d.ts +1 -0
  7. package/dist/bars/hooks/useGanttBarDrag.d.ts +16 -0
  8. package/dist/bars/hooks/useGanttDrawCreate.d.ts +25 -0
  9. package/dist/bars/hooks/useGanttProgressDrag.d.ts +11 -0
  10. package/dist/core/calendar.d.ts +27 -0
  11. package/dist/core/dates.d.ts +16 -0
  12. package/dist/core/index.d.ts +3 -0
  13. package/dist/core/reorder.d.ts +55 -0
  14. package/dist/core/tree.d.ts +34 -0
  15. package/dist/core/types.d.ts +43 -0
  16. package/dist/dependencies/components/GanttDependencyArrows.d.ts +13 -0
  17. package/dist/dependencies/hooks/useGanttLinkDrag.d.ts +20 -0
  18. package/dist/dependencies/utils/arrowPath.d.ts +20 -0
  19. package/dist/dependencies/utils/link.d.ts +17 -0
  20. package/dist/detail/components/GanttDetailPanel.d.ts +21 -0
  21. package/dist/detail/hooks/useGanttDetail.d.ts +42 -0
  22. package/dist/detail/utils/edit.d.ts +21 -0
  23. package/dist/gantt-chart.css +1 -1
  24. package/dist/index.cjs +1 -0
  25. package/dist/index.d.cts +11 -0
  26. package/dist/index.d.ts +11 -51
  27. package/dist/index.js +4749 -0
  28. package/dist/interaction/hooks/useGanttInteraction.d.ts +2 -0
  29. package/dist/interaction/hooks/useGanttKeyboardNav.d.ts +33 -0
  30. package/dist/interaction/hooks/useGanttSelection.d.ts +12 -0
  31. package/dist/interaction/utils/a11y.d.ts +84 -0
  32. package/dist/props.d.ts +121 -0
  33. package/dist/rows/components/GanttRowsLayer.d.ts +13 -0
  34. package/dist/rows/hooks/useGanttCollapse.d.ts +18 -0
  35. package/dist/rows/hooks/useGanttRowModel.d.ts +19 -0
  36. package/dist/rows/utils/rows.d.ts +21 -0
  37. package/dist/shared/constants.d.ts +24 -0
  38. package/dist/shared/context.d.ts +4 -0
  39. package/dist/shared/hooks/useLatestRef.d.ts +2 -0
  40. package/dist/shared/hooks/useResolvedTheme.d.ts +8 -0
  41. package/dist/shared/store.d.ts +81 -0
  42. package/dist/shared/task.d.ts +55 -0
  43. package/dist/shared/types.d.ts +115 -0
  44. package/dist/shared/utils/holidays.d.ts +12 -0
  45. package/dist/shared/utils/i18n.d.ts +5 -0
  46. package/dist/shared/utils/pointerGesture.d.ts +11 -0
  47. package/dist/shared/virtual/axis.d.ts +13 -0
  48. package/dist/shared/virtual/useVirtualWindow.d.ts +16 -0
  49. package/dist/shared/virtual/window.d.ts +30 -0
  50. package/dist/task-list/components/GanttGridSplitter.d.ts +6 -0
  51. package/dist/task-list/components/GanttTaskAddRow.d.ts +7 -0
  52. package/dist/task-list/components/GanttTaskGrid.d.ts +24 -0
  53. package/dist/task-list/hooks/useGanttRowDrag.d.ts +17 -0
  54. package/dist/task-list/hooks/useGanttTaskListPane.d.ts +11 -0
  55. package/dist/task-list/hooks/useGanttTaskMove.d.ts +16 -0
  56. package/dist/timeline/components/GanttChartHeader.d.ts +10 -0
  57. package/dist/timeline/components/GanttHolidayLabels.d.ts +6 -0
  58. package/dist/timeline/components/GanttNonWorkingLayer.d.ts +6 -0
  59. package/dist/timeline/components/GanttTodayLine.d.ts +6 -0
  60. package/dist/timeline/hooks/useGanttScrollApi.d.ts +62 -0
  61. package/dist/timeline/hooks/useGanttViewport.d.ts +47 -0
  62. package/dist/timeline/hooks/useGanttVirtualization.d.ts +28 -0
  63. package/dist/timeline/utils/geometry.d.ts +52 -0
  64. package/dist/timeline/utils/header.d.ts +8 -0
  65. package/dist/timeline/utils/transform.d.ts +4 -0
  66. package/dist/timeline/utils/viewport.d.ts +31 -0
  67. package/dist/useGanttSelectors.d.ts +11 -0
  68. package/package.json +53 -38
  69. package/dist/index.cjs.js +0 -4
  70. package/dist/index.es.js +0 -2394
  71. 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,160 +1,258 @@
1
- # @jaeungkim/gantt-chart
2
-
3
- <!-- ![React Gantt Chart](https://raw.githubusercontent.com/jaeungkim/gantt-chart/main/public/readmeImg.png) -->
4
-
5
- Lightweight, high-performance Gantt chart component for React applications. Designed for fast rendering with virtualization and clean, minimal aesthetics.
6
-
7
- ## 🎯 Motivation
8
-
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.
10
-
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.
12
-
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!
14
-
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
1
+ [![Banner](https://raw.githubusercontent.com/jaeungkim/gantt-chart/main/public/banner.png)](https://gantt.jaeungkim.com)
28
2
 
29
- ## 📺 [Demo](https://jaeungkim.com/gantt-chart)
30
-
31
- ## 🚀 Getting Started
3
+ # @jaeungkim/gantt-chart
32
4
 
33
- ### Installation
5
+ [![npm version](https://img.shields.io/npm/v/@jaeungkim/gantt-chart)](https://www.npmjs.com/package/@jaeungkim/gantt-chart)
6
+ [![CI](https://github.com/jaeungkim/gantt-chart/actions/workflows/ci.yml/badge.svg)](https://github.com/jaeungkim/gantt-chart/actions/workflows/ci.yml)
7
+ [![license](https://img.shields.io/npm/l/@jaeungkim/gantt-chart)](LICENSE)
8
+
9
+ A Gantt chart for React that you can actually edit. Virtualized rows, four dependency types, a
10
+ working-day calendar, keyboard and screen-reader support, and a date core that runs without a DOM.
11
+
12
+ **[Quick start](https://gantt.jaeungkim.com/docs/quick-start)** ·
13
+ **[Playground](https://gantt.jaeungkim.com/playground)** ·
14
+ **[Documentation](https://gantt.jaeungkim.com/docs)** ·
15
+ **[한국어 문서](https://gantt.jaeungkim.com/ko/docs)**
16
+
17
+ The package is two layers. `ReactGanttChart` renders the chart, handles every gesture, and hands
18
+ your app a new `tasks` array each time an edit commits. The tree and calendar math underneath it is
19
+ exported as plain functions, so a server, a worker or a test can call them without rendering
20
+ anything.
21
+
22
+ ## Features
23
+
24
+ ### Rendering
25
+
26
+ - Rows and time cells are virtualized together. Bars outside the window are not mounted.
27
+ - Five scales, `day` through `year`, each with its own tick unit, drag step and label format.
28
+ - A task list pane on the left with an optional row-number column, behind a draggable splitter.
29
+ - `hierarchy` derives depth and summary rows from `parentId`. A summary row's dates and progress
30
+ roll up from its children, and it collapses.
31
+ - `lane` packs tasks that never overlap onto one row, side by side.
32
+ - Dependency arrows routed as elbows for all four link types: `FS`, `SS`, `FF`, `SF`.
33
+ - A today line, weekend and holiday shading, and a hover card per bar.
34
+ - A docked detail panel that narrows the timeline instead of covering it. `renderDetail` replaces
35
+ its body; `detailTaskId` controls which task is open.
36
+
37
+ ### Editing
38
+
39
+ - Drag a bar to move it, pull either edge to resize it, drag the handle to set progress. Touch and
40
+ pen get wider grab zones.
41
+ - While a drag is live the dragged dates print in the date-axis cells they land in. Nothing floats
42
+ over the chart.
43
+ - Draw a dependency from one bar's link handle to another; click an arrow and press Delete to
44
+ remove it. `onDependencyCreate` and `onDependencyDelete` can veto either.
45
+ - Propose a new task from the **Add task** button under the task list, from `addTask()` on the ref,
46
+ or by drawing a range below the last row. The chart reports a draft through `onTaskCreate` and
47
+ never adds the row itself.
48
+ - Drag a task-list row to a new position or a new parent with `allowReorder`. `onTaskMove` can
49
+ reject the move.
50
+ - The detail panel edits too. Its built-in body changes the name, either date and the progress in
51
+ place, committing through the same `onTasksChange` and gated by the same per-task flags as the
52
+ bar gestures. A `renderDetail` body of your own commits through `update(patch)`.
53
+ - Permissions per chart and per task: `readOnly`, `allowMove`, `allowResize`,
54
+ `allowProgressChange`, `allowLinkCreate`, `allowLinkDelete`, `allowTaskCreate`, `allowReorder`,
55
+ plus `minDate` and `maxDate` drag bounds.
56
+ - Every committed gesture ends in one `onTasksChange` call with the complete next array.
57
+
58
+ ### Dates
59
+
60
+ - `workingCalendar` moves a drop forward off a weekend or a holiday. `workingWeekdays` says which
61
+ weekdays are worked and `holidays` lists the days off beyond them; both feed the calendar and the
62
+ shading, so the two cannot drift apart.
63
+ - A holiday can carry a `label` and a `color`. The name is written in the tick row over its band and
64
+ the colour tints it, so it reads apart from the weekend beside it.
65
+ - `visibleStart` and `visibleEnd` pin the range; `infiniteScroll` grows it at either end and
66
+ `onRangeChange` reports every change.
67
+ - Every date is UTC. A bare `YYYY-MM-DD` lands on the day it names in every viewer's time zone.
68
+
69
+ ### Keyboard and screen readers
70
+
71
+ - The chart is one ARIA treegrid with a single roving tab stop. Arrow keys move between rows and
72
+ cells; Home and End jump.
73
+ - Bars move, resize and step their progress from the keyboard. Rows reorder, indent and outdent.
74
+ Ctrl/Cmd + ArrowUp and ArrowDown step the scale, and edits are announced.
75
+ - A bar's accessible name is built from the task name, its dates and its progress.
76
+ - The gestures with no keyboard equivalent are written down in
77
+ [Keyboard and screen readers](https://gantt.jaeungkim.com/docs/accessibility), not hidden.
78
+
79
+ ### Locale and theme
80
+
81
+ - `locale` renders every date label through `Intl.DateTimeFormat`. `formats` overrides the tick,
82
+ header and tooltip labels per scale, and `firstDayOfWeek` picks where a week starts. No locale
83
+ package needed.
84
+ - `theme` takes `'light'`, `'dark'` or `'system'`. Omitted, the chart follows the host page's
85
+ `color-scheme`, which is what an app's own light/dark toggle already sets.
86
+ - 26 `--gantt-*` custom properties scoped to `.gantt-container`, so they cannot collide with your
87
+ own tokens.
88
+ - A per-task `color` derives the bar, its progress fill, its hover shade and a readable label color
89
+ from one value. A per-task `className` reaches the bar and its task-list row.
90
+
91
+ ### Imperative API
92
+
93
+ A `ref` of type `GanttHandle` exposes `scrollToDate`, `scrollToToday`, `scrollToTask`, `setScale`,
94
+ `zoomToFit`, `openDetail`, `closeDetail`, `addTask` and `getScrollElement`. The chart renders no
95
+ toolbar and no scale picker; you render the control and drive it through the ref.
96
+
97
+ ### Headless core
98
+
99
+ `buildTaskTree`, `collectSubtreeIds`, `rollUpTasks`, `sortTasksBySequence`, `validateMove`,
100
+ `moveTask`, `createWorkingCalendar` and `CALENDAR_DAYS` import no React and touch no DOM. They are
101
+ the same functions the chart runs, so a report on the server and the bars in the browser agree.
102
+
103
+ ### Packaging
104
+
105
+ - TypeScript types for every prop, callback and helper.
106
+ - ESM and CJS builds, one stylesheet at `@jaeungkim/gantt-chart/style.css`.
107
+ - React 18 and 19 as peer dependencies. Two runtime dependencies: `dayjs` and `zustand`.
108
+ - Published from CI with npm provenance.
109
+
110
+ ## Install
34
111
 
35
112
  ```bash
36
- npm install @jaeungkim/gantt-chart
37
- # or
38
- yarn add @jaeungkim/gantt-chart
113
+ pnpm add @jaeungkim/gantt-chart
114
+ # npm install @jaeungkim/gantt-chart
115
+ # yarn add @jaeungkim/gantt-chart
39
116
  ```
40
117
 
41
- ### Basic Usage
118
+ `react` and `react-dom` (`^18` or `^19`) are peer dependencies.
119
+
120
+ ## Quick example
42
121
 
43
122
  ```tsx
44
- import { ReactGanttChart } from '@jaeungkim/gantt-chart';
45
- import type { Task } from '@jaeungkim/gantt-chart';
123
+ import { useState } from 'react';
124
+ import { ReactGanttChart, type Task } from '@jaeungkim/gantt-chart';
125
+ import '@jaeungkim/gantt-chart/style.css';
46
126
 
47
- const tasks: Task[] = [
127
+ const initialTasks: Task[] = [
48
128
  {
49
- id: '1',
50
- name: 'Project Kickoff',
51
- startDate: '2024-06-01T09:00:00Z',
52
- endDate: '2024-06-03T17:00:00Z',
129
+ id: 'design',
130
+ name: 'Design',
131
+ startDate: '2026-03-02',
132
+ endDate: '2026-03-06',
53
133
  parentId: null,
54
134
  sequence: '1',
55
- dependencies: [],
135
+ progress: 100,
56
136
  },
57
137
  {
58
- id: '2',
59
- name: 'Requirements Gathering',
60
- startDate: '2024-06-04T09:00:00Z',
61
- endDate: '2024-06-10T17:00:00Z',
138
+ id: 'build',
139
+ name: 'Build',
140
+ startDate: '2026-03-09',
141
+ endDate: '2026-03-20',
62
142
  parentId: null,
63
143
  sequence: '2',
64
- dependencies: [{ targetId: '1', type: 'FS' }],
144
+ progress: 40,
145
+ dependencies: [{ targetId: 'design', type: 'FS' }],
146
+ },
147
+ {
148
+ id: 'ship',
149
+ name: 'Ship',
150
+ startDate: '2026-03-23',
151
+ endDate: '2026-03-23',
152
+ parentId: null,
153
+ sequence: '3',
154
+ dependencies: [{ targetId: 'build', type: 'FS' }],
65
155
  },
66
156
  ];
67
157
 
68
- export default function App() {
158
+ export default function ProjectChart() {
159
+ const [tasks, setTasks] = useState(initialTasks);
160
+
69
161
  return (
70
162
  <ReactGanttChart
71
163
  tasks={tasks}
72
- height="100vh"
73
- width="100%"
74
- theme="system"
164
+ onTasksChange={setTasks}
165
+ height={420}
166
+ showTaskList
75
167
  defaultScale="month"
76
- onTasksChange={(updated) => console.log('Tasks updated:', updated)}
77
168
  />
78
169
  );
79
170
  }
80
171
  ```
81
172
 
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
- }
108
-
109
- interface TaskDependency {
110
- targetId: string;
111
- type: DependencyType;
112
- }
113
-
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
- ```
120
-
121
- ## Timeline Scales
173
+ That chart is already editable. The chart keeps no canonical copy of your data: a committed gesture
174
+ ends in one `onTasksChange` call with the complete next array, so your app stays the source of
175
+ truth.
122
176
 
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 |
177
+ ### Add a scale control
129
178
 
130
- Switch scales using the dropdown at the top-right of the chart.
179
+ The chart ships no toolbar, so the scale picker is a control you own: render it, and call `setScale`
180
+ on the ref. `onScaleChange` fires for every source, so your control stays in step when Ctrl/Cmd +
181
+ wheel or Ctrl/Cmd + arrow moves the scale instead.
131
182
 
132
- ## Theming
183
+ The whole recipe is in **[Imperative API](https://gantt.jaeungkim.com/docs/imperative-api)**.
133
184
 
134
- The chart supports three theme modes:
185
+ ### Use the core without a chart
135
186
 
136
- - **`light`** - Light background with dark text
137
- - **`dark`** - Dark background with light text
138
- - **`system`** - Follows system preference (uses `prefers-color-scheme`)
187
+ ```ts
188
+ import { createWorkingCalendar, rollUpTasks, type Task } from '@jaeungkim/gantt-chart';
139
189
 
140
- ```tsx
141
- <ReactGanttChart theme="dark" ... />
190
+ const calendar = createWorkingCalendar({ holidays: ['2026-09-21'] });
191
+ const rolled = rollUpTasks(tasks); // summary rows recomputed from their children
142
192
  ```
143
193
 
144
- ## Roadmap
145
-
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
152
-
153
- ## 🤝 Contributing
154
-
155
- Pull requests are welcome!
156
- If you find bugs or have suggestions, feel free to open an issue or contribute directly.
157
-
158
- ## 📄 License
159
-
160
- MIT © [jaeungkim](https://github.com/jaeungkim)
194
+ Full walkthroughs: **[Quick start](https://gantt.jaeungkim.com/docs/quick-start)** and
195
+ **[Headless core](https://gantt.jaeungkim.com/docs/headless-core)**.
196
+
197
+ ## What it leaves to you
198
+
199
+ The chart renders the timeline and handles the gestures. Your app owns everything else:
200
+
201
+ - Data fetching and persistence. Tasks arrive as a prop; nothing is stored, not even the scale.
202
+ - Validation. Ids, date order and parseable dates are not checked before render.
203
+ - Automatic rescheduling. Moving a predecessor never moves its successors.
204
+ - Chrome. No toolbar, scale picker, zoom buttons or collapse button.
205
+ - Resources, costs, export and print.
206
+
207
+ The full boundary list is in
208
+ **[Introduction](https://gantt.jaeungkim.com/docs/introduction)**.
209
+
210
+ ## Documentation
211
+
212
+ | Guide | What it covers |
213
+ |---|---|
214
+ | [Introduction](https://gantt.jaeungkim.com/docs/introduction) | What the library is, and what it deliberately leaves to you |
215
+ | [Concepts and vocabulary](https://gantt.jaeungkim.com/docs/concepts) | Every term the rest of the docs use, defined once |
216
+ | [Quick start](https://gantt.jaeungkim.com/docs/quick-start) | Install to a working, editable chart |
217
+ | [Task data](https://gantt.jaeungkim.com/docs/task-data) | The `Task` shape, date handling, and how the `tasks` prop is compared |
218
+ | [Task list and hierarchy](https://gantt.jaeungkim.com/docs/task-list) | The left pane and the `parentId` tree |
219
+ | [Lanes](https://gantt.jaeungkim.com/docs/lanes) | The `lane` task field, which packs tasks that never overlap onto one row |
220
+ | [The timeline](https://gantt.jaeungkim.com/docs/timeline) | Scales, range, zoom, the today line, and non-working days |
221
+ | [Editing tasks](https://gantt.jaeungkim.com/docs/editing) | Move, resize, progress, permissions, drag bounds, and touch |
222
+ | [Creating tasks](https://gantt.jaeungkim.com/docs/task-creation) | The three ways a new task is proposed, and `onTaskCreate` |
223
+ | [Reordering rows](https://gantt.jaeungkim.com/docs/reordering) | Dragging a row to a new position or a new parent, and `onTaskMove` |
224
+ | [Dependencies](https://gantt.jaeungkim.com/docs/dependencies) | The four link types, and drawing arrows |
225
+ | [Working calendar](https://gantt.jaeungkim.com/docs/working-calendar) | Keeping a drop off weekends and holidays |
226
+ | [Detail panel](https://gantt.jaeungkim.com/docs/detail-panel) | The docked side panel: what opens it, editing in place, `renderDetail`, and controlling it |
227
+ | [Events](https://gantt.jaeungkim.com/docs/events) | Every callback a click, a drag and a keyboard edit fire |
228
+ | [Styling](https://gantt.jaeungkim.com/docs/styling) | Per-task color and class names |
229
+ | [Imperative API](https://gantt.jaeungkim.com/docs/imperative-api) | The `ref` handle: scrolling, zoom, the detail panel and task creation |
230
+ | [Keyboard and screen readers](https://gantt.jaeungkim.com/docs/accessibility) | The key map, the ARIA tree, and the gaps |
231
+ | [Locale and date formats](https://gantt.jaeungkim.com/docs/i18n) | `locale`, per-scale overrides, week start |
232
+ | [Theming](https://gantt.jaeungkim.com/docs/theming) | The theme prop and the CSS custom properties |
233
+ | [Headless core](https://gantt.jaeungkim.com/docs/headless-core) | Tree and calendar math without React or a DOM |
234
+
235
+ | Reference | Symbols |
236
+ |---|---|
237
+ | [GanttProps](https://gantt.jaeungkim.com/docs/ref/props) | `GanttProps` |
238
+ | [Task and task types](https://gantt.jaeungkim.com/docs/ref/task) | `Task`, `TaskDependency`, `DependencyType`, `TaskTransformed` |
239
+ | [GanttInteractionConfig](https://gantt.jaeungkim.com/docs/ref/interaction-config) | `GanttInteractionConfig` |
240
+ | [GanttRow](https://gantt.jaeungkim.com/docs/ref/rows) | `GanttRow` |
241
+ | [Detail renderer](https://gantt.jaeungkim.com/docs/ref/renderers) | `GanttDetailRenderer`, `GanttDetailRenderProps` |
242
+ | [GanttHandle](https://gantt.jaeungkim.com/docs/ref/handle) | `GanttHandle`, `GanttScrollApi`, `GanttDetailApi`, `GanttTaskCreateApi`, `GanttScrollOptions`, `GanttZoomAnchor` |
243
+ | [Scale and theme types](https://gantt.jaeungkim.com/docs/ref/scales) | `GanttScaleKey`, `GanttScaleFormat`, `GanttFormatOverrides`, `GanttTheme`, `Holiday` |
244
+ | [Tree helpers](https://gantt.jaeungkim.com/docs/ref/core-tree) | `buildTaskTree`, `collectSubtreeIds`, `rollUpTasks`, `moveTask`, `validateMove`, `sortTasksBySequence` |
245
+ | [Working calendar helpers](https://gantt.jaeungkim.com/docs/ref/core-calendar) | `createWorkingCalendar`, `CALENDAR_DAYS`, `WorkingCalendar` |
246
+
247
+ Full docs: **[English](https://gantt.jaeungkim.com/docs)** · **[한국어](https://gantt.jaeungkim.com/ko/docs)**
248
+
249
+ ## Contributing
250
+
251
+ Setup, the checks CI runs, and the branch and PR conventions are in
252
+ [CONTRIBUTING.md](CONTRIBUTING.md). Questions and ideas go in
253
+ [Discussions](https://github.com/jaeungkim/gantt-chart/discussions); issues are for bugs and
254
+ concrete feature requests.
255
+
256
+ ## License
257
+
258
+ [MIT](LICENSE)
@@ -0,0 +1,5 @@
1
+ import { GanttHandle } from './timeline/hooks/useGanttScrollApi';
2
+ import { GanttProps } from './props';
3
+ /** Gantt chart component. Creates a store per instance, so two charts on one page cannot share state. */
4
+ declare const Gantt: import('react').ForwardRefExoticComponent<GanttProps & import('react').RefAttributes<GanttHandle>>;
5
+ export default Gantt;
@@ -0,0 +1,20 @@
1
+ import { GanttDependencyChange } from '../../dependencies/hooks/useGanttLinkDrag';
2
+ import { GanttBarOptions } from '../../shared/types';
3
+ import { GanttInteractionConfig, TaskTransformed } from '../../shared/task';
4
+ import { WorkingCalendar } from '../../core';
5
+ interface GanttBarProps {
6
+ currentTask: TaskTransformed;
7
+ options: GanttBarOptions;
8
+ interaction?: GanttInteractionConfig;
9
+ /** Roving tabindex of the treegrid - exactly one cell carries 0, so Tab enters the grid once */
10
+ tabIndex: number;
11
+ /** `row:column` coordinate the chart's focus manager looks the cell up by */
12
+ cellCoord?: string;
13
+ /** Working-day calendar - drag results snap forward off non-working days */
14
+ calendar?: WorkingCalendar;
15
+ /** Scroll the timeline when the drag reaches a viewport edge; Gantt.tsx owns the default */
16
+ autoScrollOnDrag: boolean;
17
+ onDependencyCreate?: (change: GanttDependencyChange) => boolean | void;
18
+ }
19
+ export default function GanttBar({ currentTask, options, interaction, tabIndex, cellCoord, calendar, autoScrollOnDrag, onDependencyCreate, }: GanttBarProps): import("react").JSX.Element;
20
+ export {};
@@ -0,0 +1,24 @@
1
+ import { VirtualItem } from '../../shared/virtual/window';
2
+ import { GanttDependencyChange } from '../../dependencies/hooks/useGanttLinkDrag';
3
+ import { GanttBarOptions } from '../../shared/types';
4
+ import { WorkingCalendar } from '../../core';
5
+ import { GanttInteractionConfig } from '../../shared/task';
6
+ import { GanttFocus } from '../../interaction/utils/a11y';
7
+ import { GanttRow } from '../../rows/utils/rows';
8
+ interface GanttBarsLayerProps {
9
+ rows: GanttRow[];
10
+ virtualItems: VirtualItem[];
11
+ /** Cells before the bars on a row - the bar's column is this plus its lane */
12
+ gridColumnCount: number;
13
+ focus: GanttFocus;
14
+ /** Horizontal culling, shared with the header so the two cannot disagree */
15
+ isBarVisible: (barLeft: number, barWidth: number) => boolean;
16
+ options: GanttBarOptions;
17
+ interaction: GanttInteractionConfig;
18
+ /** Working-day calendar - drag results snap forward off non-working days */
19
+ calendar?: WorkingCalendar;
20
+ autoScrollOnDrag: boolean;
21
+ onDependencyCreate?: (change: GanttDependencyChange) => boolean | void;
22
+ }
23
+ export default function GanttBarsLayer({ rows, virtualItems, gridColumnCount, focus, isBarVisible, options, interaction, calendar, autoScrollOnDrag, onDependencyCreate, }: GanttBarsLayerProps): (import("react").JSX.Element | null)[];
24
+ export {};
@@ -0,0 +1 @@
1
+ export default function GanttDragGuides(): import("react").JSX.Element | null;
@@ -0,0 +1,16 @@
1
+ import { GanttDragMode } from '../../shared/types';
2
+ import { GanttInteractionConfig, Task, TaskTransformed } from '../../shared/task';
3
+ import { WorkingCalendar } from '../../core';
4
+ export type DragMode = GanttDragMode;
5
+ interface GanttBarDragOptions {
6
+ onTasksChange?: (updatedTasks: Task[]) => void;
7
+ /** Scroll the timeline when the drag reaches a viewport edge (default true) */
8
+ autoScroll?: boolean;
9
+ }
10
+ /** Gantt bar drag behavior; `autoScroll` (default true) scrolls the timeline at a viewport edge. */
11
+ export declare function useGanttBarDrag(task: TaskTransformed, options?: GanttBarDragOptions, interaction?: GanttInteractionConfig, calendar?: WorkingCalendar): {
12
+ onPointerDown: import('react').PointerEventHandler<HTMLDivElement>;
13
+ dragMode: GanttDragMode | null;
14
+ consumeDragClick: () => boolean;
15
+ };
16
+ export {};
@@ -0,0 +1,25 @@
1
+ import { Dayjs } from 'dayjs';
2
+ import { GanttBottomRowCell, GanttScaleKey } from '../../shared/types';
3
+ /** The task the user drew, handed to `onTaskCreate` - nothing is committed by the chart */
4
+ export interface GanttTaskDraft {
5
+ /** UTC ISO string, snapped to the current scale */
6
+ startDate: string;
7
+ endDate: string;
8
+ }
9
+ export declare function defaultTaskDraft(now: Dayjs, timelineTicks: GanttBottomRowCell[], scaleKey: GanttScaleKey): GanttTaskDraft | null;
10
+ interface DrawGhost {
11
+ leftPx: number;
12
+ widthPx: number;
13
+ topPx: number;
14
+ }
15
+ interface UseGanttDrawCreateParams {
16
+ enabled: boolean;
17
+ rowCount: number;
18
+ onTaskCreate?: (draft: GanttTaskDraft) => void;
19
+ }
20
+ export declare function drawSlotTopPx(offsetY: number, rowCount: number): number | null;
21
+ export declare function useGanttDrawCreate({ enabled, rowCount, onTaskCreate, }: UseGanttDrawCreateParams): {
22
+ onDrawPointerDown: (e: React.PointerEvent<HTMLDivElement>) => void;
23
+ ghost: DrawGhost | null;
24
+ };
25
+ export {};
@@ -0,0 +1,11 @@
1
+ import { default as React } from 'react';
2
+ import { Task, TaskTransformed } from '../../shared/task';
3
+ interface GanttProgressDragOptions {
4
+ onTasksChange?: (updatedTasks: Task[]) => void;
5
+ }
6
+ export declare function useGanttProgressDrag(task: TaskTransformed, barRef: React.RefObject<HTMLDivElement | null>, options?: GanttProgressDragOptions): {
7
+ onProgressPointerDown: React.PointerEventHandler<HTMLDivElement>;
8
+ progress: number | null;
9
+ isDraggingProgress: boolean;
10
+ };
11
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Dayjs } from 'dayjs';
2
+ /** The calendar every piece of date arithmetic in the core routes through. */
3
+ export interface WorkingCalendar {
4
+ /** False for the default calendar (every day counts) */
5
+ readonly skipsNonWorkingDays: boolean;
6
+ isWorkingDay(date: Dayjs): boolean;
7
+ /** Moves `days` days forward (or backward), skipping non-working days */
8
+ addDays(date: Dayjs, days: number): Dayjs;
9
+ /** Days from `from` to `to`, counted the same way `addDays` moves. Signed. */
10
+ daysBetween(from: Dayjs, to: Dayjs): number;
11
+ /** Smallest d where `addDays(from, d) >= target` - how far a task must move to clear a date */
12
+ daysUntil(from: Dayjs, target: Dayjs): number;
13
+ /** Largest d where `addDays(from, d) <= target` - how far a task may slip before it breaks one */
14
+ daysUpTo(from: Dayjs, target: Dayjs): number;
15
+ /** The date itself when it is a working day, otherwise the next one (time of day kept) */
16
+ snapForward(date: Dayjs): Dayjs;
17
+ }
18
+ export interface WorkingCalendarOptions {
19
+ /** Working weekdays as UTC day numbers, 0 = Sunday (default Mon-Fri) */
20
+ workingWeekdays?: number[];
21
+ /** Non-working dates as UTC `YYYY-MM-DD` strings */
22
+ holidays?: string[];
23
+ }
24
+ /** The default calendar: every day counts, so arithmetic through it is plain calendar arithmetic. */
25
+ export declare const CALENDAR_DAYS: WorkingCalendar;
26
+ /** A calendar that skips weekends and holidays, configured like the chart's non-working-day shading. */
27
+ export declare function createWorkingCalendar(options?: WorkingCalendarOptions): WorkingCalendar;
@@ -0,0 +1,16 @@
1
+ import { default as dayjs, Dayjs } from 'dayjs';
2
+ /**
3
+ * The chart's own dayjs - always parses and displays in UTC, so the same data lands in the
4
+ * same cells for every viewer and DST never changes a cell's width (#84, #28).
5
+ */
6
+ declare const ganttDayjs: typeof dayjs.utc;
7
+ export default ganttDayjs;
8
+ /** Calendar quarter of the date, 1-4 - inlined so dayjs' quarterOfYear plugin stays out of the bundle */
9
+ export declare function quarterOfYear(date: Dayjs): number;
10
+ /** First moment of the calendar quarter the date falls in */
11
+ export declare function startOfQuarter(date: Dayjs): Dayjs;
12
+ /**
13
+ * First moment of the week the date falls in; `firstDayOfWeek` is 0 = Sunday .. 6 = Saturday.
14
+ * Computed here because dayjs' `startOf('week')` is fixed to the loaded locale.
15
+ */
16
+ export declare function startOfWeek(date: Dayjs, firstDayOfWeek?: number): Dayjs;
@@ -0,0 +1,3 @@
1
+ export { CALENDAR_DAYS, createWorkingCalendar, type WorkingCalendar, type WorkingCalendarOptions, } from './calendar';
2
+ export { buildTaskTree, collectSubtreeIds, getVisibleTasks, rollUpTasks, type TaskTree, } from './tree';
3
+ export { moveTask, sortTasksBySequence, validateMove, type GanttMoveOptions, } from './reorder';
@@ -0,0 +1,55 @@
1
+ import { Task } from './types';
2
+ /** Where a task is going: a parent, and a slot among that parent's children */
3
+ export interface GanttTaskMove {
4
+ taskId: string;
5
+ /** New parent, null for the root level */
6
+ toParentId: string | null;
7
+ /** Slot among the new parent's children, counted in the list as it stands after the move */
8
+ toIndex: number;
9
+ }
10
+ /** The move that was applied - `toIndex` for an index-based API, `afterId`/`beforeId` for a position-based one */
11
+ export interface GanttTaskMoveChange extends GanttTaskMove {
12
+ fromParentId: string | null;
13
+ fromIndex: number;
14
+ /** Sibling the task now follows - null when it is the first child */
15
+ afterId: string | null;
16
+ /** Sibling the task now precedes - null when it is the last child */
17
+ beforeId: string | null;
18
+ }
19
+ /** Where a drop lands relative to the row under the pointer */
20
+ export type GanttDropMode = "before" | "after" | "child";
21
+ /** Why a move was refused - null from `validateMove` means it is allowed */
22
+ export type GanttMoveRejection = "unknown-task" | "unknown-parent" | "read-only" | "cycle" | "reparent-disabled" | "no-op";
23
+ export interface GanttMoveOptions {
24
+ /** Whether the parentId hierarchy is on - off, depth comes from `sequence` and a reparent is refused */
25
+ hierarchy: boolean;
26
+ /** Whether this task may be moved at all - left out, every task may */
27
+ canReorder?: (task: Task) => boolean;
28
+ }
29
+ /** The sibling lists a move is measured against - `toIndex` is counted against exactly these */
30
+ interface TaskOrder {
31
+ /** Normalized parent of each task - null for a root, an orphan or a cycle */
32
+ parentOf: ReadonlyMap<string, string | null>;
33
+ /** One parent's children in row order; pass null for the root list */
34
+ childrenOf: (parentId: string | null) => readonly string[];
35
+ }
36
+ /** Sort tasks by their sequence hierarchy - row order comes from this and nothing else */
37
+ export declare function sortTasksBySequence<T extends Pick<Task, "sequence">>(tasks: T[]): T[];
38
+ /** Reads the ordered forest the moves below are counted against */
39
+ export declare function buildTaskOrder(tasks: Task[], hierarchy: boolean): TaskOrder;
40
+ /**
41
+ * The move a drop on `targetId` would make: `before`/`after` make it a sibling, `child`
42
+ * appends it. Says nothing about whether the move is allowed - that is `validateMove`.
43
+ */
44
+ export declare function moveForDrop(order: TaskOrder, taskId: string, targetId: string, mode: GanttDropMode): GanttTaskMove;
45
+ /** Whether a move can be applied, and why not when it cannot - runs on every frame of a row drag */
46
+ export declare function validateMove(tasks: Task[], move: GanttTaskMove, options: GanttMoveOptions): GanttMoveRejection | null;
47
+ /**
48
+ * Applies a move, renumbering every sequence from the resulting row order; `parentId` is rewritten
49
+ * on the moved task only. Null when refused (`validateMove` says why); unchanged tasks keep identity.
50
+ */
51
+ export declare function moveTask(tasks: Task[], move: GanttTaskMove, options: GanttMoveOptions): {
52
+ tasks: Task[];
53
+ change: GanttTaskMoveChange;
54
+ } | null;
55
+ export {};