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.

Signature
class SideEffectManager<
  CTX extends {
    history: {
      onBatchComplete: () => void
    }
    store: TLStore
  },
> {}
References

TLStore

Source

packages/editor/src/lib/editor/managers/SideEffectManager.ts


Constructor

Public constructor

Constructs a new instance of the SideEffectManager class

Parameters
NameDescription

editor

CTX

Properties

editor

Public property

Signature
editor: CTX

history

Public propertysignature

Signature
history: {
  onBatchComplete: () => void
}

store

Public propertysignature

Signature
store: TLStore
References

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.

Example
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' },
      }))
    )
  }
})
Signature
registerAfterChangeHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLAfterChangeHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLAfterChangeHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

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.

Example
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 },
  })
})
Signature
registerAfterCreateHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLAfterCreateHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLAfterCreateHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

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.

Example
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)
  }
})
Signature
registerAfterDeleteHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLAfterDeleteHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLAfterDeleteHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

TLRecord, TLAfterDeleteHandler


registerBatchCompleteHandler()

Public method

Register a handler to be called when a store completes a batch.

Example
let count = 0

editor.cleanup.registerBatchCompleteHandler(() => count++)

editor.selectAll()
expect(count).toBe(1)

editor.batch(() => {
  editor.selectNone()
  editor.selectAll()
})

expect(count).toBe(2)
Signature
registerBatchCompleteHandler(handler: TLBatchCompleteHandler): () => void
Parameters
NameDescription

handler

TLBatchCompleteHandler

The handler to call

Returns
() => void
References

TLBatchCompleteHandler


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.

Example
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
  }
)
Signature
registerBeforeChangeHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLBeforeChangeHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLBeforeChangeHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

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.

Example
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
})
Signature
registerBeforeCreateHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLBeforeCreateHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLBeforeCreateHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

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.

Example
editor.sideEffects.registerBeforeDeleteHandler('shape', (shape, source) => {
  if (shape.props.color === 'red') {
    // prevent red shapes from being deleted
    return false
  }
})
Signature
registerBeforeDeleteHandler<T extends TLRecord['typeName']>(
  typeName: T,
  handler: TLBeforeDeleteHandler<
    TLRecord & {
      typeName: T
    }
  >
): () => void
Parameters
NameDescription

typeName

T

The type of record to listen for

handler

TLBeforeDeleteHandler<
  TLRecord & {
    typeName: T
  }
>

The handler to call

Returns
() => void
References

TLRecord, TLBeforeDeleteHandler


shortAngleDistSIDES