tldraw zero - package shuffle (#1710)
This PR moves code between our packages so that:
- @tldraw/editor is a “core” library with the engine and canvas but no
shapes, tools, or other things
- @tldraw/tldraw contains everything particular to the experience we’ve
built for tldraw
At first look, this might seem like a step away from customization and
configuration, however I believe it greatly increases the configuration
potential of the @tldraw/editor while also providing a more accurate
reflection of what configuration options actually exist for
@tldraw/tldraw.
## Library changes
@tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports
@tldraw/editor.
- users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always
only import things from @tldraw/editor.
- users of @tldraw/tldraw should almost always only import things from
@tldraw/tldraw.
- @tldraw/polyfills is merged into @tldraw/editor
- @tldraw/indices is merged into @tldraw/editor
- @tldraw/primitives is merged mostly into @tldraw/editor, partially
into @tldraw/tldraw
- @tldraw/file-format is merged into @tldraw/tldraw
- @tldraw/ui is merged into @tldraw/tldraw
Many (many) utils and other code is moved from the editor to tldraw. For
example, embeds now are entirely an feature of @tldraw/tldraw. The only
big chunk of code left in core is related to arrow handling.
## API Changes
The editor can now be used without tldraw's assets. We load them in
@tldraw/tldraw instead, so feel free to use whatever fonts or images or
whatever that you like with the editor.
All tools and shapes (except for the `Group` shape) are moved to
@tldraw/tldraw. This includes the `select` tool.
You should use the editor with at least one tool, however, so you now
also need to send in an `initialState` prop to the Editor /
<TldrawEditor> component indicating which state the editor should begin
in.
The `components` prop now also accepts `SelectionForeground`.
The complex selection component that we use for tldraw is moved to
@tldraw/tldraw. The default component is quite basic but can easily be
replaced via the `components` prop. We pass down our tldraw-flavored
SelectionFg via `components`.
Likewise with the `Scribble` component: the `DefaultScribble` no longer
uses our freehand tech and is a simple path instead. We pass down the
tldraw-flavored scribble via `components`.
The `ExternalContentManager` (`Editor.externalContentManager`) is
removed and replaced with a mapping of types to handlers.
- Register new content handlers with
`Editor.registerExternalContentHandler`.
- Register new asset creation handlers (for files and URLs) with
`Editor.registerExternalAssetHandler`
### Change Type
- [x] `major` — Breaking change
### Test Plan
- [x] Unit Tests
- [x] End to end tests
### Release Notes
- [@tldraw/editor] lots, wip
- [@tldraw/ui] gone, merged to tldraw/tldraw
- [@tldraw/polyfills] gone, merged to tldraw/editor
- [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw
- [@tldraw/indices] gone, merged to tldraw/editor
- [@tldraw/file-format] gone, merged to tldraw/tldraw
---------
Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
|
|
|
import assert from 'assert'
|
2023-06-03 20:46:53 +00:00
|
|
|
import { BaseRecord, RecordId } from '../BaseRecord'
|
2023-04-25 11:01:25 +00:00
|
|
|
import { createRecordType } from '../RecordType'
|
|
|
|
import { StoreSchema } from '../StoreSchema'
|
|
|
|
|
|
|
|
/** A user of tldraw */
|
2023-06-03 20:46:53 +00:00
|
|
|
interface User extends BaseRecord<'user', RecordId<User>> {
|
2023-04-25 11:01:25 +00:00
|
|
|
name: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const User = createRecordType<User>('user', {
|
|
|
|
validator: {
|
|
|
|
validate: (record) => {
|
|
|
|
assert(
|
|
|
|
record && typeof record === 'object' && 'name' in record && typeof record.name === 'string'
|
|
|
|
)
|
|
|
|
return record as User
|
|
|
|
},
|
|
|
|
},
|
derived presence state (#1204)
This PR adds
- A new `TLInstancePresence` record type, to collect info about the
presence state in a particular instance of the editor. This will
eventually be used to sync presence data instead of sending
instance-only state across the wire.
- **Record Scopes**
`RecordType` now has a `scope` property which can be one of three
things:
- `document`: the record belongs to the document and should be synced
and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and
`TLAsset`
- `instance`: the record belongs to a single instance of the store and
should not be synced at all. It should not be persisted directly in most
cases, but rather compiled into a kind of 'instance configuration' to
store alongside the local document data so that when reopening the
associated document it can remember some of the previous instance state.
Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`,
`TLUserDocument`, `TLUserPresence`
- `presence`: the record belongs to a single instance of the store and
should not be persisted, but may be synced using the special presence
sync protocol. Currently just `TLInstancePresence`
This sets us up for the following changes, which are gonna be pretty
high-impact in terms of integrating tldraw into existing systems:
- Removing `instanceId` as a config option. Each instance gets a
randomly generated ID.
- We'd replace it with an `instanceConfig` option that has stuff like
selectedIds, camera positions, and so on. Then it's up to library users
to get and reinstate the instance config at persistence boundaries.
- Removing `userId` as config option, and removing the `TLUser` type
altogether.
- We might need to revisit when doing auth-enabled features like locking
shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
|
|
|
scope: 'document',
|
2023-04-25 11:01:25 +00:00
|
|
|
})
|
|
|
|
|
2023-06-03 20:46:53 +00:00
|
|
|
interface Shape<Props> extends BaseRecord<'shape', RecordId<Shape<object>>> {
|
2023-04-25 11:01:25 +00:00
|
|
|
type: string
|
|
|
|
x: number
|
|
|
|
y: number
|
|
|
|
props: Props
|
|
|
|
}
|
|
|
|
|
|
|
|
interface RectangleProps {
|
|
|
|
width: number
|
|
|
|
height: number
|
|
|
|
opactiy: number
|
|
|
|
}
|
|
|
|
|
|
|
|
interface OvalProps {
|
|
|
|
radius: number
|
|
|
|
borderStyle: 'solid' | 'dashed'
|
|
|
|
}
|
|
|
|
|
|
|
|
const Shape = createRecordType<Shape<RectangleProps | OvalProps>>('shape', {
|
|
|
|
validator: {
|
|
|
|
validate: (record) => {
|
|
|
|
assert(
|
|
|
|
record &&
|
|
|
|
typeof record === 'object' &&
|
|
|
|
'type' in record &&
|
|
|
|
typeof record.type === 'string' &&
|
|
|
|
'x' in record &&
|
|
|
|
typeof record.x === 'number' &&
|
|
|
|
'y' in record &&
|
|
|
|
typeof record.y === 'number' &&
|
|
|
|
'props' in record &&
|
|
|
|
typeof record.props === 'object'
|
|
|
|
)
|
|
|
|
return record as Shape<RectangleProps | OvalProps>
|
|
|
|
},
|
|
|
|
},
|
derived presence state (#1204)
This PR adds
- A new `TLInstancePresence` record type, to collect info about the
presence state in a particular instance of the editor. This will
eventually be used to sync presence data instead of sending
instance-only state across the wire.
- **Record Scopes**
`RecordType` now has a `scope` property which can be one of three
things:
- `document`: the record belongs to the document and should be synced
and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and
`TLAsset`
- `instance`: the record belongs to a single instance of the store and
should not be synced at all. It should not be persisted directly in most
cases, but rather compiled into a kind of 'instance configuration' to
store alongside the local document data so that when reopening the
associated document it can remember some of the previous instance state.
Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`,
`TLUserDocument`, `TLUserPresence`
- `presence`: the record belongs to a single instance of the store and
should not be persisted, but may be synced using the special presence
sync protocol. Currently just `TLInstancePresence`
This sets us up for the following changes, which are gonna be pretty
high-impact in terms of integrating tldraw into existing systems:
- Removing `instanceId` as a config option. Each instance gets a
randomly generated ID.
- We'd replace it with an `instanceConfig` option that has stuff like
selectedIds, camera positions, and so on. Then it's up to library users
to get and reinstate the instance config at persistence boundaries.
- Removing `userId` as config option, and removing the `TLUser` type
altogether.
- We might need to revisit when doing auth-enabled features like locking
shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
|
|
|
scope: 'document',
|
2023-04-25 11:01:25 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
// this interface only exists to be removed
|
2023-06-03 20:46:53 +00:00
|
|
|
interface Org extends BaseRecord<'org', RecordId<Org>> {
|
2023-04-25 11:01:25 +00:00
|
|
|
name: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const Org = createRecordType<Org>('org', {
|
|
|
|
validator: {
|
|
|
|
validate: (record) => {
|
|
|
|
assert(
|
|
|
|
record && typeof record === 'object' && 'name' in record && typeof record.name === 'string'
|
|
|
|
)
|
|
|
|
return record as Org
|
|
|
|
},
|
|
|
|
},
|
derived presence state (#1204)
This PR adds
- A new `TLInstancePresence` record type, to collect info about the
presence state in a particular instance of the editor. This will
eventually be used to sync presence data instead of sending
instance-only state across the wire.
- **Record Scopes**
`RecordType` now has a `scope` property which can be one of three
things:
- `document`: the record belongs to the document and should be synced
and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and
`TLAsset`
- `instance`: the record belongs to a single instance of the store and
should not be synced at all. It should not be persisted directly in most
cases, but rather compiled into a kind of 'instance configuration' to
store alongside the local document data so that when reopening the
associated document it can remember some of the previous instance state.
Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`,
`TLUserDocument`, `TLUserPresence`
- `presence`: the record belongs to a single instance of the store and
should not be persisted, but may be synced using the special presence
sync protocol. Currently just `TLInstancePresence`
This sets us up for the following changes, which are gonna be pretty
high-impact in terms of integrating tldraw into existing systems:
- Removing `instanceId` as a config option. Each instance gets a
randomly generated ID.
- We'd replace it with an `instanceConfig` option that has stuff like
selectedIds, camera positions, and so on. Then it's up to library users
to get and reinstate the instance config at persistence boundaries.
- Removing `userId` as config option, and removing the `TLUser` type
altogether.
- We might need to revisit when doing auth-enabled features like locking
shapes, but I suspect that will be separate.
2023-04-27 18:03:19 +00:00
|
|
|
scope: 'document',
|
2023-04-25 11:01:25 +00:00
|
|
|
})
|
|
|
|
|
2024-04-16 11:13:54 +00:00
|
|
|
export const testSchemaV0 = StoreSchema.create({
|
|
|
|
user: User,
|
|
|
|
shape: Shape,
|
|
|
|
org: Org,
|
|
|
|
})
|