diff --git a/packages/core/README.md b/packages/core/README.md index 6594872ae..b6b16c8dd 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -9,7 +9,6 @@ This package contains the core of the [tldraw](https://tldraw.com) library. It i - [`Utils`](#utils) - [`Vec`](#vec) - [`Svg`](#svg) - - [`brushUpdater`](#brushupdater) - [`Intersect`](#intersect) ## Installation @@ -160,17 +159,6 @@ An object that describes a relationship between two shapes on the page. The `TLShapeUtil` is an abstract class that you can extend to create utilities for your custom shapes. See [Guide: Create a Custom Shape](#create-a-custom-shape). -### `brushUpdater` - -The `brushUpdater` is a special class instance that allows you to quickly update the selection brush rectangle. - -| Method | Description | -| ------- | --------------------------------------------------------------- | -| `set` | a method that accepts either a `TLBounds` object or `undefined` | -| `clear` | a method to hide the brush | - -Normally, the renderer's brush will update in response to changes to `pageState.brush`; however, calling `brushUpdater.set` will produce a faster change in the brush rectangle. Calling `brushUpdater.set` will prevent the brush from any future updates from `pageState.brush`. - ## `inputs` A class instance that stores the current pointer position and pressed keys. diff --git a/packages/core/src/components/brush/BrushUpdater.ts b/packages/core/src/components/brush/BrushUpdater.ts deleted file mode 100644 index d760b3713..000000000 --- a/packages/core/src/components/brush/BrushUpdater.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as React from 'react' -import type { TLBounds } from '+types' - -export class BrushUpdater { - ref = React.createRef() - - isControlled = false - - set(bounds?: TLBounds) { - if (!this.isControlled) this.isControlled = true - - if (!bounds) { - this.clear() - return - } - - const elm = this.ref?.current - if (!elm) return - - elm.setAttribute('opacity', '1') - elm.setAttribute('transform', `translate(${bounds.minX.toString()}, ${bounds.minY.toString()})`) - elm.setAttribute('width', bounds.width.toString()) - elm.setAttribute('height', bounds.height.toString()) - } - - clear() { - const elm = this.ref?.current - if (!elm) return - elm.setAttribute('opacity', '0') - elm.setAttribute('width', '0') - elm.setAttribute('height', '0') - } -} diff --git a/packages/core/src/components/brush/brush.test.tsx b/packages/core/src/components/brush/brush.test.tsx index de0f3c7e2..2ab55599b 100644 --- a/packages/core/src/components/brush/brush.test.tsx +++ b/packages/core/src/components/brush/brush.test.tsx @@ -4,6 +4,17 @@ import { Brush } from './brush' describe('brush', () => { test('mounts component without crashing', () => { - renderWithSvg() + renderWithSvg( + + ) }) }) diff --git a/packages/core/src/components/brush/brush.tsx b/packages/core/src/components/brush/brush.tsx index 7b035324c..0b8479832 100644 --- a/packages/core/src/components/brush/brush.tsx +++ b/packages/core/src/components/brush/brush.tsx @@ -1,12 +1,21 @@ +import { SVGContainer } from '+components' +import { Container } from '+components/container' +import type { TLBounds } from '+types' import * as React from 'react' -import { BrushUpdater } from './BrushUpdater' -export const brushUpdater = new BrushUpdater() - -export const Brush = React.memo((): JSX.Element | null => { +export const Brush = React.memo(({ brush }: { brush: TLBounds }): JSX.Element | null => { return ( - - - + + + + + ) }) diff --git a/packages/core/src/components/brush/index.ts b/packages/core/src/components/brush/index.ts index 6931dc407..907faeba0 100644 --- a/packages/core/src/components/brush/index.ts +++ b/packages/core/src/components/brush/index.ts @@ -1,2 +1 @@ export * from './brush' -export * from './BrushUpdater' diff --git a/packages/core/src/components/canvas/canvas.tsx b/packages/core/src/components/canvas/canvas.tsx index 5cca00555..39efa67bb 100644 --- a/packages/core/src/components/canvas/canvas.tsx +++ b/packages/core/src/components/canvas/canvas.tsx @@ -73,7 +73,7 @@ export function Canvas>({ hideHandles={hideHandles} meta={meta} /> - + {pageState.brush && } diff --git a/packages/core/src/components/index.tsx b/packages/core/src/components/index.tsx index 8ede353af..df6ec775c 100644 --- a/packages/core/src/components/index.tsx +++ b/packages/core/src/components/index.tsx @@ -1,4 +1,3 @@ export * from './renderer' -export { brushUpdater } from './brush' export * from './svg-container' export * from './html-container' diff --git a/packages/core/src/components/renderer/renderer.tsx b/packages/core/src/components/renderer/renderer.tsx index f29d8d6d1..1c3c42ab1 100644 --- a/packages/core/src/components/renderer/renderer.tsx +++ b/packages/core/src/components/renderer/renderer.tsx @@ -55,6 +55,10 @@ export interface RendererProps void } /** @@ -74,6 +78,7 @@ export function Renderer): JSX.Element { useTLTheme(theme) @@ -96,6 +101,10 @@ export function Renderer { + onMount?.(context.inputs) + }, [context]) + return ( }> diff --git a/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx b/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx index 8476b0d7c..18e11805a 100644 --- a/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx +++ b/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import { inputs } from '@tldraw/core' import { useHotkeys } from 'react-hotkeys-hook' import { TLDrawShapeType } from '~types' import { useTLDrawContext } from '~hooks' @@ -9,13 +8,11 @@ export function useKeyboardShortcuts() { React.useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - const info = inputs.keydown(e) - tlstate.onKeyDown(e.key, info) + tlstate.onKeyDown(e.key) } const handleKeyUp = (e: KeyboardEvent) => { - const info = inputs.keyup(e) - tlstate.onKeyUp(e.key, info) + tlstate.onKeyUp(e.key) } window.addEventListener('keydown', handleKeyDown) diff --git a/packages/tldraw/src/state/session/sessions/brush/brush.session.ts b/packages/tldraw/src/state/session/sessions/brush/brush.session.ts index 01b151594..c336bd104 100644 --- a/packages/tldraw/src/state/session/sessions/brush/brush.session.ts +++ b/packages/tldraw/src/state/session/sessions/brush/brush.session.ts @@ -1,4 +1,4 @@ -import { brushUpdater, Utils } from '@tldraw/core' +import { Utils } from '@tldraw/core' import { Vec } from '@tldraw/vec' import { Data, Session, TLDrawPatch, TLDrawStatus } from '~types' import { TLDR } from '~state/tldr' @@ -23,14 +23,11 @@ export class BrushSession implements Session { // Create a bounding box between the origin and the new point const brush = Utils.getBoundsFromPoints([origin, point]) - brushUpdater.set(brush) - // Find ids of brushed shapes const hits = new Set() const selectedIds = new Set(snapshot.selectedIds) const page = TLDR.getPage(data, currentPageId) - const pageState = TLDR.getPageState(data, currentPageId) snapshot.shapesToTest.forEach(({ id, util, selectId }) => { if (selectedIds.has(id)) return @@ -55,17 +52,18 @@ export class BrushSession implements Session { } }) - if ( - selectedIds.size === pageState.selectedIds.length && - pageState.selectedIds.every((id) => selectedIds.has(id)) - ) { - return {} - } + // if ( + // selectedIds.size === pageState.selectedIds.length && + // pageState.selectedIds.every((id) => selectedIds.has(id)) + // ) { + // return {} + // } return { document: { pageStates: { [currentPageId]: { + brush, selectedIds: Array.from(selectedIds.values()), }, }, @@ -79,6 +77,7 @@ export class BrushSession implements Session { document: { pageStates: { [currentPageId]: { + brush: null, selectedIds: this.snapshot.selectedIds, }, }, @@ -89,10 +88,12 @@ export class BrushSession implements Session { complete(data: Data) { const { currentPageId } = data.appState const pageState = TLDR.getPageState(data, currentPageId) + return { document: { pageStates: { [currentPageId]: { + brush: null, selectedIds: [...pageState.selectedIds], }, }, diff --git a/packages/tldraw/src/state/tlstate.ts b/packages/tldraw/src/state/tlstate.ts index 6cf860be9..210ee622b 100644 --- a/packages/tldraw/src/state/tlstate.ts +++ b/packages/tldraw/src/state/tlstate.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { StateManager } from 'rko' import { TLBoundsCorner, @@ -5,15 +6,14 @@ import { TLBoundsEventHandler, TLBoundsHandleEventHandler, TLCanvasEventHandler, - TLKeyboardInfo, TLPageState, TLPinchEventHandler, TLPointerEventHandler, TLWheelEventHandler, Utils, - brushUpdater, TLPointerInfo, TLBounds, + Inputs, } from '@tldraw/core' import { Vec } from '@tldraw/vec' import { @@ -98,6 +98,8 @@ export class TLDrawState extends StateManager { private _onChange?: (tlstate: TLDrawState, data: Data, reason: string) => void private _onMount?: (tlstate: TLDrawState) => void + inputs?: Inputs + selectHistory: SelectHistory = { stack: [[]], pointer: 0, @@ -271,6 +273,10 @@ export class TLDrawState extends StateManager { ...data.document.pageStates[pageId], } + if (!nextPageState.brush) { + delete nextPageState.brush + } + if (nextPageState.hoveredId && !page.shapes[nextPageState.hoveredId]) { delete nextPageState.hoveredId } @@ -339,6 +345,10 @@ export class TLDrawState extends StateManager { ) } + handleMount = (inputs: Inputs): void => { + this.inputs = inputs + } + /* -------------------------------------------------- */ /* Settings & UI */ /* -------------------------------------------------- */ @@ -1357,10 +1367,10 @@ export class TLDrawState extends StateManager { if (!session) return this - const result = session.complete(this.state, ...args) - this.session = undefined + const result = session.complete(this.state, ...args) + if (result === undefined) { this.isCreating = false @@ -1450,6 +1460,7 @@ export class TLDrawState extends StateManager { document: { pageStates: { [this.currentPageId]: { + ...result.document?.pageStates?.[this.currentPageId], editingId: null, }, }, @@ -1939,7 +1950,6 @@ export class TLDrawState extends StateManager { } case TLDrawStatus.Brushing: { this.cancelSession() - brushUpdater.clear() break } case TLDrawStatus.Translating: @@ -2132,9 +2142,13 @@ export class TLDrawState extends StateManager { /* ----------------- Keyboard Events ---------------- */ - onKeyDown = (key: string, info: TLKeyboardInfo) => { + onKeyDown = (key: string) => { + const info = this.inputs?.pointer + if (!info) return + if (key === 'Escape') { this.cancel() + return } @@ -2188,7 +2202,10 @@ export class TLDrawState extends StateManager { } } - onKeyUp = (key: string, info: TLKeyboardInfo) => { + onKeyUp = (key: string) => { + const info = this.inputs?.pointer + if (!info) return + switch (this.appState.status.current) { case TLDrawStatus.Brushing: { if (key === 'Meta' || key === 'Control') { @@ -2360,7 +2377,6 @@ export class TLDrawState extends StateManager { } case TLDrawStatus.Brushing: { this.completeSession() - brushUpdater.clear() break } case TLDrawStatus.Translating: { @@ -2642,7 +2658,6 @@ export class TLDrawState extends StateManager { } case TLDrawStatus.Brushing: { this.completeSession() - brushUpdater.clear() break } }