GanttInteractionConfig
The chart-wide interaction flags, the capability precedence order and the summary row mask
GanttInteractionConfig is the chart-wide half of the interaction settings: seven capability flags,
one readOnly, and two drag bounds. The type is exported from the package root. The chart takes the
ten fields as flat props and builds the object itself, so there is no interaction prop.
import type { GanttInteractionConfig } from '@jaeungkim/gantt-chart';GanttInteractionConfig
/** Chart-wide interaction settings - every gesture is allowed by default (task creation also needs `onTaskCreate`), and a task's own field of the same name wins. */
export interface GanttInteractionConfig {
readOnly?: boolean;
allowMove?: boolean;
allowResize?: boolean;
allowProgressChange?: boolean;
allowLinkCreate?: boolean;
allowLinkDelete?: boolean;
allowTaskCreate?: boolean;
/** Turns row reordering on - opt-in (default false). */
allowReorder?: boolean;
minDate?: string;
maxDate?: string;
}| Field | Type | Default | Description |
|---|---|---|---|
readOnly | boolean | undefined | Blocks every gesture on every task and renders the detail panel's built-in fields as plain text. A capability flag set at either level overrides it. The panel's Name reads only readOnly at either level, so it stays plain text regardless of the capability flags. |
allowMove | boolean | undefined | Dragging a bar along the timeline. |
allowResize | boolean | undefined | Dragging either edge of a bar. It also decides whether the detail panel's Start and End are editable date inputs. |
allowProgressChange | boolean | undefined | Dragging the progress handle. It also decides whether the detail panel's Progress is an editable number input. |
allowLinkCreate | boolean | undefined | Starting a dependency drag from a bar's handle. |
allowLinkDelete | boolean | undefined | Selecting and deleting a dependency arrow. |
allowTaskCreate | boolean | undefined | Sending a draft to onTaskCreate from the Add task button, addTask() or the drawn range. Chart-wide only. |
allowReorder | boolean | undefined | Dragging a task-list row to a new position or a new parent, and the keyboard bindings that do the same. |
minDate | string | undefined | Earliest date a bar can be dragged to, as a UTC ISO string. A date typed into the detail panel is clamped to it as well. |
maxDate | string | undefined | Latest date a bar can be dragged to, as a UTC ISO string. A date typed into the detail panel is clamped to it as well. |
With every field unset, every gesture is allowed and there are no drag bounds. Two fields differ.
allowTaskCreate also needs an onTaskCreate callback. See Task creation.
allowReorder is off until set. See canReorder.
The ten props of the same names on GanttProps feed this object. See GanttProps. The
per-task fields that override it are listed in Task and task types.
Capability resolution
An internal function, resolveTaskInteraction, resolves each of the six per-task capabilities. It
is not exported from the package root. The order is documented here because it decides what the
chart does.
// Precedence: `task.allowX` > `task.readOnly` > `config.allowX` > `config.readOnly` > allowed.
// Summary rows are never resizable and have no draggable progress - both roll up from children.
// Reordering is the exception: its floor is `false`, so only an explicit flag turns it on.
export function resolveTaskInteraction(
task: Pick<
Task,
| 'readOnly'
| 'allowMove'
| 'allowResize'
| 'allowProgressChange'
| 'allowLinkCreate'
| 'allowLinkDelete'
| 'allowReorder'
| 'minDate'
| 'maxDate'
> & { isSummary?: boolean },
config: GanttInteractionConfig = NO_INTERACTION_CONFIG
): ResolvedTaskInteraction {
const resolve = (
taskFlag: boolean | undefined,
configFlag: boolean | undefined
): boolean => {
if (taskFlag !== undefined) return taskFlag;
if (task.readOnly !== undefined) return !task.readOnly;
if (configFlag !== undefined) return configFlag;
return !config.readOnly;
};
const canReorder =
task.allowReorder ??
(task.readOnly === true ? false : (config.allowReorder ?? false));
const derived = task.isSummary === true;
return {
canMove: resolve(task.allowMove, config.allowMove),
canResize:
!derived &&
resolve(task.allowResize, config.allowResize),
canChangeProgress:
!derived &&
resolve(task.allowProgressChange, config.allowProgressChange),
canCreateLink: resolve(task.allowLinkCreate, config.allowLinkCreate),
canDeleteLink: resolve(task.allowLinkDelete, config.allowLinkDelete),
canReorder,
minDate: task.minDate ?? config.minDate,
maxDate: task.maxDate ?? config.maxDate,
};
}Five of the six capabilities follow the order below. canReorder follows a shorter order,
described under canReorder.
The order, most specific first:
- If
task.allowXis set, it is the result. - If
task.readOnlyis set, the result is its negation. - If
config.allowXis set, it is the result. - Otherwise the result is the negation of
config.readOnly. Unset reads asfalse, so an untouched chart allows the gesture.
In the table, unset means the field is undefined.
task.allowX | task.readOnly | config.allowX | config.readOnly | Result | Decided by |
|---|---|---|---|---|---|
true | any | any | any | allowed | 1 |
false | any | any | any | blocked | 1 |
| unset | true | any | any | blocked | 2 |
| unset | false | any | any | allowed | 2 |
| unset | unset | true | any | allowed | 3 |
| unset | unset | false | any | blocked | 3 |
| unset | unset | unset | true | blocked | 4 |
| unset | unset | unset | false | allowed | 4 |
| unset | unset | unset | unset | allowed | 4 |
A chart-level readOnly with allowProgressChange: true on one task resolves at level 1 for
that task and at level 4 for everything else. See Editing tasks.
The six capabilities
Five capabilities read one pair of fields through the order above. The structural mask in the last
column is then &&-ed in front of the result. canReorder reads its pair through the shorter
order in the next section.
| Resolved capability | Task field | GanttInteractionConfig field | Structural mask |
|---|---|---|---|
canMove | allowMove | allowMove | none |
canResize | allowResize | allowResize | !isSummary |
canChangeProgress | allowProgressChange | allowProgressChange | !isSummary |
canCreateLink | allowLinkCreate | allowLinkCreate | none |
canDeleteLink | allowLinkDelete | allowLinkDelete | none |
canReorder | allowReorder | allowReorder | none |
The resolver returns them as a ResolvedTaskInteraction. This type is not exported from the package
root either. Its field names appear in the source and in the table above.
interface ResolvedTaskInteraction {
canMove: boolean;
canResize: boolean;
canChangeProgress: boolean;
canCreateLink: boolean;
canDeleteLink: boolean;
canReorder: boolean;
minDate?: string;
maxDate?: string;
}canReorder
Reordering is opt-in, so its order ends at false instead of !config.readOnly.
const canReorder =
task.allowReorder ??
(task.readOnly === true ? false : (config.allowReorder ?? false));config.readOnly is never read. A read-only chart and an untouched chart both block reordering.
Only an explicit allowReorder at either level turns it on. The two upper levels are unchanged. A
task's own flag wins, and a task with its own readOnly is not reorderable through the chart-wide
flag.
task.allowReorder | task.readOnly | config.allowReorder | Result |
|---|---|---|---|
true | any | any | allowed |
false | any | any | blocked |
| unset | true | any | blocked |
| unset | false or unset | true | allowed |
| unset | false or unset | false | blocked |
| unset | false or unset | unset | blocked |
Drag bounds
minDate and maxDate do not use the order. Each is resolved by one nullish coalescing step.
minDate: task.minDate ?? config.minDate,
maxDate: task.maxDate ?? config.maxDate,A task's own bound replaces the chart's. readOnly and the capability flags do not affect either
bound. Editing tasks covers what the bounds clamp during a drag.
Task creation
Task creation is chart-wide only, so it has its own two-level resolver. It is internal and not exported.
// Chart-wide only - no entry point starts on a task, so there is no per-task rung
export function canCreateTasks(
config: GanttInteractionConfig = NO_INTERACTION_CONFIG
): boolean {
return config.allowTaskCreate ?? !config.readOnly;
}config.allowTaskCreate | config.readOnly | Result |
|---|---|---|
true | any | allowed |
false | any | blocked |
| unset | true | blocked |
| unset | false | allowed |
| unset | unset | allowed |
Task has no allowTaskCreate field, so there is no per-task level. The chart also requires the
callback.
const canCreateTask = onTaskCreate !== undefined && canCreateTasks(interaction);This one value gates all three entry points. Without it the Add task button is not rendered,
addTask() returns early, and the drawing gesture is off. Without onTaskCreate there is no way
to create a task, regardless of the flags. See Creating tasks.
Constraints
A summary row cannot be resized and has no draggable progress. The rule is applied to the
resolver's output with &&, so no flag at any level re-enables it.
canResize and canChangeProgress are both false when isSummary is true, even when the task
sets allowResize: true and allowProgressChange: true. canMove is unaffected. Moving a summary
is allowed and moves its whole subtree.
Both values are derived. rollUpTasks recomputes a summary's start and end from its children on
every render, and its progress as well unless the summary carries an explicit one. An edit here
would be discarded on the next render or would freeze a derived value.
isSummary is set only when the hierarchy prop is on, so the rule does not apply to a flat chart.
readOnly still blocks every gesture on a summary row.
Notes
The package root exports GanttInteractionConfig as a type only.
resolveTaskInteraction, canCreateTasks, ResolvedTaskInteraction and NO_INTERACTION_CONFIG
are not exported. They are named on this page only to describe the chart's behaviour. Do not import
them.
The gestures these flags govern are described in Editing tasks and Dependencies. The panel fields they gate are described in Detail panel.