diff --git a/CHANGELOG.md b/CHANGELOG.md
index e9703c3..697304e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
## Unreleased
+* [Zoom shortcuts in context menu only on gantt area, not on item context menu](https://github.com/flower-platform/react-timeline-10000/pull/115)
* [ContextMenu: scrollable and always visible](https://github.com/flower-platform/react-timeline-10000/pull/114/changes)
## v2.15.0
diff --git a/demo-app/featurebook/testsAreDemo/ZoomTestsAreDemo.md b/demo-app/featurebook/testsAreDemo/ZoomTestsAreDemo.md
new file mode 100644
index 0000000..e285e12
--- /dev/null
+++ b/demo-app/featurebook/testsAreDemo/ZoomTestsAreDemo.md
@@ -0,0 +1,85 @@
+# Featurebook > ZoomTestsAreDemo.md
+Go to [Featurebook > Index](../FEATUREBOOK.md)
+
+## TOC
+
+* [`@Scenario` `whenRightClickOnGanttArea()`](#whenRightClickOnGanttArea)
+* [`@Scenario` `whenRightClickOnAnItem()`](#whenRightClickOnAnItem)
+* [`@Scenario` `whenMaxZoomOutClickZoomOut()`](#whenMaxZoomOutClickZoomOut)
+* [`@Scenario` `whenClickZoomIn()`](#whenClickZoomIn)
+* [`@Scenario` `whenClickZoomOut()`](#whenClickZoomOut)
+* [`@Scenario` `whenClickZoomReset()`](#whenClickZoomReset)
+* [`@Scenario` `whenClickZoomEnabled()`](#whenClickZoomEnabled)
+
+## Scenarios
+
+
+
+
+
+`@Scenario` `whenRightClickOnGanttArea()`
+ |
+|
+
+* WHEN right click on gantt area
+* THEN the zoom actions are available on the CM
+ |
+
+
+
+
+
+
+`@Scenario` `whenRightClickOnAnItem()`
+ |
+|
+
+* WHEN right click on an item
+* THEN the zoom actions are not available on the CM
+ |
+
+
+
+
+
+
+`@Scenario` `whenMaxZoomOutClickZoomOut()` **WHEN the gantt was maxim zoom out AND click on zoom out, THEN the startDate and endDate not changed**
+ |
+
+
+
+
+
+
+
+`@Scenario` `whenClickZoomIn()` **When click zoomIn from context menu, THEN zoomed in AND show the message `Zoomed in` with fade effect.**
+ |
+
+
+
+
+
+
+
+`@Scenario` `whenClickZoomOut()` **When click zoomOut from context menu, THEN zoomed out AND show the message `Zoomed out` with fade effect.**
+ |
+
+
+
+
+
+
+
+`@Scenario` `whenClickZoomReset()` **When click zoomReset from context menu, THEN zoomed reset AND show the message `Zoom reset` with fade effect.**
+ |
+
+
+
+
+
+
+
+`@Scenario` `whenClickZoomEnabled()` **When `Zoom enabled` is checked/unchecked AND we click zoomIn/zoomOut from context menu, THEN the gantt zooms/ doesn't zoom in accordingly**
+ |
+
+
diff --git a/demo-app/src/testsAreDemo/ZoomTestsAreDemo.tsx b/demo-app/src/testsAreDemo/ZoomTestsAreDemo.tsx
index ccaf053..9f2e973 100644
--- a/demo-app/src/testsAreDemo/ZoomTestsAreDemo.tsx
+++ b/demo-app/src/testsAreDemo/ZoomTestsAreDemo.tsx
@@ -3,7 +3,7 @@ import moment from "moment";
import { rightClick } from "./testUtils";
import { contextMenuTestIds } from "../../../src/components/ContextMenu/ContextMenu";
import { zoomStoriesTestIds } from "../stories/zoom/Zoom.stories";
-import Timeline, { ZOOM_PERCENT, timelineTestids as testids } from "../../../src/timeline";
+import Timeline, { ZOOM_IN_ACTION_LABEL, ZOOM_OUT_ACTION_LABEL, ZOOM_PERCENT, ZOOM_RESET_ACTION_LABEL, timelineTestids as testids } from "../../../src/timeline";
import { Main } from "../stories/zoom/Zoom.stories";
export class ZoomTestsAreDemo {
@@ -42,6 +42,45 @@ export class ZoomTestsAreDemo {
return { expetedStartDate: startDate, expetedEndDate: endDate };
}
+ /**
+ * * WHEN right click on gantt area
+ * * THEN the zoom actions are available on the CM
+ */
+ @Scenario()
+ async whenRightClickOnGanttArea() {
+ tad.ref("WHEN");
+ const firstRow = tad.screenCapturing.getByTestId('2_' + testids.row + "_0");
+ rightClick(firstRow, {
+ clientX: Math.round(firstRow.getBoundingClientRect().x) + 40,
+ clientY: Math.round(firstRow.getBoundingClientRect().y) + 40
+ });
+
+ tad.ref("THEN");
+ const popup = tad.screenCapturing.getByTestId(contextMenuTestIds.popup);
+ await tad.assertWaitable.exists(popup);
+ await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_0").textContent, ZOOM_IN_ACTION_LABEL);
+ await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_1").textContent, ZOOM_OUT_ACTION_LABEL);
+ await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_2").textContent, ZOOM_RESET_ACTION_LABEL);
+ }
+
+ /**
+ * * WHEN right click on an item
+ * * THEN the zoom actions are not available on the CM
+ */
+ @Scenario()
+ async whenRightClickOnAnItem() {
+ tad.ref("WHEN");
+ const segment = tad.screenCapturing.getByTestId('2_' + testids.item + "_0");
+ const rect = segment.getBoundingClientRect();
+ rightClick(segment, {
+ clientX: Math.round(rect.x + rect.width / 2),
+ clientY: Math.round(rect.y + rect.height / 2)
+ });
+ tad.ref("THEN");
+ await tad.assertWaitable.notExists(tad.screenCapturing.queryByTestId(contextMenuTestIds.popup));
+ }
+
+
@Scenario("WHEN the gantt was maxim zoom out AND click on zoom out, THEN the startDate and endDate not changed")
async whenMaxZoomOutClickZoomOut() {
const initialStartDate = this.timeline.state.startDate;
diff --git a/src/timeline.js b/src/timeline.js
index 6d6fa85..363c3f2 100644
--- a/src/timeline.js
+++ b/src/timeline.js
@@ -748,6 +748,11 @@ export default class Timeline extends React.Component {
param.closeContextMenu();
}
};
+ const ZOOM_BASE_ACTION = {
+ isVisible(param) {
+ return !param || !param.selection || param.selection.length === 0;
+ }
+ };
this.ZOOM_IN_ACTION = {
label: ZOOM_IN_ACTION_LABEL,
icon: 'zoom-in',
@@ -762,7 +767,8 @@ export default class Timeline extends React.Component {
that._gridDomNode.dispatchEvent(event);
params.dontCloseContextMenuAfterRunAutomatically = true;
that.startFadeOutEffect('Zoomed in');
- }
+ },
+ ...ZOOM_BASE_ACTION
};
this.ZOOM_OUT_ACTION = {
label: ZOOM_OUT_ACTION_LABEL,
@@ -778,7 +784,8 @@ export default class Timeline extends React.Component {
that._gridDomNode.dispatchEvent(event);
params.dontCloseContextMenuAfterRunAutomatically = true;
that.startFadeOutEffect('Zoomed out');
- }
+ },
+ ...ZOOM_BASE_ACTION
};
this.ZOOM_RESET_ACTION = {
label: ZOOM_RESET_ACTION_LABEL,
@@ -789,7 +796,8 @@ export default class Timeline extends React.Component {
endDate: this.props.useMoment ? moment(this.props.endDate) : this.props.endDate
});
that.startFadeOutEffect('Zoom reset');
- }
+ },
+ ...ZOOM_BASE_ACTION
};
}
@@ -2033,7 +2041,8 @@ export default class Timeline extends React.Component {
this.props.verticalGapBetweenOverlappingItems,
this.props.rowTopBottomPadding,
this.props.zIndexFunction,
- rowIndex
+ rowIndex,
+ this.props.componentId
)}
{rowLayerRenderer(
layersInRow,
diff --git a/src/utils/itemUtils.js b/src/utils/itemUtils.js
index 936734e..45a0e53 100644
--- a/src/utils/itemUtils.js
+++ b/src/utils/itemUtils.js
@@ -35,7 +35,8 @@ export function rowItemsRenderer(
verticalGapBetweenOverlappingItems,
rowTopBottomPadding,
zIndexFunction,
- rowIndex
+ rowIndex,
+ timelineComponentId = 'r9k1'
) {
const start_end_ms = vis_end.diff(vis_start, 'milliseconds');
const pixels_per_ms = total_width / start_end_ms;
@@ -79,7 +80,7 @@ export function rowItemsRenderer(
return (