[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
|
||||
coverage
|
||||
*.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
|
||||
|
||||
> `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
|
||||
|
||||
```bash
|
||||
npm i @tldraw/tldraw
|
||||
```
|
||||
|
||||
or
|
||||
Use your package manager of choice to install `@tldraw/core` and its peer dependencies.
|
||||
|
||||
```bash
|
||||
yarn add @tldraw/tldraw
|
||||
# or
|
||||
npm i @tldraw/tldraw
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
### `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 |
|
||||
| --------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | `string` | (optional) An id under which to persist the component's state. |
|
||||
| `document` | `TLDrawDocument` | (optional) An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||
| `currentPageId` | `string` | (optional) 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`. |
|
||||
| `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. |
|
||||
| Prop | Type | Description |
|
||||
| --------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `id` | `string` | An id under which to persist the component's state. |
|
||||
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||
| `currentPageId` | `string` | A current page id, referencing the `TLDrawDocument` object provided via the `document` prop. |
|
||||
| `onMount` | `Function` | A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||
| `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`
|
||||
|
||||
A `TLDrawDocument` is an object with three properties:
|
||||
|
||||
- `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
|
||||
- `version` - The document's version, used internally for migrations.
|
||||
|
||||
```ts
|
||||
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
||||
|
||||
const tldocument: TLDrawDocument = {
|
||||
id: 'doc',
|
||||
version: TLDrawState.version,
|
||||
pages: {
|
||||
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
|
||||
|
||||
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 |
|
||||
| --------------------- | ------------ | --------------------------------------------------------------- |
|
||||
| `id` | `string` | A unique ID for the shape. |
|
||||
| `name` | `string` | The shape's name. |
|
||||
| `type` | `string` | The shape's type. |
|
||||
| `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. |
|
||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||
| `handles` | `TLHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||
| `isLocked` | `boolean` | True if the shape is locked. |
|
||||
| `isHidden` | `boolean` | True if the shape is hidden. |
|
||||
| `isEditing` | `boolean` | True if the shape is currently editing. |
|
||||
| `isGenerated` | `boolean` | True if the shape is generated. |
|
||||
| `isAspectRatioLocked` | `boolean` | True if the shape's aspect ratio is locked. |
|
||||
| Property | Type | Description |
|
||||
| --------------------- | ---------------- | --------------------------------------------------------------- |
|
||||
| `id` | `string` | A unique ID for the shape. |
|
||||
| `name` | `string` | The shape's name. |
|
||||
| `type` | `string` | The shape's type. |
|
||||
| `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. |
|
||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||
| `handles` | `TLDrawHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||
| `isLocked` | `boolean` | (optional) True if the shape is locked. |
|
||||
| `isHidden` | `boolean` | (optional) True if the shape is hidden. |
|
||||
| `isEditing` | `boolean` | (optional) True if the shape is currently editing. |
|
||||
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
||||
| `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.
|
||||
|
||||
|
@ -110,38 +153,98 @@ The `ShapeStyle` object is a common style API for all shapes.
|
|||
| `color` | `ColorStyle` | The shape's color. |
|
||||
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
||||
|
||||
#### Draw
|
||||
#### `DrawShape`
|
||||
|
||||
A hand-drawn line.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ------------ | ----------------------------------------- |
|
||||
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
||||
|
||||
##### Rectangle
|
||||
##### `RectangleShape`
|
||||
|
||||
A rectangular shape.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | --------------------------------------- |
|
||||
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
||||
|
||||
#### Ellipse
|
||||
#### `EllipseShape`
|
||||
|
||||
An elliptical shape.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | ----------------------------------- |
|
||||
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
||||
|
||||
#### Arrow
|
||||
#### `ArrowShape`
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------- | -------- | ----------------------------------------------------------------------- |
|
||||
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
||||
An arrow that can connect shapes.
|
||||
|
||||
#### 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 |
|
||||
| -------- | -------- | ------------------------- |
|
||||
| `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",
|
||||
"private": true,
|
||||
"description": "A tiny little drawing app (dev)",
|
||||
"description": "A tiny little drawing app example.",
|
||||
"author": "@steveruizok",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
@ -18,14 +18,10 @@
|
|||
"src"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@liveblocks/client": "^0.12.1",
|
||||
"@liveblocks/react": "^0.12.1",
|
||||
"@tldraw/tldraw": "^0.1.1",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": "^16.8 || ^17.0",
|
||||
"react-router": "^5.2.1",
|
||||
"react-router-dom": "^5.3.0"
|
||||
"react-dom": "^16.8 || ^17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.35",
|
||||
|
@ -36,7 +32,12 @@
|
|||
"create-serve": "1.0.1",
|
||||
"esbuild": "^0.13.8",
|
||||
"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"
|
||||
}
|
|
@ -40,24 +40,8 @@ function TLDrawWrapper() {
|
|||
const doc = useObject<{ uuid: string; document: TLDrawDocument }>('doc', {
|
||||
uuid: docId,
|
||||
document: {
|
||||
...TLDrawState.defaultDocument,
|
||||
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",
|
||||
"workspaces": [
|
||||
"packages/tldraw",
|
||||
"dev",
|
||||
"example",
|
||||
"www"
|
||||
],
|
||||
"scripts": {
|
||||
|
@ -45,9 +45,6 @@
|
|||
"typedoc": "^0.22.3",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"www": "0.0.133"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true,
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
<div style="text-align: center; transform: scale(.5);">
|
||||
<img src="card-repo.png"/>
|
||||
</div>
|
||||
|
||||
# @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
|
||||
|
||||
```bash
|
||||
npm i @tldraw/tldraw
|
||||
```
|
||||
|
||||
or
|
||||
Use your package manager of choice to install `@tldraw/core` and its peer dependencies.
|
||||
|
||||
```bash
|
||||
yarn add @tldraw/tldraw
|
||||
# or
|
||||
npm i @tldraw/tldraw
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
### `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 |
|
||||
| --------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | `string` | (optional) An id under which to persist the component's state. |
|
||||
| `document` | `TLDrawDocument` | (optional) An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||
| `currentPageId` | `string` | (optional) 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`. |
|
||||
| `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. |
|
||||
| Prop | Type | Description |
|
||||
| --------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `id` | `string` | An id under which to persist the component's state. |
|
||||
| `document` | `TLDrawDocument` | An initial [`TLDrawDocument`](#tldrawdocument) object. |
|
||||
| `currentPageId` | `string` | A current page id, referencing the `TLDrawDocument` object provided via the `document` prop. |
|
||||
| `onMount` | `Function` | A callback function that will be called when the editor first mounts, receiving the current `TLDrawState`. |
|
||||
| `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`
|
||||
|
||||
A `TLDrawDocument` is an object with three properties:
|
||||
|
||||
- `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
|
||||
- `version` - The document's version, used internally for migrations.
|
||||
|
||||
```ts
|
||||
import { TLDrawDocument, TLDrawState } from '@tldraw/tldraw'
|
||||
|
||||
const tldocument: TLDrawDocument = {
|
||||
id: 'doc',
|
||||
version: TLDrawState.version,
|
||||
pages: {
|
||||
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
|
||||
|
||||
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 |
|
||||
| --------------------- | ------------ | --------------------------------------------------------------- |
|
||||
| `id` | `string` | A unique ID for the shape. |
|
||||
| `name` | `string` | The shape's name. |
|
||||
| `type` | `string` | The shape's type. |
|
||||
| `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. |
|
||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||
| `handles` | `TLHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||
| `isLocked` | `boolean` | True if the shape is locked. |
|
||||
| `isHidden` | `boolean` | True if the shape is hidden. |
|
||||
| `isEditing` | `boolean` | True if the shape is currently editing. |
|
||||
| `isGenerated` | `boolean` | True if the shape is generated. |
|
||||
| `isAspectRatioLocked` | `boolean` | True if the shape's aspect ratio is locked. |
|
||||
| Property | Type | Description |
|
||||
| --------------------- | ---------------- | --------------------------------------------------------------- |
|
||||
| `id` | `string` | A unique ID for the shape. |
|
||||
| `name` | `string` | The shape's name. |
|
||||
| `type` | `string` | The shape's type. |
|
||||
| `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. |
|
||||
| `point` | `number[]` | The `[x, y]` position of the shape. |
|
||||
| `rotation` | `number[]` | (optional) The shape's rotation in radians. |
|
||||
| `children` | `string[]` | (optional) The shape's child shape ids. |
|
||||
| `handles` | `TLDrawHandle{}` | (optional) A table of `TLHandle` objects. |
|
||||
| `isLocked` | `boolean` | (optional) True if the shape is locked. |
|
||||
| `isHidden` | `boolean` | (optional) True if the shape is hidden. |
|
||||
| `isEditing` | `boolean` | (optional) True if the shape is currently editing. |
|
||||
| `isGenerated` | `boolean` | (optional) True if the shape is generated. |
|
||||
| `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.
|
||||
|
||||
|
@ -110,38 +153,98 @@ The `ShapeStyle` object is a common style API for all shapes.
|
|||
| `color` | `ColorStyle` | The shape's color. |
|
||||
| `isFilled` | `boolean` | (optional) True if the shape is filled. |
|
||||
|
||||
#### Draw
|
||||
#### `DrawShape`
|
||||
|
||||
A hand-drawn line.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ------------ | ----------------------------------------- |
|
||||
| `points` | `number[][]` | An array of points as `[x, y, pressure]`. |
|
||||
|
||||
##### Rectangle
|
||||
##### `RectangleShape`
|
||||
|
||||
A rectangular shape.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | --------------------------------------- |
|
||||
| `size` | `number[]` | The `[width, height]` of the rectangle. |
|
||||
|
||||
#### Ellipse
|
||||
#### `EllipseShape`
|
||||
|
||||
An elliptical shape.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | ---------- | ----------------------------------- |
|
||||
| `radius` | `number[]` | The `[x, y]` radius of the ellipse. |
|
||||
|
||||
#### Arrow
|
||||
#### `ArrowShape`
|
||||
|
||||
| Property | Type | Description |
|
||||
| --------- | -------- | ----------------------------------------------------------------------- |
|
||||
| `handles` | `object` | An object with three `TLHandle` properties: `start`, `end`, and `bend`. |
|
||||
An arrow that can connect shapes.
|
||||
|
||||
#### 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 |
|
||||
| -------- | -------- | ------------------------- |
|
||||
| `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",
|
||||
"perfect-freehand": "^1.0.16",
|
||||
"react-hotkeys-hook": "^3.4.0",
|
||||
"rko": "^0.5.25"
|
||||
"rko": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsconfig-replace-paths": "^0.0.5"
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Tooltip } from '~components/Tooltip'
|
|||
import styled from '~styles'
|
||||
|
||||
export interface ToolButtonProps {
|
||||
onClick?: () => void
|
||||
onSelect?: () => void
|
||||
onDoubleClick?: () => void
|
||||
isActive?: boolean
|
||||
|
@ -12,12 +13,13 @@ export interface 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 (
|
||||
<StyledToolButton
|
||||
ref={ref}
|
||||
isActive={isActive}
|
||||
variant={variant}
|
||||
onClick={onClick}
|
||||
onPointerDown={onSelect}
|
||||
onDoubleClick={onDoubleClick}
|
||||
bp={breakpoints}
|
||||
|
|
|
@ -4,14 +4,14 @@ import { strokes } from '~shape-utils'
|
|||
import { useTheme, useTLDrawContext } from '~hooks'
|
||||
import type { Data, ColorStyle } from '~types'
|
||||
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 { IconButton } from '~components/IconButton'
|
||||
import { ToolButton } from '~components/ToolButton'
|
||||
import { Tooltip } from '~components/Tooltip'
|
||||
|
||||
const selectColor = (s: Data) => s.appState.selectedStyle.color
|
||||
|
||||
const preventEvent = (e: Event) => e.preventDefault()
|
||||
|
||||
export const ColorMenu = React.memo((): JSX.Element => {
|
||||
const { theme } = useTheme()
|
||||
const { tlstate, useSelector } = useTLDrawContext()
|
||||
|
@ -25,17 +25,18 @@ export const ColorMenu = React.memo((): JSX.Element => {
|
|||
</DMTriggerIcon>
|
||||
<DMContent variant="grid">
|
||||
{Object.keys(strokes[theme]).map((colorStyle: string) => (
|
||||
<ToolButton
|
||||
key={colorStyle}
|
||||
variant="icon"
|
||||
isActive={color === colorStyle}
|
||||
onSelect={() => tlstate.style({ color: colorStyle as ColorStyle })}
|
||||
>
|
||||
<BoxIcon
|
||||
fill={strokes[theme][colorStyle as ColorStyle]}
|
||||
stroke={strokes[theme][colorStyle as ColorStyle]}
|
||||
/>
|
||||
</ToolButton>
|
||||
<DropdownMenu.Item key={colorStyle} onSelect={preventEvent} asChild>
|
||||
<ToolButton
|
||||
variant="icon"
|
||||
isActive={color === colorStyle}
|
||||
onClick={() => tlstate.style({ color: colorStyle as ColorStyle })}
|
||||
>
|
||||
<BoxIcon
|
||||
fill={strokes[theme][colorStyle as ColorStyle]}
|
||||
stroke={strokes[theme][colorStyle as ColorStyle]}
|
||||
/>
|
||||
</ToolButton>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DMContent>
|
||||
</DropdownMenu.Root>
|
||||
|
|
|
@ -15,6 +15,8 @@ const dashes = {
|
|||
|
||||
const selectDash = (s: Data) => s.appState.selectedStyle.dash
|
||||
|
||||
const preventEvent = (e: Event) => e.preventDefault()
|
||||
|
||||
export const DashMenu = React.memo((): JSX.Element => {
|
||||
const { tlstate, useSelector } = useTLDrawContext()
|
||||
|
||||
|
@ -24,15 +26,16 @@ export const DashMenu = React.memo((): JSX.Element => {
|
|||
<DropdownMenu.Root dir="ltr">
|
||||
<DMTriggerIcon>{dashes[dash]}</DMTriggerIcon>
|
||||
<DMContent variant="horizontal">
|
||||
{Object.keys(DashStyle).map((dashStyle) => (
|
||||
<ToolButton
|
||||
key={dashStyle}
|
||||
variant="icon"
|
||||
isActive={dash === dashStyle}
|
||||
onSelect={() => tlstate.style({ dash: dashStyle as DashStyle })}
|
||||
>
|
||||
{dashes[dashStyle as DashStyle]}
|
||||
</ToolButton>
|
||||
{Object.values(DashStyle).map((dashStyle) => (
|
||||
<DropdownMenu.Item key={dashStyle} onSelect={preventEvent} asChild>
|
||||
<ToolButton
|
||||
variant="icon"
|
||||
isActive={dash === dashStyle}
|
||||
onClick={() => tlstate.style({ dash: dashStyle as DashStyle })}
|
||||
>
|
||||
{dashes[dashStyle as DashStyle]}
|
||||
</ToolButton>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DMContent>
|
||||
</DropdownMenu.Root>
|
||||
|
|
|
@ -128,6 +128,8 @@ export const StyledDialogOverlay = styled(Dialog.Overlay, {
|
|||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
})
|
||||
|
||||
function DialogAction({ onSelect, ...rest }: RowButtonProps) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react'
|
|||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||
import { Data, SizeStyle } from '~types'
|
||||
import { useTLDrawContext } from '~hooks'
|
||||
import { DMContent, DMTriggerIcon } from '~components/DropdownMenu'
|
||||
import { DMContent, DMItem, DMTriggerIcon } from '~components/DropdownMenu'
|
||||
import { ToolButton } from '~components/ToolButton'
|
||||
import { SizeSmallIcon, SizeMediumIcon, SizeLargeIcon } from '~components/icons'
|
||||
|
||||
|
@ -14,6 +14,8 @@ const sizes = {
|
|||
|
||||
const selectSize = (s: Data) => s.appState.selectedStyle.size
|
||||
|
||||
const preventEvent = (e: Event) => e.preventDefault()
|
||||
|
||||
export const SizeMenu = React.memo((): JSX.Element => {
|
||||
const { tlstate, useSelector } = useTLDrawContext()
|
||||
|
||||
|
@ -23,14 +25,16 @@ export const SizeMenu = React.memo((): JSX.Element => {
|
|||
<DropdownMenu.Root dir="ltr">
|
||||
<DMTriggerIcon>{sizes[size as SizeStyle]}</DMTriggerIcon>
|
||||
<DMContent variant="horizontal">
|
||||
{Object.keys(SizeStyle).map((sizeStyle: string) => (
|
||||
<ToolButton
|
||||
key={sizeStyle}
|
||||
isActive={size === sizeStyle}
|
||||
onSelect={() => tlstate.style({ size: sizeStyle as SizeStyle })}
|
||||
>
|
||||
{sizes[sizeStyle as SizeStyle]}
|
||||
</ToolButton>
|
||||
{Object.values(SizeStyle).map((sizeStyle: string) => (
|
||||
<DropdownMenu.Item key={sizeStyle} onSelect={preventEvent} asChild>
|
||||
<ToolButton
|
||||
isActive={size === sizeStyle}
|
||||
variant="icon"
|
||||
onClick={() => tlstate.style({ size: sizeStyle as SizeStyle })}
|
||||
>
|
||||
{sizes[sizeStyle as SizeStyle]}
|
||||
</ToolButton>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DMContent>
|
||||
</DropdownMenu.Root>
|
||||
|
|
|
@ -5,7 +5,7 @@ Object {
|
|||
"bend": 0,
|
||||
"childIndex": 1,
|
||||
"decorations": Object {
|
||||
"end": "Arrow",
|
||||
"end": "arrow",
|
||||
},
|
||||
"handles": Object {
|
||||
"bend": Object {
|
||||
|
@ -44,10 +44,10 @@ Object {
|
|||
],
|
||||
"rotation": 0,
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "arrow",
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ Object {
|
|||
"points": Array [],
|
||||
"rotation": 0,
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "draw",
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@ Object {
|
|||
],
|
||||
"rotation": 0,
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "ellipse",
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ Object {
|
|||
100,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "group",
|
||||
}
|
||||
|
|
|
@ -16,10 +16,10 @@ Object {
|
|||
1,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "rectangle",
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ Object {
|
|||
],
|
||||
"rotation": 0,
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"text": " ",
|
||||
"type": "text",
|
||||
|
|
|
@ -33,10 +33,10 @@ Array [
|
|||
200,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"type": "rectangle",
|
||||
},
|
||||
|
@ -93,10 +93,10 @@ Array [
|
|||
200,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
"dash": "Draw",
|
||||
"color": "black",
|
||||
"dash": "draw",
|
||||
"isFilled": false,
|
||||
"size": "Small",
|
||||
"size": "small",
|
||||
},
|
||||
"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 type { BaseTool } from './tool/BaseTool'
|
||||
import { USER_COLORS, FIT_TO_SCREEN_PADDING } from '~constants'
|
||||
import { migrate } from './migrate'
|
||||
|
||||
const uuid = Utils.uniqueId()
|
||||
|
||||
|
@ -100,21 +101,15 @@ export class TLDrawState extends StateManager<Data> {
|
|||
onUserChange?: (tlstate: TLDrawState, user: TLDrawUser) => void
|
||||
) {
|
||||
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 {
|
||||
...next,
|
||||
document: { ...next.document, ...prev.document },
|
||||
}
|
||||
})
|
||||
|
||||
this.loadDocument(this.document)
|
||||
this.patchState({ document: migrate(this.document, TLDrawState.version) })
|
||||
|
||||
this._onChange = onChange
|
||||
this._onMount = onMount
|
||||
this._onUserChange = onUserChange
|
||||
|
@ -130,6 +125,7 @@ export class TLDrawState extends StateManager<Data> {
|
|||
appState: {
|
||||
status: TLDrawStatus.Idle,
|
||||
},
|
||||
document: migrate(this.document, TLDrawState.version),
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('The data appears to be corrupted. Resetting!', e)
|
||||
|
@ -641,7 +637,7 @@ export class TLDrawState extends StateManager<Data> {
|
|||
...this.appState,
|
||||
currentPageId: Object.keys(document.pages)[0],
|
||||
},
|
||||
document,
|
||||
document: migrate(document, TLDrawState.version),
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
@ -709,7 +705,7 @@ export class TLDrawState extends StateManager<Data> {
|
|||
...this.state,
|
||||
appState: nextAppState,
|
||||
document: {
|
||||
...document,
|
||||
...migrate(document, TLDrawState.version),
|
||||
pageStates: currentPageStates,
|
||||
},
|
||||
},
|
||||
|
@ -803,7 +799,7 @@ export class TLDrawState extends StateManager<Data> {
|
|||
return this.replaceState(
|
||||
{
|
||||
...TLDrawState.defaultState,
|
||||
document,
|
||||
document: migrate(document, TLDrawState.version),
|
||||
appState: {
|
||||
...TLDrawState.defaultState.appState,
|
||||
currentPageId: Object.keys(document.pages)[0],
|
||||
|
@ -1068,8 +1064,6 @@ export class TLDrawState extends StateManager<Data> {
|
|||
Utils.deepClone(this.getShape(id, this.currentPageId))
|
||||
)
|
||||
|
||||
console.log(copyingShapes.length)
|
||||
|
||||
if (copyingShapes.length === 0) return this
|
||||
|
||||
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 = {
|
||||
id: 'doc',
|
||||
version: 12.4,
|
||||
pages: {
|
||||
page: {
|
||||
id: 'page',
|
||||
|
|
|
@ -46,8 +46,6 @@ export abstract class BaseTool<T extends string = any> {
|
|||
}
|
||||
|
||||
onCancel = () => {
|
||||
console.log('cancelling')
|
||||
|
||||
if (this.status === Status.Idle) {
|
||||
this.state.selectTool('select')
|
||||
} else {
|
||||
|
|
|
@ -11,8 +11,6 @@ export class TextTool extends BaseTool {
|
|||
stopEditingShape = () => {
|
||||
this.setStatus(Status.Idle)
|
||||
|
||||
console.log(this.state.appState.isToolLocked)
|
||||
|
||||
if (!this.state.appState.isToolLocked) {
|
||||
this.state.selectTool('select')
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ import oldDoc from './old-doc'
|
|||
|
||||
describe('When migrating bindings', () => {
|
||||
it('migrates', () => {
|
||||
Object.values((oldDoc as unknown as TLDrawDocument).pages).forEach((page) => {
|
||||
Object.values(page.bindings).forEach((binding) => {
|
||||
if ('meta' in binding) {
|
||||
// @ts-ignore
|
||||
Object.assign(binding, binding.meta)
|
||||
}
|
||||
})
|
||||
})
|
||||
// Object.values((oldDoc as unknown as TLDrawDocument).pages).forEach((page) => {
|
||||
// Object.values(page.bindings).forEach((binding) => {
|
||||
// if ('meta' in binding) {
|
||||
// // @ts-ignore
|
||||
// Object.assign(binding, binding.meta)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
|
||||
new TLDrawState().loadDocument(oldDoc as unknown as TLDrawDocument)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { TLDrawDocument, ColorStyle, DashStyle, SizeStyle, TLDrawShapeType } from '~types'
|
||||
|
||||
export const mockDocument: TLDrawDocument = {
|
||||
version: 0,
|
||||
id: 'doc',
|
||||
pages: {
|
||||
page1: {
|
||||
|
|
|
@ -9,7 +9,6 @@ import type {
|
|||
TLHandle,
|
||||
TLBounds,
|
||||
TLSnapLine,
|
||||
TLComponentProps,
|
||||
} from '@tldraw/core'
|
||||
import type { TLPage, TLUser, TLPageState } from '@tldraw/core'
|
||||
import type { StoreApi } from 'zustand'
|
||||
|
@ -28,12 +27,6 @@ export interface TLDrawTransformInfo<T extends TLShape> {
|
|||
transformOrigin: number[]
|
||||
}
|
||||
|
||||
export type TLDrawComponentProps<T extends TLDrawShape, E extends Element = any> = TLComponentProps<
|
||||
T,
|
||||
E,
|
||||
TLDrawMeta
|
||||
>
|
||||
|
||||
// old
|
||||
export type TLStore = StoreApi<Data>
|
||||
|
||||
|
@ -45,6 +38,7 @@ export interface TLDrawDocument {
|
|||
id: string
|
||||
pages: Record<string, TLDrawPage>
|
||||
pageStates: Record<string, TLPageState>
|
||||
version: number
|
||||
}
|
||||
|
||||
export interface TLDrawSettings {
|
||||
|
@ -229,7 +223,7 @@ export enum TLDrawShapeType {
|
|||
}
|
||||
|
||||
export enum Decoration {
|
||||
Arrow = 'Arrow',
|
||||
Arrow = 'arrow',
|
||||
}
|
||||
|
||||
export interface TLDrawBaseShape extends TLShape {
|
||||
|
@ -304,38 +298,38 @@ export interface ArrowBinding extends TLBinding {
|
|||
export type TLDrawBinding = ArrowBinding
|
||||
|
||||
export enum ColorStyle {
|
||||
White = 'White',
|
||||
LightGray = 'LightGray',
|
||||
Gray = 'Gray',
|
||||
Black = 'Black',
|
||||
Green = 'Green',
|
||||
Cyan = 'Cyan',
|
||||
Blue = 'Blue',
|
||||
Indigo = 'Indigo',
|
||||
Violet = 'Violet',
|
||||
Red = 'Red',
|
||||
Orange = 'Orange',
|
||||
Yellow = 'Yellow',
|
||||
White = 'white',
|
||||
LightGray = 'lightGray',
|
||||
Gray = 'gray',
|
||||
Black = 'black',
|
||||
Green = 'green',
|
||||
Cyan = 'cyan',
|
||||
Blue = 'blue',
|
||||
Indigo = 'indigo',
|
||||
Violet = 'violet',
|
||||
Red = 'red',
|
||||
Orange = 'orange',
|
||||
Yellow = 'yellow',
|
||||
}
|
||||
|
||||
export enum SizeStyle {
|
||||
Small = 'Small',
|
||||
Medium = 'Medium',
|
||||
Large = 'Large',
|
||||
Small = 'small',
|
||||
Medium = 'medium',
|
||||
Large = 'large',
|
||||
}
|
||||
|
||||
export enum DashStyle {
|
||||
Draw = 'Draw',
|
||||
Solid = 'Solid',
|
||||
Dashed = 'Dashed',
|
||||
Dotted = 'Dotted',
|
||||
Draw = 'draw',
|
||||
Solid = 'solid',
|
||||
Dashed = 'dashed',
|
||||
Dotted = 'dotted',
|
||||
}
|
||||
|
||||
export enum FontSize {
|
||||
Small = 'Small',
|
||||
Medium = 'Medium',
|
||||
Large = 'Large',
|
||||
ExtraLarge = 'ExtraLarge',
|
||||
Small = 'small',
|
||||
Medium = 'medium',
|
||||
Large = 'large',
|
||||
ExtraLarge = 'extraLarge',
|
||||
}
|
||||
|
||||
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,
|
||||
document: {
|
||||
id: 'test-room',
|
||||
pages: {
|
||||
page: {
|
||||
id: 'page',
|
||||
shapes: {},
|
||||
bindings: {},
|
||||
},
|
||||
},
|
||||
pageStates: {
|
||||
page: {
|
||||
id: 'page',
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
...TLDrawState.defaultDocument,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -156,7 +140,11 @@ function Editor({ id }: { id: string }) {
|
|||
doc.subscribe(handleDocumentUpdates)
|
||||
|
||||
// Load the shared document
|
||||
tlstate.loadDocument(doc.toObject().document)
|
||||
const newDocument = doc.toObject().document
|
||||
|
||||
if (newDocument) {
|
||||
tlstate.loadDocument(newDocument)
|
||||
}
|
||||
|
||||
return () => {
|
||||
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": {
|
||||
"composite": true,
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -9920,7 +9920,7 @@ raw-body@2.4.1:
|
|||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
react-dom@17.0.2, "react-dom@^16.8 || ^17.0":
|
||||
react-dom@17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
||||
|
@ -10008,7 +10008,7 @@ react-style-singleton@^2.1.0:
|
|||
invariant "^2.2.4"
|
||||
tslib "^1.0.0"
|
||||
|
||||
react@17.0.2, react@>=16.8:
|
||||
react@17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
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"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rko@^0.5.25:
|
||||
version "0.5.25"
|
||||
resolved "https://registry.yarnpkg.com/rko/-/rko-0.5.25.tgz#1095803900e3f912f6adf8a1c113b8227d3d88bf"
|
||||
integrity sha512-HU6M3PxK3VEqrr6QZKAsqO98juQX24kEgJkKSdFJhw8U/DBUGAnU/fgyxNIaTw7TCI7vjIy/RzBEXf5I4sijKg==
|
||||
rko@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/rko/-/rko-0.6.0.tgz#fa640384b4e82fdcd90fc58c958256148c4eb10c"
|
||||
integrity sha512-u05SAiyz02Sw+QyGaQb3NGPXf3xXxQ9AwNG+tItHx2MpAsPEEH84NqYDyG9jem/ji/FPQPQHuRKcy2MHb1a1Ow==
|
||||
dependencies:
|
||||
idb-keyval "^5.1.3"
|
||||
zustand "^3.5.9"
|
||||
|
|
Loading…
Reference in a new issue