Fix meta examples (#2379)

This PR fixes a bug in our meta examples.

### Change Type

- [x] `patch` — Bug fix
This commit is contained in:
Steve Ruiz 2024-01-03 08:26:22 +00:00 committed by GitHub
parent 530596ac5d
commit 16316ac2a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 20 deletions

View file

@ -1,11 +1,11 @@
import { Tldraw } from '@tldraw/tldraw' import { TLShape, Tldraw, track, useEditor } from '@tldraw/tldraw'
import '@tldraw/tldraw/tldraw.css' import '@tldraw/tldraw/tldraw.css'
export default function OnChangeShapeMetaExample() { export default function OnChangeShapeMetaExample() {
return ( return (
<div className="tldraw__editor"> <div className="tldraw__editor">
<Tldraw <Tldraw
persistenceKey="tldraw_example" persistenceKey="tldraw_change_meta_example"
onMount={(editor) => { onMount={(editor) => {
// See the "meta-on-create" example for more about setting the // See the "meta-on-create" example for more about setting the
// initial meta for a shape. // initial meta for a shape.
@ -20,14 +20,33 @@ export default function OnChangeShapeMetaExample() {
// all shapes whenever they are updated. // all shapes whenever they are updated.
editor.sideEffects.registerBeforeChangeHandler('shape', (_prev, next, source) => { editor.sideEffects.registerBeforeChangeHandler('shape', (_prev, next, source) => {
if (source !== 'user') return next if (source !== 'user') return next
next.meta = { return {
...next,
meta: {
updatedBy: editor.user.getId(), updatedBy: editor.user.getId(),
updatedAt: Date.now(), updatedAt: Date.now(),
},
} }
return next
}) })
}} }}
/> >
<MetaUiHelper />
</Tldraw>
</div> </div>
) )
} }
type ShapeWithMyMeta = TLShape & { meta: { updatedBy: string; updatedAt: string } }
export const MetaUiHelper = track(function MetaUiHelper() {
const editor = useEditor()
const onlySelectedShape = editor.getOnlySelectedShape() as ShapeWithMyMeta | null
return (
<pre style={{ position: 'absolute', zIndex: 300, top: 64, left: 12, margin: 0 }}>
{onlySelectedShape
? JSON.stringify(onlySelectedShape.meta, null, 2)
: 'Select one shape to see its meta data.'}
</pre>
)
})

View file

@ -7,4 +7,4 @@ Add custom metadata to shapes when they're changed.
--- ---
In this example, we add updatedAt metadata to shapes when they're updated. We can update a shape's metadata whenever it changes. A UI displays the current selected shape's metadata. Create a shape, select it, and move it around. The metadata will updated any time the shape changes.

View file

@ -1,4 +1,4 @@
import { Tldraw } from '@tldraw/tldraw' import { TLShape, Tldraw, track, useEditor } from '@tldraw/tldraw'
import '@tldraw/tldraw/tldraw.css' import '@tldraw/tldraw/tldraw.css'
export default function OnCreateShapeMetaExample() { export default function OnCreateShapeMetaExample() {
@ -17,7 +17,24 @@ export default function OnCreateShapeMetaExample() {
} }
} }
}} }}
/> >
<MetaUiHelper />
</Tldraw>
</div> </div>
) )
} }
type ShapeWithMyMeta = TLShape & { meta: { updatedBy: string; updatedAt: string } }
export const MetaUiHelper = track(function MetaUiHelper() {
const editor = useEditor()
const onlySelectedShape = editor.getOnlySelectedShape() as ShapeWithMyMeta | null
return (
<pre style={{ position: 'absolute', zIndex: 300, top: 64, left: 12, margin: 0 }}>
{onlySelectedShape
? JSON.stringify(onlySelectedShape.meta, null, 2)
: 'Select one shape to see its meta data.'}
</pre>
)
})

View file

@ -7,4 +7,4 @@ Add custom metadata to shapes when they're created.
--- ---
In this example, we add createdBy and createdAt metadata to shapes when they're created. We can update a shape's metadata whenever it is created. A UI displays the current selected shape's metadata. Create a shape and select it. The metadata will display its created at / created by data.

View file

@ -7,4 +7,4 @@ Add a label to shapes with the meta property.
--- ---
Select a shape and try changing its label. The label is stored in the shape's meta property, which can be used to add custom data to any shape. We can update a shape's metadata using a custom UI. Create a shape, select it, and edit the `label` metadata. The label is stored in the shape's meta property, which can be used to add custom data to any shape.

View file

@ -26,10 +26,6 @@ export const ShapeLabelUiWithHelper = track(function ShapeLabelUiWithHelper() {
const editor = useEditor() const editor = useEditor()
const onlySelectedShape = editor.getOnlySelectedShape() as ShapeWithMyMeta | null const onlySelectedShape = editor.getOnlySelectedShape() as ShapeWithMyMeta | null
if (!onlySelectedShape) {
return null
}
function onChange(e: React.ChangeEvent<HTMLInputElement>) { function onChange(e: React.ChangeEvent<HTMLInputElement>) {
if (onlySelectedShape) { if (onlySelectedShape) {
const { id, type, meta } = onlySelectedShape const { id, type, meta } = onlySelectedShape
@ -42,7 +38,12 @@ export const ShapeLabelUiWithHelper = track(function ShapeLabelUiWithHelper() {
return ( return (
<div style={{ position: 'absolute', zIndex: 300, top: 64, left: 12 }}> <div style={{ position: 'absolute', zIndex: 300, top: 64, left: 12 }}>
shape label: <input value={onlySelectedShape.meta.label} onChange={onChange} /> <pre style={{ margin: '0 0 16px 0' }}>
{onlySelectedShape
? JSON.stringify(onlySelectedShape.meta, null, 2)
: 'Select one shape to see / edit its meta data.'}
</pre>
{onlySelectedShape && <input value={onlySelectedShape.meta.label} onChange={onChange} />}
</div> </div>
) )
}) })

View file

@ -382,12 +382,12 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
const recordAtom = (map ?? currentMap)[record.id as IdOf<R>] const recordAtom = (map ?? currentMap)[record.id as IdOf<R>]
if (recordAtom) { if (recordAtom) {
if (beforeUpdate) record = beforeUpdate(recordAtom.get(), record, source)
// If we already have an atom for this record, update its value. // If we already have an atom for this record, update its value.
const initialValue = recordAtom.__unsafe__getWithoutCapture() const initialValue = recordAtom.__unsafe__getWithoutCapture()
// If we have a beforeUpdate callback, run it against the initial and next records
if (beforeUpdate) record = beforeUpdate(initialValue, record, source)
// Validate the record // Validate the record
record = this.schema.validateRecord( record = this.schema.validateRecord(
this, this,
@ -402,6 +402,7 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
const finalValue = recordAtom.__unsafe__getWithoutCapture() const finalValue = recordAtom.__unsafe__getWithoutCapture()
// If the value has changed, assign it to updates. // If the value has changed, assign it to updates.
// todo: is this always going to be true?
if (initialValue !== finalValue) { if (initialValue !== finalValue) {
didChange = true didChange = true
updates[record.id] = [initialValue, finalValue] updates[record.id] = [initialValue, finalValue]