gantt-task-react-v 1.2.14 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4684,11 +4684,14 @@ const getStartAndEnd = (containerEl, property, cellSize) => {
4684
4684
  if (!containerEl) {
4685
4685
  return null;
4686
4686
  }
4687
- const scrollValue = containerEl[property];
4688
- const maxScrollValue = property === "scrollLeft" ? containerEl.scrollWidth : containerEl.scrollHeight;
4689
- const fullValue = property === "scrollLeft" ? containerEl.clientWidth : containerEl.clientHeight;
4690
- const firstIndex = Math.floor(scrollValue / cellSize);
4691
- const lastIndex = Math.ceil((scrollValue + fullValue) / cellSize) + 10;
4687
+ const el = containerEl;
4688
+ const scrollValue = property === "scrollLeft" ? el.scrollLeft : el.scrollTop;
4689
+ const maxScrollValue = property === "scrollLeft" ? el.scrollWidth : el.scrollHeight;
4690
+ const fullValue = property === "scrollLeft" ? el.clientWidth : el.clientHeight;
4691
+ const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize));
4692
+ const visibleCount = Math.max(1, Math.ceil(fullValue / cellSize));
4693
+ const overscan = Math.min(100, Math.max(10, Math.ceil(visibleCount * 0.5)));
4694
+ const lastIndex = Math.floor((scrollValue + fullValue) / cellSize) + overscan;
4692
4695
  const isStartOfScroll = scrollValue < DELTA;
4693
4696
  const isEndOfScroll = scrollValue + fullValue > maxScrollValue - DELTA;
4694
4697
  return [firstIndex, lastIndex, isStartOfScroll, isEndOfScroll, fullValue];
@@ -4697,31 +4700,49 @@ const useOptimizedList = (containerRef, property, cellSize) => {
4697
4700
  const [indexes, setIndexes] = useState(
4698
4701
  () => getStartAndEnd(containerRef.current, property, cellSize)
4699
4702
  );
4703
+ const rafRef = useRef(null);
4704
+ const pendingRef = useRef(false);
4705
+ const update = useMemo(() => {
4706
+ const fn = () => {
4707
+ pendingRef.current = false;
4708
+ const next = getStartAndEnd(containerRef.current, property, cellSize);
4709
+ setIndexes((prev) => {
4710
+ const changed = !prev || !next || next.some((v, i) => prev ? prev[i] !== v : true);
4711
+ return changed ? next : prev;
4712
+ });
4713
+ rafRef.current = null;
4714
+ };
4715
+ return fn;
4716
+ }, [cellSize, containerRef, property]);
4700
4717
  useEffect(() => {
4701
- let rafId = null;
4702
- let prevIndexes = indexes;
4703
- const handler = () => {
4704
- const nextIndexes = getStartAndEnd(
4705
- containerRef.current,
4706
- property,
4707
- cellSize
4708
- );
4709
- const isChanged = prevIndexes ? nextIndexes ? nextIndexes.some(
4710
- (value, index2) => !prevIndexes || prevIndexes[index2] !== value
4711
- ) : true : Boolean(nextIndexes);
4712
- if (isChanged) {
4713
- prevIndexes = nextIndexes;
4714
- setIndexes(nextIndexes);
4715
- }
4716
- rafId = requestAnimationFrame(handler);
4718
+ const el = containerRef.current;
4719
+ if (!el) {
4720
+ return void 0;
4721
+ }
4722
+ setIndexes(getStartAndEnd(el, property, cellSize));
4723
+ const onScroll = () => {
4724
+ if (pendingRef.current)
4725
+ return;
4726
+ pendingRef.current = true;
4727
+ rafRef.current = requestAnimationFrame(update);
4717
4728
  };
4718
- rafId = requestAnimationFrame(handler);
4729
+ const resizeObserver = new ResizeObserver(() => {
4730
+ if (pendingRef.current)
4731
+ return;
4732
+ pendingRef.current = true;
4733
+ rafRef.current = requestAnimationFrame(update);
4734
+ });
4735
+ resizeObserver.observe(el);
4736
+ el.addEventListener("scroll", onScroll, { passive: true });
4719
4737
  return () => {
4720
- if (rafId !== null) {
4721
- cancelAnimationFrame(rafId);
4738
+ el.removeEventListener("scroll", onScroll);
4739
+ resizeObserver.disconnect();
4740
+ if (rafRef.current !== null) {
4741
+ cancelAnimationFrame(rafRef.current);
4722
4742
  }
4743
+ pendingRef.current = false;
4723
4744
  };
4724
- }, [cellSize, containerRef, indexes, property]);
4745
+ }, [cellSize, containerRef, property, update]);
4725
4746
  return indexes;
4726
4747
  };
4727
4748
  const taskListNameWrapper = "_taskListNameWrapper_16z6n_1";
@@ -10911,7 +10932,7 @@ const styles$c = {
10911
10932
  };
10912
10933
  const GanttTodayInner = ({
10913
10934
  additionalLeftSpace,
10914
- distances,
10935
+ distances: { columnWidth },
10915
10936
  ganttFullHeight,
10916
10937
  isUnknownDates,
10917
10938
  rtl,
@@ -10925,7 +10946,6 @@ const GanttTodayInner = ({
10925
10946
  todayLabel = "Today",
10926
10947
  dataDateLabel = "Data Date"
10927
10948
  }) => {
10928
- const { columnWidth, rowHeight, barFill } = distances;
10929
10949
  const todayElement = useMemo(() => {
10930
10950
  if (isUnknownDates || !showTodayLine) {
10931
10951
  return null;
@@ -11032,20 +11052,13 @@ const GanttTodayInner = ({
11032
11052
  }
11033
11053
  };
11034
11054
  const tickX = dataIndex * columnWidth * extraMultiplier();
11035
- const dateBaseX = rtl ? tickX + columnWidth : tickX;
11055
+ const x = rtl ? tickX + columnWidth : tickX;
11036
11056
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11037
- const taskHeight = rowHeight * barFill / 100;
11038
- const rotatedHeight = taskHeight / Math.SQRT2;
11039
- const centerX = dateBaseX;
11040
- const centerY = 6;
11041
- const rectX = centerX - rotatedHeight / 2;
11042
- const rectY = centerY - rotatedHeight / 2;
11043
- const rightEdgeX = centerX + taskHeight / 2;
11044
11057
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11045
11058
  /* @__PURE__ */ jsx(
11046
11059
  "rect",
11047
11060
  {
11048
- x: additionalLeftSpace + rightEdgeX,
11061
+ x: additionalLeftSpace + x,
11049
11062
  y: 0,
11050
11063
  width: 2,
11051
11064
  height: ganttFullHeight,
@@ -11054,22 +11067,19 @@ const GanttTodayInner = ({
11054
11067
  }
11055
11068
  ),
11056
11069
  /* @__PURE__ */ jsx(
11057
- "rect",
11070
+ "circle",
11058
11071
  {
11059
- x: additionalLeftSpace + rectX,
11060
- y: rectY,
11061
- width: rotatedHeight,
11062
- height: rotatedHeight,
11063
- fill: color,
11064
- transform: `rotate(45 ${additionalLeftSpace + centerX} ${centerY})`,
11065
- rx: 2,
11066
- ry: 2
11072
+ className: styles$c.ganttTodayCircle,
11073
+ cx: x + 1,
11074
+ cy: 6,
11075
+ r: 6,
11076
+ fill: color
11067
11077
  }
11068
11078
  ),
11069
11079
  /* @__PURE__ */ jsx(
11070
11080
  "text",
11071
11081
  {
11072
- x: additionalLeftSpace + rightEdgeX + 8,
11082
+ x: additionalLeftSpace + x + 8,
11073
11083
  y: 10,
11074
11084
  fill: color,
11075
11085
  fontSize: 12,
@@ -11088,9 +11098,7 @@ const GanttTodayInner = ({
11088
11098
  showDataDateLine,
11089
11099
  dataDate,
11090
11100
  dataDateColor,
11091
- dataDateLabel,
11092
- rowHeight,
11093
- barFill
11101
+ dataDateLabel
11094
11102
  ]);
11095
11103
  return /* @__PURE__ */ jsxs("g", { className: "today", children: [
11096
11104
  dataDateElement,
@@ -4701,11 +4701,14 @@
4701
4701
  if (!containerEl) {
4702
4702
  return null;
4703
4703
  }
4704
- const scrollValue = containerEl[property];
4705
- const maxScrollValue = property === "scrollLeft" ? containerEl.scrollWidth : containerEl.scrollHeight;
4706
- const fullValue = property === "scrollLeft" ? containerEl.clientWidth : containerEl.clientHeight;
4707
- const firstIndex = Math.floor(scrollValue / cellSize);
4708
- const lastIndex = Math.ceil((scrollValue + fullValue) / cellSize) + 10;
4704
+ const el = containerEl;
4705
+ const scrollValue = property === "scrollLeft" ? el.scrollLeft : el.scrollTop;
4706
+ const maxScrollValue = property === "scrollLeft" ? el.scrollWidth : el.scrollHeight;
4707
+ const fullValue = property === "scrollLeft" ? el.clientWidth : el.clientHeight;
4708
+ const firstIndex = Math.max(0, Math.floor(scrollValue / cellSize));
4709
+ const visibleCount = Math.max(1, Math.ceil(fullValue / cellSize));
4710
+ const overscan = Math.min(100, Math.max(10, Math.ceil(visibleCount * 0.5)));
4711
+ const lastIndex = Math.floor((scrollValue + fullValue) / cellSize) + overscan;
4709
4712
  const isStartOfScroll = scrollValue < DELTA;
4710
4713
  const isEndOfScroll = scrollValue + fullValue > maxScrollValue - DELTA;
4711
4714
  return [firstIndex, lastIndex, isStartOfScroll, isEndOfScroll, fullValue];
@@ -4714,31 +4717,49 @@
4714
4717
  const [indexes, setIndexes] = React.useState(
4715
4718
  () => getStartAndEnd(containerRef.current, property, cellSize)
4716
4719
  );
4720
+ const rafRef = React.useRef(null);
4721
+ const pendingRef = React.useRef(false);
4722
+ const update = React.useMemo(() => {
4723
+ const fn = () => {
4724
+ pendingRef.current = false;
4725
+ const next = getStartAndEnd(containerRef.current, property, cellSize);
4726
+ setIndexes((prev) => {
4727
+ const changed = !prev || !next || next.some((v, i) => prev ? prev[i] !== v : true);
4728
+ return changed ? next : prev;
4729
+ });
4730
+ rafRef.current = null;
4731
+ };
4732
+ return fn;
4733
+ }, [cellSize, containerRef, property]);
4717
4734
  React.useEffect(() => {
4718
- let rafId = null;
4719
- let prevIndexes = indexes;
4720
- const handler = () => {
4721
- const nextIndexes = getStartAndEnd(
4722
- containerRef.current,
4723
- property,
4724
- cellSize
4725
- );
4726
- const isChanged = prevIndexes ? nextIndexes ? nextIndexes.some(
4727
- (value, index2) => !prevIndexes || prevIndexes[index2] !== value
4728
- ) : true : Boolean(nextIndexes);
4729
- if (isChanged) {
4730
- prevIndexes = nextIndexes;
4731
- setIndexes(nextIndexes);
4732
- }
4733
- rafId = requestAnimationFrame(handler);
4735
+ const el = containerRef.current;
4736
+ if (!el) {
4737
+ return void 0;
4738
+ }
4739
+ setIndexes(getStartAndEnd(el, property, cellSize));
4740
+ const onScroll = () => {
4741
+ if (pendingRef.current)
4742
+ return;
4743
+ pendingRef.current = true;
4744
+ rafRef.current = requestAnimationFrame(update);
4734
4745
  };
4735
- rafId = requestAnimationFrame(handler);
4746
+ const resizeObserver = new ResizeObserver(() => {
4747
+ if (pendingRef.current)
4748
+ return;
4749
+ pendingRef.current = true;
4750
+ rafRef.current = requestAnimationFrame(update);
4751
+ });
4752
+ resizeObserver.observe(el);
4753
+ el.addEventListener("scroll", onScroll, { passive: true });
4736
4754
  return () => {
4737
- if (rafId !== null) {
4738
- cancelAnimationFrame(rafId);
4755
+ el.removeEventListener("scroll", onScroll);
4756
+ resizeObserver.disconnect();
4757
+ if (rafRef.current !== null) {
4758
+ cancelAnimationFrame(rafRef.current);
4739
4759
  }
4760
+ pendingRef.current = false;
4740
4761
  };
4741
- }, [cellSize, containerRef, indexes, property]);
4762
+ }, [cellSize, containerRef, property, update]);
4742
4763
  return indexes;
4743
4764
  };
4744
4765
  const taskListNameWrapper = "_taskListNameWrapper_16z6n_1";
@@ -10928,7 +10949,7 @@
10928
10949
  };
10929
10950
  const GanttTodayInner = ({
10930
10951
  additionalLeftSpace,
10931
- distances,
10952
+ distances: { columnWidth },
10932
10953
  ganttFullHeight,
10933
10954
  isUnknownDates,
10934
10955
  rtl,
@@ -10942,7 +10963,6 @@
10942
10963
  todayLabel = "Today",
10943
10964
  dataDateLabel = "Data Date"
10944
10965
  }) => {
10945
- const { columnWidth, rowHeight, barFill } = distances;
10946
10966
  const todayElement = React.useMemo(() => {
10947
10967
  if (isUnknownDates || !showTodayLine) {
10948
10968
  return null;
@@ -11049,20 +11069,13 @@
11049
11069
  }
11050
11070
  };
11051
11071
  const tickX = dataIndex * columnWidth * extraMultiplier();
11052
- const dateBaseX = rtl ? tickX + columnWidth : tickX;
11072
+ const x = rtl ? tickX + columnWidth : tickX;
11053
11073
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11054
- const taskHeight = rowHeight * barFill / 100;
11055
- const rotatedHeight = taskHeight / Math.SQRT2;
11056
- const centerX = dateBaseX;
11057
- const centerY = 6;
11058
- const rectX = centerX - rotatedHeight / 2;
11059
- const rectY = centerY - rotatedHeight / 2;
11060
- const rightEdgeX = centerX + taskHeight / 2;
11061
11074
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11062
11075
  /* @__PURE__ */ jsxRuntime.jsx(
11063
11076
  "rect",
11064
11077
  {
11065
- x: additionalLeftSpace + rightEdgeX,
11078
+ x: additionalLeftSpace + x,
11066
11079
  y: 0,
11067
11080
  width: 2,
11068
11081
  height: ganttFullHeight,
@@ -11071,22 +11084,19 @@
11071
11084
  }
11072
11085
  ),
11073
11086
  /* @__PURE__ */ jsxRuntime.jsx(
11074
- "rect",
11087
+ "circle",
11075
11088
  {
11076
- x: additionalLeftSpace + rectX,
11077
- y: rectY,
11078
- width: rotatedHeight,
11079
- height: rotatedHeight,
11080
- fill: color,
11081
- transform: `rotate(45 ${additionalLeftSpace + centerX} ${centerY})`,
11082
- rx: 2,
11083
- ry: 2
11089
+ className: styles$c.ganttTodayCircle,
11090
+ cx: x + 1,
11091
+ cy: 6,
11092
+ r: 6,
11093
+ fill: color
11084
11094
  }
11085
11095
  ),
11086
11096
  /* @__PURE__ */ jsxRuntime.jsx(
11087
11097
  "text",
11088
11098
  {
11089
- x: additionalLeftSpace + rightEdgeX + 8,
11099
+ x: additionalLeftSpace + x + 8,
11090
11100
  y: 10,
11091
11101
  fill: color,
11092
11102
  fontSize: 12,
@@ -11105,9 +11115,7 @@
11105
11115
  showDataDateLine,
11106
11116
  dataDate,
11107
11117
  dataDateColor,
11108
- dataDateLabel,
11109
- rowHeight,
11110
- barFill
11118
+ dataDateLabel
11111
11119
  ]);
11112
11120
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "today", children: [
11113
11121
  dataDateElement,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.2.14",
3
+ "version": "1.3.0",
4
4
  "description": "Interactive Gantt Chart for React with TypeScript.",
5
5
  "author": "aguilanbon",
6
6
  "homepage": "https://github.com/aguilanbon/gantt-task-react-v",