Skip to content

Commit

Permalink
馃悰 (editor) Fix dragging text bubble after editting
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Jan 29, 2024
1 parent 0817fba commit 1ebfc15
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 32 deletions.
11 changes: 2 additions & 9 deletions apps/builder/src/features/graph/components/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ export const Graph = ({
const [groupRects, setGroupRects] = useState<
{ groupId: string; rect: DOMRect }[] | undefined
>()
const [lastMouseClickPosition, setLastMouseClickPosition] = useState<
Coordinates | undefined
>()
const [isDragging, setIsDragging] = useState(false)

const graphContainerRef = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -167,7 +164,7 @@ export const Graph = ({
if (isRightClick) e.stopPropagation()
}

const handlePointerUp = (e: PointerEvent) => {
const handlePointerUp = () => {
if (isDraggingGraph) return
if (
!selectBoxCoordinates ||
Expand All @@ -176,9 +173,6 @@ export const Graph = ({
5
) {
blurGroups()
setLastMouseClickPosition(
projectMouse({ x: e.clientX, y: e.clientY }, graphPosition)
)
}
setSelectBoxCoordinates(undefined)
setOpenedBlockId(undefined)
Expand Down Expand Up @@ -355,10 +349,9 @@ export const Graph = ({
{selectBoxCoordinates && <SelectBox {...selectBoxCoordinates} />}
<Fade in={!isReadOnly && focusedGroups.length > 1}>
<GroupSelectionMenu
lastMouseClickPosition={lastMouseClickPosition}
graphPosition={graphPosition}
focusedGroups={focusedGroups}
blurGroups={blurGroups}
graphPosition={graphPosition}
isReadOnly={isReadOnly}
/>
</Fade>
Expand Down
25 changes: 12 additions & 13 deletions apps/builder/src/features/graph/components/GroupSelectionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,29 @@ import {
useColorModeValue,
useEventListener,
} from '@chakra-ui/react'
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { useGroupsStore } from '../hooks/useGroupsStore'
import { toast } from 'sonner'
import { createId } from '@paralleldrive/cuid2'
import { Edge, GroupV6 } from '@typebot.io/schemas'
import { projectMouse } from '../helpers/projectMouse'
import { Coordinates } from '../types'
import { useShallow } from 'zustand/react/shallow'
import { projectMouse } from '../helpers/projectMouse'

type Props = {
graphPosition: Coordinates & { scale: number }
isReadOnly: boolean
lastMouseClickPosition: Coordinates | undefined
focusedGroups: string[]
blurGroups: () => void
}

export const GroupSelectionMenu = ({
graphPosition,
lastMouseClickPosition,
isReadOnly,
focusedGroups,
blurGroups,
}: Props) => {
const [mousePosition, setMousePosition] = useState<Coordinates>()
const { typebot, deleteGroups, pasteGroups } = useTypebot()
const ref = useRef<HTMLDivElement>(null)

Expand All @@ -50,6 +49,13 @@ export const GroupSelectionMenu = ({

useEventListener('pointerup', (e) => e.stopPropagation(), ref.current)

useEventListener('mousemove', (e) => {
setMousePosition({
x: e.clientX,
y: e.clientY,
})
})

const handleCopy = () => {
if (!typebot) return
const groups = typebot.groups.filter((g) => focusedGroups.includes(g.id))
Expand All @@ -72,18 +78,11 @@ export const GroupSelectionMenu = ({
groups: GroupV6[]
edges: Edge[]
}) => {
if (!groupsInClipboard || isReadOnly) return
if (!groupsInClipboard || isReadOnly || !mousePosition) return
const clipboard = overrideClipBoard ?? groupsInClipboard
const { groups, oldToNewIdsMapping } = parseGroupsToPaste(
clipboard.groups,
lastMouseClickPosition ??
projectMouse(
{
x: window.innerWidth / 2,
y: window.innerHeight / 2,
},
graphPosition
)
projectMouse(mousePosition, graphPosition)
)
groups.forEach((group) => {
updateGroupCoordinates(group.id, group.graphCoordinates)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const BlockNode = ({
ref: blockRef,
onDrag,
isDisabled: !onMouseDown,
deps: [isEditing],
})

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,13 @@ export const useDragDistance = ({
onDrag,
distanceTolerance = 20,
isDisabled = false,
deps = [],
}: {
ref: React.MutableRefObject<HTMLDivElement | null>
onDrag: (position: { absolute: Coordinates; relative: Coordinates }) => void
distanceTolerance?: number
isDisabled: boolean
deps?: unknown[]
}) => {
const mouseDownPosition = useRef<{
absolute: Coordinates
Expand All @@ -119,7 +121,7 @@ export const useDragDistance = ({
const handleMouseUp = () => {
if (mouseDownPosition) mouseDownPosition.current = undefined
}
useEventListener('mouseup', handleMouseUp)
useEventListener('mouseup', handleMouseUp, undefined, undefined, deps)

const handleMouseDown = (e: MouseEvent) => {
if (isDisabled || !ref.current) return
Expand All @@ -133,7 +135,7 @@ export const useDragDistance = ({
},
}
}
useEventListener('mousedown', handleMouseDown, ref)
useEventListener('mousedown', handleMouseDown, ref, undefined, deps)

useEffect(() => {
let triggered = false
Expand Down
32 changes: 24 additions & 8 deletions apps/builder/src/hooks/useEventListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ function useEventListener<K extends keyof MediaQueryListEventMap>(
eventName: K,
handler: (event: MediaQueryListEventMap[K]) => void,
element: RefObject<MediaQueryList>,
options?: Options
options?: Options,
deps?: unknown[]
): void

// Window Event based useEventListener interface
function useEventListener<K extends keyof WindowEventMap>(
eventName: K,
handler: (event: WindowEventMap[K]) => void,
element?: undefined,
options?: Options
options?: Options,
deps?: unknown[]
): void

// Element Event based useEventListener interface
Expand All @@ -28,15 +30,17 @@ function useEventListener<
eventName: K,
handler: (event: HTMLElementEventMap[K]) => void,
element: RefObject<T>,
options?: Options
options?: Options,
deps?: unknown[]
): void

// Document Event based useEventListener interface
function useEventListener<K extends keyof DocumentEventMap>(
eventName: K,
handler: (event: DocumentEventMap[K]) => void,
element: RefObject<Document>,
options?: Options
options?: Options,
deps?: unknown[]
): void

function useEventListener<
Expand All @@ -54,7 +58,8 @@ function useEventListener<
| Event
) => void,
element?: RefObject<T>,
options?: Options
options?: Options,
deps: unknown[] = []
) {
// Create a ref that stores handler
const savedHandler = useRef(handler)
Expand All @@ -72,7 +77,12 @@ function useEventListener<
if (!(targetElement && targetElement.addEventListener)) return

if (options && typeof options !== 'boolean')
console.log('Add event listener', { eventName, element, options })
console.log('Add event listener', {
elementText: (targetElement as HTMLElement).textContent,
eventName,
element: targetElement,
options,
})
// Create event listener that calls handler function stored in ref
const listener: typeof handler = (event) => savedHandler.current(event)

Expand All @@ -81,10 +91,16 @@ function useEventListener<
// Remove event listener on cleanup
return () => {
if (options && typeof options !== 'boolean')
console.log('Remove event listener')
console.log('Remove event listener', {
elementText: (targetElement as HTMLElement).textContent,
eventName,
element: targetElement,
options,
})
targetElement.removeEventListener(eventName, listener, options)
}
}, [eventName, element, options])
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eventName, ...deps])
}

export { useEventListener }
5 changes: 5 additions & 0 deletions apps/builder/src/hooks/useKeyboardShortcuts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isNotEmpty } from '@typebot.io/lib'
import { useEventListener } from './useEventListener'

type Props = {
Expand Down Expand Up @@ -40,6 +41,10 @@ export const useKeyboardShortcuts = ({
event.key === 'Backspace'

useEventListener('keydown', (event: KeyboardEvent) => {
if (!event.metaKey && !event.ctrlKey && event.key !== 'Backspace') return
// get text selection
const textSelection = window.getSelection()?.toString()
if (isNotEmpty(textSelection)) return
const target = event.target as HTMLElement | null
const isTyping =
target?.role === 'textbox' ||
Expand Down

0 comments on commit 1ebfc15

Please sign in to comment.