Merge pull request #3063 from wbkd/refactor/control-buttons
refactor(controls): disable min/max buttons when reached
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@reactflow/controls': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
disable min/max buttons when min/max is reached
|
||||||
@@ -39,7 +39,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reactflow/core": "workspace:*",
|
"@reactflow/core": "workspace:*",
|
||||||
"classcat": "^5.0.3"
|
"classcat": "^5.0.3",
|
||||||
|
"zustand": "^4.3.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=17",
|
"react": ">=17",
|
||||||
@@ -55,7 +56,9 @@
|
|||||||
},
|
},
|
||||||
"rollup": {
|
"rollup": {
|
||||||
"globals": {
|
"globals": {
|
||||||
"classcat": "cc"
|
"classcat": "cc",
|
||||||
|
"zustand": "Zustand",
|
||||||
|
"zustand/shallow": "zustandShallow"
|
||||||
},
|
},
|
||||||
"name": "ReactFlowControls"
|
"name": "ReactFlowControls"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { memo, useEffect, useState, type FC, type PropsWithChildren } from 'react';
|
import { memo, useEffect, useState, type FC, type PropsWithChildren } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
import { shallow } from 'zustand/shallow';
|
||||||
import { useStore, useStoreApi, useReactFlow, Panel, type ReactFlowState } from '@reactflow/core';
|
import { useStore, useStoreApi, useReactFlow, Panel, type ReactFlowState } from '@reactflow/core';
|
||||||
|
|
||||||
import PlusIcon from './Icons/Plus';
|
import PlusIcon from './Icons/Plus';
|
||||||
@@ -11,7 +12,11 @@ import ControlButton from './ControlButton';
|
|||||||
|
|
||||||
import type { ControlProps } from './types';
|
import type { ControlProps } from './types';
|
||||||
|
|
||||||
const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable || s.nodesConnectable || s.elementsSelectable;
|
const selector = (s: ReactFlowState) => ({
|
||||||
|
isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
|
||||||
|
minZoomReached: s.transform[2] <= s.minZoom,
|
||||||
|
maxZoomReached: s.transform[2] >= s.maxZoom,
|
||||||
|
});
|
||||||
|
|
||||||
const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
||||||
style,
|
style,
|
||||||
@@ -29,7 +34,7 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||||
const isInteractive = useStore(isInteractiveSelector);
|
const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector, shallow);
|
||||||
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -79,6 +84,7 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
|||||||
className="react-flow__controls-zoomin"
|
className="react-flow__controls-zoomin"
|
||||||
title="zoom in"
|
title="zoom in"
|
||||||
aria-label="zoom in"
|
aria-label="zoom in"
|
||||||
|
disabled={maxZoomReached}
|
||||||
>
|
>
|
||||||
<PlusIcon />
|
<PlusIcon />
|
||||||
</ControlButton>
|
</ControlButton>
|
||||||
@@ -87,6 +93,7 @@ const Controls: FC<PropsWithChildren<ControlProps>> = ({
|
|||||||
className="react-flow__controls-zoomout"
|
className="react-flow__controls-zoomout"
|
||||||
title="zoom out"
|
title="zoom out"
|
||||||
aria-label="zoom out"
|
aria-label="zoom out"
|
||||||
|
disabled={minZoomReached}
|
||||||
>
|
>
|
||||||
<MinusIcon />
|
<MinusIcon />
|
||||||
</ControlButton>
|
</ControlButton>
|
||||||
|
|||||||
@@ -24,5 +24,13 @@
|
|||||||
max-width: 12px;
|
max-width: 12px;
|
||||||
max-height: 12px;
|
max-height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill-opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+27
@@ -132,9 +132,11 @@ importers:
|
|||||||
'@types/react': '>=17'
|
'@types/react': '>=17'
|
||||||
classcat: ^5.0.3
|
classcat: ^5.0.3
|
||||||
typescript: ^4.9.4
|
typescript: ^4.9.4
|
||||||
|
zustand: ^4.3.1
|
||||||
dependencies:
|
dependencies:
|
||||||
'@reactflow/core': link:../core
|
'@reactflow/core': link:../core
|
||||||
classcat: registry.npmjs.org/classcat/5.0.4
|
classcat: registry.npmjs.org/classcat/5.0.4
|
||||||
|
zustand: registry.npmjs.org/zustand/4.3.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@reactflow/eslint-config': link:../../tooling/eslint-config
|
'@reactflow/eslint-config': link:../../tooling/eslint-config
|
||||||
'@reactflow/rollup-config': link:../../tooling/rollup-config
|
'@reactflow/rollup-config': link:../../tooling/rollup-config
|
||||||
@@ -7445,6 +7447,14 @@ packages:
|
|||||||
punycode: registry.npmjs.org/punycode/2.1.1
|
punycode: registry.npmjs.org/punycode/2.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmjs.org/use-sync-external-store/1.2.0:
|
||||||
|
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz}
|
||||||
|
name: use-sync-external-store
|
||||||
|
version: 1.2.0
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmjs.org/use-sync-external-store/1.2.0_react@18.2.0:
|
registry.npmjs.org/use-sync-external-store/1.2.0_react@18.2.0:
|
||||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz}
|
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz}
|
||||||
id: registry.npmjs.org/use-sync-external-store/1.2.0
|
id: registry.npmjs.org/use-sync-external-store/1.2.0
|
||||||
@@ -7786,6 +7796,23 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmjs.org/zustand/4.3.1:
|
||||||
|
resolution: {integrity: sha512-EVyo/eLlOTcJm/X5M00rwtbYFXwRVTaRteSvhtbTZUCQFJkNfIyHPiJ6Ke68MSWzcKHpPzvqNH4gC2ZS/sbNqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/zustand/-/zustand-4.3.1.tgz}
|
||||||
|
name: zustand
|
||||||
|
version: 4.3.1
|
||||||
|
engines: {node: '>=12.7.0'}
|
||||||
|
peerDependencies:
|
||||||
|
immer: '>=9.0'
|
||||||
|
react: '>=16.8'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
immer:
|
||||||
|
optional: true
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
use-sync-external-store: registry.npmjs.org/use-sync-external-store/1.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmjs.org/zustand/4.3.1_react@18.2.0:
|
registry.npmjs.org/zustand/4.3.1_react@18.2.0:
|
||||||
resolution: {integrity: sha512-EVyo/eLlOTcJm/X5M00rwtbYFXwRVTaRteSvhtbTZUCQFJkNfIyHPiJ6Ke68MSWzcKHpPzvqNH4gC2ZS/sbNqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/zustand/-/zustand-4.3.1.tgz}
|
resolution: {integrity: sha512-EVyo/eLlOTcJm/X5M00rwtbYFXwRVTaRteSvhtbTZUCQFJkNfIyHPiJ6Ke68MSWzcKHpPzvqNH4gC2ZS/sbNqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/zustand/-/zustand-4.3.1.tgz}
|
||||||
id: registry.npmjs.org/zustand/4.3.1
|
id: registry.npmjs.org/zustand/4.3.1
|
||||||
|
|||||||
Reference in New Issue
Block a user