Bindings documentation (#3812)
Adds docs (reference material and a guide) for the bindings API. Also, the unbind reason enum is now a union of strings. ### Change Type - [x] `docs` — Changes to the documentation, examples, or templates. - [x] `improvement` — Improving existing features
This commit is contained in:
parent
ccb6b918c5
commit
f5a6ed7b91
6 changed files with 352 additions and 62 deletions
|
@ -387,6 +387,108 @@ The camera may be in two states, `idle` or `moving`.
|
|||
|
||||
You can get the current camera state with [Editor#getCameraState](?).
|
||||
|
||||
# Bindings
|
||||
|
||||
A binding is a relationship from one [shape](/docs/shapes) to another. They're used to connect
|
||||
shapes so they can update together or depend on one and other. For example: tldraw's default arrow
|
||||
shape uses bindings to connect the ends of the arrows to the shapes they're pointing to, one binding
|
||||
for each end of the arrow.
|
||||
|
||||
You can create different types of binding that do all sorts of different things with relationships
|
||||
between shapes. For example, you could create a [sticker
|
||||
shape](/examples/shapes/tools/sticker-bindings) that sticks to any other shape it's dropped onto.
|
||||
|
||||
## The binding object
|
||||
|
||||
Bindings are records (JSON objects) that live in the [store](/docs/editor#store). For example,
|
||||
here's a binding record for one end of an arrow shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "binding:someId",
|
||||
"typeName": "binding"
|
||||
"type": "arrow",
|
||||
"fromId": "shape:arrowId",
|
||||
"toId": "shape:someOtherShapeId",
|
||||
"props": {
|
||||
"terminal": "end"
|
||||
"isPrecise": true,
|
||||
"isExact": false,
|
||||
"normalizedAnchor": {
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
},
|
||||
"meta": {},
|
||||
}
|
||||
```
|
||||
|
||||
Every binding contains some base information - its ID & the type of binding, as well as the ID of
|
||||
the shape that a binding comes _from_ and the ID of the shape that the binding goes _to_. These two
|
||||
properties work the same way, but it's often useful to have an explicit direction in a binding
|
||||
relationship. For example, an arrow binding always goes _from_ an arrow _to_ another shape.
|
||||
|
||||
Bindings contain their own type-specific information in the `props` object. Each type of binding can
|
||||
have different props.
|
||||
|
||||
Bindings also have a `meta` property which can be used by your application to add data to bindings
|
||||
you haven't built yourself. You can read more about the meta property
|
||||
[here](/docs/shapes#Meta-information).
|
||||
|
||||
## Custom bindings
|
||||
|
||||
To create a binding of your own, you can define a custom binding.
|
||||
|
||||
### The binding type
|
||||
|
||||
First, you need to create a type that describes what the binding object will look like:
|
||||
|
||||
```ts
|
||||
import { TLBaseBinding } from 'tldraw'
|
||||
|
||||
type StickerBinding = TLBaseBinding<'sticker', { x: number; y: number }>
|
||||
```
|
||||
|
||||
With [TLBaseBinding](?) we define the binding's type (`sticker`) and `props` property (`{x: number,
|
||||
y: number}`). The type can be any string, and the props must be a plain JSON object (ie not a class
|
||||
instance).
|
||||
|
||||
The [TLBaseBinding](?) helper adds the other base properties like `id`, `toId`, and `fromId`.
|
||||
|
||||
### The `BindingUtil` class
|
||||
|
||||
While bindings themselves are plain JSON objects, we use
|
||||
[`BindingUtil`](/reference/editor/BindingUtil) classes to define how bindings should work. They tell
|
||||
tldraw the structure of a binding, and what to do when it or the shapes it involves are created,
|
||||
updated, or deleted.
|
||||
|
||||
```ts
|
||||
import { BindingUtil } from 'tldraw'
|
||||
|
||||
class StickerBindingUtil extends BindingUtil<StickerBinding> {
|
||||
static override type = 'sticker' as const
|
||||
|
||||
override getDefaultProps() {
|
||||
return { x: 0.5, y: 0.5 }
|
||||
}
|
||||
|
||||
override onAfterChangeToShape({ binding }) {
|
||||
const sticker = this.editor.getShape(binding.fromShape)
|
||||
|
||||
// move the sticker so it stays attached to the to shape
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each binding util needs a `type` and `getDefaultProps` to define its basic structure. You can also
|
||||
define a number of different callbacks describing how the binding should behave. See the
|
||||
[BindingUtil](?) reference or a [complete example of a
|
||||
binding](/examples/shapes/tools/sticker-bindings) for details.
|
||||
|
||||
If the strucutre of your binding needs to change over time, you can provide
|
||||
[migrations](/docs/persistence#Shape-props-migrations) describing how old stored bindings can be
|
||||
brought up to date.
|
||||
|
||||
# Common things to do with the editor
|
||||
|
||||
### Create a shape id
|
||||
|
|
|
@ -175,50 +175,39 @@ export abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> extends Sha
|
|||
onResize: TLOnResizeHandler<any>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
bindingAfter: Binding;
|
||||
// (undocumented)
|
||||
bindingBefore: Binding;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
binding: Binding;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
binding: Binding;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
binding: Binding;
|
||||
// (undocumented)
|
||||
shapeAfter: TLShape;
|
||||
// (undocumented)
|
||||
shapeBefore: TLShape;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
binding: Binding;
|
||||
// (undocumented)
|
||||
shape: TLShape;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding> {
|
||||
// (undocumented)
|
||||
binding: Binding;
|
||||
// (undocumented)
|
||||
shape: TLShape;
|
||||
removedShape: TLShape;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
|
@ -229,31 +218,18 @@ export abstract class BindingUtil<Binding extends TLUnknownBinding = TLUnknownBi
|
|||
abstract getDefaultProps(): Partial<Binding['props']>;
|
||||
// (undocumented)
|
||||
static migrations?: TLPropsMigrations;
|
||||
// (undocumented)
|
||||
onAfterChange?(options: BindingOnChangeOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onAfterChangeFromShape?(options: BindingOnShapeChangeOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onAfterChangeToShape?(options: BindingOnShapeChangeOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onAfterCreate?(options: BindingOnCreateOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onAfterDelete?(options: BindingOnDeleteOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onBeforeChange?(options: BindingOnChangeOptions<Binding>): Binding | void;
|
||||
// (undocumented)
|
||||
onBeforeCreate?(options: BindingOnCreateOptions<Binding>): Binding | void;
|
||||
// (undocumented)
|
||||
onBeforeDelete?(options: BindingOnDeleteOptions<Binding>): Binding | void;
|
||||
// (undocumented)
|
||||
onBeforeDelete?(options: BindingOnDeleteOptions<Binding>): void;
|
||||
onBeforeDeleteFromShape?(options: BindingOnShapeDeleteOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onBeforeDeleteToShape?(options: BindingOnShapeDeleteOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onBeforeIsolateFromShape?(options: BindingOnShapeIsolateOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onBeforeIsolateToShape?(options: BindingOnShapeIsolateOptions<Binding>): void;
|
||||
// (undocumented)
|
||||
onOperationComplete?(): void;
|
||||
// (undocumented)
|
||||
static props?: RecordProps<TLUnknownBinding>;
|
||||
|
@ -790,9 +766,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
// @internal (undocumented)
|
||||
crash(error: unknown): this;
|
||||
createAssets(assets: TLAsset[]): this;
|
||||
// (undocumented)
|
||||
createBinding<B extends TLBinding = TLBinding>(partial: TLBindingCreate<B>): this;
|
||||
// (undocumented)
|
||||
createBindings(partials: TLBindingCreate[]): this;
|
||||
// @internal (undocumented)
|
||||
createErrorAnnotations(origin: string, willCrashApp: 'unknown' | boolean): {
|
||||
|
@ -811,9 +785,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
createShape<T extends TLUnknownShape>(shape: OptionalKeys<TLShapePartial<T>, 'id'>): this;
|
||||
createShapes<T extends TLUnknownShape>(shapes: OptionalKeys<TLShapePartial<T>, 'id'>[]): this;
|
||||
deleteAssets(assets: TLAsset[] | TLAssetId[]): this;
|
||||
// (undocumented)
|
||||
deleteBinding(binding: TLBinding | TLBindingId, opts?: Parameters<this['deleteBindings']>[1]): this;
|
||||
// (undocumented)
|
||||
deleteBindings(bindings: (TLBinding | TLBindingId)[], { isolateShapes }?: {
|
||||
isolateShapes?: boolean | undefined;
|
||||
}): this;
|
||||
|
@ -860,13 +832,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
getAssetForExternalContent(info: TLExternalAssetContent): Promise<TLAsset | undefined>;
|
||||
getAssets(): (TLBookmarkAsset | TLImageAsset | TLVideoAsset)[];
|
||||
getBaseZoom(): number;
|
||||
// (undocumented)
|
||||
getBinding(id: TLBindingId): TLBinding | undefined;
|
||||
// (undocumented)
|
||||
getBindingsFromShape<Binding extends TLUnknownBinding = TLBinding>(shape: TLShape | TLShapeId, type: Binding['type']): Binding[];
|
||||
// (undocumented)
|
||||
getBindingsInvolvingShape<Binding extends TLUnknownBinding = TLBinding>(shape: TLShape | TLShapeId, type?: Binding['type']): Binding[];
|
||||
// (undocumented)
|
||||
getBindingsToShape<Binding extends TLUnknownBinding = TLBinding>(shape: TLShape | TLShapeId, type: Binding['type']): Binding[];
|
||||
getBindingUtil<S extends TLUnknownBinding>(binding: {
|
||||
type: S['type'];
|
||||
|
@ -1141,9 +1109,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
select: boolean;
|
||||
}>): this;
|
||||
updateAssets(assets: TLAssetPartial[]): this;
|
||||
// (undocumented)
|
||||
updateBinding<B extends TLBinding = TLBinding>(partial: TLBindingUpdate<B>): this;
|
||||
// (undocumented)
|
||||
updateBindings(partials: (null | TLBindingUpdate | undefined)[]): this;
|
||||
updateCurrentPageState(partial: Partial<Omit<TLInstancePageState, 'editingShapeId' | 'focusedGroupId' | 'pageId' | 'selectedShapeIds'>>, historyOptions?: TLHistoryBatchOptions): this;
|
||||
// (undocumented)
|
||||
|
@ -2181,9 +2147,7 @@ export interface TLBaseEventInfo {
|
|||
export interface TLBindingUtilConstructor<T extends TLUnknownBinding, U extends BindingUtil<T> = BindingUtil<T>> {
|
||||
// (undocumented)
|
||||
new (editor: Editor): U;
|
||||
// (undocumented)
|
||||
migrations?: TLPropsMigrations;
|
||||
// (undocumented)
|
||||
props?: RecordProps<T>;
|
||||
// (undocumented)
|
||||
type: T['type'];
|
||||
|
|
|
@ -492,10 +492,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
deleteBindingIds.push(binding.id)
|
||||
const util = this.getBindingUtil(binding)
|
||||
if (binding.fromId === shape.id) {
|
||||
util.onBeforeIsolateToShape?.({ binding, shape })
|
||||
util.onBeforeIsolateToShape?.({ binding, removedShape: shape })
|
||||
util.onBeforeDeleteFromShape?.({ binding, shape })
|
||||
} else {
|
||||
util.onBeforeIsolateFromShape?.({ binding, shape })
|
||||
util.onBeforeIsolateFromShape?.({ binding, removedShape: shape })
|
||||
util.onBeforeDeleteToShape?.({ binding, shape })
|
||||
}
|
||||
}
|
||||
|
@ -5152,10 +5152,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a binding from the store by its ID if it exists.
|
||||
*/
|
||||
getBinding(id: TLBindingId): TLBinding | undefined {
|
||||
return this.store.get(id) as TLBinding | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
|
||||
* `fromId` matched the shape's ID.
|
||||
*/
|
||||
getBindingsFromShape<Binding extends TLUnknownBinding = TLBinding>(
|
||||
shape: TLShape | TLShapeId,
|
||||
type: Binding['type']
|
||||
|
@ -5165,6 +5172,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
(b) => b.fromId === id && b.type === type
|
||||
) as Binding[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
|
||||
* `toId` matches the shape's ID.
|
||||
*/
|
||||
getBindingsToShape<Binding extends TLUnknownBinding = TLBinding>(
|
||||
shape: TLShape | TLShapeId,
|
||||
type: Binding['type']
|
||||
|
@ -5174,6 +5186,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
(b) => b.toId === id && b.type === type
|
||||
) as Binding[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bindings involving a particular shape. This includes bindings where the shape is the
|
||||
* `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
|
||||
*/
|
||||
getBindingsInvolvingShape<Binding extends TLUnknownBinding = TLBinding>(
|
||||
shape: TLShape | TLShapeId,
|
||||
type?: Binding['type']
|
||||
|
@ -5184,6 +5201,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
return result.filter((b) => b.type === type) as Binding[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bindings from a list of partial bindings. You can omit the ID and most props of a
|
||||
* binding, but the `type`, `toId`, and `fromId` must all be provided.
|
||||
*/
|
||||
createBindings(partials: TLBindingCreate[]) {
|
||||
const bindings: TLBinding[] = []
|
||||
for (const partial of partials) {
|
||||
|
@ -5209,10 +5230,20 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
this.store.put(bindings)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single binding from a partial. You can omit the ID and most props of a binding, but
|
||||
* the `type`, `toId`, and `fromId` must all be provided.
|
||||
*/
|
||||
createBinding<B extends TLBinding = TLBinding>(partial: TLBindingCreate<B>) {
|
||||
return this.createBindings([partial])
|
||||
}
|
||||
|
||||
/**
|
||||
* Update bindings from a list of partial bindings. Each partial must include an ID, which will
|
||||
* be used to match the binding to it's existing record. If there is no existing record, that
|
||||
* binding is skipped. The changes from the partial are merged into the existing record.
|
||||
*/
|
||||
updateBindings(partials: (TLBindingUpdate | null | undefined)[]) {
|
||||
const updated: TLBinding[] = []
|
||||
|
||||
|
@ -5238,10 +5269,18 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a binding from a partial binding. Each partial must include an ID, which will be used
|
||||
* to match the binding to it's existing record. If there is no existing record, that binding is
|
||||
* skipped. The changes from the partial are merged into the existing record.
|
||||
*/
|
||||
updateBinding<B extends TLBinding = TLBinding>(partial: TLBindingUpdate<B>) {
|
||||
return this.updateBindings([partial])
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete several bindings by their IDs. If a binding ID doesn't exist, it's ignored.
|
||||
*/
|
||||
deleteBindings(bindings: (TLBinding | TLBindingId)[], { isolateShapes = false } = {}) {
|
||||
const ids = bindings.map((binding) => (typeof binding === 'string' ? binding : binding.id))
|
||||
if (isolateShapes) {
|
||||
|
@ -5250,8 +5289,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
const binding = this.getBinding(id)
|
||||
if (!binding) continue
|
||||
const util = this.getBindingUtil(binding)
|
||||
util.onBeforeIsolateFromShape?.({ binding, shape: this.getShape(binding.fromId)! })
|
||||
util.onBeforeIsolateToShape?.({ binding, shape: this.getShape(binding.toId)! })
|
||||
util.onBeforeIsolateFromShape?.({ binding, removedShape: this.getShape(binding.toId)! })
|
||||
util.onBeforeIsolateToShape?.({ binding, removedShape: this.getShape(binding.fromId)! })
|
||||
this.store.remove([id])
|
||||
}
|
||||
})
|
||||
|
@ -5260,6 +5299,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|||
}
|
||||
return this
|
||||
}
|
||||
/**
|
||||
* Delete a binding by its ID. If the binding doesn't exist, it's ignored.
|
||||
*/
|
||||
deleteBinding(binding: TLBinding | TLBindingId, opts?: Parameters<this['deleteBindings']>[1]) {
|
||||
return this.deleteBindings([binding], opts)
|
||||
}
|
||||
|
|
|
@ -8,42 +8,110 @@ export interface TLBindingUtilConstructor<
|
|||
> {
|
||||
new (editor: Editor): U
|
||||
type: T['type']
|
||||
/** Validations for this binding's props. */
|
||||
props?: RecordProps<T>
|
||||
/** Migrations for this binding's props. */
|
||||
migrations?: TLPropsMigrations
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onBeforeCreate} and {@link BindingUtil.onAfterCreate},
|
||||
* describing a the creating a binding.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding being created. */
|
||||
binding: Binding
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onBeforeChange} and {@link BindingUtil.onAfterChange},
|
||||
* describing the data associated with a binding being changed.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding record before the change is made. */
|
||||
bindingBefore: Binding
|
||||
/** The binding record after the change is made. */
|
||||
bindingAfter: Binding
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onBeforeDelete} and {@link BindingUtil.onAfterDelete},
|
||||
* describing a binding being deleted.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding being deleted. */
|
||||
binding: Binding
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onAfterChangeFromShape} and
|
||||
* {@link BindingUtil.onAfterChangeToShape}, describing a bound shape being changed.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding record linking these two shapes. */
|
||||
binding: Binding
|
||||
/** The shape record before the change is made. */
|
||||
shapeBefore: TLShape
|
||||
/** The shape record after the change is made. */
|
||||
shapeAfter: TLShape
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onBeforeIsolateFromShape} and
|
||||
* {@link BindingUtil.onBeforeIsolateToShape}, describing a shape that is about to be isolated from
|
||||
* the one that it's bound to.
|
||||
*
|
||||
* Isolation happens whenever two bound shapes are separated. For example
|
||||
* 1. One is deleted, but the other is not.
|
||||
* 1. One is copied, but the other is not.
|
||||
* 1. One is duplicated, but the other is not.
|
||||
*
|
||||
* In each of these cases, if the remaining shape depends on the binding for its rendering, it may
|
||||
* now be in an inconsistent state. For example, tldraw's arrow shape depends on the binding to know
|
||||
* where the end of the arrow is. If we removed the binding without doing anything else, the arrow
|
||||
* would suddenly be pointing to the wrong location. Instead, when the shape the arrow is pointing
|
||||
* to is deleted, or the arrow is copied/duplicated, we use an isolation callback. The callback
|
||||
* updates the arrow based on the binding that's about to be removed, so it doesn't end up pointing
|
||||
* to the wrong place.
|
||||
*
|
||||
* For this style of consistency update, use isolation callbacks. For actions specific to deletion
|
||||
* (like deleting a sticker when the shape it's bound to is removed), use the delete callbacks
|
||||
* ({@link BindingUtil.onBeforeDeleteFromShape} and {@link BindingUtil.onBeforeDeleteToShape})
|
||||
* instead.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding record that refers to the shape in question. */
|
||||
binding: Binding
|
||||
shape: TLShape
|
||||
/**
|
||||
* The shape being removed. For deletion, this is the deleted shape. For copy/duplicate, this is
|
||||
* the shape that _isn't_ being copied/duplicated and is getting left behind.
|
||||
*/
|
||||
removedShape: TLShape
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options passed to {@link BindingUtil.onBeforeDeleteFromShape} and
|
||||
* {@link BindingUtil.onBeforeDeleteToShape}, describing a bound shape that is about to be deleted.
|
||||
*
|
||||
* See {@link BindingOnShapeIsolateOptions} for discussion on when to use the delete vs. the isolate
|
||||
* callbacks.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
|
||||
/** The binding record that refers to the shape in question. */
|
||||
binding: Binding
|
||||
/** The shape that is about to be deleted. */
|
||||
shape: TLShape
|
||||
}
|
||||
|
||||
|
@ -67,22 +135,132 @@ export abstract class BindingUtil<Binding extends TLUnknownBinding = TLUnknownBi
|
|||
*/
|
||||
abstract getDefaultProps(): Partial<Binding['props']>
|
||||
|
||||
/**
|
||||
* Called whenever a store operation involving this binding type has completed. This is useful
|
||||
* for working with networks of related bindings that may need to update together.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* class MyBindingUtil extends BindingUtil<MyBinding> {
|
||||
* changedBindingIds = new Set<TLBindingId>()
|
||||
*
|
||||
* onOperationComplete() {
|
||||
* doSomethingWithChangedBindings(this.changedBindingIds)
|
||||
* this.changedBindingIds.clear()
|
||||
* }
|
||||
*
|
||||
* onAfterChange({ bindingAfter }: BindingOnChangeOptions<MyBinding>) {
|
||||
* this.changedBindingIds.add(bindingAfter.id)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onOperationComplete?(): void
|
||||
|
||||
// self lifecycle hooks
|
||||
/**
|
||||
* Called when a binding is about to be created. See {@link BindingOnCreateOptions} for details.
|
||||
*
|
||||
* You can optionally return a new binding to replace the one being created - for example, to
|
||||
* set different initial props.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onBeforeCreate?(options: BindingOnCreateOptions<Binding>): Binding | void
|
||||
|
||||
/**
|
||||
* Called after a binding has been created. See {@link BindingOnCreateOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onAfterCreate?(options: BindingOnCreateOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called when a binding is about to be changed. See {@link BindingOnChangeOptions} for details.
|
||||
*
|
||||
* Note that this only fires when the binding record is changing, not when the shapes
|
||||
* associated change. Use {@link BindingUtil.onAfterChangeFromShape} and
|
||||
* {@link BindingUtil.onAfterChangeToShape} for that.
|
||||
*
|
||||
* You can optionally return a new binding to replace the one being changed - for example, to
|
||||
* enforce constraints on the binding's props.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onBeforeChange?(options: BindingOnChangeOptions<Binding>): Binding | void
|
||||
|
||||
/**
|
||||
* Called after a binding has been changed. See {@link BindingOnChangeOptions} for details.
|
||||
*
|
||||
* Note that this only fires when the binding record is changing, not when the shapes
|
||||
* associated change. Use {@link BindingUtil.onAfterChangeFromShape} and
|
||||
* {@link BindingUtil.onAfterChangeToShape} for that.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onAfterChange?(options: BindingOnChangeOptions<Binding>): void
|
||||
onBeforeDelete?(options: BindingOnDeleteOptions<Binding>): Binding | void
|
||||
|
||||
/**
|
||||
* Called when a binding is about to be deleted. See {@link BindingOnDeleteOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onBeforeDelete?(options: BindingOnDeleteOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called after a binding has been deleted. See {@link BindingOnDeleteOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onAfterDelete?(options: BindingOnDeleteOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called after the shape referenced in a binding's `fromId` is changed. Use this to propagate
|
||||
* any changes to the binding itself or the other shape as needed. See
|
||||
* {@link BindingOnShapeChangeOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onAfterChangeFromShape?(options: BindingOnShapeChangeOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called after the shape referenced in a binding's `toId` is changed. Use this to propagate any
|
||||
* changes to the binding itself or the other shape as needed. See
|
||||
* {@link BindingOnShapeChangeOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onAfterChangeToShape?(options: BindingOnShapeChangeOptions<Binding>): void
|
||||
|
||||
onBeforeIsolateFromShape?(options: BindingOnShapeIsolateOptions<Binding>): void
|
||||
onBeforeIsolateToShape?(options: BindingOnShapeIsolateOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called before the shape referenced in a binding's `fromId` is about to be deleted. Use this
|
||||
* with care - you may want to use {@link BindingUtil.onBeforeIsolateToShape} instead. See
|
||||
* {@link BindingOnShapeDeleteOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onBeforeDeleteFromShape?(options: BindingOnShapeDeleteOptions<Binding>): void
|
||||
/**
|
||||
* Called before the shape referenced in a binding's `toId` is about to be deleted. Use this
|
||||
* with care - you may want to use {@link BindingUtil.onBeforeIsolateFromShape} instead. See
|
||||
* {@link BindingOnShapeDeleteOptions} for details.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
onBeforeDeleteToShape?(options: BindingOnShapeDeleteOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called before the shape referenced in a binding's `fromId` is about to be isolated from the
|
||||
* shape referenced in `toId`. See {@link BindingOnShapeIsolateOptions} for discussion on what
|
||||
* isolation means, and when/how to use this callback.
|
||||
*/
|
||||
onBeforeIsolateFromShape?(options: BindingOnShapeIsolateOptions<Binding>): void
|
||||
|
||||
/**
|
||||
* Called before the shape referenced in a binding's `toId` is about to be isolated from the
|
||||
* shape referenced in `fromId`. See {@link BindingOnShapeIsolateOptions} for discussion on what
|
||||
* isolation means, and when/how to use this callback.
|
||||
*/
|
||||
onBeforeIsolateToShape?(options: BindingOnShapeIsolateOptions<Binding>): void
|
||||
}
|
||||
|
|
|
@ -959,7 +959,7 @@ export type TLBindingCreate<T extends TLBinding = TLBinding> = Expand<{
|
|||
typeName?: T['typeName'];
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type TLBindingId = RecordId<TLUnknownBinding>;
|
||||
|
||||
// @public (undocumented)
|
||||
|
|
|
@ -55,7 +55,11 @@ export type TLBindingCreate<T extends TLBinding = TLBinding> = Expand<{
|
|||
meta?: Partial<T['meta']>
|
||||
}>
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* An ID for a {@link TLBinding}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TLBindingId = RecordId<TLUnknownBinding>
|
||||
|
||||
/** @public */
|
||||
|
|
Loading…
Reference in a new issue