2
0

🐛 (editor) Share groups clipboard state across tabs

This commit is contained in:
Baptiste Arnaud
2024-03-20 17:29:05 +01:00
parent 97107d4121
commit 5b9176708c
3 changed files with 87 additions and 80 deletions

View File

@ -84,6 +84,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"shared-zustand": "2.0.0",
"sonner": "1.3.1", "sonner": "1.3.1",
"stripe": "12.13.0", "stripe": "12.13.0",
"svg-round-corners": "0.4.1", "svg-round-corners": "0.4.1",
@ -97,12 +98,17 @@
"devDependencies": { "devDependencies": {
"@chakra-ui/styled-system": "2.9.1", "@chakra-ui/styled-system": "2.9.1",
"@playwright/test": "1.41.2", "@playwright/test": "1.41.2",
"@typebot.io/billing": "workspace:*",
"@typebot.io/forge": "workspace:*", "@typebot.io/forge": "workspace:*",
"@typebot.io/forge-repository": "workspace:*", "@typebot.io/forge-repository": "workspace:*",
"@typebot.io/lib": "workspace:*", "@typebot.io/lib": "workspace:*",
"@typebot.io/migrations": "workspace:*",
"@typebot.io/playwright": "workspace:*",
"@typebot.io/prisma": "workspace:*", "@typebot.io/prisma": "workspace:*",
"@typebot.io/radar": "workspace:*", "@typebot.io/radar": "workspace:*",
"@typebot.io/results": "workspace:*",
"@typebot.io/schemas": "workspace:*", "@typebot.io/schemas": "workspace:*",
"@typebot.io/telemetry": "workspace:*",
"@typebot.io/tsconfig": "workspace:*", "@typebot.io/tsconfig": "workspace:*",
"@types/canvas-confetti": "1.6.0", "@types/canvas-confetti": "1.6.0",
"@types/jsonwebtoken": "9.0.2", "@types/jsonwebtoken": "9.0.2",
@ -121,11 +127,6 @@
"next-runtime-env": "1.6.2", "next-runtime-env": "1.6.2",
"superjson": "1.12.4", "superjson": "1.12.4",
"typescript": "5.3.2", "typescript": "5.3.2",
"zod": "3.22.4", "zod": "3.22.4"
"@typebot.io/playwright": "workspace:*",
"@typebot.io/billing": "workspace:*",
"@typebot.io/results": "workspace:*",
"@typebot.io/migrations": "workspace:*",
"@typebot.io/telemetry": "workspace:*"
} }
} }

View File

@ -1,7 +1,8 @@
import { createWithEqualityFn } from 'zustand/traditional' import { createWithEqualityFn } from 'zustand/traditional'
import { Coordinates, CoordinatesMap } from '../types' import { Coordinates, CoordinatesMap } from '../types'
import { Edge, Group, GroupV6 } from '@typebot.io/schemas' import { Edge, Group, GroupV6 } from '@typebot.io/schemas'
import { persist } from 'zustand/middleware' import { subscribeWithSelector } from 'zustand/middleware'
import { share } from 'shared-zustand'
type Store = { type Store = {
focusedGroups: string[] focusedGroups: string[]
@ -21,80 +22,78 @@ type Store = {
} }
export const useGroupsStore = createWithEqualityFn<Store>()( export const useGroupsStore = createWithEqualityFn<Store>()(
persist( subscribeWithSelector((set, get) => ({
(set, get) => ({ focusedGroups: [],
focusedGroups: [], groupsCoordinates: undefined,
groupsCoordinates: undefined, groupsInClipboard: undefined,
groupsInClipboard: undefined, isDraggingGraph: false,
isDraggingGraph: false, getGroupsCoordinates: () => get().groupsCoordinates,
getGroupsCoordinates: () => get().groupsCoordinates, focusGroup: (groupId, isShiftKeyPressed) =>
focusGroup: (groupId, isShiftKeyPressed) => set((state) => ({
set((state) => ({ focusedGroups: isShiftKeyPressed
focusedGroups: isShiftKeyPressed ? state.focusedGroups.includes(groupId)
? state.focusedGroups.includes(groupId) ? state.focusedGroups.filter((id) => id !== groupId)
? state.focusedGroups.filter((id) => id !== groupId) : [...state.focusedGroups, groupId]
: [...state.focusedGroups, groupId] : [groupId],
: [groupId], })),
})), blurGroups: () => set({ focusedGroups: [] }),
blurGroups: () => set({ focusedGroups: [] }), moveFocusedGroups: (delta) =>
moveFocusedGroups: (delta) => set(({ focusedGroups, groupsCoordinates }) => ({
set(({ focusedGroups, groupsCoordinates }) => ({ groupsCoordinates: groupsCoordinates
groupsCoordinates: groupsCoordinates ? {
? { ...groupsCoordinates,
...groupsCoordinates, ...focusedGroups.reduce(
...focusedGroups.reduce( (coords, groupId) => ({
(coords, groupId) => ({
...coords,
[groupId]: {
x: Number(
(groupsCoordinates[groupId].x + delta.x).toFixed(2)
),
y: Number(
(groupsCoordinates[groupId].y + delta.y).toFixed(2)
),
},
}),
groupsCoordinates
),
}
: undefined,
})),
setFocusedGroups: (groupIds) => set({ focusedGroups: groupIds }),
setGroupsCoordinates: (groups) =>
set({
groupsCoordinates: groups
? groups.reduce(
(coords, group) => ({
...coords, ...coords,
[group.id]: { [groupId]: {
x: group.graphCoordinates.x, x: Number(
y: group.graphCoordinates.y, (groupsCoordinates[groupId].x + delta.x).toFixed(2)
),
y: Number(
(groupsCoordinates[groupId].y + delta.y).toFixed(2)
),
}, },
}), }),
{} groupsCoordinates
) ),
: undefined, }
}), : undefined,
updateGroupCoordinates: (groupId, newCoord) => { })),
set((state) => ({ setFocusedGroups: (groupIds) => set({ focusedGroups: groupIds }),
groupsCoordinates: { setGroupsCoordinates: (groups) =>
...state.groupsCoordinates, set({
[groupId]: newCoord, groupsCoordinates: groups
}, ? groups.reduce(
})) (coords, group) => ({
}, ...coords,
copyGroups: (groups, edges) => [group.id]: {
set({ x: group.graphCoordinates.x,
groupsInClipboard: { y: group.graphCoordinates.y,
groups, },
edges, }),
}, {}
}), )
setIsDraggingGraph: (isDragging) => set({ isDraggingGraph: isDragging }), : undefined,
}), }),
{ updateGroupCoordinates: (groupId, newCoord) => {
name: 'store', set((state) => ({
partialize: (state) => ({ groupsInClipboard: state.groupsInClipboard }), groupsCoordinates: {
} ...state.groupsCoordinates,
) [groupId]: newCoord,
},
}))
},
copyGroups: (groups, edges) =>
set({
groupsInClipboard: {
groups,
edges,
},
}),
setIsDraggingGraph: (isDragging) => set({ isDraggingGraph: isDragging }),
}))
) )
if ('BroadcastChannel' in globalThis) {
share('groupsInClipboard', useGroupsStore)
}

7
pnpm-lock.yaml generated
View File

@ -242,6 +242,9 @@ importers:
react-markdown: react-markdown:
specifier: ^9.0.1 specifier: ^9.0.1
version: 9.0.1(@types/react@18.2.15)(react@18.2.0) version: 9.0.1(@types/react@18.2.15)(react@18.2.0)
shared-zustand:
specifier: 2.0.0
version: 2.0.0
sonner: sonner:
specifier: 1.3.1 specifier: 1.3.1
version: 1.3.1(react-dom@18.2.0)(react@18.2.0) version: 1.3.1(react-dom@18.2.0)(react@18.2.0)
@ -20658,6 +20661,10 @@ packages:
/setprototypeof@1.2.0: /setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
/shared-zustand@2.0.0:
resolution: {integrity: sha512-DKBWe2w62wZif79XcUXStBBQ47T4y3XEApueseZ1O3wEsMbamDK01ac0zQNVj4MOH9Z5jesM2oLuug/79LPM1A==}
dev: false
/sharp@0.33.2: /sharp@0.33.2:
resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==} resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==}
engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0}