From be74ad103aa754a7db219b71231f33742beaa89e Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Tue, 23 Jan 2024 17:53:44 +0100 Subject: [PATCH] :zap: (editor) Improve graph pan when dragging on groups --- .../components/GraphNavigationRadioGroup.tsx | 68 ------------------- .../components/UserPreferencesForm.tsx | 15 +--- .../src/features/graph/components/Graph.tsx | 12 ++-- .../components/nodes/block/BlockNode.tsx | 5 +- .../components/nodes/event/EventNode.tsx | 3 + .../components/nodes/group/GroupNode.tsx | 2 + .../features/graph/hooks/useGroupsStore.ts | 4 ++ apps/docs/editor/graph.mdx | 18 +++++ apps/docs/mint.json | 1 + 9 files changed, 40 insertions(+), 88 deletions(-) delete mode 100644 apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx create mode 100644 apps/docs/editor/graph.mdx diff --git a/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx b/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx deleted file mode 100644 index e66205032..000000000 --- a/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { MouseIcon, LaptopIcon } from '@/components/icons' -import { useTranslate } from '@tolgee/react' -import { - HStack, - Radio, - RadioGroup, - Stack, - VStack, - Text, -} from '@chakra-ui/react' -import { GraphNavigation } from '@typebot.io/prisma' - -type Props = { - defaultValue: string - onChange: (value: string) => void -} -export const GraphNavigationRadioGroup = ({ - defaultValue, - onChange, -}: Props) => { - const { t } = useTranslate() - const graphNavigationData = [ - { - value: GraphNavigation.MOUSE, - label: t('account.preferences.graphNavigation.mouse.label'), - description: t('account.preferences.graphNavigation.mouse.description'), - icon: , - }, - { - value: GraphNavigation.TRACKPAD, - label: t('account.preferences.graphNavigation.trackpad.label'), - description: t( - 'account.preferences.graphNavigation.trackpad.description' - ), - icon: , - }, - ] - return ( - - - {graphNavigationData.map((option) => ( - - - {option.icon} - - {option.label} - {option.description} - - - - - - ))} - - - ) -} diff --git a/apps/builder/src/features/account/components/UserPreferencesForm.tsx b/apps/builder/src/features/account/components/UserPreferencesForm.tsx index 52b3abc85..0604b4631 100644 --- a/apps/builder/src/features/account/components/UserPreferencesForm.tsx +++ b/apps/builder/src/features/account/components/UserPreferencesForm.tsx @@ -11,7 +11,6 @@ import { } from '@chakra-ui/react' import { GraphNavigation } from '@typebot.io/prisma' import React, { useEffect } from 'react' -import { GraphNavigationRadioGroup } from './GraphNavigationRadioGroup' import { AppearanceRadioGroup } from './AppearanceRadioGroup' import { useUser } from '../hooks/useUser' import { ChevronDownIcon } from '@/components/icons' @@ -42,10 +41,6 @@ export const UserPreferencesForm = () => { updateUser({ graphNavigation: GraphNavigation.TRACKPAD }) }, [updateUser, user?.graphNavigation]) - const changeGraphNavigation = async (value: string) => { - updateUser({ graphNavigation: value as GraphNavigation }) - } - const changeAppearance = async (value: string) => { updateUser({ preferredAppAppearance: value }) } @@ -99,15 +94,7 @@ export const UserPreferencesForm = () => { )} - - - {t('account.preferences.graphNavigation.heading')} - - - + {t('account.preferences.appearance.heading')} diff --git a/apps/builder/src/features/graph/components/Graph.tsx b/apps/builder/src/features/graph/components/Graph.tsx index 67ad470e1..047adce7e 100644 --- a/apps/builder/src/features/graph/components/Graph.tsx +++ b/apps/builder/src/features/graph/components/Graph.tsx @@ -63,6 +63,8 @@ export const Graph = ({ setPreviewingEdge, connectingIds, } = useGraph() + const isDraggingGraph = useGroupsStore((state) => state.isDraggingGraph) + const setIsDraggingGraph = useGroupsStore((state) => state.setIsDraggingGraph) const focusedGroups = useGroupsStore( useShallow((state) => state.focusedGroups) ) @@ -107,7 +109,6 @@ export const Graph = ({ const [lastMouseClickPosition, setLastMouseClickPosition] = useState< Coordinates | undefined >() - const [isSpacePressed, setIsSpacePressed] = useState(false) const [isDragging, setIsDragging] = useState(false) const graphContainerRef = useRef(null) @@ -172,6 +173,7 @@ export const Graph = ({ } const handlePointerUp = (e: PointerEvent) => { + if (isDraggingGraph) return if ( !selectBoxCoordinates || Math.abs(selectBoxCoordinates?.dimension.width) + @@ -192,7 +194,7 @@ export const Graph = ({ useGesture( { onDrag: (props) => { - if (isSpacePressed) { + if (isDraggingGraph) { if (props.first) setIsDragging(true) if (props.last) setIsDragging(false) setGraphPosition({ @@ -333,11 +335,11 @@ export const Graph = ({ }) useEventListener('keydown', (e) => { - if (e.key === ' ') setIsSpacePressed(true) + if (e.key === ' ') setIsDraggingGraph(true) }) useEventListener('keyup', (e) => { if (e.key === ' ') { - setIsSpacePressed(false) + setIsDraggingGraph(false) setIsDragging(false) } }) @@ -357,7 +359,7 @@ export const Graph = ({ const zoomIn = () => zoom({ delta: zoomButtonsScaleBlock }) const zoomOut = () => zoom({ delta: -zoomButtonsScaleBlock }) - const cursor = isSpacePressed ? (isDragging ? 'grabbing' : 'grab') : 'auto' + const cursor = isDraggingGraph ? (isDragging ? 'grabbing' : 'grab') : 'auto' return ( state.isDraggingGraph) + const onDrag = (position: NodePosition) => { if (!onMouseDown) return onMouseDown(position, block) @@ -212,7 +215,7 @@ export const BlockNode = ({ data-testid={`block ${block.id}`} w="full" className="prevent-group-drag" - pointerEvents={isReadOnly ? 'none' : 'auto'} + pointerEvents={isReadOnly || isDraggingGraph ? 'none' : 'auto'} > (null) const [debouncedEventPosition] = useDebounce(currentCoordinates, 100) const [isFocused, setIsFocused] = useState(false) + const isDraggingGraph = useGroupsStore((state) => state.isDraggingGraph) useOutsideClick({ handler: () => setIsFocused(false), @@ -172,6 +174,7 @@ const NonMemoizedDraggableEventNode = ({ shadow="md" _hover={{ shadow: 'lg' }} zIndex={isFocused ? 10 : 1} + pointerEvents={isDraggingGraph ? 'none' : 'auto'} > { isNotDefined(previewingEdge.to.blockId)))) const groupRef = useRef(null) + const isDraggingGraph = useGroupsStore((state) => state.isDraggingGraph) const focusedGroups = useGroupsStore( useShallow((state) => state.focusedGroups) ) @@ -192,6 +193,7 @@ export const GroupNode = ({ group, groupIndex }: Props) => { _hover={{ shadow: 'lg' }} zIndex={isFocused ? 10 : 1} spacing={isEmpty(group.title) ? '0' : '2'} + pointerEvents={isDraggingGraph ? 'none' : 'auto'} > CoordinatesMap | undefined focusGroup: (groupId: string, isAppending?: boolean) => void @@ -15,12 +16,14 @@ type Store = { setGroupsCoordinates: (groups: Group[] | undefined) => void updateGroupCoordinates: (groupId: string, newCoord: Coordinates) => void copyGroups: (groups: GroupV6[], edges: Edge[]) => void + setIsDraggingGraph: (isDragging: boolean) => void } export const useGroupsStore = createWithEqualityFn((set, get) => ({ focusedGroups: [], groupsCoordinates: undefined, groupsInClipboard: undefined, + isDraggingGraph: false, getGroupsCoordinates: () => get().groupsCoordinates, focusGroup: (groupId, isShiftKeyPressed) => set((state) => ({ @@ -80,4 +83,5 @@ export const useGroupsStore = createWithEqualityFn((set, get) => ({ edges, }, }), + setIsDraggingGraph: (isDragging) => set({ isDraggingGraph: isDragging }), })) diff --git a/apps/docs/editor/graph.mdx b/apps/docs/editor/graph.mdx new file mode 100644 index 000000000..74eda6ad0 --- /dev/null +++ b/apps/docs/editor/graph.mdx @@ -0,0 +1,18 @@ +--- +title: Graph +icon: game-board +--- + +import { LoomVideo } from '/snippets/loom-video.mdx' + +The Graph is where you arrange your conversation flow and connect the Typebot [blocks](./blocks/overview) together. + +## Gestures + +**Select**: `Left click` + `drag` + +**Zoom**: `Ctrl` + `Mouse wheel` on a mouse or `pinch` on a trackpad + +**Pan**: `Space` + `Mouse wheel` on a mouse or `two-finger drag` on a trackpad + + diff --git a/apps/docs/mint.json b/apps/docs/mint.json index 5ed8a464a..d1d4cb9d9 100644 --- a/apps/docs/mint.json +++ b/apps/docs/mint.json @@ -76,6 +76,7 @@ { "group": "Flow", "pages": [ + "editor/graph", { "group": "Blocks", "icon": "block",