gantt-task-react-v 1.1.2 → 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,16 +11004,38 @@ const GanttTodayInner = ({
11180
11004
  if (!showDataDateLine || !dataDate) {
11181
11005
  return null;
11182
11006
  }
11183
- const index2 = getDatesDiff(dataDate, startDate, viewMode);
11184
- const intervalEndX = (index2 + 1) * columnWidth;
11185
- const milestoneEndX = intervalEndX + taskHeight * 0.5;
11186
- 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;
11187
11033
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11188
11034
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11189
11035
  /* @__PURE__ */ jsx(
11190
11036
  "rect",
11191
11037
  {
11192
- x: additionalLeftSpace + adjustedX,
11038
+ x: additionalLeftSpace + x,
11193
11039
  y: 0,
11194
11040
  width: 2,
11195
11041
  height: ganttFullHeight,
@@ -11201,7 +11047,7 @@ const GanttTodayInner = ({
11201
11047
  "circle",
11202
11048
  {
11203
11049
  className: styles$c.ganttTodayCircle,
11204
- cx: adjustedX + 1,
11050
+ cx: x + 1,
11205
11051
  cy: 6,
11206
11052
  r: 6,
11207
11053
  fill: color
@@ -11210,7 +11056,7 @@ const GanttTodayInner = ({
11210
11056
  /* @__PURE__ */ jsx(
11211
11057
  "text",
11212
11058
  {
11213
- x: additionalLeftSpace + adjustedX + 8,
11059
+ x: additionalLeftSpace + x + 8,
11214
11060
  y: 10,
11215
11061
  fill: color,
11216
11062
  fontSize: 12,
@@ -11226,7 +11072,6 @@ const GanttTodayInner = ({
11226
11072
  rtl,
11227
11073
  startDate,
11228
11074
  viewMode,
11229
- taskHeight,
11230
11075
  showDataDateLine,
11231
11076
  dataDate,
11232
11077
  dataDateColor,
@@ -11925,6 +11770,204 @@ const RelationLine = ({
11925
11770
  }
11926
11771
  );
11927
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
+ };
11928
11971
  const barWrapper = "_barWrapper_5jhkr_1";
11929
11972
  const barHandle = "_barHandle_5jhkr_11";
11930
11973
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -13281,7 +13324,9 @@ const TaskGanttContentInner = (props) => {
13281
13324
  isDateChangeable,
13282
13325
  isRelationChangeable,
13283
13326
  visibleTasksMirror,
13284
- onArrowDoubleClick
13327
+ onArrowDoubleClick,
13328
+ showProgress,
13329
+ progressColor
13285
13330
  ]);
13286
13331
  return /* @__PURE__ */ jsxs("g", { className: "content", children: [
13287
13332
  renderedSelectedTasks,
@@ -13343,7 +13388,8 @@ const TaskGanttInner = (props) => {
13343
13388
  horizontalContainerRef,
13344
13389
  onVerticalScrollbarScrollX,
13345
13390
  verticalGanttContainerRef,
13346
- verticalScrollbarRef
13391
+ verticalScrollbarRef,
13392
+ onOpenGanttContextMenu
13347
13393
  } = props;
13348
13394
  const contentRef = React__default.useRef(null);
13349
13395
  const moveStateVertRef = useRef(null);
@@ -13481,6 +13527,12 @@ const TaskGanttInner = (props) => {
13481
13527
  height: ganttFullHeight,
13482
13528
  fontFamily: "var(--gantt-font-family)",
13483
13529
  ref: ganttSVGRef,
13530
+ onContextMenu: (event) => {
13531
+ event.preventDefault();
13532
+ if (onOpenGanttContextMenu) {
13533
+ onOpenGanttContextMenu(event.clientX, event.clientY);
13534
+ }
13535
+ },
13484
13536
  children: [
13485
13537
  /* @__PURE__ */ jsx(GanttToday, { ...ganttTodayProps }),
13486
13538
  /* @__PURE__ */ jsx(
@@ -19034,6 +19086,34 @@ const Gantt = (props) => {
19034
19086
  [mapTaskToCoordinates, setScrollXProgrammatically]
19035
19087
  );
19036
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
+ }, []);
19037
19117
  const [dependencyMap, dependentMap, dependencyMarginsMap] = useMemo(
19038
19118
  () => getDependencyMap(
19039
19119
  sortedTasks,
@@ -19822,6 +19902,12 @@ const Gantt = (props) => {
19822
19902
  createDeleteOption(locale)
19823
19903
  ];
19824
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]);
19825
19911
  const tooltipTaskFromMap = useMemo(() => {
19826
19912
  if (!tooltipTask) {
19827
19913
  return null;
@@ -19865,7 +19951,6 @@ const Gantt = (props) => {
19865
19951
  rtl,
19866
19952
  startDate,
19867
19953
  viewMode,
19868
- taskHeight,
19869
19954
  showTodayLine,
19870
19955
  showDataDateLine,
19871
19956
  dataDate,
@@ -19882,7 +19967,6 @@ const Gantt = (props) => {
19882
19967
  rtl,
19883
19968
  startDate,
19884
19969
  viewMode,
19885
- taskHeight,
19886
19970
  showTodayLine,
19887
19971
  showDataDateLine,
19888
19972
  dataDate,
@@ -20092,7 +20176,10 @@ const Gantt = (props) => {
20092
20176
  horizontalContainerRef,
20093
20177
  verticalScrollbarRef,
20094
20178
  onVerticalScrollbarScrollX,
20095
- verticalGanttContainerRef
20179
+ verticalGanttContainerRef,
20180
+ onOpenGanttContextMenu: (clientX, clientY) => {
20181
+ handleOpenGanttContextMenu(null, clientX, clientY);
20182
+ }
20096
20183
  }
20097
20184
  ),
20098
20185
  tooltipTaskFromMap && /* @__PURE__ */ jsx(
@@ -20131,6 +20218,18 @@ const Gantt = (props) => {
20131
20218
  options: contextMenuOptions
20132
20219
  }
20133
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
+ ),
20134
20233
  /* @__PURE__ */ jsx(GanttLoader, { loading: waitCommitTasks })
20135
20234
  ]
20136
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,16 +11021,38 @@
11197
11021
  if (!showDataDateLine || !dataDate) {
11198
11022
  return null;
11199
11023
  }
11200
- const index2 = getDatesDiff(dataDate, startDate, viewMode);
11201
- const intervalEndX = (index2 + 1) * columnWidth;
11202
- const milestoneEndX = intervalEndX + taskHeight * 0.5;
11203
- 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;
11204
11050
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11205
11051
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11206
11052
  /* @__PURE__ */ jsxRuntime.jsx(
11207
11053
  "rect",
11208
11054
  {
11209
- x: additionalLeftSpace + adjustedX,
11055
+ x: additionalLeftSpace + x,
11210
11056
  y: 0,
11211
11057
  width: 2,
11212
11058
  height: ganttFullHeight,
@@ -11218,7 +11064,7 @@
11218
11064
  "circle",
11219
11065
  {
11220
11066
  className: styles$c.ganttTodayCircle,
11221
- cx: adjustedX + 1,
11067
+ cx: x + 1,
11222
11068
  cy: 6,
11223
11069
  r: 6,
11224
11070
  fill: color
@@ -11227,7 +11073,7 @@
11227
11073
  /* @__PURE__ */ jsxRuntime.jsx(
11228
11074
  "text",
11229
11075
  {
11230
- x: additionalLeftSpace + adjustedX + 8,
11076
+ x: additionalLeftSpace + x + 8,
11231
11077
  y: 10,
11232
11078
  fill: color,
11233
11079
  fontSize: 12,
@@ -11243,7 +11089,6 @@
11243
11089
  rtl,
11244
11090
  startDate,
11245
11091
  viewMode,
11246
- taskHeight,
11247
11092
  showDataDateLine,
11248
11093
  dataDate,
11249
11094
  dataDateColor,
@@ -11942,6 +11787,204 @@
11942
11787
  }
11943
11788
  );
11944
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
+ };
11945
11988
  const barWrapper = "_barWrapper_5jhkr_1";
11946
11989
  const barHandle = "_barHandle_5jhkr_11";
11947
11990
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -13298,7 +13341,9 @@
13298
13341
  isDateChangeable,
13299
13342
  isRelationChangeable,
13300
13343
  visibleTasksMirror,
13301
- onArrowDoubleClick
13344
+ onArrowDoubleClick,
13345
+ showProgress,
13346
+ progressColor
13302
13347
  ]);
13303
13348
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "content", children: [
13304
13349
  renderedSelectedTasks,
@@ -13360,7 +13405,8 @@
13360
13405
  horizontalContainerRef,
13361
13406
  onVerticalScrollbarScrollX,
13362
13407
  verticalGanttContainerRef,
13363
- verticalScrollbarRef
13408
+ verticalScrollbarRef,
13409
+ onOpenGanttContextMenu
13364
13410
  } = props;
13365
13411
  const contentRef = React.useRef(null);
13366
13412
  const moveStateVertRef = React.useRef(null);
@@ -13498,6 +13544,12 @@
13498
13544
  height: ganttFullHeight,
13499
13545
  fontFamily: "var(--gantt-font-family)",
13500
13546
  ref: ganttSVGRef,
13547
+ onContextMenu: (event) => {
13548
+ event.preventDefault();
13549
+ if (onOpenGanttContextMenu) {
13550
+ onOpenGanttContextMenu(event.clientX, event.clientY);
13551
+ }
13552
+ },
13501
13553
  children: [
13502
13554
  /* @__PURE__ */ jsxRuntime.jsx(GanttToday, { ...ganttTodayProps }),
13503
13555
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -19051,6 +19103,34 @@
19051
19103
  [mapTaskToCoordinates, setScrollXProgrammatically]
19052
19104
  );
19053
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
+ }, []);
19054
19134
  const [dependencyMap, dependentMap, dependencyMarginsMap] = React.useMemo(
19055
19135
  () => getDependencyMap(
19056
19136
  sortedTasks,
@@ -19839,6 +19919,12 @@
19839
19919
  createDeleteOption(locale)
19840
19920
  ];
19841
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]);
19842
19928
  const tooltipTaskFromMap = React.useMemo(() => {
19843
19929
  if (!tooltipTask) {
19844
19930
  return null;
@@ -19882,7 +19968,6 @@
19882
19968
  rtl,
19883
19969
  startDate,
19884
19970
  viewMode,
19885
- taskHeight,
19886
19971
  showTodayLine,
19887
19972
  showDataDateLine,
19888
19973
  dataDate,
@@ -19899,7 +19984,6 @@
19899
19984
  rtl,
19900
19985
  startDate,
19901
19986
  viewMode,
19902
- taskHeight,
19903
19987
  showTodayLine,
19904
19988
  showDataDateLine,
19905
19989
  dataDate,
@@ -20109,7 +20193,10 @@
20109
20193
  horizontalContainerRef,
20110
20194
  verticalScrollbarRef,
20111
20195
  onVerticalScrollbarScrollX,
20112
- verticalGanttContainerRef
20196
+ verticalGanttContainerRef,
20197
+ onOpenGanttContextMenu: (clientX, clientY) => {
20198
+ handleOpenGanttContextMenu(null, clientX, clientY);
20199
+ }
20113
20200
  }
20114
20201
  ),
20115
20202
  tooltipTaskFromMap && /* @__PURE__ */ jsxRuntime.jsx(
@@ -20148,6 +20235,18 @@
20148
20235
  options: contextMenuOptions
20149
20236
  }
20150
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
+ ),
20151
20250
  /* @__PURE__ */ jsxRuntime.jsx(GanttLoader, { loading: waitCommitTasks })
20152
20251
  ]
20153
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.2",
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",