diff --git a/example/tsconfig.tsbuildinfo b/example/tsconfig.tsbuildinfo
index 039bd6d5c..dec7891d1 100644
--- a/example/tsconfig.tsbuildinfo
+++ b/example/tsconfig.tsbuildinfo
@@ -396,7 +396,7 @@
"signature": "1444afb2d3c50b5a15354934187d75bc9a7ca2d10bf20fe9c79cbcd1f8548549",
"affectsGlobalScope": false
},
- "../tldraw/dist/types/state/tlstate.d.ts": {
+ "../tldraw/dist/types/state/state.d.ts": {
"version": "3a31dc5b6306ee6cff5e03e4a3ab1eda22f07231bc207f77807915e7c01a96a9",
"signature": "3a31dc5b6306ee6cff5e03e4a3ab1eda22f07231bc207f77807915e7c01a96a9",
"affectsGlobalScope": false
@@ -1245,9 +1245,9 @@
"../tldraw/dist/types/types.d.ts"
],
"../tldraw/dist/types/state/index.d.ts": [
- "../tldraw/dist/types/state/tlstate.d.ts"
+ "../tldraw/dist/types/state/state.d.ts"
],
- "../tldraw/dist/types/state/tlstate.d.ts": [
+ "../tldraw/dist/types/state/state.d.ts": [
"../../node_modules/rko/dist/types/index.d.ts",
"../core/dist/types/index.d.ts",
"../tldraw/dist/types/types.d.ts"
@@ -1621,9 +1621,9 @@
"../tldraw/dist/types/types.d.ts"
],
"../tldraw/dist/types/state/index.d.ts": [
- "../tldraw/dist/types/state/tlstate.d.ts"
+ "../tldraw/dist/types/state/state.d.ts"
],
- "../tldraw/dist/types/state/tlstate.d.ts": [
+ "../tldraw/dist/types/state/state.d.ts": [
"../../node_modules/rko/dist/types/index.d.ts",
"../core/dist/types/index.d.ts",
"../tldraw/dist/types/types.d.ts"
@@ -1792,7 +1792,7 @@
"../tldraw/dist/types/shape/shape-styles.d.ts",
"../tldraw/dist/types/shape/shape-utils.d.ts",
"../tldraw/dist/types/state/index.d.ts",
- "../tldraw/dist/types/state/tlstate.d.ts",
+ "../tldraw/dist/types/state/state.d.ts",
"../tldraw/dist/types/types.d.ts"
]
},
diff --git a/packages/tldraw/CHANGELOG.md b/packages/tldraw/CHANGELOG.md
index b6c00afb0..0480652f0 100644
--- a/packages/tldraw/CHANGELOG.md
+++ b/packages/tldraw/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 0.1.6
+## 0.1.4
- UI bug fixes.
diff --git a/packages/tldraw/README.md b/packages/tldraw/README.md
index 7ffec82fd..5f23103ea 100644
--- a/packages/tldraw/README.md
+++ b/packages/tldraw/README.md
@@ -32,7 +32,21 @@ function App() {
}
```
-You can control the `TLDraw` component through props:
+### Persisting the State
+
+You can use the `id` to persist the state in a user's browser storage.
+
+```tsx
+import { TLDraw } from '@tldraw/tldraw'
+
+function App() {
+ return
+}
+```
+
+### Controlling the Component through Props
+
+You can control the `TLDraw` component through its props.
```tsx
import { TLDraw, TLDrawDocument } from '@tldraw/tldraw'
@@ -44,22 +58,40 @@ function App() {
}
```
-Or imperatively through the `TLDrawState` instance:
+### Controlling the Component through the TLDrawState API
+
+You can also control the `TLDraw` component imperatively through the `TLDrawState` API.
```tsx
import { TLDraw, TLDrawState } from '@tldraw/tldraw'
function App() {
- const handleMount = React.useCallback((tlstate: TLDrawState) => {
- const myDocument: TLDrawDocument = {}
-
- tlstate.loadDocument(myDocument).selectAll()
+ const handleMount = React.useCallback((state: TLDrawState) => {
+ state.selectAll()
}, [])
return
}
```
+Internally, the `TLDraw` component's user interface uses this API to make changes to the component's state. See the `TLDrawState` section for more on this API.
+
+### Responding to Changes
+
+You can respond to changes and user actions using the `onChange` callback.
+
+```tsx
+import { TLDraw, TLDrawState } from '@tldraw/tldraw'
+
+function App() {
+ const handleChange = React.useCallback((state: TLDrawState, reason: string) => {}, [])
+
+ return
+}
+```
+
+Internally, the `TLDraw` component's user interface uses this API to make changes to the component's state. See the `TLDrawState` section for more on this API.
+
## Documentation
### `TLDraw`
diff --git a/packages/tldraw/package.json b/packages/tldraw/package.json
index 664c33939..4272a9ca2 100644
--- a/packages/tldraw/package.json
+++ b/packages/tldraw/package.json
@@ -53,7 +53,7 @@
"@tldraw/vec": "^0.1.3",
"perfect-freehand": "^1.0.16",
"react-hotkeys-hook": "^3.4.0",
- "rko": "^0.6.0",
+ "rko": "^0.6.2",
"tslib": "^2.3.1"
},
"devDependencies": {
diff --git a/packages/tldraw/src/TLDraw.tsx b/packages/tldraw/src/TLDraw.tsx
index 201244abb..e937aeea4 100644
--- a/packages/tldraw/src/TLDraw.tsx
+++ b/packages/tldraw/src/TLDraw.tsx
@@ -2,8 +2,8 @@ import * as React from 'react'
import { IdProvider } from '@radix-ui/react-id'
import { Renderer } from '@tldraw/core'
import { styled, dark } from '~styles'
-import { Data, TLDrawDocument, TLDrawStatus, TLDrawUser } from '~types'
-import { TLDrawState } from '~state'
+import { TLDrawSnapshot, TLDrawDocument, TLDrawStatus, TLDrawUser } from '~types'
+import { TLDrawCallbacks, TLDrawState } from '~state'
import {
TLDrawContext,
TLDrawContextType,
@@ -19,9 +19,9 @@ import { ContextMenu } from '~components/ContextMenu'
import { FocusButton } from '~components/FocusButton/FocusButton'
// Selectors
-const isInSelectSelector = (s: Data) => s.appState.activeTool === 'select'
+const isInSelectSelector = (s: TLDrawSnapshot) => s.appState.activeTool === 'select'
-const isHideBoundsShapeSelector = (s: Data) => {
+const isHideBoundsShapeSelector = (s: TLDrawSnapshot) => {
const { shapes } = s.document.pages[s.appState.currentPageId]
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
return (
@@ -30,17 +30,17 @@ const isHideBoundsShapeSelector = (s: Data) => {
)
}
-const pageSelector = (s: Data) => s.document.pages[s.appState.currentPageId]
+const pageSelector = (s: TLDrawSnapshot) => s.document.pages[s.appState.currentPageId]
-const snapLinesSelector = (s: Data) => s.appState.snapLines
+const snapLinesSelector = (s: TLDrawSnapshot) => s.appState.snapLines
-const usersSelector = (s: Data) => s.room?.users
+const usersSelector = (s: TLDrawSnapshot) => s.room?.users
-const pageStateSelector = (s: Data) => s.document.pageStates[s.appState.currentPageId]
+const pageStateSelector = (s: TLDrawSnapshot) => s.document.pageStates[s.appState.currentPageId]
-const settingsSelector = (s: Data) => s.settings
+const settingsSelector = (s: TLDrawSnapshot) => s.settings
-export interface TLDrawProps {
+export interface TLDrawProps extends TLDrawCallbacks {
/**
* (optional) If provided, the component will load / persist state under this key.
*/
@@ -100,12 +100,6 @@ export interface TLDrawProps {
* (optional) A callback to run when the component mounts.
*/
onMount?: (state: TLDrawState) => void
-
- /**
- * (optional) A callback to run when the component's state changes.
- */
- onChange?: TLDrawState['_onChange']
-
/**
* (optional) A callback to run when the user creates a new project through the menu or through a keyboard shortcut.
*/
@@ -130,10 +124,35 @@ export interface TLDrawProps {
* (optional) A callback to run when the user signs out via the menu.
*/
onSignOut?: (state: TLDrawState) => void
+
/**
* (optional) A callback to run when the user creates a new project.
*/
onUserChange?: (state: TLDrawState, user: TLDrawUser) => void
+ /**
+ * (optional) A callback to run when the component's state changes.
+ */
+ onChange?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the state is patched.
+ */
+ onPatch?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the state is changed with a command.
+ */
+ onCommand?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the state is persisted.
+ */
+ onPersist?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user undos.
+ */
+ onUndo?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user redos.
+ */
+ onRedo?: (state: TLDrawState) => void
}
export function TLDraw({
@@ -157,57 +176,85 @@ export function TLDraw({
onOpenProject,
onSignOut,
onSignIn,
+ onUndo,
+ onRedo,
+ onPersist,
+ onPatch,
+ onCommand,
}: TLDrawProps) {
const [sId, setSId] = React.useState(id)
- const [tlstate, setTlstate] = React.useState(
- () => new TLDrawState(id, onMount, onChange, onUserChange)
- )
+ const [state, setState] = React.useState(() => new TLDrawState(id))
+
const [context, setContext] = React.useState
(() => ({
- tlstate,
- useSelector: tlstate.useStore,
- callbacks: {
- onNewProject,
- onSaveProject,
- onSaveProjectAs,
- onOpenProject,
- onSignIn,
- onSignOut,
- },
+ state,
+ useSelector: state.useStore,
}))
React.useEffect(() => {
if (id === sId) return
- // If a new id is loaded, replace the entire state
+ const newState = new TLDrawState(id)
+
setSId(id)
- const newState = new TLDrawState(id, onMount, onChange, onUserChange)
- setTlstate(newState)
+
setContext((ctx) => ({
...ctx,
- tlstate: newState,
+ state: newState,
useSelector: newState.useStore,
}))
+
+ setState(newState)
}, [sId, id])
- // Update the callbacks when any callback changes
React.useEffect(() => {
- setContext((ctx) => ({
- ...ctx,
- callbacks: {
- onNewProject,
- onSaveProject,
- onSaveProjectAs,
- onOpenProject,
- onSignIn,
- onSignOut,
- },
- }))
- }, [onNewProject, onSaveProject, onSaveProjectAs, onOpenProject, onSignIn, onSignOut])
+ state.readOnly = readOnly
+ }, [state, readOnly])
React.useEffect(() => {
- tlstate.readOnly = readOnly
- }, [tlstate, readOnly])
+ if (!document) return
+
+ if (document.id === state.document.id) {
+ state.updateDocument(document)
+ } else {
+ state.loadDocument(document)
+ }
+ }, [document, state])
+
+ React.useEffect(() => {
+ state.callbacks = {
+ onMount,
+ onChange,
+ onUserChange,
+ onNewProject,
+ onSaveProject,
+ onSaveProjectAs,
+ onOpenProject,
+ onSignOut,
+ onSignIn,
+ onUndo,
+ onRedo,
+ onPatch,
+ onCommand,
+ onPersist,
+ }
+ }, [
+ state,
+ onMount,
+ onChange,
+ onUserChange,
+ onNewProject,
+ onSaveProject,
+ onSaveProjectAs,
+ onOpenProject,
+ onSignOut,
+ onSignIn,
+ onUndo,
+ onRedo,
+ onPatch,
+ onCommand,
+ onPersist,
+ ])
// Use the `key` to ensure that new selector hooks are made when the id changes
return (
@@ -217,7 +264,6 @@ export function TLDraw({
key={sId || 'tldraw'}
id={sId}
currentPageId={currentPageId}
- document={document}
autofocus={autofocus}
showPages={showPages}
showMenu={showMenu}
@@ -243,10 +289,9 @@ interface InnerTLDrawProps {
showUI: boolean
showTools: boolean
readOnly: boolean
- document?: TLDrawDocument
}
-function InnerTldraw({
+const InnerTldraw = React.memo(function InnerTldraw({
id,
currentPageId,
autofocus,
@@ -257,9 +302,8 @@ function InnerTldraw({
showTools,
readOnly,
showUI,
- document,
}: InnerTLDrawProps) {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const rWrapper = React.useRef(null)
@@ -277,11 +321,11 @@ function InnerTldraw({
const isHideBoundsShape = useSelector(isHideBoundsShapeSelector)
- const isInSession = tlstate.session !== undefined
+ const isInSession = state.session !== undefined
// Hide bounds when not using the select tool, or when the only selected shape has handles
const hideBounds =
- (isInSession && tlstate.session?.constructor.name !== 'BrushSession') ||
+ (isInSession && state.session?.constructor.name !== 'BrushSession') ||
!isSelecting ||
isHideBoundsShape ||
!!pageState.editingId
@@ -291,7 +335,7 @@ function InnerTldraw({
// Hide indicators when not using the select tool, or when in session
const hideIndicators =
- (isInSession && tlstate.appState.status !== TLDrawStatus.Brushing) || !isSelecting
+ (isInSession && state.appState.status !== TLDrawStatus.Brushing) || !isSelecting
// Custom rendering meta, with dark mode for shapes
const meta = React.useMemo(() => ({ isDarkMode: settings.isDarkMode }), [settings.isDarkMode])
@@ -312,22 +356,10 @@ function InnerTldraw({
return {}
}, [settings.isDarkMode])
- React.useEffect(() => {
- if (!document) return
-
- if (document.id === tlstate.document.id) {
- console.log('updating')
- tlstate.updateDocument(document)
- } else {
- console.log('loading')
- tlstate.loadDocument(document)
- }
- }, [document, tlstate])
-
React.useEffect(() => {
if (!currentPageId) return
- tlstate.changePage(currentPageId)
- }, [currentPageId, tlstate])
+ state.changePage(currentPageId)
+ }, [currentPageId, state])
return (
@@ -341,7 +373,7 @@ function InnerTldraw({
pageState={pageState}
snapLines={snapLines}
users={users}
- userId={tlstate.state.room?.userId}
+ userId={state.state.room?.userId}
theme={theme}
meta={meta}
hideBounds={hideBounds}
@@ -350,61 +382,61 @@ function InnerTldraw({
hideBindingHandles={!settings.showBindingHandles}
hideCloneHandles={!settings.showCloneHandles}
hideRotateHandles={!settings.showRotateHandles}
- onPinchStart={tlstate.onPinchStart}
- onPinchEnd={tlstate.onPinchEnd}
- onPinch={tlstate.onPinch}
- onPan={tlstate.onPan}
- onZoom={tlstate.onZoom}
- onPointerDown={tlstate.onPointerDown}
- onPointerMove={tlstate.onPointerMove}
- onPointerUp={tlstate.onPointerUp}
- onPointCanvas={tlstate.onPointCanvas}
- onDoubleClickCanvas={tlstate.onDoubleClickCanvas}
- onRightPointCanvas={tlstate.onRightPointCanvas}
- onDragCanvas={tlstate.onDragCanvas}
- onReleaseCanvas={tlstate.onReleaseCanvas}
- onPointShape={tlstate.onPointShape}
- onDoubleClickShape={tlstate.onDoubleClickShape}
- onRightPointShape={tlstate.onRightPointShape}
- onDragShape={tlstate.onDragShape}
- onHoverShape={tlstate.onHoverShape}
- onUnhoverShape={tlstate.onUnhoverShape}
- onReleaseShape={tlstate.onReleaseShape}
- onPointBounds={tlstate.onPointBounds}
- onDoubleClickBounds={tlstate.onDoubleClickBounds}
- onRightPointBounds={tlstate.onRightPointBounds}
- onDragBounds={tlstate.onDragBounds}
- onHoverBounds={tlstate.onHoverBounds}
- onUnhoverBounds={tlstate.onUnhoverBounds}
- onReleaseBounds={tlstate.onReleaseBounds}
- onPointBoundsHandle={tlstate.onPointBoundsHandle}
- onDoubleClickBoundsHandle={tlstate.onDoubleClickBoundsHandle}
- onRightPointBoundsHandle={tlstate.onRightPointBoundsHandle}
- onDragBoundsHandle={tlstate.onDragBoundsHandle}
- onHoverBoundsHandle={tlstate.onHoverBoundsHandle}
- onUnhoverBoundsHandle={tlstate.onUnhoverBoundsHandle}
- onReleaseBoundsHandle={tlstate.onReleaseBoundsHandle}
- onPointHandle={tlstate.onPointHandle}
- onDoubleClickHandle={tlstate.onDoubleClickHandle}
- onRightPointHandle={tlstate.onRightPointHandle}
- onDragHandle={tlstate.onDragHandle}
- onHoverHandle={tlstate.onHoverHandle}
- onUnhoverHandle={tlstate.onUnhoverHandle}
- onReleaseHandle={tlstate.onReleaseHandle}
- onError={tlstate.onError}
- onRenderCountChange={tlstate.onRenderCountChange}
- onShapeChange={tlstate.onShapeChange}
- onShapeBlur={tlstate.onShapeBlur}
- onShapeClone={tlstate.onShapeClone}
- onBoundsChange={tlstate.updateBounds}
- onKeyDown={tlstate.onKeyDown}
- onKeyUp={tlstate.onKeyUp}
+ onPinchStart={state.onPinchStart}
+ onPinchEnd={state.onPinchEnd}
+ onPinch={state.onPinch}
+ onPan={state.onPan}
+ onZoom={state.onZoom}
+ onPointerDown={state.onPointerDown}
+ onPointerMove={state.onPointerMove}
+ onPointerUp={state.onPointerUp}
+ onPointCanvas={state.onPointCanvas}
+ onDoubleClickCanvas={state.onDoubleClickCanvas}
+ onRightPointCanvas={state.onRightPointCanvas}
+ onDragCanvas={state.onDragCanvas}
+ onReleaseCanvas={state.onReleaseCanvas}
+ onPointShape={state.onPointShape}
+ onDoubleClickShape={state.onDoubleClickShape}
+ onRightPointShape={state.onRightPointShape}
+ onDragShape={state.onDragShape}
+ onHoverShape={state.onHoverShape}
+ onUnhoverShape={state.onUnhoverShape}
+ onReleaseShape={state.onReleaseShape}
+ onPointBounds={state.onPointBounds}
+ onDoubleClickBounds={state.onDoubleClickBounds}
+ onRightPointBounds={state.onRightPointBounds}
+ onDragBounds={state.onDragBounds}
+ onHoverBounds={state.onHoverBounds}
+ onUnhoverBounds={state.onUnhoverBounds}
+ onReleaseBounds={state.onReleaseBounds}
+ onPointBoundsHandle={state.onPointBoundsHandle}
+ onDoubleClickBoundsHandle={state.onDoubleClickBoundsHandle}
+ onRightPointBoundsHandle={state.onRightPointBoundsHandle}
+ onDragBoundsHandle={state.onDragBoundsHandle}
+ onHoverBoundsHandle={state.onHoverBoundsHandle}
+ onUnhoverBoundsHandle={state.onUnhoverBoundsHandle}
+ onReleaseBoundsHandle={state.onReleaseBoundsHandle}
+ onPointHandle={state.onPointHandle}
+ onDoubleClickHandle={state.onDoubleClickHandle}
+ onRightPointHandle={state.onRightPointHandle}
+ onDragHandle={state.onDragHandle}
+ onHoverHandle={state.onHoverHandle}
+ onUnhoverHandle={state.onUnhoverHandle}
+ onReleaseHandle={state.onReleaseHandle}
+ onError={state.onError}
+ onRenderCountChange={state.onRenderCountChange}
+ onShapeChange={state.onShapeChange}
+ onShapeBlur={state.onShapeBlur}
+ onShapeClone={state.onShapeClone}
+ onBoundsChange={state.updateBounds}
+ onKeyDown={state.onKeyDown}
+ onKeyUp={state.onKeyUp}
/>
{showUI && (
{settings.isFocusMode ? (
-
+
) : (
<>
)
-}
+})
const OneOff = React.memo(function OneOff({
focusableRef,
diff --git a/packages/tldraw/src/components/ContextMenu/ContextMenu.tsx b/packages/tldraw/src/components/ContextMenu/ContextMenu.tsx
index a026c037e..acea35bb4 100644
--- a/packages/tldraw/src/components/ContextMenu/ContextMenu.tsx
+++ b/packages/tldraw/src/components/ContextMenu/ContextMenu.tsx
@@ -2,7 +2,7 @@ import * as React from 'react'
import { styled } from '~styles'
import * as RadixContextMenu from '@radix-ui/react-context-menu'
import { useTLDrawContext } from '~hooks'
-import { Data, AlignType, DistributeType, StretchType } from '~types'
+import { TLDrawSnapshot, AlignType, DistributeType, StretchType } from '~types'
import {
AlignBottomIcon,
AlignCenterHorizontallyIcon,
@@ -21,21 +21,21 @@ import { CMTriggerButton } from './CMTriggerButton'
import { Divider } from '~components/Divider'
import { MenuContent } from '~components/MenuContent'
-const has1SelectedIdsSelector = (s: Data) => {
+const has1SelectedIdsSelector = (s: TLDrawSnapshot) => {
return s.document.pageStates[s.appState.currentPageId].selectedIds.length > 0
}
-const has2SelectedIdsSelector = (s: Data) => {
+const has2SelectedIdsSelector = (s: TLDrawSnapshot) => {
return s.document.pageStates[s.appState.currentPageId].selectedIds.length > 1
}
-const has3SelectedIdsSelector = (s: Data) => {
+const has3SelectedIdsSelector = (s: TLDrawSnapshot) => {
return s.document.pageStates[s.appState.currentPageId].selectedIds.length > 2
}
-const isDebugModeSelector = (s: Data) => {
+const isDebugModeSelector = (s: TLDrawSnapshot) => {
return s.settings.isDebugMode
}
-const hasGroupSelectedSelector = (s: Data) => {
+const hasGroupSelectedSelector = (s: TLDrawSnapshot) => {
return s.document.pageStates[s.appState.currentPageId].selectedIds.some(
(id) => s.document.pages[s.appState.currentPageId].shapes[id].children !== undefined
)
@@ -48,7 +48,7 @@ interface ContextMenuProps {
}
export const ContextMenu = ({ children }: ContextMenuProps): JSX.Element => {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const hasSelection = useSelector(has1SelectedIdsSelector)
const hasTwoOrMore = useSelector(has2SelectedIdsSelector)
const hasThreeOrMore = useSelector(has3SelectedIdsSelector)
@@ -58,64 +58,64 @@ export const ContextMenu = ({ children }: ContextMenuProps): JSX.Element => {
const rContent = React.useRef(null)
const handleFlipHorizontal = React.useCallback(() => {
- tlstate.flipHorizontal()
- }, [tlstate])
+ state.flipHorizontal()
+ }, [state])
const handleFlipVertical = React.useCallback(() => {
- tlstate.flipVertical()
- }, [tlstate])
+ state.flipVertical()
+ }, [state])
const handleDuplicate = React.useCallback(() => {
- tlstate.duplicate()
- }, [tlstate])
+ state.duplicate()
+ }, [state])
const handleGroup = React.useCallback(() => {
- tlstate.group()
- }, [tlstate])
+ state.group()
+ }, [state])
const handleMoveToBack = React.useCallback(() => {
- tlstate.moveToBack()
- }, [tlstate])
+ state.moveToBack()
+ }, [state])
const handleMoveBackward = React.useCallback(() => {
- tlstate.moveBackward()
- }, [tlstate])
+ state.moveBackward()
+ }, [state])
const handleMoveForward = React.useCallback(() => {
- tlstate.moveForward()
- }, [tlstate])
+ state.moveForward()
+ }, [state])
const handleMoveToFront = React.useCallback(() => {
- tlstate.moveToFront()
- }, [tlstate])
+ state.moveToFront()
+ }, [state])
const handleDelete = React.useCallback(() => {
- tlstate.delete()
- }, [tlstate])
+ state.delete()
+ }, [state])
const handleCopyJson = React.useCallback(() => {
- tlstate.copyJson()
- }, [tlstate])
+ state.copyJson()
+ }, [state])
const handleCopy = React.useCallback(() => {
- tlstate.copy()
- }, [tlstate])
+ state.copy()
+ }, [state])
const handlePaste = React.useCallback(() => {
- tlstate.paste()
- }, [tlstate])
+ state.paste()
+ }, [state])
const handleCopySvg = React.useCallback(() => {
- tlstate.copySvg()
- }, [tlstate])
+ state.copySvg()
+ }, [state])
const handleUndo = React.useCallback(() => {
- tlstate.undo()
- }, [tlstate])
+ state.undo()
+ }, [state])
const handleRedo = React.useCallback(() => {
- tlstate.redo()
- }, [tlstate])
+ state.redo()
+ }, [state])
return (
@@ -207,47 +207,47 @@ function AlignDistributeSubMenu({
hasTwoOrMore: boolean
hasThreeOrMore: boolean
}) {
- const { tlstate } = useTLDrawContext()
+ const { state } = useTLDrawContext()
const alignTop = React.useCallback(() => {
- tlstate.align(AlignType.Top)
- }, [tlstate])
+ state.align(AlignType.Top)
+ }, [state])
const alignCenterVertical = React.useCallback(() => {
- tlstate.align(AlignType.CenterVertical)
- }, [tlstate])
+ state.align(AlignType.CenterVertical)
+ }, [state])
const alignBottom = React.useCallback(() => {
- tlstate.align(AlignType.Bottom)
- }, [tlstate])
+ state.align(AlignType.Bottom)
+ }, [state])
const stretchVertically = React.useCallback(() => {
- tlstate.stretch(StretchType.Vertical)
- }, [tlstate])
+ state.stretch(StretchType.Vertical)
+ }, [state])
const distributeVertically = React.useCallback(() => {
- tlstate.distribute(DistributeType.Vertical)
- }, [tlstate])
+ state.distribute(DistributeType.Vertical)
+ }, [state])
const alignLeft = React.useCallback(() => {
- tlstate.align(AlignType.Left)
- }, [tlstate])
+ state.align(AlignType.Left)
+ }, [state])
const alignCenterHorizontal = React.useCallback(() => {
- tlstate.align(AlignType.CenterHorizontal)
- }, [tlstate])
+ state.align(AlignType.CenterHorizontal)
+ }, [state])
const alignRight = React.useCallback(() => {
- tlstate.align(AlignType.Right)
- }, [tlstate])
+ state.align(AlignType.Right)
+ }, [state])
const stretchHorizontally = React.useCallback(() => {
- tlstate.stretch(StretchType.Horizontal)
- }, [tlstate])
+ state.stretch(StretchType.Horizontal)
+ }, [state])
const distributeHorizontally = React.useCallback(() => {
- tlstate.distribute(DistributeType.Horizontal)
- }, [tlstate])
+ state.distribute(DistributeType.Horizontal)
+ }, [state])
return (
@@ -311,11 +311,11 @@ const StyledGridContent = styled(MenuContent, {
/* ------------------ Move to Page ------------------ */
-const currentPageIdSelector = (s: Data) => s.appState.currentPageId
-const documentPagesSelector = (s: Data) => s.document.pages
+const currentPageIdSelector = (s: TLDrawSnapshot) => s.appState.currentPageId
+const documentPagesSelector = (s: TLDrawSnapshot) => s.document.pages
function MoveToPageMenu(): JSX.Element | null {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const currentPageId = useSelector(currentPageIdSelector)
const documentPages = useSelector(documentPagesSelector)
@@ -334,7 +334,7 @@ function MoveToPageMenu(): JSX.Element | null {
tlstate.moveToPage(id)}
+ onSelect={() => state.moveToPage(id)}
>
{name || `Page ${i}`}
diff --git a/packages/tldraw/src/components/ToolsPanel/ActionButton.tsx b/packages/tldraw/src/components/ToolsPanel/ActionButton.tsx
index e6f31aa17..4aec1cb51 100644
--- a/packages/tldraw/src/components/ToolsPanel/ActionButton.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/ActionButton.tsx
@@ -3,7 +3,7 @@ import { Tooltip } from '~components/Tooltip/Tooltip'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { useTLDrawContext } from '~hooks'
import { styled } from '~styles'
-import { AlignType, Data, DistributeType, StretchType } from '~types'
+import { AlignType, TLDrawSnapshot, DistributeType, StretchType } from '~types'
import {
ArrowDownIcon,
ArrowUpIcon,
@@ -33,22 +33,22 @@ import { TrashIcon } from '~components/icons'
import { IconButton } from '~components/IconButton'
import { ToolButton } from '~components/ToolButton'
-const selectedShapesCountSelector = (s: Data) =>
+const selectedShapesCountSelector = (s: TLDrawSnapshot) =>
s.document.pageStates[s.appState.currentPageId].selectedIds.length
-const isAllLockedSelector = (s: Data) => {
+const isAllLockedSelector = (s: TLDrawSnapshot) => {
const page = s.document.pages[s.appState.currentPageId]
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
return selectedIds.every((id) => page.shapes[id].isLocked)
}
-const isAllAspectLockedSelector = (s: Data) => {
+const isAllAspectLockedSelector = (s: TLDrawSnapshot) => {
const page = s.document.pages[s.appState.currentPageId]
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
return selectedIds.every((id) => page.shapes[id].isAspectRatioLocked)
}
-const isAllGroupedSelector = (s: Data) => {
+const isAllGroupedSelector = (s: TLDrawSnapshot) => {
const page = s.document.pages[s.appState.currentPageId]
const selectedShapes = s.document.pageStates[s.appState.currentPageId].selectedIds.map(
(id) => page.shapes[id]
@@ -62,18 +62,18 @@ const isAllGroupedSelector = (s: Data) => {
)
}
-const hasSelectionClickor = (s: Data) => {
+const hasSelectionClickor = (s: TLDrawSnapshot) => {
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
return selectedIds.length > 0
}
-const hasMultipleSelectionClickor = (s: Data) => {
+const hasMultipleSelectionClickor = (s: TLDrawSnapshot) => {
const { selectedIds } = s.document.pageStates[s.appState.currentPageId]
return selectedIds.length > 1
}
export function ActionButton(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const isAllLocked = useSelector(isAllLockedSelector)
@@ -86,84 +86,84 @@ export function ActionButton(): JSX.Element {
const hasMultipleSelection = useSelector(hasMultipleSelectionClickor)
const handleRotate = React.useCallback(() => {
- tlstate.rotate()
- }, [tlstate])
+ state.rotate()
+ }, [state])
const handleDuplicate = React.useCallback(() => {
- tlstate.duplicate()
- }, [tlstate])
+ state.duplicate()
+ }, [state])
const handleToggleLocked = React.useCallback(() => {
- tlstate.toggleLocked()
- }, [tlstate])
+ state.toggleLocked()
+ }, [state])
const handleToggleAspectRatio = React.useCallback(() => {
- tlstate.toggleAspectRatioLocked()
- }, [tlstate])
+ state.toggleAspectRatioLocked()
+ }, [state])
const handleGroup = React.useCallback(() => {
- tlstate.group()
- }, [tlstate])
+ state.group()
+ }, [state])
const handleMoveToBack = React.useCallback(() => {
- tlstate.moveToBack()
- }, [tlstate])
+ state.moveToBack()
+ }, [state])
const handleMoveBackward = React.useCallback(() => {
- tlstate.moveBackward()
- }, [tlstate])
+ state.moveBackward()
+ }, [state])
const handleMoveForward = React.useCallback(() => {
- tlstate.moveForward()
- }, [tlstate])
+ state.moveForward()
+ }, [state])
const handleMoveToFront = React.useCallback(() => {
- tlstate.moveToFront()
- }, [tlstate])
+ state.moveToFront()
+ }, [state])
const handleDelete = React.useCallback(() => {
- tlstate.delete()
- }, [tlstate])
+ state.delete()
+ }, [state])
const alignTop = React.useCallback(() => {
- tlstate.align(AlignType.Top)
- }, [tlstate])
+ state.align(AlignType.Top)
+ }, [state])
const alignCenterVertical = React.useCallback(() => {
- tlstate.align(AlignType.CenterVertical)
- }, [tlstate])
+ state.align(AlignType.CenterVertical)
+ }, [state])
const alignBottom = React.useCallback(() => {
- tlstate.align(AlignType.Bottom)
- }, [tlstate])
+ state.align(AlignType.Bottom)
+ }, [state])
const stretchVertically = React.useCallback(() => {
- tlstate.stretch(StretchType.Vertical)
- }, [tlstate])
+ state.stretch(StretchType.Vertical)
+ }, [state])
const distributeVertically = React.useCallback(() => {
- tlstate.distribute(DistributeType.Vertical)
- }, [tlstate])
+ state.distribute(DistributeType.Vertical)
+ }, [state])
const alignLeft = React.useCallback(() => {
- tlstate.align(AlignType.Left)
- }, [tlstate])
+ state.align(AlignType.Left)
+ }, [state])
const alignCenterHorizontal = React.useCallback(() => {
- tlstate.align(AlignType.CenterHorizontal)
- }, [tlstate])
+ state.align(AlignType.CenterHorizontal)
+ }, [state])
const alignRight = React.useCallback(() => {
- tlstate.align(AlignType.Right)
- }, [tlstate])
+ state.align(AlignType.Right)
+ }, [state])
const stretchHorizontally = React.useCallback(() => {
- tlstate.stretch(StretchType.Horizontal)
- }, [tlstate])
+ state.stretch(StretchType.Horizontal)
+ }, [state])
const distributeHorizontally = React.useCallback(() => {
- tlstate.distribute(DistributeType.Horizontal)
- }, [tlstate])
+ state.distribute(DistributeType.Horizontal)
+ }, [state])
const selectedShapesCount = useSelector(selectedShapesCountSelector)
diff --git a/packages/tldraw/src/components/ToolsPanel/BackToContent.tsx b/packages/tldraw/src/components/ToolsPanel/BackToContent.tsx
index 90507855e..3508ebeed 100644
--- a/packages/tldraw/src/components/ToolsPanel/BackToContent.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/BackToContent.tsx
@@ -1,16 +1,16 @@
import * as React from 'react'
import { styled } from '~styles'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { useTLDrawContext } from '~hooks'
import { RowButton } from '~components/RowButton'
import { MenuContent } from '~components/MenuContent'
-const isEmptyCanvasSelector = (s: Data) =>
+const isEmptyCanvasSelector = (s: TLDrawSnapshot) =>
Object.keys(s.document.pages[s.appState.currentPageId].shapes).length > 0 &&
s.appState.isEmptyCanvas
export const BackToContent = React.memo(function BackToContent() {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const isEmptyCanvas = useSelector(isEmptyCanvasSelector)
@@ -18,7 +18,7 @@ export const BackToContent = React.memo(function BackToContent() {
return (
- Back to content
+ Back to content
)
})
diff --git a/packages/tldraw/src/components/ToolsPanel/LockButton.tsx b/packages/tldraw/src/components/ToolsPanel/LockButton.tsx
index f387c80fe..284c02a2b 100644
--- a/packages/tldraw/src/components/ToolsPanel/LockButton.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/LockButton.tsx
@@ -3,18 +3,18 @@ import { LockClosedIcon, LockOpen1Icon } from '@radix-ui/react-icons'
import { Tooltip } from '~components/Tooltip'
import { useTLDrawContext } from '~hooks'
import { ToolButton } from '~components/ToolButton'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
-const isToolLockedSelector = (s: Data) => s.appState.isToolLocked
+const isToolLockedSelector = (s: TLDrawSnapshot) => s.appState.isToolLocked
export function LockButton(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const isToolLocked = useSelector(isToolLockedSelector)
return (
-
+
{isToolLocked ? : }
diff --git a/packages/tldraw/src/components/ToolsPanel/PrimaryTools.tsx b/packages/tldraw/src/components/ToolsPanel/PrimaryTools.tsx
index 12f4944fa..bd2d673bf 100644
--- a/packages/tldraw/src/components/ToolsPanel/PrimaryTools.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/PrimaryTools.tsx
@@ -8,45 +8,45 @@ import {
SquareIcon,
TextIcon,
} from '@radix-ui/react-icons'
-import { Data, TLDrawShapeType } from '~types'
+import { TLDrawSnapshot, TLDrawShapeType } from '~types'
import { useTLDrawContext } from '~hooks'
import { ToolButtonWithTooltip } from '~components/ToolButton'
import { Panel } from '~components/Panel'
-const activeToolSelector = (s: Data) => s.appState.activeTool
+const activeToolSelector = (s: TLDrawSnapshot) => s.appState.activeTool
export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const activeTool = useSelector(activeToolSelector)
const selectSelectTool = React.useCallback(() => {
- tlstate.selectTool('select')
- }, [tlstate])
+ state.selectTool('select')
+ }, [state])
const selectDrawTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Draw)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Draw)
+ }, [state])
const selectRectangleTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Rectangle)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Rectangle)
+ }, [state])
const selectEllipseTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Ellipse)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Ellipse)
+ }, [state])
const selectArrowTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Arrow)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Arrow)
+ }, [state])
const selectTextTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Text)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Text)
+ }, [state])
const selectStickyTool = React.useCallback(() => {
- tlstate.selectTool(TLDrawShapeType.Sticky)
- }, [tlstate])
+ state.selectTool(TLDrawShapeType.Sticky)
+ }, [state])
return (
diff --git a/packages/tldraw/src/components/ToolsPanel/StatusBar.tsx b/packages/tldraw/src/components/ToolsPanel/StatusBar.tsx
index fc77e2aea..156e72e3f 100644
--- a/packages/tldraw/src/components/ToolsPanel/StatusBar.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/StatusBar.tsx
@@ -1,11 +1,11 @@
import * as React from 'react'
import { useTLDrawContext } from '~hooks'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { styled } from '~styles'
import { breakpoints } from '~components/breakpoints'
-const statusSelector = (s: Data) => s.appState.status
-const activeToolSelector = (s: Data) => s.appState.activeTool
+const statusSelector = (s: TLDrawSnapshot) => s.appState.status
+const activeToolSelector = (s: TLDrawSnapshot) => s.appState.activeTool
export function StatusBar(): JSX.Element | null {
const { useSelector } = useTLDrawContext()
diff --git a/packages/tldraw/src/components/ToolsPanel/ToolsPanel.tsx b/packages/tldraw/src/components/ToolsPanel/ToolsPanel.tsx
index ed3a3f57a..14742f490 100644
--- a/packages/tldraw/src/components/ToolsPanel/ToolsPanel.tsx
+++ b/packages/tldraw/src/components/ToolsPanel/ToolsPanel.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import { styled } from '~styles'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { useTLDrawContext } from '~hooks'
import { StatusBar } from './StatusBar'
import { BackToContent } from './BackToContent'
@@ -8,7 +8,7 @@ import { PrimaryTools } from './PrimaryTools'
import { ActionButton } from './ActionButton'
import { LockButton } from './LockButton'
-const isDebugModeSelector = (s: Data) => s.settings.isDebugMode
+const isDebugModeSelector = (s: TLDrawSnapshot) => s.settings.isDebugMode
export const ToolsPanel = React.memo(function ToolsPanel(): JSX.Element {
const { useSelector } = useTLDrawContext()
diff --git a/packages/tldraw/src/components/TopPanel/ColorMenu.tsx b/packages/tldraw/src/components/TopPanel/ColorMenu.tsx
index 0cb613c99..6032eba38 100644
--- a/packages/tldraw/src/components/TopPanel/ColorMenu.tsx
+++ b/packages/tldraw/src/components/TopPanel/ColorMenu.tsx
@@ -5,14 +5,14 @@ import { useTLDrawContext } from '~hooks'
import { DMContent, DMTriggerIcon } from '~components/DropdownMenu'
import { BoxIcon, CircleIcon } from '~components/icons'
import { ToolButton } from '~components/ToolButton'
-import type { Data, ColorStyle } from '~types'
+import type { TLDrawSnapshot, ColorStyle } from '~types'
-const selectColor = (s: Data) => s.appState.selectedStyle.color
+const selectColor = (s: TLDrawSnapshot) => s.appState.selectedStyle.color
const preventEvent = (e: Event) => e.preventDefault()
-const themeSelector = (data: Data) => (data.settings.isDarkMode ? 'dark' : 'light')
+const themeSelector = (data: TLDrawSnapshot) => (data.settings.isDarkMode ? 'dark' : 'light')
export const ColorMenu = React.memo(function ColorMenu(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const theme = useSelector(themeSelector)
const color = useSelector(selectColor)
@@ -28,7 +28,7 @@ export const ColorMenu = React.memo(function ColorMenu(): JSX.Element {
tlstate.style({ color: colorStyle as ColorStyle })}
+ onClick={() => state.style({ color: colorStyle as ColorStyle })}
>
,
}
-const selectDash = (s: Data) => s.appState.selectedStyle.dash
+const selectDash = (s: TLDrawSnapshot) => s.appState.selectedStyle.dash
const preventEvent = (e: Event) => e.preventDefault()
export const DashMenu = React.memo(function DashMenu(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const dash = useSelector(selectDash)
@@ -31,7 +31,7 @@ export const DashMenu = React.memo(function DashMenu(): JSX.Element {
tlstate.style({ dash: dashStyle as DashStyle })}
+ onClick={() => state.style({ dash: dashStyle as DashStyle })}
>
{dashes[dashStyle as DashStyle]}
diff --git a/packages/tldraw/src/components/TopPanel/FillCheckbox.tsx b/packages/tldraw/src/components/TopPanel/FillCheckbox.tsx
index 2602c4f85..c987cde0f 100644
--- a/packages/tldraw/src/components/TopPanel/FillCheckbox.tsx
+++ b/packages/tldraw/src/components/TopPanel/FillCheckbox.tsx
@@ -1,20 +1,20 @@
import * as React from 'react'
import * as Checkbox from '@radix-ui/react-checkbox'
import { useTLDrawContext } from '~hooks'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { BoxIcon, IsFilledIcon } from '~components/icons'
import { ToolButton } from '~components/ToolButton'
-const isFilledSelector = (s: Data) => s.appState.selectedStyle.isFilled
+const isFilledSelector = (s: TLDrawSnapshot) => s.appState.selectedStyle.isFilled
export const FillCheckbox = React.memo(function FillCheckbox(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const isFilled = useSelector(isFilledSelector)
const handleIsFilledChange = React.useCallback(
- (isFilled: boolean) => tlstate.style({ isFilled }),
- [tlstate]
+ (isFilled: boolean) => state.style({ isFilled }),
+ [state]
)
return (
diff --git a/packages/tldraw/src/components/TopPanel/Menu.tsx b/packages/tldraw/src/components/TopPanel/Menu.tsx
index 157a36da4..e44324a2f 100644
--- a/packages/tldraw/src/components/TopPanel/Menu.tsx
+++ b/packages/tldraw/src/components/TopPanel/Menu.tsx
@@ -12,53 +12,53 @@ interface MenuProps {
}
export const Menu = React.memo(function Menu({ readOnly }: MenuProps) {
- const { tlstate, callbacks } = useTLDrawContext()
+ const { state } = useTLDrawContext()
const { onNewProject, onOpenProject, onSaveProject, onSaveProjectAs } = useFileSystemHandlers()
const handleSignIn = React.useCallback(() => {
- callbacks.onSignIn?.(tlstate)
- }, [tlstate])
+ state.callbacks.onSignIn?.(state)
+ }, [state])
const handleSignOut = React.useCallback(() => {
- callbacks.onSignOut?.(tlstate)
- }, [tlstate])
+ state.callbacks.onSignOut?.(state)
+ }, [state])
const handleCut = React.useCallback(() => {
- tlstate.cut()
- }, [tlstate])
+ state.cut()
+ }, [state])
const handleCopy = React.useCallback(() => {
- tlstate.copy()
- }, [tlstate])
+ state.copy()
+ }, [state])
const handlePaste = React.useCallback(() => {
- tlstate.paste()
- }, [tlstate])
+ state.paste()
+ }, [state])
const handleCopySvg = React.useCallback(() => {
- tlstate.copySvg()
- }, [tlstate])
+ state.copySvg()
+ }, [state])
const handleCopyJson = React.useCallback(() => {
- tlstate.copyJson()
- }, [tlstate])
+ state.copyJson()
+ }, [state])
const handleSelectAll = React.useCallback(() => {
- tlstate.selectAll()
- }, [tlstate])
+ state.selectAll()
+ }, [state])
const handleselectNone = React.useCallback(() => {
- tlstate.selectNone()
- }, [tlstate])
+ state.selectNone()
+ }, [state])
const showFileMenu =
- callbacks.onNewProject ||
- callbacks.onOpenProject ||
- callbacks.onSaveProject ||
- callbacks.onSaveProjectAs
+ state.callbacks.onNewProject ||
+ state.callbacks.onOpenProject ||
+ state.callbacks.onSaveProject ||
+ state.callbacks.onSaveProjectAs
- const showSignInOutMenu = callbacks.onSignIn || callbacks.onSignOut
+ const showSignInOutMenu = state.callbacks.onSignIn || state.callbacks.onSignOut
return (
@@ -68,22 +68,22 @@ export const Menu = React.memo(function Menu({ readOnly }: MenuProps) {
{showFileMenu && (
- {callbacks.onNewProject && (
+ {state.callbacks.onNewProject && (
New Project
)}
- {callbacks.onOpenProject && (
+ {state.callbacks.onOpenProject && (
Open...
)}
- {callbacks.onSaveProject && (
+ {state.callbacks.onSaveProject && (
Save
)}
- {callbacks.onSaveProjectAs && (
+ {state.callbacks.onSaveProjectAs && (
Save As...
@@ -93,10 +93,10 @@ export const Menu = React.memo(function Menu({ readOnly }: MenuProps) {
{!readOnly && (
<>
-
+
Undo
-
+
Redo
@@ -127,8 +127,8 @@ export const Menu = React.memo(function Menu({ readOnly }: MenuProps) {
{showSignInOutMenu && (
<>
{' '}
- {callbacks.onSignIn && Sign In}
- {callbacks.onSignOut && (
+ {state.callbacks.onSignIn && Sign In}
+ {state.callbacks.onSignOut && (
Sign Out
diff --git a/packages/tldraw/src/components/TopPanel/PageMenu.tsx b/packages/tldraw/src/components/TopPanel/PageMenu.tsx
index cb3a09f61..0c3837cfd 100644
--- a/packages/tldraw/src/components/TopPanel/PageMenu.tsx
+++ b/packages/tldraw/src/components/TopPanel/PageMenu.tsx
@@ -4,18 +4,19 @@ import { PlusIcon, CheckIcon } from '@radix-ui/react-icons'
import { PageOptionsDialog } from './PageOptionsDialog'
import { styled } from '~styles'
import { useTLDrawContext } from '~hooks'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { DMContent, DMDivider } from '~components/DropdownMenu'
import { SmallIcon } from '~components/SmallIcon'
import { RowButton } from '~components/RowButton'
import { ToolButton } from '~components/ToolButton'
-const sortedSelector = (s: Data) =>
+const sortedSelector = (s: TLDrawSnapshot) =>
Object.values(s.document.pages).sort((a, b) => (a.childIndex || 0) - (b.childIndex || 0))
-const currentPageNameSelector = (s: Data) => s.document.pages[s.appState.currentPageId].name
+const currentPageNameSelector = (s: TLDrawSnapshot) =>
+ s.document.pages[s.appState.currentPageId].name
-const currentPageIdSelector = (s: Data) => s.document.pages[s.appState.currentPageId].id
+const currentPageIdSelector = (s: TLDrawSnapshot) => s.document.pages[s.appState.currentPageId].id
export function PageMenu(): JSX.Element {
const { useSelector } = useTLDrawContext()
@@ -57,22 +58,22 @@ export function PageMenu(): JSX.Element {
}
function PageMenuContent({ onClose }: { onClose: () => void }) {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const sortedPages = useSelector(sortedSelector)
const currentPageId = useSelector(currentPageIdSelector)
const handleCreatePage = React.useCallback(() => {
- tlstate.createPage()
- }, [tlstate])
+ state.createPage()
+ }, [state])
const handleChangePage = React.useCallback(
(id: string) => {
onClose()
- tlstate.changePage(id)
+ state.changePage(id)
},
- [tlstate]
+ [state]
)
return (
diff --git a/packages/tldraw/src/components/TopPanel/PageOptionsDialog.tsx b/packages/tldraw/src/components/TopPanel/PageOptionsDialog.tsx
index 094b61ec6..4ecafbced 100644
--- a/packages/tldraw/src/components/TopPanel/PageOptionsDialog.tsx
+++ b/packages/tldraw/src/components/TopPanel/PageOptionsDialog.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as Dialog from '@radix-ui/react-alert-dialog'
import { MixerVerticalIcon } from '@radix-ui/react-icons'
-import type { Data, TLDrawPage } from '~types'
+import type { TLDrawSnapshot, TLDrawPage } from '~types'
import { useTLDrawContext } from '~hooks'
import { RowButton, RowButtonProps } from '~components/RowButton'
import { styled } from '~styles'
@@ -10,7 +10,7 @@ import { IconButton } from '~components/IconButton/IconButton'
import { SmallIcon } from '~components/SmallIcon'
import { breakpoints } from '~components/breakpoints'
-const canDeleteSelector = (s: Data) => {
+const canDeleteSelector = (s: TLDrawSnapshot) => {
return Object.keys(s.document.pages).length > 1
}
@@ -21,7 +21,7 @@ interface PageOptionsDialogProps {
}
export function PageOptionsDialog({ page, onOpen, onClose }: PageOptionsDialogProps): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const [isOpen, setIsOpen] = React.useState(false)
@@ -30,16 +30,16 @@ export function PageOptionsDialog({ page, onOpen, onClose }: PageOptionsDialogPr
const rInput = React.useRef(null)
const handleDuplicate = React.useCallback(() => {
- tlstate.duplicatePage(page.id)
+ state.duplicatePage(page.id)
onClose?.()
- }, [tlstate])
+ }, [state])
const handleDelete = React.useCallback(() => {
if (window.confirm(`Are you sure you want to delete this page?`)) {
- tlstate.deletePage(page.id)
+ state.deletePage(page.id)
onClose?.()
}
- }, [tlstate])
+ }, [state])
const handleOpenChange = React.useCallback(
(isOpen: boolean) => {
@@ -50,7 +50,7 @@ export function PageOptionsDialog({ page, onOpen, onClose }: PageOptionsDialogPr
return
}
},
- [tlstate, name]
+ [state, name]
)
function stopPropagation(e: React.KeyboardEvent) {
@@ -60,7 +60,7 @@ export function PageOptionsDialog({ page, onOpen, onClose }: PageOptionsDialogPr
// TODO: Replace with text input
function handleRename() {
const nextName = window.prompt('New name:', page.name)
- tlstate.renamePage(page.id, nextName || page.name || 'Page')
+ state.renamePage(page.id, nextName || page.name || 'Page')
}
React.useEffect(() => {
diff --git a/packages/tldraw/src/components/TopPanel/PreferencesMenu.tsx b/packages/tldraw/src/components/TopPanel/PreferencesMenu.tsx
index e9de8294b..046f9c124 100644
--- a/packages/tldraw/src/components/TopPanel/PreferencesMenu.tsx
+++ b/packages/tldraw/src/components/TopPanel/PreferencesMenu.tsx
@@ -1,42 +1,42 @@
import * as React from 'react'
import { DMCheckboxItem, DMDivider, DMSubMenu } from '~components/DropdownMenu'
import { useTLDrawContext } from '~hooks'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
-const settingsSelector = (s: Data) => s.settings
+const settingsSelector = (s: TLDrawSnapshot) => s.settings
export function PreferencesMenu() {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const settings = useSelector(settingsSelector)
const toggleDebugMode = React.useCallback(() => {
- tlstate.setSetting('isDebugMode', (v) => !v)
- }, [tlstate])
+ state.setSetting('isDebugMode', (v) => !v)
+ }, [state])
const toggleDarkMode = React.useCallback(() => {
- tlstate.setSetting('isDarkMode', (v) => !v)
- }, [tlstate])
+ state.setSetting('isDarkMode', (v) => !v)
+ }, [state])
const toggleFocusMode = React.useCallback(() => {
- tlstate.setSetting('isFocusMode', (v) => !v)
- }, [tlstate])
+ state.setSetting('isFocusMode', (v) => !v)
+ }, [state])
const toggleRotateHandle = React.useCallback(() => {
- tlstate.setSetting('showRotateHandles', (v) => !v)
- }, [tlstate])
+ state.setSetting('showRotateHandles', (v) => !v)
+ }, [state])
const toggleBoundShapesHandle = React.useCallback(() => {
- tlstate.setSetting('showBindingHandles', (v) => !v)
- }, [tlstate])
+ state.setSetting('showBindingHandles', (v) => !v)
+ }, [state])
const toggleisSnapping = React.useCallback(() => {
- tlstate.setSetting('isSnapping', (v) => !v)
- }, [tlstate])
+ state.setSetting('isSnapping', (v) => !v)
+ }, [state])
const toggleCloneControls = React.useCallback(() => {
- tlstate.setSetting('showCloneHandles', (v) => !v)
- }, [tlstate])
+ state.setSetting('showCloneHandles', (v) => !v)
+ }, [state])
return (
diff --git a/packages/tldraw/src/components/TopPanel/SizeMenu.tsx b/packages/tldraw/src/components/TopPanel/SizeMenu.tsx
index de7647fd1..7b9bff5fd 100644
--- a/packages/tldraw/src/components/TopPanel/SizeMenu.tsx
+++ b/packages/tldraw/src/components/TopPanel/SizeMenu.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
-import { Data, SizeStyle } from '~types'
+import { TLDrawSnapshot, SizeStyle } from '~types'
import { useTLDrawContext } from '~hooks'
import { DMContent, DMTriggerIcon } from '~components/DropdownMenu'
import { ToolButton } from '~components/ToolButton'
@@ -12,12 +12,12 @@ const sizes = {
[SizeStyle.Large]: ,
}
-const selectSize = (s: Data) => s.appState.selectedStyle.size
+const selectSize = (s: TLDrawSnapshot) => s.appState.selectedStyle.size
const preventEvent = (e: Event) => e.preventDefault()
export const SizeMenu = React.memo(function SizeMenu(): JSX.Element {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const size = useSelector(selectSize)
@@ -30,7 +30,7 @@ export const SizeMenu = React.memo(function SizeMenu(): JSX.Element {
tlstate.style({ size: sizeStyle as SizeStyle })}
+ onClick={() => state.style({ size: sizeStyle as SizeStyle })}
>
{sizes[sizeStyle as SizeStyle]}
diff --git a/packages/tldraw/src/components/TopPanel/ZoomMenu.tsx b/packages/tldraw/src/components/TopPanel/ZoomMenu.tsx
index 8601fb20c..6243b37e2 100644
--- a/packages/tldraw/src/components/TopPanel/ZoomMenu.tsx
+++ b/packages/tldraw/src/components/TopPanel/ZoomMenu.tsx
@@ -1,15 +1,16 @@
import * as React from 'react'
import { useTLDrawContext } from '~hooks'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { styled } from '~styles'
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
import { DMItem, DMContent } from '~components/DropdownMenu'
import { ToolButton } from '~components/ToolButton'
-const zoomSelector = (s: Data) => s.document.pageStates[s.appState.currentPageId].camera.zoom
+const zoomSelector = (s: TLDrawSnapshot) =>
+ s.document.pageStates[s.appState.currentPageId].camera.zoom
export function ZoomMenu() {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const zoom = useSelector(zoomSelector)
return (
@@ -18,19 +19,19 @@ export function ZoomMenu() {
{Math.round(zoom * 100)}%
-
+
Zoom In
-
+
Zoom Out
-
+
To 100%
-
+
To Fit
-
+
To Selection
diff --git a/packages/tldraw/src/hooks/useFileSystem.ts b/packages/tldraw/src/hooks/useFileSystem.ts
index 79f88585e..904d21148 100644
--- a/packages/tldraw/src/hooks/useFileSystem.ts
+++ b/packages/tldraw/src/hooks/useFileSystem.ts
@@ -2,40 +2,40 @@ import * as React from 'react'
import type { TLDrawState } from '~state'
export function useFileSystem() {
- const promptSaveBeforeChange = React.useCallback(async (tlstate: TLDrawState) => {
- if (tlstate.isDirty) {
- if (tlstate.fileSystemHandle) {
+ const promptSaveBeforeChange = React.useCallback(async (state: TLDrawState) => {
+ if (state.isDirty) {
+ if (state.fileSystemHandle) {
if (window.confirm('Do you want to save changes to your current project?')) {
- await tlstate.saveProject()
+ await state.saveProject()
}
} else {
if (window.confirm('Do you want to save your current project?')) {
- await tlstate.saveProject()
+ await state.saveProject()
}
}
}
}, [])
const onNewProject = React.useCallback(
- async (tlstate: TLDrawState) => {
- await promptSaveBeforeChange(tlstate)
- tlstate.newProject()
+ async (state: TLDrawState) => {
+ await promptSaveBeforeChange(state)
+ state.newProject()
},
[promptSaveBeforeChange]
)
- const onSaveProject = React.useCallback((tlstate: TLDrawState) => {
- tlstate.saveProject()
+ const onSaveProject = React.useCallback((state: TLDrawState) => {
+ state.saveProject()
}, [])
- const onSaveProjectAs = React.useCallback((tlstate: TLDrawState) => {
- tlstate.saveProjectAs()
+ const onSaveProjectAs = React.useCallback((state: TLDrawState) => {
+ state.saveProjectAs()
}, [])
const onOpenProject = React.useCallback(
- async (tlstate: TLDrawState) => {
- await promptSaveBeforeChange(tlstate)
- tlstate.openProject()
+ async (state: TLDrawState) => {
+ await promptSaveBeforeChange(state)
+ state.openProject()
},
[promptSaveBeforeChange]
)
diff --git a/packages/tldraw/src/hooks/useFileSystemHandlers.ts b/packages/tldraw/src/hooks/useFileSystemHandlers.ts
index 1fad1cc2c..00b6c2a04 100644
--- a/packages/tldraw/src/hooks/useFileSystemHandlers.ts
+++ b/packages/tldraw/src/hooks/useFileSystemHandlers.ts
@@ -2,38 +2,38 @@ import * as React from 'react'
import { useTLDrawContext } from '~hooks'
export function useFileSystemHandlers() {
- const { tlstate, callbacks } = useTLDrawContext()
+ const { state } = useTLDrawContext()
const onNewProject = React.useCallback(
async (e?: KeyboardEvent) => {
- if (e && callbacks.onOpenProject) e.preventDefault()
- callbacks.onNewProject?.(tlstate)
+ if (e && state.callbacks.onOpenProject) e.preventDefault()
+ state.callbacks.onNewProject?.(state)
},
- [callbacks]
+ [state]
)
const onSaveProject = React.useCallback(
(e?: KeyboardEvent) => {
- if (e && callbacks.onOpenProject) e.preventDefault()
- callbacks.onSaveProject?.(tlstate)
+ if (e && state.callbacks.onOpenProject) e.preventDefault()
+ state.callbacks.onSaveProject?.(state)
},
- [callbacks]
+ [state]
)
const onSaveProjectAs = React.useCallback(
(e?: KeyboardEvent) => {
- if (e && callbacks.onOpenProject) e.preventDefault()
- callbacks.onSaveProjectAs?.(tlstate)
+ if (e && state.callbacks.onOpenProject) e.preventDefault()
+ state.callbacks.onSaveProjectAs?.(state)
},
- [callbacks]
+ [state]
)
const onOpenProject = React.useCallback(
async (e?: KeyboardEvent) => {
- if (e && callbacks.onOpenProject) e.preventDefault()
- callbacks.onOpenProject?.(tlstate)
+ if (e && state.callbacks.onOpenProject) e.preventDefault()
+ state.callbacks.onOpenProject?.(state)
},
- [callbacks]
+ [state]
)
return {
diff --git a/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx b/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx
index fcdea9dd7..071623513 100644
--- a/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx
+++ b/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx
@@ -4,7 +4,7 @@ import { TLDrawShapeType } from '~types'
import { useFileSystemHandlers, useTLDrawContext } from '~hooks'
export function useKeyboardShortcuts(ref: React.RefObject) {
- const { tlstate } = useTLDrawContext()
+ const { state } = useTLDrawContext()
const canHandleEvent = React.useCallback(() => {
const elm = ref.current
@@ -16,63 +16,63 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'v,1',
() => {
- if (canHandleEvent()) tlstate.selectTool('select')
+ if (canHandleEvent()) state.selectTool('select')
},
- [tlstate, ref.current]
+ [state, ref.current]
)
useHotkeys(
'd,2',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Draw)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Draw)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'r,3',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Rectangle)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Rectangle)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'e,4',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Ellipse)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Ellipse)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'a,5',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Arrow)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Arrow)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
't,6',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Text)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Text)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'n,7',
() => {
- if (canHandleEvent()) tlstate.selectTool(TLDrawShapeType.Sticky)
+ if (canHandleEvent()) state.selectTool(TLDrawShapeType.Sticky)
},
undefined,
- [tlstate]
+ [state]
)
/* ---------------------- Misc ---------------------- */
@@ -83,12 +83,12 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'ctrl+shift+d,command+shift+d',
(e) => {
if (canHandleEvent()) {
- tlstate.toggleDarkMode()
+ state.toggleDarkMode()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
// Focus Mode
@@ -96,10 +96,10 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'ctrl+.,command+.',
() => {
- if (canHandleEvent()) tlstate.toggleFocusMode()
+ if (canHandleEvent()) state.toggleFocusMode()
},
undefined,
- [tlstate]
+ [state]
)
// File System
@@ -114,7 +114,7 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'ctrl+s,command+s',
@@ -124,7 +124,7 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
@@ -135,7 +135,7 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'ctrl+o,command+o',
@@ -145,7 +145,7 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
}
},
undefined,
- [tlstate]
+ [state]
)
// Undo Redo
@@ -154,30 +154,30 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'command+z,ctrl+z',
() => {
if (canHandleEvent()) {
- if (tlstate.session) {
- tlstate.cancelSession()
+ if (state.session) {
+ state.cancelSession()
} else {
- tlstate.undo()
+ state.undo()
}
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'ctrl+shift-z,command+shift+z',
() => {
if (canHandleEvent()) {
- if (tlstate.session) {
- tlstate.cancelSession()
+ if (state.session) {
+ state.cancelSession()
} else {
- tlstate.redo()
+ state.redo()
}
}
},
undefined,
- [tlstate]
+ [state]
)
// Undo Redo
@@ -185,19 +185,19 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'command+u,ctrl+u',
() => {
- if (canHandleEvent()) tlstate.undoSelect()
+ if (canHandleEvent()) state.undoSelect()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'ctrl+shift-u,command+shift+u',
() => {
- if (canHandleEvent()) tlstate.redoSelect()
+ if (canHandleEvent()) state.redoSelect()
},
undefined,
- [tlstate]
+ [state]
)
/* -------------------- Commands -------------------- */
@@ -208,51 +208,51 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'ctrl+=,command+=',
(e) => {
if (canHandleEvent()) {
- tlstate.zoomIn()
+ state.zoomIn()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'ctrl+-,command+-',
(e) => {
if (canHandleEvent()) {
- tlstate.zoomOut()
+ state.zoomOut()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+1',
() => {
- if (canHandleEvent()) tlstate.zoomToFit()
+ if (canHandleEvent()) state.zoomToFit()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+2',
() => {
- if (canHandleEvent()) tlstate.zoomToSelection()
+ if (canHandleEvent()) state.zoomToSelection()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+0',
() => {
- if (canHandleEvent()) tlstate.resetZoom()
+ if (canHandleEvent()) state.resetZoom()
},
undefined,
- [tlstate]
+ [state]
)
// Duplicate
@@ -261,12 +261,12 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'ctrl+d,command+d',
(e) => {
if (canHandleEvent()) {
- tlstate.duplicate()
+ state.duplicate()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
// Flip
@@ -274,19 +274,19 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'shift+h',
() => {
- if (canHandleEvent()) tlstate.flipHorizontal()
+ if (canHandleEvent()) state.flipHorizontal()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+v',
() => {
- if (canHandleEvent()) tlstate.flipVertical()
+ if (canHandleEvent()) state.flipVertical()
},
undefined,
- [tlstate]
+ [state]
)
// Cancel
@@ -295,11 +295,11 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'escape',
() => {
if (canHandleEvent()) {
- tlstate.cancel()
+ state.cancel()
}
},
undefined,
- [tlstate]
+ [state]
)
// Delete
@@ -307,10 +307,10 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'backspace',
() => {
- if (canHandleEvent()) tlstate.delete()
+ if (canHandleEvent()) state.delete()
},
undefined,
- [tlstate]
+ [state]
)
// Select All
@@ -318,10 +318,10 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'command+a,ctrl+a',
() => {
- if (canHandleEvent()) tlstate.selectAll()
+ if (canHandleEvent()) state.selectAll()
},
undefined,
- [tlstate]
+ [state]
)
// Nudge
@@ -329,73 +329,73 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'up',
() => {
- if (canHandleEvent()) tlstate.nudge([0, -1], false)
+ if (canHandleEvent()) state.nudge([0, -1], false)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'right',
() => {
- if (canHandleEvent()) tlstate.nudge([1, 0], false)
+ if (canHandleEvent()) state.nudge([1, 0], false)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'down',
() => {
- if (canHandleEvent()) tlstate.nudge([0, 1], false)
+ if (canHandleEvent()) state.nudge([0, 1], false)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'left',
() => {
- if (canHandleEvent()) tlstate.nudge([-1, 0], false)
+ if (canHandleEvent()) state.nudge([-1, 0], false)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+up',
() => {
- if (canHandleEvent()) tlstate.nudge([0, -1], true)
+ if (canHandleEvent()) state.nudge([0, -1], true)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+right',
() => {
- if (canHandleEvent()) tlstate.nudge([1, 0], true)
+ if (canHandleEvent()) state.nudge([1, 0], true)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+down',
() => {
- if (canHandleEvent()) tlstate.nudge([0, 1], true)
+ if (canHandleEvent()) state.nudge([0, 1], true)
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+left',
() => {
- if (canHandleEvent()) tlstate.nudge([-1, 0], true)
+ if (canHandleEvent()) state.nudge([-1, 0], true)
},
undefined,
- [tlstate]
+ [state]
)
// Copy, Cut & Paste
@@ -403,28 +403,28 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'command+c,ctrl+c',
() => {
- if (canHandleEvent()) tlstate.copy()
+ if (canHandleEvent()) state.copy()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'command+x,ctrl+x',
() => {
- if (canHandleEvent()) tlstate.cut()
+ if (canHandleEvent()) state.cut()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'command+v,ctrl+v',
() => {
- if (canHandleEvent()) tlstate.paste()
+ if (canHandleEvent()) state.paste()
},
undefined,
- [tlstate]
+ [state]
)
// Group & Ungroup
@@ -433,24 +433,24 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
'command+g,ctrl+g',
(e) => {
if (canHandleEvent()) {
- tlstate.group()
+ state.group()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'command+shift+g,ctrl+shift+g',
(e) => {
if (canHandleEvent()) {
- tlstate.ungroup()
+ state.ungroup()
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
// Move
@@ -458,37 +458,37 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
useHotkeys(
'[',
() => {
- if (canHandleEvent()) tlstate.moveBackward()
+ if (canHandleEvent()) state.moveBackward()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
']',
() => {
- if (canHandleEvent()) tlstate.moveForward()
+ if (canHandleEvent()) state.moveForward()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+[',
() => {
- if (canHandleEvent()) tlstate.moveToBack()
+ if (canHandleEvent()) state.moveToBack()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
'shift+]',
() => {
- if (canHandleEvent()) tlstate.moveToFront()
+ if (canHandleEvent()) state.moveToFront()
},
undefined,
- [tlstate]
+ [state]
)
useHotkeys(
@@ -496,12 +496,12 @@ export function useKeyboardShortcuts(ref: React.RefObject) {
(e) => {
if (canHandleEvent()) {
if (process.env.NODE_ENV === 'development') {
- tlstate.resetDocument()
+ state.resetDocument()
}
e.preventDefault()
}
},
undefined,
- [tlstate]
+ [state]
)
}
diff --git a/packages/tldraw/src/hooks/useTLDrawContext.tsx b/packages/tldraw/src/hooks/useTLDrawContext.tsx
index a638ba9ba..cd57c6ae3 100644
--- a/packages/tldraw/src/hooks/useTLDrawContext.tsx
+++ b/packages/tldraw/src/hooks/useTLDrawContext.tsx
@@ -1,19 +1,11 @@
import * as React from 'react'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import type { UseBoundStore } from 'zustand'
import type { TLDrawState } from '~state'
export interface TLDrawContextType {
- tlstate: TLDrawState
- useSelector: UseBoundStore
- callbacks: {
- onNewProject?: (tlstate: TLDrawState) => void
- onSaveProject?: (tlstate: TLDrawState) => void
- onSaveProjectAs?: (tlstate: TLDrawState) => void
- onOpenProject?: (tlstate: TLDrawState) => void
- onSignIn?: (tlstate: TLDrawState) => void
- onSignOut?: (tlstate: TLDrawState) => void
- }
+ state: TLDrawState
+ useSelector: UseBoundStore
}
export const TLDrawContext = React.createContext({} as TLDrawContextType)
diff --git a/packages/tldraw/src/hooks/useTheme.ts b/packages/tldraw/src/hooks/useTheme.ts
index 419b74638..63e59a3fe 100644
--- a/packages/tldraw/src/hooks/useTheme.ts
+++ b/packages/tldraw/src/hooks/useTheme.ts
@@ -1,14 +1,14 @@
-import type { Data, Theme } from '~types'
+import type { TLDrawSnapshot, Theme } from '~types'
import { useTLDrawContext } from './useTLDrawContext'
-const themeSelector = (data: Data): Theme => (data.settings.isDarkMode ? 'dark' : 'light')
+const themeSelector = (data: TLDrawSnapshot): Theme => (data.settings.isDarkMode ? 'dark' : 'light')
export function useTheme() {
- const { tlstate, useSelector } = useTLDrawContext()
+ const { state, useSelector } = useTLDrawContext()
const theme = useSelector(themeSelector)
return {
theme,
- toggle: tlstate.toggleDarkMode,
+ toggle: state.toggleDarkMode,
}
}
diff --git a/packages/tldraw/src/state/TLDR.ts b/packages/tldraw/src/state/TLDR.ts
index 2604ae8e6..8be397abb 100644
--- a/packages/tldraw/src/state/TLDR.ts
+++ b/packages/tldraw/src/state/TLDR.ts
@@ -1,6 +1,6 @@
import { TLBounds, TLTransformInfo, Utils, TLPageState } from '@tldraw/core'
import {
- Data,
+ TLDrawSnapshot,
ShapeStyles,
ShapesWithProp,
TLDrawShape,
@@ -24,13 +24,13 @@ export class TLDR {
return getShapeUtils(shape)
}
- static getSelectedShapes(data: Data, pageId: string) {
+ static getSelectedShapes(data: TLDrawSnapshot, pageId: string) {
const page = TLDR.getPage(data, pageId)
const selectedIds = TLDR.getSelectedIds(data, pageId)
return selectedIds.map((id) => page.shapes[id])
}
- static screenToWorld(data: Data, point: number[]) {
+ static screenToWorld(data: TLDrawSnapshot, point: number[]) {
const camera = TLDR.getPageState(data, data.appState.currentPageId).camera
return Vec.sub(Vec.div(point, camera.zoom), camera.point)
}
@@ -39,28 +39,28 @@ export class TLDR {
return Utils.clamp(zoom, 0.1, 5)
}
- static getPage(data: Data, pageId: string): TLDrawPage {
+ static getPage(data: TLDrawSnapshot, pageId: string): TLDrawPage {
return data.document.pages[pageId]
}
- static getPageState(data: Data, pageId: string): TLPageState {
+ static getPageState(data: TLDrawSnapshot, pageId: string): TLPageState {
return data.document.pageStates[pageId]
}
- static getSelectedIds(data: Data, pageId: string): string[] {
+ static getSelectedIds(data: TLDrawSnapshot, pageId: string): string[] {
return TLDR.getPageState(data, pageId).selectedIds
}
- static getShapes(data: Data, pageId: string): TLDrawShape[] {
+ static getShapes(data: TLDrawSnapshot, pageId: string): TLDrawShape[] {
return Object.values(TLDR.getPage(data, pageId).shapes)
}
- static getCamera(data: Data, pageId: string): TLPageState['camera'] {
+ static getCamera(data: TLDrawSnapshot, pageId: string): TLPageState['camera'] {
return TLDR.getPageState(data, pageId).camera
}
static getShape(
- data: Data,
+ data: TLDrawSnapshot,
shapeId: string,
pageId: string
): T {
@@ -79,7 +79,7 @@ export class TLDR {
return TLDR.getShapeUtils(shape).getRotatedBounds(shape)
}
- static getSelectedBounds(data: Data): TLBounds {
+ static getSelectedBounds(data: TLDrawSnapshot): TLBounds {
return Utils.getCommonBounds(
TLDR.getSelectedShapes(data, data.appState.currentPageId).map((shape) =>
TLDR.getShapeUtils(shape).getBounds(shape)
@@ -87,11 +87,11 @@ export class TLDR {
)
}
- static getParentId(data: Data, id: string, pageId: string) {
+ static getParentId(data: TLDrawSnapshot, id: string, pageId: string) {
return TLDR.getShape(data, id, pageId).parentId
}
- // static getPointedId(data: Data, id: string, pageId: string): string {
+ // static getPointedId(data: TLDrawSnapshot, id: string, pageId: string): string {
// const page = TLDR.getPage(data, pageId)
// const pageState = TLDR.getPageState(data, data.appState.currentPageId)
// const shape = TLDR.getShape(data, id, pageId)
@@ -102,7 +102,7 @@ export class TLDR {
// : TLDR.getPointedId(data, shape.parentId, pageId)
// }
- // static getDrilledPointedId(data: Data, id: string, pageId: string): string {
+ // static getDrilledPointedId(data: TLDrawSnapshot, id: string, pageId: string): string {
// const shape = TLDR.getShape(data, id, pageId)
// const { currentPageId } = data.appState
// const { currentParentId, pointedId } = TLDR.getPageState(data, data.appState.currentPageId)
@@ -114,7 +114,7 @@ export class TLDR {
// : TLDR.getDrilledPointedId(data, shape.parentId, pageId)
// }
- // static getTopParentId(data: Data, id: string, pageId: string): string {
+ // static getTopParentId(data: TLDrawSnapshot, id: string, pageId: string): string {
// const page = TLDR.getPage(data, pageId)
// const pageState = TLDR.getPageState(data, pageId)
// const shape = TLDR.getShape(data, id, pageId)
@@ -129,7 +129,7 @@ export class TLDR {
// }
// Get an array of a shape id and its descendant shapes' ids
- static getDocumentBranch(data: Data, id: string, pageId: string): string[] {
+ static getDocumentBranch(data: TLDrawSnapshot, id: string, pageId: string): string[] {
const shape = TLDR.getShape(data, id, pageId)
if (shape.children === undefined) return [id]
@@ -142,13 +142,13 @@ export class TLDR {
// Get a deep array of unproxied shapes and their descendants
static getSelectedBranchSnapshot(
- data: Data,
+ data: TLDrawSnapshot,
pageId: string,
fn: (shape: TLDrawShape) => K
): ({ id: string } & K)[]
- static getSelectedBranchSnapshot(data: Data, pageId: string): TLDrawShape[]
+ static getSelectedBranchSnapshot(data: TLDrawSnapshot, pageId: string): TLDrawShape[]
static getSelectedBranchSnapshot(
- data: Data,
+ data: TLDrawSnapshot,
pageId: string,
fn?: (shape: TLDrawShape) => K
): (TLDrawShape | K)[] {
@@ -167,14 +167,14 @@ export class TLDR {
}
// Get a shallow array of unproxied shapes
- static getSelectedShapeSnapshot(data: Data, pageId: string): TLDrawShape[]
+ static getSelectedShapeSnapshot(data: TLDrawSnapshot, pageId: string): TLDrawShape[]
static getSelectedShapeSnapshot(
- data: Data,
+ data: TLDrawSnapshot,
pageId: string,
fn?: (shape: TLDrawShape) => K
): ({ id: string } & K)[]
static getSelectedShapeSnapshot(
- data: Data,
+ data: TLDrawSnapshot,
pageId: string,
fn?: (shape: TLDrawShape) => K
): (TLDrawShape | K)[] {
@@ -191,7 +191,7 @@ export class TLDR {
// For a given array of shape ids, an array of all other shapes that may be affected by a mutation to it.
// Use this to decide which shapes to clone as before / after for a command.
- static getAllEffectedShapeIds(data: Data, ids: string[], pageId: string): string[] {
+ static getAllEffectedShapeIds(data: TLDrawSnapshot, ids: string[], pageId: string): string[] {
const page = TLDR.getPage(data, pageId)
const visited = new Set(ids)
@@ -236,41 +236,47 @@ export class TLDR {
}
static updateBindings(
- data: Data,
+ data: TLDrawSnapshot,
id: string,
beforeShapes: Record> = {},
afterShapes: Record> = {},
pageId: string
- ): Data {
+ ): TLDrawSnapshot {
const page = { ...TLDR.getPage(data, pageId) }
return Object.values(page.bindings)
.filter((binding) => binding.fromId === id || binding.toId === id)
- .reduce((cData, binding) => {
+ .reduce((cTLDrawSnapshot, binding) => {
if (!beforeShapes[binding.fromId]) {
beforeShapes[binding.fromId] = Utils.deepClone(
- TLDR.getShape(cData, binding.fromId, pageId)
+ TLDR.getShape(cTLDrawSnapshot, binding.fromId, pageId)
)
}
if (!beforeShapes[binding.toId]) {
- beforeShapes[binding.toId] = Utils.deepClone(TLDR.getShape(cData, binding.toId, pageId))
+ beforeShapes[binding.toId] = Utils.deepClone(
+ TLDR.getShape(cTLDrawSnapshot, binding.toId, pageId)
+ )
}
TLDR.onBindingChange(
- TLDR.getShape(cData, binding.fromId, pageId),
+ TLDR.getShape(cTLDrawSnapshot, binding.fromId, pageId),
binding,
- TLDR.getShape(cData, binding.toId, pageId)
+ TLDR.getShape(cTLDrawSnapshot, binding.toId, pageId)
)
- afterShapes[binding.fromId] = Utils.deepClone(TLDR.getShape(cData, binding.fromId, pageId))
- afterShapes[binding.toId] = Utils.deepClone(TLDR.getShape(cData, binding.toId, pageId))
+ afterShapes[binding.fromId] = Utils.deepClone(
+ TLDR.getShape(cTLDrawSnapshot, binding.fromId, pageId)
+ )
+ afterShapes[binding.toId] = Utils.deepClone(
+ TLDR.getShape(cTLDrawSnapshot, binding.toId, pageId)
+ )
- return cData
+ return cTLDrawSnapshot
}, data)
}
static getLinkedShapes(
- data: Data,
+ data: TLDrawSnapshot,
pageId: string,
direction: 'center' | 'left' | 'right',
includeArrows = true
@@ -372,7 +378,7 @@ export class TLDR {
return Array.from(linkedIds.values())
}
- static getChildIndexAbove(data: Data, id: string, pageId: string): number {
+ static getChildIndexAbove(data: TLDrawSnapshot, id: string, pageId: string): number {
const page = data.document.pages[pageId]
const shape = page.shapes[id]
@@ -410,14 +416,14 @@ export class TLDR {
}
static mutateShapes(
- data: Data,
+ data: TLDrawSnapshot,
ids: string[],
fn: (shape: T, i: number) => Partial | void,
pageId: string
): {
before: Record>
after: Record>
- data: Data
+ data: TLDrawSnapshot
} {
const beforeShapes: Record> = {}
const afterShapes: Record> = {}
@@ -440,8 +446,8 @@ export class TLDR {
},
},
})
- const dataWithBindingChanges = ids.reduce((cData, id) => {
- return TLDR.updateBindings(cData, id, beforeShapes, afterShapes, pageId)
+ const dataWithBindingChanges = ids.reduce((cTLDrawSnapshot, id) => {
+ return TLDR.updateBindings(cTLDrawSnapshot, id, beforeShapes, afterShapes, pageId)
}, dataWithMutations)
return {
@@ -451,7 +457,7 @@ export class TLDR {
}
}
- static createShapes(data: Data, shapes: TLDrawShape[], pageId: string): TLDrawCommand {
+ static createShapes(data: TLDrawSnapshot, shapes: TLDrawShape[], pageId: string): TLDrawCommand {
const before: TLDrawPatch = {
document: {
pages: {
@@ -515,7 +521,7 @@ export class TLDR {
}
static deleteShapes(
- data: Data,
+ data: TLDrawSnapshot,
shapes: TLDrawShape[] | string[],
pageId?: string
): TLDrawCommand {
@@ -612,7 +618,7 @@ export class TLDR {
return { ...shape, ...delta }
}
- static onChildrenChange(data: Data, shape: T, pageId: string) {
+ static onChildrenChange(data: TLDrawSnapshot, shape: T, pageId: string) {
if (!shape.children) return
const delta = TLDR.getShapeUtils(shape).onChildrenChange?.(
@@ -717,7 +723,7 @@ export class TLDR {
/* Parents */
/* -------------------------------------------------- */
- static updateParents(data: Data, pageId: string, changedShapeIds: string[]): void {
+ static updateParents(data: TLDrawSnapshot, pageId: string, changedShapeIds: string[]): void {
const page = TLDR.getPage(data, pageId)
if (changedShapeIds.length === 0) return
@@ -741,7 +747,7 @@ export class TLDR {
TLDR.updateParents(data, pageId, parentToUpdateIds)
}
- static getSelectedStyle(data: Data, pageId: string): ShapeStyles | false {
+ static getSelectedStyle(data: TLDrawSnapshot, pageId: string): ShapeStyles | false {
const { currentStyle } = data.appState
const page = data.document.pages[pageId]
@@ -782,23 +788,27 @@ export class TLDR {
/* Bindings */
/* -------------------------------------------------- */
- static getBinding(data: Data, id: string, pageId: string): TLDrawBinding {
+ static getBinding(data: TLDrawSnapshot, id: string, pageId: string): TLDrawBinding {
return TLDR.getPage(data, pageId).bindings[id]
}
- static getBindings(data: Data, pageId: string): TLDrawBinding[] {
+ static getBindings(data: TLDrawSnapshot, pageId: string): TLDrawBinding[] {
const page = TLDR.getPage(data, pageId)
return Object.values(page.bindings)
}
- static getBindableShapeIds(data: Data) {
+ static getBindableShapeIds(data: TLDrawSnapshot) {
return TLDR.getShapes(data, data.appState.currentPageId)
.filter((shape) => TLDR.getShapeUtils(shape).canBind)
.sort((a, b) => b.childIndex - a.childIndex)
.map((shape) => shape.id)
}
- static getBindingsWithShapeIds(data: Data, ids: string[], pageId: string): TLDrawBinding[] {
+ static getBindingsWithShapeIds(
+ data: TLDrawSnapshot,
+ ids: string[],
+ pageId: string
+ ): TLDrawBinding[] {
return Array.from(
new Set(
TLDR.getBindings(data, pageId).filter((binding) => {
@@ -808,7 +818,7 @@ export class TLDR {
)
}
- static getRelatedBindings(data: Data, ids: string[], pageId: string): TLDrawBinding[] {
+ static getRelatedBindings(data: TLDrawSnapshot, ids: string[], pageId: string): TLDrawBinding[] {
const changedShapeIds = new Set(ids)
const page = TLDR.getPage(data, pageId)
@@ -887,7 +897,7 @@ export class TLDR {
/* Groups */
/* -------------------------------------------------- */
- static flattenShape = (data: Data, shape: TLDrawShape): TLDrawShape[] => {
+ static flattenShape = (data: TLDrawSnapshot, shape: TLDrawShape): TLDrawShape[] => {
return [
shape,
...(shape.children ?? [])
@@ -897,13 +907,13 @@ export class TLDR {
]
}
- static flattenPage = (data: Data, pageId: string): TLDrawShape[] => {
+ static flattenPage = (data: TLDrawSnapshot, pageId: string): TLDrawShape[] => {
return Object.values(data.document.pages[pageId].shapes)
.sort((a, b) => a.childIndex - b.childIndex)
.reduce((acc, shape) => [...acc, ...TLDR.flattenShape(data, shape)], [])
}
- static getTopChildIndex = (data: Data, pageId: string): number => {
+ static getTopChildIndex = (data: TLDrawSnapshot, pageId: string): number => {
const shapes = TLDR.getShapes(data, pageId)
return shapes.length === 0
? 1
diff --git a/packages/tldraw/src/state/TLDrawState.spec.ts b/packages/tldraw/src/state/TLDrawState.spec.ts
index e134e5311..d277cb5e2 100644
--- a/packages/tldraw/src/state/TLDrawState.spec.ts
+++ b/packages/tldraw/src/state/TLDrawState.spec.ts
@@ -5,63 +5,63 @@ import { ArrowShape, ColorStyle, SessionType, TLDrawShapeType } from '~types'
import type { SelectTool } from './tools/SelectTool'
describe('TLDrawState', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
describe('When copying and pasting...', () => {
it('copies a shape', () => {
- tlstate.loadDocument(mockDocument).selectNone().copy(['rect1'])
+ state.loadDocument(mockDocument).selectNone().copy(['rect1'])
})
it('pastes a shape', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- const prevCount = Object.keys(tlstate.page.shapes).length
+ const prevCount = Object.keys(state.page.shapes).length
- tlstate.selectNone().copy(['rect1']).paste()
+ state.selectNone().copy(['rect1']).paste()
- expect(Object.keys(tlstate.page.shapes).length).toBe(prevCount + 1)
+ expect(Object.keys(state.page.shapes).length).toBe(prevCount + 1)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(prevCount)
+ expect(Object.keys(state.page.shapes).length).toBe(prevCount)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(prevCount + 1)
+ expect(Object.keys(state.page.shapes).length).toBe(prevCount + 1)
})
it('pastes a shape to a new page', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- tlstate.selectNone().copy(['rect1']).createPage().paste()
+ state.selectNone().copy(['rect1']).createPage().paste()
- expect(Object.keys(tlstate.page.shapes).length).toBe(1)
+ expect(Object.keys(state.page.shapes).length).toBe(1)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(0)
+ expect(Object.keys(state.page.shapes).length).toBe(0)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(1)
+ expect(Object.keys(state.page.shapes).length).toBe(1)
})
it('Copies grouped shapes.', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.group(['rect1', 'rect2'], 'groupA')
.select('groupA')
.copy()
- const beforeShapes = tlstate.shapes
+ const beforeShapes = state.shapes
- tlstate.paste()
+ state.paste()
- expect(tlstate.shapes.filter((shape) => shape.type === TLDrawShapeType.Group).length).toBe(2)
+ expect(state.shapes.filter((shape) => shape.type === TLDrawShapeType.Group).length).toBe(2)
- const afterShapes = tlstate.shapes
+ const afterShapes = state.shapes
const newShapes = afterShapes.filter(
(shape) => !beforeShapes.find(({ id }) => id === shape.id)
@@ -83,9 +83,9 @@ describe('TLDrawState', () => {
describe('When copying and pasting a shape with bindings', () => {
it('copies two bound shapes and their binding', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
- tlstate
+ state
.createShapes(
{ type: TLDrawShapeType.Rectangle, id: 'target1', point: [0, 0], size: [100, 100] },
{ type: TLDrawShapeType.Arrow, id: 'arrow1', point: [200, 200] }
@@ -95,23 +95,23 @@ describe('TLDrawState', () => {
.updateSession([55, 55])
.completeSession()
- expect(tlstate.bindings.length).toBe(1)
+ expect(state.bindings.length).toBe(1)
- tlstate.selectAll().copy().paste()
+ state.selectAll().copy().paste()
- const newArrow = tlstate.shapes.sort((a, b) => b.childIndex - a.childIndex)[0] as ArrowShape
+ const newArrow = state.shapes.sort((a, b) => b.childIndex - a.childIndex)[0] as ArrowShape
expect(newArrow.handles.start.bindingId).not.toBe(
- tlstate.getShape('arrow1').handles.start.bindingId
+ state.getShape('arrow1').handles.start.bindingId
)
- expect(tlstate.bindings.length).toBe(2)
+ expect(state.bindings.length).toBe(2)
})
it('removes bindings from copied shape handles', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
- tlstate
+ state
.createShapes(
{ type: TLDrawShapeType.Rectangle, id: 'target1', point: [0, 0], size: [100, 100] },
{ type: TLDrawShapeType.Arrow, id: 'arrow1', point: [200, 200] }
@@ -121,13 +121,13 @@ describe('TLDrawState', () => {
.updateSession([55, 55])
.completeSession()
- expect(tlstate.bindings.length).toBe(1)
+ expect(state.bindings.length).toBe(1)
- expect(tlstate.getShape('arrow1').handles.start.bindingId).toBeDefined()
+ expect(state.getShape('arrow1').handles.start.bindingId).toBeDefined()
- tlstate.select('arrow1').copy().paste()
+ state.select('arrow1').copy().paste()
- const newArrow = tlstate.shapes.sort((a, b) => b.childIndex - a.childIndex)[0] as ArrowShape
+ const newArrow = state.shapes.sort((a, b) => b.childIndex - a.childIndex)[0] as ArrowShape
expect(newArrow.handles.start.bindingId).toBeUndefined()
})
@@ -135,62 +135,62 @@ describe('TLDrawState', () => {
describe('Selection', () => {
it('selects a shape', () => {
- tlstate.loadDocument(mockDocument).selectNone()
+ state.loadDocument(mockDocument).selectNone()
tlu.clickShape('rect1')
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual(['rect1'])
+ expect(state.appState.status).toBe('idle')
})
it('selects and deselects a shape', () => {
- tlstate.loadDocument(mockDocument).selectNone()
+ state.loadDocument(mockDocument).selectNone()
tlu.clickShape('rect1')
tlu.clickCanvas()
- expect(tlstate.selectedIds).toStrictEqual([])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual([])
+ expect(state.appState.status).toBe('idle')
})
it('selects multiple shapes', () => {
- tlstate.loadDocument(mockDocument).selectNone()
+ state.loadDocument(mockDocument).selectNone()
tlu.clickShape('rect1')
tlu.clickShape('rect2', { shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.appState.status).toBe('idle')
})
it('shift-selects to deselect shapes', () => {
- tlstate.loadDocument(mockDocument).selectNone()
+ state.loadDocument(mockDocument).selectNone()
tlu.clickShape('rect1')
tlu.clickShape('rect2', { shiftKey: true })
tlu.clickShape('rect2', { shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual(['rect1'])
+ expect(state.appState.status).toBe('idle')
})
it('clears selection when clicking bounds', () => {
- tlstate.loadDocument(mockDocument).selectNone()
- tlstate.startSession(SessionType.Brush, [-10, -10])
- tlstate.updateSession([110, 110])
- tlstate.completeSession()
- expect(tlstate.selectedIds.length).toBe(3)
+ state.loadDocument(mockDocument).selectNone()
+ state.startSession(SessionType.Brush, [-10, -10])
+ state.updateSession([110, 110])
+ state.completeSession()
+ expect(state.selectedIds.length).toBe(3)
})
it('selects selected shape when single-clicked', () => {
- tlstate.loadDocument(mockDocument).selectAll()
+ state.loadDocument(mockDocument).selectAll()
tlu.clickShape('rect2')
- expect(tlstate.selectedIds).toStrictEqual(['rect2'])
+ expect(state.selectedIds).toStrictEqual(['rect2'])
})
// it('selects shape when double-clicked', () => {
- // tlstate.loadDocument(mockDocument).selectAll()
+ // state.loadDocument(mockDocument).selectAll()
// tlu.doubleClickShape('rect2')
- // expect(tlstate.selectedIds).toStrictEqual(['rect2'])
+ // expect(state.selectedIds).toStrictEqual(['rect2'])
// })
it('does not select on meta-click', () => {
- tlstate.loadDocument(mockDocument).selectNone()
+ state.loadDocument(mockDocument).selectNone()
tlu.clickShape('rect1', { ctrlKey: true })
- expect(tlstate.selectedIds).toStrictEqual([])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual([])
+ expect(state.appState.status).toBe('idle')
})
it.todo('deletes shapes if cancelled during creating')
@@ -201,120 +201,120 @@ describe('TLDrawState', () => {
describe('When selecting all', () => {
it('selects all', () => {
- const tlstate = new TLDrawState().loadDocument(mockDocument).selectAll()
- expect(tlstate.selectedIds).toMatchSnapshot('selected all')
+ const state = new TLDrawState().loadDocument(mockDocument).selectAll()
+ expect(state.selectedIds).toMatchSnapshot('selected all')
})
it('does not select children of a group', () => {
- const tlstate = new TLDrawState().loadDocument(mockDocument).selectAll().group()
- expect(tlstate.selectedIds.length).toBe(1)
+ const state = new TLDrawState().loadDocument(mockDocument).selectAll().group()
+ expect(state.selectedIds.length).toBe(1)
})
})
// Single click on a selected shape to select just that shape
it('single-selects shape in selection on click', () => {
- tlstate.selectNone()
+ state.selectNone()
tlu.clickShape('rect1')
tlu.clickShape('rect2', { shiftKey: true })
tlu.clickShape('rect2')
- expect(tlstate.selectedIds).toStrictEqual(['rect2'])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual(['rect2'])
+ expect(state.appState.status).toBe('idle')
})
it('single-selects shape in selection on pointerup only', () => {
- tlstate.selectNone()
+ state.selectNone()
tlu.clickShape('rect1')
tlu.clickShape('rect2', { shiftKey: true })
tlu.pointShape('rect2')
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
tlu.stopPointing('rect2')
- expect(tlstate.selectedIds).toStrictEqual(['rect2'])
- expect(tlstate.appState.status).toBe('idle')
+ expect(state.selectedIds).toStrictEqual(['rect2'])
+ expect(state.appState.status).toBe('idle')
})
// it('selects shapes if shift key is lifted before pointerup', () => {
- // tlstate.selectNone()
+ // state.selectNone()
// tlu.clickShape('rect1')
// tlu.pointShape('rect2', { shiftKey: true })
- // expect(tlstate.appState.status).toBe('pointingBounds')
+ // expect(state.appState.status).toBe('pointingBounds')
// tlu.stopPointing('rect2')
- // expect(tlstate.selectedIds).toStrictEqual(['rect2'])
- // expect(tlstate.appState.status).toBe('idle')
+ // expect(state.selectedIds).toStrictEqual(['rect2'])
+ // expect(state.appState.status).toBe('idle')
// })
})
describe('Select history', () => {
it('selects, undoes and redoes', () => {
- tlstate.reset().loadDocument(mockDocument)
+ state.reset().loadDocument(mockDocument)
- expect(tlstate.selectHistory.pointer).toBe(0)
- expect(tlstate.selectHistory.stack).toStrictEqual([[]])
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectHistory.pointer).toBe(0)
+ expect(state.selectHistory.stack).toStrictEqual([[]])
+ expect(state.selectedIds).toStrictEqual([])
tlu.pointShape('rect1')
- expect(tlstate.selectHistory.pointer).toBe(1)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1']])
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectHistory.pointer).toBe(1)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1']])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
tlu.stopPointing('rect1')
- expect(tlstate.selectHistory.pointer).toBe(1)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1']])
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectHistory.pointer).toBe(1)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1']])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
tlu.clickShape('rect2', { shiftKey: true })
- expect(tlstate.selectHistory.pointer).toBe(2)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.selectHistory.pointer).toBe(2)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
- tlstate.undoSelect()
+ state.undoSelect()
- expect(tlstate.selectHistory.pointer).toBe(1)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectHistory.pointer).toBe(1)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
- tlstate.undoSelect()
+ state.undoSelect()
- expect(tlstate.selectHistory.pointer).toBe(0)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectHistory.pointer).toBe(0)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
+ expect(state.selectedIds).toStrictEqual([])
- tlstate.redoSelect()
+ state.redoSelect()
- expect(tlstate.selectHistory.pointer).toBe(1)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectHistory.pointer).toBe(1)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect1', 'rect2']])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
- tlstate.select('rect2')
+ state.select('rect2')
- expect(tlstate.selectHistory.pointer).toBe(2)
- expect(tlstate.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect2']])
- expect(tlstate.selectedIds).toStrictEqual(['rect2'])
+ expect(state.selectHistory.pointer).toBe(2)
+ expect(state.selectHistory.stack).toStrictEqual([[], ['rect1'], ['rect2']])
+ expect(state.selectedIds).toStrictEqual(['rect2'])
- tlstate.delete()
+ state.delete()
- expect(tlstate.selectHistory.pointer).toBe(0)
- expect(tlstate.selectHistory.stack).toStrictEqual([[]])
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectHistory.pointer).toBe(0)
+ expect(state.selectHistory.stack).toStrictEqual([[]])
+ expect(state.selectedIds).toStrictEqual([])
- tlstate.undoSelect()
+ state.undoSelect()
- expect(tlstate.selectHistory.pointer).toBe(0)
- expect(tlstate.selectHistory.stack).toStrictEqual([[]])
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectHistory.pointer).toBe(0)
+ expect(state.selectHistory.stack).toStrictEqual([[]])
+ expect(state.selectedIds).toStrictEqual([])
})
})
describe('Copies to JSON', () => {
- tlstate.selectAll()
- expect(tlstate.copyJson()).toMatchSnapshot('copied json')
+ state.selectAll()
+ expect(state.copyJson()).toMatchSnapshot('copied json')
})
describe('Mutates bound shapes', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.createShapes(
{
id: 'rect',
@@ -337,88 +337,80 @@ describe('TLDrawState', () => {
.selectAll()
.style({ color: ColorStyle.Red })
- expect(tlstate.getShape('arrow').style.color).toBe(ColorStyle.Red)
- expect(tlstate.getShape('rect').style.color).toBe(ColorStyle.Red)
+ expect(state.getShape('arrow').style.color).toBe(ColorStyle.Red)
+ expect(state.getShape('rect').style.color).toBe(ColorStyle.Red)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('arrow').style.color).toBe(ColorStyle.Black)
- expect(tlstate.getShape('rect').style.color).toBe(ColorStyle.Black)
+ expect(state.getShape('arrow').style.color).toBe(ColorStyle.Black)
+ expect(state.getShape('rect').style.color).toBe(ColorStyle.Black)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('arrow').style.color).toBe(ColorStyle.Red)
- expect(tlstate.getShape('rect').style.color).toBe(ColorStyle.Red)
+ expect(state.getShape('arrow').style.color).toBe(ColorStyle.Red)
+ expect(state.getShape('rect').style.color).toBe(ColorStyle.Red)
})
describe('when selecting shapes in a group', () => {
it('selects the group when a grouped shape is clicked', () => {
- const tlstate = new TLDrawState()
- .loadDocument(mockDocument)
- .group(['rect1', 'rect2'], 'groupA')
+ const state = new TLDrawState().loadDocument(mockDocument).group(['rect1', 'rect2'], 'groupA')
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
tlu.clickShape('rect1')
- expect((tlstate.currentTool as SelectTool).selectedGroupId).toBeUndefined()
- expect(tlstate.selectedIds).toStrictEqual(['groupA'])
+ expect((state.currentTool as SelectTool).selectedGroupId).toBeUndefined()
+ expect(state.selectedIds).toStrictEqual(['groupA'])
})
it('selects the grouped shape when double clicked', () => {
- const tlstate = new TLDrawState()
- .loadDocument(mockDocument)
- .group(['rect1', 'rect2'], 'groupA')
+ const state = new TLDrawState().loadDocument(mockDocument).group(['rect1', 'rect2'], 'groupA')
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
tlu.doubleClickShape('rect1')
- expect((tlstate.currentTool as SelectTool).selectedGroupId).toStrictEqual('groupA')
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect((state.currentTool as SelectTool).selectedGroupId).toStrictEqual('groupA')
+ expect(state.selectedIds).toStrictEqual(['rect1'])
})
it('clears the selectedGroupId when selecting a different shape', () => {
- const tlstate = new TLDrawState()
- .loadDocument(mockDocument)
- .group(['rect1', 'rect2'], 'groupA')
+ const state = new TLDrawState().loadDocument(mockDocument).group(['rect1', 'rect2'], 'groupA')
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
tlu.doubleClickShape('rect1')
tlu.clickShape('rect3')
- expect((tlstate.currentTool as SelectTool).selectedGroupId).toBeUndefined()
- expect(tlstate.selectedIds).toStrictEqual(['rect3'])
+ expect((state.currentTool as SelectTool).selectedGroupId).toBeUndefined()
+ expect(state.selectedIds).toStrictEqual(['rect3'])
})
it('selects a grouped shape when meta-shift-clicked', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.group(['rect1', 'rect2'], 'groupA')
.selectNone()
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
tlu.clickShape('rect1', { ctrlKey: true, shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
tlu.clickShape('rect1', { ctrlKey: true, shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectedIds).toStrictEqual([])
})
it('selects a hovered shape from the selected group when meta-shift-clicked', () => {
- const tlstate = new TLDrawState()
- .loadDocument(mockDocument)
- .group(['rect1', 'rect2'], 'groupA')
+ const state = new TLDrawState().loadDocument(mockDocument).group(['rect1', 'rect2'], 'groupA')
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
tlu.clickShape('rect1', { ctrlKey: true, shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual(['rect1'])
+ expect(state.selectedIds).toStrictEqual(['rect1'])
tlu.clickShape('rect1', { ctrlKey: true, shiftKey: true })
- expect(tlstate.selectedIds).toStrictEqual([])
+ expect(state.selectedIds).toStrictEqual([])
})
})
describe('when creating shapes', () => {
it('Creates shapes with the correct child index', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.createShapes(
{
id: 'rect1',
@@ -438,39 +430,39 @@ describe('TLDrawState', () => {
)
.selectTool(TLDrawShapeType.Rectangle)
- const tlu = new TLDrawStateUtils(tlstate)
+ const tlu = new TLDrawStateUtils(state)
- const prevA = tlstate.shapes.map((shape) => shape.id)
+ const prevA = state.shapes.map((shape) => shape.id)
tlu.pointCanvas({ x: 0, y: 0 })
tlu.movePointer({ x: 100, y: 100 })
tlu.stopPointing()
- const newIdA = tlstate.shapes.map((shape) => shape.id).find((id) => !prevA.includes(id))!
- const shapeA = tlstate.getShape(newIdA)
+ const newIdA = state.shapes.map((shape) => shape.id).find((id) => !prevA.includes(id))!
+ const shapeA = state.getShape(newIdA)
expect(shapeA.childIndex).toBe(4)
- tlstate.group(['rect2', 'rect3', newIdA], 'groupA')
+ state.group(['rect2', 'rect3', newIdA], 'groupA')
- expect(tlstate.getShape('groupA').childIndex).toBe(2)
+ expect(state.getShape('groupA').childIndex).toBe(2)
- tlstate.selectNone()
- tlstate.selectTool(TLDrawShapeType.Rectangle)
+ state.selectNone()
+ state.selectTool(TLDrawShapeType.Rectangle)
- const prevB = tlstate.shapes.map((shape) => shape.id)
+ const prevB = state.shapes.map((shape) => shape.id)
tlu.pointCanvas({ x: 0, y: 0 })
tlu.movePointer({ x: 100, y: 100 })
tlu.stopPointing()
- const newIdB = tlstate.shapes.map((shape) => shape.id).find((id) => !prevB.includes(id))!
- const shapeB = tlstate.getShape(newIdB)
+ const newIdB = state.shapes.map((shape) => shape.id).find((id) => !prevB.includes(id))!
+ const shapeB = state.getShape(newIdB)
expect(shapeB.childIndex).toBe(3)
})
})
it('Exposes undo/redo stack', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.createShapes({
id: 'rect1',
@@ -485,23 +477,23 @@ describe('TLDrawState', () => {
size: [100, 200],
})
- expect(tlstate.history.length).toBe(2)
+ expect(state.history.length).toBe(2)
- expect(tlstate.history).toBeDefined()
- expect(tlstate.history).toMatchSnapshot('history')
+ expect(state.history).toBeDefined()
+ expect(state.history).toMatchSnapshot('history')
- tlstate.history = []
- expect(tlstate.history).toEqual([])
+ state.history = []
+ expect(state.history).toEqual([])
- const before = tlstate.state
- tlstate.undo()
- const after = tlstate.state
+ const before = state.state
+ state.undo()
+ const after = state.state
expect(before).toBe(after)
})
it('Exposes undo/redo stack up to the current pointer', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.createShapes({
id: 'rect1',
@@ -517,11 +509,11 @@ describe('TLDrawState', () => {
})
.undo()
- expect(tlstate.history.length).toBe(1)
+ expect(state.history.length).toBe(1)
})
it('Sets the undo/redo history', () => {
- const tlstate = new TLDrawState('some_state_a')
+ const state = new TLDrawState('some_state_a')
.createShapes({
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -536,29 +528,29 @@ describe('TLDrawState', () => {
})
// Save the history and document from the first state
- const doc = tlstate.document
- const history = tlstate.history
+ const doc = state.document
+ const history = state.history
// Create a new state
- const tlstate2 = new TLDrawState('some_state_b')
+ const state2 = new TLDrawState('some_state_b')
// Load the document and set the history
- tlstate2.loadDocument(doc)
- tlstate2.history = history
+ state2.loadDocument(doc)
+ state2.history = history
- expect(tlstate2.shapes.length).toBe(2)
+ expect(state2.shapes.length).toBe(2)
// We should be able to undo the change that was made on the first
// state, now that we've brought in its undo / redo stack
- tlstate2.undo()
+ state2.undo()
- expect(tlstate2.shapes.length).toBe(1)
+ expect(state2.shapes.length).toBe(1)
})
describe('When copying to SVG', () => {
it('Copies shapes.', () => {
- const tlstate = new TLDrawState()
- const result = tlstate
+ const state = new TLDrawState()
+ const result = state
.loadDocument(mockDocument)
.select('rect1')
.rotate(0.1)
@@ -568,8 +560,8 @@ describe('TLDrawState', () => {
})
it('Copies grouped shapes.', () => {
- const tlstate = new TLDrawState()
- const result = tlstate
+ const state = new TLDrawState()
+ const result = state
.loadDocument(mockDocument)
.select('rect1', 'rect2')
.group()
@@ -581,9 +573,9 @@ describe('TLDrawState', () => {
it.todo('Copies Text shapes as elements.')
// it('Copies Text shapes as elements.', () => {
- // const tlstate2 = new TLDrawState()
+ // const state2 = new TLDrawState()
- // const svgString = tlstate2
+ // const svgString = state2
// .createShapes({
// id: 'text1',
// type: TLDrawShapeType.Text,
@@ -633,9 +625,9 @@ describe('TLDrawState', () => {
TLDrawState.defaultState = withoutRoom
- const tlstate = new TLDrawState('migrate_1')
+ const state = new TLDrawState('migrate_1')
- tlstate.createShapes({
+ state.createShapes({
id: 'rect1',
type: TLDrawShapeType.Rectangle,
})
@@ -645,11 +637,11 @@ describe('TLDrawState', () => {
TLDrawState.version = 100
TLDrawState.defaultState.room = defaultState.room
- const tlstate2 = new TLDrawState('migrate_1')
+ const state2 = new TLDrawState('migrate_1')
setTimeout(() => {
try {
- expect(tlstate2.getShape('rect1')).toBeTruthy()
+ expect(state2.getShape('rect1')).toBeTruthy()
done()
} catch (e) {
done(e)
diff --git a/packages/tldraw/src/state/TLDrawState.ts b/packages/tldraw/src/state/TLDrawState.ts
index 757e08fc3..02da22fc2 100644
--- a/packages/tldraw/src/state/TLDrawState.ts
+++ b/packages/tldraw/src/state/TLDrawState.ts
@@ -27,7 +27,7 @@ import {
ShapeStyles,
TLDrawShape,
TLDrawShapeType,
- Data,
+ TLDrawSnapshot,
Session,
TLDrawStatus,
SelectHistory,
@@ -58,35 +58,86 @@ import { USER_COLORS, FIT_TO_SCREEN_PADDING } from '~constants'
const uuid = Utils.uniqueId()
-export class TLDrawState extends StateManager {
- private _onMount?: (tlstate: TLDrawState) => void
- private _onChange?: (tlstate: TLDrawState, data: Data, reason: string) => void
- private _onUserChange?: (tlstate: TLDrawState, user: TLDrawUser) => void
+export interface TLDrawCallbacks {
+ /**
+ * (optional) A callback to run when the component mounts.
+ */
+ onMount?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the component's state changes.
+ */
+ onChange?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the user creates a new project through the menu or through a keyboard shortcut.
+ */
+ onNewProject?: (state: TLDrawState, e?: KeyboardEvent) => void
+ /**
+ * (optional) A callback to run when the user saves a project through the menu or through a keyboard shortcut.
+ */
+ onSaveProject?: (state: TLDrawState, e?: KeyboardEvent) => void
+ /**
+ * (optional) A callback to run when the user saves a project as a new project through the menu or through a keyboard shortcut.
+ */
+ onSaveProjectAs?: (state: TLDrawState, e?: KeyboardEvent) => void
+ /**
+ * (optional) A callback to run when the user opens new project through the menu or through a keyboard shortcut.
+ */
+ onOpenProject?: (state: TLDrawState, e?: KeyboardEvent) => void
+ /**
+ * (optional) A callback to run when the user signs in via the menu.
+ */
+ onSignIn?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user signs out via the menu.
+ */
+ onSignOut?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user creates a new project.
+ */
+ onUserChange?: (state: TLDrawState, user: TLDrawUser) => void
+ /**
+ * (optional) A callback to run when the state is patched.
+ */
+ onPatch?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the state is changed with a command.
+ */
+ onCommand?: (state: TLDrawState, reason?: string) => void
+ /**
+ * (optional) A callback to run when the state is persisted.
+ */
+ onPersist?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user undos.
+ */
+ onUndo?: (state: TLDrawState) => void
+ /**
+ * (optional) A callback to run when the user redos.
+ */
+ onRedo?: (state: TLDrawState) => void
+}
- readOnly = false
-
- inputs?: Inputs
+export class TLDrawState extends StateManager {
+ public callbacks: TLDrawCallbacks = {}
selectHistory: SelectHistory = {
stack: [[]],
pointer: 0,
}
- clipboard?: {
+ private clipboard?: {
shapes: TLDrawShape[]
bindings: TLDrawBinding[]
}
- tools = createTools(this)
+ private tools = createTools(this)
currentTool: BaseTool = this.tools.select
- session?: Session
-
- isCreating = false
+ private isCreating = false
// The editor's bounding client rect
- bounds: TLBounds = {
+ private bounds: TLBounds = {
minX: 0,
minY: 0,
maxX: 640,
@@ -96,7 +147,7 @@ export class TLDrawState extends StateManager {
}
// The most recent pointer location
- pointerPoint: number[] = [0, 0]
+ private pointerPoint: number[] = [0, 0]
private pasteInfo = {
center: [0, 0],
@@ -104,15 +155,11 @@ export class TLDrawState extends StateManager {
}
fileSystemHandle: FileSystemHandle | null = null
-
+ readOnly = false
+ session?: Session
isDirty = false
- constructor(
- id?: string,
- onMount?: (tlstate: TLDrawState) => void,
- onChange?: (tlstate: TLDrawState, data: Data, reason: string) => void,
- onUserChange?: (tlstate: TLDrawState, user: TLDrawUser) => void
- ) {
+ constructor(id?: string, callbacks = {} as TLDrawCallbacks) {
super(TLDrawState.defaultState, id, TLDrawState.version, (prev, next, prevVersion) => {
return {
...next,
@@ -123,23 +170,18 @@ export class TLDrawState extends StateManager {
}
})
+ this.callbacks = callbacks
+ }
+
+ /* -------------------- Internal -------------------- */
+
+ protected onReady = () => {
this.loadDocument(this.document)
- this.patchState({ document: migrate(this.document, TLDrawState.version) })
loadFileHandle().then((fileHandle) => {
this.fileSystemHandle = fileHandle
})
- this._onChange = onChange
- this._onMount = onMount
- this._onUserChange = onUserChange
-
- this.session = undefined
- }
-
- /* -------------------- Internal -------------------- */
-
- onReady = () => {
try {
this.patchState({
appState: {
@@ -160,8 +202,7 @@ export class TLDrawState extends StateManager {
})
}
- this.persist()
- this._onMount?.(this)
+ this.callbacks.onMount?.(this)
}
/**
@@ -171,7 +212,7 @@ export class TLDrawState extends StateManager {
* @protected
* @returns The final state
*/
- protected cleanup = (state: Data, prev: Data): Data => {
+ protected cleanup = (state: TLDrawSnapshot, prev: TLDrawSnapshot): TLDrawSnapshot => {
const data = { ...state }
// Remove deleted shapes and bindings (in Commands, these will be set to undefined)
@@ -361,29 +402,58 @@ export class TLDrawState extends StateManager {
return data
}
+ onPatch = (state: TLDrawSnapshot, id?: string) => {
+ this.callbacks.onPatch?.(this, id)
+ }
+
+ onCommand = (state: TLDrawSnapshot, id?: string) => {
+ this.clearSelectHistory()
+ this.isDirty = true
+ this.callbacks.onCommand?.(this, id)
+ }
+
+ onReplace = () => {
+ this.clearSelectHistory()
+ this.isDirty = false
+ }
+
+ onUndo = () => {
+ Session.cache.selectedIds = [...this.selectedIds]
+ this.callbacks.onUndo?.(this)
+ }
+
+ onRedo = () => {
+ Session.cache.selectedIds = [...this.selectedIds]
+ this.callbacks.onRedo?.(this)
+ }
+
+ onPersist = () => {
+ this.callbacks.onPersist?.(this)
+ }
+
/**
* Clear the selection history after each new command, undo or redo.
* @param state
* @param id
*/
- protected onStateDidChange = (state: Data, id: string): void => {
- if (!id.startsWith('patch')) {
- if (!id.startsWith('replace')) {
- // If we've changed the undo stack, then the file is out of
- // sync with any saved version on the file system.
- this.isDirty = true
- }
-
- this.clearSelectHistory()
- }
-
- if (id.startsWith('undo') || id.startsWith('redo')) {
- Session.cache.selectedIds = [...this.selectedIds]
- }
-
- this._onChange?.(this, state, id)
+ protected onStateDidChange = (_state: TLDrawSnapshot, id?: string): void => {
+ this.callbacks.onChange?.(this, id)
}
+ // if (id && !id.startsWith('patch')) {
+ // if (!id.startsWith('replace')) {
+ // // If we've changed the undo stack, then the file is out of
+ // // sync with any saved version on the file system.
+ // this.isDirty = true
+ // }
+ // this.clearSelectHistory()
+ // }
+ // if (id.startsWith('undo') || id.startsWith('redo')) {
+ // Session.cache.selectedIds = [...this.selectedIds]
+ // }
+ // this.onChange?.(this, id)
+ // }
+
/**
* Set the current status.
* @param status The new status to set.
@@ -456,13 +526,16 @@ export class TLDrawState extends StateManager {
/**
* Set a setting.
*/
- setSetting = (
+ setSetting = <
+ T extends keyof TLDrawSnapshot['settings'],
+ V extends TLDrawSnapshot['settings'][T]
+ >(
name: T,
value: V | ((value: V) => V)
): this => {
if (this.session) return this
- return this.patchState(
+ this.patchState(
{
settings: {
[name]: typeof value === 'function' ? value(this.state.settings[name] as V) : value,
@@ -470,6 +543,8 @@ export class TLDrawState extends StateManager {
},
`settings:${name}`
)
+ this.persist()
+ return this
}
/**
@@ -477,7 +552,7 @@ export class TLDrawState extends StateManager {
*/
toggleFocusMode = (): this => {
if (this.session) return this
- return this.patchState(
+ this.patchState(
{
settings: {
isFocusMode: !this.state.settings.isFocusMode,
@@ -485,6 +560,8 @@ export class TLDrawState extends StateManager {
},
`settings:toggled_focus_mode`
)
+ this.persist()
+ return this
}
/**
@@ -492,7 +569,7 @@ export class TLDrawState extends StateManager {
*/
togglePenMode = (): this => {
if (this.session) return this
- return this.patchState(
+ this.patchState(
{
settings: {
isPenMode: !this.state.settings.isPenMode,
@@ -500,6 +577,8 @@ export class TLDrawState extends StateManager {
},
`settings:toggled_pen_mode`
)
+ this.persist()
+ return this
}
/**
@@ -816,8 +895,7 @@ export class TLDrawState extends StateManager {
this.resetHistory()
this.clearSelectHistory()
this.session = undefined
-
- return this.replaceState(
+ this.replaceState(
{
...TLDrawState.defaultState,
document: migrate(document, TLDrawState.version),
@@ -828,6 +906,7 @@ export class TLDrawState extends StateManager {
},
'loaded_document'
)
+ return this
}
// Should we move this to the app layer? onSave, onSaveAs, etc?
@@ -912,7 +991,7 @@ export class TLDrawState extends StateManager {
/**
* Get the current app state.
*/
- getAppState = (): Data['appState'] => {
+ getAppState = (): TLDrawSnapshot['appState'] => {
return this.appState
}
@@ -958,10 +1037,6 @@ export class TLDrawState extends StateManager {
return TLDR.getBounds(this.getShape(id, pageId))
}
- greet() {
- return 'hello'
- }
-
/**
* Get a binding from a given page.
* @param id The binding's id.
@@ -1013,7 +1088,7 @@ export class TLDrawState extends StateManager {
/**
* The current app state.
*/
- get appState(): Data['appState'] {
+ get appState(): TLDrawSnapshot['appState'] {
return this.state.appState
}
@@ -1598,7 +1673,7 @@ export class TLDrawState extends StateManager {
* @param delta The zoom delta.
* @param center The point to zoom toward.
*/
- zoom = Utils.throttle((delta: number, center?: number[]): this => {
+ zoomBy = Utils.throttle((delta: number, center?: number[]): this => {
const { zoom } = this.pageState.camera
const nextZoom = TLDR.getCameraZoom(zoom - delta * zoom)
return this.zoomTo(nextZoom, center)
@@ -1639,7 +1714,8 @@ export class TLDrawState extends StateManager {
if (this.state.room) {
const { users, userId } = this.state.room
- this._onUserChange?.(this, {
+
+ this.callbacks.onUserChange?.(this, {
...users[userId],
selectedIds: nextIds,
})
@@ -2034,7 +2110,7 @@ export class TLDrawState extends StateManager {
/**
* Delete all shapes on the page.
*/
- clear = (): this => {
+ deleteAll = (): this => {
this.selectAll()
this.delete()
return this
@@ -2333,7 +2409,7 @@ export class TLDrawState extends StateManager {
onZoom: TLWheelEventHandler = (info, e) => {
if (this.state.appState.status !== TLDrawStatus.Idle) return
- this.zoom(info.delta[2] / 100, info.delta)
+ this.zoomBy(info.delta[2] / 100, info.delta)
this.onPointerMove(info, e as unknown as React.PointerEvent)
}
@@ -2349,7 +2425,7 @@ export class TLDrawState extends StateManager {
if (this.state.room) {
const { users, userId } = this.state.room
- this._onUserChange?.(this, {
+ this.callbacks.onUserChange?.(this, {
...users[userId],
point: this.getPagePoint(info.point),
})
@@ -2565,7 +2641,7 @@ export class TLDrawState extends StateManager {
},
}
- static defaultState: Data = {
+ static defaultState: TLDrawSnapshot = {
settings: {
isPenMode: false,
isDarkMode: false,
diff --git a/packages/tldraw/src/state/commands/alignShapes/alignShapes.spec.ts b/packages/tldraw/src/state/commands/alignShapes/alignShapes.spec.ts
index ff5a6c2c1..e094eb10e 100644
--- a/packages/tldraw/src/state/commands/alignShapes/alignShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/alignShapes/alignShapes.spec.ts
@@ -4,14 +4,14 @@ import { mockDocument, TLDrawStateUtils } from '~test'
import { AlignType, TLDrawShapeType } from '~types'
describe('Align command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
describe('when less than two shapes are selected', () => {
it('does nothing', () => {
- tlstate.loadDocument(mockDocument).select('rect2')
- const initialState = tlstate.state
- tlstate.align(AlignType.Top)
- const currentState = tlstate.state
+ state.loadDocument(mockDocument).select('rect2')
+ const initialState = state.state
+ state.align(AlignType.Top)
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
@@ -19,67 +19,67 @@ describe('Align command', () => {
describe('when multiple shapes are selected', () => {
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
- tlstate.selectAll()
+ state.loadDocument(mockDocument)
+ state.selectAll()
})
it('does, undoes and redoes command', () => {
- tlstate.align(AlignType.Top)
+ state.align(AlignType.Top)
- expect(tlstate.getShape('rect2').point).toEqual([100, 0])
+ expect(state.getShape('rect2').point).toEqual([100, 0])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect2').point).toEqual([100, 100])
+ expect(state.getShape('rect2').point).toEqual([100, 100])
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect2').point).toEqual([100, 0])
+ expect(state.getShape('rect2').point).toEqual([100, 0])
})
it('aligns top', () => {
- tlstate.align(AlignType.Top)
+ state.align(AlignType.Top)
- expect(tlstate.getShape('rect2').point).toEqual([100, 0])
+ expect(state.getShape('rect2').point).toEqual([100, 0])
})
it('aligns right', () => {
- tlstate.align(AlignType.Right)
+ state.align(AlignType.Right)
- expect(tlstate.getShape('rect1').point).toEqual([100, 0])
+ expect(state.getShape('rect1').point).toEqual([100, 0])
})
it('aligns bottom', () => {
- tlstate.align(AlignType.Bottom)
+ state.align(AlignType.Bottom)
- expect(tlstate.getShape('rect1').point).toEqual([0, 100])
+ expect(state.getShape('rect1').point).toEqual([0, 100])
})
it('aligns left', () => {
- tlstate.align(AlignType.Left)
+ state.align(AlignType.Left)
- expect(tlstate.getShape('rect2').point).toEqual([0, 100])
+ expect(state.getShape('rect2').point).toEqual([0, 100])
})
it('aligns center horizontal', () => {
- tlstate.align(AlignType.CenterHorizontal)
+ state.align(AlignType.CenterHorizontal)
- expect(tlstate.getShape('rect1').point).toEqual([50, 0])
- expect(tlstate.getShape('rect2').point).toEqual([50, 100])
+ expect(state.getShape('rect1').point).toEqual([50, 0])
+ expect(state.getShape('rect2').point).toEqual([50, 100])
})
it('aligns center vertical', () => {
- tlstate.align(AlignType.CenterVertical)
+ state.align(AlignType.CenterVertical)
- expect(tlstate.getShape('rect1').point).toEqual([0, 50])
- expect(tlstate.getShape('rect2').point).toEqual([100, 50])
+ expect(state.getShape('rect1').point).toEqual([0, 50])
+ expect(state.getShape('rect2').point).toEqual([100, 50])
})
})
})
describe('when aligning groups', () => {
it('aligns children', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.createShapes(
{ id: 'rect1', type: TLDrawShapeType.Rectangle, point: [0, 0], size: [100, 100] },
{ id: 'rect2', type: TLDrawShapeType.Rectangle, point: [100, 100], size: [100, 100] },
@@ -90,12 +90,12 @@ describe('when aligning groups', () => {
.select('rect3', 'rect4')
.align(AlignType.CenterVertical)
- const p0 = tlstate.getShape('rect4').point
- const p1 = tlstate.getShape('rect3').point
+ const p0 = state.getShape('rect4').point
+ const p1 = state.getShape('rect3').point
- tlstate.undo().delete(['rect4']).selectAll().align(AlignType.CenterVertical)
+ state.undo().delete(['rect4']).selectAll().align(AlignType.CenterVertical)
- new TLDrawStateUtils(tlstate).expectShapesToBeAtPoints({
+ new TLDrawStateUtils(state).expectShapesToBeAtPoints({
rect1: p0,
rect2: Vec.add(p0, [100, 100]),
rect3: p1,
diff --git a/packages/tldraw/src/state/commands/alignShapes/alignShapes.ts b/packages/tldraw/src/state/commands/alignShapes/alignShapes.ts
index cc8e5143c..e28966c27 100644
--- a/packages/tldraw/src/state/commands/alignShapes/alignShapes.ts
+++ b/packages/tldraw/src/state/commands/alignShapes/alignShapes.ts
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { Utils } from '@tldraw/core'
import { AlignType, TLDrawCommand, TLDrawShapeType } from '~types'
-import type { Data } from '~types'
+import type { TLDrawSnapshot } from '~types'
import { TLDR } from '~state/TLDR'
import Vec from '@tldraw/vec'
-export function alignShapes(data: Data, ids: string[], type: AlignType): TLDrawCommand {
+export function alignShapes(data: TLDrawSnapshot, ids: string[], type: AlignType): TLDrawCommand {
const { currentPageId } = data.appState
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
diff --git a/packages/tldraw/src/state/commands/changePage/changePage.spec.ts b/packages/tldraw/src/state/commands/changePage/changePage.spec.ts
index 6f1379179..4ed72dfd6 100644
--- a/packages/tldraw/src/state/commands/changePage/changePage.spec.ts
+++ b/packages/tldraw/src/state/commands/changePage/changePage.spec.ts
@@ -2,31 +2,31 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Change page command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
it('does, undoes and redoes command', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- const initialId = tlstate.page.id
+ const initialId = state.page.id
- tlstate.createPage()
+ state.createPage()
- const nextId = tlstate.page.id
+ const nextId = state.page.id
- tlstate.changePage(initialId)
+ state.changePage(initialId)
- expect(tlstate.page.id).toBe(initialId)
+ expect(state.page.id).toBe(initialId)
- tlstate.changePage(nextId)
+ state.changePage(nextId)
- expect(tlstate.page.id).toBe(nextId)
+ expect(state.page.id).toBe(nextId)
- tlstate.undo()
+ state.undo()
- expect(tlstate.page.id).toBe(initialId)
+ expect(state.page.id).toBe(initialId)
- tlstate.redo()
+ state.redo()
- expect(tlstate.page.id).toBe(nextId)
+ expect(state.page.id).toBe(nextId)
})
})
diff --git a/packages/tldraw/src/state/commands/changePage/changePage.ts b/packages/tldraw/src/state/commands/changePage/changePage.ts
index a625b3000..d6c5e4c07 100644
--- a/packages/tldraw/src/state/commands/changePage/changePage.ts
+++ b/packages/tldraw/src/state/commands/changePage/changePage.ts
@@ -1,6 +1,6 @@
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
-export function changePage(data: Data, pageId: string): TLDrawCommand {
+export function changePage(data: TLDrawSnapshot, pageId: string): TLDrawCommand {
return {
id: 'change_page',
before: {
diff --git a/packages/tldraw/src/state/commands/createPage/createPage.spec.ts b/packages/tldraw/src/state/commands/createPage/createPage.spec.ts
index e25ff1a36..bfea4ec5c 100644
--- a/packages/tldraw/src/state/commands/createPage/createPage.spec.ts
+++ b/packages/tldraw/src/state/commands/createPage/createPage.spec.ts
@@ -2,33 +2,33 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Create page command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
it('does, undoes and redoes command', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- const initialId = tlstate.page.id
- const initialPageState = tlstate.pageState
+ const initialId = state.page.id
+ const initialPageState = state.pageState
- tlstate.createPage()
+ state.createPage()
- const nextId = tlstate.page.id
- const nextPageState = tlstate.pageState
+ const nextId = state.page.id
+ const nextPageState = state.pageState
- expect(Object.keys(tlstate.document.pages).length).toBe(2)
- expect(tlstate.page.id).toBe(nextId)
- expect(tlstate.pageState).toEqual(nextPageState)
+ expect(Object.keys(state.document.pages).length).toBe(2)
+ expect(state.page.id).toBe(nextId)
+ expect(state.pageState).toEqual(nextPageState)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.document.pages).length).toBe(1)
- expect(tlstate.page.id).toBe(initialId)
- expect(tlstate.pageState).toEqual(initialPageState)
+ expect(Object.keys(state.document.pages).length).toBe(1)
+ expect(state.page.id).toBe(initialId)
+ expect(state.pageState).toEqual(initialPageState)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.document.pages).length).toBe(2)
- expect(tlstate.page.id).toBe(nextId)
- expect(tlstate.pageState).toEqual(nextPageState)
+ expect(Object.keys(state.document.pages).length).toBe(2)
+ expect(state.page.id).toBe(nextId)
+ expect(state.pageState).toEqual(nextPageState)
})
})
diff --git a/packages/tldraw/src/state/commands/createPage/createPage.ts b/packages/tldraw/src/state/commands/createPage/createPage.ts
index 8fb792ce9..3e4834d16 100644
--- a/packages/tldraw/src/state/commands/createPage/createPage.ts
+++ b/packages/tldraw/src/state/commands/createPage/createPage.ts
@@ -1,7 +1,11 @@
-import type { Data, TLDrawCommand, TLDrawPage } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand, TLDrawPage } from '~types'
import { Utils, TLPageState } from '@tldraw/core'
-export function createPage(data: Data, center: number[], pageId = Utils.uniqueId()): TLDrawCommand {
+export function createPage(
+ data: TLDrawSnapshot,
+ center: number[],
+ pageId = Utils.uniqueId()
+): TLDrawCommand {
const { currentPageId } = data.appState
const topPage = Object.values(data.document.pages).sort(
diff --git a/packages/tldraw/src/state/commands/createShapes/createShapes.spec.ts b/packages/tldraw/src/state/commands/createShapes/createShapes.spec.ts
index 9a9b532db..5a466fc1a 100644
--- a/packages/tldraw/src/state/commands/createShapes/createShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/createShapes/createShapes.spec.ts
@@ -2,36 +2,36 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Create command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is provided', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.create()
+ const initialState = state.state
+ state.create()
- const currentState = tlstate.state
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- const shape = { ...tlstate.getShape('rect1'), id: 'rect4' }
- tlstate.create([shape])
+ const shape = { ...state.getShape('rect1'), id: 'rect4' }
+ state.create([shape])
- expect(tlstate.getShape('rect4')).toBeTruthy()
+ expect(state.getShape('rect4')).toBeTruthy()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect4')).toBe(undefined)
+ expect(state.getShape('rect4')).toBe(undefined)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect4')).toBeTruthy()
+ expect(state.getShape('rect4')).toBeTruthy()
})
it.todo('Creates bindings')
diff --git a/packages/tldraw/src/state/commands/createShapes/createShapes.ts b/packages/tldraw/src/state/commands/createShapes/createShapes.ts
index 67e35f544..2557452d6 100644
--- a/packages/tldraw/src/state/commands/createShapes/createShapes.ts
+++ b/packages/tldraw/src/state/commands/createShapes/createShapes.ts
@@ -1,9 +1,9 @@
import type { Patch } from 'rko'
import { TLDR } from '~state/TLDR'
-import type { TLDrawShape, Data, TLDrawCommand, TLDrawBinding } from '~types'
+import type { TLDrawShape, TLDrawSnapshot, TLDrawCommand, TLDrawBinding } from '~types'
export function createShapes(
- data: Data,
+ data: TLDrawSnapshot,
shapes: TLDrawShape[],
bindings: TLDrawBinding[] = []
): TLDrawCommand {
diff --git a/packages/tldraw/src/state/commands/deletePage/deletePage.spec.ts b/packages/tldraw/src/state/commands/deletePage/deletePage.spec.ts
index 1d358bccb..7308c1e2d 100644
--- a/packages/tldraw/src/state/commands/deletePage/deletePage.spec.ts
+++ b/packages/tldraw/src/state/commands/deletePage/deletePage.spec.ts
@@ -2,40 +2,40 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Delete page', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when there are no pages in the current document', () => {
it('does nothing', () => {
- tlstate.resetDocument()
- const initialState = tlstate.state
- tlstate.deletePage('page1')
- const currentState = tlstate.state
+ state.resetDocument()
+ const initialState = state.state
+ state.deletePage('page1')
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- const initialId = tlstate.currentPageId
+ const initialId = state.currentPageId
- tlstate.createPage()
+ state.createPage()
- const nextId = tlstate.currentPageId
+ const nextId = state.currentPageId
- tlstate.deletePage()
+ state.deletePage()
- expect(tlstate.currentPageId).toBe(initialId)
+ expect(state.currentPageId).toBe(initialId)
- tlstate.undo()
+ state.undo()
- expect(tlstate.currentPageId).toBe(nextId)
+ expect(state.currentPageId).toBe(nextId)
- tlstate.redo()
+ state.redo()
- expect(tlstate.currentPageId).toBe(initialId)
+ expect(state.currentPageId).toBe(initialId)
})
})
diff --git a/packages/tldraw/src/state/commands/deletePage/deletePage.ts b/packages/tldraw/src/state/commands/deletePage/deletePage.ts
index b54fd7d8b..4f71bdf26 100644
--- a/packages/tldraw/src/state/commands/deletePage/deletePage.ts
+++ b/packages/tldraw/src/state/commands/deletePage/deletePage.ts
@@ -1,6 +1,6 @@
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
-export function deletePage(data: Data, pageId: string): TLDrawCommand {
+export function deletePage(data: TLDrawSnapshot, pageId: string): TLDrawCommand {
const { currentPageId } = data.appState
const pagesArr = Object.values(data.document.pages).sort(
diff --git a/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.spec.ts b/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.spec.ts
index 70c647fb1..1ec71c8bd 100644
--- a/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.spec.ts
@@ -3,56 +3,56 @@ import { mockDocument } from '~test'
import { SessionType, TLDrawShapeType } from '~types'
describe('Delete command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.delete()
- const currentState = tlstate.state
+ const initialState = state.state
+ state.delete()
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('rect2')
- tlstate.delete()
+ state.select('rect2')
+ state.delete()
- expect(tlstate.getShape('rect2')).toBe(undefined)
- expect(tlstate.getPageState().selectedIds.length).toBe(0)
+ expect(state.getShape('rect2')).toBe(undefined)
+ expect(state.getPageState().selectedIds.length).toBe(0)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect2')).toBeTruthy()
- expect(tlstate.getPageState().selectedIds.length).toBe(1)
+ expect(state.getShape('rect2')).toBeTruthy()
+ expect(state.getPageState().selectedIds.length).toBe(1)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect2')).toBe(undefined)
- expect(tlstate.getPageState().selectedIds.length).toBe(0)
+ expect(state.getShape('rect2')).toBe(undefined)
+ expect(state.getPageState().selectedIds.length).toBe(0)
})
it('deletes two shapes', () => {
- tlstate.selectAll()
- tlstate.delete()
+ state.selectAll()
+ state.delete()
- expect(tlstate.getShape('rect1')).toBe(undefined)
- expect(tlstate.getShape('rect2')).toBe(undefined)
+ expect(state.getShape('rect1')).toBe(undefined)
+ expect(state.getShape('rect2')).toBe(undefined)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1')).toBeTruthy()
- expect(tlstate.getShape('rect2')).toBeTruthy()
+ expect(state.getShape('rect1')).toBeTruthy()
+ expect(state.getShape('rect2')).toBeTruthy()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1')).toBe(undefined)
- expect(tlstate.getShape('rect2')).toBe(undefined)
+ expect(state.getShape('rect1')).toBe(undefined)
+ expect(state.getShape('rect2')).toBe(undefined)
})
it('deletes bound shapes, undoes and redoes', () => {
@@ -70,9 +70,9 @@ describe('Delete command', () => {
})
it('deletes bound shapes', () => {
- expect(Object.values(tlstate.page.bindings)[0]).toBe(undefined)
+ expect(Object.values(state.page.bindings)[0]).toBe(undefined)
- tlstate
+ state
.selectNone()
.createShapes({
id: 'arrow1',
@@ -83,46 +83,46 @@ describe('Delete command', () => {
.updateSession([110, 110])
.completeSession()
- const binding = Object.values(tlstate.page.bindings)[0]
+ const binding = Object.values(state.page.bindings)[0]
expect(binding).toBeTruthy()
expect(binding.fromId).toBe('arrow1')
expect(binding.toId).toBe('rect3')
expect(binding.handleId).toBe('start')
- expect(tlstate.getShape('arrow1').handles?.start.bindingId).toBe(binding.id)
+ expect(state.getShape('arrow1').handles?.start.bindingId).toBe(binding.id)
- tlstate.select('rect3').delete()
+ state.select('rect3').delete()
- expect(Object.values(tlstate.page.bindings)[0]).toBe(undefined)
- expect(tlstate.getShape('arrow1').handles?.start.bindingId).toBe(undefined)
+ expect(Object.values(state.page.bindings)[0]).toBe(undefined)
+ expect(state.getShape('arrow1').handles?.start.bindingId).toBe(undefined)
- tlstate.undo()
+ state.undo()
- expect(Object.values(tlstate.page.bindings)[0]).toBeTruthy()
- expect(tlstate.getShape('arrow1').handles?.start.bindingId).toBe(binding.id)
+ expect(Object.values(state.page.bindings)[0]).toBeTruthy()
+ expect(state.getShape('arrow1').handles?.start.bindingId).toBe(binding.id)
- tlstate.redo()
+ state.redo()
- expect(Object.values(tlstate.page.bindings)[0]).toBe(undefined)
- expect(tlstate.getShape('arrow1').handles?.start.bindingId).toBe(undefined)
+ expect(Object.values(state.page.bindings)[0]).toBe(undefined)
+ expect(state.getShape('arrow1').handles?.start.bindingId).toBe(undefined)
})
describe('when deleting shapes in a group', () => {
it('updates the group', () => {
- tlstate.group(['rect1', 'rect2', 'rect3'], 'newGroup').select('rect1').delete()
+ state.group(['rect1', 'rect2', 'rect3'], 'newGroup').select('rect1').delete()
- expect(tlstate.getShape('rect1')).toBeUndefined()
- expect(tlstate.getShape('newGroup').children).toStrictEqual(['rect2', 'rect3'])
+ expect(state.getShape('rect1')).toBeUndefined()
+ expect(state.getShape('newGroup').children).toStrictEqual(['rect2', 'rect3'])
})
})
describe('when deleting a group', () => {
it('deletes all grouped shapes', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup').select('newGroup').delete()
+ state.group(['rect1', 'rect2'], 'newGroup').select('newGroup').delete()
- expect(tlstate.getShape('rect1')).toBeUndefined()
- expect(tlstate.getShape('rect2')).toBeUndefined()
- expect(tlstate.getShape('newGroup')).toBeUndefined()
+ expect(state.getShape('rect1')).toBeUndefined()
+ expect(state.getShape('rect2')).toBeUndefined()
+ expect(state.getShape('newGroup')).toBeUndefined()
})
})
diff --git a/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.ts b/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.ts
index 156f4969a..0cd0c0c41 100644
--- a/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.ts
+++ b/packages/tldraw/src/state/commands/deleteShapes/deleteShapes.ts
@@ -1,9 +1,9 @@
import { TLDR } from '~state/TLDR'
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { removeShapesFromPage } from '../shared/removeShapesFromPage'
export function deleteShapes(
- data: Data,
+ data: TLDrawSnapshot,
ids: string[],
pageId = data.appState.currentPageId
): TLDrawCommand {
diff --git a/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.spec.ts b/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.spec.ts
index 64747f8ca..76094b848 100644
--- a/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.spec.ts
@@ -4,45 +4,45 @@ import { mockDocument, TLDrawStateUtils } from '~test'
import { AlignType, DistributeType, TLDrawShapeType } from '~types'
describe('Distribute command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when less than three shapes are selected', () => {
it('does nothing', () => {
- tlstate.select('rect1', 'rect2')
- const initialState = tlstate.state
- tlstate.distribute(DistributeType.Horizontal)
- const currentState = tlstate.state
+ state.select('rect1', 'rect2')
+ const initialState = state.state
+ state.distribute(DistributeType.Horizontal)
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.selectAll()
- tlstate.distribute(DistributeType.Horizontal)
+ state.selectAll()
+ state.distribute(DistributeType.Horizontal)
- expect(tlstate.getShape('rect3').point).toEqual([50, 20])
- tlstate.undo()
- expect(tlstate.getShape('rect3').point).toEqual([20, 20])
- tlstate.redo()
- expect(tlstate.getShape('rect3').point).toEqual([50, 20])
+ expect(state.getShape('rect3').point).toEqual([50, 20])
+ state.undo()
+ expect(state.getShape('rect3').point).toEqual([20, 20])
+ state.redo()
+ expect(state.getShape('rect3').point).toEqual([50, 20])
})
it('distributes vertically', () => {
- tlstate.selectAll()
- tlstate.distribute(DistributeType.Vertical)
+ state.selectAll()
+ state.distribute(DistributeType.Vertical)
- expect(tlstate.getShape('rect3').point).toEqual([20, 50])
+ expect(state.getShape('rect3').point).toEqual([20, 50])
})
})
describe('when distributing groups', () => {
it('distributes children', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.createShapes(
{ id: 'rect1', type: TLDrawShapeType.Rectangle, point: [0, 0], size: [100, 100] },
{ id: 'rect2', type: TLDrawShapeType.Rectangle, point: [100, 100], size: [100, 100] },
@@ -54,12 +54,12 @@ describe('when distributing groups', () => {
.select('rect3', 'rect4', 'rect5')
.distribute(DistributeType.Vertical)
- const p0 = tlstate.getShape('rect4').point
- const p1 = tlstate.getShape('rect3').point
+ const p0 = state.getShape('rect4').point
+ const p1 = state.getShape('rect3').point
- tlstate.undo().delete(['rect4']).selectAll().distribute(DistributeType.Vertical)
+ state.undo().delete(['rect4']).selectAll().distribute(DistributeType.Vertical)
- new TLDrawStateUtils(tlstate).expectShapesToBeAtPoints({
+ new TLDrawStateUtils(state).expectShapesToBeAtPoints({
rect1: p0,
rect2: Vec.add(p0, [100, 100]),
rect3: p1,
diff --git a/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.ts b/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.ts
index 8b554384d..f5e66cfd4 100644
--- a/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.ts
+++ b/packages/tldraw/src/state/commands/distributeShapes/distributeShapes.ts
@@ -1,10 +1,14 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { Utils } from '@tldraw/core'
-import { DistributeType, TLDrawShape, Data, TLDrawCommand, TLDrawShapeType } from '~types'
+import { DistributeType, TLDrawShape, TLDrawSnapshot, TLDrawCommand, TLDrawShapeType } from '~types'
import { TLDR } from '~state/TLDR'
import Vec from '@tldraw/vec'
-export function distributeShapes(data: Data, ids: string[], type: DistributeType): TLDrawCommand {
+export function distributeShapes(
+ data: TLDrawSnapshot,
+ ids: string[],
+ type: DistributeType
+): TLDrawCommand {
const { currentPageId } = data.appState
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
diff --git a/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.spec.ts b/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.spec.ts
index 8b215dbd2..a66091057 100644
--- a/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.spec.ts
+++ b/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.spec.ts
@@ -2,23 +2,23 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Duplicate page command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
it('does, undoes and redoes command', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- const initialId = tlstate.page.id
+ const initialId = state.page.id
- tlstate.duplicatePage(tlstate.currentPageId)
+ state.duplicatePage(state.currentPageId)
- const nextId = tlstate.page.id
+ const nextId = state.page.id
- tlstate.undo()
+ state.undo()
- expect(tlstate.page.id).toBe(initialId)
+ expect(state.page.id).toBe(initialId)
- tlstate.redo()
+ state.redo()
- expect(tlstate.page.id).toBe(nextId)
+ expect(state.page.id).toBe(nextId)
})
})
diff --git a/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.ts b/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.ts
index 1270b0a1d..b0bdc7952 100644
--- a/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.ts
+++ b/packages/tldraw/src/state/commands/duplicatePage/duplicatePage.ts
@@ -1,7 +1,11 @@
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { Utils } from '@tldraw/core'
-export function duplicatePage(data: Data, center: number[], pageId: string): TLDrawCommand {
+export function duplicatePage(
+ data: TLDrawSnapshot,
+ center: number[],
+ pageId: string
+): TLDrawCommand {
const newId = Utils.uniqueId()
const { currentPageId } = data.appState
diff --git a/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.spec.ts b/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.spec.ts
index 2e89dd472..84584dbda 100644
--- a/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.spec.ts
@@ -6,38 +6,38 @@ import { mockDocument } from '~test'
import { ArrowShape, SessionType, TLDrawShapeType } from '~types'
describe('Duplicate command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.duplicate()
- const currentState = tlstate.state
+ const initialState = state.state
+ state.duplicate()
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('rect1')
+ state.select('rect1')
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(3)
+ expect(Object.keys(state.getPage().shapes).length).toBe(3)
- tlstate.duplicate()
+ state.duplicate()
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(4)
+ expect(Object.keys(state.getPage().shapes).length).toBe(4)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(3)
+ expect(Object.keys(state.getPage().shapes).length).toBe(3)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.getPage().shapes).length).toBe(4)
+ expect(Object.keys(state.getPage().shapes).length).toBe(4)
})
describe('when duplicating a shape', () => {
@@ -46,7 +46,7 @@ describe('Duplicate command', () => {
describe('when duplicating a bound shape', () => {
it('removed the binding when the target is not selected', () => {
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'target1',
type: TLDrawShapeType.Rectangle,
@@ -60,33 +60,33 @@ describe('Duplicate command', () => {
}
)
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
+ const beforeShapeIds = Object.keys(state.page.shapes)
- tlstate
+ state
.select('arrow1')
.startSession(SessionType.Arrow, [200, 200], 'start')
.updateSession([50, 50])
.completeSession()
- const beforeArrow = tlstate.getShape('arrow1')
+ const beforeArrow = state.getShape('arrow1')
expect(beforeArrow.handles.start.bindingId).toBeTruthy()
- tlstate.select('arrow1').duplicate()
+ state.select('arrow1').duplicate()
- const afterShapeIds = Object.keys(tlstate.page.shapes)
+ const afterShapeIds = Object.keys(state.page.shapes)
const newShapeIds = afterShapeIds.filter((id) => !beforeShapeIds.includes(id))
expect(newShapeIds.length).toBe(1)
- const duplicatedArrow = tlstate.getShape(newShapeIds[0])
+ const duplicatedArrow = state.getShape(newShapeIds[0])
expect(duplicatedArrow.handles.start.bindingId).toBeUndefined()
})
it('duplicates the binding when the target is selected', () => {
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'target1',
type: TLDrawShapeType.Rectangle,
@@ -100,76 +100,74 @@ describe('Duplicate command', () => {
}
)
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
+ const beforeShapeIds = Object.keys(state.page.shapes)
- tlstate
+ state
.select('arrow1')
.startSession(SessionType.Arrow, [200, 200], 'start')
.updateSession([50, 50])
.completeSession()
- const oldBindingId = tlstate.getShape('arrow1').handles.start.bindingId
+ const oldBindingId = state.getShape('arrow1').handles.start.bindingId
expect(oldBindingId).toBeTruthy()
- tlstate.select('arrow1', 'target1').duplicate()
+ state.select('arrow1', 'target1').duplicate()
- const afterShapeIds = Object.keys(tlstate.page.shapes)
+ const afterShapeIds = Object.keys(state.page.shapes)
const newShapeIds = afterShapeIds.filter((id) => !beforeShapeIds.includes(id))
expect(newShapeIds.length).toBe(2)
- const newBindingId = tlstate.getShape(newShapeIds[0]).handles.start.bindingId
+ const newBindingId = state.getShape(newShapeIds[0]).handles.start.bindingId
expect(newBindingId).toBeTruthy()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getBinding(newBindingId!)).toBeUndefined()
- expect(tlstate.getShape(newShapeIds[0])).toBeUndefined()
+ expect(state.getBinding(newBindingId!)).toBeUndefined()
+ expect(state.getShape(newShapeIds[0])).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getBinding(newBindingId!)).toBeTruthy()
- expect(tlstate.getShape(newShapeIds[0]).handles.start.bindingId).toBe(
- newBindingId
- )
+ expect(state.getBinding(newBindingId!)).toBeTruthy()
+ expect(state.getShape(newShapeIds[0]).handles.start.bindingId).toBe(newBindingId)
})
it('duplicates groups', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup').select('newGroup')
+ state.group(['rect1', 'rect2'], 'newGroup').select('newGroup')
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
+ const beforeShapeIds = Object.keys(state.page.shapes)
- tlstate.duplicate()
+ state.duplicate()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 3)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length + 3)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 3)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length + 3)
})
it('duplicates grouped shapes', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup').select('rect1')
+ state.group(['rect1', 'rect2'], 'newGroup').select('rect1')
- const beforeShapeIds = Object.keys(tlstate.page.shapes)
+ const beforeShapeIds = Object.keys(state.page.shapes)
- tlstate.duplicate()
+ state.duplicate()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 1)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length + 1)
- tlstate.undo()
+ state.undo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length)
- tlstate.redo()
+ state.redo()
- expect(Object.keys(tlstate.page.shapes).length).toBe(beforeShapeIds.length + 1)
+ expect(Object.keys(state.page.shapes).length).toBe(beforeShapeIds.length + 1)
})
})
@@ -178,25 +176,25 @@ describe('Duplicate command', () => {
describe('when point-duplicating', () => {
it('duplicates without crashing', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
- tlstate
+ state
.loadDocument(mockDocument)
.group(['rect1', 'rect2'])
.selectAll()
- .duplicate(tlstate.selectedIds, [200, 200])
+ .duplicate(state.selectedIds, [200, 200])
})
it('duplicates in the correct place', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
- tlstate.loadDocument(mockDocument).group(['rect1', 'rect2']).selectAll()
+ state.loadDocument(mockDocument).group(['rect1', 'rect2']).selectAll()
- const before = tlstate.shapes.map((shape) => shape.id)
+ const before = state.shapes.map((shape) => shape.id)
- tlstate.duplicate(tlstate.selectedIds, [200, 200])
+ state.duplicate(state.selectedIds, [200, 200])
- const after = tlstate.shapes.filter((shape) => !before.includes(shape.id))
+ const after = state.shapes.filter((shape) => !before.includes(shape.id))
expect(
Utils.getBoundsCenter(Utils.getCommonBounds(after.map((shape) => TLDR.getBounds(shape))))
diff --git a/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.ts b/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.ts
index 104734120..97aa1b7b0 100644
--- a/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.ts
+++ b/packages/tldraw/src/state/commands/duplicateShapes/duplicateShapes.ts
@@ -2,9 +2,13 @@
import { Utils } from '@tldraw/core'
import { Vec } from '@tldraw/vec'
import { TLDR } from '~state/TLDR'
-import type { Data, PagePartial, TLDrawCommand, TLDrawShape } from '~types'
+import type { TLDrawSnapshot, PagePartial, TLDrawCommand, TLDrawShape } from '~types'
-export function duplicateShapes(data: Data, ids: string[], point?: number[]): TLDrawCommand {
+export function duplicateShapes(
+ data: TLDrawSnapshot,
+ ids: string[],
+ point?: number[]
+): TLDrawCommand {
const { currentPageId } = data.appState
const page = TLDR.getPage(data, currentPageId)
diff --git a/packages/tldraw/src/state/commands/flipShapes/flipShapes.spec.ts b/packages/tldraw/src/state/commands/flipShapes/flipShapes.spec.ts
index 248dca5af..db66f29cc 100644
--- a/packages/tldraw/src/state/commands/flipShapes/flipShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/flipShapes/flipShapes.spec.ts
@@ -3,48 +3,48 @@ import { mockDocument } from '~test'
import type { RectangleShape } from '~types'
describe('Flip command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.flipHorizontal()
- const currentState = tlstate.state
+ const initialState = state.state
+ state.flipHorizontal()
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.flipHorizontal()
+ state.select('rect1', 'rect2')
+ state.flipHorizontal()
- expect(tlstate.getShape('rect1').point).toStrictEqual([100, 0])
+ expect(state.getShape('rect1').point).toStrictEqual([100, 0])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1').point).toStrictEqual([100, 0])
+ expect(state.getShape('rect1').point).toStrictEqual([100, 0])
})
it('flips horizontally', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.flipHorizontal()
+ state.select('rect1', 'rect2')
+ state.flipHorizontal()
- expect(tlstate.getShape('rect1').point).toStrictEqual([100, 0])
+ expect(state.getShape('rect1').point).toStrictEqual([100, 0])
})
it('flips vertically', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.flipVertical()
+ state.select('rect1', 'rect2')
+ state.flipVertical()
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 100])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 100])
})
})
diff --git a/packages/tldraw/src/state/commands/flipShapes/flipShapes.ts b/packages/tldraw/src/state/commands/flipShapes/flipShapes.ts
index 92c5375b6..ec4046f63 100644
--- a/packages/tldraw/src/state/commands/flipShapes/flipShapes.ts
+++ b/packages/tldraw/src/state/commands/flipShapes/flipShapes.ts
@@ -1,9 +1,9 @@
import { FlipType } from '~types'
import { TLBoundsCorner, Utils } from '@tldraw/core'
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { TLDR } from '~state/TLDR'
-export function flipShapes(data: Data, ids: string[], type: FlipType): TLDrawCommand {
+export function flipShapes(data: TLDrawSnapshot, ids: string[], type: FlipType): TLDrawCommand {
const { currentPageId } = data.appState
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
diff --git a/packages/tldraw/src/state/commands/groupShapes/groupShapes.spec.ts b/packages/tldraw/src/state/commands/groupShapes/groupShapes.spec.ts
index 5ad564142..108f628d2 100644
--- a/packages/tldraw/src/state/commands/groupShapes/groupShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/groupShapes/groupShapes.spec.ts
@@ -4,42 +4,42 @@ import { mockDocument } from '~test'
import { GroupShape, TLDrawShape, TLDrawShapeType } from '~types'
describe('Group command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
it('does, undoes and redoes command', () => {
- tlstate.group(['rect1', 'rect2'], 'newGroup')
+ state.group(['rect1', 'rect2'], 'newGroup')
- expect(tlstate.getShape('newGroup')).toBeTruthy()
+ expect(state.getShape('newGroup')).toBeTruthy()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('newGroup')).toBeUndefined()
+ expect(state.getShape('newGroup')).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('newGroup')).toBeTruthy()
+ expect(state.getShape('newGroup')).toBeTruthy()
})
describe('when less than two shapes are selected', () => {
it('does nothing', () => {
- tlstate.selectNone()
+ state.selectNone()
// @ts-ignore
- const stackLength = tlstate.stack.length
+ const stackLength = state.stack.length
- tlstate.group([], 'newGroup')
- expect(tlstate.getShape('newGroup')).toBeUndefined()
+ state.group([], 'newGroup')
+ expect(state.getShape('newGroup')).toBeUndefined()
// @ts-ignore
- expect(tlstate.stack.length).toBe(stackLength)
+ expect(state.stack.length).toBe(stackLength)
- tlstate.group(['rect1'], 'newGroup')
- expect(tlstate.getShape('newGroup')).toBeUndefined()
+ state.group(['rect1'], 'newGroup')
+ expect(state.getShape('newGroup')).toBeUndefined()
// @ts-ignore
- expect(tlstate.stack.length).toBe(stackLength)
+ expect(state.stack.length).toBe(stackLength)
})
})
@@ -51,7 +51,7 @@ describe('Group command', () => {
*/
it('creates a group with the correct props', () => {
- tlstate.updateShapes(
+ state.updateShapes(
{
id: 'rect1',
point: [300, 300],
@@ -64,8 +64,8 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2'], 'newGroup')
- const group = tlstate.getShape('newGroup')
+ state.group(['rect1', 'rect2'], 'newGroup')
+ const group = state.getShape('newGroup')
expect(group).toBeTruthy()
expect(group.parentId).toBe('page1')
expect(group.childIndex).toBe(3)
@@ -74,7 +74,7 @@ describe('Group command', () => {
})
it('reparents the grouped shapes', () => {
- tlstate.updateShapes(
+ state.updateShapes(
{
id: 'rect1',
childIndex: 2.5,
@@ -85,13 +85,13 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2'], 'newGroup')
+ state.group(['rect1', 'rect2'], 'newGroup')
let rect1: TLDrawShape
let rect2: TLDrawShape
- rect1 = tlstate.getShape('rect1')
- rect2 = tlstate.getShape('rect2')
+ rect1 = state.getShape('rect1')
+ rect2 = state.getShape('rect2')
// Reparents the shapes
expect(rect1.parentId).toBe('newGroup')
expect(rect2.parentId).toBe('newGroup')
@@ -99,10 +99,10 @@ describe('Group command', () => {
expect(rect1.childIndex).toBe(1)
expect(rect2.childIndex).toBe(2)
- tlstate.undo()
+ state.undo()
- rect1 = tlstate.getShape('rect1')
- rect2 = tlstate.getShape('rect2')
+ rect1 = state.getShape('rect1')
+ rect2 = state.getShape('rect2')
// Restores the shapes' parentIds
expect(rect1.parentId).toBe('page1')
expect(rect2.parentId).toBe('page1')
@@ -127,7 +127,7 @@ describe('Group command', () => {
original group be updated to only contain the remaining ones.
*/
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -150,59 +150,59 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2', 'rect3', 'rect4'], 'newGroupA')
+ state.group(['rect1', 'rect2', 'rect3', 'rect4'], 'newGroupA')
- expect(tlstate.getShape('newGroupA')).toBeTruthy()
- expect(tlstate.getShape('rect1').childIndex).toBe(1)
- expect(tlstate.getShape('rect2').childIndex).toBe(2)
- expect(tlstate.getShape('rect3').childIndex).toBe(3)
- expect(tlstate.getShape('rect4').childIndex).toBe(4)
- expect(tlstate.getShape('newGroupA').children).toStrictEqual([
+ expect(state.getShape('newGroupA')).toBeTruthy()
+ expect(state.getShape('rect1').childIndex).toBe(1)
+ expect(state.getShape('rect2').childIndex).toBe(2)
+ expect(state.getShape('rect3').childIndex).toBe(3)
+ expect(state.getShape('rect4').childIndex).toBe(4)
+ expect(state.getShape('newGroupA').children).toStrictEqual([
'rect1',
'rect2',
'rect3',
'rect4',
])
- tlstate.group(['rect1', 'rect3'], 'newGroupB')
+ state.group(['rect1', 'rect3'], 'newGroupB')
- expect(tlstate.getShape('newGroupA')).toBeTruthy()
- expect(tlstate.getShape('rect2').childIndex).toBe(2)
- expect(tlstate.getShape('rect4').childIndex).toBe(4)
- expect(tlstate.getShape('newGroupA').children).toStrictEqual(['rect2', 'rect4'])
+ expect(state.getShape('newGroupA')).toBeTruthy()
+ expect(state.getShape('rect2').childIndex).toBe(2)
+ expect(state.getShape('rect4').childIndex).toBe(4)
+ expect(state.getShape('newGroupA').children).toStrictEqual(['rect2', 'rect4'])
- expect(tlstate.getShape('newGroupB')).toBeTruthy()
- expect(tlstate.getShape('rect1').childIndex).toBe(1)
- expect(tlstate.getShape('rect3').childIndex).toBe(2)
- expect(tlstate.getShape('newGroupB').children).toStrictEqual(['rect1', 'rect3'])
+ expect(state.getShape('newGroupB')).toBeTruthy()
+ expect(state.getShape('rect1').childIndex).toBe(1)
+ expect(state.getShape('rect3').childIndex).toBe(2)
+ expect(state.getShape('newGroupB').children).toStrictEqual(['rect1', 'rect3'])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('newGroupA')).toBeTruthy()
- expect(tlstate.getShape('rect1').childIndex).toBe(1)
- expect(tlstate.getShape('rect2').childIndex).toBe(2)
- expect(tlstate.getShape('rect3').childIndex).toBe(3)
- expect(tlstate.getShape('rect4').childIndex).toBe(4)
- expect(tlstate.getShape('newGroupA').children).toStrictEqual([
+ expect(state.getShape('newGroupA')).toBeTruthy()
+ expect(state.getShape('rect1').childIndex).toBe(1)
+ expect(state.getShape('rect2').childIndex).toBe(2)
+ expect(state.getShape('rect3').childIndex).toBe(3)
+ expect(state.getShape('rect4').childIndex).toBe(4)
+ expect(state.getShape('newGroupA').children).toStrictEqual([
'rect1',
'rect2',
'rect3',
'rect4',
])
- expect(tlstate.getShape('newGroupB')).toBeUndefined()
+ expect(state.getShape('newGroupB')).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('newGroupA')).toBeTruthy()
- expect(tlstate.getShape('rect2').childIndex).toBe(2)
- expect(tlstate.getShape('rect4').childIndex).toBe(4)
- expect(tlstate.getShape('newGroupA').children).toStrictEqual(['rect2', 'rect4'])
+ expect(state.getShape('newGroupA')).toBeTruthy()
+ expect(state.getShape('rect2').childIndex).toBe(2)
+ expect(state.getShape('rect4').childIndex).toBe(4)
+ expect(state.getShape('newGroupA').children).toStrictEqual(['rect2', 'rect4'])
- expect(tlstate.getShape('newGroupB')).toBeTruthy()
- expect(tlstate.getShape('rect1').childIndex).toBe(1)
- expect(tlstate.getShape('rect3').childIndex).toBe(2)
- expect(tlstate.getShape('newGroupB').children).toStrictEqual(['rect1', 'rect3'])
+ expect(state.getShape('newGroupB')).toBeTruthy()
+ expect(state.getShape('rect1').childIndex).toBe(1)
+ expect(state.getShape('rect3').childIndex).toBe(2)
+ expect(state.getShape('newGroupB').children).toStrictEqual(['rect1', 'rect3'])
})
it('does nothing if all shapes in the group are selected', () => {
@@ -210,7 +210,7 @@ describe('Group command', () => {
If the selected shapes represent ALL of the children of the a
group, then no effect should occur.
*/
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -228,9 +228,9 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2', 'rect3'], 'newGroupA')
- tlstate.group(['rect1', 'rect2', 'rect3'], 'newGroupB')
- expect(tlstate.getShape('newGroupB')).toBeUndefined()
+ state.group(['rect1', 'rect2', 'rect3'], 'newGroupA')
+ state.group(['rect1', 'rect2', 'rect3'], 'newGroupB')
+ expect(state.getShape('newGroupB')).toBeUndefined()
})
it('deletes any groups that no longer have children', () => {
@@ -240,7 +240,7 @@ describe('Group command', () => {
Other rules around deleted shapes should here apply: bindings
connected to the group should be deleted, etc.
*/
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -258,10 +258,10 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2'], 'newGroupA')
- tlstate.group(['rect1', 'rect2', 'rect3'], 'newGroupB')
- expect(tlstate.getShape('newGroupA')).toBeUndefined()
- expect(tlstate.getShape('newGroupB').children).toStrictEqual([
+ state.group(['rect1', 'rect2'], 'newGroupA')
+ state.group(['rect1', 'rect2', 'rect3'], 'newGroupB')
+ expect(state.getShape('newGroupA')).toBeUndefined()
+ expect(state.getShape('newGroupB').children).toStrictEqual([
'rect1',
'rect2',
'rect3',
@@ -274,7 +274,7 @@ describe('Group command', () => {
groups, then the selected groups should be destroyed and a new
group created with the selected shapes and the group(s)' children.
*/
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -292,26 +292,26 @@ describe('Group command', () => {
}
)
- tlstate.group(['rect1', 'rect2'], 'newGroupA')
- tlstate.group(['newGroupA', 'rect3'], 'newGroupB')
- expect(tlstate.getShape('newGroupA')).toBeUndefined()
- expect(tlstate.getShape('newGroupB').children).toStrictEqual([
+ state.group(['rect1', 'rect2'], 'newGroupA')
+ state.group(['newGroupA', 'rect3'], 'newGroupB')
+ expect(state.getShape('newGroupA')).toBeUndefined()
+ expect(state.getShape('newGroupB').children).toStrictEqual([
'rect1',
'rect2',
'rect3',
])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('newGroupB')).toBeUndefined()
- expect(tlstate.getShape('newGroupA')).toBeDefined()
- expect(tlstate.getShape('newGroupA').children).toStrictEqual(['rect1', 'rect2'])
+ expect(state.getShape('newGroupB')).toBeUndefined()
+ expect(state.getShape('newGroupA')).toBeDefined()
+ expect(state.getShape('newGroupA').children).toStrictEqual(['rect1', 'rect2'])
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('newGroupA')).toBeUndefined()
- expect(tlstate.getShape('newGroupB')).toBeDefined()
- expect(tlstate.getShape('newGroupB').children).toStrictEqual([
+ expect(state.getShape('newGroupA')).toBeUndefined()
+ expect(state.getShape('newGroupB')).toBeDefined()
+ expect(state.getShape('newGroupB').children).toStrictEqual([
'rect1',
'rect2',
'rect3',
@@ -319,7 +319,7 @@ describe('Group command', () => {
})
it('Ungroups if the only shape selected is a group', () => {
- tlstate.resetDocument().createShapes(
+ state.resetDocument().createShapes(
{
id: 'rect1',
type: TLDrawShapeType.Rectangle,
@@ -337,15 +337,15 @@ describe('Group command', () => {
}
)
- expect(tlstate.shapes.length).toBe(3)
+ expect(state.shapes.length).toBe(3)
- tlstate.selectAll().group()
+ state.selectAll().group()
- expect(tlstate.shapes.length).toBe(4)
+ expect(state.shapes.length).toBe(4)
- tlstate.selectAll().group()
+ state.selectAll().group()
- expect(tlstate.shapes.length).toBe(3)
+ expect(state.shapes.length).toBe(3)
})
/*
diff --git a/packages/tldraw/src/state/commands/groupShapes/groupShapes.ts b/packages/tldraw/src/state/commands/groupShapes/groupShapes.ts
index 5bf04d411..1f873921e 100644
--- a/packages/tldraw/src/state/commands/groupShapes/groupShapes.ts
+++ b/packages/tldraw/src/state/commands/groupShapes/groupShapes.ts
@@ -1,11 +1,11 @@
import { TLDrawBinding, TLDrawShape, TLDrawShapeType } from '~types'
import { Utils } from '@tldraw/core'
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { TLDR } from '~state/TLDR'
import type { Patch } from 'rko'
export function groupShapes(
- data: Data,
+ data: TLDrawSnapshot,
ids: string[],
groupId: string,
pageId: string
diff --git a/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.spec.ts b/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.spec.ts
index e195cfab0..ac69d6051 100644
--- a/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.spec.ts
+++ b/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.spec.ts
@@ -3,17 +3,17 @@ import { mockDocument } from '~test'
import { ArrowShape, SessionType, TLDrawShapeType } from '~types'
describe('Move to page command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument).createPage('page2').changePage('page1')
+ state.loadDocument(mockDocument).createPage('page2').changePage('page1')
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.moveToPage('page2')
- const currentState = tlstate.state
+ const initialState = state.state
+ state.moveToPage('page2')
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
@@ -29,37 +29,37 @@ describe('Move to page command', () => {
*/
it('does, undoes and redoes command', () => {
- tlstate.select('rect1', 'rect2').moveToPage('page2')
+ state.select('rect1', 'rect2').moveToPage('page2')
- expect(tlstate.currentPageId).toBe('page2')
- expect(tlstate.getShape('rect1', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeDefined()
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.currentPageId).toBe('page2')
+ expect(state.getShape('rect1', 'page1')).toBeUndefined()
+ expect(state.getShape('rect1', 'page2')).toBeDefined()
+ expect(state.getShape('rect2', 'page1')).toBeUndefined()
+ expect(state.getShape('rect2', 'page2')).toBeDefined()
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1', 'page1')).toBeDefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeUndefined()
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
- expect(tlstate.currentPageId).toBe('page1')
+ expect(state.getShape('rect1', 'page1')).toBeDefined()
+ expect(state.getShape('rect1', 'page2')).toBeUndefined()
+ expect(state.getShape('rect2', 'page1')).toBeDefined()
+ expect(state.getShape('rect2', 'page2')).toBeUndefined()
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.currentPageId).toBe('page1')
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeDefined()
- expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
- expect(tlstate.currentPageId).toBe('page2')
+ expect(state.getShape('rect1', 'page1')).toBeUndefined()
+ expect(state.getShape('rect1', 'page2')).toBeDefined()
+ expect(state.getShape('rect2', 'page1')).toBeUndefined()
+ expect(state.getShape('rect2', 'page2')).toBeDefined()
+ expect(state.selectedIds).toStrictEqual(['rect1', 'rect2'])
+ expect(state.currentPageId).toBe('page2')
})
describe('when moving shapes with bindings', () => {
it('deletes bindings when only the bound-to shape is moved', () => {
- tlstate
+ state
.selectAll()
.delete()
.createShapes(
@@ -71,36 +71,30 @@ describe('Move to page command', () => {
.updateSession([50, 50])
.completeSession()
- const bindingId = tlstate.bindings[0].id
- expect(tlstate.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
+ const bindingId = state.bindings[0].id
+ expect(state.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
- tlstate.select('target1').moveToPage('page2')
+ state.select('target1').moveToPage('page2')
- expect(
- tlstate.getShape('arrow1', 'page1').handles.start.bindingId
- ).toBeUndefined()
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page1').handles.start.bindingId).toBeUndefined()
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('arrow1', 'page1').handles.start.bindingId).toBe(
- bindingId
- )
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeDefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page1').handles.start.bindingId).toBe(bindingId)
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeDefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(
- tlstate.getShape('arrow1', 'page1').handles.start.bindingId
- ).toBeUndefined()
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page1').handles.start.bindingId).toBeUndefined()
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
})
it('deletes bindings when only the bound-from shape is moved', () => {
- tlstate
+ state
.selectAll()
.delete()
.createShapes(
@@ -112,36 +106,30 @@ describe('Move to page command', () => {
.updateSession([50, 50])
.completeSession()
- const bindingId = tlstate.bindings[0].id
- expect(tlstate.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
+ const bindingId = state.bindings[0].id
+ expect(state.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
- tlstate.select('arrow1').moveToPage('page2')
+ state.select('arrow1').moveToPage('page2')
- expect(
- tlstate.getShape('arrow1', 'page2').handles.start.bindingId
- ).toBeUndefined()
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page2').handles.start.bindingId).toBeUndefined()
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('arrow1', 'page1').handles.start.bindingId).toBe(
- bindingId
- )
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeDefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page1').handles.start.bindingId).toBe(bindingId)
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeDefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(
- tlstate.getShape('arrow1', 'page2').handles.start.bindingId
- ).toBeUndefined()
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page2').handles.start.bindingId).toBeUndefined()
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
})
it('moves bindings when both shapes are moved', () => {
- tlstate
+ state
.selectAll()
.delete()
.createShapes(
@@ -153,87 +141,77 @@ describe('Move to page command', () => {
.updateSession([50, 50])
.completeSession()
- const bindingId = tlstate.bindings[0].id
- expect(tlstate.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
+ const bindingId = state.bindings[0].id
+ expect(state.getShape('arrow1').handles.start.bindingId).toBe(bindingId)
- tlstate.select('arrow1', 'target1').moveToPage('page2')
+ state.select('arrow1', 'target1').moveToPage('page2')
- expect(tlstate.getShape('arrow1', 'page2').handles.start.bindingId).toBe(
- bindingId
- )
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeDefined()
+ expect(state.getShape('arrow1', 'page2').handles.start.bindingId).toBe(bindingId)
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeDefined()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('arrow1', 'page1').handles.start.bindingId).toBe(
- bindingId
- )
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeDefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeUndefined()
+ expect(state.getShape('arrow1', 'page1').handles.start.bindingId).toBe(bindingId)
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeDefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeUndefined()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('arrow1', 'page2').handles.start.bindingId).toBe(
- bindingId
- )
- expect(tlstate.document.pages['page1'].bindings[bindingId]).toBeUndefined()
- expect(tlstate.document.pages['page2'].bindings[bindingId]).toBeDefined()
+ expect(state.getShape('arrow1', 'page2').handles.start.bindingId).toBe(bindingId)
+ expect(state.document.pages['page1'].bindings[bindingId]).toBeUndefined()
+ expect(state.document.pages['page2'].bindings[bindingId]).toBeDefined()
})
})
describe('when moving grouped shapes', () => {
it('moves groups and their children', () => {
- tlstate.group(['rect1', 'rect2'], 'groupA').moveToPage('page2')
+ state.group(['rect1', 'rect2'], 'groupA').moveToPage('page2')
- expect(tlstate.getShape('rect1', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeUndefined()
- expect(tlstate.getShape('groupA', 'page1')).toBeUndefined()
+ expect(state.getShape('rect1', 'page1')).toBeUndefined()
+ expect(state.getShape('rect2', 'page1')).toBeUndefined()
+ expect(state.getShape('groupA', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeDefined()
- expect(tlstate.getShape('groupA', 'page2')).toBeDefined()
+ expect(state.getShape('rect1', 'page2')).toBeDefined()
+ expect(state.getShape('rect2', 'page2')).toBeDefined()
+ expect(state.getShape('groupA', 'page2')).toBeDefined()
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1', 'page2')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeUndefined()
- expect(tlstate.getShape('groupA', 'page2')).toBeUndefined()
+ expect(state.getShape('rect1', 'page2')).toBeUndefined()
+ expect(state.getShape('rect2', 'page2')).toBeUndefined()
+ expect(state.getShape('groupA', 'page2')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page1')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeDefined()
- expect(tlstate.getShape('groupA', 'page1')).toBeDefined()
+ expect(state.getShape('rect1', 'page1')).toBeDefined()
+ expect(state.getShape('rect2', 'page1')).toBeDefined()
+ expect(state.getShape('groupA', 'page1')).toBeDefined()
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect2', 'page1')).toBeUndefined()
- expect(tlstate.getShape('groupA', 'page1')).toBeUndefined()
+ expect(state.getShape('rect1', 'page1')).toBeUndefined()
+ expect(state.getShape('rect2', 'page1')).toBeUndefined()
+ expect(state.getShape('groupA', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeDefined()
- expect(tlstate.getShape('rect2', 'page2')).toBeDefined()
- expect(tlstate.getShape('groupA', 'page2')).toBeDefined()
+ expect(state.getShape('rect1', 'page2')).toBeDefined()
+ expect(state.getShape('rect2', 'page2')).toBeDefined()
+ expect(state.getShape('groupA', 'page2')).toBeDefined()
})
it.todo('deletes groups shapes if the groups children were all moved')
it('reparents grouped shapes if the group is not moved', () => {
- tlstate.group(['rect1', 'rect2', 'rect3'], 'groupA').select('rect1').moveToPage('page2')
+ state.group(['rect1', 'rect2', 'rect3'], 'groupA').select('rect1').moveToPage('page2')
- expect(tlstate.getShape('rect1', 'page1')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page2')).toBeDefined()
- expect(tlstate.getShape('rect1', 'page2').parentId).toBe('page2')
- expect(tlstate.getShape('groupA', 'page1').children).toStrictEqual(['rect2', 'rect3'])
+ expect(state.getShape('rect1', 'page1')).toBeUndefined()
+ expect(state.getShape('rect1', 'page2')).toBeDefined()
+ expect(state.getShape('rect1', 'page2').parentId).toBe('page2')
+ expect(state.getShape('groupA', 'page1').children).toStrictEqual(['rect2', 'rect3'])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1', 'page2')).toBeUndefined()
- expect(tlstate.getShape('rect1', 'page1').parentId).toBe('groupA')
- expect(tlstate.getShape('groupA', 'page1').children).toStrictEqual([
- 'rect1',
- 'rect2',
- 'rect3',
- ])
+ expect(state.getShape('rect1', 'page2')).toBeUndefined()
+ expect(state.getShape('rect1', 'page1').parentId).toBe('groupA')
+ expect(state.getShape('groupA', 'page1').children).toStrictEqual(['rect1', 'rect2', 'rect3'])
})
})
diff --git a/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.ts b/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.ts
index fc2c8e87b..fd0e8a71d 100644
--- a/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.ts
+++ b/packages/tldraw/src/state/commands/moveShapesToPage/moveShapesToPage.ts
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
-import type { ArrowShape, Data, PagePartial, TLDrawCommand, TLDrawShape } from '~types'
+import type { ArrowShape, TLDrawSnapshot, PagePartial, TLDrawCommand, TLDrawShape } from '~types'
import { TLDR } from '~state/TLDR'
import { Utils, TLBounds } from '@tldraw/core'
import { Vec } from '@tldraw/vec'
export function moveShapesToPage(
- data: Data,
+ data: TLDrawSnapshot,
ids: string[],
viewportBounds: TLBounds,
fromPageId: string,
diff --git a/packages/tldraw/src/state/commands/renamePage/renamePage.spec.ts b/packages/tldraw/src/state/commands/renamePage/renamePage.spec.ts
index ffa84024d..fa4391878 100644
--- a/packages/tldraw/src/state/commands/renamePage/renamePage.spec.ts
+++ b/packages/tldraw/src/state/commands/renamePage/renamePage.spec.ts
@@ -2,24 +2,24 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Rename page command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
it('does, undoes and redoes command', () => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
- const initialId = tlstate.page.id
- const initialName = tlstate.page.name
+ const initialId = state.page.id
+ const initialName = state.page.name
- tlstate.renamePage(initialId, 'My Special Page')
+ state.renamePage(initialId, 'My Special Page')
- expect(tlstate.page.name).toBe('My Special Page')
+ expect(state.page.name).toBe('My Special Page')
- tlstate.undo()
+ state.undo()
- expect(tlstate.page.name).toBe(initialName)
+ expect(state.page.name).toBe(initialName)
- tlstate.redo()
+ state.redo()
- expect(tlstate.page.name).toBe('My Special Page')
+ expect(state.page.name).toBe('My Special Page')
})
})
diff --git a/packages/tldraw/src/state/commands/renamePage/renamePage.ts b/packages/tldraw/src/state/commands/renamePage/renamePage.ts
index a694bd8eb..679c57132 100644
--- a/packages/tldraw/src/state/commands/renamePage/renamePage.ts
+++ b/packages/tldraw/src/state/commands/renamePage/renamePage.ts
@@ -1,6 +1,6 @@
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
-export function renamePage(data: Data, pageId: string, name: string): TLDrawCommand {
+export function renamePage(data: TLDrawSnapshot, pageId: string, name: string): TLDrawCommand {
const page = data.document.pages[pageId]
return {
id: 'rename_page',
diff --git a/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.spec.ts b/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.spec.ts
index ac4f09d24..ae5ced124 100644
--- a/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.spec.ts
@@ -1,8 +1,8 @@
import { TLDrawState } from '~state'
-import { Data, TLDrawShapeType } from '~types'
+import { TLDrawSnapshot, TLDrawShapeType } from '~types'
import { TLDR } from '~state/TLDR'
-const tlstate = new TLDrawState().createShapes(
+const state = new TLDrawState().createShapes(
{
type: TLDrawShapeType.Rectangle,
id: 'a',
@@ -25,16 +25,16 @@ const tlstate = new TLDrawState().createShapes(
}
)
-const doc = { ...tlstate.document }
+const doc = { ...state.document }
-function getSortedShapeIds(data: Data) {
+function getSortedShapeIds(data: TLDrawSnapshot) {
return TLDR.getShapes(data, data.appState.currentPageId)
.sort((a, b) => a.childIndex - b.childIndex)
.map((shape) => shape.id)
.join('')
}
-function getSortedIndices(data: Data) {
+function getSortedIndices(data: TLDrawSnapshot) {
return TLDR.getShapes(data, data.appState.currentPageId)
.sort((a, b) => a.childIndex - b.childIndex)
.map((shape) => shape.childIndex.toFixed(2))
@@ -43,156 +43,156 @@ function getSortedIndices(data: Data) {
describe('Move command', () => {
beforeEach(() => {
- tlstate.loadDocument(doc)
+ state.loadDocument(doc)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.moveToBack()
+ const initialState = state.state
+ state.moveToBack()
- const currentState = tlstate.state
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('b')
- tlstate.moveToBack()
- expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
- tlstate.undo()
- expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
- tlstate.redo()
- expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
+ state.select('b')
+ state.moveToBack()
+ expect(getSortedShapeIds(state.state)).toBe('bacd')
+ state.undo()
+ expect(getSortedShapeIds(state.state)).toBe('abcd')
+ state.redo()
+ expect(getSortedShapeIds(state.state)).toBe('bacd')
})
describe('to back', () => {
it('moves a shape to back', () => {
- tlstate.select('b')
- tlstate.moveToBack()
- expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
- expect(getSortedIndices(tlstate.state)).toBe('0.50,1.00,3.00,4.00')
+ state.select('b')
+ state.moveToBack()
+ expect(getSortedShapeIds(state.state)).toBe('bacd')
+ expect(getSortedIndices(state.state)).toBe('0.50,1.00,3.00,4.00')
})
it('moves two adjacent siblings to back', () => {
- tlstate.select('b', 'c')
- tlstate.moveToBack()
- expect(getSortedShapeIds(tlstate.state)).toBe('bcad')
- expect(getSortedIndices(tlstate.state)).toBe('0.33,0.67,1.00,4.00')
+ state.select('b', 'c')
+ state.moveToBack()
+ expect(getSortedShapeIds(state.state)).toBe('bcad')
+ expect(getSortedIndices(state.state)).toBe('0.33,0.67,1.00,4.00')
})
it('moves two non-adjacent siblings to back', () => {
- tlstate.select('b', 'd')
- tlstate.moveToBack()
- expect(getSortedShapeIds(tlstate.state)).toBe('bdac')
- expect(getSortedIndices(tlstate.state)).toBe('0.33,0.67,1.00,3.00')
+ state.select('b', 'd')
+ state.moveToBack()
+ expect(getSortedShapeIds(state.state)).toBe('bdac')
+ expect(getSortedIndices(state.state)).toBe('0.33,0.67,1.00,3.00')
})
})
describe('backward', () => {
it('moves a shape backward', () => {
- tlstate.select('c')
- tlstate.moveBackward()
- expect(getSortedShapeIds(tlstate.state)).toBe('acbd')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,1.50,2.00,4.00')
+ state.select('c')
+ state.moveBackward()
+ expect(getSortedShapeIds(state.state)).toBe('acbd')
+ expect(getSortedIndices(state.state)).toBe('1.00,1.50,2.00,4.00')
})
it('moves a shape at first index backward', () => {
- tlstate.select('a')
- tlstate.moveBackward()
- expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,2.00,3.00,4.00')
+ state.select('a')
+ state.moveBackward()
+ expect(getSortedShapeIds(state.state)).toBe('abcd')
+ expect(getSortedIndices(state.state)).toBe('1.00,2.00,3.00,4.00')
})
it('moves two adjacent siblings backward', () => {
- tlstate.select('c', 'd')
- tlstate.moveBackward()
- expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,1.50,1.67,2.00')
+ state.select('c', 'd')
+ state.moveBackward()
+ expect(getSortedShapeIds(state.state)).toBe('acdb')
+ expect(getSortedIndices(state.state)).toBe('1.00,1.50,1.67,2.00')
})
it('moves two non-adjacent siblings backward', () => {
- tlstate.select('b', 'd')
- tlstate.moveBackward()
- expect(getSortedShapeIds(tlstate.state)).toBe('badc')
- expect(getSortedIndices(tlstate.state)).toBe('0.50,1.00,2.50,3.00')
+ state.select('b', 'd')
+ state.moveBackward()
+ expect(getSortedShapeIds(state.state)).toBe('badc')
+ expect(getSortedIndices(state.state)).toBe('0.50,1.00,2.50,3.00')
})
it('moves two adjacent siblings backward at zero index', () => {
- tlstate.select('a', 'b')
- tlstate.moveBackward()
- expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,2.00,3.00,4.00')
+ state.select('a', 'b')
+ state.moveBackward()
+ expect(getSortedShapeIds(state.state)).toBe('abcd')
+ expect(getSortedIndices(state.state)).toBe('1.00,2.00,3.00,4.00')
})
})
describe('forward', () => {
it('moves a shape forward', () => {
- tlstate.select('c')
- tlstate.moveForward()
- expect(getSortedShapeIds(tlstate.state)).toBe('abdc')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,2.00,4.00,5.00')
+ state.select('c')
+ state.moveForward()
+ expect(getSortedShapeIds(state.state)).toBe('abdc')
+ expect(getSortedIndices(state.state)).toBe('1.00,2.00,4.00,5.00')
})
it('moves a shape forward at the top index', () => {
- tlstate.select('b')
- tlstate.moveForward()
- tlstate.moveForward()
- tlstate.moveForward()
- expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,3.00,4.00,5.00')
+ state.select('b')
+ state.moveForward()
+ state.moveForward()
+ state.moveForward()
+ expect(getSortedShapeIds(state.state)).toBe('acdb')
+ expect(getSortedIndices(state.state)).toBe('1.00,3.00,4.00,5.00')
})
it('moves two adjacent siblings forward', () => {
- tlstate.select('a', 'b')
- tlstate.moveForward()
- expect(getSortedShapeIds(tlstate.state)).toBe('cabd')
- expect(getSortedIndices(tlstate.state)).toBe('3.00,3.33,3.50,4.00')
+ state.select('a', 'b')
+ state.moveForward()
+ expect(getSortedShapeIds(state.state)).toBe('cabd')
+ expect(getSortedIndices(state.state)).toBe('3.00,3.33,3.50,4.00')
})
it('moves two non-adjacent siblings forward', () => {
- tlstate.select('a', 'c')
- tlstate.moveForward()
- expect(getSortedShapeIds(tlstate.state)).toBe('badc')
- expect(getSortedIndices(tlstate.state)).toBe('2.00,2.50,4.00,5.00')
+ state.select('a', 'c')
+ state.moveForward()
+ expect(getSortedShapeIds(state.state)).toBe('badc')
+ expect(getSortedIndices(state.state)).toBe('2.00,2.50,4.00,5.00')
})
it('moves two adjacent siblings forward at top index', () => {
- tlstate.select('c', 'd')
- tlstate.moveForward()
- expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,2.00,3.00,4.00')
+ state.select('c', 'd')
+ state.moveForward()
+ expect(getSortedShapeIds(state.state)).toBe('abcd')
+ expect(getSortedIndices(state.state)).toBe('1.00,2.00,3.00,4.00')
})
})
describe('to front', () => {
it('moves a shape to front', () => {
- tlstate.select('b')
- tlstate.moveToFront()
- expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,3.00,4.00,5.00')
+ state.select('b')
+ state.moveToFront()
+ expect(getSortedShapeIds(state.state)).toBe('acdb')
+ expect(getSortedIndices(state.state)).toBe('1.00,3.00,4.00,5.00')
})
it('moves two adjacent siblings to front', () => {
- tlstate.select('a', 'b')
- tlstate.moveToFront()
- expect(getSortedShapeIds(tlstate.state)).toBe('cdab')
- expect(getSortedIndices(tlstate.state)).toBe('3.00,4.00,5.00,6.00')
+ state.select('a', 'b')
+ state.moveToFront()
+ expect(getSortedShapeIds(state.state)).toBe('cdab')
+ expect(getSortedIndices(state.state)).toBe('3.00,4.00,5.00,6.00')
})
it('moves two non-adjacent siblings to front', () => {
- tlstate.select('a', 'c')
- tlstate.moveToFront()
- expect(getSortedShapeIds(tlstate.state)).toBe('bdac')
- expect(getSortedIndices(tlstate.state)).toBe('2.00,4.00,5.00,6.00')
+ state.select('a', 'c')
+ state.moveToFront()
+ expect(getSortedShapeIds(state.state)).toBe('bdac')
+ expect(getSortedIndices(state.state)).toBe('2.00,4.00,5.00,6.00')
})
it('moves siblings already at front to front', () => {
- tlstate.select('c', 'd')
- tlstate.moveToFront()
- expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
- expect(getSortedIndices(tlstate.state)).toBe('1.00,2.00,3.00,4.00')
+ state.select('c', 'd')
+ state.moveToFront()
+ expect(getSortedShapeIds(state.state)).toBe('abcd')
+ expect(getSortedIndices(state.state)).toBe('1.00,2.00,3.00,4.00')
})
})
})
diff --git a/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.ts b/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.ts
index ee6457428..c3cf38fd5 100644
--- a/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.ts
+++ b/packages/tldraw/src/state/commands/reorderShapes/reorderShapes.ts
@@ -1,7 +1,7 @@
-import { MoveType, Data, TLDrawShape, TLDrawCommand } from '~types'
+import { MoveType, TLDrawSnapshot, TLDrawShape, TLDrawCommand } from '~types'
import { TLDR } from '~state/TLDR'
-export function reorderShapes(data: Data, ids: string[], type: MoveType): TLDrawCommand {
+export function reorderShapes(data: TLDrawSnapshot, ids: string[], type: MoveType): TLDrawCommand {
const { currentPageId } = data.appState
// Get the unique parent ids for the selected elements
diff --git a/packages/tldraw/src/state/commands/resetBounds/resetBounds.spec.ts b/packages/tldraw/src/state/commands/resetBounds/resetBounds.spec.ts
index c49a2ff95..2f91f6927 100644
--- a/packages/tldraw/src/state/commands/resetBounds/resetBounds.spec.ts
+++ b/packages/tldraw/src/state/commands/resetBounds/resetBounds.spec.ts
@@ -5,14 +5,14 @@ import { mockDocument } from '~test'
import { SessionType, TLDrawShapeType } from '~types'
describe('Reset bounds command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
it('does, undoes and redoes command', () => {
- tlstate.createShapes({
+ state.createShapes({
id: 'text1',
type: TLDrawShapeType.Text,
point: [0, 0],
@@ -20,18 +20,18 @@ describe('Reset bounds command', () => {
})
// Scale is undefined by default
- expect(tlstate.getShape('text1').style.scale).toBeUndefined()
+ expect(state.getShape('text1').style.scale).toBeUndefined()
// Transform the shape in order to change its point and scale
- tlstate
+ state
.select('text1')
.startSession(SessionType.Transform, [0, 0], TLBoundsCorner.TopLeft)
.updateSession([-100, -100], false, false)
.completeSession()
- const scale = tlstate.getShape('text1').style.scale
- const bounds = TLDR.getBounds(tlstate.getShape('text1'))
+ const scale = state.getShape('text1').style.scale
+ const bounds = TLDR.getBounds(state.getShape('text1'))
const center = Utils.getBoundsCenter(bounds)
expect(scale).not.toBe(1)
@@ -39,25 +39,25 @@ describe('Reset bounds command', () => {
// Reset the bounds
- tlstate.resetBounds(['text1'])
+ state.resetBounds(['text1'])
// The scale should be back to 1
- expect(tlstate.getShape('text1').style.scale).toBe(1)
+ expect(state.getShape('text1').style.scale).toBe(1)
// The centers should be the same
- expect(Utils.getBoundsCenter(TLDR.getBounds(tlstate.getShape('text1')))).toStrictEqual(center)
+ expect(Utils.getBoundsCenter(TLDR.getBounds(state.getShape('text1')))).toStrictEqual(center)
- tlstate.undo()
+ state.undo()
// The scale should be what it was before
- expect(tlstate.getShape('text1').style.scale).not.toBe(1)
+ expect(state.getShape('text1').style.scale).not.toBe(1)
// The centers should be the same
- expect(Utils.getBoundsCenter(TLDR.getBounds(tlstate.getShape('text1')))).toStrictEqual(center)
+ expect(Utils.getBoundsCenter(TLDR.getBounds(state.getShape('text1')))).toStrictEqual(center)
- tlstate.redo()
+ state.redo()
// The scale should be back to 1
- expect(tlstate.getShape('text1').style.scale).toBe(1)
+ expect(state.getShape('text1').style.scale).toBe(1)
// The centers should be the same
- expect(Utils.getBoundsCenter(TLDR.getBounds(tlstate.getShape('text1')))).toStrictEqual(center)
+ expect(Utils.getBoundsCenter(TLDR.getBounds(state.getShape('text1')))).toStrictEqual(center)
})
})
diff --git a/packages/tldraw/src/state/commands/resetBounds/resetBounds.ts b/packages/tldraw/src/state/commands/resetBounds/resetBounds.ts
index b3fbd6cc2..7010fa541 100644
--- a/packages/tldraw/src/state/commands/resetBounds/resetBounds.ts
+++ b/packages/tldraw/src/state/commands/resetBounds/resetBounds.ts
@@ -1,7 +1,7 @@
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { TLDR } from '~state/TLDR'
-export function resetBounds(data: Data, ids: string[], pageId: string): TLDrawCommand {
+export function resetBounds(data: TLDrawSnapshot, ids: string[], pageId: string): TLDrawCommand {
const { currentPageId } = data.appState
const { before, after } = TLDR.mutateShapes(
diff --git a/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.spec.ts b/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.spec.ts
index ebae41f59..1471ce699 100644
--- a/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.spec.ts
@@ -2,38 +2,38 @@ import { TLDrawState } from '~state'
import { mockDocument } from '~test'
describe('Rotate command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.rotate()
- const currentState = tlstate.state
+ const initialState = state.state
+ state.rotate()
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('rect1')
+ state.select('rect1')
- expect(tlstate.getShape('rect1').rotation).toBe(undefined)
+ expect(state.getShape('rect1').rotation).toBe(undefined)
- tlstate.rotate()
+ state.rotate()
- expect(tlstate.getShape('rect1').rotation).toBe(Math.PI * (6 / 4))
+ expect(state.getShape('rect1').rotation).toBe(Math.PI * (6 / 4))
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1').rotation).toBe(undefined)
+ expect(state.getShape('rect1').rotation).toBe(undefined)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1').rotation).toBe(Math.PI * (6 / 4))
+ expect(state.getShape('rect1').rotation).toBe(Math.PI * (6 / 4))
})
it.todo('Rotates several shapes at once.')
@@ -43,17 +43,17 @@ describe('Rotate command', () => {
describe('when running the command', () => {
it('restores selection on undo', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.select('rect1')
.rotate()
.selectNone()
.undo()
- expect(tlstate.selectedIds).toEqual(['rect1'])
+ expect(state.selectedIds).toEqual(['rect1'])
- tlstate.selectNone().redo()
+ state.selectNone().redo()
- expect(tlstate.selectedIds).toEqual(['rect1'])
+ expect(state.selectedIds).toEqual(['rect1'])
})
})
diff --git a/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.ts b/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.ts
index d76b98216..a9971f497 100644
--- a/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.ts
+++ b/packages/tldraw/src/state/commands/rotateShapes/rotateShapes.ts
@@ -1,10 +1,14 @@
import { Utils } from '@tldraw/core'
-import type { TLDrawCommand, Data, TLDrawShape } from '~types'
+import type { TLDrawCommand, TLDrawSnapshot, TLDrawShape } from '~types'
import { TLDR } from '~state/TLDR'
const PI2 = Math.PI * 2
-export function rotateShapes(data: Data, ids: string[], delta = -PI2 / 4): TLDrawCommand | void {
+export function rotateShapes(
+ data: TLDrawSnapshot,
+ ids: string[],
+ delta = -PI2 / 4
+): TLDrawCommand | void {
const { currentPageId } = data.appState
// The shapes for the before patch
diff --git a/packages/tldraw/src/state/commands/shared/removeShapesFromPage.ts b/packages/tldraw/src/state/commands/shared/removeShapesFromPage.ts
index 90fe2263a..7a53bfed3 100644
--- a/packages/tldraw/src/state/commands/shared/removeShapesFromPage.ts
+++ b/packages/tldraw/src/state/commands/shared/removeShapesFromPage.ts
@@ -1,7 +1,7 @@
import { TLDR } from '~state/TLDR'
-import type { ArrowShape, Data, GroupShape, PagePartial } from '~types'
+import type { ArrowShape, TLDrawSnapshot, GroupShape, PagePartial } from '~types'
-export function removeShapesFromPage(data: Data, ids: string[], pageId: string) {
+export function removeShapesFromPage(data: TLDrawSnapshot, ids: string[], pageId: string) {
const before: PagePartial = {
shapes: {},
bindings: {},
diff --git a/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.spec.ts b/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.spec.ts
index f1a67e1d0..891d9ef66 100644
--- a/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.spec.ts
@@ -4,88 +4,88 @@ import { mockDocument, TLDrawStateUtils } from '~test'
import Vec from '@tldraw/vec'
describe('Stretch command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when less than two shapes are selected', () => {
it('does nothing', () => {
- tlstate.select('rect2')
- const initialState = tlstate.state
- tlstate.stretch(StretchType.Horizontal)
- const currentState = tlstate.state
+ state.select('rect2')
+ const initialState = state.state
+ state.stretch(StretchType.Horizontal)
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.stretch(StretchType.Horizontal)
+ state.select('rect1', 'rect2')
+ state.stretch(StretchType.Horizontal)
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
- expect(tlstate.getShape('rect1').size).toStrictEqual([200, 100])
- expect(tlstate.getShape('rect2').point).toStrictEqual([0, 100])
- expect(tlstate.getShape('rect2').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect2').point).toStrictEqual([0, 100])
+ expect(state.getShape('rect2').size).toStrictEqual([200, 100])
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
- expect(tlstate.getShape('rect1').size).toStrictEqual([100, 100])
- expect(tlstate.getShape('rect2').point).toStrictEqual([100, 100])
- expect(tlstate.getShape('rect2').size).toStrictEqual([100, 100])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').size).toStrictEqual([100, 100])
+ expect(state.getShape('rect2').point).toStrictEqual([100, 100])
+ expect(state.getShape('rect2').size).toStrictEqual([100, 100])
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
- expect(tlstate.getShape('rect1').size).toStrictEqual([200, 100])
- expect(tlstate.getShape('rect2').point).toStrictEqual([0, 100])
- expect(tlstate.getShape('rect2').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect2').point).toStrictEqual([0, 100])
+ expect(state.getShape('rect2').size).toStrictEqual([200, 100])
})
it('stretches horizontally', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.stretch(StretchType.Horizontal)
+ state.select('rect1', 'rect2')
+ state.stretch(StretchType.Horizontal)
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
- expect(tlstate.getShape('rect1').size).toStrictEqual([200, 100])
- expect(tlstate.getShape('rect2').point).toStrictEqual([0, 100])
- expect(tlstate.getShape('rect2').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').size).toStrictEqual([200, 100])
+ expect(state.getShape('rect2').point).toStrictEqual([0, 100])
+ expect(state.getShape('rect2').size).toStrictEqual([200, 100])
})
it('stretches vertically', () => {
- tlstate.select('rect1', 'rect2')
- tlstate.stretch(StretchType.Vertical)
+ state.select('rect1', 'rect2')
+ state.stretch(StretchType.Vertical)
- expect(tlstate.getShape('rect1').point).toStrictEqual([0, 0])
- expect(tlstate.getShape('rect1').size).toStrictEqual([100, 200])
- expect(tlstate.getShape('rect2').point).toStrictEqual([100, 0])
- expect(tlstate.getShape('rect2').size).toStrictEqual([100, 200])
+ expect(state.getShape('rect1').point).toStrictEqual([0, 0])
+ expect(state.getShape('rect1').size).toStrictEqual([100, 200])
+ expect(state.getShape('rect2').point).toStrictEqual([100, 0])
+ expect(state.getShape('rect2').size).toStrictEqual([100, 200])
})
})
describe('when running the command', () => {
it('restores selection on undo', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.select('rect1', 'rect2')
.stretch(StretchType.Horizontal)
.selectNone()
.undo()
- expect(tlstate.selectedIds).toEqual(['rect1', 'rect2'])
+ expect(state.selectedIds).toEqual(['rect1', 'rect2'])
- tlstate.selectNone().redo()
+ state.selectNone().redo()
- expect(tlstate.selectedIds).toEqual(['rect1', 'rect2'])
+ expect(state.selectedIds).toEqual(['rect1', 'rect2'])
})
})
describe('when stretching groups', () => {
it('stretches children', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.createShapes(
{ id: 'rect1', type: TLDrawShapeType.Rectangle, point: [0, 0], size: [100, 100] },
{ id: 'rect2', type: TLDrawShapeType.Rectangle, point: [100, 100], size: [100, 100] },
@@ -95,7 +95,7 @@ describe('when stretching groups', () => {
.selectAll()
.stretch(StretchType.Vertical)
- new TLDrawStateUtils(tlstate).expectShapesToHaveProps({
+ new TLDrawStateUtils(state).expectShapesToHaveProps({
rect1: { point: [0, 0], size: [100, 300] },
rect2: { point: [100, 0], size: [100, 300] },
rect3: { point: [200, 0], size: [100, 300] },
diff --git a/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.ts b/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.ts
index a5713034b..1221d9ea1 100644
--- a/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.ts
+++ b/packages/tldraw/src/state/commands/stretchShapes/stretchShapes.ts
@@ -1,10 +1,14 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { TLBoundsCorner, Utils } from '@tldraw/core'
import { StretchType, TLDrawShapeType } from '~types'
-import type { Data, TLDrawCommand } from '~types'
+import type { TLDrawSnapshot, TLDrawCommand } from '~types'
import { TLDR } from '~state/TLDR'
-export function stretchShapes(data: Data, ids: string[], type: StretchType): TLDrawCommand {
+export function stretchShapes(
+ data: TLDrawSnapshot,
+ ids: string[],
+ type: StretchType
+): TLDrawCommand {
const { currentPageId } = data.appState
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
diff --git a/packages/tldraw/src/state/commands/styleShapes/styleShapes.spec.ts b/packages/tldraw/src/state/commands/styleShapes/styleShapes.spec.ts
index b3298dce1..eae919601 100644
--- a/packages/tldraw/src/state/commands/styleShapes/styleShapes.spec.ts
+++ b/packages/tldraw/src/state/commands/styleShapes/styleShapes.spec.ts
@@ -5,69 +5,69 @@ import { SizeStyle, TLDrawShapeType } from '~types'
describe('Style command', () => {
it('does, undoes and redoes command', () => {
- const tlstate = new TLDrawState()
- tlstate.loadDocument(mockDocument)
- tlstate.select('rect1')
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
+ const state = new TLDrawState()
+ state.loadDocument(mockDocument)
+ state.select('rect1')
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
- tlstate.style({ size: SizeStyle.Small })
+ state.style({ size: SizeStyle.Small })
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Small)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Small)
})
describe('When styling groups', () => {
it('applies style to all group children', () => {
- const tlstate = new TLDrawState()
- tlstate
+ const state = new TLDrawState()
+ state
.loadDocument(mockDocument)
.group(['rect1', 'rect2'], 'groupA')
.select('groupA')
.style({ size: SizeStyle.Small })
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Small)
- expect(tlstate.getShape('rect2').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect2').style.size).toEqual(SizeStyle.Small)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
- expect(tlstate.getShape('rect2').style.size).toEqual(SizeStyle.Medium)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Medium)
+ expect(state.getShape('rect2').style.size).toEqual(SizeStyle.Medium)
- tlstate.redo()
+ state.redo()
- expect(tlstate.getShape('rect1').style.size).toEqual(SizeStyle.Small)
- expect(tlstate.getShape('rect2').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect1').style.size).toEqual(SizeStyle.Small)
+ expect(state.getShape('rect2').style.size).toEqual(SizeStyle.Small)
})
})
describe('When styling text', () => {
it('recenters the shape if the size changed', () => {
- const tlstate = new TLDrawState().createShapes({
+ const state = new TLDrawState().createShapes({
id: 'text1',
type: TLDrawShapeType.Text,
text: 'Hello world',
})
- const centerA = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(tlstate.getShape('text1'))
+ const centerA = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(state.getShape('text1'))
- tlstate.select('text1').style({ size: SizeStyle.Large })
+ state.select('text1').style({ size: SizeStyle.Large })
- const centerB = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(tlstate.getShape('text1'))
+ const centerB = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(state.getShape('text1'))
- tlstate.style({ size: SizeStyle.Small })
+ state.style({ size: SizeStyle.Small })
- const centerC = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(tlstate.getShape('text1'))
+ const centerC = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(state.getShape('text1'))
- tlstate.style({ size: SizeStyle.Medium })
+ state.style({ size: SizeStyle.Medium })
- const centerD = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(tlstate.getShape('text1'))
+ const centerD = TLDR.getShapeUtils(TLDrawShapeType.Text).getCenter(state.getShape('text1'))
expect(centerA).toEqual(centerB)
expect(centerA).toEqual(centerC)
@@ -78,17 +78,17 @@ describe('Style command', () => {
describe('when running the command', () => {
it('restores selection on undo', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
.loadDocument(mockDocument)
.select('rect1')
.style({ size: SizeStyle.Small })
.selectNone()
.undo()
- expect(tlstate.selectedIds).toEqual(['rect1'])
+ expect(state.selectedIds).toEqual(['rect1'])
- tlstate.selectNone().redo()
+ state.selectNone().redo()
- expect(tlstate.selectedIds).toEqual(['rect1'])
+ expect(state.selectedIds).toEqual(['rect1'])
})
})
diff --git a/packages/tldraw/src/state/commands/styleShapes/styleShapes.ts b/packages/tldraw/src/state/commands/styleShapes/styleShapes.ts
index 7d689d9bd..f64be5dcf 100644
--- a/packages/tldraw/src/state/commands/styleShapes/styleShapes.ts
+++ b/packages/tldraw/src/state/commands/styleShapes/styleShapes.ts
@@ -1,10 +1,17 @@
-import { ShapeStyles, TLDrawCommand, Data, TLDrawShape, TLDrawShapeType, TextShape } from '~types'
+import {
+ ShapeStyles,
+ TLDrawCommand,
+ TLDrawSnapshot,
+ TLDrawShape,
+ TLDrawShapeType,
+ TextShape,
+} from '~types'
import { TLDR } from '~state/TLDR'
import type { Patch } from 'rko'
import Vec from '@tldraw/vec'
export function styleShapes(
- data: Data,
+ data: TLDrawSnapshot,
ids: string[],
changes: Partial
): TLDrawCommand {
diff --git a/packages/tldraw/src/state/commands/toggleShapesDecoration/toggleShapesDecoration.spec.ts b/packages/tldraw/src/state/commands/toggleShapesDecoration/toggleShapesDecoration.spec.ts
index 2ea7e50c1..bffb2eda7 100644
--- a/packages/tldraw/src/state/commands/toggleShapesDecoration/toggleShapesDecoration.spec.ts
+++ b/packages/tldraw/src/state/commands/toggleShapesDecoration/toggleShapesDecoration.spec.ts
@@ -4,17 +4,17 @@ import { mockDocument } from '~test'
import { ArrowShape, Decoration, TLDrawShape, TLDrawShapeType } from '~types'
describe('Toggle decoration command', () => {
- const tlstate = new TLDrawState()
+ const state = new TLDrawState()
beforeEach(() => {
- tlstate.loadDocument(mockDocument)
+ state.loadDocument(mockDocument)
})
describe('when no shape is selected', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.toggleDecoration('start')
- const currentState = tlstate.state
+ const initialState = state.state
+ state.toggleDecoration('start')
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
@@ -22,34 +22,34 @@ describe('Toggle decoration command', () => {
describe('when handle id is invalid', () => {
it('does nothing', () => {
- const initialState = tlstate.state
- tlstate.toggleDecoration('invalid')
- const currentState = tlstate.state
+ const initialState = state.state
+ state.toggleDecoration('invalid')
+ const currentState = state.state
expect(currentState).toEqual(initialState)
})
})
it('does, undoes and redoes command', () => {
- tlstate
+ state
.createShapes({
id: 'arrow1',
type: TLDrawShapeType.Arrow,
})
.select('arrow1')
- expect(tlstate.getShape('arrow1').decorations?.end).toBe(Decoration.Arrow)
+ expect(state.getShape('arrow1').decorations?.end).toBe(Decoration.Arrow)
- tlstate.toggleDecoration('end')
+ state.toggleDecoration('end')
- expect(tlstate.getShape('arrow1').decorations?.end).toBe(undefined)
+ expect(state.getShape('arrow1').decorations?.end).toBe(undefined)
- tlstate.undo()
+ state.undo()
- expect(tlstate.getShape