Make core asset types more generic, update docs.

This commit is contained in:
Steve Ruiz 2021-12-25 18:39:50 +00:00
parent bd09342596
commit 0ed7e55c4c
7 changed files with 60 additions and 40 deletions

View file

@ -93,6 +93,7 @@ const myDocument: TDDocument = {
},
},
},
assets: {},
}
function App() {
@ -102,6 +103,8 @@ function App() {
**Tip:** The pages and pageStates in tldraw are objects containing `TLPage` and `TLPageState` objects from the [@tldraw/core](https://github.com/tldraw/core) library.
**Tip:** The `assets` in tldraw is a table of `TDAssets` (images and videos).
**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

View file

@ -82,10 +82,11 @@ function App() {
To avoid unnecessary renders, be sure to pass "stable" values as props to the `Renderer`. Either define these values outside of the parent component, or place them in React state, or memoize them with `React.useMemo`.
| Prop | Type | Description |
| ------------ | ------------------------------- | ---------------------------------------------- |
| ------------ | ------------------------------- | ------------------------------------------------ |
| `page` | [`TLPage`](#tlpage) | The current page object. |
| `pageState` | [`TLPageState`](#tlpagestate) | The current page's state. |
| `shapeUtils` | [`TLShapeUtils`](#tlshapeutils) | The shape utilities used to render the shapes. |
| `assets` | [`TLAssets`](#tlassets) | A table of assets used by shapes in the project. |
In addition to these required props, the Renderer accents many other **optional** props.
@ -206,6 +207,17 @@ An object describing the current page. It contains:
| `bindingId` | `string` | (optional) The currently editing binding. |
| `brush` | `TLBounds` | (optional) A `Bounds` for the current selection box |
### `TLAsset`
An object describing the current page. It contains:
| Property | Type | Description |
| -------- | -------- | -------------------------- |
| `id` | `string` | A unique id for the asset. |
| `type` | `string` | The type of the asset. |
Specific asset types may describe additional properties.
### `TLShape`
An object that describes a shape on the page. The shapes in your document should extend this interface with other properties. See [Shape Type](#shape-type).

View file

@ -6,30 +6,11 @@ import type React from 'react'
export type TLAssets = Record<string, TLAsset>
export enum TLAssetType {
Image = 'image',
Video = 'video',
}
export interface TLBaseAsset {
export interface TLAsset {
id: string
type: TLAssetType
type: string
}
export interface TLImageAsset extends TLBaseAsset {
type: TLAssetType.Image
src: string
size: number[]
}
export interface TLVideoAsset extends TLBaseAsset {
type: TLAssetType.Video
src: string
size: number[]
}
export type TLAsset = TLImageAsset | TLVideoAsset
export type Patch<T> = Partial<{ [P in keyof T]: T | Partial<T> | Patch<T[P]> }>
export type TLForwardedRef<T> =

View file

@ -15,8 +15,6 @@ import {
Utils,
TLBounds,
TLDropEventHandler,
TLAssetType,
TLAsset,
} from '@tldraw/core'
import {
FlipType,
@ -37,6 +35,8 @@ import {
TDUser,
SessionType,
TDToolType,
TDAssetType,
TDAsset,
} from '~types'
import {
migrate,
@ -214,7 +214,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
clipboard?: {
shapes: TDShape[]
bindings: TDBinding[]
assets: TLAsset[]
assets: TDAsset[]
}
rotationInfo = {
@ -1646,7 +1646,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
if (!shape.assetId) return
return this.document.assets[shape.assetId]
})
.filter(Boolean) as TLAsset[]
.filter(Boolean) as TDAsset[]
this.clipboard = {
shapes: copyingShapes,
bindings: copyingBindings,
@ -1690,7 +1690,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
*/
paste = (point?: number[]) => {
if (this.readOnly) return
const pasteInCurrentPage = (shapes: TDShape[], bindings: TDBinding[], assets: TLAsset[]) => {
const pasteInCurrentPage = (shapes: TDShape[], bindings: TDBinding[], assets: TDAsset[]) => {
const idsMap: Record<string, string> = {}
const newAssets = assets.filter((asset) => this.document.assets[asset.id] === undefined)
if (newAssets.length) {
@ -1773,7 +1773,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
type: string
shapes: TDShape[]
bindings: TDBinding[]
assets: TLAsset[]
assets: TDAsset[]
} = JSON.parse(result)
if (data.type !== 'tldr/clipboard') {
throw Error('The pasted string was not from the Tldraw clipboard.')
@ -2821,7 +2821,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
let assetId = Utils.uniqueId()
const pagePoint = this.getPagePoint(point)
const shapeType = isImage ? TDShapeType.Image : TDShapeType.Video
const assetType = isImage ? TLAssetType.Image : TLAssetType.Video
const assetType = isImage ? TDAssetType.Image : TDAssetType.Video
const size = isImage ? await getSizeFromDataurl(dataurl) : [401.42, 401.42] // special
const match = Object.values(this.document.assets).find(
(asset) => asset.type === assetType && asset.src === dataurl

View file

@ -1,6 +1,6 @@
import * as React from 'react'
import { Utils, HTMLContainer } from '@tldraw/core'
import { TDShapeType, TDMeta, ImageShape } from '~types'
import { TDShapeType, TDMeta, ImageShape, TDAsset, TDImageAsset } from '~types'
import { GHOSTED_OPACITY } from '~constants'
import { TDShapeUtil } from '../TDShapeUtil'
import {
@ -89,7 +89,7 @@ export class ImageUtil extends TDShapeUtil<T, E> {
>
<ImageElement
ref={imgRef}
src={asset.src}
src={(asset as TDImageAsset).src}
alt="tl_image_asset"
draggable={false}
onLoad={onImageLoad}

View file

@ -1,6 +1,6 @@
import * as React from 'react'
import { Utils, HTMLContainer } from '@tldraw/core'
import { TDShapeType, TDMeta, VideoShape } from '~types'
import { TDShapeType, TDMeta, VideoShape, TDVideoAsset } from '~types'
import { GHOSTED_OPACITY } from '~constants'
import { TDShapeUtil } from '../TDShapeUtil'
import {
@ -45,7 +45,10 @@ export class VideoUtil extends TDShapeUtil<T, E> {
}
Component = TDShapeUtil.Component<T, E, TDMeta>(
({ shape, asset, isBinding, isEditing, isGhost, meta, events, onShapeChange }, ref) => {
(
{ shape, asset = { src: '' }, isBinding, isEditing, isGhost, meta, events, onShapeChange },
ref
) => {
const rVideo = React.useRef<HTMLVideoElement>(null)
const wrapperRef = React.useRef<HTMLDivElement>(null)
@ -137,7 +140,7 @@ export class VideoUtil extends TDShapeUtil<T, E> {
onTimeUpdate={handleSetCurrentTime}
onLoadedMetadata={onImageLoad}
>
<source src={asset?.src} />
<source src={(asset as TDVideoAsset).src} />
</VideoElement>
</Wrapper>
</HTMLContainer>

View file

@ -19,7 +19,7 @@ import type {
TLBoundsHandleEventHandler,
TLShapeBlurHandler,
TLShapeCloneHandler,
TLAssets,
TLAsset,
} from '@tldraw/core'
/* -------------------------------------------------- */
@ -133,7 +133,7 @@ export interface TDDocument {
version: number
pages: Record<string, TDPage>
pageStates: Record<string, TLPageState>
assets: TLAssets
assets: TDAssets
}
// The shape of a single page in the Tldraw document
@ -458,6 +458,27 @@ export type ShapeStyles = {
scale?: number
}
export enum TDAssetType {
Image = 'image',
Video = 'video',
}
export interface TDImageAsset extends TLAsset {
type: TDAssetType.Image
src: string
size: number[]
}
export interface TDVideoAsset extends TLAsset {
type: TDAssetType.Video
src: string
size: number[]
}
export type TDAsset = TDImageAsset | TDVideoAsset
export type TDAssets = Record<string, TDAsset>
/* -------------------------------------------------- */
/* Type Helpers */
/* -------------------------------------------------- */