[improvement] examples (#264)
* Example project, fix bugs in readonly mode * Adds ui options
This commit is contained in:
parent
2441ca0c90
commit
fa38c0ef0d
25 changed files with 1566 additions and 731 deletions
180
README.md
180
README.md
|
@ -98,29 +98,51 @@ Internally, the `TLDraw` component's user interface uses this API to make change
|
||||||
|
|
||||||
The `TLDraw` React component is the [tldraw](https://tldraw.com) editor exported as a standalone component. You can control the editor through props, or through the `TLDrawState`'s imperative API. **All props are optional.**
|
The `TLDraw` React component is the [tldraw](https://tldraw.com) editor exported as a standalone component. You can control the editor through props, or through the `TLDrawState`'s imperative API. **All props are optional.**
|
||||||
|
|
||||||
| Prop | Type | Description |
|
| Prop | Type | Description |
|
||||||
| --------------- | ---------------- | -------------------------------------------------------------------------------------------- |
|
| ----------------- | ---------------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
| `id` | `string` | An id under which to persist the component's state. |
|
| `id` | `string` | An id under which to persist the component's state. |
|
||||||
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||||
| `currentPageId` | `string` | A current page id, referencing the `TLDrawDocument` object provided via the `document` prop. |
|
| `currentPageId` | `string` | A current page id, referencing the `TLDrawDocument` object provided via the `document` prop. |
|
||||||
| `onMount` | `Function` | Called when the editor first mounts, receiving the current `TLDrawState`. |
|
| `autofocus` | `boolean` | Whether the editor should immediately receive focus. Defaults to true. |
|
||||||
| `onPatch` | `Function` | Called when the state is updated via a patch. |
|
| `showMenu` | `boolean` | Whether to show the menu. |
|
||||||
| `onCommand` | `Function` | Called when the state is updated via a command. |
|
| `showPages` | `boolean` | Whether to show the pages menu. |
|
||||||
| `onPersist` | `Function` | Called when the state is persisted after an action. |
|
| `showStyles` | `boolean` | Whether to show the styles menu. |
|
||||||
| `onChange` | `Function` | Called when the `TLDrawState` updates for any reason. |
|
| `showTools` | `boolean` | Whether to show the tools. |
|
||||||
| `onUndo` | `Function` | Called when the `TLDrawState` updates after an undo. |
|
| `showUI` | `boolean` | Whether to show any UI other than the canvas. |
|
||||||
| `onRedo` | `Function` | Called when the `TLDrawState` updates after a redo. |
|
| `onMount` | `Function` | Called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||||
| `onUserChange` | `Function` | Called when the user's "presence" information changes. |
|
| `onPatch` | `Function` | Called when the state is updated via a patch. |
|
||||||
| `autofocus` | `boolean` | Whether the editor should immediately receive focus. Defaults to true. |
|
| `onCommand` | `Function` | Called when the state is updated via a command. |
|
||||||
| `showMenu` | `boolean` | Whether to show the menu. |
|
| `onPersist` | `Function` | Called when the state is persisted after an action. |
|
||||||
| `showPages` | `boolean` | Whether to show the pages menu. |
|
| `onChange` | `Function` | Called when the `TLDrawState` updates for any reason. |
|
||||||
| `showStyles` | `boolean` | Whether to show the styles menu. |
|
| `onUserChange` | `Function` | Called when the user's "presence" information changes. |
|
||||||
| `showTools` | `boolean` | Whether to show the tools. |
|
| `onUndo` | `Function` | Called when the `TLDrawState` updates after an undo. |
|
||||||
| `showUI` | `boolean` | Whether to show any UI other than the canvas. |
|
| `onRedo` | `Function` | Called when the `TLDrawState` updates after a redo. |
|
||||||
|
| `onSignIn` | `Function` | Called when the user selects Sign In from the menu. |
|
||||||
|
| `onSignOut` | `Function` | Called when the user selects Sign Out from the menu. |
|
||||||
|
| `onNewProject` | `Function` | Called when the user when the user creates a new project through the menu or through a keyboard shortcut. |
|
||||||
|
| `onSaveProject` | `Function` | Called when the user saves a project through the menu or through a keyboard shortcut. |
|
||||||
|
| `onSaveProjectAs` | `Function` | Called when the user saves a project as a new project through the menu or through a keyboard shortcut. |
|
||||||
|
| `onOpenProject` | `Function` | Called when the user opens new project through the menu or through a keyboard shortcut. |
|
||||||
|
|
||||||
|
> **Note**: For help with the file-related callbacks, see `useFileSystem`.
|
||||||
|
|
||||||
|
### `useFileSystem`
|
||||||
|
|
||||||
|
You can use the `useFileSystem` hook to get prepared callbacks for `onNewProject`, `onOpenProject`, `onSaveProject`, and `onSaveProjectAs`. These callbacks allow a user to save files via the [FileSystem](https://developer.mozilla.org/en-US/docs/Web/API/FileSystem) API.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { TLDraw, useFileSystem } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const fileSystemEvents = useFileSystem()
|
||||||
|
|
||||||
|
return <TLDraw {...fileSystemEvents} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `TLDrawDocument`
|
### `TLDrawDocument`
|
||||||
|
|
||||||
A `TLDrawDocument` is an object with three properties:
|
You can initialize or control the `<TLDraw>` component via its `document` property. A `TLDrawDocument` is an object with three properties:
|
||||||
|
|
||||||
- `id` - A unique ID for this document
|
- `id` - A unique ID for this document
|
||||||
- `pages` - A table of `TLDrawPage` objects
|
- `pages` - A table of `TLDrawPage` objects
|
||||||
|
@ -130,7 +152,7 @@ A `TLDrawDocument` is an object with three properties:
|
||||||
```ts
|
```ts
|
||||||
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
const tldocument: TLDrawDocument = {
|
const myDocument: TLDrawDocument = {
|
||||||
id: 'doc',
|
id: 'doc',
|
||||||
version: TLDrawState.version,
|
version: TLDrawState.version,
|
||||||
pages: {
|
pages: {
|
||||||
|
@ -152,9 +174,13 @@ const tldocument: TLDrawDocument = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return <TLDraw document={myDocument} />
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Tip:** TLDraw is built on [@tldraw/core](https://github.com/tldraw/core). The pages and pageStates in TLDraw are just objects containing `TLPage` and `TLPageState` objects from the core library. For more about these types, check out the [@tldraw/core](https://github.com/tldraw/core) documentation.
|
**Tip:** TLDraw is built on [@tldraw/core](https://github.com/tldraw/core). The pages and pageStates in TLDraw are objects containing `TLPage` and `TLPageState` objects from the core library. For more about these types, check out the [@tldraw/core](https://github.com/tldraw/core) documentation.
|
||||||
|
|
||||||
**Important:** In the `pages` object, each `TLPage` object must be keyed under its `id` property. Likewise, each `TLPageState` object must be keyed under its `id`. In addition, each `TLPageState` object must have an `id` that matches its corresponding page.
|
**Important:** In the `pages` object, each `TLPage` object must be keyed under its `id` property. Likewise, each `TLPageState` object must be keyed under its `id`. In addition, each `TLPageState` object must have an `id` that matches its corresponding page.
|
||||||
|
|
||||||
|
@ -179,7 +205,7 @@ Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawSha
|
||||||
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
||||||
| `isAspectRatioLocked` | `boolean` | (optional) True if the shape's aspect ratio is locked. |
|
| `isAspectRatioLocked` | `boolean` | (optional) True if the shape's aspect ratio is locked. |
|
||||||
|
|
||||||
> **Important:** In order for re-ordering to work correctly, a shape's `childIndex` values _must_ start from 1, not 0. The page or parent shape's "bottom-most" child should have a `childIndex` of 1.
|
> **Important:** In order for re-ordering to work, a shape's `childIndex` values _must_ start from 1, not 0. The page or parent shape's "bottom-most" child should have a `childIndex` of 1.
|
||||||
|
|
||||||
The `ShapeStyle` object is a common style API for all shapes.
|
The `ShapeStyle` object is a common style API for all shapes.
|
||||||
|
|
||||||
|
@ -268,71 +294,81 @@ function App() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `TLDrawState` API is too large to document here. To view documentation for the API, build the documentation by running `yarn docs` from the root folder and open the file at `/packages/tldraw/docs/classes/TLDrawState.html` in your browser.
|
To view the full documentation of the `TLDrawState` API, generate the project's documentation by running `yarn docs` from the root folder, then open the file at:
|
||||||
|
|
||||||
|
```
|
||||||
|
/packages/tldraw/docs/classes/TLDrawState.html
|
||||||
|
```
|
||||||
|
|
||||||
Here are some useful methods:
|
Here are some useful methods:
|
||||||
|
|
||||||
| Method | Description |
|
- `loadDocument`
|
||||||
| ----------------- | ----------- |
|
- `select`
|
||||||
| `loadDocument` | |
|
- `selectAll`
|
||||||
| `select` | |
|
- `selectNone`
|
||||||
| `selectAll` | |
|
- `delete`
|
||||||
| `selectNone` | |
|
- `deleteAll`
|
||||||
| `delete` | |
|
- `deletePage`
|
||||||
| `deleteAll` | |
|
- `changePage`
|
||||||
| `deletePage` | |
|
- `cut`
|
||||||
| `changePage` | |
|
- `copy`
|
||||||
| `cut` | |
|
- `paste`
|
||||||
| `copy` | |
|
- `copyJson`
|
||||||
| `paste` | |
|
- `copySvg`
|
||||||
| `copyJson` | |
|
- `undo`
|
||||||
| `copySvg` | |
|
- `redo`
|
||||||
| `undo` | |
|
- `zoomIn`
|
||||||
| `redo` | |
|
- `zoomOut`
|
||||||
| `zoomIn` | |
|
- `zoomToContent`
|
||||||
| `zoomOut` | |
|
- `zoomToSelection`
|
||||||
| `zoomToContent` | |
|
- `zoomToFit`
|
||||||
| `zoomToSelection` | |
|
- `zoomTo`
|
||||||
| `zoomToFit` | |
|
- `resetZoom`
|
||||||
| `zoomTo` | |
|
- `setCamera`
|
||||||
| `resetZoom` | |
|
- `resetCamera`
|
||||||
| `setCamera` | |
|
- `align`
|
||||||
| `resetCamera` | |
|
- `distribute`
|
||||||
| `align` | |
|
- `stretch`
|
||||||
| `distribute` | |
|
- `nudge`
|
||||||
| `stretch` | |
|
- `duplicate`
|
||||||
| `nudge` | |
|
- `flipHorizontal`
|
||||||
| `duplicate` | |
|
- `flipVertical`
|
||||||
| `flipHorizontal` | |
|
- `rotate`
|
||||||
| `flipVertical` | |
|
- `style`
|
||||||
| `rotate` | |
|
- `group`
|
||||||
| `style` | |
|
- `ungroup`
|
||||||
| `group` | |
|
- `createShapes`
|
||||||
| `ungroup` | |
|
- `updateShapes`
|
||||||
| `createShapes` | |
|
- `updateDocument`
|
||||||
| `updateShapes` | |
|
- `updateUsers`
|
||||||
| `updateDocument` | |
|
- `removeUser`
|
||||||
| `updateUsers` | |
|
- `setSetting`
|
||||||
| `removeUser` | |
|
- `selectTool`
|
||||||
| `setSetting` | |
|
- `cancel`
|
||||||
| `selectTool` | |
|
|
||||||
| `cancel` | |
|
Check the generated docs, source or the TypeScript types for more on these and other methods.
|
||||||
|
|
||||||
## Local Development
|
## Local Development
|
||||||
|
|
||||||
|
From the root folder:
|
||||||
|
|
||||||
- Run `yarn` to install dependencies.
|
- Run `yarn` to install dependencies.
|
||||||
|
|
||||||
- Run `yarn start` to start the development server for the package and for the example.
|
- Run `yarn start` to start the development server for the package and for the example.
|
||||||
|
|
||||||
- Open `localhost:5420` to view the example project.
|
- Open `localhost:5420` to view the example project.
|
||||||
|
|
||||||
|
**Note:** The multiplayer examples and endpoints currently require an API key from [Liveblocks](https://liveblocks.io/), however the storage services that are used in TLDraw are currently in alpha and (as of November 2021) not accessible to the general public. You won't be able to authenticate and run these parts of the project.
|
||||||
|
|
||||||
|
Other scripts:
|
||||||
|
|
||||||
- Run `yarn test` to execute unit tests via [Jest](https://jestjs.io).
|
- Run `yarn test` to execute unit tests via [Jest](https://jestjs.io).
|
||||||
|
|
||||||
- Run `yarn docs` to build the docs via [ts-doc](https://typedoc.org/).
|
- Run `yarn docs` to build the docs via [ts-doc](https://typedoc.org/).
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
See the `example` folder.
|
See the `example` folder for examples of how to use the `<TLDraw/>` component.
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
@ -346,7 +382,9 @@ Want to connect with other devs? Visit the [Discord channel](https://discord.gg/
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
This project is licensed under MIT. If you're using the library in a commercial product, please consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
|
This project is licensed under MIT.
|
||||||
|
|
||||||
|
If you're using the library in a commercial product, please consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
import esbuild from 'esbuild'
|
import esbuild from 'esbuild'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
import { createRequire } from 'module'
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
const pkg = createRequire(import.meta.url)('../package.json')
|
const pkg = createRequire(import.meta.url)('../package.json')
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if (fs.existsSync('./dist')) {
|
|
||||||
fs.rmSync('./dist', { recursive: true }, (e) => {
|
|
||||||
if (e) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
esbuild.buildSync({
|
esbuild.buildSync({
|
||||||
entryPoints: ['./src/index.tsx'],
|
entryPoints: ['./src/index.tsx'],
|
||||||
|
@ -27,15 +21,17 @@ async function main() {
|
||||||
tsconfig: './tsconfig.json',
|
tsconfig: './tsconfig.json',
|
||||||
define: {
|
define: {
|
||||||
'process.env.NODE_ENV': '"production"',
|
'process.env.NODE_ENV': '"production"',
|
||||||
|
'process.env.LIVEBLOCKS_PUBLIC_API_KEY': `"${process.env.LIVEBLOCKS_PUBLIC_API_KEY}"`,
|
||||||
},
|
},
|
||||||
metafile: false,
|
metafile: false,
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
fs.copyFile('./src/index.html', './dist/index.html', (err) => {
|
fs.readdirSync('./src/public').forEach((file) =>
|
||||||
if (err) throw err
|
fs.copyFile(path.join('./src/public', file), path.join('./dist', file), (err) => {
|
||||||
})
|
if (err) throw err
|
||||||
|
})
|
||||||
|
)
|
||||||
console.log(`✔ ${pkg.name}: Build completed.`)
|
console.log(`✔ ${pkg.name}: Build completed.`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`× ${pkg.name}: Build failed due to an error.`)
|
console.log(`× ${pkg.name}: Build failed due to an error.`)
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
import esbuildServe from 'esbuild-serve'
|
import esbuildServe from 'esbuild-serve'
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
if (!fs.existsSync('./dist')) {
|
if (fs.existsSync('./dist')) {
|
||||||
fs.mkdirSync('./dist')
|
fs.rmSync('./dist', { recursive: true }, (e) => {
|
||||||
|
if (e) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.copyFile('./src/index.html', './dist/index.html', (err) => {
|
fs.mkdirSync('./dist')
|
||||||
if (err) throw err
|
|
||||||
})
|
fs.readdirSync('./src/public').forEach((file) =>
|
||||||
|
fs.copyFile(path.join('./src/public', file), path.join('./dist', file), (err) => {
|
||||||
|
if (err) throw err
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await esbuildServe(
|
await esbuildServe(
|
||||||
|
|
30
example/src/api.tsx
Normal file
30
example/src/api.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLDraw, TLDrawState, TLDrawShapeType, ColorStyle } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
export default function Api(): JSX.Element {
|
||||||
|
const rTLDrawState = React.useRef<TLDrawState>()
|
||||||
|
|
||||||
|
const handleMount = React.useCallback((state: TLDrawState) => {
|
||||||
|
rTLDrawState.current = state
|
||||||
|
|
||||||
|
state
|
||||||
|
.createShapes({
|
||||||
|
id: 'rect1',
|
||||||
|
type: TLDrawShapeType.Rectangle,
|
||||||
|
point: [100, 100],
|
||||||
|
size: [200, 200],
|
||||||
|
})
|
||||||
|
.selectAll()
|
||||||
|
.nudge([1, 1], true)
|
||||||
|
.duplicate()
|
||||||
|
.select('rect1')
|
||||||
|
.style({ color: ColorStyle.Blue })
|
||||||
|
.selectNone()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw onMount={handleMount} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -2,29 +2,54 @@ import * as React from 'react'
|
||||||
import { Switch, Route, Link } from 'react-router-dom'
|
import { Switch, Route, Link } from 'react-router-dom'
|
||||||
import Basic from './basic'
|
import Basic from './basic'
|
||||||
import ReadOnly from './readonly'
|
import ReadOnly from './readonly'
|
||||||
import Controlled from './controlled'
|
import PropsControl from './props-control'
|
||||||
import Imperative from './imperative'
|
import ApiControl from './api-control'
|
||||||
|
import LoadingFiles from './loading-files'
|
||||||
import Embedded from './embedded'
|
import Embedded from './embedded'
|
||||||
import NoSizeEmbedded from './no-size-embedded'
|
import NoSizeEmbedded from './no-size-embedded'
|
||||||
import { Multiplayer } from './multiplayer'
|
|
||||||
import ChangingId from './changing-id'
|
import ChangingId from './changing-id'
|
||||||
|
import Persisted from './persisted'
|
||||||
|
import Develop from './develop'
|
||||||
|
import Api from './api'
|
||||||
|
import FileSystem from './file-system'
|
||||||
|
import UIOptions from './ui-options'
|
||||||
|
import { Multiplayer } from './multiplayer'
|
||||||
import './styles.css'
|
import './styles.css'
|
||||||
|
|
||||||
export default function App(): JSX.Element {
|
export default function App(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
|
<img className="hero" src="./card-repo.png" />
|
||||||
<Switch>
|
<Switch>
|
||||||
|
<Route path="/basic">
|
||||||
|
<Develop />
|
||||||
|
</Route>
|
||||||
<Route path="/basic">
|
<Route path="/basic">
|
||||||
<Basic />
|
<Basic />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path="/ui-options">
|
||||||
|
<UIOptions />
|
||||||
|
</Route>
|
||||||
|
<Route path="/persisted">
|
||||||
|
<Persisted />
|
||||||
|
</Route>
|
||||||
|
<Route path="/loading-files">
|
||||||
|
<LoadingFiles />
|
||||||
|
</Route>
|
||||||
|
<Route path="/file-system">
|
||||||
|
<FileSystem />
|
||||||
|
</Route>
|
||||||
|
<Route path="/api">
|
||||||
|
<Api />
|
||||||
|
</Route>
|
||||||
<Route path="/readonly">
|
<Route path="/readonly">
|
||||||
<ReadOnly />
|
<ReadOnly />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/controlled">
|
<Route path="/controlled">
|
||||||
<Controlled />
|
<PropsControl />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/imperative">
|
<Route path="/imperative">
|
||||||
<Imperative />
|
<ApiControl />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/changing-id">
|
<Route path="/changing-id">
|
||||||
<ChangingId />
|
<ChangingId />
|
||||||
|
@ -39,30 +64,52 @@ export default function App(): JSX.Element {
|
||||||
<Multiplayer />
|
<Multiplayer />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/">
|
<Route path="/">
|
||||||
<ul>
|
<ul className="links">
|
||||||
<li>
|
<li>
|
||||||
<Link to="/basic">basic</Link>
|
<Link to="/basic">Develop</Link>
|
||||||
|
</li>
|
||||||
|
<hr />
|
||||||
|
<li>
|
||||||
|
<Link to="/basic">Basic</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/readonly">readonly</Link>
|
<Link to="/ui-options">UI Options</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/controlled">controlled</Link>
|
<Link to="/persisted">Persisting State with an ID</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/imperative">imperative</Link>
|
<Link to="/file-system">Using the File System</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/changing-id">changing id</Link>
|
<Link to="/readonly">Readonly Mode</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/embedded">embedded</Link>
|
<Link to="/loading-files">Loading Files</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/no-size-embedded">embedded (no size)</Link>
|
<Link to="/file-system">Using the File System</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/multiplayer">multiplayer</Link>
|
<Link to="/controlled">Controlled via Props</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/api">Using the TLDrawState API</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/imperative">Controlled via TLDrawState API</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/changing-id">Changing ID</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/embedded">Embedded</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/no-size-embedded">Embedded (without explicit size)</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/multiplayer">Multiplayer</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Route>
|
</Route>
|
||||||
|
|
|
@ -1,561 +0,0 @@
|
||||||
{
|
|
||||||
"id": "doc",
|
|
||||||
"pages": {
|
|
||||||
"page": {
|
|
||||||
"id": "page",
|
|
||||||
"name": "Page 1",
|
|
||||||
"childIndex": 1,
|
|
||||||
"shapes": {
|
|
||||||
"58343232-2843-48ff-214c-f801ba274f24": {
|
|
||||||
"id": "58343232-2843-48ff-214c-f801ba274f24",
|
|
||||||
"type": "rectangle",
|
|
||||||
"name": "Rectangle",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 1,
|
|
||||||
"point": [
|
|
||||||
653.82,
|
|
||||||
158.58
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
146.33,
|
|
||||||
213.43
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Green",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"a755e702-548c-4ae3-0f62-307ced48d060": {
|
|
||||||
"id": "a755e702-548c-4ae3-0f62-307ced48d060",
|
|
||||||
"type": "ellipse",
|
|
||||||
"name": "Ellipse",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 2,
|
|
||||||
"point": [
|
|
||||||
316.64,
|
|
||||||
164.11
|
|
||||||
],
|
|
||||||
"radius": [
|
|
||||||
73.7000000000001,
|
|
||||||
74.86500000000002
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Blue",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2ac5ddca-0fdd-4744-3c5b-dc63d9804993": {
|
|
||||||
"id": "2ac5ddca-0fdd-4744-3c5b-dc63d9804993",
|
|
||||||
"type": "rectangle",
|
|
||||||
"name": "Rectangle",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 2,
|
|
||||||
"point": [
|
|
||||||
495.88,
|
|
||||||
466.31
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
149.87,
|
|
||||||
134.37
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Red",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"8f7c6768-8124-427f-0795-5b11b8e55cb3": {
|
|
||||||
"id": "8f7c6768-8124-427f-0795-5b11b8e55cb3",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 3,
|
|
||||||
"point": [
|
|
||||||
663.96,
|
|
||||||
388.01
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
0,
|
|
||||||
66.018
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "37f1f650-7368-41df-2489-b980efab5b7d"
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
37.531,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "284b2bbb-92eb-4f2b-255d-4b5a78e8a991"
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
18.765,
|
|
||||||
33.009
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"10e6dade-7fab-42f8-0fc3-2091f8b5cb1f": {
|
|
||||||
"id": "10e6dade-7fab-42f8-0fc3-2091f8b5cb1f",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 4,
|
|
||||||
"point": [
|
|
||||||
479.98,
|
|
||||||
235.6
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
157.84,
|
|
||||||
18.972
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "500844a2-1dc9-4f58-0837-1a0caf446604"
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "a9c71649-7729-47c5-0e3c-37455ecd837c"
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
78.921,
|
|
||||||
9.4859
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"0ef85012-7e75-4fdf-119f-18e615609335": {
|
|
||||||
"id": "0ef85012-7e75-4fdf-119f-18e615609335",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page",
|
|
||||||
"childIndex": 5,
|
|
||||||
"point": [
|
|
||||||
414.98,
|
|
||||||
326.35
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "aea8ac9a-0527-47ea-1d50-43862270759a"
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
74.457,
|
|
||||||
123.96
|
|
||||||
],
|
|
||||||
"canBind": true,
|
|
||||||
"bindingId": "be4cee5e-484d-4908-1079-a93aba785bd1"
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
37.228,
|
|
||||||
61.982
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bindings": {
|
|
||||||
"284b2bbb-92eb-4f2b-255d-4b5a78e8a991": {
|
|
||||||
"id": "284b2bbb-92eb-4f2b-255d-4b5a78e8a991",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "8f7c6768-8124-427f-0795-5b11b8e55cb3",
|
|
||||||
"handleId": "end",
|
|
||||||
"toId": "58343232-2843-48ff-214c-f801ba274f24",
|
|
||||||
"point": [
|
|
||||||
0.67161,
|
|
||||||
0.5518
|
|
||||||
],
|
|
||||||
"distance": 16
|
|
||||||
},
|
|
||||||
"37f1f650-7368-41df-2489-b980efab5b7d": {
|
|
||||||
"id": "37f1f650-7368-41df-2489-b980efab5b7d",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "8f7c6768-8124-427f-0795-5b11b8e55cb3",
|
|
||||||
"handleId": "start",
|
|
||||||
"toId": "2ac5ddca-0fdd-4744-3c5b-dc63d9804993",
|
|
||||||
"point": [
|
|
||||||
0.68144,
|
|
||||||
0.58126
|
|
||||||
],
|
|
||||||
"distance": 18.210000000000036
|
|
||||||
},
|
|
||||||
"a9c71649-7729-47c5-0e3c-37455ecd837c": {
|
|
||||||
"id": "a9c71649-7729-47c5-0e3c-37455ecd837c",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "10e6dade-7fab-42f8-0fc3-2091f8b5cb1f",
|
|
||||||
"handleId": "end",
|
|
||||||
"toId": "a755e702-548c-4ae3-0f62-307ced48d060",
|
|
||||||
"point": [
|
|
||||||
0.84807,
|
|
||||||
0.4752
|
|
||||||
],
|
|
||||||
"distance": 16
|
|
||||||
},
|
|
||||||
"500844a2-1dc9-4f58-0837-1a0caf446604": {
|
|
||||||
"id": "500844a2-1dc9-4f58-0837-1a0caf446604",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "10e6dade-7fab-42f8-0fc3-2091f8b5cb1f",
|
|
||||||
"handleId": "start",
|
|
||||||
"toId": "58343232-2843-48ff-214c-f801ba274f24",
|
|
||||||
"point": [
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"distance": 16
|
|
||||||
},
|
|
||||||
"be4cee5e-484d-4908-1079-a93aba785bd1": {
|
|
||||||
"id": "be4cee5e-484d-4908-1079-a93aba785bd1",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "0ef85012-7e75-4fdf-119f-18e615609335",
|
|
||||||
"handleId": "end",
|
|
||||||
"toId": "2ac5ddca-0fdd-4744-3c5b-dc63d9804993",
|
|
||||||
"point": [
|
|
||||||
0.38339,
|
|
||||||
0.55439
|
|
||||||
],
|
|
||||||
"distance": 16
|
|
||||||
},
|
|
||||||
"aea8ac9a-0527-47ea-1d50-43862270759a": {
|
|
||||||
"id": "aea8ac9a-0527-47ea-1d50-43862270759a",
|
|
||||||
"type": "arrow",
|
|
||||||
"fromId": "0ef85012-7e75-4fdf-119f-18e615609335",
|
|
||||||
"handleId": "start",
|
|
||||||
"toId": "a755e702-548c-4ae3-0f62-307ced48d060",
|
|
||||||
"point": [
|
|
||||||
0.57016,
|
|
||||||
0.83242
|
|
||||||
],
|
|
||||||
"distance": 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"page1": {
|
|
||||||
"id": "page1",
|
|
||||||
"shapes": {
|
|
||||||
"fa7a50a0-00d3-432c-3e97-585a9d97b6c6": {
|
|
||||||
"id": "fa7a50a0-00d3-432c-3e97-585a9d97b6c6",
|
|
||||||
"type": "rectangle",
|
|
||||||
"name": "Rectangle",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 1,
|
|
||||||
"point": [
|
|
||||||
1757.9,
|
|
||||||
912.27
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
92.549,
|
|
||||||
78.049
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"radius": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Indigo",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"76a961f3-9cad-4a44-3790-74d8e46c918b": {
|
|
||||||
"id": "76a961f3-9cad-4a44-3790-74d8e46c918b",
|
|
||||||
"type": "rectangle",
|
|
||||||
"name": "Rectangle",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 2,
|
|
||||||
"point": [
|
|
||||||
2054.6,
|
|
||||||
956.4
|
|
||||||
],
|
|
||||||
"size": [
|
|
||||||
53.205,
|
|
||||||
136.52
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"radius": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Red",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"5e9a929d-6fa4-4176-3f60-9a0d206a986b": {
|
|
||||||
"id": "5e9a929d-6fa4-4176-3f60-9a0d206a986b",
|
|
||||||
"type": "ellipse",
|
|
||||||
"name": "Ellipse",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 3,
|
|
||||||
"point": [
|
|
||||||
1821.3,
|
|
||||||
1044.1
|
|
||||||
],
|
|
||||||
"radius": [
|
|
||||||
34.65772824556598,
|
|
||||||
39.066377761684635
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"style": {
|
|
||||||
"color": "Green",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"d6e6f6a8-8472-4a05-352e-3749bc75f487": {
|
|
||||||
"id": "d6e6f6a8-8472-4a05-352e-3749bc75f487",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 4,
|
|
||||||
"point": [
|
|
||||||
1873.779,
|
|
||||||
968.915
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
71.321,
|
|
||||||
20.225
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
-8.5265e-14,
|
|
||||||
2.1316e-14
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
35.661,
|
|
||||||
10.112
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ede2b8f7-2ce0-4b79-2770-a5d5b174f7d4": {
|
|
||||||
"id": "ede2b8f7-2ce0-4b79-2770-a5d5b174f7d4",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 5,
|
|
||||||
"point": [
|
|
||||||
1781.2,
|
|
||||||
1003.8
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
25.925,
|
|
||||||
43.226
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
12.963,
|
|
||||||
21.613
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"8edca8a7-0c6d-414b-0ff0-e00c32733b46": {
|
|
||||||
"id": "8edca8a7-0c6d-414b-0ff0-e00c32733b46",
|
|
||||||
"type": "arrow",
|
|
||||||
"name": "Arrow",
|
|
||||||
"parentId": "page1",
|
|
||||||
"childIndex": 6,
|
|
||||||
"point": [
|
|
||||||
1912.9,
|
|
||||||
1065.7669999999998
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"bend": 0,
|
|
||||||
"handles": {
|
|
||||||
"start": {
|
|
||||||
"id": "start",
|
|
||||||
"index": 0,
|
|
||||||
"point": [
|
|
||||||
0,
|
|
||||||
12.333
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"id": "end",
|
|
||||||
"index": 1,
|
|
||||||
"point": [
|
|
||||||
36.712,
|
|
||||||
8.3489e-14
|
|
||||||
],
|
|
||||||
"canBind": true
|
|
||||||
},
|
|
||||||
"bend": {
|
|
||||||
"id": "bend",
|
|
||||||
"index": 2,
|
|
||||||
"point": [
|
|
||||||
18.356,
|
|
||||||
6.1665
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"decorations": {
|
|
||||||
"end": "Arrow"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"color": "Black",
|
|
||||||
"size": "Medium",
|
|
||||||
"isFilled": true,
|
|
||||||
"dash": "Draw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bindings": {},
|
|
||||||
"name": "Page 2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pageStates": {
|
|
||||||
"page": {
|
|
||||||
"id": "page",
|
|
||||||
"selectedIds": [],
|
|
||||||
"camera": {
|
|
||||||
"point": [
|
|
||||||
-257,
|
|
||||||
-61
|
|
||||||
],
|
|
||||||
"zoom": 1
|
|
||||||
},
|
|
||||||
"editingId": null
|
|
||||||
},
|
|
||||||
"page1": {
|
|
||||||
"id": "page1",
|
|
||||||
"selectedIds": [
|
|
||||||
"76a961f3-9cad-4a44-3790-74d8e46c918b"
|
|
||||||
],
|
|
||||||
"camera": {
|
|
||||||
"point": [
|
|
||||||
-1620.9073790458274,
|
|
||||||
-841.1990943476605
|
|
||||||
],
|
|
||||||
"zoom": 1.5319298689588086
|
|
||||||
},
|
|
||||||
"currentParentId": "page1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,10 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Editor from './components/editor'
|
import { TLDraw } from '@tldraw/tldraw'
|
||||||
|
|
||||||
export default function Basic(): JSX.Element {
|
export default function Basic(): JSX.Element {
|
||||||
return <Editor />
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import * as React from 'react'
|
|
||||||
import { TLDraw, TLDrawProps, TLDrawState, useFileSystem } from '@tldraw/tldraw'
|
|
||||||
|
|
||||||
export default function Editor(props: TLDrawProps): JSX.Element {
|
|
||||||
const rTLDrawState = React.useRef<TLDrawState>()
|
|
||||||
|
|
||||||
const fileSystemEvents = useFileSystem()
|
|
||||||
|
|
||||||
const handleMount = React.useCallback((state: TLDrawState) => {
|
|
||||||
rTLDrawState.current = state
|
|
||||||
props.onMount?.(state)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
window.state = state
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onSignIn = React.useCallback((state: TLDrawState) => {
|
|
||||||
// Sign in?
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onSignOut = React.useCallback((state: TLDrawState) => {
|
|
||||||
// Sign out?
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="tldraw">
|
|
||||||
<TLDraw
|
|
||||||
id="tldraw1"
|
|
||||||
{...props}
|
|
||||||
onMount={handleMount}
|
|
||||||
onSignIn={onSignIn}
|
|
||||||
onSignOut={onSignOut}
|
|
||||||
{...fileSystemEvents}
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
41
example/src/develop.tsx
Normal file
41
example/src/develop.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLDraw, TLDrawState, useFileSystem } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
declare const window: Window & { state: TLDrawState }
|
||||||
|
|
||||||
|
export default function Develop(): JSX.Element {
|
||||||
|
const rTLDrawState = React.useRef<TLDrawState>()
|
||||||
|
|
||||||
|
const fileSystemEvents = useFileSystem()
|
||||||
|
|
||||||
|
const handleMount = React.useCallback((state: TLDrawState) => {
|
||||||
|
window.state = state
|
||||||
|
rTLDrawState.current = state
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSignOut = React.useCallback(() => {
|
||||||
|
// noop
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSignIn = React.useCallback(() => {
|
||||||
|
// noop
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handlePersist = React.useCallback(() => {
|
||||||
|
// noop
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw
|
||||||
|
id="develop"
|
||||||
|
{...fileSystemEvents}
|
||||||
|
onMount={handleMount}
|
||||||
|
onSignIn={handleSignIn}
|
||||||
|
onSignOut={handleSignOut}
|
||||||
|
onPersist={handlePersist}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ export default function Embedded(): JSX.Element {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TLDraw id="small6" />
|
<TLDraw id="embedded" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
14
example/src/file-system.tsx
Normal file
14
example/src/file-system.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLDraw, useFileSystem } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
export default function FileSystem(): JSX.Element {
|
||||||
|
const fileSystemEvents = useFileSystem()
|
||||||
|
|
||||||
|
// Use the Menu > File to create, open, and save .tldr files.
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw {...fileSystemEvents} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
17
example/src/loading-files.tsx
Normal file
17
example/src/loading-files.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { TLDraw, TLDrawFile } from '@tldraw/tldraw'
|
||||||
|
import * as React from 'react'
|
||||||
|
|
||||||
|
export default function LoadingFiles(): JSX.Element {
|
||||||
|
const [file, setFile] = React.useState<TLDrawFile>()
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
async function loadFile(): Promise<void> {
|
||||||
|
const file = await fetch('Example.tldr').then((response) => response.json())
|
||||||
|
setFile(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadFile()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <TLDraw document={file?.document} />
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
export function Cursors() {
|
|
||||||
return <div>hi</div>
|
|
||||||
}
|
|
|
@ -1,11 +1,6 @@
|
||||||
import { TLDraw } from '@tldraw/tldraw'
|
import { TLDraw } from '@tldraw/tldraw'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
/**
|
|
||||||
* This is bugged until Radix gives me an option to control
|
|
||||||
* where menus are portaled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default function NoSizeEmbedded(): JSX.Element {
|
export default function NoSizeEmbedded(): JSX.Element {
|
||||||
return <TLDraw />
|
return <TLDraw />
|
||||||
}
|
}
|
||||||
|
|
10
example/src/persisted.tsx
Normal file
10
example/src/persisted.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLDraw } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
export default function Persisted(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw id="tldraw-persisted-id" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
1165
example/src/public/Example.tldr
Normal file
1165
example/src/public/Example.tldr
Normal file
File diff suppressed because it is too large
Load diff
BIN
example/src/public/card-repo.png
Normal file
BIN
example/src/public/card-repo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
|
@ -1,6 +1,21 @@
|
||||||
|
import { TLDraw, TLDrawFile } from '@tldraw/tldraw'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Editor from './components/editor'
|
|
||||||
|
|
||||||
export default function Basic(): JSX.Element {
|
export default function ReadOnly(): JSX.Element {
|
||||||
return <Editor readOnly />
|
const [file, setFile] = React.useState<TLDrawFile>()
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
async function loadFile(): Promise<void> {
|
||||||
|
const file = await fetch('Example.tldr').then((response) => response.json())
|
||||||
|
setFile(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadFile()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw readOnly document={file?.document} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ body {
|
||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tldraw {
|
.tldraw {
|
||||||
|
@ -18,3 +20,29 @@ body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: grid;
|
||||||
|
width: fit-content;
|
||||||
|
list-style: none;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links a {
|
||||||
|
padding: 0.5em 0.7em;
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.2em;
|
||||||
|
display: block;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links a:hover {
|
||||||
|
background-color: rgba(144, 144, 144, 0.1);
|
||||||
|
}
|
||||||
|
|
17
example/src/ui-options.tsx
Normal file
17
example/src/ui-options.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLDraw } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
export default function UIOptions(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="tldraw">
|
||||||
|
<TLDraw
|
||||||
|
showUI={true}
|
||||||
|
showMenu={true}
|
||||||
|
showPages={true}
|
||||||
|
showStyles={true}
|
||||||
|
showTools={true}
|
||||||
|
showZoom={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -475,6 +475,7 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
|
||||||
* @param bounds
|
* @param bounds
|
||||||
*/
|
*/
|
||||||
updateBounds = (bounds: TLBounds) => {
|
updateBounds = (bounds: TLBounds) => {
|
||||||
|
if (this.readOnly) return
|
||||||
this.bounds = { ...bounds }
|
this.bounds = { ...bounds }
|
||||||
if (this.session) {
|
if (this.session) {
|
||||||
this.session.updateViewport(this.viewport)
|
this.session.updateViewport(this.viewport)
|
||||||
|
@ -487,6 +488,8 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
|
||||||
* @param id [string]
|
* @param id [string]
|
||||||
*/
|
*/
|
||||||
setEditingId = (id?: string) => {
|
setEditingId = (id?: string) => {
|
||||||
|
if (this.readOnly) return
|
||||||
|
|
||||||
this.editingStartTime = Date.now()
|
this.editingStartTime = Date.now()
|
||||||
this.patchState(
|
this.patchState(
|
||||||
{
|
{
|
||||||
|
@ -640,7 +643,7 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
|
||||||
* @param tool The tool to select, or "select".
|
* @param tool The tool to select, or "select".
|
||||||
*/
|
*/
|
||||||
selectTool = (type: ToolType): this => {
|
selectTool = (type: ToolType): this => {
|
||||||
if (this.session) return this
|
if (this.readOnly || this.session) return this
|
||||||
|
|
||||||
const tool = this.tools[type]
|
const tool = this.tools[type]
|
||||||
|
|
||||||
|
@ -1145,6 +1148,7 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
|
||||||
* @param pageId (optional) The new page's id.
|
* @param pageId (optional) The new page's id.
|
||||||
*/
|
*/
|
||||||
createPage = (id?: string): this => {
|
createPage = (id?: string): this => {
|
||||||
|
if (this.readOnly) return this
|
||||||
return this.setState(
|
return this.setState(
|
||||||
Commands.createPage(this.state, [-this.bounds.width / 2, -this.bounds.height / 2], id)
|
Commands.createPage(this.state, [-this.bounds.width / 2, -this.bounds.height / 2], id)
|
||||||
)
|
)
|
||||||
|
@ -1164,6 +1168,7 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
|
||||||
* @param name The page's new name
|
* @param name The page's new name
|
||||||
*/
|
*/
|
||||||
renamePage = (pageId: string, name: string): this => {
|
renamePage = (pageId: string, name: string): this => {
|
||||||
|
if (this.readOnly) return this
|
||||||
return this.setState(Commands.renamePage(this.state, pageId, name))
|
return this.setState(Commands.renamePage(this.state, pageId, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { TLDrawState } from '@tldraw/tldraw'
|
import { TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
export function useFileSystem(state: TLDrawState) {
|
export function useFileSystem() {
|
||||||
const promptSaveBeforeChange = React.useCallback(async () => {
|
const promptSaveBeforeChange = React.useCallback(async (state: TLDrawState) => {
|
||||||
if (state.isDirty) {
|
if (state.isDirty) {
|
||||||
if (state.fileSystemHandle) {
|
if (state.fileSystemHandle) {
|
||||||
if (window.confirm('Do you want to save changes to your current project?')) {
|
if (window.confirm('Do you want to save changes to your current project?')) {
|
||||||
|
@ -14,25 +14,31 @@ export function useFileSystem(state: TLDrawState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [state])
|
}, [])
|
||||||
|
|
||||||
const onNewProject = React.useCallback(async () => {
|
const onNewProject = React.useCallback(
|
||||||
await promptSaveBeforeChange()
|
async (state: TLDrawState) => {
|
||||||
state.newProject()
|
await promptSaveBeforeChange(state)
|
||||||
}, [state, promptSaveBeforeChange])
|
state.newProject()
|
||||||
|
},
|
||||||
|
[promptSaveBeforeChange]
|
||||||
|
)
|
||||||
|
|
||||||
const onSaveProject = React.useCallback(() => {
|
const onSaveProject = React.useCallback((state: TLDrawState) => {
|
||||||
state.saveProject()
|
state.saveProject()
|
||||||
}, [state])
|
}, [])
|
||||||
|
|
||||||
const onSaveProjectAs = React.useCallback(() => {
|
const onSaveProjectAs = React.useCallback((state: TLDrawState) => {
|
||||||
state.saveProjectAs()
|
state.saveProjectAs()
|
||||||
}, [state])
|
}, [])
|
||||||
|
|
||||||
const onOpenProject = React.useCallback(async () => {
|
const onOpenProject = React.useCallback(
|
||||||
await promptSaveBeforeChange()
|
async (state: TLDrawState) => {
|
||||||
state.openProject()
|
await promptSaveBeforeChange(state)
|
||||||
}, [state, promptSaveBeforeChange])
|
state.openProject()
|
||||||
|
},
|
||||||
|
[promptSaveBeforeChange]
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onNewProject,
|
onNewProject,
|
||||||
|
|
Loading…
Reference in a new issue