Conversation
…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`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )