gantt-task-react-v 1.1.1 → 1.1.3

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.
@@ -17,5 +17,6 @@ export interface TaskGanttProps extends GanttTaskBarActions {
17
17
  verticalScrollbarRef: RefObject<HTMLDivElement>;
18
18
  onVerticalScrollbarScrollX: (event: SyntheticEvent<HTMLDivElement>) => void;
19
19
  verticalGanttContainerRef: RefObject<HTMLDivElement>;
20
+ onOpenGanttContextMenu?: (clientX: number, clientY: number) => void;
20
21
  }
21
22
  export declare const TaskGantt: React.NamedExoticComponent<TaskGanttProps>;
@@ -8,7 +8,6 @@ export type GanttTodayProps = {
8
8
  startDate: Date;
9
9
  rtl: boolean;
10
10
  viewMode: ViewMode;
11
- taskHeight: number;
12
11
  showTodayLine?: boolean;
13
12
  showDataDateLine?: boolean;
14
13
  dataDate?: Date | null;
@@ -10907,204 +10907,6 @@ const styles$c = {
10907
10907
  ganttToday,
10908
10908
  ganttTodayCircle
10909
10909
  };
10910
- const getDateByOffset = (startDate, offset2, viewMode) => {
10911
- switch (viewMode) {
10912
- case ViewMode.Day:
10913
- return addDays(startDate, offset2);
10914
- case ViewMode.HalfDay:
10915
- return addHours(startDate, offset2 * 12);
10916
- case ViewMode.QuarterDay:
10917
- return addHours(startDate, offset2 * 6);
10918
- case ViewMode.Hour:
10919
- return addHours(startDate, offset2);
10920
- case ViewMode.Month:
10921
- return addMonths(startDate, offset2);
10922
- case ViewMode.Week:
10923
- return addWeeks(startDate, offset2);
10924
- case ViewMode.Year:
10925
- return addYears(startDate, offset2);
10926
- default:
10927
- throw new Error("Unknown view mode");
10928
- }
10929
- };
10930
- const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10931
- const index2 = getDatesDiff(xDate, startDate, viewMode);
10932
- const currentDate = getDateByOffset(startDate, index2, viewMode);
10933
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10934
- const remainderMillis = xDate.getTime() - currentDate.getTime();
10935
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10936
- return index2 * columnWidth + percentOfInterval * columnWidth;
10937
- };
10938
- const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10939
- const index2 = getDatesDiff(xDate, startDate, viewMode);
10940
- const currentDate = getDateByOffset(startDate, index2, viewMode);
10941
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10942
- const remainderMillis = xDate.getTime() - currentDate.getTime();
10943
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10944
- return index2 * columnWidth + percentOfInterval * columnWidth;
10945
- };
10946
- const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
10947
- const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
10948
- let progressX;
10949
- if (rtl) {
10950
- progressX = taskX2 - progressWidth;
10951
- } else {
10952
- progressX = taskX1;
10953
- }
10954
- return [progressWidth, progressX];
10955
- };
10956
- const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
10957
- let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
10958
- newDate = new Date(
10959
- newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
10960
- );
10961
- return newDate;
10962
- };
10963
- const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10964
- let result;
10965
- switch (selectedTask.type) {
10966
- case "milestone":
10967
- result = handleTaskBySVGMouseEventForMilestone(
10968
- action,
10969
- selectedTask,
10970
- initialCoordinates,
10971
- coordinates,
10972
- xStep,
10973
- timeStep
10974
- );
10975
- break;
10976
- default:
10977
- result = handleTaskBySVGMouseEventForBar(
10978
- action,
10979
- selectedTask,
10980
- initialCoordinates,
10981
- coordinates,
10982
- xStep,
10983
- timeStep,
10984
- rtl
10985
- );
10986
- break;
10987
- }
10988
- return result;
10989
- };
10990
- const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10991
- const changedTask = { ...selectedTask };
10992
- let isChanged = false;
10993
- switch (action) {
10994
- case "progress":
10995
- isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
10996
- if (isChanged) {
10997
- changedTask.progress = Math.round(
10998
- coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
10999
- );
11000
- }
11001
- break;
11002
- case "start": {
11003
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11004
- if (isChanged) {
11005
- if (rtl) {
11006
- changedTask.end = dateByX(
11007
- coordinates.x1,
11008
- initialCoordinates.x1,
11009
- selectedTask.end,
11010
- xStep,
11011
- timeStep
11012
- );
11013
- } else {
11014
- changedTask.start = dateByX(
11015
- coordinates.x1,
11016
- initialCoordinates.x1,
11017
- selectedTask.start,
11018
- xStep,
11019
- timeStep
11020
- );
11021
- }
11022
- }
11023
- break;
11024
- }
11025
- case "end": {
11026
- isChanged = initialCoordinates.x2 !== coordinates.x2;
11027
- if (isChanged) {
11028
- if (rtl) {
11029
- changedTask.start = dateByX(
11030
- coordinates.x2,
11031
- initialCoordinates.x2,
11032
- selectedTask.start,
11033
- xStep,
11034
- timeStep
11035
- );
11036
- } else {
11037
- changedTask.end = dateByX(
11038
- coordinates.x2,
11039
- initialCoordinates.x2,
11040
- selectedTask.end,
11041
- xStep,
11042
- timeStep
11043
- );
11044
- }
11045
- }
11046
- break;
11047
- }
11048
- case "move": {
11049
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11050
- if (isChanged) {
11051
- if (rtl) {
11052
- changedTask.end = dateByX(
11053
- coordinates.x1,
11054
- initialCoordinates.x1,
11055
- selectedTask.end,
11056
- xStep,
11057
- timeStep
11058
- );
11059
- changedTask.start = dateByX(
11060
- coordinates.x2,
11061
- initialCoordinates.x2,
11062
- selectedTask.start,
11063
- xStep,
11064
- timeStep
11065
- );
11066
- } else {
11067
- changedTask.start = dateByX(
11068
- coordinates.x1,
11069
- initialCoordinates.x1,
11070
- selectedTask.start,
11071
- xStep,
11072
- timeStep
11073
- );
11074
- changedTask.end = dateByX(
11075
- coordinates.x2,
11076
- initialCoordinates.x2,
11077
- selectedTask.end,
11078
- xStep,
11079
- timeStep
11080
- );
11081
- }
11082
- }
11083
- break;
11084
- }
11085
- }
11086
- return { isChanged, changedTask };
11087
- };
11088
- const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11089
- const changedTask = { ...selectedTask };
11090
- const isChanged = coordinates.x1 !== initialCoordinates.x1;
11091
- if (isChanged) {
11092
- switch (action) {
11093
- case "move": {
11094
- changedTask.start = dateByX(
11095
- coordinates.x1,
11096
- initialCoordinates.x1,
11097
- selectedTask.start,
11098
- xStep,
11099
- timeStep
11100
- );
11101
- changedTask.end = changedTask.start;
11102
- break;
11103
- }
11104
- }
11105
- }
11106
- return { isChanged, changedTask };
11107
- };
11108
10910
  const GanttTodayInner = ({
11109
10911
  additionalLeftSpace,
11110
10912
  distances: { columnWidth },
@@ -11113,8 +10915,6 @@ const GanttTodayInner = ({
11113
10915
  rtl,
11114
10916
  startDate,
11115
10917
  viewMode,
11116
- taskHeight,
11117
- // Add taskHeight parameter
11118
10918
  showTodayLine = true,
11119
10919
  showDataDateLine = false,
11120
10920
  dataDate = null,
@@ -11128,14 +10928,38 @@ const GanttTodayInner = ({
11128
10928
  return null;
11129
10929
  }
11130
10930
  const today = /* @__PURE__ */ new Date();
11131
- const x = taskXCoordinate(today, startDate, viewMode, columnWidth);
11132
- const adjustedX = rtl ? x + columnWidth : x;
10931
+ const todayIndex = getDatesDiff(today, startDate, viewMode);
10932
+ const extraMultiplier = () => {
10933
+ switch (viewMode) {
10934
+ case ViewMode.Week: {
10935
+ const percent = today.getDay() / 7;
10936
+ return 1 + percent * 0.2;
10937
+ }
10938
+ case ViewMode.Month: {
10939
+ const dayInMonth = today.getDate();
10940
+ const maxDaysInMonth = getDaysInMonth(
10941
+ today.getMonth(),
10942
+ today.getFullYear()
10943
+ );
10944
+ const percent = dayInMonth / maxDaysInMonth;
10945
+ return 1 + percent * 0.5;
10946
+ }
10947
+ case ViewMode.Year: {
10948
+ const percent = today.getMonth() / 12;
10949
+ return 1 + percent * 0.5;
10950
+ }
10951
+ default:
10952
+ return 1;
10953
+ }
10954
+ };
10955
+ const tickX = todayIndex * columnWidth * extraMultiplier();
10956
+ const x = rtl ? tickX + columnWidth : tickX;
11133
10957
  const color = todayColor || "var(--gantt-calendar-today-color)";
11134
10958
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11135
10959
  /* @__PURE__ */ jsx(
11136
10960
  "rect",
11137
10961
  {
11138
- x: additionalLeftSpace + adjustedX,
10962
+ x: additionalLeftSpace + x,
11139
10963
  y: 0,
11140
10964
  width: 2,
11141
10965
  height: ganttFullHeight,
@@ -11146,7 +10970,7 @@ const GanttTodayInner = ({
11146
10970
  "circle",
11147
10971
  {
11148
10972
  className: styles$c.ganttTodayCircle,
11149
- cx: adjustedX + 1,
10973
+ cx: x + 1,
11150
10974
  cy: 6,
11151
10975
  r: 6,
11152
10976
  fill: color
@@ -11155,7 +10979,7 @@ const GanttTodayInner = ({
11155
10979
  /* @__PURE__ */ jsx(
11156
10980
  "text",
11157
10981
  {
11158
- x: additionalLeftSpace + adjustedX + 8,
10982
+ x: additionalLeftSpace + x + 8,
11159
10983
  y: 10,
11160
10984
  fill: color,
11161
10985
  fontSize: 12,
@@ -11180,15 +11004,38 @@ const GanttTodayInner = ({
11180
11004
  if (!showDataDateLine || !dataDate) {
11181
11005
  return null;
11182
11006
  }
11183
- const dateX = taskXCoordinate(dataDate, startDate, viewMode, columnWidth);
11184
- const milestoneEndX = dateX + taskHeight * 0.5;
11185
- const adjustedX = rtl ? milestoneEndX + columnWidth : milestoneEndX;
11007
+ const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11008
+ const extraMultiplier = () => {
11009
+ switch (viewMode) {
11010
+ case ViewMode.Week: {
11011
+ const percent = dataDate.getDay() / 7;
11012
+ return 1 + percent * 0.2;
11013
+ }
11014
+ case ViewMode.Month: {
11015
+ const dayInMonth = dataDate.getDate();
11016
+ const maxDaysInMonth = getDaysInMonth(
11017
+ dataDate.getMonth(),
11018
+ dataDate.getFullYear()
11019
+ );
11020
+ const percent = dayInMonth / maxDaysInMonth;
11021
+ return 1 + percent * 0.5;
11022
+ }
11023
+ case ViewMode.Year: {
11024
+ const percent = dataDate.getMonth() / 12;
11025
+ return 1 + percent * 0.5;
11026
+ }
11027
+ default:
11028
+ return 1;
11029
+ }
11030
+ };
11031
+ const tickX = dataIndex * columnWidth * extraMultiplier();
11032
+ const x = rtl ? tickX + columnWidth : tickX;
11186
11033
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11187
11034
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11188
11035
  /* @__PURE__ */ jsx(
11189
11036
  "rect",
11190
11037
  {
11191
- x: additionalLeftSpace + adjustedX,
11038
+ x: additionalLeftSpace + x,
11192
11039
  y: 0,
11193
11040
  width: 2,
11194
11041
  height: ganttFullHeight,
@@ -11200,7 +11047,7 @@ const GanttTodayInner = ({
11200
11047
  "circle",
11201
11048
  {
11202
11049
  className: styles$c.ganttTodayCircle,
11203
- cx: adjustedX + 1,
11050
+ cx: x + 1,
11204
11051
  cy: 6,
11205
11052
  r: 6,
11206
11053
  fill: color
@@ -11209,7 +11056,7 @@ const GanttTodayInner = ({
11209
11056
  /* @__PURE__ */ jsx(
11210
11057
  "text",
11211
11058
  {
11212
- x: additionalLeftSpace + adjustedX + 8,
11059
+ x: additionalLeftSpace + x + 8,
11213
11060
  y: 10,
11214
11061
  fill: color,
11215
11062
  fontSize: 12,
@@ -11225,7 +11072,6 @@ const GanttTodayInner = ({
11225
11072
  rtl,
11226
11073
  startDate,
11227
11074
  viewMode,
11228
- taskHeight,
11229
11075
  showDataDateLine,
11230
11076
  dataDate,
11231
11077
  dataDateColor,
@@ -11924,6 +11770,204 @@ const RelationLine = ({
11924
11770
  }
11925
11771
  );
11926
11772
  };
11773
+ const getDateByOffset = (startDate, offset2, viewMode) => {
11774
+ switch (viewMode) {
11775
+ case ViewMode.Day:
11776
+ return addDays(startDate, offset2);
11777
+ case ViewMode.HalfDay:
11778
+ return addHours(startDate, offset2 * 12);
11779
+ case ViewMode.QuarterDay:
11780
+ return addHours(startDate, offset2 * 6);
11781
+ case ViewMode.Hour:
11782
+ return addHours(startDate, offset2);
11783
+ case ViewMode.Month:
11784
+ return addMonths(startDate, offset2);
11785
+ case ViewMode.Week:
11786
+ return addWeeks(startDate, offset2);
11787
+ case ViewMode.Year:
11788
+ return addYears(startDate, offset2);
11789
+ default:
11790
+ throw new Error("Unknown view mode");
11791
+ }
11792
+ };
11793
+ const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11794
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
11795
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
11796
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11797
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
11798
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11799
+ return index2 * columnWidth + percentOfInterval * columnWidth;
11800
+ };
11801
+ const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11802
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
11803
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
11804
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11805
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
11806
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11807
+ return index2 * columnWidth + percentOfInterval * columnWidth;
11808
+ };
11809
+ const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
11810
+ const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
11811
+ let progressX;
11812
+ if (rtl) {
11813
+ progressX = taskX2 - progressWidth;
11814
+ } else {
11815
+ progressX = taskX1;
11816
+ }
11817
+ return [progressWidth, progressX];
11818
+ };
11819
+ const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
11820
+ let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
11821
+ newDate = new Date(
11822
+ newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
11823
+ );
11824
+ return newDate;
11825
+ };
11826
+ const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11827
+ let result;
11828
+ switch (selectedTask.type) {
11829
+ case "milestone":
11830
+ result = handleTaskBySVGMouseEventForMilestone(
11831
+ action,
11832
+ selectedTask,
11833
+ initialCoordinates,
11834
+ coordinates,
11835
+ xStep,
11836
+ timeStep
11837
+ );
11838
+ break;
11839
+ default:
11840
+ result = handleTaskBySVGMouseEventForBar(
11841
+ action,
11842
+ selectedTask,
11843
+ initialCoordinates,
11844
+ coordinates,
11845
+ xStep,
11846
+ timeStep,
11847
+ rtl
11848
+ );
11849
+ break;
11850
+ }
11851
+ return result;
11852
+ };
11853
+ const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11854
+ const changedTask = { ...selectedTask };
11855
+ let isChanged = false;
11856
+ switch (action) {
11857
+ case "progress":
11858
+ isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11859
+ if (isChanged) {
11860
+ changedTask.progress = Math.round(
11861
+ coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11862
+ );
11863
+ }
11864
+ break;
11865
+ case "start": {
11866
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11867
+ if (isChanged) {
11868
+ if (rtl) {
11869
+ changedTask.end = dateByX(
11870
+ coordinates.x1,
11871
+ initialCoordinates.x1,
11872
+ selectedTask.end,
11873
+ xStep,
11874
+ timeStep
11875
+ );
11876
+ } else {
11877
+ changedTask.start = dateByX(
11878
+ coordinates.x1,
11879
+ initialCoordinates.x1,
11880
+ selectedTask.start,
11881
+ xStep,
11882
+ timeStep
11883
+ );
11884
+ }
11885
+ }
11886
+ break;
11887
+ }
11888
+ case "end": {
11889
+ isChanged = initialCoordinates.x2 !== coordinates.x2;
11890
+ if (isChanged) {
11891
+ if (rtl) {
11892
+ changedTask.start = dateByX(
11893
+ coordinates.x2,
11894
+ initialCoordinates.x2,
11895
+ selectedTask.start,
11896
+ xStep,
11897
+ timeStep
11898
+ );
11899
+ } else {
11900
+ changedTask.end = dateByX(
11901
+ coordinates.x2,
11902
+ initialCoordinates.x2,
11903
+ selectedTask.end,
11904
+ xStep,
11905
+ timeStep
11906
+ );
11907
+ }
11908
+ }
11909
+ break;
11910
+ }
11911
+ case "move": {
11912
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11913
+ if (isChanged) {
11914
+ if (rtl) {
11915
+ changedTask.end = dateByX(
11916
+ coordinates.x1,
11917
+ initialCoordinates.x1,
11918
+ selectedTask.end,
11919
+ xStep,
11920
+ timeStep
11921
+ );
11922
+ changedTask.start = dateByX(
11923
+ coordinates.x2,
11924
+ initialCoordinates.x2,
11925
+ selectedTask.start,
11926
+ xStep,
11927
+ timeStep
11928
+ );
11929
+ } else {
11930
+ changedTask.start = dateByX(
11931
+ coordinates.x1,
11932
+ initialCoordinates.x1,
11933
+ selectedTask.start,
11934
+ xStep,
11935
+ timeStep
11936
+ );
11937
+ changedTask.end = dateByX(
11938
+ coordinates.x2,
11939
+ initialCoordinates.x2,
11940
+ selectedTask.end,
11941
+ xStep,
11942
+ timeStep
11943
+ );
11944
+ }
11945
+ }
11946
+ break;
11947
+ }
11948
+ }
11949
+ return { isChanged, changedTask };
11950
+ };
11951
+ const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11952
+ const changedTask = { ...selectedTask };
11953
+ const isChanged = coordinates.x1 !== initialCoordinates.x1;
11954
+ if (isChanged) {
11955
+ switch (action) {
11956
+ case "move": {
11957
+ changedTask.start = dateByX(
11958
+ coordinates.x1,
11959
+ initialCoordinates.x1,
11960
+ selectedTask.start,
11961
+ xStep,
11962
+ timeStep
11963
+ );
11964
+ changedTask.end = changedTask.start;
11965
+ break;
11966
+ }
11967
+ }
11968
+ }
11969
+ return { isChanged, changedTask };
11970
+ };
11927
11971
  const barWrapper = "_barWrapper_5jhkr_1";
11928
11972
  const barHandle = "_barHandle_5jhkr_11";
11929
11973
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -13280,7 +13324,9 @@ const TaskGanttContentInner = (props) => {
13280
13324
  isDateChangeable,
13281
13325
  isRelationChangeable,
13282
13326
  visibleTasksMirror,
13283
- onArrowDoubleClick
13327
+ onArrowDoubleClick,
13328
+ showProgress,
13329
+ progressColor
13284
13330
  ]);
13285
13331
  return /* @__PURE__ */ jsxs("g", { className: "content", children: [
13286
13332
  renderedSelectedTasks,
@@ -13342,7 +13388,8 @@ const TaskGanttInner = (props) => {
13342
13388
  horizontalContainerRef,
13343
13389
  onVerticalScrollbarScrollX,
13344
13390
  verticalGanttContainerRef,
13345
- verticalScrollbarRef
13391
+ verticalScrollbarRef,
13392
+ onOpenGanttContextMenu
13346
13393
  } = props;
13347
13394
  const contentRef = React__default.useRef(null);
13348
13395
  const moveStateVertRef = useRef(null);
@@ -13480,6 +13527,12 @@ const TaskGanttInner = (props) => {
13480
13527
  height: ganttFullHeight,
13481
13528
  fontFamily: "var(--gantt-font-family)",
13482
13529
  ref: ganttSVGRef,
13530
+ onContextMenu: (event) => {
13531
+ event.preventDefault();
13532
+ if (onOpenGanttContextMenu) {
13533
+ onOpenGanttContextMenu(event.clientX, event.clientY);
13534
+ }
13535
+ },
13483
13536
  children: [
13484
13537
  /* @__PURE__ */ jsx(GanttToday, { ...ganttTodayProps }),
13485
13538
  /* @__PURE__ */ jsx(
@@ -19033,6 +19086,34 @@ const Gantt = (props) => {
19033
19086
  [mapTaskToCoordinates, setScrollXProgrammatically]
19034
19087
  );
19035
19088
  const { contextMenu, handleCloseContextMenu, handleOpenContextMenu } = useContextMenu(wrapperRef, scrollToTask);
19089
+ const [ganttContextMenu, setGanttContextMenu] = useState({
19090
+ task: null,
19091
+ x: 0,
19092
+ y: 0
19093
+ });
19094
+ const handleOpenGanttContextMenu = useCallback(
19095
+ (task, clientX, clientY) => {
19096
+ const wrapperNode = wrapperRef.current;
19097
+ if (!wrapperNode) {
19098
+ return;
19099
+ }
19100
+ const { top, left } = wrapperNode.getBoundingClientRect();
19101
+ setGanttContextMenu({
19102
+ task: task || { id: "__gantt_area__", type: "empty" },
19103
+ // Use a dummy task for gantt area
19104
+ x: clientX - left,
19105
+ y: clientY - top
19106
+ });
19107
+ },
19108
+ [wrapperRef]
19109
+ );
19110
+ const handleCloseGanttContextMenu = useCallback(() => {
19111
+ setGanttContextMenu({
19112
+ task: null,
19113
+ x: 0,
19114
+ y: 0
19115
+ });
19116
+ }, []);
19036
19117
  const [dependencyMap, dependentMap, dependencyMarginsMap] = useMemo(
19037
19118
  () => getDependencyMap(
19038
19119
  sortedTasks,
@@ -19821,6 +19902,12 @@ const Gantt = (props) => {
19821
19902
  createDeleteOption(locale)
19822
19903
  ];
19823
19904
  }, [taskList.contextMenuOptions, locale]);
19905
+ const ganttContextMenuOptions = useMemo(() => {
19906
+ if (taskBar.taskGanttContextMenuOption) {
19907
+ return taskBar.taskGanttContextMenuOption;
19908
+ }
19909
+ return [createPasteOption(locale)];
19910
+ }, [taskBar.taskGanttContextMenuOption, locale]);
19824
19911
  const tooltipTaskFromMap = useMemo(() => {
19825
19912
  if (!tooltipTask) {
19826
19913
  return null;
@@ -19864,7 +19951,6 @@ const Gantt = (props) => {
19864
19951
  rtl,
19865
19952
  startDate,
19866
19953
  viewMode,
19867
- taskHeight,
19868
19954
  showTodayLine,
19869
19955
  showDataDateLine,
19870
19956
  dataDate,
@@ -19881,7 +19967,6 @@ const Gantt = (props) => {
19881
19967
  rtl,
19882
19968
  startDate,
19883
19969
  viewMode,
19884
- taskHeight,
19885
19970
  showTodayLine,
19886
19971
  showDataDateLine,
19887
19972
  dataDate,
@@ -20091,7 +20176,10 @@ const Gantt = (props) => {
20091
20176
  horizontalContainerRef,
20092
20177
  verticalScrollbarRef,
20093
20178
  onVerticalScrollbarScrollX,
20094
- verticalGanttContainerRef
20179
+ verticalGanttContainerRef,
20180
+ onOpenGanttContextMenu: (clientX, clientY) => {
20181
+ handleOpenGanttContextMenu(null, clientX, clientY);
20182
+ }
20095
20183
  }
20096
20184
  ),
20097
20185
  tooltipTaskFromMap && /* @__PURE__ */ jsx(
@@ -20130,6 +20218,18 @@ const Gantt = (props) => {
20130
20218
  options: contextMenuOptions
20131
20219
  }
20132
20220
  ),
20221
+ ganttContextMenu.task && !waitCommitTasks && /* @__PURE__ */ jsx(
20222
+ ContextMenu,
20223
+ {
20224
+ checkHasCopyTasks,
20225
+ checkHasCutTasks,
20226
+ contextMenu: ganttContextMenu,
20227
+ distances,
20228
+ handleAction,
20229
+ handleCloseContextMenu: handleCloseGanttContextMenu,
20230
+ options: ganttContextMenuOptions
20231
+ }
20232
+ ),
20133
20233
  /* @__PURE__ */ jsx(GanttLoader, { loading: waitCommitTasks })
20134
20234
  ]
20135
20235
  }
@@ -10924,204 +10924,6 @@
10924
10924
  ganttToday,
10925
10925
  ganttTodayCircle
10926
10926
  };
10927
- const getDateByOffset = (startDate, offset2, viewMode) => {
10928
- switch (viewMode) {
10929
- case ViewMode.Day:
10930
- return addDays(startDate, offset2);
10931
- case ViewMode.HalfDay:
10932
- return addHours(startDate, offset2 * 12);
10933
- case ViewMode.QuarterDay:
10934
- return addHours(startDate, offset2 * 6);
10935
- case ViewMode.Hour:
10936
- return addHours(startDate, offset2);
10937
- case ViewMode.Month:
10938
- return addMonths(startDate, offset2);
10939
- case ViewMode.Week:
10940
- return addWeeks(startDate, offset2);
10941
- case ViewMode.Year:
10942
- return addYears(startDate, offset2);
10943
- default:
10944
- throw new Error("Unknown view mode");
10945
- }
10946
- };
10947
- const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10948
- const index2 = getDatesDiff(xDate, startDate, viewMode);
10949
- const currentDate = getDateByOffset(startDate, index2, viewMode);
10950
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10951
- const remainderMillis = xDate.getTime() - currentDate.getTime();
10952
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10953
- return index2 * columnWidth + percentOfInterval * columnWidth;
10954
- };
10955
- const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10956
- const index2 = getDatesDiff(xDate, startDate, viewMode);
10957
- const currentDate = getDateByOffset(startDate, index2, viewMode);
10958
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10959
- const remainderMillis = xDate.getTime() - currentDate.getTime();
10960
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10961
- return index2 * columnWidth + percentOfInterval * columnWidth;
10962
- };
10963
- const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
10964
- const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
10965
- let progressX;
10966
- if (rtl) {
10967
- progressX = taskX2 - progressWidth;
10968
- } else {
10969
- progressX = taskX1;
10970
- }
10971
- return [progressWidth, progressX];
10972
- };
10973
- const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
10974
- let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
10975
- newDate = new Date(
10976
- newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
10977
- );
10978
- return newDate;
10979
- };
10980
- const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10981
- let result;
10982
- switch (selectedTask.type) {
10983
- case "milestone":
10984
- result = handleTaskBySVGMouseEventForMilestone(
10985
- action,
10986
- selectedTask,
10987
- initialCoordinates,
10988
- coordinates,
10989
- xStep,
10990
- timeStep
10991
- );
10992
- break;
10993
- default:
10994
- result = handleTaskBySVGMouseEventForBar(
10995
- action,
10996
- selectedTask,
10997
- initialCoordinates,
10998
- coordinates,
10999
- xStep,
11000
- timeStep,
11001
- rtl
11002
- );
11003
- break;
11004
- }
11005
- return result;
11006
- };
11007
- const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11008
- const changedTask = { ...selectedTask };
11009
- let isChanged = false;
11010
- switch (action) {
11011
- case "progress":
11012
- isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11013
- if (isChanged) {
11014
- changedTask.progress = Math.round(
11015
- coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11016
- );
11017
- }
11018
- break;
11019
- case "start": {
11020
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11021
- if (isChanged) {
11022
- if (rtl) {
11023
- changedTask.end = dateByX(
11024
- coordinates.x1,
11025
- initialCoordinates.x1,
11026
- selectedTask.end,
11027
- xStep,
11028
- timeStep
11029
- );
11030
- } else {
11031
- changedTask.start = dateByX(
11032
- coordinates.x1,
11033
- initialCoordinates.x1,
11034
- selectedTask.start,
11035
- xStep,
11036
- timeStep
11037
- );
11038
- }
11039
- }
11040
- break;
11041
- }
11042
- case "end": {
11043
- isChanged = initialCoordinates.x2 !== coordinates.x2;
11044
- if (isChanged) {
11045
- if (rtl) {
11046
- changedTask.start = dateByX(
11047
- coordinates.x2,
11048
- initialCoordinates.x2,
11049
- selectedTask.start,
11050
- xStep,
11051
- timeStep
11052
- );
11053
- } else {
11054
- changedTask.end = dateByX(
11055
- coordinates.x2,
11056
- initialCoordinates.x2,
11057
- selectedTask.end,
11058
- xStep,
11059
- timeStep
11060
- );
11061
- }
11062
- }
11063
- break;
11064
- }
11065
- case "move": {
11066
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11067
- if (isChanged) {
11068
- if (rtl) {
11069
- changedTask.end = dateByX(
11070
- coordinates.x1,
11071
- initialCoordinates.x1,
11072
- selectedTask.end,
11073
- xStep,
11074
- timeStep
11075
- );
11076
- changedTask.start = dateByX(
11077
- coordinates.x2,
11078
- initialCoordinates.x2,
11079
- selectedTask.start,
11080
- xStep,
11081
- timeStep
11082
- );
11083
- } else {
11084
- changedTask.start = dateByX(
11085
- coordinates.x1,
11086
- initialCoordinates.x1,
11087
- selectedTask.start,
11088
- xStep,
11089
- timeStep
11090
- );
11091
- changedTask.end = dateByX(
11092
- coordinates.x2,
11093
- initialCoordinates.x2,
11094
- selectedTask.end,
11095
- xStep,
11096
- timeStep
11097
- );
11098
- }
11099
- }
11100
- break;
11101
- }
11102
- }
11103
- return { isChanged, changedTask };
11104
- };
11105
- const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11106
- const changedTask = { ...selectedTask };
11107
- const isChanged = coordinates.x1 !== initialCoordinates.x1;
11108
- if (isChanged) {
11109
- switch (action) {
11110
- case "move": {
11111
- changedTask.start = dateByX(
11112
- coordinates.x1,
11113
- initialCoordinates.x1,
11114
- selectedTask.start,
11115
- xStep,
11116
- timeStep
11117
- );
11118
- changedTask.end = changedTask.start;
11119
- break;
11120
- }
11121
- }
11122
- }
11123
- return { isChanged, changedTask };
11124
- };
11125
10927
  const GanttTodayInner = ({
11126
10928
  additionalLeftSpace,
11127
10929
  distances: { columnWidth },
@@ -11130,8 +10932,6 @@
11130
10932
  rtl,
11131
10933
  startDate,
11132
10934
  viewMode,
11133
- taskHeight,
11134
- // Add taskHeight parameter
11135
10935
  showTodayLine = true,
11136
10936
  showDataDateLine = false,
11137
10937
  dataDate = null,
@@ -11145,14 +10945,38 @@
11145
10945
  return null;
11146
10946
  }
11147
10947
  const today = /* @__PURE__ */ new Date();
11148
- const x = taskXCoordinate(today, startDate, viewMode, columnWidth);
11149
- const adjustedX = rtl ? x + columnWidth : x;
10948
+ const todayIndex = getDatesDiff(today, startDate, viewMode);
10949
+ const extraMultiplier = () => {
10950
+ switch (viewMode) {
10951
+ case ViewMode.Week: {
10952
+ const percent = today.getDay() / 7;
10953
+ return 1 + percent * 0.2;
10954
+ }
10955
+ case ViewMode.Month: {
10956
+ const dayInMonth = today.getDate();
10957
+ const maxDaysInMonth = getDaysInMonth(
10958
+ today.getMonth(),
10959
+ today.getFullYear()
10960
+ );
10961
+ const percent = dayInMonth / maxDaysInMonth;
10962
+ return 1 + percent * 0.5;
10963
+ }
10964
+ case ViewMode.Year: {
10965
+ const percent = today.getMonth() / 12;
10966
+ return 1 + percent * 0.5;
10967
+ }
10968
+ default:
10969
+ return 1;
10970
+ }
10971
+ };
10972
+ const tickX = todayIndex * columnWidth * extraMultiplier();
10973
+ const x = rtl ? tickX + columnWidth : tickX;
11150
10974
  const color = todayColor || "var(--gantt-calendar-today-color)";
11151
10975
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11152
10976
  /* @__PURE__ */ jsxRuntime.jsx(
11153
10977
  "rect",
11154
10978
  {
11155
- x: additionalLeftSpace + adjustedX,
10979
+ x: additionalLeftSpace + x,
11156
10980
  y: 0,
11157
10981
  width: 2,
11158
10982
  height: ganttFullHeight,
@@ -11163,7 +10987,7 @@
11163
10987
  "circle",
11164
10988
  {
11165
10989
  className: styles$c.ganttTodayCircle,
11166
- cx: adjustedX + 1,
10990
+ cx: x + 1,
11167
10991
  cy: 6,
11168
10992
  r: 6,
11169
10993
  fill: color
@@ -11172,7 +10996,7 @@
11172
10996
  /* @__PURE__ */ jsxRuntime.jsx(
11173
10997
  "text",
11174
10998
  {
11175
- x: additionalLeftSpace + adjustedX + 8,
10999
+ x: additionalLeftSpace + x + 8,
11176
11000
  y: 10,
11177
11001
  fill: color,
11178
11002
  fontSize: 12,
@@ -11197,15 +11021,38 @@
11197
11021
  if (!showDataDateLine || !dataDate) {
11198
11022
  return null;
11199
11023
  }
11200
- const dateX = taskXCoordinate(dataDate, startDate, viewMode, columnWidth);
11201
- const milestoneEndX = dateX + taskHeight * 0.5;
11202
- const adjustedX = rtl ? milestoneEndX + columnWidth : milestoneEndX;
11024
+ const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11025
+ const extraMultiplier = () => {
11026
+ switch (viewMode) {
11027
+ case ViewMode.Week: {
11028
+ const percent = dataDate.getDay() / 7;
11029
+ return 1 + percent * 0.2;
11030
+ }
11031
+ case ViewMode.Month: {
11032
+ const dayInMonth = dataDate.getDate();
11033
+ const maxDaysInMonth = getDaysInMonth(
11034
+ dataDate.getMonth(),
11035
+ dataDate.getFullYear()
11036
+ );
11037
+ const percent = dayInMonth / maxDaysInMonth;
11038
+ return 1 + percent * 0.5;
11039
+ }
11040
+ case ViewMode.Year: {
11041
+ const percent = dataDate.getMonth() / 12;
11042
+ return 1 + percent * 0.5;
11043
+ }
11044
+ default:
11045
+ return 1;
11046
+ }
11047
+ };
11048
+ const tickX = dataIndex * columnWidth * extraMultiplier();
11049
+ const x = rtl ? tickX + columnWidth : tickX;
11203
11050
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11204
11051
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11205
11052
  /* @__PURE__ */ jsxRuntime.jsx(
11206
11053
  "rect",
11207
11054
  {
11208
- x: additionalLeftSpace + adjustedX,
11055
+ x: additionalLeftSpace + x,
11209
11056
  y: 0,
11210
11057
  width: 2,
11211
11058
  height: ganttFullHeight,
@@ -11217,7 +11064,7 @@
11217
11064
  "circle",
11218
11065
  {
11219
11066
  className: styles$c.ganttTodayCircle,
11220
- cx: adjustedX + 1,
11067
+ cx: x + 1,
11221
11068
  cy: 6,
11222
11069
  r: 6,
11223
11070
  fill: color
@@ -11226,7 +11073,7 @@
11226
11073
  /* @__PURE__ */ jsxRuntime.jsx(
11227
11074
  "text",
11228
11075
  {
11229
- x: additionalLeftSpace + adjustedX + 8,
11076
+ x: additionalLeftSpace + x + 8,
11230
11077
  y: 10,
11231
11078
  fill: color,
11232
11079
  fontSize: 12,
@@ -11242,7 +11089,6 @@
11242
11089
  rtl,
11243
11090
  startDate,
11244
11091
  viewMode,
11245
- taskHeight,
11246
11092
  showDataDateLine,
11247
11093
  dataDate,
11248
11094
  dataDateColor,
@@ -11941,6 +11787,204 @@
11941
11787
  }
11942
11788
  );
11943
11789
  };
11790
+ const getDateByOffset = (startDate, offset2, viewMode) => {
11791
+ switch (viewMode) {
11792
+ case ViewMode.Day:
11793
+ return addDays(startDate, offset2);
11794
+ case ViewMode.HalfDay:
11795
+ return addHours(startDate, offset2 * 12);
11796
+ case ViewMode.QuarterDay:
11797
+ return addHours(startDate, offset2 * 6);
11798
+ case ViewMode.Hour:
11799
+ return addHours(startDate, offset2);
11800
+ case ViewMode.Month:
11801
+ return addMonths(startDate, offset2);
11802
+ case ViewMode.Week:
11803
+ return addWeeks(startDate, offset2);
11804
+ case ViewMode.Year:
11805
+ return addYears(startDate, offset2);
11806
+ default:
11807
+ throw new Error("Unknown view mode");
11808
+ }
11809
+ };
11810
+ const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11811
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
11812
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
11813
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11814
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
11815
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11816
+ return index2 * columnWidth + percentOfInterval * columnWidth;
11817
+ };
11818
+ const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11819
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
11820
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
11821
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11822
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
11823
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11824
+ return index2 * columnWidth + percentOfInterval * columnWidth;
11825
+ };
11826
+ const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
11827
+ const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
11828
+ let progressX;
11829
+ if (rtl) {
11830
+ progressX = taskX2 - progressWidth;
11831
+ } else {
11832
+ progressX = taskX1;
11833
+ }
11834
+ return [progressWidth, progressX];
11835
+ };
11836
+ const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
11837
+ let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
11838
+ newDate = new Date(
11839
+ newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
11840
+ );
11841
+ return newDate;
11842
+ };
11843
+ const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11844
+ let result;
11845
+ switch (selectedTask.type) {
11846
+ case "milestone":
11847
+ result = handleTaskBySVGMouseEventForMilestone(
11848
+ action,
11849
+ selectedTask,
11850
+ initialCoordinates,
11851
+ coordinates,
11852
+ xStep,
11853
+ timeStep
11854
+ );
11855
+ break;
11856
+ default:
11857
+ result = handleTaskBySVGMouseEventForBar(
11858
+ action,
11859
+ selectedTask,
11860
+ initialCoordinates,
11861
+ coordinates,
11862
+ xStep,
11863
+ timeStep,
11864
+ rtl
11865
+ );
11866
+ break;
11867
+ }
11868
+ return result;
11869
+ };
11870
+ const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11871
+ const changedTask = { ...selectedTask };
11872
+ let isChanged = false;
11873
+ switch (action) {
11874
+ case "progress":
11875
+ isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11876
+ if (isChanged) {
11877
+ changedTask.progress = Math.round(
11878
+ coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11879
+ );
11880
+ }
11881
+ break;
11882
+ case "start": {
11883
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11884
+ if (isChanged) {
11885
+ if (rtl) {
11886
+ changedTask.end = dateByX(
11887
+ coordinates.x1,
11888
+ initialCoordinates.x1,
11889
+ selectedTask.end,
11890
+ xStep,
11891
+ timeStep
11892
+ );
11893
+ } else {
11894
+ changedTask.start = dateByX(
11895
+ coordinates.x1,
11896
+ initialCoordinates.x1,
11897
+ selectedTask.start,
11898
+ xStep,
11899
+ timeStep
11900
+ );
11901
+ }
11902
+ }
11903
+ break;
11904
+ }
11905
+ case "end": {
11906
+ isChanged = initialCoordinates.x2 !== coordinates.x2;
11907
+ if (isChanged) {
11908
+ if (rtl) {
11909
+ changedTask.start = dateByX(
11910
+ coordinates.x2,
11911
+ initialCoordinates.x2,
11912
+ selectedTask.start,
11913
+ xStep,
11914
+ timeStep
11915
+ );
11916
+ } else {
11917
+ changedTask.end = dateByX(
11918
+ coordinates.x2,
11919
+ initialCoordinates.x2,
11920
+ selectedTask.end,
11921
+ xStep,
11922
+ timeStep
11923
+ );
11924
+ }
11925
+ }
11926
+ break;
11927
+ }
11928
+ case "move": {
11929
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11930
+ if (isChanged) {
11931
+ if (rtl) {
11932
+ changedTask.end = dateByX(
11933
+ coordinates.x1,
11934
+ initialCoordinates.x1,
11935
+ selectedTask.end,
11936
+ xStep,
11937
+ timeStep
11938
+ );
11939
+ changedTask.start = dateByX(
11940
+ coordinates.x2,
11941
+ initialCoordinates.x2,
11942
+ selectedTask.start,
11943
+ xStep,
11944
+ timeStep
11945
+ );
11946
+ } else {
11947
+ changedTask.start = dateByX(
11948
+ coordinates.x1,
11949
+ initialCoordinates.x1,
11950
+ selectedTask.start,
11951
+ xStep,
11952
+ timeStep
11953
+ );
11954
+ changedTask.end = dateByX(
11955
+ coordinates.x2,
11956
+ initialCoordinates.x2,
11957
+ selectedTask.end,
11958
+ xStep,
11959
+ timeStep
11960
+ );
11961
+ }
11962
+ }
11963
+ break;
11964
+ }
11965
+ }
11966
+ return { isChanged, changedTask };
11967
+ };
11968
+ const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11969
+ const changedTask = { ...selectedTask };
11970
+ const isChanged = coordinates.x1 !== initialCoordinates.x1;
11971
+ if (isChanged) {
11972
+ switch (action) {
11973
+ case "move": {
11974
+ changedTask.start = dateByX(
11975
+ coordinates.x1,
11976
+ initialCoordinates.x1,
11977
+ selectedTask.start,
11978
+ xStep,
11979
+ timeStep
11980
+ );
11981
+ changedTask.end = changedTask.start;
11982
+ break;
11983
+ }
11984
+ }
11985
+ }
11986
+ return { isChanged, changedTask };
11987
+ };
11944
11988
  const barWrapper = "_barWrapper_5jhkr_1";
11945
11989
  const barHandle = "_barHandle_5jhkr_11";
11946
11990
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -13297,7 +13341,9 @@
13297
13341
  isDateChangeable,
13298
13342
  isRelationChangeable,
13299
13343
  visibleTasksMirror,
13300
- onArrowDoubleClick
13344
+ onArrowDoubleClick,
13345
+ showProgress,
13346
+ progressColor
13301
13347
  ]);
13302
13348
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "content", children: [
13303
13349
  renderedSelectedTasks,
@@ -13359,7 +13405,8 @@
13359
13405
  horizontalContainerRef,
13360
13406
  onVerticalScrollbarScrollX,
13361
13407
  verticalGanttContainerRef,
13362
- verticalScrollbarRef
13408
+ verticalScrollbarRef,
13409
+ onOpenGanttContextMenu
13363
13410
  } = props;
13364
13411
  const contentRef = React.useRef(null);
13365
13412
  const moveStateVertRef = React.useRef(null);
@@ -13497,6 +13544,12 @@
13497
13544
  height: ganttFullHeight,
13498
13545
  fontFamily: "var(--gantt-font-family)",
13499
13546
  ref: ganttSVGRef,
13547
+ onContextMenu: (event) => {
13548
+ event.preventDefault();
13549
+ if (onOpenGanttContextMenu) {
13550
+ onOpenGanttContextMenu(event.clientX, event.clientY);
13551
+ }
13552
+ },
13500
13553
  children: [
13501
13554
  /* @__PURE__ */ jsxRuntime.jsx(GanttToday, { ...ganttTodayProps }),
13502
13555
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -19050,6 +19103,34 @@
19050
19103
  [mapTaskToCoordinates, setScrollXProgrammatically]
19051
19104
  );
19052
19105
  const { contextMenu, handleCloseContextMenu, handleOpenContextMenu } = useContextMenu(wrapperRef, scrollToTask);
19106
+ const [ganttContextMenu, setGanttContextMenu] = React.useState({
19107
+ task: null,
19108
+ x: 0,
19109
+ y: 0
19110
+ });
19111
+ const handleOpenGanttContextMenu = React.useCallback(
19112
+ (task, clientX, clientY) => {
19113
+ const wrapperNode = wrapperRef.current;
19114
+ if (!wrapperNode) {
19115
+ return;
19116
+ }
19117
+ const { top, left } = wrapperNode.getBoundingClientRect();
19118
+ setGanttContextMenu({
19119
+ task: task || { id: "__gantt_area__", type: "empty" },
19120
+ // Use a dummy task for gantt area
19121
+ x: clientX - left,
19122
+ y: clientY - top
19123
+ });
19124
+ },
19125
+ [wrapperRef]
19126
+ );
19127
+ const handleCloseGanttContextMenu = React.useCallback(() => {
19128
+ setGanttContextMenu({
19129
+ task: null,
19130
+ x: 0,
19131
+ y: 0
19132
+ });
19133
+ }, []);
19053
19134
  const [dependencyMap, dependentMap, dependencyMarginsMap] = React.useMemo(
19054
19135
  () => getDependencyMap(
19055
19136
  sortedTasks,
@@ -19838,6 +19919,12 @@
19838
19919
  createDeleteOption(locale)
19839
19920
  ];
19840
19921
  }, [taskList.contextMenuOptions, locale]);
19922
+ const ganttContextMenuOptions = React.useMemo(() => {
19923
+ if (taskBar.taskGanttContextMenuOption) {
19924
+ return taskBar.taskGanttContextMenuOption;
19925
+ }
19926
+ return [createPasteOption(locale)];
19927
+ }, [taskBar.taskGanttContextMenuOption, locale]);
19841
19928
  const tooltipTaskFromMap = React.useMemo(() => {
19842
19929
  if (!tooltipTask) {
19843
19930
  return null;
@@ -19881,7 +19968,6 @@
19881
19968
  rtl,
19882
19969
  startDate,
19883
19970
  viewMode,
19884
- taskHeight,
19885
19971
  showTodayLine,
19886
19972
  showDataDateLine,
19887
19973
  dataDate,
@@ -19898,7 +19984,6 @@
19898
19984
  rtl,
19899
19985
  startDate,
19900
19986
  viewMode,
19901
- taskHeight,
19902
19987
  showTodayLine,
19903
19988
  showDataDateLine,
19904
19989
  dataDate,
@@ -20108,7 +20193,10 @@
20108
20193
  horizontalContainerRef,
20109
20194
  verticalScrollbarRef,
20110
20195
  onVerticalScrollbarScrollX,
20111
- verticalGanttContainerRef
20196
+ verticalGanttContainerRef,
20197
+ onOpenGanttContextMenu: (clientX, clientY) => {
20198
+ handleOpenGanttContextMenu(null, clientX, clientY);
20199
+ }
20112
20200
  }
20113
20201
  ),
20114
20202
  tooltipTaskFromMap && /* @__PURE__ */ jsxRuntime.jsx(
@@ -20147,6 +20235,18 @@
20147
20235
  options: contextMenuOptions
20148
20236
  }
20149
20237
  ),
20238
+ ganttContextMenu.task && !waitCommitTasks && /* @__PURE__ */ jsxRuntime.jsx(
20239
+ ContextMenu,
20240
+ {
20241
+ checkHasCopyTasks,
20242
+ checkHasCutTasks,
20243
+ contextMenu: ganttContextMenu,
20244
+ distances,
20245
+ handleAction,
20246
+ handleCloseContextMenu: handleCloseGanttContextMenu,
20247
+ options: ganttContextMenuOptions
20248
+ }
20249
+ ),
20150
20250
  /* @__PURE__ */ jsxRuntime.jsx(GanttLoader, { loading: waitCommitTasks })
20151
20251
  ]
20152
20252
  }
@@ -183,6 +183,10 @@ export interface GanttTaskBarProps extends GanttTaskBarActions {
183
183
  TooltipContent?: ComponentType<{
184
184
  task: Task;
185
185
  }>;
186
+ /**
187
+ * Context menu options for right-click on the gantt chart area
188
+ */
189
+ taskGanttContextMenuOption?: ContextMenuOptionType[];
186
190
  /**
187
191
  * Invokes on double-click on the relation arrow between tasks
188
192
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
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",