[improvement] Migrations (#217)
* Add better migrations * Improves migrations * rename dev to example * renames migrate * Removes workers from git * Remove rogue dependency * Fix dropdown navigation by keyboard
This commit is contained in:
parent
cb777c85d1
commit
fe2e3c81fe
53 changed files with 516 additions and 271 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -8,3 +8,7 @@ docs/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
coverage
|
coverage
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
www/public/worker-*
|
||||||
|
www/public/sw.js
|
||||||
|
www/public/sw.js.map
|
||||||
|
|
193
README.md
193
README.md
|
@ -1,19 +1,23 @@
|
||||||
|
<div style="text-align: center; transform: scale(.5);">
|
||||||
|
<img src="card-repo.png"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
# @tldraw/tldraw
|
# @tldraw/tldraw
|
||||||
|
|
||||||
> `This library is not yet released and these docs are partially out of date!`
|
This package contains the [tldraw](https://tldraw.com) editor as a React component named `<TLDraw>`. You can use this package to embed the editor in any React application.
|
||||||
|
|
||||||
This package contains the [tldraw](https://tldraw.com) editor as a standalone React component.
|
🎨 Want to build your own tldraw-ish app instead? Try [@tldraw/core](https://github.com/tldraw/core).
|
||||||
|
|
||||||
|
💕 Love this library? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
Use your package manager of choice to install `@tldraw/core` and its peer dependencies.
|
||||||
npm i @tldraw/tldraw
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn add @tldraw/tldraw
|
yarn add @tldraw/tldraw
|
||||||
|
# or
|
||||||
|
npm i @tldraw/tldraw
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
@ -28,31 +32,70 @@ function App() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can control the `TLDraw` component through props:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { TLDraw, TLDrawDocument } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const myDocument: TLDrawDocument = {}
|
||||||
|
|
||||||
|
return <TLDraw document={document} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or imperatively through the `TLDrawState` instance:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { TLDraw, TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const handleMount = React.useCallback((tlstate: TLDrawState) => {
|
||||||
|
const myDocument: TLDrawDocument = {}
|
||||||
|
|
||||||
|
tlstate.loadDocument(myDocument).selectAll()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <TLDraw onMount={handleMount} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### `TLDraw`
|
### `TLDraw`
|
||||||
|
|
||||||
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.
|
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` | (optional) An id under which to persist the component's state. |
|
| `id` | `string` | An id under which to persist the component's state. |
|
||||||
| `document` | `TLDrawDocument` | (optional) An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||||
| `currentPageId` | `string` | (optional) 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` | `(TLDrawState) => void` | (optional) A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
| `onMount` | `Function` | A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||||
| `onChange` | `(TLDrawState, string) => void` | (optional) A callback function that will be called whenever the `TLDrawState` updates. The update will include the current `TLDrawState` and the reason for the change. |
|
| `onChange` | `Function` | A callback function that will be called whenever the `TLDrawState` updates. The update will include the current `TLDrawState` and the reason for the change. |
|
||||||
|
| `onUserChange` | `Function` | A callback function that will be fired when the user's "presence" information changes. |
|
||||||
|
| `autofocus` | `boolean` | Whether the editor should immediately receive focus. Defaults to true. |
|
||||||
|
| `showMenu` | `boolean` | Whether to show the menu. |
|
||||||
|
| `showPages` | `boolean` | Whether to show the pages menu. |
|
||||||
|
| `showStyles` | `boolean` | Whether to show the styles menu. |
|
||||||
|
| `showTools` | `boolean` | Whether to show the tools. |
|
||||||
|
| `showUI` | `boolean` | Whether to show any UI other than the canvas. |
|
||||||
|
|
||||||
### `TLDrawDocument`
|
### `TLDrawDocument`
|
||||||
|
|
||||||
A `TLDrawDocument` is an object with three properties:
|
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 `TLPage` objects
|
- `pages` - A table of `TLDrawPage` objects
|
||||||
- `pageStates` - A table of `TLPageState` objects
|
- `pageStates` - A table of `TLPageState` objects
|
||||||
|
- `version` - The document's version, used internally for migrations.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
const tldocument: TLDrawDocument = {
|
const tldocument: TLDrawDocument = {
|
||||||
id: 'doc',
|
id: 'doc',
|
||||||
|
version: TLDrawState.version,
|
||||||
pages: {
|
pages: {
|
||||||
page1: {
|
page1: {
|
||||||
id: 'page1',
|
id: 'page1',
|
||||||
|
@ -74,30 +117,30 @@ const tldocument: TLDrawDocument = {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**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.
|
**Tip:** TLDraw is built [@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.
|
||||||
|
|
||||||
In the example above, the page above with the id `page1`is at `tldocument.pages["page1"]`. Its corresponding page state has the same id (`page1`) and is at `tldocument.pageStates["page1"]`.
|
**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.
|
||||||
|
|
||||||
### Shapes
|
### Shapes
|
||||||
|
|
||||||
Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawShape` interfaces listed below. All `TLDrawShapes` extends a common interface:
|
Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawShape` interfaces listed below. All `TLDrawShapes` extends a common interface:
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --------------------- | ------------ | --------------------------------------------------------------- |
|
| --------------------- | ---------------- | --------------------------------------------------------------- |
|
||||||
| `id` | `string` | A unique ID for the shape. |
|
| `id` | `string` | A unique ID for the shape. |
|
||||||
| `name` | `string` | The shape's name. |
|
| `name` | `string` | The shape's name. |
|
||||||
| `type` | `string` | The shape's type. |
|
| `type` | `string` | The shape's type. |
|
||||||
| `parentId` | `string` | The ID of the shape's parent (a shape or its page). |
|
| `parentId` | `string` | The ID of the shape's parent (a shape or its page). |
|
||||||
| `childIndex` | `number` | The shape's order within its parent's children, indexed from 1. |
|
| `childIndex` | `number` | The shape's order within its parent's children, indexed from 1. |
|
||||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||||
| `handles` | `TLHandle{}` | (optional) A table of `TLHandle` objects. |
|
| `handles` | `TLDrawHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||||
| `isLocked` | `boolean` | True if the shape is locked. |
|
| `isLocked` | `boolean` | (optional) True if the shape is locked. |
|
||||||
| `isHidden` | `boolean` | True if the shape is hidden. |
|
| `isHidden` | `boolean` | (optional) True if the shape is hidden. |
|
||||||
| `isEditing` | `boolean` | True if the shape is currently editing. |
|
| `isEditing` | `boolean` | (optional) True if the shape is currently editing. |
|
||||||
| `isGenerated` | `boolean` | True if the shape is generated. |
|
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
||||||
| `isAspectRatioLocked` | `boolean` | 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 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.
|
||||||
|
|
||||||
|
@ -110,38 +153,98 @@ The `ShapeStyle` object is a common style API for all shapes.
|
||||||
| `color` | `ColorStyle` | The shape's color. |
|
| `color` | `ColorStyle` | The shape's color. |
|
||||||
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
||||||
|
|
||||||
#### Draw
|
#### `DrawShape`
|
||||||
|
|
||||||
|
A hand-drawn line.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------------ | ----------------------------------------- |
|
| -------- | ------------ | ----------------------------------------- |
|
||||||
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
||||||
|
|
||||||
##### Rectangle
|
##### `RectangleShape`
|
||||||
|
|
||||||
|
A rectangular shape.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ---------- | --------------------------------------- |
|
| -------- | ---------- | --------------------------------------- |
|
||||||
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
||||||
|
|
||||||
#### Ellipse
|
#### `EllipseShape`
|
||||||
|
|
||||||
|
An elliptical shape.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ---------- | ----------------------------------- |
|
| -------- | ---------- | ----------------------------------- |
|
||||||
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
||||||
|
|
||||||
#### Arrow
|
#### `ArrowShape`
|
||||||
|
|
||||||
| Property | Type | Description |
|
An arrow that can connect shapes.
|
||||||
| --------- | -------- | ----------------------------------------------------------------------- |
|
|
||||||
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
|
||||||
|
|
||||||
#### Text
|
| Property | Type | Description |
|
||||||
|
| ------------- | -------- | ----------------------------------------------------------------------- |
|
||||||
|
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
||||||
|
| `decorations` | `object` | An object with two properties `start`, `end`, and `bend`. |
|
||||||
|
|
||||||
|
#### `TextShape`
|
||||||
|
|
||||||
|
A line of text.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | -------- | ------------------------- |
|
| -------- | -------- | ------------------------- |
|
||||||
| `text` | `string` | The shape's text content. |
|
| `text` | `string` | The shape's text content. |
|
||||||
|
|
||||||
## Development
|
#### `StickyShape`
|
||||||
|
|
||||||
### Running unit tests
|
A sticky note.
|
||||||
|
|
||||||
Run `nx test tldraw` to execute the unit tests via [Jest](https://jestjs.io).
|
| Property | Type | Description |
|
||||||
|
| -------- | -------- | ------------------------- |
|
||||||
|
| `text` | `string` | The shape's text content. |
|
||||||
|
|
||||||
|
### Bindings
|
||||||
|
|
||||||
|
A binding is a connection **from** one shape and **to** another shape. At the moment, only arrows may be bound "from". Most shapes may be bound "to", except other `ArrowShape` and `DrawShape`s.
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| ---------- | ---------------- | -------------------------------------------------------- |
|
||||||
|
| `id` | `string` | The binding's own unique ID. |
|
||||||
|
| `fromId` | `string` | The id of the `ArrowShape` that the binding is bound to. |
|
||||||
|
| `toId` | `string` | The id of the other shape that the binding is bound to. |
|
||||||
|
| `handleId` | `start` or `end` | The connected arrow handle. |
|
||||||
|
| `distance` | `number` | The distance from the bound point. |
|
||||||
|
| `point` | `number[]` | A normalized point representing the bound point. |
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
- Run `yarn` to install dependencies.
|
||||||
|
|
||||||
|
- Run `yarn start` to start the development server for the package and for the example.
|
||||||
|
|
||||||
|
- Open `localhost:5000` to view the example project.
|
||||||
|
|
||||||
|
- 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/).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
See the `example` folder.
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
### Support
|
||||||
|
|
||||||
|
Need help? Please [open an issue](https://github.com/tldraw/tldraw/issues/new) for support.
|
||||||
|
|
||||||
|
### Discussion
|
||||||
|
|
||||||
|
Want to connect with other devs? Visit the [Discord channel](https://discord.gg/s4FXZ6fppJ).
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
- [@steveruizok](https://twitter.com/steveruizok)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# @tldraw/dev
|
|
||||||
|
|
||||||
A very fast dev server.
|
|
||||||
|
|
||||||
You probably do not need to start the server here: it is started as
|
|
||||||
part of `yarn start` in the root directory.
|
|
6
example/README.md
Normal file
6
example/README.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# @tldraw/tldraw-example
|
||||||
|
|
||||||
|
An example for @tldraw/tldraw with a very fast dev server.
|
||||||
|
|
||||||
|
**Note:** You probably do not need to start the server here: it is started as
|
||||||
|
part of `yarn start` in the root directory.
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "@tldraw/dev",
|
"name": "@tldraw/tldraw-example",
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "A tiny little drawing app (dev)",
|
"description": "A tiny little drawing app example.",
|
||||||
"author": "@steveruizok",
|
"author": "@steveruizok",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -18,14 +18,10 @@
|
||||||
"src"
|
"src"
|
||||||
],
|
],
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"@liveblocks/client": "^0.12.1",
|
"peerDependencies": {
|
||||||
"@liveblocks/react": "^0.12.1",
|
|
||||||
"@tldraw/tldraw": "^0.1.1",
|
|
||||||
"react": ">=16.8",
|
"react": ">=16.8",
|
||||||
"react-dom": "^16.8 || ^17.0",
|
"react-dom": "^16.8 || ^17.0"
|
||||||
"react-router": "^5.2.1",
|
|
||||||
"react-router-dom": "^5.3.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^14.14.35",
|
"@types/node": "^14.14.35",
|
||||||
|
@ -36,7 +32,12 @@
|
||||||
"create-serve": "1.0.1",
|
"create-serve": "1.0.1",
|
||||||
"esbuild": "^0.13.8",
|
"esbuild": "^0.13.8",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"typescript": "4.2.3"
|
"typescript": "4.2.3",
|
||||||
|
"@liveblocks/client": "^0.12.1",
|
||||||
|
"@liveblocks/react": "^0.12.1",
|
||||||
|
"@tldraw/tldraw": "^0.1.1",
|
||||||
|
"react-router": "^5.2.1",
|
||||||
|
"react-router-dom": "^5.3.0"
|
||||||
},
|
},
|
||||||
"gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
|
"gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
|
||||||
}
|
}
|
|
@ -40,24 +40,8 @@ function TLDrawWrapper() {
|
||||||
const doc = useObject<{ uuid: string; document: TLDrawDocument }>('doc', {
|
const doc = useObject<{ uuid: string; document: TLDrawDocument }>('doc', {
|
||||||
uuid: docId,
|
uuid: docId,
|
||||||
document: {
|
document: {
|
||||||
|
...TLDrawState.defaultDocument,
|
||||||
id: 'test-room',
|
id: 'test-room',
|
||||||
pages: {
|
|
||||||
page: {
|
|
||||||
id: 'page',
|
|
||||||
shapes: {},
|
|
||||||
bindings: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pageStates: {
|
|
||||||
page: {
|
|
||||||
id: 'page',
|
|
||||||
selectedIds: [],
|
|
||||||
camera: {
|
|
||||||
point: [0, 0],
|
|
||||||
zoom: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/tldraw",
|
"packages/tldraw",
|
||||||
"dev",
|
"example",
|
||||||
"www"
|
"www"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -45,9 +45,6 @@
|
||||||
"typedoc": "^0.22.3",
|
"typedoc": "^0.22.3",
|
||||||
"typescript": "^4.4.2"
|
"typescript": "^4.4.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
|
||||||
"www": "0.0.133"
|
|
||||||
},
|
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
|
@ -80,4 +77,4 @@
|
||||||
"\\~(.*)": "<rootDir>/packages/tldraw/src/$1"
|
"\\~(.*)": "<rootDir>/packages/tldraw/src/$1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,19 +1,23 @@
|
||||||
|
<div style="text-align: center; transform: scale(.5);">
|
||||||
|
<img src="card-repo.png"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
# @tldraw/tldraw
|
# @tldraw/tldraw
|
||||||
|
|
||||||
> `This library is not yet released and these docs are partially out of date!`
|
This package contains the [tldraw](https://tldraw.com) editor as a React component named `<TLDraw>`. You can use this package to embed the editor in any React application.
|
||||||
|
|
||||||
This package contains the [tldraw](https://tldraw.com) editor as a standalone React component.
|
🎨 Want to build your own tldraw-ish app instead? Try [@tldraw/core](https://github.com/tldraw/core).
|
||||||
|
|
||||||
|
💕 Love this library? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
Use your package manager of choice to install `@tldraw/core` and its peer dependencies.
|
||||||
npm i @tldraw/tldraw
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn add @tldraw/tldraw
|
yarn add @tldraw/tldraw
|
||||||
|
# or
|
||||||
|
npm i @tldraw/tldraw
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
@ -28,31 +32,70 @@ function App() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can control the `TLDraw` component through props:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { TLDraw, TLDrawDocument } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const myDocument: TLDrawDocument = {}
|
||||||
|
|
||||||
|
return <TLDraw document={document} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or imperatively through the `TLDrawState` instance:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { TLDraw, TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const handleMount = React.useCallback((tlstate: TLDrawState) => {
|
||||||
|
const myDocument: TLDrawDocument = {}
|
||||||
|
|
||||||
|
tlstate.loadDocument(myDocument).selectAll()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <TLDraw onMount={handleMount} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### `TLDraw`
|
### `TLDraw`
|
||||||
|
|
||||||
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.
|
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` | (optional) An id under which to persist the component's state. |
|
| `id` | `string` | An id under which to persist the component's state. |
|
||||||
| `document` | `TLDrawDocument` | (optional) An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||||
| `currentPageId` | `string` | (optional) 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` | `(TLDrawState) => void` | (optional) A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
| `onMount` | `Function` | A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||||
| `onChange` | `(TLDrawState, string) => void` | (optional) A callback function that will be called whenever the `TLDrawState` updates. The update will include the current `TLDrawState` and the reason for the change. |
|
| `onChange` | `Function` | A callback function that will be called whenever the `TLDrawState` updates. The update will include the current `TLDrawState` and the reason for the change. |
|
||||||
|
| `onUserChange` | `Function` | A callback function that will be fired when the user's "presence" information changes. |
|
||||||
|
| `autofocus` | `boolean` | Whether the editor should immediately receive focus. Defaults to true. |
|
||||||
|
| `showMenu` | `boolean` | Whether to show the menu. |
|
||||||
|
| `showPages` | `boolean` | Whether to show the pages menu. |
|
||||||
|
| `showStyles` | `boolean` | Whether to show the styles menu. |
|
||||||
|
| `showTools` | `boolean` | Whether to show the tools. |
|
||||||
|
| `showUI` | `boolean` | Whether to show any UI other than the canvas. |
|
||||||
|
|
||||||
### `TLDrawDocument`
|
### `TLDrawDocument`
|
||||||
|
|
||||||
A `TLDrawDocument` is an object with three properties:
|
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 `TLPage` objects
|
- `pages` - A table of `TLDrawPage` objects
|
||||||
- `pageStates` - A table of `TLPageState` objects
|
- `pageStates` - A table of `TLPageState` objects
|
||||||
|
- `version` - The document's version, used internally for migrations.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
||||||
|
|
||||||
const tldocument: TLDrawDocument = {
|
const tldocument: TLDrawDocument = {
|
||||||
id: 'doc',
|
id: 'doc',
|
||||||
|
version: TLDrawState.version,
|
||||||
pages: {
|
pages: {
|
||||||
page1: {
|
page1: {
|
||||||
id: 'page1',
|
id: 'page1',
|
||||||
|
@ -74,30 +117,30 @@ const tldocument: TLDrawDocument = {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**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.
|
**Tip:** TLDraw is built [@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.
|
||||||
|
|
||||||
In the example above, the page above with the id `page1`is at `tldocument.pages["page1"]`. Its corresponding page state has the same id (`page1`) and is at `tldocument.pageStates["page1"]`.
|
**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.
|
||||||
|
|
||||||
### Shapes
|
### Shapes
|
||||||
|
|
||||||
Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawShape` interfaces listed below. All `TLDrawShapes` extends a common interface:
|
Your `TLPage` objects may include shapes: objects that fit one of the `TLDrawShape` interfaces listed below. All `TLDrawShapes` extends a common interface:
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --------------------- | ------------ | --------------------------------------------------------------- |
|
| --------------------- | ---------------- | --------------------------------------------------------------- |
|
||||||
| `id` | `string` | A unique ID for the shape. |
|
| `id` | `string` | A unique ID for the shape. |
|
||||||
| `name` | `string` | The shape's name. |
|
| `name` | `string` | The shape's name. |
|
||||||
| `type` | `string` | The shape's type. |
|
| `type` | `string` | The shape's type. |
|
||||||
| `parentId` | `string` | The ID of the shape's parent (a shape or its page). |
|
| `parentId` | `string` | The ID of the shape's parent (a shape or its page). |
|
||||||
| `childIndex` | `number` | The shape's order within its parent's children, indexed from 1. |
|
| `childIndex` | `number` | The shape's order within its parent's children, indexed from 1. |
|
||||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||||
| `handles` | `TLHandle{}` | (optional) A table of `TLHandle` objects. |
|
| `handles` | `TLDrawHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||||
| `isLocked` | `boolean` | True if the shape is locked. |
|
| `isLocked` | `boolean` | (optional) True if the shape is locked. |
|
||||||
| `isHidden` | `boolean` | True if the shape is hidden. |
|
| `isHidden` | `boolean` | (optional) True if the shape is hidden. |
|
||||||
| `isEditing` | `boolean` | True if the shape is currently editing. |
|
| `isEditing` | `boolean` | (optional) True if the shape is currently editing. |
|
||||||
| `isGenerated` | `boolean` | True if the shape is generated. |
|
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
||||||
| `isAspectRatioLocked` | `boolean` | 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 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.
|
||||||
|
|
||||||
|
@ -110,38 +153,98 @@ The `ShapeStyle` object is a common style API for all shapes.
|
||||||
| `color` | `ColorStyle` | The shape's color. |
|
| `color` | `ColorStyle` | The shape's color. |
|
||||||
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
||||||
|
|
||||||
#### Draw
|
#### `DrawShape`
|
||||||
|
|
||||||
|
A hand-drawn line.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------------ | ----------------------------------------- |
|
| -------- | ------------ | ----------------------------------------- |
|
||||||
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
||||||
|
|
||||||
##### Rectangle
|
##### `RectangleShape`
|
||||||
|
|
||||||
|
A rectangular shape.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ---------- | --------------------------------------- |
|
| -------- | ---------- | --------------------------------------- |
|
||||||
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
||||||
|
|
||||||
#### Ellipse
|
#### `EllipseShape`
|
||||||
|
|
||||||
|
An elliptical shape.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ---------- | ----------------------------------- |
|
| -------- | ---------- | ----------------------------------- |
|
||||||
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
||||||
|
|
||||||
#### Arrow
|
#### `ArrowShape`
|
||||||
|
|
||||||
| Property | Type | Description |
|
An arrow that can connect shapes.
|
||||||
| --------- | -------- | ----------------------------------------------------------------------- |
|
|
||||||
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
|
||||||
|
|
||||||
#### Text
|
| Property | Type | Description |
|
||||||
|
| ------------- | -------- | ----------------------------------------------------------------------- |
|
||||||
|
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
||||||
|
| `decorations` | `object` | An object with two properties `start`, `end`, and `bend`. |
|
||||||
|
|
||||||
|
#### `TextShape`
|
||||||
|
|
||||||
|
A line of text.
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | -------- | ------------------------- |
|
| -------- | -------- | ------------------------- |
|
||||||
| `text` | `string` | The shape's text content. |
|
| `text` | `string` | The shape's text content. |
|
||||||
|
|
||||||
## Development
|
#### `StickyShape`
|
||||||
|
|
||||||
### Running unit tests
|
A sticky note.
|
||||||
|
|
||||||
Run `nx test tldraw` to execute the unit tests via [Jest](https://jestjs.io).
|
| Property | Type | Description |
|
||||||
|
| -------- | -------- | ------------------------- |
|
||||||
|
| `text` | `string` | The shape's text content. |
|
||||||
|
|
||||||
|
### Bindings
|
||||||
|
|
||||||
|
A binding is a connection **from** one shape and **to** another shape. At the moment, only arrows may be bound "from". Most shapes may be bound "to", except other `ArrowShape` and `DrawShape`s.
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| ---------- | ---------------- | -------------------------------------------------------- |
|
||||||
|
| `id` | `string` | The binding's own unique ID. |
|
||||||
|
| `fromId` | `string` | The id of the `ArrowShape` that the binding is bound to. |
|
||||||
|
| `toId` | `string` | The id of the other shape that the binding is bound to. |
|
||||||
|
| `handleId` | `start` or `end` | The connected arrow handle. |
|
||||||
|
| `distance` | `number` | The distance from the bound point. |
|
||||||
|
| `point` | `number[]` | A normalized point representing the bound point. |
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
- Run `yarn` to install dependencies.
|
||||||
|
|
||||||
|
- Run `yarn start` to start the development server for the package and for the example.
|
||||||
|
|
||||||
|
- Open `localhost:5000` to view the example project.
|
||||||
|
|
||||||
|
- 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/).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
See the `example` folder.
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
### Support
|
||||||
|
|
||||||
|
Need help? Please [open an issue](https://github.com/tldraw/tldraw/issues/new) for support.
|
||||||
|
|
||||||
|
### Discussion
|
||||||
|
|
||||||
|
Want to connect with other devs? Visit the [Discord channel](https://discord.gg/s4FXZ6fppJ).
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
- [@steveruizok](https://twitter.com/steveruizok)
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
"@tldraw/vec": "^0.1.3",
|
"@tldraw/vec": "^0.1.3",
|
||||||
"perfect-freehand": "^1.0.16",
|
"perfect-freehand": "^1.0.16",
|
||||||
"react-hotkeys-hook": "^3.4.0",
|
"react-hotkeys-hook": "^3.4.0",
|
||||||
"rko": "^0.5.25"
|
"rko": "^0.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsconfig-replace-paths": "^0.0.5"
|
"tsconfig-replace-paths": "^0.0.5"
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Tooltip } from '~components/Tooltip'
|
||||||
import styled from '~styles'
|
import styled from '~styles'
|
||||||
|
|
||||||
export interface ToolButtonProps {
|
export interface ToolButtonProps {
|
||||||
|
onClick?: () => void
|
||||||
onSelect?: () => void
|
onSelect?: () => void
|
||||||
onDoubleClick?: () => void
|
onDoubleClick?: () => void
|
||||||
isActive?: boolean
|
isActive?: boolean
|
||||||
|
@ -12,12 +13,13 @@ export interface ToolButtonProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolButton = React.forwardRef<HTMLButtonElement, ToolButtonProps>(
|
export const ToolButton = React.forwardRef<HTMLButtonElement, ToolButtonProps>(
|
||||||
({ onSelect, onDoubleClick, isActive = false, variant, children, ...rest }, ref) => {
|
({ onSelect, onClick, onDoubleClick, isActive = false, variant, children, ...rest }, ref) => {
|
||||||
return (
|
return (
|
||||||
<StyledToolButton
|
<StyledToolButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
|
onClick={onClick}
|
||||||
onPointerDown={onSelect}
|
onPointerDown={onSelect}
|
||||||
onDoubleClick={onDoubleClick}
|
onDoubleClick={onDoubleClick}
|
||||||
bp={breakpoints}
|
bp={breakpoints}
|
||||||
|
|
|
@ -4,14 +4,14 @@ import { strokes } from '~shape-utils'
|
||||||
import { useTheme, useTLDrawContext } from '~hooks'
|
import { useTheme, useTLDrawContext } from '~hooks'
|
||||||
import type { Data, ColorStyle } from '~types'
|
import type { Data, ColorStyle } from '~types'
|
||||||
import CircleIcon from '~components/icons/CircleIcon'
|
import CircleIcon from '~components/icons/CircleIcon'
|
||||||
import { DMContent, DMRadioItem, DMTriggerIcon } from '~components/DropdownMenu'
|
import { DMContent, DMTriggerIcon } from '~components/DropdownMenu'
|
||||||
import { BoxIcon } from '~components/icons'
|
import { BoxIcon } from '~components/icons'
|
||||||
import { IconButton } from '~components/IconButton'
|
|
||||||
import { ToolButton } from '~components/ToolButton'
|
import { ToolButton } from '~components/ToolButton'
|
||||||
import { Tooltip } from '~components/Tooltip'
|
|
||||||
|
|
||||||
const selectColor = (s: Data) => s.appState.selectedStyle.color
|
const selectColor = (s: Data) => s.appState.selectedStyle.color
|
||||||
|
|
||||||
|
const preventEvent = (e: Event) => e.preventDefault()
|
||||||
|
|
||||||
export const ColorMenu = React.memo((): JSX.Element => {
|
export const ColorMenu = React.memo((): JSX.Element => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const { tlstate, useSelector } = useTLDrawContext()
|
const { tlstate, useSelector } = useTLDrawContext()
|
||||||
|
@ -25,17 +25,18 @@ export const ColorMenu = React.memo((): JSX.Element => {
|
||||||
</DMTriggerIcon>
|
</DMTriggerIcon>
|
||||||
<DMContent variant="grid">
|
<DMContent variant="grid">
|
||||||
{Object.keys(strokes[theme]).map((colorStyle: string) => (
|
{Object.keys(strokes[theme]).map((colorStyle: string) => (
|
||||||
<ToolButton
|
<DropdownMenu.Item key={colorStyle} onSelect={preventEvent} asChild>
|
||||||
key={colorStyle}
|
<ToolButton
|
||||||
variant="icon"
|
variant="icon"
|
||||||
isActive={color === colorStyle}
|
isActive={color === colorStyle}
|
||||||
onSelect={() => tlstate.style({ color: colorStyle as ColorStyle })}
|
onClick={() => tlstate.style({ color: colorStyle as ColorStyle })}
|
||||||
>
|
>
|
||||||
<BoxIcon
|
<BoxIcon
|
||||||
fill={strokes[theme][colorStyle as ColorStyle]}
|
fill={strokes[theme][colorStyle as ColorStyle]}
|
||||||
stroke={strokes[theme][colorStyle as ColorStyle]}
|
stroke={strokes[theme][colorStyle as ColorStyle]}
|
||||||
/>
|
/>
|
||||||
</ToolButton>
|
</ToolButton>
|
||||||
|
</DropdownMenu.Item>
|
||||||
))}
|
))}
|
||||||
</DMContent>
|
</DMContent>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
|
@ -15,6 +15,8 @@ const dashes = {
|
||||||
|
|
||||||
const selectDash = (s: Data) => s.appState.selectedStyle.dash
|
const selectDash = (s: Data) => s.appState.selectedStyle.dash
|
||||||
|
|
||||||
|
const preventEvent = (e: Event) => e.preventDefault()
|
||||||
|
|
||||||
export const DashMenu = React.memo((): JSX.Element => {
|
export const DashMenu = React.memo((): JSX.Element => {
|
||||||
const { tlstate, useSelector } = useTLDrawContext()
|
const { tlstate, useSelector } = useTLDrawContext()
|
||||||
|
|
||||||
|
@ -24,15 +26,16 @@ export const DashMenu = React.memo((): JSX.Element => {
|
||||||
<DropdownMenu.Root dir="ltr">
|
<DropdownMenu.Root dir="ltr">
|
||||||
<DMTriggerIcon>{dashes[dash]}</DMTriggerIcon>
|
<DMTriggerIcon>{dashes[dash]}</DMTriggerIcon>
|
||||||
<DMContent variant="horizontal">
|
<DMContent variant="horizontal">
|
||||||
{Object.keys(DashStyle).map((dashStyle) => (
|
{Object.values(DashStyle).map((dashStyle) => (
|
||||||
<ToolButton
|
<DropdownMenu.Item key={dashStyle} onSelect={preventEvent} asChild>
|
||||||
key={dashStyle}
|
<ToolButton
|
||||||
variant="icon"
|
variant="icon"
|
||||||
isActive={dash === dashStyle}
|
isActive={dash === dashStyle}
|
||||||
onSelect={() => tlstate.style({ dash: dashStyle as DashStyle })}
|
onClick={() => tlstate.style({ dash: dashStyle as DashStyle })}
|
||||||
>
|
>
|
||||||
{dashes[dashStyle as DashStyle]}
|
{dashes[dashStyle as DashStyle]}
|
||||||
</ToolButton>
|
</ToolButton>
|
||||||
|
</DropdownMenu.Item>
|
||||||
))}
|
))}
|
||||||
</DMContent>
|
</DMContent>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
|
@ -128,6 +128,8 @@ export const StyledDialogOverlay = styled(Dialog.Overlay, {
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
})
|
})
|
||||||
|
|
||||||
function DialogAction({ onSelect, ...rest }: RowButtonProps) {
|
function DialogAction({ onSelect, ...rest }: RowButtonProps) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react'
|
||||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||||
import { Data, SizeStyle } from '~types'
|
import { Data, SizeStyle } from '~types'
|
||||||
import { useTLDrawContext } from '~hooks'
|
import { useTLDrawContext } from '~hooks'
|
||||||
import { DMContent, DMTriggerIcon } from '~components/DropdownMenu'
|
import { DMContent, DMItem, DMTriggerIcon } from '~components/DropdownMenu'
|
||||||
import { ToolButton } from '~components/ToolButton'
|
import { ToolButton } from '~components/ToolButton'
|
||||||
import { SizeSmallIcon, SizeMediumIcon, SizeLargeIcon } from '~components/icons'
|
import { SizeSmallIcon, SizeMediumIcon, SizeLargeIcon } from '~components/icons'
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ const sizes = {
|
||||||
|
|
||||||
const selectSize = (s: Data) => s.appState.selectedStyle.size
|
const selectSize = (s: Data) => s.appState.selectedStyle.size
|
||||||
|
|
||||||
|
const preventEvent = (e: Event) => e.preventDefault()
|
||||||
|
|
||||||
export const SizeMenu = React.memo((): JSX.Element => {
|
export const SizeMenu = React.memo((): JSX.Element => {
|
||||||
const { tlstate, useSelector } = useTLDrawContext()
|
const { tlstate, useSelector } = useTLDrawContext()
|
||||||
|
|
||||||
|
@ -23,14 +25,16 @@ export const SizeMenu = React.memo((): JSX.Element => {
|
||||||
<DropdownMenu.Root dir="ltr">
|
<DropdownMenu.Root dir="ltr">
|
||||||
<DMTriggerIcon>{sizes[size as SizeStyle]}</DMTriggerIcon>
|
<DMTriggerIcon>{sizes[size as SizeStyle]}</DMTriggerIcon>
|
||||||
<DMContent variant="horizontal">
|
<DMContent variant="horizontal">
|
||||||
{Object.keys(SizeStyle).map((sizeStyle: string) => (
|
{Object.values(SizeStyle).map((sizeStyle: string) => (
|
||||||
<ToolButton
|
<DropdownMenu.Item key={sizeStyle} onSelect={preventEvent} asChild>
|
||||||
key={sizeStyle}
|
<ToolButton
|
||||||
isActive={size === sizeStyle}
|
isActive={size === sizeStyle}
|
||||||
onSelect={() => tlstate.style({ size: sizeStyle as SizeStyle })}
|
variant="icon"
|
||||||
>
|
onClick={() => tlstate.style({ size: sizeStyle as SizeStyle })}
|
||||||
{sizes[sizeStyle as SizeStyle]}
|
>
|
||||||
</ToolButton>
|
{sizes[sizeStyle as SizeStyle]}
|
||||||
|
</ToolButton>
|
||||||
|
</DropdownMenu.Item>
|
||||||
))}
|
))}
|
||||||
</DMContent>
|
</DMContent>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
|
@ -5,7 +5,7 @@ Object {
|
||||||
"bend": 0,
|
"bend": 0,
|
||||||
"childIndex": 1,
|
"childIndex": 1,
|
||||||
"decorations": Object {
|
"decorations": Object {
|
||||||
"end": "Arrow",
|
"end": "arrow",
|
||||||
},
|
},
|
||||||
"handles": Object {
|
"handles": Object {
|
||||||
"bend": Object {
|
"bend": Object {
|
||||||
|
@ -44,10 +44,10 @@ Object {
|
||||||
],
|
],
|
||||||
"rotation": 0,
|
"rotation": 0,
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@ Object {
|
||||||
"points": Array [],
|
"points": Array [],
|
||||||
"rotation": 0,
|
"rotation": 0,
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "draw",
|
"type": "draw",
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ Object {
|
||||||
],
|
],
|
||||||
"rotation": 0,
|
"rotation": 0,
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "ellipse",
|
"type": "ellipse",
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ Object {
|
||||||
100,
|
100,
|
||||||
],
|
],
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "group",
|
"type": "group",
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ Object {
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ Object {
|
||||||
],
|
],
|
||||||
"rotation": 0,
|
"rotation": 0,
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"text": " ",
|
"text": " ",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|
|
@ -33,10 +33,10 @@ Array [
|
||||||
200,
|
200,
|
||||||
],
|
],
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
},
|
},
|
||||||
|
@ -93,10 +93,10 @@ Array [
|
||||||
200,
|
200,
|
||||||
],
|
],
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"color": "Black",
|
"color": "black",
|
||||||
"dash": "Draw",
|
"dash": "draw",
|
||||||
"isFilled": false,
|
"isFilled": false,
|
||||||
"size": "Small",
|
"size": "small",
|
||||||
},
|
},
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
},
|
},
|
||||||
|
|
53
packages/tldraw/src/state/migrate.ts
Normal file
53
packages/tldraw/src/state/migrate.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
import { Decoration, TLDrawDocument, TLDrawShapeType } from '~types'
|
||||||
|
|
||||||
|
export function migrate(document: TLDrawDocument, newVersion: number): TLDrawDocument {
|
||||||
|
const { version = 0 } = document
|
||||||
|
|
||||||
|
if (version === newVersion) return document
|
||||||
|
|
||||||
|
if (version <= 12) {
|
||||||
|
Object.values(document.pages).forEach((page) => {
|
||||||
|
Object.values(page.bindings).forEach((binding) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
Object.assign(binding, (binding as any).meta)
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.values(page.shapes).forEach((shape) => {
|
||||||
|
Object.entries(shape.style).forEach(([id, style]) => {
|
||||||
|
if (typeof style === 'string') {
|
||||||
|
// @ts-ignore
|
||||||
|
shape.style[id] = style.toLowerCase()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (shape.type === TLDrawShapeType.Arrow) {
|
||||||
|
if (shape.decorations) {
|
||||||
|
Object.entries(shape.decorations).forEach(([id, decoration]) => {
|
||||||
|
if ((decoration as unknown) === 'Arrow') {
|
||||||
|
shape.decorations = {
|
||||||
|
...shape.decorations,
|
||||||
|
[id]: Decoration.Arrow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.values(document.pageStates).forEach((pageState) => {
|
||||||
|
pageState.selectedIds = pageState.selectedIds.filter((id) => {
|
||||||
|
return document.pages[pageState.id].shapes[id] !== undefined
|
||||||
|
})
|
||||||
|
pageState.bindingId = undefined
|
||||||
|
pageState.editingId = undefined
|
||||||
|
pageState.hoveredId = undefined
|
||||||
|
pageState.pointedId = undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
document.version = newVersion
|
||||||
|
|
||||||
|
return document
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ import { sample } from './utils'
|
||||||
import { createTools, ToolType } from './tool'
|
import { createTools, ToolType } from './tool'
|
||||||
import type { BaseTool } from './tool/BaseTool'
|
import type { BaseTool } from './tool/BaseTool'
|
||||||
import { USER_COLORS, FIT_TO_SCREEN_PADDING } from '~constants'
|
import { USER_COLORS, FIT_TO_SCREEN_PADDING } from '~constants'
|
||||||
|
import { migrate } from './migrate'
|
||||||
|
|
||||||
const uuid = Utils.uniqueId()
|
const uuid = Utils.uniqueId()
|
||||||
|
|
||||||
|
@ -100,21 +101,15 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
onUserChange?: (tlstate: TLDrawState, user: TLDrawUser) => void
|
onUserChange?: (tlstate: TLDrawState, user: TLDrawUser) => void
|
||||||
) {
|
) {
|
||||||
super(TLDrawState.defaultState, id, TLDrawState.version, (prev, next) => {
|
super(TLDrawState.defaultState, id, TLDrawState.version, (prev, next) => {
|
||||||
Object.values(prev.document.pages).forEach((page) => {
|
|
||||||
Object.values(page.bindings).forEach((binding) => {
|
|
||||||
if ('meta' in binding) {
|
|
||||||
// @ts-ignore
|
|
||||||
Object.assign(binding, binding.meta)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...next,
|
...next,
|
||||||
document: { ...next.document, ...prev.document },
|
document: { ...next.document, ...prev.document },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.loadDocument(this.document)
|
||||||
|
this.patchState({ document: migrate(this.document, TLDrawState.version) })
|
||||||
|
|
||||||
this._onChange = onChange
|
this._onChange = onChange
|
||||||
this._onMount = onMount
|
this._onMount = onMount
|
||||||
this._onUserChange = onUserChange
|
this._onUserChange = onUserChange
|
||||||
|
@ -130,6 +125,7 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
appState: {
|
appState: {
|
||||||
status: TLDrawStatus.Idle,
|
status: TLDrawStatus.Idle,
|
||||||
},
|
},
|
||||||
|
document: migrate(this.document, TLDrawState.version),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('The data appears to be corrupted. Resetting!', e)
|
console.error('The data appears to be corrupted. Resetting!', e)
|
||||||
|
@ -641,7 +637,7 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
...this.appState,
|
...this.appState,
|
||||||
currentPageId: Object.keys(document.pages)[0],
|
currentPageId: Object.keys(document.pages)[0],
|
||||||
},
|
},
|
||||||
document,
|
document: migrate(document, TLDrawState.version),
|
||||||
})
|
})
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -709,7 +705,7 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
...this.state,
|
...this.state,
|
||||||
appState: nextAppState,
|
appState: nextAppState,
|
||||||
document: {
|
document: {
|
||||||
...document,
|
...migrate(document, TLDrawState.version),
|
||||||
pageStates: currentPageStates,
|
pageStates: currentPageStates,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -803,7 +799,7 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
return this.replaceState(
|
return this.replaceState(
|
||||||
{
|
{
|
||||||
...TLDrawState.defaultState,
|
...TLDrawState.defaultState,
|
||||||
document,
|
document: migrate(document, TLDrawState.version),
|
||||||
appState: {
|
appState: {
|
||||||
...TLDrawState.defaultState.appState,
|
...TLDrawState.defaultState.appState,
|
||||||
currentPageId: Object.keys(document.pages)[0],
|
currentPageId: Object.keys(document.pages)[0],
|
||||||
|
@ -1068,8 +1064,6 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
Utils.deepClone(this.getShape(id, this.currentPageId))
|
Utils.deepClone(this.getShape(id, this.currentPageId))
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(copyingShapes.length)
|
|
||||||
|
|
||||||
if (copyingShapes.length === 0) return this
|
if (copyingShapes.length === 0) return this
|
||||||
|
|
||||||
const copyingBindings: TLDrawBinding[] = Object.values(this.page.bindings).filter(
|
const copyingBindings: TLDrawBinding[] = Object.values(this.page.bindings).filter(
|
||||||
|
@ -2463,10 +2457,11 @@ export class TLDrawState extends StateManager<Data> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static version = 11
|
static version = 12.5
|
||||||
|
|
||||||
static defaultDocument: TLDrawDocument = {
|
static defaultDocument: TLDrawDocument = {
|
||||||
id: 'doc',
|
id: 'doc',
|
||||||
|
version: 12.4,
|
||||||
pages: {
|
pages: {
|
||||||
page: {
|
page: {
|
||||||
id: 'page',
|
id: 'page',
|
||||||
|
|
|
@ -46,8 +46,6 @@ export abstract class BaseTool<T extends string = any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancel = () => {
|
onCancel = () => {
|
||||||
console.log('cancelling')
|
|
||||||
|
|
||||||
if (this.status === Status.Idle) {
|
if (this.status === Status.Idle) {
|
||||||
this.state.selectTool('select')
|
this.state.selectTool('select')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,8 +11,6 @@ export class TextTool extends BaseTool {
|
||||||
stopEditingShape = () => {
|
stopEditingShape = () => {
|
||||||
this.setStatus(Status.Idle)
|
this.setStatus(Status.Idle)
|
||||||
|
|
||||||
console.log(this.state.appState.isToolLocked)
|
|
||||||
|
|
||||||
if (!this.state.appState.isToolLocked) {
|
if (!this.state.appState.isToolLocked) {
|
||||||
this.state.selectTool('select')
|
this.state.selectTool('select')
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ import oldDoc from './old-doc'
|
||||||
|
|
||||||
describe('When migrating bindings', () => {
|
describe('When migrating bindings', () => {
|
||||||
it('migrates', () => {
|
it('migrates', () => {
|
||||||
Object.values((oldDoc as unknown as TLDrawDocument).pages).forEach((page) => {
|
// Object.values((oldDoc as unknown as TLDrawDocument).pages).forEach((page) => {
|
||||||
Object.values(page.bindings).forEach((binding) => {
|
// Object.values(page.bindings).forEach((binding) => {
|
||||||
if ('meta' in binding) {
|
// if ('meta' in binding) {
|
||||||
// @ts-ignore
|
// // @ts-ignore
|
||||||
Object.assign(binding, binding.meta)
|
// Object.assign(binding, binding.meta)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
|
|
||||||
new TLDrawState().loadDocument(oldDoc as unknown as TLDrawDocument)
|
new TLDrawState().loadDocument(oldDoc as unknown as TLDrawDocument)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { TLDrawDocument, ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
|
import { TLDrawDocument, ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
|
||||||
|
|
||||||
export const mockDocument: TLDrawDocument = {
|
export const mockDocument: TLDrawDocument = {
|
||||||
|
version: 0,
|
||||||
id: 'doc',
|
id: 'doc',
|
||||||
pages: {
|
pages: {
|
||||||
page1: {
|
page1: {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import type {
|
||||||
TLHandle,
|
TLHandle,
|
||||||
TLBounds,
|
TLBounds,
|
||||||
TLSnapLine,
|
TLSnapLine,
|
||||||
TLComponentProps,
|
|
||||||
} from '@tldraw/core'
|
} from '@tldraw/core'
|
||||||
import type { TLPage, TLUser, TLPageState } from '@tldraw/core'
|
import type { TLPage, TLUser, TLPageState } from '@tldraw/core'
|
||||||
import type { StoreApi } from 'zustand'
|
import type { StoreApi } from 'zustand'
|
||||||
|
@ -28,12 +27,6 @@ export interface TLDrawTransformInfo<T extends TLShape> {
|
||||||
transformOrigin: number[]
|
transformOrigin: number[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TLDrawComponentProps<T extends TLDrawShape, E extends Element = any> = TLComponentProps<
|
|
||||||
T,
|
|
||||||
E,
|
|
||||||
TLDrawMeta
|
|
||||||
>
|
|
||||||
|
|
||||||
// old
|
// old
|
||||||
export type TLStore = StoreApi<Data>
|
export type TLStore = StoreApi<Data>
|
||||||
|
|
||||||
|
@ -45,6 +38,7 @@ export interface TLDrawDocument {
|
||||||
id: string
|
id: string
|
||||||
pages: Record<string, TLDrawPage>
|
pages: Record<string, TLDrawPage>
|
||||||
pageStates: Record<string, TLPageState>
|
pageStates: Record<string, TLPageState>
|
||||||
|
version: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TLDrawSettings {
|
export interface TLDrawSettings {
|
||||||
|
@ -229,7 +223,7 @@ export enum TLDrawShapeType {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Decoration {
|
export enum Decoration {
|
||||||
Arrow = 'Arrow',
|
Arrow = 'arrow',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TLDrawBaseShape extends TLShape {
|
export interface TLDrawBaseShape extends TLShape {
|
||||||
|
@ -304,38 +298,38 @@ export interface ArrowBinding extends TLBinding {
|
||||||
export type TLDrawBinding = ArrowBinding
|
export type TLDrawBinding = ArrowBinding
|
||||||
|
|
||||||
export enum ColorStyle {
|
export enum ColorStyle {
|
||||||
White = 'White',
|
White = 'white',
|
||||||
LightGray = 'LightGray',
|
LightGray = 'lightGray',
|
||||||
Gray = 'Gray',
|
Gray = 'gray',
|
||||||
Black = 'Black',
|
Black = 'black',
|
||||||
Green = 'Green',
|
Green = 'green',
|
||||||
Cyan = 'Cyan',
|
Cyan = 'cyan',
|
||||||
Blue = 'Blue',
|
Blue = 'blue',
|
||||||
Indigo = 'Indigo',
|
Indigo = 'indigo',
|
||||||
Violet = 'Violet',
|
Violet = 'violet',
|
||||||
Red = 'Red',
|
Red = 'red',
|
||||||
Orange = 'Orange',
|
Orange = 'orange',
|
||||||
Yellow = 'Yellow',
|
Yellow = 'yellow',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SizeStyle {
|
export enum SizeStyle {
|
||||||
Small = 'Small',
|
Small = 'small',
|
||||||
Medium = 'Medium',
|
Medium = 'medium',
|
||||||
Large = 'Large',
|
Large = 'large',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DashStyle {
|
export enum DashStyle {
|
||||||
Draw = 'Draw',
|
Draw = 'draw',
|
||||||
Solid = 'Solid',
|
Solid = 'solid',
|
||||||
Dashed = 'Dashed',
|
Dashed = 'dashed',
|
||||||
Dotted = 'Dotted',
|
Dotted = 'dotted',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FontSize {
|
export enum FontSize {
|
||||||
Small = 'Small',
|
Small = 'small',
|
||||||
Medium = 'Medium',
|
Medium = 'medium',
|
||||||
Large = 'Large',
|
Large = 'large',
|
||||||
ExtraLarge = 'ExtraLarge',
|
ExtraLarge = 'extraLarge',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ShapeStyles = {
|
export type ShapeStyles = {
|
||||||
|
|
11
www/.babelrc
Normal file
11
www/.babelrc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"next/babel",
|
||||||
|
{
|
||||||
|
"preset-env": { "targets": { "node": true } }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": []
|
||||||
|
}
|
|
@ -37,23 +37,7 @@ function Editor({ id }: { id: string }) {
|
||||||
uuid: docId,
|
uuid: docId,
|
||||||
document: {
|
document: {
|
||||||
id: 'test-room',
|
id: 'test-room',
|
||||||
pages: {
|
...TLDrawState.defaultDocument,
|
||||||
page: {
|
|
||||||
id: 'page',
|
|
||||||
shapes: {},
|
|
||||||
bindings: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pageStates: {
|
|
||||||
page: {
|
|
||||||
id: 'page',
|
|
||||||
selectedIds: [],
|
|
||||||
camera: {
|
|
||||||
point: [0, 0],
|
|
||||||
zoom: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -156,7 +140,11 @@ function Editor({ id }: { id: string }) {
|
||||||
doc.subscribe(handleDocumentUpdates)
|
doc.subscribe(handleDocumentUpdates)
|
||||||
|
|
||||||
// Load the shared document
|
// Load the shared document
|
||||||
tlstate.loadDocument(doc.toObject().document)
|
const newDocument = doc.toObject().document
|
||||||
|
|
||||||
|
if (newDocument) {
|
||||||
|
tlstate.loadDocument(newDocument)
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('beforeunload', handleExit)
|
window.removeEventListener('beforeunload', handleExit)
|
||||||
|
|
2
www/public/workbox-a6b3f14f.js
Normal file
2
www/public/workbox-a6b3f14f.js
Normal file
File diff suppressed because one or more lines are too long
1
www/public/workbox-a6b3f14f.js.map
Normal file
1
www/public/workbox-a6b3f14f.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"target": "es5",
|
"target": "es6",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -9920,7 +9920,7 @@ raw-body@2.4.1:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
react-dom@17.0.2, "react-dom@^16.8 || ^17.0":
|
react-dom@17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||||
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
||||||
|
@ -10008,7 +10008,7 @@ react-style-singleton@^2.1.0:
|
||||||
invariant "^2.2.4"
|
invariant "^2.2.4"
|
||||||
tslib "^1.0.0"
|
tslib "^1.0.0"
|
||||||
|
|
||||||
react@17.0.2, react@>=16.8:
|
react@17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||||
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
|
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
|
||||||
|
@ -10445,10 +10445,10 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||||
hash-base "^3.0.0"
|
hash-base "^3.0.0"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
|
|
||||||
rko@^0.5.25:
|
rko@^0.6.0:
|
||||||
version "0.5.25"
|
version "0.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/rko/-/rko-0.5.25.tgz#1095803900e3f912f6adf8a1c113b8227d3d88bf"
|
resolved "https://registry.yarnpkg.com/rko/-/rko-0.6.0.tgz#fa640384b4e82fdcd90fc58c958256148c4eb10c"
|
||||||
integrity sha512-HU6M3PxK3VEqrr6QZKAsqO98juQX24kEgJkKSdFJhw8U/DBUGAnU/fgyxNIaTw7TCI7vjIy/RzBEXf5I4sijKg==
|
integrity sha512-u05SAiyz02Sw+QyGaQb3NGPXf3xXxQ9AwNG+tItHx2MpAsPEEH84NqYDyG9jem/ji/FPQPQHuRKcy2MHb1a1Ow==
|
||||||
dependencies:
|
dependencies:
|
||||||
idb-keyval "^5.1.3"
|
idb-keyval "^5.1.3"
|
||||||
zustand "^3.5.9"
|
zustand "^3.5.9"
|
||||||
|
|
Loading…
Reference in a new issue