SideEffectManager
Table of contents
Public class
The side effect manager (aka a "correct state enforcer") is responsible for making sure that the editor's state is always correct. This includes things like: deleting a shape if its parent is deleted; unbinding arrows when their binding target is deleted; etc.
class SideEffectManager<
CTX extends {
history: {
onBatchComplete: () => void
}
store: TLStore
},
> {}
packages/editor/src/lib/editor/managers/SideEffectManager.ts
Constructor
Public constructor
Constructs a new instance of the SideEffectManager
class
Name | Description |
---|---|
|
|
Properties
editor
Public property
editor: CTX
history
Public propertysignature
history: {
onBatchComplete: () => void
}
store
Public propertysignature
store: TLStore
Methods
registerAfterChangeHandler()
Public method
Register a handler to be called after a record is changed. This is useful for side-effects that would update other records - if you want to modify the record being changed, use SideEffectManager.registerBeforeChangeHandler instead.
editor.sideEffects.registerAfterChangeHandler('shape', (prev, next, source) => {
if (next.props.color === 'red') {
// there can only be one red shape at a time:
const otherRedShapes = editor
.getCurrentPageShapes()
.filter((s) => s.props.color === 'red' && s.id !== next.id)
editor.updateShapes(
otherRedShapes.map((s) => ({
...s,
props: { ...s.props, color: 'blue' },
}))
)
}
})
registerAfterChangeHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLAfterChangeHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLAfterChangeHandler
registerAfterCreateHandler()
Public method
Register a handler to be called after a record is created. This is useful for side-effects that would update other records. If you want to modify the record being created use SideEffectManager.registerBeforeCreateHandler instead.
editor.sideEffects.registerAfterCreateHandler('page', (page, source) => {
// Automatically create a shape when a page is created
editor.createShape({
id: createShapeId(),
type: 'text',
props: { text: page.name },
})
})
registerAfterCreateHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLAfterCreateHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLAfterCreateHandler
registerAfterDeleteHandler()
Public method
Register a handler to be called after a record is deleted. This is useful for side-effects that would update other records - if you want to block the deletion of the record itself, use SideEffectManager.registerBeforeDeleteHandler instead.
editor.sideEffects.registerAfterDeleteHandler('shape', (shape, source) => {
// if the last shape in a frame is deleted, delete the frame too:
const parentFrame = editor.getShape(shape.parentId)
if (!parentFrame || parentFrame.type !== 'frame') return
const siblings = editor.getSortedChildIdsForParent(parentFrame)
if (siblings.length === 0) {
editor.deleteShape(parentFrame.id)
}
})
registerAfterDeleteHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLAfterDeleteHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLAfterDeleteHandler
registerBatchCompleteHandler()
Public method
Register a handler to be called when a store completes a batch.
let count = 0
editor.cleanup.registerBatchCompleteHandler(() => count++)
editor.selectAll()
expect(count).toBe(1)
editor.batch(() => {
editor.selectNone()
editor.selectAll()
})
expect(count).toBe(2)
registerBatchCompleteHandler(handler: TLBatchCompleteHandler): () => void
Name | Description |
---|---|
|
The handler to call |
() => void
registerBeforeChangeHandler()
Public method
Register a handler to be called before a record is changed. The handler is given the old and new record - you can return a modified record to apply a different update, or the old record to block the update entirely.
Use this handler only for intercepting updates to the record itself. If you want to update other records in response to a change, use SideEffectManager.registerAfterChangeHandler instead.
editor.sideEffects.registerBeforeChangeHandler(
'shape',
(prev, next, source) => {
if (next.isLocked && !prev.isLocked) {
// prevent shapes from ever being locked:
return prev
}
// other types of change are allowed
return next
}
)
registerBeforeChangeHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLBeforeChangeHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLBeforeChangeHandler
registerBeforeCreateHandler()
Public method
Register a handler to be called before a record of a certain type is created. Return a modified record from the handler to change the record that will be created.
Use this handle only to modify the creation of the record itself. If you want to trigger a side-effect on a different record (for example, moving one shape when another is created), use SideEffectManager.registerAfterCreateHandler instead.
editor.sideEffects.registerBeforeCreateHandler('shape', (shape, source) => {
// only modify shapes created by the user
if (source !== 'user') return shape
//by default, arrow shapes have no label. Let's make sure they always have a label.
if (shape.type === 'arrow') {
return { ...shape, props: { ...shape.props, text: 'an arrow' } }
}
// other shapes get returned unmodified
return shape
})
registerBeforeCreateHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLBeforeCreateHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLBeforeCreateHandler
registerBeforeDeleteHandler()
Public method
Register a handler to be called before a record is deleted. The handler can return false
to prevent the deletion.
Use this handler only for intercepting deletions of the record itself. If you want to do something to other records in response to a deletion, use SideEffectManager.registerAfterDeleteHandler instead.
editor.sideEffects.registerBeforeDeleteHandler('shape', (shape, source) => {
if (shape.props.color === 'red') {
// prevent red shapes from being deleted
return false
}
})
registerBeforeDeleteHandler<T extends TLRecord['typeName']>(
typeName: T,
handler: TLBeforeDeleteHandler<
TLRecord & {
typeName: T
}
>
): () => void
Name | Description |
---|---|
|
The type of record to listen for |
|
The handler to call |
() => void
TLRecord, TLBeforeDeleteHandler