Move state to rko

This commit is contained in:
Steve Ruiz 2021-08-29 14:33:43 +01:00
parent c3e6c55a68
commit 9e8e99cb6f
22 changed files with 4105 additions and 1482 deletions

View file

@ -17,6 +17,7 @@
],
"scripts": {
"test": "jest",
"test:watch": "jest --watchAll",
"lerna": "lerna",
"start": "lerna run start --stream --parallel",
"start:www": "lerna run start --stream --parallel & cd packages/www && yarn dev",
@ -26,25 +27,27 @@
},
"devDependencies": {
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@types/jest": "^26.0.24",
"@types/jest": "^27.0.1",
"@types/node": "^15.0.1",
"@types/react": "^17.0.16",
"@types/react": "^17.0.19",
"@types/react-dom": "^17.0.9",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"babel-jest": "^27.0.6",
"babel-jest": "^27.1.0",
"esbuild": "^0.11.11",
"jest": "^27.0.6",
"fake-indexeddb": "^3.1.3",
"jest": "^27.1.0",
"lerna": "^3.15.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"ts-jest": "^27.0.4",
"ts-jest": "^27.0.5",
"tslib": "^2.3.0",
"typescript": "^4.3.5"
"typescript": "^4.4.2"
},
"dependencies": {},
"prettier": {
@ -59,7 +62,7 @@
"<rootDir>/setupTests.ts"
],
"transform": {
"^.+\\.(tsx|jsx|ts|js)?$": "ts-jest"
"^.+\\.(tsx|jsx|ts|js|mjs)?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": [
@ -72,9 +75,17 @@
],
"globals": {
"ts-jest": {
"tsConfig": "tsconfig.json",
"tsconfig": "tsconfig.json",
"babelConfig": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"esmodules": true
}
}
],
[
"@babel/preset-react"
],

View file

@ -58,7 +58,7 @@
"ismobilejs": "^1.1.1",
"perfect-freehand": "^0.5.2",
"react-hotkeys-hook": "^3.4.0",
"zustand": "^3.5.7"
"rko": "^0.5.18"
},
"gitHead": "4a7439ddf81b615ee49fddbe00802699975f9375"
}
}

View file

@ -22,7 +22,7 @@ async function main() {
esbuild.buildSync({
entryPoints: ['./src/index.ts'],
outdir: 'dist/esm',
minify: true,
minify: false,
bundle: true,
format: 'esm',
target: 'es6',

View file

@ -32,7 +32,7 @@ const isDarkModeSelector = (s: Data) => s.settings.isDarkMode
export function TLDraw({ document, currentPageId, onMount, onChange: _onChange }: TLDrawProps) {
const [tlstate] = React.useState(() => new TLDrawState())
const [context] = React.useState(() => {
return { tlstate, useSelector: tlstate.store }
return { tlstate, useSelector: tlstate.useStore }
})
useKeyboardShortcuts(tlstate)

View file

@ -26,67 +26,56 @@ export function useKeyboardShortcuts(tlstate: TLDrawState) {
/* ---------------------- Tools --------------------- */
useHotkeys('v,1', (e) => {
useHotkeys('v,1', () => {
tlstate.selectTool('select')
e.preventDefault()
})
useHotkeys('d,2', (e) => {
useHotkeys('d,2', () => {
tlstate.selectTool(TLDrawShapeType.Draw)
e.preventDefault()
})
useHotkeys('r,3', (e) => {
useHotkeys('r,3', () => {
tlstate.selectTool(TLDrawShapeType.Rectangle)
e.preventDefault()
})
useHotkeys('e,4', (e) => {
useHotkeys('e,4', () => {
tlstate.selectTool(TLDrawShapeType.Ellipse)
e.preventDefault()
})
useHotkeys('a,5', (e) => {
useHotkeys('a,5', () => {
tlstate.selectTool(TLDrawShapeType.Arrow)
e.preventDefault()
})
useHotkeys('t,6', (e) => {
useHotkeys('t,6', () => {
tlstate.selectTool(TLDrawShapeType.Text)
e.preventDefault()
})
/* ---------------------- Misc ---------------------- */
// Save
useHotkeys('ctrl+s,command+s', (e) => {
tlstate.save()
e.preventDefault()
useHotkeys('ctrl+s,command+s', () => {
tlstate.saveProject()
})
// Undo Redo
useHotkeys('command+z,ctrl+z', (e) => {
useHotkeys('command+z,ctrl+z', () => {
tlstate.undo()
e.preventDefault()
})
useHotkeys('ctrl+shift-z,command+shift+z', (e) => {
useHotkeys('ctrl+shift-z,command+shift+z', () => {
tlstate.redo()
e.preventDefault()
})
// Undo Redo
useHotkeys('command+u,ctrl+u', (e) => {
useHotkeys('command+u,ctrl+u', () => {
tlstate.undoSelect()
e.preventDefault()
})
useHotkeys('ctrl+shift-u,command+shift+u', (e) => {
useHotkeys('ctrl+shift-u,command+shift+u', () => {
tlstate.redoSelect()
e.preventDefault()
})
/* -------------------- Commands -------------------- */
@ -103,139 +92,115 @@ export function useKeyboardShortcuts(tlstate: TLDrawState) {
e.preventDefault()
})
useHotkeys('shift+1', (e) => {
useHotkeys('shift+1', () => {
tlstate.zoomToFit()
e.preventDefault()
})
useHotkeys('shift+2', (e) => {
useHotkeys('shift+2', () => {
tlstate.zoomToSelection()
e.preventDefault()
})
useHotkeys('shift+0', (e) => {
useHotkeys('shift+0', () => {
tlstate.zoomToActual()
e.preventDefault()
})
// Duplicate
useHotkeys('ctrl+d,command+d', (e) => {
useHotkeys('ctrl+d,command+d', () => {
tlstate.duplicate()
e.preventDefault()
})
// Flip
useHotkeys('shift+h', (e) => {
useHotkeys('shift+h', () => {
tlstate.flipHorizontal()
e.preventDefault()
})
useHotkeys('shift+v', (e) => {
useHotkeys('shift+v', () => {
tlstate.flipVertical()
e.preventDefault()
})
// Cancel
useHotkeys('escape', (e) => {
useHotkeys('escape', () => {
tlstate.cancel()
e.preventDefault()
})
// Delete
useHotkeys('backspace', (e) => {
useHotkeys('backspace', () => {
tlstate.delete()
e.preventDefault()
})
// Select All
useHotkeys('command+a,ctrl+a', (e) => {
useHotkeys('command+a,ctrl+a', () => {
tlstate.selectAll()
e.preventDefault()
})
// Nudge
useHotkeys('up', (e) => {
useHotkeys('up', () => {
tlstate.nudge([0, -1], false)
e.preventDefault()
})
useHotkeys('right', (e) => {
useHotkeys('right', () => {
tlstate.nudge([1, 0], false)
e.preventDefault()
})
useHotkeys('down', (e) => {
useHotkeys('down', () => {
tlstate.nudge([0, 1], false)
e.preventDefault()
})
useHotkeys('left', (e) => {
useHotkeys('left', () => {
tlstate.nudge([-1, 0], false)
e.preventDefault()
})
useHotkeys('shift+up', (e) => {
useHotkeys('shift+up', () => {
tlstate.nudge([0, -1], true)
e.preventDefault()
})
useHotkeys('shift+right', (e) => {
useHotkeys('shift+right', () => {
tlstate.nudge([1, 0], true)
e.preventDefault()
})
useHotkeys('shift+down', (e) => {
useHotkeys('shift+down', () => {
tlstate.nudge([0, 1], true)
e.preventDefault()
})
useHotkeys('shift+left', (e) => {
useHotkeys('shift+left', () => {
tlstate.nudge([-1, 0], true)
e.preventDefault()
})
// Copy & Paste
useHotkeys('command+c,ctrl+c', (e) => {
useHotkeys('command+c,ctrl+c', () => {
tlstate.copy()
e.preventDefault()
})
useHotkeys('command+v,ctrl+v', (e) => {
useHotkeys('command+v,ctrl+v', () => {
tlstate.paste()
e.preventDefault()
})
// Move
useHotkeys('[', (e) => {
useHotkeys('[', () => {
tlstate.moveBackward()
e.preventDefault()
})
useHotkeys(']', (e) => {
useHotkeys(']', () => {
tlstate.moveForward()
e.preventDefault()
})
useHotkeys('shift+[', (e) => {
useHotkeys('shift+[', () => {
tlstate.moveToBack()
e.preventDefault()
})
useHotkeys('shift+]', (e) => {
useHotkeys('shift+]', () => {
tlstate.moveToFront()
e.preventDefault()
})
useHotkeys('command+shift+backspace', (e) => {
useHotkeys('command+shift+backspace', () => {
tlstate.reset()
e.preventDefault()
})
}

File diff suppressed because it is too large Load diff

View file

@ -46,11 +46,11 @@ describe('Move command', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b'])
tlstate.moveToBack()
expect(getSortedShapeIds(tlstate.data)).toBe('bacd')
expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
tlstate.undo()
expect(getSortedShapeIds(tlstate.data)).toBe('abcd')
expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
tlstate.redo()
expect(getSortedShapeIds(tlstate.data)).toBe('bacd')
expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
})
describe('to back', () => {
@ -58,21 +58,21 @@ describe('Move command', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b'])
tlstate.moveToBack()
expect(getSortedShapeIds(tlstate.data)).toBe('bacd')
expect(getSortedShapeIds(tlstate.state)).toBe('bacd')
})
it('moves two adjacent siblings to back', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b', 'c'])
tlstate.moveToBack()
expect(getSortedShapeIds(tlstate.data)).toBe('bcad')
expect(getSortedShapeIds(tlstate.state)).toBe('bcad')
})
it('moves two non-adjacent siblings to back', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b', 'd'])
tlstate.moveToBack()
expect(getSortedShapeIds(tlstate.data)).toBe('bdac')
expect(getSortedShapeIds(tlstate.state)).toBe('bdac')
})
})
@ -81,35 +81,35 @@ describe('Move command', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['c'])
tlstate.moveBackward()
expect(getSortedShapeIds(tlstate.data)).toBe('acbd')
expect(getSortedShapeIds(tlstate.state)).toBe('acbd')
})
it('moves a shape at first index backward', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a'])
tlstate.moveBackward()
expect(getSortedShapeIds(tlstate.data)).toBe('abcd')
expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
})
it('moves two adjacent siblings backward', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['c', 'd'])
tlstate.moveBackward()
expect(getSortedShapeIds(tlstate.data)).toBe('acdb')
expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
})
it('moves two non-adjacent siblings backward', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b', 'd'])
tlstate.moveBackward()
expect(getSortedShapeIds(tlstate.data)).toBe('badc')
expect(getSortedShapeIds(tlstate.state)).toBe('badc')
})
it('moves two adjacent siblings backward at zero index', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a', 'b'])
tlstate.moveBackward()
expect(getSortedShapeIds(tlstate.data)).toBe('abcd')
expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
})
})
@ -118,7 +118,7 @@ describe('Move command', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['c'])
tlstate.moveForward()
expect(getSortedShapeIds(tlstate.data)).toBe('abdc')
expect(getSortedShapeIds(tlstate.state)).toBe('abdc')
})
it('moves a shape forward at the top index', () => {
@ -127,28 +127,28 @@ describe('Move command', () => {
tlstate.moveForward()
tlstate.moveForward()
tlstate.moveForward()
expect(getSortedShapeIds(tlstate.data)).toBe('acdb')
expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
})
it('moves two adjacent siblings forward', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a', 'b'])
tlstate.moveForward()
expect(getSortedShapeIds(tlstate.data)).toBe('cabd')
expect(getSortedShapeIds(tlstate.state)).toBe('cabd')
})
it('moves two non-adjacent siblings forward', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a', 'c'])
tlstate.moveForward()
expect(getSortedShapeIds(tlstate.data)).toBe('badc')
expect(getSortedShapeIds(tlstate.state)).toBe('badc')
})
it('moves two adjacent siblings forward at top index', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['c', 'd'])
tlstate.moveForward()
expect(getSortedShapeIds(tlstate.data)).toBe('abcd')
expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
})
})
@ -157,28 +157,28 @@ describe('Move command', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['b'])
tlstate.moveToFront()
expect(getSortedShapeIds(tlstate.data)).toBe('acdb')
expect(getSortedShapeIds(tlstate.state)).toBe('acdb')
})
it('moves two adjacent siblings to front', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a', 'b'])
tlstate.moveToFront()
expect(getSortedShapeIds(tlstate.data)).toBe('cdab')
expect(getSortedShapeIds(tlstate.state)).toBe('cdab')
})
it('moves two non-adjacent siblings to front', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['a', 'c'])
tlstate.moveToFront()
expect(getSortedShapeIds(tlstate.data)).toBe('bdac')
expect(getSortedShapeIds(tlstate.state)).toBe('bdac')
})
it('moves siblings already at front to front', () => {
tlstate.loadDocument(doc)
tlstate.setSelectedIds(['c', 'd'])
tlstate.moveToFront()
expect(getSortedShapeIds(tlstate.data)).toBe('abcd')
expect(getSortedShapeIds(tlstate.state)).toBe('abcd')
})
})
})

View file

@ -41,7 +41,7 @@ describe('Arrow session', () => {
expect(binding.fromId).toBe('arrow1')
expect(binding.toId).toBe('target1')
expect(binding.handleId).toBe('start')
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.getShape('arrow1').handles?.start.bindingId).toBe(binding.id)
tlstate.undo()

View file

@ -11,7 +11,7 @@ describe('Brush session', () => {
tlstate.startBrushSession([-10, -10])
tlstate.updateBrushSession([10, 10])
tlstate.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.selectedIds.length).toBe(1)
})

View file

@ -30,7 +30,7 @@ describe('Transform session', () => {
.updateDrawSession([10, 10], 0.5)
.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
})
it('does, undoes and redoes', () => {

View file

@ -20,7 +20,7 @@ describe('Handle session', () => {
.updateHandleSession([10, 10])
.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
tlstate.undo().redo()
})

View file

@ -35,7 +35,7 @@ describe('Brush session', () => {
tlstate.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
tlstate.undo()

View file

@ -14,7 +14,7 @@ describe('Transform single session', () => {
.updateTransformSession([10, 10])
.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
tlstate.undo().redo()
})

View file

@ -31,7 +31,7 @@ describe('Transform session', () => {
.updateTransformSession([10, 10])
.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
expect(getShapeBounds(tlstate, 'rect1')).toMatchObject({
minX: 10,

View file

@ -17,7 +17,7 @@ describe('Brush session', () => {
tlstate.completeSession()
expect(tlstate.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.appState.status.current).toBe(TLDrawStatus.Idle)
expect(tlstate.getShape('rect1').point).toStrictEqual([5, 5])

View file

@ -1,6 +1,5 @@
import { TLDrawState } from './tlstate'
import { mockDocument, TLStateUtils } from '~test'
import { Utils } from '@tldraw/core'
describe('TLDrawState', () => {
const tlstate = new TLDrawState()
@ -52,7 +51,7 @@ describe('TLDrawState', () => {
tlstate.loadDocument(mockDocument).deselectAll()
tlu.clickShape('rect1')
expect(tlstate.selectedIds).toStrictEqual(['rect1'])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('selects and deselects a shape', () => {
@ -60,7 +59,7 @@ describe('TLDrawState', () => {
tlu.clickShape('rect1')
tlu.clickCanvas()
expect(tlstate.selectedIds).toStrictEqual([])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('selects multiple shapes', () => {
@ -68,7 +67,7 @@ describe('TLDrawState', () => {
tlu.clickShape('rect1')
tlu.clickShape('rect2', { shiftKey: true })
expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('shift-selects to deselect shapes', () => {
@ -78,7 +77,7 @@ describe('TLDrawState', () => {
expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
tlu.clickShape('rect2', { shiftKey: true })
expect(tlstate.selectedIds).toStrictEqual(['rect1'])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('clears selection when clicking bounds', () => {
@ -105,14 +104,14 @@ describe('TLDrawState', () => {
tlstate.loadDocument(mockDocument).deselectAll()
tlu.clickShape('rect1', { ctrlKey: true })
expect(tlstate.selectedIds).toStrictEqual([])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('does not select on meta-shift-click', () => {
tlstate.loadDocument(mockDocument).deselectAll()
tlu.clickShape('rect1', { ctrlKey: true, shiftKey: true })
expect(tlstate.selectedIds).toStrictEqual([])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('deletes shapes if cancelled during creating', () => {
@ -139,7 +138,7 @@ describe('TLDrawState', () => {
tlu.clickShape('rect2', { shiftKey: true })
tlu.clickShape('rect2')
expect(tlstate.selectedIds).toStrictEqual(['rect2'])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
it('single-selects shape in selection on pointerup only', () => {
@ -150,17 +149,17 @@ describe('TLDrawState', () => {
expect(tlstate.selectedIds).toStrictEqual(['rect1', 'rect2'])
tlu.stopPointing('rect2')
expect(tlstate.selectedIds).toStrictEqual(['rect2'])
expect(tlstate.status.current).toBe('idle')
expect(tlstate.appState.status.current).toBe('idle')
})
// it('selects shapes if shift key is lifted before pointerup', () => {
// tlstate.deselectAll()
// tlu.clickShape('rect1')
// tlu.pointShape('rect2', { shiftKey: true })
// expect(tlstate.status.current).toBe('pointingBounds')
// expect(tlstate.appState.status.current).toBe('pointingBounds')
// tlu.stopPointing('rect2')
// expect(tlstate.selectedIds).toStrictEqual(['rect2'])
// expect(tlstate.status.current).toBe('idle')
// expect(tlstate.appState.status.current).toBe('idle')
// })
})

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ import { render } from '@testing-library/react'
export const Wrapper: React.FC = ({ children }) => {
const [tlstate] = React.useState(() => new TLDrawState())
const [context] = React.useState(() => {
return { tlstate, useSelector: tlstate.store }
return { tlstate, useSelector: tlstate.useStore }
})
useKeyboardShortcuts(tlstate)

View file

@ -1 +1,2 @@
import '@testing-library/jest-dom/extend-expect'
import "fake-indexeddb/auto"

View file

@ -20,7 +20,7 @@
"strict": false,
"strictFunctionTypes": true /* Enable strict checking of function types. */,
"strictNullChecks": true /* Enable strict null checks. */,
"target": "es5",
"target": "es6",
"typeRoots": ["node_modules/@types", "node_modules/jest"],
"types": ["node", "jest"],
"jsx": "preserve",

File diff suppressed because one or more lines are too long

1468
yarn.lock

File diff suppressed because it is too large Load diff