gantt-task-react-v 1.5.27 → 1.6.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 CHANGED
@@ -1,133 +1,689 @@
1
- # kvandake-gantt-task-react
1
+ # gantt-task-react-v
2
2
 
3
- ## Interactive Gantt Chart for React with TypeScript.
3
+ Interactive Gantt Chart for React with TypeScript.
4
4
 
5
- ## Recent Updates
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install gantt-task-react-v
9
+ ```
6
10
 
7
- - Flexible Gantt height now adapts to its parent container, now we always see the horizontal scrolls for both task list and gantt.
8
- - Fixed sticky gantt header on drag
9
- - Fixed Tooltip should show only on gantt section current view boundaries
10
- - Added Tooltip for comparison bars
11
- - Show Custom Data Date Line
12
- - Customize Data Date Line and Today Line Color and Label
13
- - Show/Hide Task Table Column
14
- - Improved staggered and rounded arrows
15
- - RightClick ContextMenu option for Tasklist and Gantt
16
- - Custom Drawer on click taskbar and arrow, callback to get taskdata
11
+ ## Quick Start
17
12
 
18
- ## [Live Demo In Storybook](https://661071b076b50cb537c16c19-yrsukdfefs.chromatic.com/)
13
+ ```tsx
14
+ import { Gantt, Task, ViewMode } from "gantt-task-react-v";
15
+ import "gantt-task-react-v/dist/style.css";
19
16
 
20
- ## Install
17
+ const tasks: Task[] = [
18
+ {
19
+ id: "task-1",
20
+ type: "task",
21
+ name: "Design",
22
+ start: new Date(2026, 0, 1),
23
+ end: new Date(2026, 0, 10),
24
+ progress: 60,
25
+ assignees: ["Alice"],
26
+ },
27
+ {
28
+ id: "task-2",
29
+ type: "task",
30
+ name: "Development",
31
+ start: new Date(2026, 0, 11),
32
+ end: new Date(2026, 1, 15),
33
+ progress: 20,
34
+ dependencies: [
35
+ {
36
+ sourceId: "task-1",
37
+ sourceTarget: "endOfTask",
38
+ ownTarget: "startOfTask",
39
+ },
40
+ ],
41
+ assignees: ["Bob", "Carol"],
42
+ },
43
+ {
44
+ id: "milestone-1",
45
+ type: "milestone",
46
+ name: "MVP Release",
47
+ start: new Date(2026, 1, 15),
48
+ end: new Date(2026, 1, 15),
49
+ progress: 0,
50
+ dependencies: [
51
+ {
52
+ sourceId: "task-2",
53
+ sourceTarget: "endOfTask",
54
+ ownTarget: "startOfTask",
55
+ },
56
+ ],
57
+ },
58
+ ];
21
59
 
60
+ function App() {
61
+ return <Gantt tasks={tasks} viewMode={ViewMode.Day} />;
62
+ }
22
63
  ```
23
- npm install gantt-task-react-v
64
+
65
+ ## Core Features
66
+
67
+ ### 1. Task List (WBS)
68
+
69
+ Hierarchical work breakdown structure with expand/collapse, nested numbering, drag-and-drop reordering, and resizable columns.
70
+
71
+ ```tsx
72
+ <Gantt
73
+ tasks={tasks}
74
+ taskList={{
75
+ isShowTaskNumbers: true,
76
+ canReorderTasks: true,
77
+ canResizeColumns: true,
78
+ canToggleColumns: true,
79
+ }}
80
+ />
81
+ ```
82
+
83
+ ### 2. Timeline
84
+
85
+ Horizontal time scale supporting multiple view modes.
86
+
87
+ ```tsx
88
+ <Gantt tasks={tasks} viewMode={ViewMode.Week} viewDate={new Date()} />
24
89
  ```
25
90
 
26
- ## How to use it
91
+ **ViewMode values:** `Hour`, `QuarterDay`, `HalfDay`, `Day`, `Week`, `Month`, `Year`
92
+
93
+ ### 3. Task Bars
27
94
 
28
- ```ts
29
- import { Gantt, Task, EventOption, StylingOption, ViewMode, DisplayOption } from 'gantt-task-react';
30
- import "gantt-task-react/dist/index.css";
95
+ Bars represent duration and are drag-resizable. Hold **Ctrl** to show start/end drag handles.
31
96
 
32
- let tasks: Task[] = [
33
- {
34
- start: new Date(2020, 1, 1),
35
- end: new Date(2020, 1, 2),
36
- name: 'Idea',
37
- id: 'Task 0',
38
- type:'task',
39
- progress: 45,
40
- isDisabled: true,
41
- styles: { progressColor: '#ffbb54', progressSelectedColor: '#ff9e0d' },
97
+ Progress is displayed as a filled overlay with a percentage label on the bar. The progress drag handle allows interactive editing.
98
+
99
+ ```tsx
100
+ <Gantt
101
+ tasks={tasks}
102
+ showProgress={true}
103
+ progressColor="#4dabf7"
104
+ taskBar={{
105
+ isProgressChangeable: task => !task.isDisabled,
106
+ isDateChangeable: task => !task.isDisabled,
107
+ allowMoveTaskBar: (action, task) => true,
108
+ }}
109
+ />
110
+ ```
111
+
112
+ ### 4. Dependencies (Arrows)
113
+
114
+ Arrows link tasks to define execution order. Supports four relation kinds.
115
+
116
+ ```tsx
117
+ <Gantt
118
+ tasks={tasks}
119
+ authorizedRelations={["endToStart", "startToStart", "endToEnd", "startToEnd"]}
120
+ taskBar={{
121
+ isRelationChangeable: task => true,
122
+ isDeleteDependencyOnDoubleClick: true,
123
+ onArrowDoubleClick: (taskFrom, taskTo, event) => {
124
+ /* handle */
42
125
  },
43
- ...
126
+ onArrowClick: (taskFrom, taskTo) => {
127
+ /* handle */
128
+ },
129
+ }}
130
+ />
131
+ ```
132
+
133
+ **RelationKind values:** `"startToStart"`, `"startToEnd"`, `"endToStart"`, `"endToEnd"`
134
+
135
+ ### 5. Milestones
136
+
137
+ Rendered as diamonds. Set `type: "milestone"` on a task.
138
+
139
+ ```tsx
140
+ const milestone: Task = {
141
+ id: "m1",
142
+ type: "milestone",
143
+ name: "Go-Live",
144
+ start: new Date(2026, 3, 1),
145
+ end: new Date(2026, 3, 1),
146
+ progress: 0,
147
+ };
148
+ ```
149
+
150
+ ### 6. Progress Tracking
151
+
152
+ Progress is shown as a filled bar overlay with a percentage label. Tasks have a `progress` field (0–100). The progress drag handle is enabled when `isProgressChangeable` returns true.
153
+
154
+ ```tsx
155
+ <Gantt
156
+ tasks={tasks}
157
+ showProgress={true}
158
+ taskBar={{ isProgressChangeable: task => !task.isDisabled }}
159
+ />
160
+ ```
161
+
162
+ ### 7. Resource Allocation (Assignees)
163
+
164
+ Tasks support an `assignees` field. Use the built-in `AssigneesColumn` via the columns builder.
165
+
166
+ ```tsx
167
+ import { Gantt, useTaskListColumnsBuilder } from "gantt-task-react-v";
168
+
169
+ function App() {
170
+ const {
171
+ createNameColumn,
172
+ createStartDateColumn,
173
+ createEndDateColumn,
174
+ createAssigneesColumn,
175
+ } = useTaskListColumnsBuilder();
176
+
177
+ const columns = [
178
+ createNameColumn("Name", 200),
179
+ createStartDateColumn("Start", 100),
180
+ createEndDateColumn("End", 100),
181
+ createAssigneesColumn("Assignees", 150),
182
+ ];
183
+
184
+ return <Gantt tasks={tasks} columns={columns} />;
185
+ }
186
+ ```
187
+
188
+ ### 8. Critical Path
189
+
190
+ Highlight the longest chain of dependent tasks that determines project duration.
191
+
192
+ ```tsx
193
+ <Gantt tasks={tasks} taskBar={{ isShowCriticalPath: true }} />
194
+ ```
195
+
196
+ ### 9. Today Line & Data Date Line
197
+
198
+ Vertical markers for the current date and a custom data date.
199
+
200
+ ```tsx
201
+ <Gantt
202
+ tasks={tasks}
203
+ showTodayLine={true}
204
+ todayColor="#ff6b6b"
205
+ todayLabel="Today"
206
+ showDataDateLine={true}
207
+ dataDate={new Date(2026, 2, 15)}
208
+ dataDateColor="#4dabf7"
209
+ dataDateLabel="Data Date"
210
+ />
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Drawer Panel
216
+
217
+ A slide-in panel for viewing task/arrow details with built-in "Go to" navigation.
218
+
219
+ ```tsx
220
+ <Gantt
221
+ tasks={tasks}
222
+ drawer={{
223
+ enableDrawer: true,
224
+ drawerWidth: 400,
225
+ renderDrawerContent: (data, goToTask) => {
226
+ if (data.type === "task") {
227
+ return (
228
+ <div>
229
+ <h3>{data.task.name}</h3>
230
+ <p>Progress: {data.task.progress}%</p>
231
+ {data.task.dependencies?.map(dep => (
232
+ <button key={dep.sourceId} onClick={() => goToTask(dep.sourceId)}>
233
+ Go to {dep.sourceId}
234
+ </button>
235
+ ))}
236
+ </div>
237
+ );
238
+ }
239
+ if (data.type === "arrow") {
240
+ return (
241
+ <div>
242
+ <button onClick={() => goToTask(data.taskFrom.id)}>
243
+ Go to {data.taskFrom.name}
244
+ </button>
245
+ <button onClick={() => goToTask(data.taskTo.id)}>
246
+ Go to {data.taskTo.name}
247
+ </button>
248
+ </div>
249
+ );
250
+ }
251
+ return null;
252
+ },
253
+ }}
254
+ />
255
+ ```
256
+
257
+ The `goToTask(taskId)` function scrolls both horizontally and vertically to center the target task and selects it. Built-in "Go to" buttons also appear automatically in the drawer header for arrow-type panels and task-type panels.
258
+
259
+ ## Scroll To Task
260
+
261
+ Programmatically scroll to and select any task by id.
262
+
263
+ ```tsx
264
+ const [targetId, setTargetId] = useState<string | undefined>();
265
+
266
+ <Gantt tasks={tasks} scrollToTaskId={targetId} />
267
+ <button onClick={() => setTargetId("task-2")}>Go to Task 2</button>
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Task List Callbacks
273
+
274
+ Row click and double-click callbacks are inside the `taskList` prop.
275
+
276
+ ```tsx
277
+ <Gantt
278
+ tasks={tasks}
279
+ taskList={{
280
+ onClickTaskRow: task => console.log("Clicked:", task.id),
281
+ onDoubleClickTaskRow: task => console.log("Double-clicked:", task.id),
282
+ }}
283
+ />
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Custom Columns
289
+
290
+ Build columns with the hook or provide fully custom ones.
291
+
292
+ ```tsx
293
+ import {
294
+ Gantt,
295
+ useTaskListColumnsBuilder,
296
+ Column,
297
+ ColumnProps,
298
+ } from "gantt-task-react-v";
299
+
300
+ // Custom column component
301
+ const ProgressColumn: React.FC<ColumnProps> = ({ data: { task } }) => {
302
+ if (task.type === "empty") return null;
303
+ return <>{task.progress}%</>;
304
+ };
305
+
306
+ function App() {
307
+ const { createNameColumn, createDeleteActionColumn, createEditActionColumn } =
308
+ useTaskListColumnsBuilder();
309
+
310
+ const columns: Column[] = [
311
+ createNameColumn("Task", 200),
312
+ { id: "progress", component: ProgressColumn, width: 80, title: "Progress" },
313
+ createEditActionColumn(40),
314
+ createDeleteActionColumn(40),
315
+ ];
316
+
317
+ return <Gantt tasks={tasks} columns={columns} />;
318
+ }
319
+ ```
320
+
321
+ ### Column Pinning
322
+
323
+ Pin columns so they stay visible while scrolling.
324
+
325
+ ```tsx
326
+ const columns: Column[] = [
327
+ { ...createNameColumn("Task", 200), pinned: "left" },
328
+ createStartDateColumn("Start", 100),
329
+ createEndDateColumn("End", 100),
330
+ { ...createDeleteActionColumn(40), pinned: "right" },
44
331
  ];
45
- <Gantt tasks={tasks} />
46
332
  ```
47
333
 
48
- You may handle actions
334
+ ### Column Visibility
49
335
 
50
- ```ts
336
+ Columns can be hidden and toggled by the user.
337
+
338
+ ```tsx
51
339
  <Gantt
52
340
  tasks={tasks}
53
- viewMode={view}
54
- onDateChange={onTaskChange}
55
- onTaskDelete={onTaskDelete}
56
- onProgressChange={onProgressChange}
57
- onDoubleClick={onDblClick}
58
- onClick={onClick}
341
+ columns={[
342
+ createNameColumn("Task", 200),
343
+ { ...createStartDateColumn("Start"), hidden: true },
344
+ ]}
345
+ taskList={{
346
+ canToggleColumns: true,
347
+ onColumnVisibilityChange: columns => console.log(columns),
348
+ }}
59
349
  />
60
350
  ```
61
351
 
62
- ## How to run example
352
+ ### Built-in Columns Builder Methods
353
+
354
+ | Method | Description |
355
+ | ----------------------------------------- | ------------------------------ |
356
+ | `createNameColumn(title, width?)` | Task name with expand/collapse |
357
+ | `createStartDateColumn(title, width?)` | Start date |
358
+ | `createEndDateColumn(title, width?)` | End date |
359
+ | `createDependenciesColumn(title, width?)` | Dependency names |
360
+ | `createAssigneesColumn(title, width?)` | Assignees list |
361
+ | `createEditActionColumn(width?)` | Edit button |
362
+ | `createDeleteActionColumn(width?)` | Delete button |
363
+ | `createAddActionColumn(width?)` | Add task button |
364
+
365
+ ---
366
+
367
+ ## Context Menu
368
+
369
+ Right-click context menus for the task list and chart area.
63
370
 
64
- ```shell
65
- yarn storebook
371
+ ```tsx
372
+ import {
373
+ Gantt,
374
+ createCopyOption,
375
+ createCutOption,
376
+ createPasteOption,
377
+ createDeleteOption,
378
+ createEditOption,
379
+ } from "gantt-task-react-v";
380
+
381
+ <Gantt
382
+ tasks={tasks}
383
+ taskList={{
384
+ enableTableListContextMenu: 1, // right-click trigger
385
+ contextMenuOptions: [
386
+ createEditOption(),
387
+ createCopyOption(),
388
+ createCutOption(),
389
+ createPasteOption(),
390
+ createDeleteOption(),
391
+ ],
392
+ }}
393
+ onRowContextMenu={task => console.log("Right-clicked:", task.id)}
394
+ />;
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Theming
400
+
401
+ Customize colors, typography, shapes, distances, and date formats.
402
+
403
+ ```tsx
404
+ <Gantt
405
+ tasks={tasks}
406
+ theme={{
407
+ rtl: false,
408
+ colors: {
409
+ barProgressColor: "#4dabf7",
410
+ barBackgroundColor: "#e3f2fd",
411
+ barBackgroundSelectedColor: "#bbdefb",
412
+ milestoneBackgroundColor: "#7c4dff",
413
+ arrowColor: "#90a4ae",
414
+ calendarTodayColor: "#ff6b6b",
415
+ tableSelectedTaskBackgroundColor: "#e3f2fd",
416
+ },
417
+ typography: {
418
+ fontFamily: "'Inter', sans-serif",
419
+ fontSize: "13px",
420
+ },
421
+ shape: {
422
+ borderRadius: "4px",
423
+ },
424
+ distances: {
425
+ rowHeight: 40,
426
+ },
427
+ dateFormats: {
428
+ dateColumnFormat: "dd/MM/yyyy",
429
+ },
430
+ }}
431
+ />
66
432
  ```
67
433
 
68
- ## Gantt Configuration
434
+ ### Color Reference
435
+
436
+ | Group | Keys |
437
+ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
438
+ | **Bar** | `barProgressColor`, `barProgressCriticalColor`, `barProgressSelectedColor`, `barProgressSelectedCriticalColor`, `barBackgroundColor`, `barBackgroundCriticalColor`, `barBackgroundSelectedColor`, `barBackgroundSelectedCriticalColor`, `barHandleColor` |
439
+ | **Group** | `groupProgressColor`, `groupProgressCriticalColor`, `groupProgressSelectedColor`, `groupProgressSelectedCriticalColor`, `groupBackgroundColor`, `groupBackgroundCriticalColor`, `groupBackgroundSelectedColor`, `groupBackgroundSelectedCriticalColor` |
440
+ | **Project** | `projectProgressColor`, `projectProgressCriticalColor`, `projectProgressSelectedColor`, `projectProgressSelectedCriticalColor`, `projectBackgroundColor`, `projectBackgroundCriticalColor`, `projectBackgroundSelectedColor`, `projectBackgroundSelectedCriticalColor` |
441
+ | **Milestone** | `milestoneBackgroundColor`, `milestoneBackgroundCriticalColor`, `milestoneBackgroundSelectedColor`, `milestoneBackgroundSelectedCriticalColor` |
442
+ | **Comparison** | `barComparisonDefaultColor`, `barComparisonPlanColor`, `barComparisonWarningColor`, `barComparisonCriticalColor` |
443
+ | **Arrow** | `arrowColor`, `arrowCriticalColor`, `arrowRelationColor`, `arrowHoverColor` |
444
+ | **Calendar** | `calendarHolidayColor`, `calendarTodayColor`, `calendarStrokeColor` |
445
+ | **Table** | `tableDragTaskBackgroundColor`, `tableSelectedTaskBackgroundColor`, `tableActionColor`, `tableDragIndicatorColor`, `tableHoverActionColor`, `tableEvenBackgroundColor` |
446
+ | **UI** | `backgroundColor`, `dividerColor`, `hoverFilter`, `loadingPrimaryColor`, `loadingSecondaryColor`, `contextMenuBoxShadow`, `contextMenuBgColor`, `contextMenuTextColor`, `tooltipBoxShadow`, `scrollbarThumbColor`, `primaryTextColor`, `secondaryTextColor` |
447
+
448
+ ---
449
+
450
+ ## Locale
451
+
452
+ ```tsx
453
+ import { Gantt, GanttLocale } from "gantt-task-react-v";
454
+ import { enUS } from "date-fns/locale";
455
+
456
+ const locale: GanttLocale = {
457
+ dateLocale: enUS,
458
+ suffix: { days: "days" },
459
+ tooltip: { duration: "Duration", progress: "Progress" },
460
+ table: {
461
+ columns: {
462
+ name: "Task",
463
+ startDate: "Start",
464
+ endDate: "End",
465
+ dependencies: "Dependencies",
466
+ progress: "Progress",
467
+ },
468
+ },
469
+ context: {
470
+ edit: "Edit",
471
+ copy: "Copy",
472
+ cut: "Cut",
473
+ paste: "Paste",
474
+ delete: "Delete",
475
+ },
476
+ };
477
+
478
+ <Gantt tasks={tasks} locale={locale} />;
479
+ ```
480
+
481
+ ---
482
+
483
+ ## Task Lifecycle Callbacks
484
+
485
+ ```tsx
486
+ <Gantt
487
+ tasks={tasks}
488
+ onCommitTasks={async (nextTasks, action) => {
489
+ // Persist changes — return { tasks } to confirm or throw to revert
490
+ await saveTasks(nextTasks);
491
+ return {};
492
+ }}
493
+ onAddTaskAction={async parentTask => {
494
+ // Return new task data or null to cancel
495
+ return {
496
+ id: "new-1",
497
+ type: "task",
498
+ name: "New",
499
+ start: new Date(),
500
+ end: new Date(),
501
+ progress: 0,
502
+ };
503
+ }}
504
+ onEditTaskAction={async task => {
505
+ // Return edited task or null to cancel
506
+ return { ...task, name: "Edited" };
507
+ }}
508
+ onSelectTaskIds={ids => console.log("Selected:", ids)}
509
+ />
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Comparison Mode
515
+
516
+ Overlay plan vs actual dates by providing `comparisonDates` on tasks.
517
+
518
+ ```tsx
519
+ const tasks: Task[] = [
520
+ {
521
+ id: "1",
522
+ type: "task",
523
+ name: "Feature A",
524
+ start: new Date(2026, 0, 5), // actual
525
+ end: new Date(2026, 0, 20),
526
+ progress: 50,
527
+ comparisonDates: {
528
+ start: new Date(2026, 0, 1), // planned
529
+ end: new Date(2026, 0, 15),
530
+ },
531
+ },
532
+ ];
533
+
534
+ <Gantt tasks={tasks} comparisonLevels={2} />;
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Full API Reference
69
540
 
70
541
  ### GanttProps
71
542
 
72
- | Parameter Name | Type | Description |
73
- | :------------------------------ | :------------ | :------------------------------------------------- |
74
- | tasks\* | [Task](#Task) | Tasks array. |
75
- | [EventOption](#EventOption) | interface | Specifies gantt events. |
76
- | [DisplayOption](#DisplayOption) | interface | Specifies view type and display timeline language. |
77
- | [StylingOption](#StylingOption) | interface | Specifies chart and global tasks styles |
78
-
79
- ### EventOption
80
-
81
- | Parameter Name | Type | Description |
82
- | :----------------- | :---------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- |
83
- | onSelect | (task: Task, isSelected: boolean) => void | Specifies the function to be executed on the taskbar select or unselect event. |
84
- | onDoubleClick | (task: Task) => void | Specifies the function to be executed on the taskbar onDoubleClick event. |
85
- | onClick | (task: Task) => void | Specifies the function to be executed on the taskbar onClick event. |
86
- | onDelete\* | (task: Task) => void/boolean/Promise<void>/Promise<boolean> | Specifies the function to be executed on the taskbar on Delete button press event. |
87
- | onDateChange\* | (task: Task, children: Task[]) => void/boolean/Promise<void>/Promise<boolean> | Specifies the function to be executed when drag taskbar event on timeline has finished. |
88
- | onProgressChange\* | (task: Task, children: Task[]) => void/boolean/Promise<void>/Promise<boolean> | Specifies the function to be executed when drag taskbar progress event has finished. |
89
- | onExpanderClick\* | onExpanderClick: (task: Task) => void; | Specifies the function to be executed on the table expander click |
90
- | onWheel\* | onWheel: (wheelEvent: WheelEvent) => void; | Specifies the function to be executed when the mouse wheel is used |
91
- | timeStep | number | A time step value for onDateChange. Specify in milliseconds. |
92
-
93
- \* Chart undoes operation if method return false or error. Parameter children returns one level deep records.
94
-
95
- ### DisplayOption
96
-
97
- | Parameter Name | Type | Description |
98
- | :------------------ | :------ | :---------------------------------------------------------------------------------------------------------- |
99
- | viewMode | enum | Specifies the time scale. Hour, Quarter Day, Half Day, Day, Week(ISO-8601, 1st day is Monday), Month, Year. |
100
- | viewDate | date | Specifies display date and time for display. |
101
- | preStepsCount | number | Specifies empty space before the fist task |
102
- | locale | string | Specifies the month name language. Able formats: ISO 639-2, Java Locale. |
103
- | monthCalendarFormat | string | Specifies the month display on calendar |
104
- | monthTaskListFormat | string | Specifies the month display on list. |
105
- | rtl | boolean | Sets rtl mode. |
106
-
107
- ### StylingOption
108
-
109
- | Parameter Name | Type | Description |
110
- | :------------------------- | :----- | :------------------------------------------------------------------------------------------------ |
111
- | headerHeight | number | Specifies the header height. |
112
- | ganttHeight | number | Specifies the gantt chart height without header. If not set or 0, adapts to its parent container. |
113
- | columnWidth | number | Specifies the time period width. |
114
- | listCellWidth | string | Specifies the task list cell width. Empty string is mean "no display". |
115
- | rowHeight | number | Specifies the task row height. |
116
- | barCornerRadius | number | Specifies the taskbar corner rounding. |
117
- | barFill | number | Specifies the taskbar occupation. Sets in percent from 0 to 100. |
118
- | handleWidth | number | Specifies width the taskbar drag event control for start and end dates. |
119
- | fontFamily | string | Specifies the application font. |
120
- | fontSize | string | Specifies the application font size. |
121
- | barProgressColor | string | Specifies the taskbar progress fill color globally. |
122
- | barProgressSelectedColor | string | Specifies the taskbar progress fill color globally on select. |
123
- | barBackgroundColor | string | Specifies the taskbar background fill color globally. |
124
- | barBackgroundSelectedColor | string | Specifies the taskbar background fill color globally on select. |
125
- | arrowColor | string | Specifies the relationship arrow fill color. |
126
- | arrowIndent | number | Specifies the relationship arrow right indent. Sets in px |
127
- | todayColor | string | Specifies the current period column fill color. |
128
- | TooltipContent | | Specifies the Tooltip view for selected taskbar. |
129
- | TaskListHeader | | Specifies the task list Header view |
130
- | TaskListTable | | Specifies the task list Table view |
543
+ | Prop | Type | Default | Description |
544
+ | --------------------------------- | --------------------------------------- | ------------- | ------------------------------- |
545
+ | `tasks` | `RenderTask[]` | **required** | Array of tasks to display |
546
+ | `viewMode` | `ViewMode` | `Day` | Time scale |
547
+ | `viewDate` | `Date` | | Scroll to this date on mount |
548
+ | `columns` | `Column[]` | | Custom table columns |
549
+ | `language` | `string` | — | Language code |
550
+ | `locale` | `GanttLocale` | English | Localization strings |
551
+ | `theme` | `GanttPartialTheme` | — | Theme overrides |
552
+ | `taskBar` | `GanttTaskBarProps` | | Chart bar options |
553
+ | `taskList` | `GanttTaskListProps` | | Task list options |
554
+ | `drawer` | `GanttDrawerProps` | | Drawer panel options |
555
+ | `authorizedRelations` | `RelationKind[]` | all four | Allowed dependency types |
556
+ | `timeStep` | `number` | `300000` | Snap interval in ms |
557
+ | `comparisonLevels` | `number` | `1` | Number of comparison levels |
558
+ | `rowHeight` | `number` | theme default | Row height in pixels |
559
+ | `showTodayLine` | `boolean` | `true` | Show today marker |
560
+ | `showDataDateLine` | `boolean` | `false` | Show data-date marker |
561
+ | `dataDate` | `Date \| null` | `null` | Data date value |
562
+ | `todayColor` | `string` | theme default | Today line color |
563
+ | `dataDateColor` | `string` | theme default | Data date line color |
564
+ | `todayLabel` | `string` | `"Today"` | Today marker label |
565
+ | `dataDateLabel` | `string` | `"Data Date"` | Data date marker label |
566
+ | `showProgress` | `boolean` | `true` | Show progress fill on bars |
567
+ | `progressColor` | `string` | theme default | Custom progress color |
568
+ | `scrollToTaskId` | `TaskId` | | Scroll to and select this task |
569
+ | `isMoveChildsWithParent` | `boolean` | `true` | Move children when parent moves |
570
+ | `isUpdateDisabledParentsOnChange` | `boolean` | `true` | Recompute parents on commit |
571
+ | `isUnknownDates` | `boolean` | `false` | Show offsets instead of dates |
572
+ | `isAdjustToWorkingDates` | `boolean` | `true` | Snap to working days |
573
+ | `checkIsHoliday` | `CheckIsHoliday` | — | Holiday check function |
574
+ | `getCopiedTaskId` | `GetCopiedTaskId` | | ID generator for paste |
575
+ | `roundStartDate` | `(date, viewMode) => Date` | | Round start after drag |
576
+ | `roundEndDate` | `(date, viewMode) => Date` | — | Round end after drag |
577
+ | `onCommitTasks` | `OnCommitTasks` | — | Task change callback |
578
+ | `onAddTaskAction` | `(task) => Promise<RenderTask \| null>` | — | Add task handler |
579
+ | `onEditTaskAction` | `(task) => Promise<RenderTask \| null>` | — | Edit task handler |
580
+ | `onSelectTaskIds` | `(ids: TaskId[]) => void` | | Selection change |
581
+ | `onWheel` | `(event: WheelEvent) => void` | — | Wheel event |
582
+ | `onRowContextMenu` | `(task: RenderTask) => void` | — | Row right-click |
583
+
584
+ ### Task
585
+
586
+ | Field | Type | Description |
587
+ | ----------------- | ------------------------------------ | ----------------------------- |
588
+ | `id` | `string` | Unique identifier |
589
+ | `type` | `"task" \| "milestone" \| "project"` | Task type |
590
+ | `name` | `string` | Display name |
591
+ | `start` | `Date` | Start date |
592
+ | `end` | `Date` | End date |
593
+ | `progress` | `number` | Completion percentage (0–100) |
594
+ | `assignees` | `string[]` | Assigned resources |
595
+ | `parent` | `string` | Parent task id for hierarchy |
596
+ | `dependencies` | `Dependency[]` | Task dependencies |
597
+ | `comparisonDates` | `{ start, end }` | Plan dates for comparison |
598
+ | `hideChildren` | `boolean` | Collapse children |
599
+ | `isDisabled` | `boolean` | Disable interactions |
600
+ | `displayOrder` | `number` | Sort order |
601
+ | `comparisonLevel` | `number` | Comparison level index |
602
+ | `style` | `CSSProperties` | Custom bar styles |
603
+ | `payload` | `Record<string, string>` | Custom data |
604
+
605
+ ### GanttTaskListProps
606
+
607
+ | Prop | Type | Default | Description |
608
+ | ---------------------------- | -------------------------------- | ------------ | ----------------------------- |
609
+ | `isShowTaskNumbers` | `boolean` | `true` | Show row numbers |
610
+ | `canReorderTasks` | `boolean` | `true` | Enable drag reorder |
611
+ | `canResizeColumns` | `boolean` | `true` | Enable column resize |
612
+ | `canToggleColumns` | `boolean` | `false` | Show column visibility toggle |
613
+ | `allowReorderTask` | `AllowReorderTask` | `() => true` | Per-task reorder guard |
614
+ | `enableTableListContextMenu` | `number` | `1` | Context menu trigger |
615
+ | `contextMenuOptions` | `ContextMenuOptionType[]` | — | Menu options |
616
+ | `icons` | `Partial<GanttRenderIconsProps>` | — | Custom icons |
617
+ | `onResizeColumn` | `OnResizeColumn` | — | Column resize callback |
618
+ | `onColumnVisibilityChange` | `OnColumnVisibilityChange` | — | Visibility change callback |
619
+ | `tableBottom` | `TableRenderBottomProps` | — | Footer render |
620
+ | `onClickTaskRow` | `(task: RenderTask) => void` | — | Row click |
621
+ | `onDoubleClickTaskRow` | `(task: RenderTask) => void` | — | Row double-click |
622
+
623
+ ### GanttTaskBarProps
624
+
625
+ | Prop | Type | Default | Description |
626
+ | --------------------------------- | ---------------------------- | ------------------ | ------------------------------- |
627
+ | `isShowCriticalPath` | `boolean` | `false` | Show critical path |
628
+ | `isProgressChangeable` | `(task) => boolean` | `!task.isDisabled` | Allow progress drag |
629
+ | `isDateChangeable` | `(task) => boolean` | `!task.isDisabled` | Allow date drag |
630
+ | `isRelationChangeable` | `(task) => boolean` | — | Allow relation draw |
631
+ | `isDeleteDependencyOnDoubleClick` | `boolean` | `true` | Delete deps on dblclick |
632
+ | `preStepsCount` | `number` | `1` | Empty columns before first task |
633
+ | `allowMoveTaskBar` | `(action, task) => boolean` | — | Per-action move guard |
634
+ | `renderBottomHeader` | `RenderBottomHeader` | — | Custom bottom header |
635
+ | `renderTopHeader` | `RenderTopHeader` | — | Custom top header |
636
+ | `renderCustomLabel` | `RenderCustomLabel` | — | Custom bar label |
637
+ | `TooltipContent` | `ComponentType<{ task }>` | built-in | Custom tooltip |
638
+ | `taskGanttContextMenuOption` | `ContextMenuOptionType[]` | — | Chart context menu |
639
+ | `onClick` | `(task: RenderTask) => void` | — | Bar click |
640
+ | `onDoubleClick` | `(task: Task) => void` | — | Bar double-click |
641
+ | `onArrowClick` | `(from, to) => void` | — | Arrow click |
642
+ | `onArrowDoubleClick` | `OnArrowDoubleClick` | — | Arrow double-click |
643
+
644
+ ### GanttDrawerProps
645
+
646
+ | Prop | Type | Default | Description |
647
+ | --------------------- | --------------------- | ------- | ----------------------- |
648
+ | `enableDrawer` | `boolean` | `false` | Enable drawer panel |
649
+ | `drawerWidth` | `number` | `360` | Panel width in px |
650
+ | `renderDrawerContent` | `RenderDrawerContent` | — | Custom content renderer |
651
+
652
+ `RenderDrawerContent = (data: GanttDrawerData, goToTask: (taskId: string) => void) => ReactNode`
653
+
654
+ ### Column
655
+
656
+ | Field | Type | Description |
657
+ | ----------- | ---------------------------- | ------------------ |
658
+ | `id` | `string` | Unique column id |
659
+ | `component` | `ComponentType<ColumnProps>` | Render component |
660
+ | `width` | `number` | Column width in px |
661
+ | `title` | `ReactNode` | Header text |
662
+ | `canResize` | `boolean` | Allow resize |
663
+ | `pinned` | `"left" \| "right"` | Sticky pinning |
664
+ | `hidden` | `boolean` | Hide column |
665
+
666
+ ---
667
+
668
+ ## Running Storybook
669
+
670
+ ```bash
671
+ npm run storybook
672
+ ```
673
+
674
+ ## License
675
+
676
+ MIT
677
+ | barProgressColor | string | Specifies the taskbar progress fill color globally. |
678
+ | barProgressSelectedColor | string | Specifies the taskbar progress fill color globally on select. |
679
+ | barBackgroundColor | string | Specifies the taskbar background fill color globally. |
680
+ | barBackgroundSelectedColor | string | Specifies the taskbar background fill color globally on select. |
681
+ | arrowColor | string | Specifies the relationship arrow fill color. |
682
+ | arrowIndent | number | Specifies the relationship arrow right indent. Sets in px |
683
+ | todayColor | string | Specifies the current period column fill color. |
684
+ | TooltipContent | | Specifies the Tooltip view for selected taskbar. |
685
+ | TaskListHeader | | Specifies the task list Header view |
686
+ | TaskListTable | | Specifies the task list Table view |
131
687
 
132
688
  - TooltipContent: [`React.FC<{ task: Task; fontSize: string; fontFamily: string; }>;`](https://github.com/MaTeMaTuK/gantt-task-react/blob/main/src/components/other/tooltip.tsx#L56)
133
689
  - TaskListHeader: `React.FC<{ headerHeight: number; rowWidth: string; fontFamily: string; fontSize: string;}>;`
@@ -8,6 +8,7 @@ type BarDisplayProps = {
8
8
  height: number;
9
9
  progressWidth: number;
10
10
  progressX: number;
11
+ progress: number;
11
12
  startMoveFullTask: (clientX: number) => void;
12
13
  taskId: TaskId;
13
14
  width: number;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import { ColumnProps } from "../../../types";
3
+ export declare const AssigneesColumn: React.FC<ColumnProps>;
@@ -42,4 +42,10 @@ export declare function useTaskListColumnsBuilder(): {
42
42
  width: number;
43
43
  canResize: boolean;
44
44
  };
45
+ createAssigneesColumn: (title: React.ReactNode | null, width?: number) => {
46
+ id: string;
47
+ component: React.FC<import("../../..").ColumnProps>;
48
+ width: number;
49
+ title: React.ReactNode;
50
+ };
45
51
  };
@@ -5017,6 +5017,16 @@ const AddColumn = ({
5017
5017
  }
5018
5018
  );
5019
5019
  };
5020
+ const AssigneesColumn = ({ data: { task } }) => {
5021
+ if (task.type === "empty") {
5022
+ return null;
5023
+ }
5024
+ const assignees = task.assignees;
5025
+ if (!assignees || assignees.length === 0) {
5026
+ return null;
5027
+ }
5028
+ return /* @__PURE__ */ jsx(Fragment, { children: assignees.join(", ") });
5029
+ };
5020
5030
  function useTaskListColumnsBuilder() {
5021
5031
  const createNameColumn = useCallback(
5022
5032
  (title2, width) => {
@@ -5086,6 +5096,17 @@ function useTaskListColumnsBuilder() {
5086
5096
  canResize: false
5087
5097
  };
5088
5098
  }, []);
5099
+ const createAssigneesColumn = useCallback(
5100
+ (title2, width) => {
5101
+ return {
5102
+ id: "AssigneesColumn",
5103
+ component: AssigneesColumn,
5104
+ width: width || 120,
5105
+ title: title2
5106
+ };
5107
+ },
5108
+ []
5109
+ );
5089
5110
  return {
5090
5111
  createNameColumn,
5091
5112
  createStartDateColumn,
@@ -5093,7 +5114,8 @@ function useTaskListColumnsBuilder() {
5093
5114
  createDependenciesColumn,
5094
5115
  createDeleteActionColumn,
5095
5116
  createEditActionColumn,
5096
- createAddActionColumn
5117
+ createAddActionColumn,
5118
+ createAssigneesColumn
5097
5119
  };
5098
5120
  }
5099
5121
  const DEFAULT_THEME = {
@@ -12176,6 +12198,17 @@ const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
12176
12198
  }
12177
12199
  return [progressWidth, progressX];
12178
12200
  };
12201
+ const getProgressPoint = (progressX, taskY, taskHeight) => {
12202
+ const point = [
12203
+ progressX - 5,
12204
+ taskY + taskHeight,
12205
+ progressX + 5,
12206
+ taskY + taskHeight,
12207
+ progressX,
12208
+ taskY + taskHeight - 8.66
12209
+ ];
12210
+ return point.join(",");
12211
+ };
12179
12212
  const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
12180
12213
  const safeX = isNaN(x) || !isFinite(x) ? 0 : x;
12181
12214
  const safeTaskX = isNaN(taskX) || !isFinite(taskX) ? 0 : taskX;
@@ -12355,6 +12388,7 @@ const BarDisplay = ({
12355
12388
  height,
12356
12389
  progressWidth,
12357
12390
  progressX,
12391
+ progress,
12358
12392
  startMoveFullTask,
12359
12393
  width,
12360
12394
  x,
@@ -12455,6 +12489,24 @@ const BarDisplay = ({
12455
12489
  rx: barCornerRadius,
12456
12490
  fill: processColor
12457
12491
  }
12492
+ ),
12493
+ showProgress && width > 40 && /* @__PURE__ */ jsxs(
12494
+ "text",
12495
+ {
12496
+ x: x + width / 2,
12497
+ y: y + height / 2,
12498
+ dominantBaseline: "central",
12499
+ textAnchor: "middle",
12500
+ fill: "#fff",
12501
+ fontSize: 11,
12502
+ fontWeight: 600,
12503
+ pointerEvents: "none",
12504
+ style: { userSelect: "none" },
12505
+ children: [
12506
+ Math.round(progress),
12507
+ "%"
12508
+ ]
12509
+ }
12458
12510
  )
12459
12511
  ]
12460
12512
  }
@@ -12495,6 +12547,31 @@ const BarDateHandle = ({
12495
12547
  }
12496
12548
  );
12497
12549
  };
12550
+ const BarProgressHandle = ({
12551
+ taskId,
12552
+ progressPoint,
12553
+ startMoveProgress,
12554
+ className
12555
+ }) => {
12556
+ return /* @__PURE__ */ jsx(
12557
+ "polygon",
12558
+ {
12559
+ "data-testid": `bar-progress-handle-${taskId}`,
12560
+ className,
12561
+ points: progressPoint,
12562
+ onMouseDown: (e) => {
12563
+ e.stopPropagation();
12564
+ startMoveProgress(e.clientX);
12565
+ },
12566
+ onTouchStart: (e) => {
12567
+ const firstTouch = e.touches[0];
12568
+ if (firstTouch) {
12569
+ startMoveProgress(firstTouch.clientX);
12570
+ }
12571
+ }
12572
+ }
12573
+ );
12574
+ };
12498
12575
  const projectWrapper = "_projectWrapper_1maxt_1";
12499
12576
  const projectBackground = "_projectBackground_1maxt_11";
12500
12577
  const projectTop = "_projectTop_1maxt_21";
@@ -12706,7 +12783,7 @@ const Bar = (props) => {
12706
12783
  showProgress = true,
12707
12784
  progressColor
12708
12785
  } = props;
12709
- useMemo(() => width < 30, [width]);
12786
+ const isSmallWidth = useMemo(() => width < 30, [width]);
12710
12787
  const handleHeight = useMemo(() => taskHeight - 2, [taskHeight]);
12711
12788
  const rootRef = useRef();
12712
12789
  const [ctrlPressed, setCtrlPressed] = useState(true);
@@ -12740,12 +12817,17 @@ const Bar = (props) => {
12740
12817
  },
12741
12818
  [onTaskEventStart]
12742
12819
  );
12743
- useCallback(
12820
+ const startMoveProgress = useCallback(
12744
12821
  (clientX) => {
12745
12822
  onTaskEventStart("progress", clientX);
12746
12823
  },
12747
12824
  [onTaskEventStart]
12748
12825
  );
12826
+ const progressPoint = getProgressPoint(
12827
+ +!rtl * progressWidth + progressX,
12828
+ taskYOffset,
12829
+ taskHeight
12830
+ );
12749
12831
  const renderBarDisplay = () => {
12750
12832
  if (task.type === "project") {
12751
12833
  return /* @__PURE__ */ jsx(
@@ -12782,6 +12864,7 @@ const Bar = (props) => {
12782
12864
  height: taskHeight,
12783
12865
  progressX,
12784
12866
  progressWidth,
12867
+ progress: task.progress,
12785
12868
  barCornerRadius,
12786
12869
  isSelected,
12787
12870
  isCritical,
@@ -12845,7 +12928,15 @@ const Bar = (props) => {
12845
12928
  }
12846
12929
  ),
12847
12930
  relationHandles,
12848
- false
12931
+ isProgressChangeable(task) && /* @__PURE__ */ jsx(
12932
+ BarProgressHandle,
12933
+ {
12934
+ className: `${styles$9.barHandle} ${isMovingProgress ? styles$9.barHandleImportantVisible : ""} ${isSmallWidth || isMovingDate || isRelationDrawMode ? styles$9.barHandleImportantHidden : ""}`,
12935
+ taskId: task.id,
12936
+ progressPoint,
12937
+ startMoveProgress
12938
+ }
12939
+ )
12849
12940
  ] });
12850
12941
  };
12851
12942
  const milestoneWrapper = "_milestoneWrapper_vcirf_1";
@@ -20818,11 +20909,11 @@ const Gantt = (props) => {
20818
20909
  if (enableDrawer) {
20819
20910
  setActiveArrowKey(null);
20820
20911
  setActiveTaskId(task.id);
20912
+ selectTask(task.id);
20821
20913
  if ((drawerData == null ? void 0 : drawerData.type) === "task") {
20822
20914
  setDrawerData({ type: "task", task });
20823
20915
  }
20824
20916
  }
20825
- selectTask(task.id);
20826
20917
  if (taskBar.onClick) {
20827
20918
  taskBar.onClick(task);
20828
20919
  }
@@ -21137,6 +21228,16 @@ const Gantt = (props) => {
21137
21228
  language
21138
21229
  ]
21139
21230
  );
21231
+ const drawerAwareSelectOnMouseDown = useCallback(
21232
+ (taskId, event) => {
21233
+ if (enableDrawer && drawerData) {
21234
+ selectTask(taskId);
21235
+ return;
21236
+ }
21237
+ selectTaskOnMouseDown(taskId, event);
21238
+ },
21239
+ [enableDrawer, drawerData, selectTask, selectTaskOnMouseDown]
21240
+ );
21140
21241
  const renderTaskBarProps = useMemo(
21141
21242
  () => ({
21142
21243
  ...taskBar,
@@ -21173,7 +21274,7 @@ const Gantt = (props) => {
21173
21274
  activeTaskId,
21174
21275
  renderedRowIndexes,
21175
21276
  rtl,
21176
- selectTaskOnMouseDown,
21277
+ selectTaskOnMouseDown: drawerAwareSelectOnMouseDown,
21177
21278
  selectedIdsMirror,
21178
21279
  startColumnIndex,
21179
21280
  taskHalfHeight,
@@ -21215,7 +21316,7 @@ const Gantt = (props) => {
21215
21316
  handleTaskClick,
21216
21317
  renderedRowIndexes,
21217
21318
  rtl,
21218
- selectTaskOnMouseDown,
21319
+ drawerAwareSelectOnMouseDown,
21219
21320
  selectedIdsMirror,
21220
21321
  startColumnIndex,
21221
21322
  taskHalfHeight,
@@ -5034,6 +5034,16 @@
5034
5034
  }
5035
5035
  );
5036
5036
  };
5037
+ const AssigneesColumn = ({ data: { task } }) => {
5038
+ if (task.type === "empty") {
5039
+ return null;
5040
+ }
5041
+ const assignees = task.assignees;
5042
+ if (!assignees || assignees.length === 0) {
5043
+ return null;
5044
+ }
5045
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: assignees.join(", ") });
5046
+ };
5037
5047
  function useTaskListColumnsBuilder() {
5038
5048
  const createNameColumn = React.useCallback(
5039
5049
  (title2, width) => {
@@ -5103,6 +5113,17 @@
5103
5113
  canResize: false
5104
5114
  };
5105
5115
  }, []);
5116
+ const createAssigneesColumn = React.useCallback(
5117
+ (title2, width) => {
5118
+ return {
5119
+ id: "AssigneesColumn",
5120
+ component: AssigneesColumn,
5121
+ width: width || 120,
5122
+ title: title2
5123
+ };
5124
+ },
5125
+ []
5126
+ );
5106
5127
  return {
5107
5128
  createNameColumn,
5108
5129
  createStartDateColumn,
@@ -5110,7 +5131,8 @@
5110
5131
  createDependenciesColumn,
5111
5132
  createDeleteActionColumn,
5112
5133
  createEditActionColumn,
5113
- createAddActionColumn
5134
+ createAddActionColumn,
5135
+ createAssigneesColumn
5114
5136
  };
5115
5137
  }
5116
5138
  const DEFAULT_THEME = {
@@ -12193,6 +12215,17 @@
12193
12215
  }
12194
12216
  return [progressWidth, progressX];
12195
12217
  };
12218
+ const getProgressPoint = (progressX, taskY, taskHeight) => {
12219
+ const point = [
12220
+ progressX - 5,
12221
+ taskY + taskHeight,
12222
+ progressX + 5,
12223
+ taskY + taskHeight,
12224
+ progressX,
12225
+ taskY + taskHeight - 8.66
12226
+ ];
12227
+ return point.join(",");
12228
+ };
12196
12229
  const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
12197
12230
  const safeX = isNaN(x) || !isFinite(x) ? 0 : x;
12198
12231
  const safeTaskX = isNaN(taskX) || !isFinite(taskX) ? 0 : taskX;
@@ -12372,6 +12405,7 @@
12372
12405
  height,
12373
12406
  progressWidth,
12374
12407
  progressX,
12408
+ progress,
12375
12409
  startMoveFullTask,
12376
12410
  width,
12377
12411
  x,
@@ -12472,6 +12506,24 @@
12472
12506
  rx: barCornerRadius,
12473
12507
  fill: processColor
12474
12508
  }
12509
+ ),
12510
+ showProgress && width > 40 && /* @__PURE__ */ jsxRuntime.jsxs(
12511
+ "text",
12512
+ {
12513
+ x: x + width / 2,
12514
+ y: y + height / 2,
12515
+ dominantBaseline: "central",
12516
+ textAnchor: "middle",
12517
+ fill: "#fff",
12518
+ fontSize: 11,
12519
+ fontWeight: 600,
12520
+ pointerEvents: "none",
12521
+ style: { userSelect: "none" },
12522
+ children: [
12523
+ Math.round(progress),
12524
+ "%"
12525
+ ]
12526
+ }
12475
12527
  )
12476
12528
  ]
12477
12529
  }
@@ -12512,6 +12564,31 @@
12512
12564
  }
12513
12565
  );
12514
12566
  };
12567
+ const BarProgressHandle = ({
12568
+ taskId,
12569
+ progressPoint,
12570
+ startMoveProgress,
12571
+ className
12572
+ }) => {
12573
+ return /* @__PURE__ */ jsxRuntime.jsx(
12574
+ "polygon",
12575
+ {
12576
+ "data-testid": `bar-progress-handle-${taskId}`,
12577
+ className,
12578
+ points: progressPoint,
12579
+ onMouseDown: (e) => {
12580
+ e.stopPropagation();
12581
+ startMoveProgress(e.clientX);
12582
+ },
12583
+ onTouchStart: (e) => {
12584
+ const firstTouch = e.touches[0];
12585
+ if (firstTouch) {
12586
+ startMoveProgress(firstTouch.clientX);
12587
+ }
12588
+ }
12589
+ }
12590
+ );
12591
+ };
12515
12592
  const projectWrapper = "_projectWrapper_1maxt_1";
12516
12593
  const projectBackground = "_projectBackground_1maxt_11";
12517
12594
  const projectTop = "_projectTop_1maxt_21";
@@ -12723,7 +12800,7 @@
12723
12800
  showProgress = true,
12724
12801
  progressColor
12725
12802
  } = props;
12726
- React.useMemo(() => width < 30, [width]);
12803
+ const isSmallWidth = React.useMemo(() => width < 30, [width]);
12727
12804
  const handleHeight = React.useMemo(() => taskHeight - 2, [taskHeight]);
12728
12805
  const rootRef = React.useRef();
12729
12806
  const [ctrlPressed, setCtrlPressed] = React.useState(true);
@@ -12757,12 +12834,17 @@
12757
12834
  },
12758
12835
  [onTaskEventStart]
12759
12836
  );
12760
- React.useCallback(
12837
+ const startMoveProgress = React.useCallback(
12761
12838
  (clientX) => {
12762
12839
  onTaskEventStart("progress", clientX);
12763
12840
  },
12764
12841
  [onTaskEventStart]
12765
12842
  );
12843
+ const progressPoint = getProgressPoint(
12844
+ +!rtl * progressWidth + progressX,
12845
+ taskYOffset,
12846
+ taskHeight
12847
+ );
12766
12848
  const renderBarDisplay = () => {
12767
12849
  if (task.type === "project") {
12768
12850
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -12799,6 +12881,7 @@
12799
12881
  height: taskHeight,
12800
12882
  progressX,
12801
12883
  progressWidth,
12884
+ progress: task.progress,
12802
12885
  barCornerRadius,
12803
12886
  isSelected,
12804
12887
  isCritical,
@@ -12862,7 +12945,15 @@
12862
12945
  }
12863
12946
  ),
12864
12947
  relationHandles,
12865
- false
12948
+ isProgressChangeable(task) && /* @__PURE__ */ jsxRuntime.jsx(
12949
+ BarProgressHandle,
12950
+ {
12951
+ className: `${styles$9.barHandle} ${isMovingProgress ? styles$9.barHandleImportantVisible : ""} ${isSmallWidth || isMovingDate || isRelationDrawMode ? styles$9.barHandleImportantHidden : ""}`,
12952
+ taskId: task.id,
12953
+ progressPoint,
12954
+ startMoveProgress
12955
+ }
12956
+ )
12866
12957
  ] });
12867
12958
  };
12868
12959
  const milestoneWrapper = "_milestoneWrapper_vcirf_1";
@@ -20835,11 +20926,11 @@
20835
20926
  if (enableDrawer) {
20836
20927
  setActiveArrowKey(null);
20837
20928
  setActiveTaskId(task.id);
20929
+ selectTask(task.id);
20838
20930
  if ((drawerData == null ? void 0 : drawerData.type) === "task") {
20839
20931
  setDrawerData({ type: "task", task });
20840
20932
  }
20841
20933
  }
20842
- selectTask(task.id);
20843
20934
  if (taskBar.onClick) {
20844
20935
  taskBar.onClick(task);
20845
20936
  }
@@ -21154,6 +21245,16 @@
21154
21245
  language
21155
21246
  ]
21156
21247
  );
21248
+ const drawerAwareSelectOnMouseDown = React.useCallback(
21249
+ (taskId, event) => {
21250
+ if (enableDrawer && drawerData) {
21251
+ selectTask(taskId);
21252
+ return;
21253
+ }
21254
+ selectTaskOnMouseDown(taskId, event);
21255
+ },
21256
+ [enableDrawer, drawerData, selectTask, selectTaskOnMouseDown]
21257
+ );
21157
21258
  const renderTaskBarProps = React.useMemo(
21158
21259
  () => ({
21159
21260
  ...taskBar,
@@ -21190,7 +21291,7 @@
21190
21291
  activeTaskId,
21191
21292
  renderedRowIndexes,
21192
21293
  rtl,
21193
- selectTaskOnMouseDown,
21294
+ selectTaskOnMouseDown: drawerAwareSelectOnMouseDown,
21194
21295
  selectedIdsMirror,
21195
21296
  startColumnIndex,
21196
21297
  taskHalfHeight,
@@ -21232,7 +21333,7 @@
21232
21333
  handleTaskClick,
21233
21334
  renderedRowIndexes,
21234
21335
  rtl,
21235
- selectTaskOnMouseDown,
21336
+ drawerAwareSelectOnMouseDown,
21236
21337
  selectedIdsMirror,
21237
21338
  startColumnIndex,
21238
21339
  taskHalfHeight,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.5.27",
3
+ "version": "1.6.0",
4
4
  "description": "Interactive Gantt Chart for React with TypeScript.",
5
5
  "author": "aguilanbon",
6
6
  "homepage": "https://github.com/aguilanbon/gantt-task-react-v",