UNPKG

gantt-task-react-v

Version:

Interactive Gantt Chart for React with TypeScript.

593 lines (592 loc) 16.2 kB
import type { ComponentType, ReactNode } from "react"; import { GanttPartialTheme } from "./theme-types"; import { GanttLocale } from "./theme-locale"; import { ChildByLevelMap, DateSetup, Distances, RelationMoveTarget, RootMapByLevel, Task, TaskBarMoveAction, RenderTask, ViewMode, TaskId } from "./common-types"; export type RenderTopHeader = (date: Date, viewMode: ViewMode, dateSetup: DateSetup) => ReactNode; export type RenderCustomLabel = (task: RenderTask, x1: number, width: number, taskHeight: number, arrowIndent: number, taskYOffset: number, movingAction: TaskBarMoveAction | null, viewMode: ViewMode, rtl?: boolean) => ReactNode; export type RenderBottomHeader = (date: Date, viewMode: ViewMode, dateSetup: DateSetup, index: number, isUnknownDates: boolean) => ReactNode; export type OnArrowDoubleClick = (taskFrom: Task, taskFromIndex: number, taskTo: Task, taskToIndex: number) => void; export type OnRelationChange = ( /** * Task, from, index */ from: [Task, RelationMoveTarget, number], /** * Task, to, index */ to: [Task, RelationMoveTarget, number], /** * One of tasks is descendant of other task */ isOneDescendant: boolean) => void; export type OnDateChangeSuggestionType = [ /** * Start date */ Date, /** * End date */ Date, /** * Suggested task */ Task, /** * Index in array of tasks */ number ]; export type OnChangeTasksAction = { type: "add_tasks"; payload: { parent: RenderTask; descendants: readonly RenderTask[]; }; } | { type: "date_change"; payload: { taskId: string; taskIndex: number; start: Date; end: Date; }; } | { type: "delete_relation"; payload: { taskFrom: Task; taskFromIndex: number; taskTo: Task; taskToIndex: number; }; } | { type: "delete_task"; payload: { tasks: readonly RenderTask[]; taskIndexes: readonly number[]; }; } | { type: "edit_task"; } | { type: "move_task_before"; payload: { task: RenderTask; taskForMove: RenderTask; taskIndex: number; taskForMoveIndex: number; }; } | { type: "move_task_after"; payload: { task: RenderTask; taskForMove: RenderTask; taskIndex: number; taskForMoveIndex: number; }; } | { type: "move_task_inside"; payload: { parent: Task; childs: readonly RenderTask[]; dependentTasks: readonly Task[]; parentIndex: number; childIndexes: readonly number[]; }; } | { type: "progress_change"; payload: { task: Task; }; } | { type: "relation_change"; payload: { /** * Task, from, index */ from: [Task, RelationMoveTarget, number]; /** * Task, to, index */ to: [Task, RelationMoveTarget, number]; /** * One of tasks is descendant of other task */ isOneDescendant: boolean; }; } | { type: "expandState_change"; payload: { changedTask: Task; }; }; export type RelationKind = "startToStart" | "startToEnd" | "endToStart" | "endToEnd"; export type OnCommitTasksResult = boolean | undefined | void; export type OnCommitTasks = (nextTasks: readonly RenderTask[], action: OnChangeTasksAction) => Promise<OnCommitTasksResult> | OnCommitTasksResult; export interface GanttTaskListProps { enableTableListContextMenu?: number; contextMenuOptions?: ContextMenuOptionType[]; /** * Allow drag-n-drop of tasks in the table */ allowReorderTask?: AllowReorderTask; /** * Can resize columns */ canResizeColumns?: boolean; /** * Custom icons */ icons?: Partial<GanttRenderIconsProps>; /** * Show numbers of tasks next to tasks */ isShowTaskNumbers?: boolean; /** * Can reorder tasks */ canReorderTasks?: boolean; /** * Can reorder tasks */ onResizeColumn?: OnResizeColumn; /** * Render bottom table content */ tableBottom?: TableRenderBottomProps; } export interface TableRenderBottomProps { height?: number; renderContent?: () => ReactNode; } export interface GanttTaskBarProps extends GanttTaskBarActions { /** * Render function of bottom part of header above chart */ renderBottomHeader?: RenderBottomHeader; /** * Render function of top part of header above chart */ renderTopHeader?: RenderTopHeader; /** * Render custom label */ renderCustomLabel?: RenderCustomLabel; /** * Show critical path */ isShowCriticalPath?: boolean; isProgressChangeable?: (task: Task) => boolean; isRelationChangeable?: (task: Task) => boolean; isDateChangeable?: (task: Task) => boolean; isDeleteDependencyOnDoubleClick?: boolean; preStepsCount?: number; TooltipContent?: ComponentType<{ task: Task; }>; /** * Context menu options for right-click on the gantt chart area */ taskGanttContextMenuOption?: ContextMenuOptionType[]; /** * Invokes on double-click on the relation arrow between tasks */ onArrowDoubleClick?: OnArrowDoubleClick; /** * Invokes on bar double click. */ onDoubleClick?: (task: Task) => void; /** * Invokes on bar click. */ onClick?: (task: RenderTask) => void; } export interface GanttRenderIconsProps { renderAddIcon: () => ReactNode; renderDragIndicatorIcon: () => ReactNode; renderClosedIcon: () => ReactNode; renderDeleteIcon: () => ReactNode; renderEditIcon: () => ReactNode; renderOpenedIcon: () => ReactNode; renderNoChildrenIcon: () => ReactNode; } export type InsertTaskPosition = "before" | "inside" | "after"; export type AllowReorderTask = (task: RenderTask, method: InsertTaskPosition) => boolean; export type CheckIsHoliday = (date: Date, minTaskDate: Date, dateSetup: DateSetup) => boolean; export interface GanttProps { /** * Language */ language?: string; /** * Theme */ theme?: GanttPartialTheme; /** * Locale */ locale?: GanttLocale; /** * Check is current date holiday * @param date the date * @param minTaskDate lower date of all tasks * @param dateSetup * @returns */ checkIsHoliday?: CheckIsHoliday; /** * Can be used to compare multiple graphs. This prop is the number of graps being compared */ comparisonLevels?: number; /** * Get new id for task after using copy-paste */ getCopiedTaskId?: GetCopiedTaskId; /** * Tasks */ tasks: readonly RenderTask[]; /** * Columns of the table */ columns?: readonly Column[]; /** * Round end date of task after move or resize * @param date Date after move * @param viewMode current date unit * @returns next date */ roundEndDate?: (date: Date, viewMode: ViewMode) => Date; /** * Round start date of task after move or resize * @param date Date after move * @param viewMode current date unit * @returns next date */ roundStartDate?: (date: Date, viewMode: ViewMode) => Date; /** * View mode */ viewMode?: ViewMode; /** * View date */ viewDate?: Date; /** * Task bar options */ taskBar?: GanttTaskBarProps; /** * Task list options */ taskList?: GanttTaskListProps; /** * Authorized relations between tasks */ authorizedRelations?: RelationKind[]; /** * Time step value for date changes. */ timeStep?: number; /** * Invokes on every commit of the list of tasks */ onCommitTasks?: OnCommitTasks; /** * Callback for getting data of the added task */ onAddTaskAction?: (task: Task | null) => Promise<RenderTask | null>; /** * Callback for getting new data of the edited task */ onEditTaskAction?: (task: RenderTask) => Promise<RenderTask | null>; /** * Callback for select task */ onSelectTaskIds?: (taskIds: TaskId[]) => void; /** * Invokes on wheel event * @param wheelEvent */ onWheel?: (wheelEvent: WheelEvent) => void; /** * Invokes when user right-clicks a row in the task list. Receives the full `task` object of the clicked row. */ onRowContextMenu?: (task: RenderTask) => void; /** * Recount descedents of a group task when moving */ isMoveChildsWithParent?: boolean; /** * Recount parents of tasks in callback `onCommitTasks` */ isUpdateDisabledParentsOnChange?: boolean; /** * Display offsets from start on timeline instead of dates */ isUnknownDates?: boolean; /** * Move dates of tasks to working days during change */ isAdjustToWorkingDates?: boolean; /** * Force row height (in pixels) for each single row. If not provided theme distances.rowHeight is used. */ rowHeight?: number; /** * Show vertical line for current day on the chart */ showTodayLine?: boolean; /** * Show vertical line for a custom 'data date' on the chart */ showDataDateLine?: boolean; /** * Custom date to render as data date line when `showDataDateLine` is true */ dataDate?: Date | null; /** * Color used for the today line, pin and label. If not provided, theme calendarTodayColor is used. */ todayColor?: string; /** * Color used for the data date line, pin and label. If not provided, theme calendarTodayColor is used. */ dataDateColor?: string; /** * Label text for the today marker. Defaults to "Today". */ todayLabel?: string; /** * Label text for the data date marker. Defaults to "Data Date". */ dataDateLabel?: string; /** * Show/hide progress bar on task bars. Defaults to true. */ showProgress?: boolean; /** * Custom color for progress bars. If not provided, theme progress colors are used. */ progressColor?: string; } export interface GanttTaskBarActions { allowMoveTaskBar?: (action: TaskBarMoveAction, task: RenderTask) => boolean; } export type ColumnData = { dateSetup: DateSetup; depth: number; dependencies: Task[]; distances: Distances; handleAddTask: (task: Task) => void; handleDeleteTasks: (task: RenderTask[]) => void; handleEditTask: (task: RenderTask) => void; hasChildren: boolean; icons?: Partial<GanttRenderIconsProps>; indexStr: string; isClosed: boolean; isShowTaskNumbers: boolean; onExpanderClick: (task: Task) => void; task: RenderTask; }; export type ColumnProps = { data: ColumnData; }; export type Column = { id: string; component: ComponentType<ColumnProps>; width: number; title?: ReactNode; canResize?: boolean; }; export type OnResizeColumn = (nextColumns: readonly Column[], columnIndex: number, deltaWidth: number) => void; export type ChangeAction = { type: "add-childs"; parent: Task; addedIdsMap: Map<number, Set<string>>; addedChildsByLevelMap: ChildByLevelMap; addedRootsByLevelMap: RootMapByLevel; descendants: readonly RenderTask[]; } | { type: "change"; task: RenderTask; } | { type: "change_start_and_end"; task: Task; changedTask: Task; originalTask: Task; } | { type: "delete"; tasks: readonly RenderTask[]; deletedIdsMap: Map<number, Set<string>>; } | { type: "move-before"; target: RenderTask; taskForMove: RenderTask; } | { type: "move-after"; target: RenderTask; taskForMove: RenderTask; } | { type: "move-inside"; parent: Task; childs: readonly RenderTask[]; movedIdsMap: Map<number, Set<string>>; }; export type ChangeMetadata = [ /** * dependent tasks */ Task[], /** * indexes in list of tasks */ Array<{ task: RenderTask; index: number; }>, /** * array of parents of the task */ Task[], /** * array of suggesgions for change parent */ OnDateChangeSuggestionType[] ]; export type ContextMenuType = { task: RenderTask | null; x: number; y: number; }; export type ActionMetaType = { /** * Check is task id exists at current level (1 by default) */ checkTaskIdExists: CheckTaskIdExistsAtLevel; /** * Copy all selected tasks */ copySelectedTasks: () => void; /** * Copy single task * @param task the task */ copyTask: (task: RenderTask) => void; /** * Cut all selected tasks */ cutSelectedTasks: () => void; /** * Cut single task * @param task the task */ cutTask: (task: RenderTask) => void; /** * @returns List of parent tasks under copy action */ getCopyParentTasks: () => readonly RenderTask[]; /** * @returns List of tasks under copy action */ getCopyTasks: () => readonly RenderTask[]; /** * @returns List of tasks with all their descendants under copy action */ getCopyTasksWithDescendants: () => readonly RenderTask[]; /** * @returns List of parent tasks under cut action */ getCutParentTasks: () => readonly RenderTask[]; /** * @returns List of tasks under cut action */ getCutTasks: () => readonly RenderTask[]; /** * @returns List of parent tasks */ getParentTasks: () => readonly RenderTask[]; /** * @returns List of selected tasks */ getSelectedTasks: () => readonly RenderTask[]; /** * @returns List of tasks with all their descendants */ getTasksWithDescendants: () => readonly RenderTask[]; /** * Add childs to the container task * @param parent the container task * @param descendants list of added childs with their descendants */ handleAddChilds: (parent: Task, descendants: readonly RenderTask[]) => void; /** * Delete tasks * @param tasksForDelete list of tasks for delete */ handleDeleteTasks: (tasksForDelete: readonly RenderTask[]) => void; /** * Edit task */ handleEditTask: (task: RenderTask) => void; /** * Move tasks to the container task * @param parent the container task * @param childs list of moved tasks */ handleMoveTasksInside: (parent: Task, childs: readonly RenderTask[]) => void; /** * Make copies of the list of tasks */ makeCopies: (tasks: readonly RenderTask[]) => readonly RenderTask[]; /** * Reset selection */ resetSelectedTasks: () => void; /** * Task that triggered context menu */ task: RenderTask; }; export type CheckIsAvailableMetaType = { /** * * @returns Check are there tasks under the copy action */ checkHasCopyTasks: () => boolean; /** * * @returns Check are there tasks under the cut action */ checkHasCutTasks: () => boolean; /** * Context menu trigger task */ task: RenderTask; }; export type ContextMenuOptionType = { /** * Invokes on click on menu option * @param meta Metadata for the action */ action: (meta: ActionMetaType) => void; /** * Check is the current action available. Available by default * @param meta Metadata for checking */ checkIsAvailable?: (meta: CheckIsAvailableMetaType) => void; /** * Optional flag to render the option as disabled (not clickable) */ disabled?: boolean; label: ReactNode; icon?: ReactNode; /** Optional nested submenu options. If present this option will render a nested submenu when hovered. */ children?: ContextMenuOptionType[]; }; export type CheckTaskIdExistsAtLevel = (newId: string, comparisonLevel?: number) => boolean; export type GetCopiedTaskId = (task: RenderTask, checkExists: (newId: string) => boolean) => string; export type AdjustTaskToWorkingDatesParams = { action: TaskBarMoveAction; changedTask: Task; originalTask: Task; };