Skip to content

[pull] main from tldraw:main#463

Merged
pull[bot] merged 4 commits intocode:mainfrom
tldraw:main
Mar 26, 2026
Merged

[pull] main from tldraw:main#463
pull[bot] merged 4 commits intocode:mainfrom
tldraw:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 26, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

angrycaptain19 and others added 4 commits March 26, 2026 10:09
…8344)

Fixes an issue where mermaid code from VS Code, textedit, and live
mermaid editor (among others) wasn't rendering as shapes because the
stripped HTML removed the linebreaks so it was parsing as invalid
mermaid.

This has been kept inside the mermaid handler to make sure it shouldn't
impact any other copy/paste functionality, but still worth testing
pasting of:
1) Pasting in formatted text (eg from google docs)
2) Copying non-mermaid code from VS Code
3) Copying in a webpage link and making sure that turns into an embed

I've tested all of those cases locally and they work fine

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… records (#8147)

In order to let developers track who created and last edited shapes —
and to display that information in the UI — this PR introduces a shape
attribution system built on a reactive `TLUserStore` provider interface,
note-specific "first edited by" labeling, and extensible user records
via `createTLSchema`.

### What's included

**`TLUserStore` interface** (`@tldraw/tlschema`)
A new optional `users` prop on the editor (and `<Tldraw />`) that
connects tldraw to your auth system. Both methods return reactive
`Signal`s so the editor automatically tracks changes to user data:
- `getCurrentUser()` — returns a `Signal<TLUser | null>` for the active
user (used for both presence broadcasting and shape attribution)
- `resolve(userId)` — returns a `Signal<TLUser | null>` to resolve any
user ID to display info (for rendering attribution labels)

When no provider is given, a default implementation falls back to
`UserPreferences` + the collaborator presence list.

**Unified `TLUser` record type** (`@tldraw/tlschema`)
Collapsed the previous `TLUser` + `TLUserInfo` types into a single
`TLUser` store record (following the `TLAsset` pattern). User records
are document-scoped and persist alongside shapes, assets, and pages —
surviving across boards, clipboard paste, and `.tldr` files.

**Extensible user metadata via `createTLSchema`**
SDK users can now extend user records with custom validated metadata:
```ts
const schema = createTLSchema({
  user: {
    meta: {
      isAdmin: T.boolean,
      department: T.string,
    },
  },
})
```
Custom meta fields are validated when present but treated as optional,
so existing user records remain valid. The new
`createUserRecordType(config?)` function builds the record type with
extended validators.

**Note shape "first edited by" label**
`NoteShapeUtil` now tracks `textFirstEditedBy` in its props and renders
a small attribution label (first name) in the bottom-right corner of the
note. The label resolves the display name through the user store and
shows a tooltip with the full name. This tracks who first added text to
the note — subsequent typo fixes by others don't change the attribution.
Includes a note shape migration (`AddFirstEditedBy`).

<img width="757" height="414" alt="Screenshot 2026-03-04 at 11 20 58"
src="https://github.com/user-attachments/assets/190ea36d-873e-44d7-aa3c-8fefebc7db56"
/>

**New editor methods**
- `editor.getAttributionUser(userId)` — resolves a user record by ID,
asking the `TLUserStore` first (the app's source of truth), falling back
to the `user:` record in the store
- `editor.getAttributionUserId()` — returns the current user's ID for
attribution purposes
- `editor.getAttributionDisplayName(userId)` — resolves a display name
for a user ID, with the same lookup order

**New "Users" example category with four examples**
- **Attribution** — demonstrates wiring up `TLUserStore` with a mock
user switcher and an attribution inspector panel
- **Attribution timeline** — shows a history scrubber that steps through
undo history and displays per-shape attribution metadata
- **Custom user metadata** — shows how to extend `TLUser` records with
custom meta fields (isAdmin, department)
- **Multiplayer sync with custom user data** — integrates custom user
data into tldraw sync



https://github.com/user-attachments/assets/bd476596-67ca-483b-8d1d-bec3f82e35d5



https://github.com/user-attachments/assets/c31f8db6-c7ae-4e21-b0d5-48e079eb5767


fixes #6115

**Unit tests**
New `attribution.test.ts` covering attribution user stamping, custom
user stores, note `textFirstEditedBy` tracking, and display name
resolution.

### Change type

- [x] `feature`

### Test plan

1. Open the Attribution example — switch between users and create/edit
shapes; verify attribution labels update in the inspector panel
2. Open the Attribution Timeline example — draw shapes, use the scrubber
to step through history, verify per-shape metadata display
3. Open the Custom User Metadata example — switch between users and
verify custom meta (department, admin badge) displays
4. Create note shapes — type text, verify the first name appears in the
bottom-right corner; hover for full name tooltip
5. Copy a note with attribution to a different board — verify the
attribution label persists

- [x] Unit tests

### API changes

- Added `TLUserStore` interface (with reactive `Signal`-based methods)
- Added `TLUser` record type (unified from previous `TLUser` +
`TLUserInfo`)
- Added `UserRecordType`, `createUserId`, `isUserId`, `userIdValidator`
- Added `createUserRecordType(config?)` for extensible user schemas
- Added `UserSchemaInfo` interface
- Added `user` parameter to `createTLSchema()`
- Added `textFirstEditedBy` prop to `TLNoteShapeProps`
- Added `Editor.getAttributionUser()`
- Added `Editor.getAttributionUserId()`
- Added `Editor.getAttributionDisplayName()`
- Removed `TLUserInfo` type (collapsed into `TLUser`)

### Release notes

- Add shape attribution system with `TLUserStore` for connecting tldraw
to your auth system.
- `TLUserStore` methods are reactive (`Signal`-based) so the editor
automatically tracks user data changes.
- Add extensible user records: pass custom meta validators to
`createTLSchema({ user: { meta: ... } })`.
- Add `createUserRecordType()` for building user record types with
custom validation.
- Note shapes now display a small "first edited by" label in the corner.
- New "Users" example category with attribution, attribution timeline,
custom user metadata, and sync examples.
we were compiling too many asset urls into a single pattern to match
against for our assets caching rules. this splits them up into multiple
rules

kudos @MitjaBezensek 

### Change type

- [ ] `bugfix`
- [ ] `improvement`
- [ ] `feature`
- [ ] `api`
- [x] `other`
@pull pull Bot locked and limited conversation to collaborators Mar 26, 2026
@pull pull Bot added the ⤵️ pull label Mar 26, 2026
@pull pull Bot merged commit db8dea4 into code:main Mar 26, 2026
@pull pull Bot had a problem deploying to vsce publish March 26, 2026 15:13 Failure
@pull pull Bot had a problem deploying to deploy-production March 26, 2026 15:13 Failure
@pull pull Bot had a problem deploying to deploy-staging March 26, 2026 15:13 Error
@pull pull Bot had a problem deploying to deploy-staging March 26, 2026 15:13 Failure
@pull pull Bot had a problem deploying to deploy-staging March 27, 2026 00:34 Failure
@pull pull Bot temporarily deployed to e2e-dotcom March 27, 2026 02:36 Inactive
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants