From ebc892a1a6b80556e1dfb7b1f953e206ca05120c Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Tue, 7 May 2024 11:06:35 +0100 Subject: [PATCH] Camera options followups (#3701) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a slideshow example (similar to @TodePond's slides but more on rails) as a way to put some pressure on camera controls. Along the way, it fixes some issues I found with animations and the new camera controls. - forced changes will continue to force through animations - animations no longer set unnecessary additional listeners - animations end correctly - updating camera options does not immediately update the camera (to allow for animations, etc.) It also changes the location of the "in front of the canvas" element so that it is not hidden by the hit test blocking element. ### Change Type - [x] `sdk` — Changes the tldraw SDK - [x] `improvement` — Improving existing features --- apps/dotcom/package.json | 2 +- apps/examples/package.json | 2 +- .../camera-options/CameraOptionsExample.tsx | 2 +- .../editor-focus/EditorFocusExample.tsx | 31 +- .../image-annotator/ImageAnnotationEditor.tsx | 30 +- .../src/examples/pdf-editor/PdfEditor.tsx | 24 +- .../examples/src/examples/slideshow/README.md | 11 + .../examples/slideshow/SlideShowExample.tsx | 264 ++++++++++++++++++ .../src/examples/slideshow/SlidesManager.tsx | 100 +++++++ apps/examples/tsconfig.json | 3 +- apps/examples/vite.config.ts | 4 +- packages/editor/api-report.md | 2 +- packages/editor/editor.css | 15 +- packages/editor/src/lib/TldrawEditor.tsx | 17 +- .../default-components/DefaultCanvas.tsx | 7 - packages/editor/src/lib/editor/Editor.ts | 46 +-- .../SelectTool/childStates/Translating.ts | 30 +- .../src/test/commands/setCamera.test.ts | 148 +++++----- packages/utils/api-report.md | 10 +- .../utils/src/lib/reordering/reordering.ts | 10 +- templates/vite/package.json | 2 +- yarn.lock | 153 ++++------ 22 files changed, 636 insertions(+), 277 deletions(-) create mode 100644 apps/examples/src/examples/slideshow/README.md create mode 100644 apps/examples/src/examples/slideshow/SlideShowExample.tsx create mode 100644 apps/examples/src/examples/slideshow/SlidesManager.tsx diff --git a/apps/dotcom/package.json b/apps/dotcom/package.json index c2cd34985..815710ae0 100644 --- a/apps/dotcom/package.json +++ b/apps/dotcom/package.json @@ -44,7 +44,7 @@ "@types/qrcode": "^1.5.0", "@types/react": "^18.2.47", "@typescript-eslint/utils": "^5.59.0", - "@vitejs/plugin-react-swc": "^3.5.0", + "@vitejs/plugin-react-swc": "^3.6.0", "dotenv": "^16.3.1", "eslint": "^8.37.0", "fast-glob": "^3.3.1", diff --git a/apps/examples/package.json b/apps/examples/package.json index 4fa778353..6c95141ab 100644 --- a/apps/examples/package.json +++ b/apps/examples/package.json @@ -50,7 +50,7 @@ }, "devDependencies": { "@types/lodash": "^4.14.188", - "@vitejs/plugin-react": "^4.2.0", + "@vitejs/plugin-react-swc": "^3.6.0", "dotenv": "^16.3.1", "remark": "^15.0.1", "remark-frontmatter": "^5.0.0", diff --git a/apps/examples/src/examples/camera-options/CameraOptionsExample.tsx b/apps/examples/src/examples/camera-options/CameraOptionsExample.tsx index 91ab37139..91ef80ace 100644 --- a/apps/examples/src/examples/camera-options/CameraOptionsExample.tsx +++ b/apps/examples/src/examples/camera-options/CameraOptionsExample.tsx @@ -145,7 +145,7 @@ const CameraOptionsControlPanel = track(() => { useEffect(() => { if (!editor) return editor.batch(() => { - editor.setCameraOptions(cameraOptions, { immediate: true }) + editor.setCameraOptions(cameraOptions) editor.setCamera(editor.getCamera(), { immediate: true, }) diff --git a/apps/examples/src/examples/editor-focus/EditorFocusExample.tsx b/apps/examples/src/examples/editor-focus/EditorFocusExample.tsx index 49b59c0f0..035d4a2a5 100644 --- a/apps/examples/src/examples/editor-focus/EditorFocusExample.tsx +++ b/apps/examples/src/examples/editor-focus/EditorFocusExample.tsx @@ -13,16 +13,26 @@ export default function EditorFocusExample() { }, [focused]) return ( -
-
- { - setFocused(e.target.checked) - }} - /> - +
{ + const editor = rEditorRef.current + if (editor && editor.getInstanceState().isFocused) { + editor.updateInstanceState({ isFocused: false }) + } + }} + > +
+
+ { + setFocused(e.target.checked) + }} + /> + +

The checkbox controls the editor's instanceState.isFocused property. @@ -39,6 +49,7 @@ export default function EditorFocusExample() { }} />

+
) } diff --git a/apps/examples/src/examples/image-annotator/ImageAnnotationEditor.tsx b/apps/examples/src/examples/image-annotator/ImageAnnotationEditor.tsx index 774e63474..854a4fe80 100644 --- a/apps/examples/src/examples/image-annotator/ImageAnnotationEditor.tsx +++ b/apps/examples/src/examples/image-annotator/ImageAnnotationEditor.tsx @@ -133,23 +133,21 @@ export function ImageAnnotationEditor({ * component hooks into camera updates to keep the camera constrained - try uploading a very long, * thin image and seeing how the camera behaves. */ - editor.setCameraOptions( - { - constraints: { - initialZoom: 'fit-max', - baseZoom: 'default', - bounds: { w: image.width, h: image.height, x: 0, y: 0 }, - padding: { x: 32, y: 64 }, - origin: { x: 0.5, y: 0.5 }, - behavior: 'contain', - }, - zoomSteps: [1, 2, 4, 8], - zoomSpeed: 1, - panSpeed: 1, - isLocked: false, + editor.setCameraOptions({ + constraints: { + initialZoom: 'fit-max', + baseZoom: 'default', + bounds: { w: image.width, h: image.height, x: 0, y: 0 }, + padding: { x: 32, y: 64 }, + origin: { x: 0.5, y: 0.5 }, + behavior: 'contain', }, - { reset: true } - ) + zoomSteps: [1, 2, 4, 8], + zoomSpeed: 1, + panSpeed: 1, + isLocked: false, + }) + editor.setCamera(editor.getCamera(), { reset: true }) }, [editor, imageShapeId, image]) return ( diff --git a/apps/examples/src/examples/pdf-editor/PdfEditor.tsx b/apps/examples/src/examples/pdf-editor/PdfEditor.tsx index c30a465c6..359531478 100644 --- a/apps/examples/src/examples/pdf-editor/PdfEditor.tsx +++ b/apps/examples/src/examples/pdf-editor/PdfEditor.tsx @@ -117,20 +117,18 @@ export function PdfEditor({ pdf }: { pdf: Pdf }) { ) function updateCameraBounds(isMobile: boolean) { - editor.setCameraOptions( - { - ...DEFAULT_CAMERA_OPTIONS, - constraints: { - bounds: targetBounds, - padding: { x: isMobile ? 16 : 164, y: 64 }, - origin: { x: 0.5, y: 0 }, - initialZoom: 'fit-x-100', - baseZoom: 'default', - behavior: 'contain', - }, + editor.setCameraOptions({ + ...DEFAULT_CAMERA_OPTIONS, + constraints: { + bounds: targetBounds, + padding: { x: isMobile ? 16 : 164, y: 64 }, + origin: { x: 0.5, y: 0 }, + initialZoom: 'fit-x-100', + baseZoom: 'default', + behavior: 'contain', }, - { reset: true } - ) + }) + editor.setCamera(editor.getCamera(), { reset: true }) } let isMobile = editor.getViewportScreenBounds().width < 840 diff --git a/apps/examples/src/examples/slideshow/README.md b/apps/examples/src/examples/slideshow/README.md new file mode 100644 index 000000000..344316208 --- /dev/null +++ b/apps/examples/src/examples/slideshow/README.md @@ -0,0 +1,11 @@ +--- +title: Slideshow with Camera +component: ./SlideShowExample.tsx +category: use-cases +--- + +--- + +The `Tldraw` component provides the tldraw editor as a regular React component. You can put this component anywhere in your React project. In this example, we make the component take up the height and width of the container. + +By default, the component does not persist between refreshes or sync locally between tabs. To keep your work after a refresh, check the [`persistenceKey`](/peristence-key) example. diff --git a/apps/examples/src/examples/slideshow/SlideShowExample.tsx b/apps/examples/src/examples/slideshow/SlideShowExample.tsx new file mode 100644 index 000000000..903911901 --- /dev/null +++ b/apps/examples/src/examples/slideshow/SlideShowExample.tsx @@ -0,0 +1,264 @@ +import { useEffect, useState } from 'react' +import { + DEFAULT_CAMERA_OPTIONS, + Editor, + TLFrameShape, + Tldraw, + createShapeId, + stopEventPropagation, + transact, + useValue, +} from 'tldraw' +import 'tldraw/tldraw.css' +import { SLIDE_MARGIN, SLIDE_SIZE, SlidesProvider, useSlides } from './SlidesManager' + +export default function SlideShowExample() { + return ( +
+ + + +
+ ) +} + +function InsideSlidesContext() { + const [editor, setEditor] = useState(null) + const slides = useSlides() + + const currentSlide = useValue('currentSlide', () => slides.getCurrentSlide(), [slides]) + + useEffect(() => { + if (!editor) return + + const nextBounds = { + x: currentSlide.index * (SLIDE_SIZE.w + SLIDE_MARGIN), + y: 0, + w: SLIDE_SIZE.w, + h: SLIDE_SIZE.h, + } + + editor.setCameraOptions({ + ...DEFAULT_CAMERA_OPTIONS, + constraints: { + bounds: nextBounds, + behavior: 'contain', + initialZoom: 'fit-max', + baseZoom: 'fit-max', + origin: { x: 0.5, y: 0.5 }, + padding: { x: 50, y: 50 }, + }, + }) + + editor.zoomToBounds(nextBounds, { force: true, animation: { duration: 500 } }) + }, [editor, currentSlide]) + + const currentSlides = useValue('slides', () => slides.getCurrentSlides(), [slides]) + + useEffect(() => { + if (!editor) return + + const ids = currentSlides.map((slide) => createShapeId(slide.id)) + + transact(() => { + for (let i = 0; i < currentSlides.length; i++) { + const shapeId = ids[i] + const slide = currentSlides[i] + const shape = editor.getShape(shapeId) + if (shape) { + if (shape.x === slide.index * (SLIDE_SIZE.w + SLIDE_MARGIN)) continue + + // if name is still Slide and number, e.g Slide 1, update it. Use regex to test + + const regex = /Slide \d+/ + let name = (shape as TLFrameShape).props.name + if (regex.test((shape as TLFrameShape).props.name)) { + name = `Slide ${slide.index + 1}` + } + + editor.updateShape({ + id: shapeId, + type: 'frame', + x: slide.index * (SLIDE_SIZE.w + SLIDE_MARGIN), + props: { + name, + }, + }) + } else { + editor.createShape({ + id: shapeId, + parentId: editor.getCurrentPageId(), + type: 'frame', + x: slide.index * (SLIDE_SIZE.w + SLIDE_MARGIN), + y: 0, + props: { + name: `Slide ${slide.index + 1}`, + w: SLIDE_SIZE.w, + h: SLIDE_SIZE.h, + }, + }) + } + } + }) + + const unsubs = [] as (() => void)[] + + unsubs.push( + editor.sideEffects.registerBeforeChangeHandler('shape', (prev, next) => { + if ( + ids.includes(next.id) && + (next as TLFrameShape).props.name === (prev as TLFrameShape).props.name + ) + return prev + return next + }) + ) + + unsubs.push( + editor.sideEffects.registerBeforeChangeHandler('instance_page_state', (prev, next) => { + next.selectedShapeIds = next.selectedShapeIds.filter((id) => !ids.includes(id)) + if (next.hoveredShapeId && ids.includes(next.hoveredShapeId)) next.hoveredShapeId = null + return next + }) + ) + + return () => { + unsubs.forEach((fn) => fn()) + } + }, [currentSlides, editor]) + + const handleMount = (editor: Editor) => { + setEditor(editor) + } + + return +} + +function Slides() { + const slides = useSlides() + const currentSlides = useValue('slides', () => slides.getCurrentSlides(), [slides]) + const lowestIndex = currentSlides[0].index + const highestIndex = currentSlides[currentSlides.length - 1].index + + return ( + <> + {/* {currentSlides.map((slide) => ( +
{ + if (slide.id !== slides.getCurrentSlideId()) { + stopEventPropagation(e) + slides.setCurrentSlide(slide.id) + } + }} + /> + ))} */} + {currentSlides.slice(0, -1).map((slide) => ( + + ))} + + + + ) +} + +function SlideControls() { + const slides = useSlides() + + return ( + <> + + + + ) +} + +const components = { + OnTheCanvas: Slides, + InFrontOfTheCanvas: SlideControls, +} diff --git a/apps/examples/src/examples/slideshow/SlidesManager.tsx b/apps/examples/src/examples/slideshow/SlidesManager.tsx new file mode 100644 index 000000000..58166c561 --- /dev/null +++ b/apps/examples/src/examples/slideshow/SlidesManager.tsx @@ -0,0 +1,100 @@ +import { createContext, ReactNode, useContext, useState } from 'react' +import { atom, computed, structuredClone, uniqueId } from 'tldraw' + +export const SLIDE_SIZE = { x: 0, y: 0, w: 1600, h: 900 } +export const SLIDE_MARGIN = 100 + +type Slide = { + id: string + index: number + name: string +} + +class SlidesManager { + private _slides = atom('slide', [ + { + id: '1', + index: 0, + name: 'Slide 1', + }, + { + id: '2', + index: 1, + name: 'Slide 2', + }, + { + id: '3', + index: 2, + name: 'Slide 3', + }, + ]) + + @computed getCurrentSlides() { + return this._slides.get().sort((a, b) => (a.index < b.index ? -1 : 1)) + } + + private _currentSlideId = atom('currentSlide', '1') + + @computed getCurrentSlideId() { + return this._currentSlideId.get() + } + + @computed getCurrentSlide() { + return this._slides.get().find((slide) => slide.id === this.getCurrentSlideId())! + } + + setCurrentSlide(id: string) { + this._currentSlideId.set(id) + } + + moveBy(delta: number) { + const slides = this.getCurrentSlides() + const currentIndex = slides.findIndex((slide) => slide.id === this.getCurrentSlideId()) + const next = slides[currentIndex + delta] + if (!next) return + this._currentSlideId.set(next.id) + } + + nextSlide() { + this.moveBy(1) + } + + prevSlide() { + this.moveBy(-1) + } + + newSlide(index: number) { + const slides = structuredClone(this.getCurrentSlides()) + + let bumping = false + for (const slide of slides) { + if (slide.index === index) { + bumping = true + } + if (bumping) { + slide.index++ + } + } + + const newSlide = { + id: uniqueId(), + index, + name: `Slide ${slides.length + 1}`, + } + + this._slides.set([...slides, newSlide]) + + return newSlide + } +} + +const slidesContext = createContext({} as SlidesManager) + +export const SlidesProvider = ({ children }: { children: ReactNode }) => { + const [slideManager] = useState(() => new SlidesManager()) + return {children} +} + +export function useSlides() { + return useContext(slidesContext) +} diff --git a/apps/examples/tsconfig.json b/apps/examples/tsconfig.json index 95d93668c..4d943aa74 100644 --- a/apps/examples/tsconfig.json +++ b/apps/examples/tsconfig.json @@ -3,7 +3,8 @@ "include": ["src", "e2e", "./vite.config.ts", "**/*.json"], "exclude": ["node_modules", "dist", "**/*.css", ".tsbuild*", "./scripts/legacy-translations"], "compilerOptions": { - "outDir": "./.tsbuild" + "outDir": "./.tsbuild", + "experimentalDecorators": true }, "references": [ { diff --git a/apps/examples/vite.config.ts b/apps/examples/vite.config.ts index 648787582..9bdce6d8b 100644 --- a/apps/examples/vite.config.ts +++ b/apps/examples/vite.config.ts @@ -1,9 +1,9 @@ -import react from '@vitejs/plugin-react' +import react from '@vitejs/plugin-react-swc' import path from 'path' import { PluginOption, defineConfig } from 'vite' export default defineConfig({ - plugins: [react(), exampleReadmePlugin()], + plugins: [react({ tsDecorators: true }), exampleReadmePlugin()], root: path.join(__dirname, 'src'), publicDir: path.join(__dirname, 'public'), build: { diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index 58e6d8ce6..1367f1294 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -899,7 +899,7 @@ export class Editor extends EventEmitter { sendBackward(shapes: TLShape[] | TLShapeId[]): this; sendToBack(shapes: TLShape[] | TLShapeId[]): this; setCamera(point: VecLike, opts?: TLCameraMoveOptions): this; - setCameraOptions(options: Partial, opts?: TLCameraMoveOptions): this; + setCameraOptions(options: Partial): this; setCroppingShape(shape: null | TLShape | TLShapeId): this; setCurrentPage(page: TLPage | TLPageId): this; setCurrentTool(id: string, info?: {}): this; diff --git a/packages/editor/editor.css b/packages/editor/editor.css index 23304a855..38418d761 100644 --- a/packages/editor/editor.css +++ b/packages/editor/editor.css @@ -28,6 +28,7 @@ --layer-canvas: 200; --layer-shapes: 300; --layer-overlays: 400; + --layer-in-front: 500; --layer-following-indicator: 1000; --layer-blocker: 10000; @@ -265,7 +266,8 @@ input, .tl-overlays { position: absolute; - inset: 0px; + top: 0px; + left: 0px; height: 100%; width: 100%; contain: strict; @@ -291,6 +293,17 @@ input, pointer-events: none; } +.tl-front { + z-index: 600; + position: absolute; + inset: 0px; + height: 100%; + width: 100%; + overflow: clip; + content-visibility: auto; + touch-action: none; + pointer-events: none; +} /* ------------------- Background ------------------- */ .tl-background__wrapper { diff --git a/packages/editor/src/lib/TldrawEditor.tsx b/packages/editor/src/lib/TldrawEditor.tsx index 94a3d587a..a099118a6 100644 --- a/packages/editor/src/lib/TldrawEditor.tsx +++ b/packages/editor/src/lib/TldrawEditor.tsx @@ -367,7 +367,22 @@ function Layout({ useFocusEvents(autoFocus) useOnMount(onMount) - return <>{children} + return ( + <> + {children} + + + ) +} + +function InFrontOfTheCanvasWrapper() { + const { InFrontOfTheCanvas } = useEditorComponents() + if (!InFrontOfTheCanvas) return null + return ( +
+ +
+ ) } function Crash({ crashingError }: { crashingError: unknown }): null { diff --git a/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx b/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx index b1dc651c1..d73a556f4 100644 --- a/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx +++ b/packages/editor/src/lib/components/default-components/DefaultCanvas.tsx @@ -169,7 +169,6 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
-
@@ -647,12 +646,6 @@ function OnTheCanvasWrapper() { return } -function InFrontOfTheCanvasWrapper() { - const { InFrontOfTheCanvas } = useEditorComponents() - if (!InFrontOfTheCanvas) return null - return -} - function MovingCameraHitTestBlocker() { const editor = useEditor() const cameraState = useValue('camera state', () => editor.getCameraState(), [editor]) diff --git a/packages/editor/src/lib/editor/Editor.ts b/packages/editor/src/lib/editor/Editor.ts index 5f7271c2f..b85d05399 100644 --- a/packages/editor/src/lib/editor/Editor.ts +++ b/packages/editor/src/lib/editor/Editor.ts @@ -2148,26 +2148,24 @@ export class Editor extends EventEmitter { } /** - * Set the camera options. + * Set the camera options. Changing the options won't immediately change the camera itself, so you may want to call `setCamera` after changing the options. * * @example * ```ts * editor.setCameraOptions(myCameraOptions) - * editor.setCameraOptions(myCameraOptions, { immediate: true, force: true, initial: false }) + * editor.setCamera(editor.getCamera()) * ``` * * @param options - The camera options to set. - * @param opts - The options for the change. * * @public */ - setCameraOptions(options: Partial, opts?: TLCameraMoveOptions) { + setCameraOptions(options: Partial) { const next = structuredClone({ - ...this.getCameraOptions(), + ...this._cameraOptions.__unsafe__getWithoutCapture(), ...options, }) if (next.zoomSteps?.length < 1) next.zoomSteps = [1] this._cameraOptions.set(next) - this.setCamera(this.getCamera(), opts) return this } @@ -2637,16 +2635,16 @@ export class Editor extends EventEmitter { bounds: BoxLike, opts?: { targetZoom?: number; inset?: number } & TLCameraMoveOptions ): this { - if (this.getCameraOptions().isLocked) return this + const cameraOptions = this._cameraOptions.__unsafe__getWithoutCapture() + if (cameraOptions.isLocked) return this const viewportScreenBounds = this.getViewportScreenBounds() const inset = opts?.inset ?? Math.min(256, viewportScreenBounds.width * 0.28) const baseZoom = this.getBaseZoom() - const { zoomSteps } = this.getCameraOptions() - const zoomMin = zoomSteps[0] - const zoomMax = last(zoomSteps)! + const zoomMin = cameraOptions.zoomSteps[0] + const zoomMax = last(cameraOptions.zoomSteps)! let zoom = clamp( Math.min( @@ -2701,19 +2699,13 @@ export class Editor extends EventEmitter { private _animateViewport(ms: number): void { if (!this._viewportAnimation) return - const cancelAnimation = () => { - this.off('tick', this._animateViewport) - this.off('stop-camera-animation', cancelAnimation) - this._viewportAnimation = null - } - - this.once('stop-camera-animation', cancelAnimation) - this._viewportAnimation.elapsed += ms const { elapsed, easing, duration, start, end } = this._viewportAnimation if (elapsed > duration) { + this.off('tick', this._animateViewport) + this._viewportAnimation = null this._setCamera(new Vec(-end.x, -end.y, this.getViewportScreenBounds().width / end.width)) return } @@ -2725,7 +2717,9 @@ export class Editor extends EventEmitter { const top = start.minY + (end.minY - start.minY) * t const right = start.maxX + (end.maxX - start.maxX) * t - this._setCamera(new Vec(-left, -top, this.getViewportScreenBounds().width / (right - left))) + this._setCamera(new Vec(-left, -top, this.getViewportScreenBounds().width / (right - left)), { + force: true, + }) } /** @internal */ @@ -2733,8 +2727,9 @@ export class Editor extends EventEmitter { targetViewportPage: Box, opts = { animation: DEFAULT_ANIMATION_OPTIONS } as TLCameraMoveOptions ) { - if (!opts.animation) return - const { duration = 0, easing = EASINGS.easeInOutCubic } = opts.animation + const { animation, ...rest } = opts + if (!animation) return + const { duration = 0, easing = EASINGS.easeInOutCubic } = animation const animationSpeed = this.user.getAnimationSpeed() const viewportPageBounds = this.getViewportPageBounds() @@ -2753,7 +2748,8 @@ export class Editor extends EventEmitter { -targetViewportPage.x, -targetViewportPage.y, this.getViewportScreenBounds().width / targetViewportPage.width - ) + ), + { ...rest } ) } @@ -2766,6 +2762,12 @@ export class Editor extends EventEmitter { end: targetViewportPage.clone(), } + // If we ever get a "stop-camera-animation" event, we stop + this.once('stop-camera-animation', () => { + this.off('tick', this._animateViewport) + this._viewportAnimation = null + }) + // On each tick, animate the viewport this.on('tick', this._animateViewport) diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts index 04520f284..d71c2dea2 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts @@ -56,6 +56,11 @@ export class Translating extends StateNode { ) => { const { isCreating = false, onCreate = () => void null } = info + if (!this.editor.getSelectedShapeIds()?.length) { + this.parent.transition('idle') + return + } + this.info = info this.parent.setCurrentToolIdMask(info.onInteractionEnd) this.isCreating = isCreating @@ -251,8 +256,17 @@ export class Translating extends StateNode { } } - protected handleChange() { - const { movingShapes } = this.snapshot + protected updateShapes() { + const { snapshot } = this + + this.dragAndDropManager.updateDroppingNode(snapshot.movingShapes, this.updateParentTransforms) + + moveShapesToPoint({ + editor: this.editor, + snapshot, + }) + + const { movingShapes } = snapshot const changes: TLShapePartial[] = [] @@ -270,18 +284,6 @@ export class Translating extends StateNode { } } - protected updateShapes() { - const { snapshot } = this - this.dragAndDropManager.updateDroppingNode(snapshot.movingShapes, this.updateParentTransforms) - - moveShapesToPoint({ - editor: this.editor, - snapshot, - }) - - this.handleChange() - } - protected updateParentTransforms = () => { const { editor, diff --git a/packages/tldraw/src/test/commands/setCamera.test.ts b/packages/tldraw/src/test/commands/setCamera.test.ts index 6db6592e7..6d3962591 100644 --- a/packages/tldraw/src/test/commands/setCamera.test.ts +++ b/packages/tldraw/src/test/commands/setCamera.test.ts @@ -361,8 +361,8 @@ describe('When constraints are contain', () => { describe('Zoom reset positions based on origin', () => { it('Default .5, .5 origin', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -370,17 +370,17 @@ describe('Zoom reset positions based on origin', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'default', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) + expect(editor.getCamera()).toMatchObject({ x: 200, y: 50, z: 1 }) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toMatchObject({ x: 200, y: 50, z: 1 }) }) it('0 0 origin', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -388,17 +388,17 @@ describe('Zoom reset positions based on origin', () => { origin: { x: 0, y: 0 }, initialZoom: 'default', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) + expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 }) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toMatchObject({ x: 0, y: 0, z: 1 }) }) it('1 1 origin', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -406,9 +406,9 @@ describe('Zoom reset positions based on origin', () => { origin: { x: 1, y: 1 }, initialZoom: 'default', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) + expect(editor.getCamera()).toMatchObject({ x: 400, y: 100, z: 1 }) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toMatchObject({ x: 400, y: 100, z: 1 }) @@ -417,8 +417,8 @@ describe('Zoom reset positions based on origin', () => { describe('CameraOptions.constraints.initialZoom + behavior', () => { it('When fit is default', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -426,17 +426,17 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'default', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) + expect(editor.getCamera()).toMatchObject({ x: 200, y: 50, z: 1 }) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toMatchObject({ x: 200, y: 50, z: 1 }) }) it('When fit is fit-max', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -444,17 +444,16 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // y should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 111.11, y: 0, z: 1.125 }, 2) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toCloselyMatchObject({ x: 111.11, y: 0, z: 1.125 }, 2) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -463,9 +462,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // y should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 666.66, y: 0, z: 0.75 }, 2) @@ -474,8 +472,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { // The proportions of the bounds don't matter, it's the proportion of the viewport that decides which axis gets fit editor.updateViewportScreenBounds(new Box(0, 0, 900, 1600)) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -483,9 +481,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) expect(editor.getCamera()).toCloselyMatchObject({ x: 0, y: 666.66, z: 0.75 }, 2) editor.zoomIn().resetZoom().forceTick() @@ -493,8 +490,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { }) it('When fit is fit-min', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -502,17 +499,16 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-min', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // x should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 0, y: -62.5, z: 1.333 }, 2) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toCloselyMatchObject({ x: 0, y: -62.5, z: 1.333 }, 2) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -521,9 +517,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-min', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // x should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 0, y: -375, z: 2 }, 2) @@ -532,8 +527,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { // The proportions of the bounds don't matter, it's the proportion of the viewport that decides which axis gets fit editor.updateViewportScreenBounds(new Box(0, 0, 900, 1600)) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -541,9 +536,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-min', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) expect(editor.getCamera()).toCloselyMatchObject({ x: -375, y: 0, z: 2 }, 2) editor.zoomIn().resetZoom().forceTick() @@ -553,8 +547,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { it('When fit is fit-min-100', () => { editor.updateViewportScreenBounds(new Box(0, 0, 1600, 900)) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -562,17 +556,16 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-min-100', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // Max 1 on initial / reset expect(editor.getCamera()).toCloselyMatchObject({ x: 200, y: 50, z: 1 }, 2) // Min is regular editor.updateViewportScreenBounds(new Box(0, 0, 800, 450)) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -580,9 +573,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { origin: { x: 0.5, y: 0.5 }, initialZoom: 'fit-min-100', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) expect(editor.getCamera()).toCloselyMatchObject({ x: 0, y: -62.5, z: 0.66 }, 2) }) @@ -590,8 +582,8 @@ describe('CameraOptions.constraints.initialZoom + behavior', () => { describe('Padding', () => { it('sets when padding is zero', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -600,9 +592,8 @@ describe('Padding', () => { padding: { x: 0, y: 0 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // y should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 111.11, y: 0, z: 1.125 }, 2) @@ -611,8 +602,8 @@ describe('Padding', () => { }) it('sets when padding is 100, 0', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -621,17 +612,16 @@ describe('Padding', () => { padding: { x: 100, y: 0 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // no change because the horizontal axis has extra space available expect(editor.getCamera()).toCloselyMatchObject({ x: 111.11, y: 0, z: 1.125 }, 2) editor.zoomIn().resetZoom().forceTick() expect(editor.getCamera()).toCloselyMatchObject({ x: 111.11, y: 0, z: 1.125 }, 2) - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -640,9 +630,8 @@ describe('Padding', () => { padding: { x: 200, y: 0 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true }) // now we're pinching expect(editor.getCamera()).toCloselyMatchObject({ x: 200, y: 50, z: 1 }, 2) @@ -651,8 +640,8 @@ describe('Padding', () => { }) it('sets when padding is 0 x 100', () => { - editor.setCameraOptions( - { + editor + .setCameraOptions({ ...DEFAULT_CAMERA_OPTIONS, constraints: { ...DEFAULT_CONSTRAINTS, @@ -661,9 +650,8 @@ describe('Padding', () => { padding: { x: 0, y: 100 }, initialZoom: 'fit-max', }, - }, - { reset: true } - ) + }) + .setCamera(editor.getCamera(), { reset: true, immediate: true }) // y should be 0 because the viewport width is bigger than the height expect(editor.getCamera()).toCloselyMatchObject({ x: 314.28, y: 114.28, z: 0.875 }, 2) diff --git a/packages/utils/api-report.md b/packages/utils/api-report.md index 961caae88..a88194d0e 100644 --- a/packages/utils/api-report.md +++ b/packages/utils/api-report.md @@ -97,22 +97,22 @@ export function getHashForObject(obj: any): string; export function getHashForString(string: string): string; // @public -export function getIndexAbove(below: IndexKey): IndexKey; +export function getIndexAbove(below?: IndexKey | undefined): IndexKey; // @public -export function getIndexBelow(above: IndexKey): IndexKey; +export function getIndexBelow(above?: IndexKey | undefined): IndexKey; // @public -export function getIndexBetween(below: IndexKey, above?: IndexKey): IndexKey; +export function getIndexBetween(below: IndexKey | undefined, above: IndexKey | undefined): IndexKey; // @public export function getIndices(n: number, start?: IndexKey): IndexKey[]; // @public -export function getIndicesAbove(below: IndexKey, n: number): IndexKey[]; +export function getIndicesAbove(below: IndexKey | undefined, n: number): IndexKey[]; // @public -export function getIndicesBelow(above: IndexKey, n: number): IndexKey[]; +export function getIndicesBelow(above: IndexKey | undefined, n: number): IndexKey[]; // @public export function getIndicesBetween(below: IndexKey | undefined, above: IndexKey | undefined, n: number): IndexKey[]; diff --git a/packages/utils/src/lib/reordering/reordering.ts b/packages/utils/src/lib/reordering/reordering.ts index 189dffc12..4bde8fed3 100644 --- a/packages/utils/src/lib/reordering/reordering.ts +++ b/packages/utils/src/lib/reordering/reordering.ts @@ -33,7 +33,7 @@ export function getIndicesBetween( * @param n - The number of indices to get. * @public */ -export function getIndicesAbove(below: IndexKey, n: number) { +export function getIndicesAbove(below: IndexKey | undefined, n: number) { return generateNKeysBetween(below, undefined, n) } @@ -43,7 +43,7 @@ export function getIndicesAbove(below: IndexKey, n: number) { * @param n - The number of indices to get. * @public */ -export function getIndicesBelow(above: IndexKey, n: number) { +export function getIndicesBelow(above: IndexKey | undefined, n: number) { return generateNKeysBetween(undefined, above, n) } @@ -53,7 +53,7 @@ export function getIndicesBelow(above: IndexKey, n: number) { * @param above - The index above. * @public */ -export function getIndexBetween(below: IndexKey, above?: IndexKey) { +export function getIndexBetween(below: IndexKey | undefined, above: IndexKey | undefined) { return generateNKeysBetween(below, above, 1)[0] } @@ -62,7 +62,7 @@ export function getIndexBetween(below: IndexKey, above?: IndexKey) { * @param below - The index below. * @public */ -export function getIndexAbove(below: IndexKey) { +export function getIndexAbove(below?: IndexKey | undefined) { return generateNKeysBetween(below, undefined, 1)[0] } @@ -71,7 +71,7 @@ export function getIndexAbove(below: IndexKey) { * @param above - The index above. * @public */ -export function getIndexBelow(above: IndexKey) { +export function getIndexBelow(above?: IndexKey | undefined) { return generateNKeysBetween(undefined, above, 1)[0] } diff --git a/templates/vite/package.json b/templates/vite/package.json index 9302d69d1..d43a18540 100644 --- a/templates/vite/package.json +++ b/templates/vite/package.json @@ -25,7 +25,7 @@ "@types/react-dom": "^18.0.11", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", - "@vitejs/plugin-react-swc": "^3.0.0", + "@vitejs/plugin-react-swc": "^3.6.0", "eslint": "^8.38.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.3.4", diff --git a/yarn.lock b/yarn.lock index 292b9c114..9857a1aee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -898,7 +898,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.6, @babel/core@npm:^7.20.7, @babel/core@npm:^7.23.5": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.6, @babel/core@npm:^7.20.7": version: 7.23.9 resolution: "@babel/core@npm:7.23.9" dependencies: @@ -1933,28 +1933,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-self@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 882bf56bc932d015c2d83214133939ddcf342e5bcafa21f1a93b19f2e052145115e1e0351730897fd66e5f67cad7875b8a8d81ceb12b6e2a886ad0102cb4eb1f - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-source@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 92287fb797e522d99bdc77eaa573ce79ff0ad9f1cf4e7df374645e28e51dce0adad129f6f075430b129b5bac8dad843f65021970e12e992d6d6671f0d65bb1e0 - languageName: node - linkType: hard - "@babel/plugin-transform-regenerator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-regenerator@npm:7.23.3" @@ -7164,91 +7142,91 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-darwin-arm64@npm:1.3.103" +"@swc/core-darwin-arm64@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-darwin-arm64@npm:1.4.17" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-darwin-x64@npm:1.3.103" +"@swc/core-darwin-x64@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-darwin-x64@npm:1.4.17" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.103" +"@swc/core-linux-arm-gnueabihf@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.17" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.103" +"@swc/core-linux-arm64-gnu@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-linux-arm64-gnu@npm:1.4.17" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.103" +"@swc/core-linux-arm64-musl@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-linux-arm64-musl@npm:1.4.17" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.103" +"@swc/core-linux-x64-gnu@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-linux-x64-gnu@npm:1.4.17" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-linux-x64-musl@npm:1.3.103" +"@swc/core-linux-x64-musl@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-linux-x64-musl@npm:1.4.17" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.103" +"@swc/core-win32-arm64-msvc@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-win32-arm64-msvc@npm:1.4.17" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.103" +"@swc/core-win32-ia32-msvc@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-win32-ia32-msvc@npm:1.4.17" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.103": - version: 1.3.103 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.103" +"@swc/core-win32-x64-msvc@npm:1.4.17": + version: 1.4.17 + resolution: "@swc/core-win32-x64-msvc@npm:1.4.17" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.55, @swc/core@npm:^1.3.96": - version: 1.3.103 - resolution: "@swc/core@npm:1.3.103" +"@swc/core@npm:^1.3.107, @swc/core@npm:^1.3.55": + version: 1.4.17 + resolution: "@swc/core@npm:1.4.17" dependencies: - "@swc/core-darwin-arm64": "npm:1.3.103" - "@swc/core-darwin-x64": "npm:1.3.103" - "@swc/core-linux-arm-gnueabihf": "npm:1.3.103" - "@swc/core-linux-arm64-gnu": "npm:1.3.103" - "@swc/core-linux-arm64-musl": "npm:1.3.103" - "@swc/core-linux-x64-gnu": "npm:1.3.103" - "@swc/core-linux-x64-musl": "npm:1.3.103" - "@swc/core-win32-arm64-msvc": "npm:1.3.103" - "@swc/core-win32-ia32-msvc": "npm:1.3.103" - "@swc/core-win32-x64-msvc": "npm:1.3.103" - "@swc/counter": "npm:^0.1.1" + "@swc/core-darwin-arm64": "npm:1.4.17" + "@swc/core-darwin-x64": "npm:1.4.17" + "@swc/core-linux-arm-gnueabihf": "npm:1.4.17" + "@swc/core-linux-arm64-gnu": "npm:1.4.17" + "@swc/core-linux-arm64-musl": "npm:1.4.17" + "@swc/core-linux-x64-gnu": "npm:1.4.17" + "@swc/core-linux-x64-musl": "npm:1.4.17" + "@swc/core-win32-arm64-msvc": "npm:1.4.17" + "@swc/core-win32-ia32-msvc": "npm:1.4.17" + "@swc/core-win32-x64-msvc": "npm:1.4.17" + "@swc/counter": "npm:^0.1.2" "@swc/types": "npm:^0.1.5" peerDependencies: "@swc/helpers": ^0.5.0 @@ -7276,14 +7254,14 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 65eff8264dfd73088b226091fc53d5242a8c9576caa76b27a91eeb30714a245ee4c92093ede50c3621dbd99315ca213e3d76ea73208eeacd3e4d0c1f32815309 + checksum: 743da3648335b10901f9c2d6c7b332f90913f9ce0e09c040eb9b5cce71dde4e1c9dd6c78c05700433ffc173194f7857c5e0a6146c39ec4bf392f875397ed96d3 languageName: node linkType: hard -"@swc/counter@npm:^0.1.1": - version: 0.1.2 - resolution: "@swc/counter@npm:0.1.2" - checksum: 8427c594f1f0cf44b83885e9c8fe1e370c9db44ae96e07a37c117a6260ee97797d0709483efbcc244e77bac578690215f45b23254c4cd8a70fb25ddbb50bf33e +"@swc/counter@npm:^0.1.2": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 languageName: node linkType: hard @@ -7830,7 +7808,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.5": +"@types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -8996,29 +8974,14 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react-swc@npm:^3.5.0": - version: 3.5.0 - resolution: "@vitejs/plugin-react-swc@npm:3.5.0" +"@vitejs/plugin-react-swc@npm:^3.6.0": + version: 3.6.0 + resolution: "@vitejs/plugin-react-swc@npm:3.6.0" dependencies: - "@swc/core": "npm:^1.3.96" + "@swc/core": "npm:^1.3.107" peerDependencies: vite: ^4 || ^5 - checksum: ca3315e2000303aa6da35b6bedc3a5c57550c5576dfa12e12d097a2f69f8c7bc68e6ce7a068685ae13fcbe121d43c133b47a0d4637ac58e366471dd6645bf8ac - languageName: node - linkType: hard - -"@vitejs/plugin-react@npm:^4.2.0": - version: 4.2.1 - resolution: "@vitejs/plugin-react@npm:4.2.1" - dependencies: - "@babel/core": "npm:^7.23.5" - "@babel/plugin-transform-react-jsx-self": "npm:^7.23.3" - "@babel/plugin-transform-react-jsx-source": "npm:^7.23.3" - "@types/babel__core": "npm:^7.20.5" - react-refresh: "npm:^0.14.0" - peerDependencies: - vite: ^4.2.0 || ^5.0.0 - checksum: d7fa6dacd3c246bcee482ff4b7037b2978b6ca002b79780ad4921e91ae4bc85ab234cfb94f8d4d825fed8488a0acdda2ff02b47c27b3055187c0727b18fc725e + checksum: 8bff5065e9689d0b0405932b5f2483bd0c388812dc13219a1511023f7eaca7a53c43f75f3eae785e27f7ce5a60e99d5d32bac4845a63ab095d5562180f7efa7c languageName: node linkType: hard @@ -11934,7 +11897,7 @@ __metadata: "@types/react": "npm:^18.2.47" "@typescript-eslint/utils": "npm:^5.59.0" "@vercel/analytics": "npm:^1.1.1" - "@vitejs/plugin-react-swc": "npm:^3.5.0" + "@vitejs/plugin-react-swc": "npm:^3.6.0" browser-fs-access: "npm:^0.35.0" dotenv: "npm:^16.3.1" eslint: "npm:^8.37.0" @@ -13628,7 +13591,7 @@ __metadata: "@tldraw/assets": "workspace:*" "@types/lodash": "npm:^4.14.188" "@vercel/analytics": "npm:^1.1.1" - "@vitejs/plugin-react": "npm:^4.2.0" + "@vitejs/plugin-react-swc": "npm:^3.6.0" classnames: "npm:^2.3.2" dotenv: "npm:^16.3.1" lazyrepo: "npm:0.0.0-alpha.27"