├── .changeset ├── README.md └── config.json ├── .devcontainer ├── Dockerfile ├── base.Dockerfile └── devcontainer.json ├── .eslintignore ├── .eslintrc ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation.md │ ├── feature.md │ └── testing.md └── workflows │ └── main.yml ├── .gitignore ├── .husky ├── pre-commit └── pre-push ├── .ignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json ├── settings.json ├── snippets.code-snippets └── tasks.json ├── .yarn └── releases │ └── yarn-1.18.0.cjs ├── .yarnrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── GETTING-STARTED.md ├── LICENSE ├── LICENSE.md ├── Quickpose.code-workspace ├── README.md ├── apps ├── vscode │ ├── README.md │ ├── editor │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── package.json │ │ ├── scripts │ │ │ ├── build.mjs │ │ │ └── dev.mjs │ │ ├── src │ │ │ ├── app.tsx │ │ │ ├── index.tsx │ │ │ ├── public │ │ │ │ ├── index.css │ │ │ │ ├── index.html │ │ │ │ └── tldraw-assets.json │ │ │ ├── types.ts │ │ │ └── utils │ │ │ │ ├── defaultDocument.ts │ │ │ │ ├── export.ts │ │ │ │ └── vscode.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.tsbuildinfo │ │ └── yarn.lock │ └── extension │ │ ├── .gitignore │ │ ├── .vscode │ │ ├── extensions.json │ │ ├── launch.json │ │ └── settings.json │ │ ├── .vscodeignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── apps │ │ └── vscode │ │ │ └── extension │ │ ├── assets │ │ ├── recording.gif │ │ └── screenshot.png │ │ ├── examples │ │ ├── 1.tldr │ │ ├── 2.tldr │ │ └── 3.tldr │ │ ├── icon.png │ │ ├── package.json │ │ ├── scripts │ │ ├── build.js │ │ ├── dev.js │ │ └── package.js │ │ ├── src │ │ ├── TldrawEditorProvider.ts │ │ ├── TldrawWebviewManager.ts │ │ ├── extension.ts │ │ ├── types.ts │ │ └── utils.ts │ │ ├── tsconfig.json │ │ └── yarn.lock └── www │ ├── .eslintrc.json │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── components │ ├── BetaNotification.tsx │ ├── Editor.tsx │ ├── IFrameWarning.tsx │ ├── MultiplayerEditor.tsx │ ├── ReadOnlyMultiplayerEditor.tsx │ └── StudyConsentPopup.tsx │ ├── faviconData.json │ ├── faviconDescription.json │ ├── hooks │ ├── useMultiplayerAssets.ts │ ├── useMultiplayerState.ts │ ├── useReadOnlyMultiplayerState.ts │ └── useUploadAssets.ts │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── api │ │ └── create.ts │ ├── index.tsx │ ├── r │ │ ├── [id].tsx │ │ └── index.tsx │ └── v │ │ └── [id].tsx │ ├── public │ ├── android-chrome-144x144.png │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── android-chrome-36x36.png │ ├── android-chrome-384x384.png │ ├── android-chrome-48x48.png │ ├── android-chrome-72x72.png │ ├── android-chrome-96x96.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── manifest.json │ ├── mstile-150x150.png │ ├── mstile-310x310.png │ ├── quickpose-banner-black.png │ ├── quickpose-banner-grad.png │ ├── quickpose_flat.png │ ├── quickpose_logo_main.png │ ├── safari-pinned-tab.svg │ ├── site.webmanifest │ ├── social-image.png │ └── tldraw-assets.json │ ├── styles │ ├── globals.css │ ├── index.ts │ └── stitches.config.ts │ ├── tsconfig.json │ ├── types.ts │ ├── utils │ ├── export.ts │ ├── github.ts │ ├── gtag.ts │ ├── liveblocks.ts │ ├── quickPoseNetworking.tsx │ ├── quickPoseTypes.tsx │ ├── quickposeDrawing.tsx │ └── useGtag.ts │ └── worker │ └── index.js ├── assets ├── export1.gif ├── export2.gif ├── fork.gif ├── linkedstate.gif ├── navigate.gif ├── quickpose-banner-black.png ├── quickpose-banner-grad.png ├── quickpose-social.png ├── quickpose_flat.png ├── quickpose_logo_main copy.png ├── quickpose_logo_main.png ├── sentry.svg └── stickies.gif ├── examples ├── core-example-advanced │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── card-repo.png │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.tsx │ │ ├── components │ │ │ ├── TitleLinks.tsx │ │ │ └── Toolbar.tsx │ │ ├── main.tsx │ │ ├── shapes │ │ │ ├── CustomShapeUtil.ts │ │ │ ├── arrow │ │ │ │ ├── ArrowComponent.tsx │ │ │ │ ├── ArrowIndicator.tsx │ │ │ │ ├── ArrowShape.ts │ │ │ │ ├── ArrowUtil.ts │ │ │ │ └── index.ts │ │ │ ├── box │ │ │ │ ├── BoxComponent.tsx │ │ │ │ ├── BoxIndicator.tsx │ │ │ │ ├── BoxShape.ts │ │ │ │ ├── BoxUtil.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── pencil │ │ │ │ ├── PencilComponent.tsx │ │ │ │ ├── PencilShape.ts │ │ │ │ ├── PencilUtil.ts │ │ │ │ ├── PenclIndicator.tsx │ │ │ │ ├── index.ts │ │ │ │ └── pencil-helpers.ts │ │ ├── state │ │ │ ├── actions │ │ │ │ ├── bindings │ │ │ │ │ ├── createBindings.ts │ │ │ │ │ ├── deleteBindings.ts │ │ │ │ │ ├── getBoundHandlePoint.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── removePartialBindings.ts │ │ │ │ │ ├── updateBindings.ts │ │ │ │ │ └── updateBoundShapes.ts │ │ │ │ ├── camera │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── panCamera.ts │ │ │ │ │ ├── pinchCamera.ts │ │ │ │ │ ├── zoomIn.ts │ │ │ │ │ ├── zoomOut.ts │ │ │ │ │ ├── zoomToFit.ts │ │ │ │ │ └── zoomToSelection.ts │ │ │ │ ├── data │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loadDocument.ts │ │ │ │ │ ├── loadNewDocument.ts │ │ │ │ │ └── restoreSavedDocument.ts │ │ │ │ ├── erase │ │ │ │ │ ├── eraseGhostShapes.ts │ │ │ │ │ ├── eraseShapes.ts │ │ │ │ │ ├── eraseShapesAtPoint.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── handles │ │ │ │ │ ├── clearPointedHandle.ts │ │ │ │ │ ├── getBoundTarget.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── setPointedHandle.ts │ │ │ │ │ └── translateHandle.ts │ │ │ │ ├── history │ │ │ │ │ ├── addToHistory.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── redo.ts │ │ │ │ │ └── undo.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mutables │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── restoreSnapshot.ts │ │ │ │ │ ├── setInitialPoint.ts │ │ │ │ │ ├── setSnapshot.ts │ │ │ │ │ ├── setViewport.ts │ │ │ │ │ └── updatePointer.ts │ │ │ │ ├── performance │ │ │ │ │ ├── clearPerformanceMode.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── setTransformPerformanceMode.ts │ │ │ │ │ └── setTranslatePerformanceMode.ts │ │ │ │ ├── selection │ │ │ │ │ ├── clearBrush.ts │ │ │ │ │ ├── clearHoveredShape.ts │ │ │ │ │ ├── clearPointedShape.ts │ │ │ │ │ ├── deselectAllShapes.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── selectAllShapes.ts │ │ │ │ │ ├── selectShape.ts │ │ │ │ │ ├── setHoveredShape.ts │ │ │ │ │ └── updateBrush.ts │ │ │ │ ├── shapes │ │ │ │ │ ├── createArrowShape.ts │ │ │ │ │ ├── createBoxShape.ts │ │ │ │ │ ├── createPencilShape.ts │ │ │ │ │ ├── createShapes.ts │ │ │ │ │ ├── deleteSelectedShapes.ts │ │ │ │ │ ├── deleteShapes.ts │ │ │ │ │ ├── extendPencilShape.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── updateShapes.ts │ │ │ │ ├── snapping │ │ │ │ │ └── clearSnapLines.ts │ │ │ │ ├── snaps │ │ │ │ │ ├── clearSnapInfo.ts │ │ │ │ │ ├── clearSnapLines.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── setSnapInfo.ts │ │ │ │ ├── transform │ │ │ │ │ ├── clearPointedBoundsHandle.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── resizeSelectedShapes.ts │ │ │ │ │ ├── rotateSelectedShapes.ts │ │ │ │ │ ├── setInitialCommonBounds.ts │ │ │ │ │ ├── setPointedBoundsHandle.ts │ │ │ │ │ └── transformSelectedShapes.ts │ │ │ │ └── translate │ │ │ │ │ ├── clearIsCloning.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── translateSelectedShapes.ts │ │ │ ├── api.ts │ │ │ ├── constants.ts │ │ │ ├── helpers.ts │ │ │ ├── history.ts │ │ │ ├── machine.ts │ │ │ └── mutables.ts │ │ ├── stitches.config.ts │ │ ├── styles.css │ │ ├── types.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── core-example │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── card-repo.png │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.tsx │ │ ├── main.tsx │ │ ├── shapes │ │ │ ├── index.ts │ │ │ └── rect │ │ │ │ ├── RectComponent.tsx │ │ │ │ ├── RectIndicator.tsx │ │ │ │ ├── RectShape.ts │ │ │ │ ├── RectUtil.ts │ │ │ │ └── index.ts │ │ ├── styles.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── tldraw-example │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── card-repo.png │ ├── index.html │ ├── package.json │ ├── public │ ├── Example.tldr │ ├── card-repo.png │ ├── favicon.ico │ └── tldraw-assets.json │ ├── src │ ├── App.tsx │ ├── api-control.tsx │ ├── api.tsx │ ├── basic.tsx │ ├── changing-id.tsx │ ├── core-stuff │ │ └── index.tsx │ ├── custom-cursors-core.tsx │ ├── custom-cursors.tsx │ ├── dark-mode.tsx │ ├── develop.tsx │ ├── embedded.tsx │ ├── export-to-server.tsx │ ├── export.tsx │ ├── file-system.tsx │ ├── iframe.tsx │ ├── loading-files.tsx │ ├── main.tsx │ ├── multiplayer │ │ ├── index.ts │ │ ├── liveblocks.config.ts │ │ ├── multiplayer.tsx │ │ └── useMultiplayerState.ts │ ├── no-size-embedded.tsx │ ├── persisted.tsx │ ├── props-control.tsx │ ├── readonly.tsx │ ├── scroll.tsx │ ├── styles.css │ ├── ui-options.tsx │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── guides ├── development.md ├── documentation.md ├── publishing.md └── translation.md ├── package.json ├── packages ├── core │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── TLShapeUtil │ │ │ ├── TLShapeUtil.spec.tsx │ │ │ ├── TLShapeUtil.tsx │ │ │ └── index.ts │ │ ├── components │ │ │ ├── Binding │ │ │ │ ├── Binding.test.tsx │ │ │ │ ├── Binding.tsx │ │ │ │ └── index.ts │ │ │ ├── Bounds │ │ │ │ ├── Bounds.tsx │ │ │ │ ├── BoundsBg.tsx │ │ │ │ ├── CenterHandle.tsx │ │ │ │ ├── CloneButton.tsx │ │ │ │ ├── CloneButtons.tsx │ │ │ │ ├── CornerHandle.tsx │ │ │ │ ├── EdgeHandle.tsx │ │ │ │ ├── LinkHandle.tsx │ │ │ │ ├── RotateHandle.tsx │ │ │ │ ├── __tests__ │ │ │ │ │ ├── Bounds.test.tsx │ │ │ │ │ ├── BoundsBg.test.tsx │ │ │ │ │ ├── CenterHandle.test.tsx │ │ │ │ │ ├── CloneButton.test.tsx │ │ │ │ │ ├── CornerHandle.test.tsx │ │ │ │ │ ├── EdgeHandle.test.tsx │ │ │ │ │ ├── LinkHandle.test.tsx │ │ │ │ │ └── RotateHandle.test.tsx │ │ │ │ └── index.ts │ │ │ ├── Brush │ │ │ │ ├── Brush.test.tsx │ │ │ │ ├── Brush.tsx │ │ │ │ └── index.ts │ │ │ ├── Canvas │ │ │ │ ├── Canvas.test.tsx │ │ │ │ ├── Canvas.tsx │ │ │ │ └── index.ts │ │ │ ├── Container │ │ │ │ ├── Container.tsx │ │ │ │ └── index.ts │ │ │ ├── Cursor │ │ │ │ ├── Cursor.tsx │ │ │ │ └── index.ts │ │ │ ├── EraseLine │ │ │ │ ├── EraseLine.tsx │ │ │ │ └── index.ts │ │ │ ├── Grid │ │ │ │ ├── Grid.tsx │ │ │ │ └── index.ts │ │ │ ├── HTMLContainer │ │ │ │ ├── HTMLContainer.tsx │ │ │ │ └── index.ts │ │ │ ├── Handles │ │ │ │ ├── Handle.test.tsx │ │ │ │ ├── Handle.tsx │ │ │ │ ├── Handles.test.tsx │ │ │ │ ├── Handles.tsx │ │ │ │ └── index.ts │ │ │ ├── Overlay │ │ │ │ ├── Overlay.tsx │ │ │ │ └── index.ts │ │ │ ├── Page │ │ │ │ ├── Page.test.tsx │ │ │ │ ├── Page.tsx │ │ │ │ └── index.ts │ │ │ ├── Renderer │ │ │ │ ├── Renderer.test.tsx │ │ │ │ ├── Renderer.tsx │ │ │ │ └── index.tsx │ │ │ ├── SVGContainer │ │ │ │ ├── SVGContainer.tsx │ │ │ │ └── index.ts │ │ │ ├── Shape │ │ │ │ ├── RenderedShape.tsx │ │ │ │ ├── Shape.test.tsx │ │ │ │ ├── Shape.tsx │ │ │ │ ├── ShapeNode.tsx │ │ │ │ └── index.ts │ │ │ ├── ShapeIndicator │ │ │ │ ├── ShapeIndicator.test.tsx │ │ │ │ ├── ShapeIndicator.tsx │ │ │ │ └── index.ts │ │ │ ├── SnapLines │ │ │ │ ├── SnapLines.tsx │ │ │ │ └── index.ts │ │ │ ├── User │ │ │ │ ├── User.tsx │ │ │ │ └── index.ts │ │ │ ├── Users │ │ │ │ ├── Users.tsx │ │ │ │ └── index.ts │ │ │ ├── UsersIndicators │ │ │ │ ├── UsersIndicators.tsx │ │ │ │ └── index.ts │ │ │ └── index.tsx │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useBoundsEvents.tsx │ │ │ ├── useBoundsHandleEvents.tsx │ │ │ ├── useCameraCss.tsx │ │ │ ├── useCanvasEvents.tsx │ │ │ ├── useHandleEvents.tsx │ │ │ ├── useHandles.ts │ │ │ ├── useKeyEvents.ts │ │ │ ├── usePerformanceCss.ts │ │ │ ├── usePosition.ts │ │ │ ├── usePreventNavigationCss.tsx │ │ │ ├── useResizeObserver.ts │ │ │ ├── useSafariFocusOutFix.tsx │ │ │ ├── useSelection.tsx │ │ │ ├── useShapeEvents.tsx │ │ │ ├── useShapeTree.tsx │ │ │ ├── useStyle.tsx │ │ │ ├── useTLContext.tsx │ │ │ └── useZoomEvents.ts │ │ ├── index.ts │ │ ├── inputs.ts │ │ ├── test │ │ │ ├── ContextWrapper.tsx │ │ │ ├── index.ts │ │ │ ├── mockDocument.ts │ │ │ ├── mockUtils.tsx │ │ │ ├── renderWithContext.tsx │ │ │ └── renderWithSvg.tsx │ │ ├── types.ts │ │ └── utils │ │ │ ├── index.ts │ │ │ ├── polyfills.ts │ │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.dev.json │ └── tsconfig.json ├── curve │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.dev.json │ └── tsconfig.json ├── intersect │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.dev.json │ └── tsconfig.json ├── tldraw │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── Tldraw.spec.tsx │ │ ├── Tldraw.tsx │ │ ├── components │ │ │ ├── ContextMenu │ │ │ │ ├── ContextMenu.test.tsx │ │ │ │ ├── ContextMenu.tsx │ │ │ │ └── index.ts │ │ │ ├── ErrorFallback │ │ │ │ ├── ErrorFallback.tsx │ │ │ │ └── index.ts │ │ │ ├── FocusButton │ │ │ │ ├── FocusButton.tsx │ │ │ │ └── index.ts │ │ │ ├── Loading │ │ │ │ ├── Loading.tsx │ │ │ │ └── index.ts │ │ │ ├── Primitives │ │ │ │ ├── AlertDialog │ │ │ │ │ ├── AlertDialog.tsx │ │ │ │ │ ├── FilenameDialog.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Divider │ │ │ │ │ ├── Divider.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── DropdownMenu │ │ │ │ │ ├── DMCheckboxItem.tsx │ │ │ │ │ ├── DMContent.tsx │ │ │ │ │ ├── DMDivider.tsx │ │ │ │ │ ├── DMItem.tsx │ │ │ │ │ ├── DMRadioItem.tsx │ │ │ │ │ ├── DMSubMenu.tsx │ │ │ │ │ ├── DMTriggerIcon.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── IconButton │ │ │ │ │ ├── IconButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Kbd │ │ │ │ │ ├── Kbd.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── MenuContent │ │ │ │ │ ├── MenuContent.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Panel │ │ │ │ │ ├── Panel.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── RowButton │ │ │ │ │ ├── RowButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SmallIcon │ │ │ │ │ ├── SmallIcon.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TextField │ │ │ │ │ ├── TextField.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ToolButton │ │ │ │ │ ├── ToolButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Tooltip │ │ │ │ │ ├── Tooltip.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── icons │ │ │ │ │ ├── BoxIcon.tsx │ │ │ │ │ ├── CircleIcon.tsx │ │ │ │ │ ├── DashDashedIcon.tsx │ │ │ │ │ ├── DashDottedIcon.tsx │ │ │ │ │ ├── DashDrawIcon.tsx │ │ │ │ │ ├── DashSolidIcon.tsx │ │ │ │ │ ├── DiscordIcon.tsx │ │ │ │ │ ├── EraserIcon.tsx │ │ │ │ │ ├── LineIcon.tsx │ │ │ │ │ ├── MultiplayerIcon2.tsx │ │ │ │ │ ├── SizeLargeIcon.tsx │ │ │ │ │ ├── SizeMediumIcon.tsx │ │ │ │ │ ├── SizeSmallIcon.tsx │ │ │ │ │ ├── TrashIcon.tsx │ │ │ │ │ ├── UndoIcon.tsx │ │ │ │ │ └── index.ts │ │ │ ├── ToolsPanel │ │ │ │ ├── ActionButton.tsx │ │ │ │ ├── BackToContent.tsx │ │ │ │ ├── DeleteButton.tsx │ │ │ │ ├── HelpPanel.tsx │ │ │ │ ├── KeyboardShortcutDialog.tsx │ │ │ │ ├── LockButton.tsx │ │ │ │ ├── PrimaryTools.tsx │ │ │ │ ├── ShapesMenu.tsx │ │ │ │ ├── StatusBar.tsx │ │ │ │ ├── ToolsPanel.test.tsx │ │ │ │ ├── ToolsPanel.tsx │ │ │ │ └── index.ts │ │ │ ├── TopPanel │ │ │ │ ├── CurrentVersionMenu │ │ │ │ │ ├── CurrentVersionMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── LanguageMenu │ │ │ │ │ └── LanguageMenu.tsx │ │ │ │ ├── Menu │ │ │ │ │ ├── Menu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── MultiplayerMenu │ │ │ │ │ ├── MultiplayerMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── PageMenu │ │ │ │ │ ├── PageMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── PageOptionsDialog │ │ │ │ │ ├── PageOptionsDialog.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── PreferencesMenu │ │ │ │ │ ├── PreferencesMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── StyleMenu │ │ │ │ │ ├── StyleMenu.test.tsx │ │ │ │ │ ├── StyleMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TopPanel.tsx │ │ │ │ ├── ZoomMenu │ │ │ │ │ ├── ZoomMenu.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── breakpoints.tsx │ │ │ ├── preventEvent.ts │ │ │ └── stopPropagation.ts │ │ ├── constants.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useCursor.ts │ │ │ ├── useDialog.ts │ │ │ ├── useFileSystem.ts │ │ │ ├── useFileSystemHandlers.ts │ │ │ ├── useKeyboardShortcuts.tsx │ │ │ ├── useTheme.ts │ │ │ ├── useTldrawApp.tsx │ │ │ └── useTranslation.ts │ │ ├── index.ts │ │ ├── state │ │ │ ├── IdbClipboard.ts │ │ │ ├── StateManager │ │ │ │ ├── StateManager.ts │ │ │ │ ├── copy.ts │ │ │ │ └── index.ts │ │ │ ├── TLDR.ts │ │ │ ├── TldrawApp.spec.ts │ │ │ ├── TldrawApp.ts │ │ │ ├── __snapshots__ │ │ │ │ └── TldrawApp.spec.ts.snap │ │ │ ├── commands │ │ │ │ ├── alignShapes │ │ │ │ │ ├── alignShapes.spec.ts │ │ │ │ │ ├── alignShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── changePage │ │ │ │ │ ├── changePage.spec.ts │ │ │ │ │ ├── changePage.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── createPage │ │ │ │ │ ├── createPage.spec.ts │ │ │ │ │ ├── createPage.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── createShapes │ │ │ │ │ ├── createShapes.spec.ts │ │ │ │ │ ├── createShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── deletePage │ │ │ │ │ ├── deletePage.spec.ts │ │ │ │ │ ├── deletePage.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── deleteShapes │ │ │ │ │ ├── deleteShapes.spec.ts │ │ │ │ │ ├── deleteShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── distributeShapes │ │ │ │ │ ├── distributeShapes.spec.ts │ │ │ │ │ ├── distributeShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── duplicatePage │ │ │ │ │ ├── duplicatePage.spec.ts │ │ │ │ │ ├── duplicatePage.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── duplicateShapes │ │ │ │ │ ├── duplicateShapes.spec.ts │ │ │ │ │ ├── duplicateShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── flipShapes │ │ │ │ │ ├── flipShapes.spec.ts │ │ │ │ │ ├── flipShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── groupShapes │ │ │ │ │ ├── groupShapes.spec.ts │ │ │ │ │ ├── groupShapes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── insertContent │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── insertContent.spec.ts │ │ │ │ │ └── insertContent.ts │ │ │ │ ├── movePage │ │ │ │ │ ├── index.ts │ │ │ │ │ └── movePage.ts │ │ │ │ ├── moveShapesToPage │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── moveShapesToPage.spec.ts │ │ │ │ │ └── moveShapesToPage.ts │ │ │ │ ├── renamePage │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── renamePage.spec.ts │ │ │ │ │ └── renamePage.ts │ │ │ │ ├── reorderShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── reorderShapes.spec.ts │ │ │ │ │ └── reorderShapes.ts │ │ │ │ ├── resetBounds │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── resetBounds.spec.ts │ │ │ │ │ └── resetBounds.ts │ │ │ │ ├── rotateShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── rotateShapes.spec.ts │ │ │ │ │ └── rotateShapes.ts │ │ │ │ ├── setShapesProps │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── setShapesProps.spec.ts │ │ │ │ │ └── setShapesProps.ts │ │ │ │ ├── shared │ │ │ │ │ ├── getIncrementedName.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── removeShapesFromPage.ts │ │ │ │ ├── stretchShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stretchShapes.spec.ts │ │ │ │ │ └── stretchShapes.ts │ │ │ │ ├── styleShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── styleShapes.spec.ts │ │ │ │ │ └── styleShapes.ts │ │ │ │ ├── toggleShapesDecoration │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── toggleShapesDecoration.spec.ts │ │ │ │ │ └── toggleShapesDecoration.ts │ │ │ │ ├── toggleShapesProp │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── toggleShapesProp.spec.ts │ │ │ │ │ └── toggleShapesProp.ts │ │ │ │ ├── translateShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── translateShapes.spec.ts │ │ │ │ │ └── translateShapes.ts │ │ │ │ ├── ungroupShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── ungroupShapes.spec.ts │ │ │ │ │ └── ungroupShapes.ts │ │ │ │ └── updateShapes │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── updateShapes.spec.ts │ │ │ │ │ └── updateShapes.ts │ │ │ ├── data │ │ │ │ ├── filesystem.spec.ts │ │ │ │ ├── filesystem.ts │ │ │ │ ├── index.ts │ │ │ │ ├── migrate.spec.ts │ │ │ │ └── migrate.ts │ │ │ ├── index.ts │ │ │ ├── internal.ts │ │ │ ├── sessions │ │ │ │ ├── ArrowSession │ │ │ │ │ ├── ArrowSession.spec.ts │ │ │ │ │ ├── ArrowSession.ts │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── ArrowSession.spec.ts.snap │ │ │ │ │ ├── arrows.tldr │ │ │ │ │ └── index.ts │ │ │ │ ├── BaseSession.ts │ │ │ │ ├── BrushSession │ │ │ │ │ ├── BrushSession.spec.ts │ │ │ │ │ ├── BrushSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── DrawSession │ │ │ │ │ ├── DrawSession.spec.ts │ │ │ │ │ ├── DrawSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── EditSession │ │ │ │ │ ├── EditSession.spec.ts │ │ │ │ │ ├── EditSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── EraseSession │ │ │ │ │ ├── EraseSession.spec.ts │ │ │ │ │ ├── EraseSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── GridSession │ │ │ │ │ ├── GridSession.spec.ts │ │ │ │ │ ├── GridSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── HandleSession │ │ │ │ │ ├── HandleSession.spec.ts │ │ │ │ │ ├── HandleSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── RotateSession │ │ │ │ │ ├── RotateSession.spec.ts │ │ │ │ │ ├── RotateSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── TransformSession │ │ │ │ │ ├── TransformSession.spec.ts │ │ │ │ │ ├── TransformSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── TransformSingleSession │ │ │ │ │ ├── TransformSingleSession.spec.ts │ │ │ │ │ ├── TransformSingleSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── TranslateLabelSession │ │ │ │ │ ├── TranslateLabelSession.spec.ts │ │ │ │ │ ├── TranslateLabelSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── TranslateSession │ │ │ │ │ ├── TranslateSession.spec.ts │ │ │ │ │ ├── TranslateSession.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── about-sessions.md │ │ │ │ └── index.ts │ │ │ ├── shapes │ │ │ │ ├── ArrowUtil │ │ │ │ │ ├── ArrowUtil.spec.tsx │ │ │ │ │ ├── ArrowUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── ArrowUtil.spec.tsx.snap │ │ │ │ │ ├── arrowHelpers.ts │ │ │ │ │ ├── components │ │ │ │ │ │ ├── ArrowHead.tsx │ │ │ │ │ │ ├── CurvedArrow.tsx.tsx │ │ │ │ │ │ └── StraightArrow.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── DrawUtil │ │ │ │ │ ├── DrawUtil.spec.tsx │ │ │ │ │ ├── DrawUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── DrawUtil.spec.tsx.snap │ │ │ │ │ ├── drawHelpers.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── EllipseUtil │ │ │ │ │ ├── EllipseUtil.spec.tsx │ │ │ │ │ ├── EllipseUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── EllipseUtil.spec.tsx.snap │ │ │ │ │ ├── components │ │ │ │ │ │ ├── DashedEllipse.tsx │ │ │ │ │ │ └── DrawEllipse.tsx │ │ │ │ │ ├── ellipseHelpers.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── GroupUtil │ │ │ │ │ ├── GroupUtil.spec.tsx │ │ │ │ │ ├── GroupUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── GroupUtil.spec.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── IFrameUtil │ │ │ │ │ ├── IFrameUtil.tsx │ │ │ │ │ ├── ImageUtil.spec.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── ImageUtil.spec.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── ImageUtil │ │ │ │ │ ├── ImageUtil.spec.tsx │ │ │ │ │ ├── ImageUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── ImageUtil.spec.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── RectangleUtil │ │ │ │ │ ├── RectangleUtil.spec.tsx │ │ │ │ │ ├── RectangleUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── RectangleUtil.spec.tsx.snap │ │ │ │ │ ├── components │ │ │ │ │ │ ├── BindingIndicator.tsx │ │ │ │ │ │ ├── DashedRectangle.tsx │ │ │ │ │ │ └── DrawRectangle.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── rectangleHelpers.ts │ │ │ │ ├── StickyUtil │ │ │ │ │ ├── StickyUtil.spec.tsx │ │ │ │ │ ├── StickyUtil.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TDShapeUtil.tsx │ │ │ │ ├── TextUtil │ │ │ │ │ ├── TextUtil.spec.tsx │ │ │ │ │ ├── TextUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── TextUtil.spec.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── TriangleUtil │ │ │ │ │ ├── TriangleUtil.spec.tsx │ │ │ │ │ ├── TriangleUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── TriangleUtil.spec.tsx.snap │ │ │ │ │ ├── components │ │ │ │ │ │ ├── DashedTriangle.tsx │ │ │ │ │ │ ├── DrawTriangle.tsx │ │ │ │ │ │ └── TriangleBindingIndicator.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── triangleHelpers.ts │ │ │ │ ├── VersionNodeUtil │ │ │ │ │ ├── DrawEllipse.tsx │ │ │ │ │ ├── VersionNodeUtil.tsx │ │ │ │ │ ├── ellipseHelpers.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── VideoUtil │ │ │ │ │ ├── VideoUtil.spec.tsx │ │ │ │ │ ├── VideoUtil.tsx │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ │ └── VideoUtil.spec.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── about-shape-utils.md │ │ │ │ ├── iframe.tsx │ │ │ │ ├── index.ts │ │ │ │ └── shared │ │ │ │ │ ├── LabelMask.tsx │ │ │ │ │ ├── PolygonUtils.ts │ │ │ │ │ ├── TextAreaUtils.ts │ │ │ │ │ ├── TextLabel.tsx │ │ │ │ │ ├── getBoundsRectangle.ts │ │ │ │ │ ├── getTextAlign.ts │ │ │ │ │ ├── getTextSize.ts │ │ │ │ │ ├── getTextSvgElement.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── shape-styles.ts │ │ │ │ │ ├── transformRectangle.ts │ │ │ │ │ └── transformSingleRectangle.ts │ │ │ └── tools │ │ │ │ ├── ArrowTool │ │ │ │ ├── ArrowTool.spec.ts │ │ │ │ ├── ArrowTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── BaseTool.ts │ │ │ │ ├── DrawTool │ │ │ │ ├── DrawTool.spec.ts │ │ │ │ ├── DrawTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── EllipseTool │ │ │ │ ├── EllipseTool.spec.ts │ │ │ │ ├── EllipseTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── EraseTool │ │ │ │ ├── EraseTool.spec.ts │ │ │ │ ├── EraseTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── LineTool │ │ │ │ ├── LineTool.spec.ts │ │ │ │ ├── LineTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── RectangleTool │ │ │ │ ├── RectangleTool.spec.ts │ │ │ │ ├── RectangleTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── SelectTool │ │ │ │ ├── SelectTool.spec.ts │ │ │ │ ├── SelectTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── StickyTool │ │ │ │ ├── StickyTool.spec.ts │ │ │ │ ├── StickyTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── TextTool │ │ │ │ ├── TextTool.spec.ts │ │ │ │ ├── TextTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── TriangleTool │ │ │ │ ├── TriangleTool.spec.ts │ │ │ │ ├── TriangleTool.ts │ │ │ │ └── index.ts │ │ │ │ ├── about-tools.md │ │ │ │ └── index.ts │ │ ├── styles │ │ │ ├── index.ts │ │ │ └── stitches.config.ts │ │ ├── test │ │ │ ├── TldrawTestApp.tsx │ │ │ ├── badDocument.spec.ts │ │ │ ├── documents │ │ │ │ ├── badDocument.ts │ │ │ │ ├── old-doc-2.ts │ │ │ │ └── old-doc.ts │ │ │ ├── index.ts │ │ │ ├── mockDocument.tsx │ │ │ ├── renderWithContext.tsx │ │ │ ├── renderWithIntlProvider.tsx │ │ │ └── stylemock.ts │ │ ├── translations │ │ │ ├── ar.json │ │ │ ├── da.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── fa.json │ │ │ ├── fr.json │ │ │ ├── he.json │ │ │ ├── index.ts │ │ │ ├── it.json │ │ │ ├── ja.json │ │ │ ├── ko-kr.json │ │ │ ├── ku.json │ │ │ ├── main.json │ │ │ ├── my.json │ │ │ ├── ne.json │ │ │ ├── no.json │ │ │ ├── pl.json │ │ │ ├── pt-br.json │ │ │ ├── pt-pt.json │ │ │ ├── ru.json │ │ │ ├── sv.json │ │ │ ├── te.json │ │ │ ├── th.json │ │ │ ├── tr.json │ │ │ ├── translations.ts │ │ │ ├── uk.json │ │ │ ├── zh-cn.json │ │ │ └── zh-tw.json │ │ └── types.ts │ ├── tldraw-assets.json │ ├── tsconfig.build.json │ ├── tsconfig.dev.json │ ├── tsconfig.json │ └── tsconfig.tsbuildinfo └── vec │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── package.json │ ├── src │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.dev.json │ └── tsconfig.json ├── repo-map.tldr ├── setupTests.ts ├── tsconfig.base.json ├── tsconfig.json ├── turbo.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.4/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [], 6 | "access": "public", 7 | "baseBranch": "main", 8 | "updateInternalDependencies": "patch", 9 | "ignore": [] 10 | } 11 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster 2 | ARG VARIANT=16 3 | FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT} 4 | 5 | # [Optional] Uncomment this section to install additional OS packages. 6 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 7 | # && apt-get -y install --no-install-recommends 8 | 9 | # [Optional] Uncomment if you want to install an additional version of node using nvm 10 | # ARG EXTRA_NODE_VERSION=10 11 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 12 | 13 | # [Optional] Uncomment if you want to install more global node packages 14 | # RUN su node -c "npm install -g " 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/* 2 | **/out/* 3 | **/.next/* 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [steveruizok] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Writing and other documentation. 4 | title: '[bug] Bug description' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation 3 | about: Writing and other documentation. 4 | title: '[documentation] Content' 5 | labels: documentation 6 | assignees: '' 7 | --- 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: Begin discussion of a new feature. 4 | title: '[feature] Feature or improvement' 5 | labels: feature 6 | assignees: '' 7 | --- 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Testing 3 | about: Tests that need to be written. 4 | title: '[tests] Test' 5 | labels: testing 6 | assignees: '' 7 | --- 8 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: push 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | 9 | # turbo cache 10 | - name: Turbo Cache 11 | id: turbo-cache 12 | uses: actions/cache@v2 13 | with: 14 | path: node_modules/.cache/turbo 15 | key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} 16 | restore-keys: | 17 | turbo-${{ github.job }}-${{ github.ref_name }}- 18 | 19 | # install modules 20 | - name: Install modules 21 | run: yarn 22 | 23 | # build 24 | - name: Build Packages 25 | run: yarn build:packages --cache-dir=".turbo" 26 | 27 | # lint 28 | - name: Lint 29 | run: yarn lint 30 | 31 | # run unit tests 32 | - name: Jest Annotations & Coverage 33 | run: yarn test:ci 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | lib/ 4 | dist/ 5 | docs/ 6 | .idea/* 7 | 8 | .DS_Store 9 | coverage 10 | *.log 11 | 12 | .vercel 13 | .next 14 | apps/www/public/workbox-* 15 | apps/www/public/worker-* 16 | apps/www/public/sw.js 17 | apps/www/public/sw.js.map 18 | .env 19 | firebase.config.*.turbo 20 | .turbo 21 | apps/new-tab-extension/tsconfig.tsbuildinfo 22 | apps/.cache 23 | .yarn 24 | .yarnrc 25 | packages/**/**.d.ts 26 | packages/**/**.d.ts.map 27 | packages/**/**.map 28 | packages/**/**.js -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | #yarn run pre-commit 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | #yarn run pre-push 5 | -------------------------------------------------------------------------------- /.ignore: -------------------------------------------------------------------------------- 1 | # Ignored Files for Search 2 | 3 | dist 4 | node_modules 5 | *.d.ts 6 | *.js 7 | *.md 8 | *.lock 9 | *.tsbuildinfo -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.github/ 2 | /.vscode/ 3 | /node_modules/ 4 | /build/ 5 | /tmp/ 6 | .idea/* 7 | 8 | coverage 9 | *.log 10 | .gitlab-ci.yml 11 | 12 | package-lock.json 13 | /*.tgz 14 | /tmp* 15 | /mnt/ 16 | /package/ 17 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | assets 2 | **/assets 3 | **/coverage 4 | **/dist 5 | **/extension/editor 6 | **/out 7 | **/public 8 | 9 | .DS_Store 10 | .next 11 | .tldr 12 | .turbo 13 | .vercel 14 | .vsix 15 | 16 | *.lock 17 | *.log 18 | *.yaml 19 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true, 4 | "semi": false, 5 | "printWidth": 100, 6 | "importOrder": ["^[~]", "^[./]"], 7 | "importOrderSortSpecifiers": true, 8 | "importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:3000", 12 | "runtimeArgs": ["--auto-open-devtools-for-tabs"], 13 | "webRoot": "${workspaceFolder}" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/snippets.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "createComment": { 3 | "scope": "typescript,typescriptreact", 4 | "prefix": "ccc", 5 | "body": [ 6 | "/**", 7 | " * ${1:description}", 8 | " *", 9 | " * ### Example", 10 | " *", 11 | " *```ts", 12 | " * ${2:example}", 13 | " *```" 14 | ], 15 | "description": "comment" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | 4 | "tasks": [ 5 | { 6 | "type": "shell", 7 | "label": "build", 8 | 9 | "linux": {"command": "sensible-browser http://localhost:3000 & nvm use 16.13.0 && yarn start:www"}, 10 | "osx": {"command": "nvm use 16.13.0 && yarn start:www"}, 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | }, 15 | }, 16 | 17 | ] 18 | } -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | yarn-path ".yarn/releases/yarn-1.18.0.cjs" 6 | -------------------------------------------------------------------------------- /Quickpose.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "editor.defaultFormatter": "esbenp.prettier-vscode", 9 | "workbench.startupEditor": "readme", 10 | "workbench.editor.sharedViewState": true 11 | } 12 | } -------------------------------------------------------------------------------- /apps/vscode/editor/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # @tldraw/vscode-editor 6 | 7 | The app for the tldraw VS Code Extension. 8 | 9 | See the README at `vscode` for more about this project. 10 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import * as ReactDOM from 'react-dom' 3 | import App from './app' 4 | 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById('root') 10 | ) 11 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/public/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | * { 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | overscroll-behavior: none; 8 | margin: 0px; 9 | padding: 0px; 10 | } 11 | 12 | .tldraw { 13 | position: fixed; 14 | top: 0px; 15 | left: 0px; 16 | right: 0px; 17 | bottom: 0px; 18 | width: 100%; 19 | height: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tldraw 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/types.ts: -------------------------------------------------------------------------------- 1 | export type MessageFromWebview = { 2 | type: 'editorUpdated' 3 | text: string 4 | } 5 | 6 | export type MessageFromExtension = 7 | | { 8 | type: 'openedFile' 9 | text: string 10 | } 11 | | { 12 | type: 'fileSaved' 13 | text: string 14 | } 15 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/utils/defaultDocument.ts: -------------------------------------------------------------------------------- 1 | import { TDDocument, TldrawApp } from '@tldraw/tldraw' 2 | 3 | export const defaultDocument: TDDocument = { 4 | id: 'doc', 5 | name: 'New Document', 6 | version: TldrawApp.version, 7 | pages: { 8 | page: { 9 | id: 'page', 10 | name: 'Page 1', 11 | childIndex: 1, 12 | shapes: {}, 13 | bindings: {}, 14 | }, 15 | }, 16 | assets: {}, 17 | pageStates: { 18 | page: { 19 | id: 'page', 20 | selectedIds: [], 21 | camera: { 22 | point: [0, 0], 23 | zoom: 1, 24 | }, 25 | }, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /apps/vscode/editor/src/utils/vscode.ts: -------------------------------------------------------------------------------- 1 | import type { MessageFromWebview } from '../types' 2 | 3 | // Will be placed in global scope by extension 4 | declare function acquireVsCodeApi(): { 5 | postMessage(options: MessageFromWebview): void 6 | } 7 | 8 | export const vscode = acquireVsCodeApi() 9 | -------------------------------------------------------------------------------- /apps/vscode/editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["node_modules", "dist"], 5 | "compilerOptions": { 6 | "outDir": "./dist", 7 | "rootDir": "src", 8 | "baseUrl": "src", 9 | "emitDeclarationOnly": false, 10 | "jsx": "react-jsx", 11 | "paths": { 12 | "@tldraw/tldraw": ["../../../packages/tldraw"] 13 | } 14 | }, 15 | "references": [ 16 | { 17 | "path": "../../../packages/tldraw" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/vscode/extension/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | editor 3 | node_modules 4 | .vscode-test-web/ 5 | *.vsix 6 | .DS_Store -------------------------------------------------------------------------------- /apps/vscode/extension/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] 5 | } 6 | -------------------------------------------------------------------------------- /apps/vscode/extension/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Web Extension ", 10 | "type": "pwa-extensionHost", 11 | "request": "launch", 12 | "program": "${workspaceFolder}/src/extension.ts", 13 | "cwd": "${workspaceFolder}", 14 | "args": [ 15 | "--disable-extensions", 16 | "--extensionDevelopmentPath=${workspaceFolder}", 17 | "${workspaceFolder}/src/extension.ts" 18 | ], 19 | "outFiles": ["${workspaceFolder}/dist/web/**/*.js", "!**/node_modules/**"], 20 | "skipFiles": ["/**", "**/node_modules/**"], 21 | "sourceMaps": true 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /apps/vscode/extension/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } 12 | -------------------------------------------------------------------------------- /apps/vscode/extension/.vscodeignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/vscode/extension/.vscodeignore -------------------------------------------------------------------------------- /apps/vscode/extension/apps/vscode/extension: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/vscode/extension/apps/vscode/extension -------------------------------------------------------------------------------- /apps/vscode/extension/assets/recording.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/vscode/extension/assets/recording.gif -------------------------------------------------------------------------------- /apps/vscode/extension/assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/vscode/extension/assets/screenshot.png -------------------------------------------------------------------------------- /apps/vscode/extension/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/vscode/extension/icon.png -------------------------------------------------------------------------------- /apps/vscode/extension/src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode' 2 | import { TldrawEditorProvider } from './TldrawEditorProvider' 3 | 4 | // When a .tldr is first opened or created, activate the extension. 5 | export function activate(context: vscode.ExtensionContext) { 6 | try { 7 | context.subscriptions.push(TldrawEditorProvider.register(context)) 8 | } catch (e) { 9 | console.error(e) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/vscode/extension/src/types.ts: -------------------------------------------------------------------------------- 1 | export type MessageFromWebview = { 2 | type: 'editorUpdated' 3 | text: string 4 | } 5 | 6 | export type MessageFromExtension = 7 | | { 8 | type: 'openedFile' 9 | text: string 10 | } 11 | | { 12 | type: 'fileSaved' 13 | text: string 14 | } 15 | -------------------------------------------------------------------------------- /apps/vscode/extension/src/utils.ts: -------------------------------------------------------------------------------- 1 | export function getNonce() { 2 | let text = '' 3 | const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 4 | for (let i = 0; i < 32; i++) { 5 | text += possible.charAt(Math.floor(Math.random() * possible.length)) 6 | } 7 | return text 8 | } 9 | -------------------------------------------------------------------------------- /apps/vscode/extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "lib": ["es6", "WebWorker"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true, 10 | "paths": { 11 | "@tldraw/tldraw": ["../../../packages/tldraw"] 12 | } 13 | }, 14 | "references": [ 15 | { 16 | "path": "../../../packages/tldraw" 17 | } 18 | ], 19 | "exclude": ["node_modules", ".vscode-test-web"] 20 | } 21 | -------------------------------------------------------------------------------- /apps/www/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "next/core-web-vitals", 4 | "rules": { 5 | "@typescript-eslint/no-explicit-any": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/www/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /apps/www/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # @tldraw/www 6 | 7 | The [tldraw](https://tldraw.com) website. 8 | -------------------------------------------------------------------------------- /apps/www/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/www/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic' 2 | import Head from 'next/head' 3 | import { useRouter } from 'next/router' 4 | import { useMemo } from 'react' 5 | 6 | const Editor = dynamic(() => import('~components/Editor'), { ssr: false }) as any 7 | 8 | const Home = () => { 9 | const { query } = useRouter() 10 | const isExportMode = useMemo(() => 'exportMode' in query, [query]) 11 | 12 | return ( 13 | <> 14 | 15 | Quickpose 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default Home 23 | 24 | 25 | -------------------------------------------------------------------------------- /apps/www/pages/r/[id].tsx: -------------------------------------------------------------------------------- 1 | import type { GetServerSideProps } from 'next' 2 | import dynamic from 'next/dynamic' 3 | import Head from 'next/head' 4 | import * as React from 'react' 5 | 6 | const IFrameWarning = dynamic(() => import('~components/IFrameWarning'), { 7 | ssr: false, 8 | }) as any 9 | 10 | const MultiplayerEditor = dynamic(() => import('~components/MultiplayerEditor'), { 11 | ssr: false, 12 | }) as any 13 | 14 | interface RoomProps { 15 | id: string 16 | } 17 | 18 | export default function Room({ id }: RoomProps) { 19 | if (typeof window !== 'undefined' && window.self !== window.top) { 20 | return 21 | } 22 | 23 | return ( 24 | <> 25 | 26 | tldraw - {id} 27 | 28 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /apps/www/pages/r/index.tsx: -------------------------------------------------------------------------------- 1 | import type { GetServerSideProps } from 'next' 2 | import Head from 'next/head' 3 | import * as React from 'react' 4 | 5 | export default function RandomRoomPage() { 6 | return ( 7 | <> 8 | 9 | tldraw 10 | 11 | 12 | ) 13 | } 14 | 15 | -------------------------------------------------------------------------------- /apps/www/public/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-144x144.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-256x256.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-36x36.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-384x384.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-48x48.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-72x72.png -------------------------------------------------------------------------------- /apps/www/public/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/android-chrome-96x96.png -------------------------------------------------------------------------------- /apps/www/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/www/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | #da532c 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/www/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/favicon-16x16.png -------------------------------------------------------------------------------- /apps/www/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/favicon-32x32.png -------------------------------------------------------------------------------- /apps/www/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/favicon.ico -------------------------------------------------------------------------------- /apps/www/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/mstile-150x150.png -------------------------------------------------------------------------------- /apps/www/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/mstile-310x310.png -------------------------------------------------------------------------------- /apps/www/public/quickpose-banner-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/quickpose-banner-black.png -------------------------------------------------------------------------------- /apps/www/public/quickpose-banner-grad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/quickpose-banner-grad.png -------------------------------------------------------------------------------- /apps/www/public/quickpose_flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/quickpose_flat.png -------------------------------------------------------------------------------- /apps/www/public/quickpose_logo_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/quickpose_logo_main.png -------------------------------------------------------------------------------- /apps/www/public/social-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/apps/www/public/social-image.png -------------------------------------------------------------------------------- /apps/www/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, 6 | Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | 18 | .tldraw { 19 | position: fixed; 20 | top: 0px; 21 | left: 0px; 22 | right: 0px; 23 | bottom: 0px; 24 | width: 100%; 25 | height: 100%; 26 | } 27 | -------------------------------------------------------------------------------- /apps/www/styles/index.ts: -------------------------------------------------------------------------------- 1 | export * from './stitches.config' 2 | -------------------------------------------------------------------------------- /apps/www/types.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /apps/www/utils/gtag.ts: -------------------------------------------------------------------------------- 1 | export const GA_TRACKING_ID = process.env.GA_ID_QUICKPOSE 2 | 3 | type GTagEvent = { 4 | action: string 5 | category: string 6 | label: string 7 | value: number 8 | } 9 | 10 | export const pageview = (url: URL): void => { 11 | if ('gtag' in window) { 12 | const win = window as any 13 | win?.gtag('config', GA_TRACKING_ID, { 14 | page_path: url, 15 | }) 16 | } 17 | } 18 | 19 | export const event = ({ action, category, label, value }: GTagEvent): void => { 20 | if ('gtag' in window) { 21 | const win = window as any 22 | win?.gtag('event', action, { 23 | event_category: category, 24 | event_label: label, 25 | value: value, 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/www/utils/useGtag.ts: -------------------------------------------------------------------------------- 1 | import router from 'next/router' 2 | import { useEffect } from 'react' 3 | import * as gtag from './gtag' 4 | 5 | function handleRouteChange(url: URL) { 6 | gtag.pageview(url) 7 | } 8 | 9 | export default function useGtag() { 10 | useEffect(() => { 11 | if (process.env.NODE_ENV !== 'production') return 12 | 13 | router.events.on('routeChangeComplete', handleRouteChange) 14 | 15 | return () => { 16 | router.events.off('routeChangeComplete', handleRouteChange) 17 | } 18 | }, []) 19 | } 20 | -------------------------------------------------------------------------------- /apps/www/worker/index.js: -------------------------------------------------------------------------------- 1 | self.__WB_DISABLE_DEV_LOGS = true 2 | -------------------------------------------------------------------------------- /assets/export1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/export1.gif -------------------------------------------------------------------------------- /assets/export2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/export2.gif -------------------------------------------------------------------------------- /assets/fork.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/fork.gif -------------------------------------------------------------------------------- /assets/linkedstate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/linkedstate.gif -------------------------------------------------------------------------------- /assets/navigate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/navigate.gif -------------------------------------------------------------------------------- /assets/quickpose-banner-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose-banner-black.png -------------------------------------------------------------------------------- /assets/quickpose-banner-grad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose-banner-grad.png -------------------------------------------------------------------------------- /assets/quickpose-social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose-social.png -------------------------------------------------------------------------------- /assets/quickpose_flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose_flat.png -------------------------------------------------------------------------------- /assets/quickpose_logo_main copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose_logo_main copy.png -------------------------------------------------------------------------------- /assets/quickpose_logo_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/quickpose_logo_main.png -------------------------------------------------------------------------------- /assets/stickies.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/assets/stickies.gif -------------------------------------------------------------------------------- /examples/core-example-advanced/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/core-example-advanced/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # @tldraw/core-example-advanced 6 | 7 | An advanced example project for `@tldraw/core`. 8 | 9 | To start this project: 10 | 11 | 1. Run `yarn` from the repository's root directory 12 | 2. Run `yarn start:core` from the repository's root directory 13 | 3. Open http://localhost:5421/ in your browser 14 | 15 | As an alternative to running `yarn start:core` you can also: 16 | 17 | 1. Run `yarn build` from the repository's root directory 18 | 2. Run `yarn dev` from the `examples/core-example-advanced` directory 19 | -------------------------------------------------------------------------------- /examples/core-example-advanced/card-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/core-example-advanced/card-repo.png -------------------------------------------------------------------------------- /examples/core-example-advanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tldraw - core example advanced 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/core-example-advanced/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/core-example-advanced/public/favicon.ico -------------------------------------------------------------------------------- /examples/core-example-advanced/src/components/TitleLinks.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import styled from 'stitches.config' 3 | 4 | export function TitleLinks() { 5 | return ( 6 | 7 | @tldraw/core 8 | 9 | ) 10 | } 11 | 12 | const TitleLinksContainer = styled('div', { 13 | position: 'fixed', 14 | top: 0, 15 | left: 0, 16 | width: '100%', 17 | display: 'flex', 18 | alignItems: 'center', 19 | justifyContent: 'center', 20 | zIndex: 100, 21 | fontSize: '$3', 22 | 23 | '& > a': { 24 | color: '$text', 25 | textDecoration: 'none', 26 | padding: '$2 $4', 27 | fontWeight: '$2', 28 | pointerEvents: 'all', 29 | '&:hover': { 30 | textDecoration: 'underline', 31 | }, 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './styles.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/CustomShapeUtil.ts: -------------------------------------------------------------------------------- 1 | import { TLBounds, TLShape, TLShapeUtil } from '@tldraw/core' 2 | 3 | export abstract class CustomShapeUtil< 4 | T extends TLShape, 5 | E extends Element = Element 6 | > extends TLShapeUtil { 7 | /* ----------------- Custom Methods ----------------- */ 8 | 9 | canBind = false 10 | 11 | hideBounds = false 12 | 13 | abstract getCenter: (shape: T) => number[] 14 | 15 | abstract getShape: (shape: Partial) => T 16 | 17 | abstract transform: (shape: T, bounds: TLBounds, initialShape: T, scale: number[]) => void 18 | 19 | abstract hitTestPoint: (shape: T, point: number[]) => boolean 20 | 21 | abstract hitTestLineSegment: (shape: T, A: number[], B: number[]) => boolean 22 | } 23 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/arrow/ArrowIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { TLShapeUtil } from '@tldraw/core' 2 | import Vec from '@tldraw/vec' 3 | import * as React from 'react' 4 | import type { ArrowShape } from './ArrowShape' 5 | 6 | export const ArrowIndicator = TLShapeUtil.Indicator(({ shape }) => { 7 | const { start, end } = shape.handles 8 | 9 | const u = Vec.uni(Vec.sub(end.point, start.point)) 10 | const dist = Vec.dist(end.point, start.point) 11 | const length = Math.min(18, dist / 2) 12 | const ahLeft = Vec.rotWith(Vec.sub(end.point, Vec.mul(u, length)), end.point, -Math.PI / 6) 13 | const ahRight = Vec.rotWith(Vec.sub(end.point, Vec.mul(u, length)), end.point, Math.PI / 6) 14 | 15 | return ( 16 | 24 | ) 25 | }) 26 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/arrow/ArrowShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLShape } from '@tldraw/core' 2 | 3 | export interface ArrowShape extends TLShape { 4 | type: 'arrow' 5 | handles: { 6 | start: { 7 | id: 'start' 8 | index: number 9 | point: number[] 10 | } 11 | end: { 12 | id: 'end' 13 | index: number 14 | point: number[] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/arrow/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ArrowShape' 2 | export * from './ArrowUtil' 3 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/box/BoxComponent.tsx: -------------------------------------------------------------------------------- 1 | import { SVGContainer, TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { BoxShape } from './BoxShape' 4 | 5 | export const BoxComponent = TLShapeUtil.Component( 6 | ({ shape, events, isGhost, meta }, ref) => { 7 | const color = meta.isDarkMode ? 'white' : 'black' 8 | 9 | return ( 10 | 11 | 22 | 23 | ) 24 | } 25 | ) 26 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/box/BoxIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { BoxShape } from './BoxShape' 4 | 5 | export const BoxIndicator = TLShapeUtil.Indicator(({ shape }) => { 6 | return ( 7 | 16 | ) 17 | }) 18 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/box/BoxShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLShape } from '@tldraw/core' 2 | 3 | export interface BoxShape extends TLShape { 4 | type: 'box' 5 | size: number[] 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/box/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BoxShape' 2 | export * from './BoxUtil' 3 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/index.ts: -------------------------------------------------------------------------------- 1 | import { TLShapeUtilsMap } from '@tldraw/core' 2 | import type { CustomShapeUtil } from './CustomShapeUtil' 3 | import { ArrowShape, ArrowUtil } from './arrow' 4 | import { BoxShape, BoxUtil } from './box' 5 | import { PencilShape, PencilUtil } from './pencil' 6 | 7 | export * from './arrow' 8 | export * from './pencil' 9 | export * from './box' 10 | 11 | export type Shape = BoxShape | ArrowShape | PencilShape 12 | 13 | export const shapeUtils = { 14 | box: new BoxUtil(), 15 | arrow: new ArrowUtil(), 16 | pencil: new PencilUtil(), 17 | } 18 | 19 | export const getShapeUtils = (shape: T | T['type']) => { 20 | if (typeof shape === 'string') return shapeUtils[shape] as unknown as CustomShapeUtil 21 | return shapeUtils[shape.type] as unknown as CustomShapeUtil 22 | } 23 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/pencil/PencilComponent.tsx: -------------------------------------------------------------------------------- 1 | import { SVGContainer, TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { PencilShape } from './PencilShape' 4 | import { getComponentSvgPath } from './pencil-helpers' 5 | 6 | export const PencilComponent = TLShapeUtil.Component( 7 | ({ shape, events, isGhost, meta }, ref) => { 8 | const color = meta.isDarkMode ? 'white' : 'black' 9 | const pathData = getComponentSvgPath(shape.points) 10 | return ( 11 | 12 | 13 | 14 | 15 | ) 16 | } 17 | ) 18 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/pencil/PencilShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLShape } from '@tldraw/core' 2 | 3 | export interface PencilShape extends TLShape { 4 | type: 'pencil' 5 | points: number[][] 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/pencil/PenclIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { PencilShape } from './PencilShape' 4 | import { getIndicatorSvgPath } from './pencil-helpers' 5 | 6 | export const PencilIndicator = TLShapeUtil.Indicator(({ shape }) => { 7 | return ( 8 | 16 | ) 17 | }) 18 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/shapes/pencil/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PencilShape' 2 | export * from './PencilUtil' 3 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/bindings/createBindings.ts: -------------------------------------------------------------------------------- 1 | import type { TLBinding } from '@tldraw/core' 2 | import { nanoid } from 'nanoid' 3 | import type { Action, CustomBinding } from 'state/constants' 4 | 5 | export const createBindings: Action = ( 6 | data, 7 | payload: { 8 | bindings: (Partial & Pick)[] 9 | } 10 | ) => { 11 | payload.bindings.forEach((partial) => { 12 | const binding = { 13 | id: nanoid(), 14 | ...partial, 15 | } 16 | 17 | data.page.bindings[binding.id] = binding 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/bindings/deleteBindings.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const deleteBindings: Action = (data, payload: { ids: string[] }) => { 4 | try { 5 | payload.ids.forEach((id) => { 6 | delete data.page.bindings[id] 7 | }) 8 | } catch (e: any) { 9 | e.message = 'Could not delete bindings: ' + e.message 10 | console.error(e) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/bindings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './updateBoundShapes' 2 | export * from './createBindings' 3 | export * from './removePartialBindings' 4 | export * from './updateBindings' 5 | export * from './deleteBindings' 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/bindings/removePartialBindings.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | // Remove bindings from selected shapes to shapes that aren't also selected 4 | export const removePartialBindings: Action = (data) => { 5 | const { selectedIds } = data.pageState 6 | 7 | const bindings = Object.values(data.page.bindings) 8 | 9 | bindings 10 | .filter((binding) => selectedIds.includes(binding.fromId)) 11 | .forEach((binding) => { 12 | if (!selectedIds.includes(binding.toId)) { 13 | delete data.page.bindings[binding.id] 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/bindings/updateBindings.ts: -------------------------------------------------------------------------------- 1 | import type { TLBinding } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | 4 | export const updateBindings: Action = ( 5 | data, 6 | payload: { bindings: (Partial & Pick)[] } 7 | ) => { 8 | try { 9 | payload.bindings.forEach((partial) => { 10 | Object.assign(data.page.bindings[partial.id], partial) 11 | }) 12 | } catch (e: any) { 13 | e.message = 'Could not update shapes: ' + e.message 14 | console.error(e) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/camera/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panCamera' 2 | export * from './pinchCamera' 3 | export * from './zoomIn' 4 | export * from './zoomOut' 5 | export * from './zoomToSelection' 6 | export * from './zoomToFit' 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/camera/panCamera.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import Vec from '@tldraw/vec' 3 | import type { Action } from 'state/constants' 4 | 5 | export const panCamera: Action = (data, payload: TLPointerInfo) => { 6 | const { point, zoom } = data.pageState.camera 7 | data.pageState.camera.point = Vec.sub(point, Vec.div(payload.delta, zoom)) 8 | } 9 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/camera/pinchCamera.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import Vec from '@tldraw/vec' 3 | import type { Action } from 'state/constants' 4 | 5 | export const pinchCamera: Action = (data, payload: TLPointerInfo) => { 6 | const { camera } = data.pageState 7 | const nextZoom = payload.delta[2] 8 | const nextPoint = Vec.sub(camera.point, Vec.div(payload.delta, camera.zoom)) 9 | const p0 = Vec.sub(Vec.div(payload.point, camera.zoom), nextPoint) 10 | const p1 = Vec.sub(Vec.div(payload.point, nextZoom), nextPoint) 11 | data.pageState.camera.point = Vec.toFixed(Vec.add(nextPoint, Vec.sub(p1, p0))) 12 | data.pageState.camera.zoom = nextZoom 13 | } 14 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/camera/zoomIn.ts: -------------------------------------------------------------------------------- 1 | import Vec from '@tldraw/vec' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const zoomIn: Action = (data) => { 6 | const { camera } = data.pageState 7 | const i = Math.round((data.pageState.camera.zoom * 100) / 25) 8 | const zoom = Math.min(5, (i + 1) * 0.25) 9 | const center = [mutables.rendererBounds.width / 2, mutables.rendererBounds.height / 2] 10 | const p0 = Vec.sub(Vec.div(center, camera.zoom), center) 11 | const p1 = Vec.sub(Vec.div(center, zoom), center) 12 | const point = Vec.toFixed(Vec.add(camera.point, Vec.sub(p1, p0))) 13 | 14 | data.pageState.camera.zoom = zoom 15 | data.pageState.camera.point = point 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/camera/zoomOut.ts: -------------------------------------------------------------------------------- 1 | import Vec from '@tldraw/vec' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const zoomOut: Action = (data) => { 6 | const { camera } = data.pageState 7 | const i = Math.round((data.pageState.camera.zoom * 100) / 25) 8 | const zoom = Math.max(0.25, (i - 1) * 0.25) 9 | const center = [mutables.rendererBounds.width / 2, mutables.rendererBounds.height / 2] 10 | const p0 = Vec.sub(Vec.div(center, camera.zoom), center) 11 | const p1 = Vec.sub(Vec.div(center, zoom), center) 12 | const point = Vec.toFixed(Vec.add(camera.point, Vec.sub(p1, p0))) 13 | 14 | data.pageState.camera.zoom = zoom 15 | data.pageState.camera.point = point 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/data/index.ts: -------------------------------------------------------------------------------- 1 | export * from './loadDocument' 2 | export * from './restoreSavedDocument' 3 | export * from './loadNewDocument' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/data/loadDocument.ts: -------------------------------------------------------------------------------- 1 | import { current } from 'immer' 2 | import type { Action, AppDocument } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const loadDocument: Action = (data, payload: { doc: AppDocument }) => { 6 | Object.assign(data, payload.doc) 7 | 8 | const snapshot = current(data) 9 | 10 | mutables.history.reset(snapshot) 11 | 12 | Object.assign(mutables, { 13 | snapshot, 14 | initialPoint: [0, 0], 15 | isCloning: false, 16 | pointedShapeId: undefined, 17 | pointedHandleId: undefined, 18 | pointedBoundsHandleId: undefined, 19 | initialCommonBounds: undefined, 20 | snapInfo: undefined, 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/data/restoreSavedDocument.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const restoreSavedDocument: Action = (data) => { 5 | const snapshot = mutables.history.restore() 6 | Object.assign(data, snapshot) 7 | } 8 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/erase/eraseGhostShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const eraseGhostShapes: Action = (data) => { 4 | const idsToDelete = Object.values(data.page.shapes) 5 | .filter((shape) => shape.isGhost) 6 | .map((shape) => shape.id) 7 | 8 | idsToDelete.forEach((id) => delete data.page.shapes[id]) 9 | 10 | data.pageState.selectedIds = data.pageState.selectedIds.filter((id) => !idsToDelete.includes(id)) 11 | 12 | if (data.pageState.hoveredId && idsToDelete.includes(data.pageState.hoveredId)) { 13 | data.pageState.hoveredId = undefined 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/erase/eraseShapes.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import { getShapeUtils } from 'shapes' 3 | import type { Action } from 'state/constants' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const eraseShapes: Action = (data, payload: TLPointerInfo) => { 7 | const { previousPoint } = mutables 8 | 9 | Object.values(data.page.shapes) 10 | .filter((shape) => !shape.isGhost) 11 | .forEach((shape) => { 12 | if (getShapeUtils(shape).hitTestLineSegment(shape, previousPoint, mutables.currentPoint)) { 13 | shape.isGhost = true 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/erase/eraseShapesAtPoint.ts: -------------------------------------------------------------------------------- 1 | import { getShapeUtils } from 'shapes' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const eraseShapesAtPoint: Action = (data) => { 6 | const { currentPoint } = mutables 7 | 8 | Object.values(data.page.shapes).forEach((shape) => { 9 | if (getShapeUtils(shape).hitTestPoint(shape, currentPoint)) { 10 | delete data.page.shapes[shape.id] 11 | } 12 | }) 13 | 14 | const { shapes } = data.page 15 | const { selectedIds, hoveredId } = data.pageState 16 | 17 | // Filter out any deleted shapes 18 | data.pageState.selectedIds = selectedIds.filter((id) => { 19 | return shapes[id] !== undefined 20 | }) 21 | 22 | // Remove hovered id if it's been deleted 23 | if (hoveredId && !shapes[hoveredId]) { 24 | data.pageState.hoveredId = undefined 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/erase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './eraseShapes' 2 | export * from './eraseShapesAtPoint' 3 | export * from './eraseGhostShapes' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/handles/clearPointedHandle.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const clearPointedHandle: Action = () => { 5 | mutables.pointedHandleId = undefined 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/handles/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setPointedHandle' 2 | export * from './clearPointedHandle' 3 | export * from './translateHandle' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/handles/setPointedHandle.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const setPointedHandle: Action = (data, payload) => { 5 | mutables.pointedHandleId = payload.target 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/history/addToHistory.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const addToHistory: Action = (data) => { 5 | mutables.history.push(data) 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/history/index.ts: -------------------------------------------------------------------------------- 1 | export * from './addToHistory' 2 | export * from './redo' 3 | export * from './undo' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/history/redo.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const redo: Action = (data) => { 5 | const snapshot = mutables.history.redo() 6 | Object.assign(data, snapshot) 7 | } 8 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/history/undo.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const undo: Action = (data) => { 5 | const snapshot = mutables.history.undo() 6 | Object.assign(data, snapshot) 7 | } 8 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bindings' 2 | export * from './camera' 3 | export * from './data' 4 | export * from './erase' 5 | export * from './handles' 6 | export * from './history' 7 | export * from './mutables/restoreSnapshot' 8 | export * from './selection' 9 | export * from './shapes' 10 | export * from './snaps' 11 | export * from './transform' 12 | export * from './translate' 13 | export * from './mutables' 14 | export * from './performance' 15 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setInitialPoint' 2 | export * from './setSnapshot' 3 | export * from './setViewport' 4 | export * from './restoreSnapshot' 5 | export * from './updatePointer' 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/restoreSnapshot.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const restoreSnapshot: Action = (data) => { 5 | Object.assign(data, mutables.snapshot) 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/setInitialPoint.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | import { getPagePoint } from 'state/helpers' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const setInitialPoint: Action = (data, payload: TLPointerInfo) => { 7 | mutables.initialPoint = getPagePoint(payload.origin, data.pageState) 8 | mutables.previousPoint = [...mutables.initialPoint] 9 | } 10 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/setSnapshot.ts: -------------------------------------------------------------------------------- 1 | import { current } from 'immer' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const setSnapshot: Action = (data) => { 6 | mutables.snapshot = current(data) 7 | } 8 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/setViewport.ts: -------------------------------------------------------------------------------- 1 | import type { TLBounds } from '@tldraw/core' 2 | import Vec from '@tldraw/vec' 3 | import type { Action } from 'state/constants' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const setViewport: Action = (data, payload: { bounds: TLBounds }) => { 7 | const { camera } = data.pageState 8 | const { width, height } = payload.bounds 9 | 10 | const [minX, minY] = Vec.sub(Vec.div([0, 0], camera.zoom), camera.point) 11 | const [maxX, maxY] = Vec.sub(Vec.div([width, height], camera.zoom), camera.point) 12 | 13 | mutables.rendererBounds = { ...payload.bounds } 14 | 15 | mutables.viewport = { 16 | minX, 17 | minY, 18 | maxX, 19 | maxY, 20 | height: maxX - minX, 21 | width: maxY - minY, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/mutables/updatePointer.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | import { getPagePoint } from 'state/helpers' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const updatePointer: Action = (data, payload: TLPointerInfo) => { 7 | mutables.previousPoint = [...mutables.currentPoint] 8 | mutables.currentPoint = getPagePoint(payload.point, data.pageState) 9 | } 10 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/performance/clearPerformanceMode.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const clearPerformanceMode: Action = (data) => { 4 | data.performanceMode = undefined 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/performance/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clearPerformanceMode' 2 | export * from './setTranslatePerformanceMode' 3 | export * from './setTransformPerformanceMode' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/performance/setTransformPerformanceMode.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const setTransformPerformanceMode: Action = (data) => { 4 | data.performanceMode = undefined 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/performance/setTranslatePerformanceMode.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const setTranslatePerformanceMode: Action = (data) => { 4 | data.performanceMode = undefined 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/clearBrush.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const clearBrush: Action = (data) => { 4 | data.pageState.brush = undefined 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/clearHoveredShape.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const clearHoveredShape: Action = (data) => { 4 | data.pageState.hoveredId = undefined 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/clearPointedShape.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const clearPointedShape: Action = () => { 5 | mutables.pointedShapeId = undefined 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/deselectAllShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const deselectAllShapes: Action = (data) => { 4 | data.pageState.selectedIds = [] 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clearBrush' 2 | export * from './clearHoveredShape' 3 | export * from './clearPointedShape' 4 | export * from './deselectAllShapes' 5 | export * from './selectShape' 6 | export * from './setHoveredShape' 7 | export * from './updateBrush' 8 | export * from './selectAllShapes' 9 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/selectAllShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const selectAllShapes: Action = (data) => { 4 | data.pageState.selectedIds = Object.keys(data.page.shapes) 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/selectShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | 5 | export const selectShape: Action = (data, payload: TLPointerInfo) => { 6 | const { selectedIds } = data.pageState 7 | 8 | if (payload.shiftKey) { 9 | if (selectedIds.includes(payload.target) && mutables.pointedShapeId !== payload.target) { 10 | selectedIds.splice(selectedIds.indexOf(payload.target), 1) 11 | } else { 12 | mutables.pointedShapeId = payload.target 13 | selectedIds.push(payload.target) 14 | } 15 | } else { 16 | data.pageState.selectedIds = [payload.target] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/selection/setHoveredShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | 4 | export const setHoveredShape: Action = (data, payload: TLPointerInfo) => { 5 | data.pageState.hoveredId = payload.target 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/createBoxShape.ts: -------------------------------------------------------------------------------- 1 | import { TLBoundsCorner, TLPointerInfo } from '@tldraw/core' 2 | import { shapeUtils } from 'shapes' 3 | import type { Action } from 'state/constants' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const createBoxShape: Action = (data, payload: TLPointerInfo) => { 7 | const shape = shapeUtils.box.getShape({ 8 | parentId: 'page1', 9 | point: mutables.currentPoint, 10 | size: [1, 1], 11 | childIndex: Object.values(data.page.shapes).length, 12 | }) 13 | 14 | data.page.shapes[shape.id] = shape 15 | data.pageState.selectedIds = [shape.id] 16 | 17 | mutables.pointedBoundsHandleId = TLBoundsCorner.BottomRight 18 | } 19 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/createPencilShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import { shapeUtils } from 'shapes' 3 | import type { Action } from 'state/constants' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const createPencilShape: Action = (data, payload: TLPointerInfo) => { 7 | const shape = shapeUtils.pencil.getShape({ 8 | parentId: 'page1', 9 | point: mutables.currentPoint, 10 | points: [[0, 0]], 11 | childIndex: Object.values(data.page.shapes).length, 12 | }) 13 | 14 | data.page.shapes[shape.id] = shape 15 | data.pageState.selectedIds = [shape.id] 16 | 17 | mutables.rawPoints = [[0, 0]] 18 | mutables.pointedShapeId = shape.id 19 | } 20 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/createShapes.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid' 2 | import { Shape, getShapeUtils } from 'shapes' 3 | import type { Action } from 'state/constants' 4 | 5 | export const createShapes: Action = ( 6 | data, 7 | payload: { shapes: (Partial & Pick)[] } 8 | ) => { 9 | try { 10 | payload.shapes.forEach((partial, i) => { 11 | const shape = getShapeUtils(partial.type).getShape({ 12 | id: nanoid(), 13 | childIndex: Object.values(data.page.shapes).length, 14 | ...partial, 15 | parentId: 'page1', 16 | }) 17 | 18 | data.page.shapes[shape.id] = shape 19 | }) 20 | } catch (e: any) { 21 | e.message = 'Could not create shapes: ' + e.message 22 | console.error(e) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/deleteSelectedShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const deleteSelectedShapes: Action = (data) => { 4 | const { page, pageState } = data 5 | if (pageState.hoveredId && pageState.selectedIds.includes(pageState.hoveredId)) { 6 | pageState.hoveredId = undefined 7 | } 8 | pageState.selectedIds.forEach((id) => delete page.shapes[id]) 9 | pageState.selectedIds = [] 10 | } 11 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/deleteShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const deleteShapes: Action = (data, payload: { ids: string[] }) => { 4 | try { 5 | data.pageState.selectedIds = data.pageState.selectedIds.filter( 6 | (id) => !payload.ids.includes(id) 7 | ) 8 | 9 | payload.ids.forEach((id) => { 10 | delete data.page.shapes[id] 11 | }) 12 | } catch (e: any) { 13 | e.message = 'Could not delete shapes: ' + e.message 14 | console.error(e) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createPencilShape' 2 | export * from './createArrowShape' 3 | export * from './createBoxShape' 4 | export * from './deleteSelectedShapes' 5 | export * from './createShapes' 6 | export * from './updateShapes' 7 | export * from './deleteShapes' 8 | export * from './extendPencilShape' 9 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/shapes/updateShapes.ts: -------------------------------------------------------------------------------- 1 | import type { Shape } from 'shapes' 2 | import type { Action } from 'state/constants' 3 | 4 | export const updateShapes: Action = ( 5 | data, 6 | payload: { shapes: (Partial & Pick)[] } 7 | ) => { 8 | try { 9 | payload.shapes.forEach((partial) => { 10 | Object.assign(data.page.shapes[partial.id], partial) 11 | }) 12 | } catch (e: any) { 13 | e.message = 'Could not update shapes: ' + e.message 14 | console.error(e) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/snapping/clearSnapLines.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const clearSnaplines: Action = (data) => { 4 | data.overlays.snapLines = [] 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/snaps/clearSnapInfo.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const clearSnapInfo: Action = () => { 5 | mutables.snapInfo = undefined 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/snaps/clearSnapLines.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | 3 | export const clearSnapLines: Action = (data) => { 4 | data.overlays.snapLines = [] 5 | } 6 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/snaps/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clearSnapLines' 2 | export * from './setSnapInfo' 3 | export * from './clearSnapInfo' 4 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/transform/clearPointedBoundsHandle.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const clearPointedBoundsHandle: Action = (data, payload) => { 5 | mutables.pointedBoundsHandleId = undefined 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/transform/index.ts: -------------------------------------------------------------------------------- 1 | export * from './transformSelectedShapes' 2 | export * from './setPointedBoundsHandle' 3 | export * from './setInitialCommonBounds' 4 | export * from './clearPointedBoundsHandle' 5 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/transform/setInitialCommonBounds.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@tldraw/core' 2 | import { getShapeUtils } from 'shapes' 3 | import type { Action } from 'state/constants' 4 | import { mutables } from 'state/mutables' 5 | 6 | export const setInitialCommonBounds: Action = (data) => { 7 | const { snapshot } = mutables 8 | const { selectedIds } = data.pageState 9 | 10 | const initialCommonBounds = Utils.getCommonBounds( 11 | selectedIds 12 | .map((id) => snapshot.page.shapes[id]) 13 | .map((shape) => getShapeUtils(shape).getBounds(shape)) 14 | ) 15 | 16 | mutables.initialCommonBounds = initialCommonBounds 17 | } 18 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/transform/setPointedBoundsHandle.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const setPointedBoundsHandle: Action = (data, payload) => { 5 | mutables.pointedBoundsHandleId = payload.target 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/transform/transformSelectedShapes.ts: -------------------------------------------------------------------------------- 1 | import type { TLPointerInfo } from '@tldraw/core' 2 | import type { Action } from 'state/constants' 3 | import { mutables } from 'state/mutables' 4 | import { resizeSelectedShapes } from './resizeSelectedShapes' 5 | import { rotateSelectedShapes } from './rotateSelectedShapes' 6 | 7 | export const transformSelectedShapes: Action = (data, payload: TLPointerInfo) => { 8 | const { pointedBoundsHandleId } = mutables 9 | 10 | if (pointedBoundsHandleId === 'rotate') { 11 | rotateSelectedShapes(data, payload) 12 | } else { 13 | resizeSelectedShapes(data, payload) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/translate/clearIsCloning.ts: -------------------------------------------------------------------------------- 1 | import type { Action } from 'state/constants' 2 | import { mutables } from 'state/mutables' 3 | 4 | export const clearIsCloning: Action = () => { 5 | mutables.isCloning = false 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/state/actions/translate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clearIsCloning' 2 | export * from './translateSelectedShapes' 3 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/styles.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700'); 2 | 3 | html, 4 | * { 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 10 | Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 11 | overscroll-behavior: none; 12 | margin: 0px; 13 | padding: 0px; 14 | } 15 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/types.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /examples/core-example-advanced/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/core-example-advanced/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "baseUrl": ".", 19 | "paths": { 20 | "*": ["src/*"] 21 | } 22 | }, 23 | "include": ["src"], 24 | "references": [ 25 | { "path": "./tsconfig.node.json" }, 26 | { "path": "../../packages/tldraw" }, 27 | { "path": "../../packages/core" } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/core-example-advanced/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /examples/core-example-advanced/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react' 2 | import { defineConfig } from 'vite' 3 | import tsconfigPaths from 'vite-tsconfig-paths' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), tsconfigPaths()], 8 | server: { 9 | port: 5421, 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /examples/core-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/core-example/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # @tldraw/core-example 6 | 7 | An simple example project for `@tldraw/core`. 8 | 9 | To start this project: 10 | 11 | 1. Run `yarn` from the repository's root directory 12 | 2. Run `yarn build` from the repository's root directory 13 | 3. Run `yarn dev` from the `examples/core-example` directory 14 | 4. Open http://localhost:5422/ in your browser 15 | -------------------------------------------------------------------------------- /examples/core-example/card-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/core-example/card-repo.png -------------------------------------------------------------------------------- /examples/core-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tldraw - core example 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/core-example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/core-example/public/favicon.ico -------------------------------------------------------------------------------- /examples/core-example/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './styles.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/index.ts: -------------------------------------------------------------------------------- 1 | import type { RectShape } from './rect' 2 | 3 | export * from './rect' 4 | 5 | export type Shape = RectShape 6 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/rect/RectComponent.tsx: -------------------------------------------------------------------------------- 1 | import { SVGContainer, TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { RectShape } from './RectShape' 4 | 5 | export const RectComponent = TLShapeUtil.Component( 6 | ({ shape, events, meta }, ref) => { 7 | const color = meta.isDarkMode ? 'white' : 'black' 8 | 9 | return ( 10 | 11 | 20 | 21 | ) 22 | } 23 | ) 24 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/rect/RectIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { TLShapeUtil } from '@tldraw/core' 2 | import * as React from 'react' 3 | import type { RectShape } from './RectShape' 4 | 5 | export const RectIndicator = TLShapeUtil.Indicator(({ shape }) => { 6 | return ( 7 | 15 | ) 16 | }) 17 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/rect/RectShape.ts: -------------------------------------------------------------------------------- 1 | import type { TLShape } from '@tldraw/core' 2 | 3 | export interface RectShape extends TLShape { 4 | type: 'rect' 5 | size: number[] 6 | } 7 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/rect/RectUtil.ts: -------------------------------------------------------------------------------- 1 | import { TLBounds, TLShapeUtil } from '@tldraw/core' 2 | import { RectComponent } from './RectComponent' 3 | import { RectIndicator } from './RectIndicator' 4 | import type { RectShape } from './RectShape' 5 | 6 | type T = RectShape 7 | type E = SVGSVGElement 8 | 9 | export class RectUtil extends TLShapeUtil { 10 | Component = RectComponent 11 | 12 | Indicator = RectIndicator 13 | 14 | getBounds = (shape: T) => { 15 | const [x, y] = shape.point 16 | const [width, height] = shape.size 17 | 18 | const bounds: TLBounds = { 19 | minX: x, 20 | maxX: x + width, 21 | minY: y, 22 | maxY: y + height, 23 | width, 24 | height, 25 | } as TLBounds 26 | 27 | return bounds 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/core-example/src/shapes/rect/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RectShape' 2 | export * from './RectUtil' 3 | -------------------------------------------------------------------------------- /examples/core-example/src/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | * { 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | overscroll-behavior: none; 8 | margin: 0px; 9 | padding: 0px; 10 | } 11 | 12 | .tldraw { 13 | position: fixed; 14 | top: 0px; 15 | left: 0px; 16 | right: 0px; 17 | bottom: 0px; 18 | width: 100%; 19 | height: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/core-example/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/core-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "experimentalDecorators": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src"], 21 | "references": [ 22 | { "path": "./tsconfig.node.json" }, 23 | { "path": "../../packages/tldraw" }, 24 | { "path": "../../packages/core" } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/core-example/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /examples/core-example/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react' 2 | import { defineConfig } from 'vite' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 5422, 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /examples/tldraw-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/tldraw-example/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # @tldraw/tldraw-example 6 | 7 | An simple example project for `@tldraw/tldraw`. 8 | 9 | To start this project: 10 | 11 | 1. Run `yarn` from the repository's root directory 12 | 2. Run `yarn start` from the repository's root directory 13 | 3. Open http://localhost:5420/ in your browser 14 | 15 | As an alternative to running `yarn start` you can also: 16 | 17 | 1. Run `yarn build` from the repository's root directory 18 | 2. Run `yarn dev` from the `examples/tldraw-example` directory 19 | -------------------------------------------------------------------------------- /examples/tldraw-example/card-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/tldraw-example/card-repo.png -------------------------------------------------------------------------------- /examples/tldraw-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tldraw - example 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/tldraw-example/public/card-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/tldraw-example/public/card-repo.png -------------------------------------------------------------------------------- /examples/tldraw-example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erawn/Quickpose/0252fbaff875ace4f623038dbc5ad9355f9284b7/examples/tldraw-example/public/favicon.ico -------------------------------------------------------------------------------- /examples/tldraw-example/src/api.tsx: -------------------------------------------------------------------------------- 1 | import { ColorStyle, TDShapeType, Tldraw, TldrawApp } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | declare const window: Window & { app: TldrawApp } 5 | 6 | export default function Api() { 7 | const rTldrawApp = React.useRef() 8 | 9 | const handleMount = React.useCallback((app: TldrawApp) => { 10 | rTldrawApp.current = app 11 | 12 | window.app = app 13 | 14 | app 15 | .createShapes({ 16 | id: 'rect1', 17 | type: TDShapeType.Rectangle, 18 | point: [100, 100], 19 | size: [200, 200], 20 | }) 21 | .selectAll() 22 | .nudge([1, 1], true) 23 | .duplicate() 24 | .select('rect1') 25 | .style({ color: ColorStyle.Blue }) 26 | .selectNone() 27 | }, []) 28 | 29 | return ( 30 |
31 | 32 |
33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/basic.tsx: -------------------------------------------------------------------------------- 1 | import { Tldraw } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | export default function Basic() { 5 | return ( 6 |
7 | 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/changing-id.tsx: -------------------------------------------------------------------------------- 1 | import { Tldraw } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | export default function ChangingId() { 5 | const [id, setId] = React.useState('example') 6 | 7 | React.useEffect(() => { 8 | const timeout = setTimeout(() => setId('example2'), 2000) 9 | 10 | return () => clearTimeout(timeout) 11 | }, []) 12 | 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/dark-mode.tsx: -------------------------------------------------------------------------------- 1 | import { Tldraw } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | export default function DarkMode() { 5 | return ( 6 |
7 | 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/embedded.tsx: -------------------------------------------------------------------------------- 1 | import { Tldraw } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | export default function Embedded() { 5 | return ( 6 |
7 |
16 | 17 |
18 | 19 |
27 | 28 |
29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/file-system.tsx: -------------------------------------------------------------------------------- 1 | import { Tldraw, useFileSystem } from '@tldraw/tldraw' 2 | import * as React from 'react' 3 | 4 | export default function FileSystem() { 5 | const fileSystemEvents = useFileSystem() 6 | 7 | // Use the Menu > File to create, open, and save .tldr files. 8 | 9 | return ( 10 |
11 | 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /examples/tldraw-example/src/iframe.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | export default function IFrame() { 4 | return ( 5 |
6 |