After create/update shape
Register a handler to run after shapes are created or updated.
You can register handlers to run after any record is created or updated. This is most useful for updating other records in response to a particular record changing. In this example, we make sure there's only ever one red shape on a page.
import { Editor, TLShape, TLShapeId, Tldraw, createShapeId } from 'tldraw'
// this function takes a shape ID, and if that shape is red, sets all other red shapes on the same
// page to black.
function ensureOnlyOneRedShape(editor: Editor, shapeId: TLShapeId) {
// grab the shape and check it's red:
const shape = editor.getShape(shapeId)!
if (!isRedShape(shape)) return
// get the ID of the page that shape belongs to:
const pageId = editor.getAncestorPageId(shape.id)!
// find any other red shapes on the same page:
const otherRedShapesOnPage = Array.from(editor.getPageShapeIds(pageId))
.map((id) => editor.getShape(id)!)
.filter((otherShape) => otherShape.id !== shape.id && isRedShape(otherShape))
// set the color of all those shapes to black:
editor.updateShapes(
otherRedShapesOnPage.map((shape) => ({
id: shape.id,
type: shape.type,
props: {
color: 'black',
},
}))
)
}
function isRedShape(shape: TLShape) {
return 'color' in shape.props && shape.props.color === 'red'
}
export default function AfterCreateUpdateShapeExample() {
return (
<div className="tldraw__editor">
<Tldraw
onMount={(editor) => {
// we can run our `ensureOnlyOneRedShape` function after any shape is created or
// changed. this means we can enforce our "only one red shape at a time" rule,
// whilst making sure that the shape most recently set to red is the one that
// stays red.
editor.sideEffects.registerAfterCreateHandler('shape', (shape) => {
ensureOnlyOneRedShape(editor, shape.id)
})
editor.sideEffects.registerAfterChangeHandler('shape', (prevShape, nextShape) => {
ensureOnlyOneRedShape(editor, nextShape.id)
})
createDemoShapes(editor)
}}
/>
</div>
)
}
// create some shapes to demonstrate the side-effects we added
function createDemoShapes(editor: Editor) {
editor
.createShapes(
'there can only be one red shape'.split(' ').map((word, i) => ({
id: createShapeId(),
type: 'text',
y: i * 30,
props: {
color: i === 5 ? 'red' : 'black',
text: word,
},
}))
)
.zoomToContent({ duration: 0 })
}