feat(tldraw): add TldrawUiSelect component#7566
Conversation
Adds a new select dropdown primitive component wrapping Radix UI's Select. Components: - TldrawUiSelect - Root with value/onChange - TldrawUiSelectTrigger - Trigger button - TldrawUiSelectValue - Displays selected value - TldrawUiSelectContent - Dropdown container - TldrawUiSelectItem - Individual item (styled like checkbox menu items) Also adds: - UI primitives example showcasing all tldraw UI components - Export of iconTypes array for icon enumeration Closes #7560
|
The latest updates on your projects. Learn more about Vercel for GitHub.
4 Skipped Deployments
|
TldrawUiSelect now uses useMenuIsOpen to register its open state with the editor, matching the pattern used by TldrawUiPopover and TldrawUiDropdownMenuRoot. This ensures MenuClickCapture blocks canvas interactions while the select is open and editor.complete() is called when opening to complete in-progress operations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
mimecuvalo
left a comment
There was a problem hiding this comment.
technically we already use radix's Select with TlaMenuSelect
where will this new component get used? might not be worth adding if we don't use it.
marking request changes to make sure we discuss before landing!
|
TlaMenuSelect is in the tldraw layer, this is part of the SDK layer. It does not have an immediate place where it would be used, except perhaps in some examples, but it seems strange not to have this one given we have most of the other UI components in place. I believe it would get tree-shaken out of the bundle when used in a downstream app (like there rest of our UI components). |
Ah right right, my bad, brainfart that tla-menu is in the dotcom code, not the general code. |
* chore(sync): disable rate limiting (#7780) Cloudflare rate limiting is broken. This disables it temporarily by making `isRateLimited` always return `false`. Original code is commented out for easy restoration. ### Change type - [x] `bugfix` ### Test plan 1. Deploy to staging 2. Verify sync connections work without rate limit errors <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Disables rate limiting across sync-worker entry points, which can increase load and abuse risk until re-enabled. The change is simple and easy to revert, but impacts production traffic control. > > **Overview** > **Temporarily disables sync-worker rate limiting.** `isRateLimited` no longer calls `env.RATE_LIMITER.limit` and instead always returns `false`, with the original implementation commented out for later restoration. > > This effectively bypasses rate-limit enforcement in call sites (e.g., websocket/session flows and `submitFeedback`) to avoid Cloudflare rate-limit failures. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 301450699961b239b0df8d6c33ff15934844ae39. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [HOTFIX] chore(sync): disable rate limiting This is an automated hotfix for dotcom deployment. Original PR: #7780 Original Author: @MitjaBezensek * Add VSCode extension v2.202.0 [skip ci] * docs(examples): expand and refine keywords in example READMEs (#7786) Improves the discoverability of SDK examples by expanding and refining the keywords in each example's README.md frontmatter. ### Change type - [x] `improvement` ### Test plan 1. Run `yarn dev` and verify the examples app loads 2. Use the search functionality to verify keywords help find relevant examples ### Release notes - Improved search keywords across all SDK examples for better discoverability <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk documentation-only change that affects example search metadata; main risk is minor YAML/frontmatter formatting issues impacting parsing or search results. > > **Overview** > Improves examples discoverability by **expanding and normalizing `keywords` frontmatter** across many example `README.md` files (often converting single-line or inconsistent `keyword(s)` fields into richer `keywords` arrays). > > No runtime logic changes were made; this primarily affects how the examples app’s sidebar filter matches against `example.keywords`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0bf2bdb3244a8bd1416f0b12a241b6d749c2493f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs: add comprehensive SDK documentation and tooling (#7507) This PR adds comprehensive SDK documentation along with supporting tooling and infrastructure. Closes #7505 ## What's included - **Voice and style guide**: Establishes documentation writing standards - **Claude commands and skills**: AI-assisted workflows for documentation generation, evaluation, and improvement - **SDK features documentation**: 52 detailed articles covering all SDK capabilities organized by topic - **Changelog documentation**: Release notes for v2.0 through v4.3 - **Updated docs app**: Navigation, structure, and layout updates to support new documentation sections - **Documentation tooling**: Scripts for generating documentation references and changelog automation - **GitHub Actions workflow**: Automated changelog updates using Claude Code The final state of this branch is identical to the `docs` branch - this is a clean reimplementation with a narrative-quality commit history suitable for review. **Original branch**: [docs](https://github.com/tldraw/tldraw/tree/docs) ### Change type - [x] `improvement` ### Test plan 1. Run `yarn dev-docs` and verify docs site builds successfully 2. Review SDK features section navigation 3. Verify changelog pages render properly - [ ] Unit tests - [ ] End to end tests ### Release notes - Added comprehensive SDK features documentation covering 52 topics - Added changelog documentation for v2.0 through v4.3 - Added documentation writing style guide and AI-assisted tooling - Added GitHub Actions workflow for automated changelog updates <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it adds a large amount of new docs content plus changes docs-site navigation/layout and introduces an automated release-notes GitHub Action that can create commits/PRs if misconfigured. > > **Overview** > Adds new documentation writing infrastructure: shared style guides (`writing-guide`, `docs-guide`, `blog-guide`, `release-notes-guide`), a `review-docs` evaluation loop skill, and a new `update-release-notes` skill with helper scripts. > > Updates the docs site UI and navigation, including wider layouts, revised category labels, new MDX components (`Feature`, `CheckItem`, `StarterKitBento`), starter-kit pages with embeds + a dedicated sidebar, and refactors sidebar link processing into `processSidebarContent`. > > Introduces a structured release-notes system under `apps/docs/content/releases/` (`next.mdx` plus historical `v2.x` files), updates the releases landing page, and adds a GitHub Actions workflow (`update-release-notes.yml`) to run Claude Code to update release notes and open a PR. Also includes small operational tweaks (Discord link update, `.gitignore`/Claude command permission adjustments). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 77f85437c7336b771314cd0774c64fdf63c2ba10. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> * docs(routing): redirect /starter-kits to /starter-kits/overview (#7789) Now that starter kits content is served from the docs site, this removes the Framer rewrite and adds a permanent redirect from `/starter-kits` to `/starter-kits/overview`. ### Change type - [x] `improvement` ### Test plan 1. Visit tldraw.dev/starter-kits 2. Verify it redirects to tldraw.dev/starter-kits/overview - [ ] Unit tests - [ ] End to end tests <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk routing-only change; main risk is unintended redirect behavior or SEO implications if other `/starter-kits` paths relied on the previous rewrite. > > **Overview** > Routes for `starter-kits` are now handled by the docs app: `/starter-kits` permanently redirects to `/starter-kits/overview`. > > The previous Framer rewrite for `/starter-kits` has been removed so the path no longer proxies to `tldrawdotdev.framer.website`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4e6f2ea9a10b54bdcbc9a70f787a8df7ab5223ef. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(docs): correct example embed URLs to use slug instead of full article ID (#7790) The example embeds on the docs site were generating broken URLs like `https://examples.tldraw.com/examples/events/derived-view/full` instead of the correct `https://examples.tldraw.com/derived-view/full`. The issue was that `article.id` contains a composite key in the format `sectionId/categoryId/articleId`, but the examples server expects just the example slug. This PR extracts the slug (last segment) from the article ID before constructing the embed URL. ### Change type - [x] `bugfix` ### Test plan 1. Run `yarn dev-docs` 2. Navigate to any example page (e.g., `/examples/events/derived-view`) 3. Verify the embedded iframe loads correctly from `examples.tldraw.com/derived-view/full` ### Release notes - Fix example embeds on docs site generating incorrect URLs <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: a small docs-only URL construction change; main risk is `slug` being undefined if `article.id` is malformed, which would still produce a bad embed URL. > > **Overview** > Fixes docs example embeds to generate URLs using only the example slug (last segment of `article.id`) instead of the full composite `section/category/article` ID. > > Updates `Example` to extract `slug` from `article.id` and uses it when building the `Embed` `src`, preventing broken `examples.tldraw.com` iframe links. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2b5862549b190fb1f5382dbc5ffe093a41c06f9d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs: expand SDK documentation with new feature guides and clarifications (#7791) This PR significantly expands and improves the tldraw SDK documentation, adding new dedicated guides for SDK features and revising existing content for clarity and accuracy. ### New documentation **SDK feature guides:** - AI integrations (ai.mdx) - guidance for using tldraw with AI tools - Arrow, draw, embed, frame, geo, note, and text shape documentation - Cross-tab sync, cursor chat, cursors, eraser, grid, pen mode - Highlighting, indicators, instance state, license key, scribble - Performance optimization guide - Visibility controls **Improvements to existing docs:** - Rewrote and reorganized editor, assets, collaboration, persistence, shapes, sync, tools, and user-interface pages for clearer structure - Updated installation and quick-start guides - Clarified starter kit documentation (branching-chat, chat, multiplayer, shader, workflow) - Updated default-shapes.mdx to reference new dedicated shape guides - Improved internal skill documentation (review-docs, writing-guide) ### Change type - [x] `docs` ### Test plan 1. Run `yarn dev-docs` and verify new pages render correctly 2. Check navigation includes new SDK features pages 3. Verify internal links work between docs ### Release notes - Add comprehensive SDK feature documentation including shape guides, AI integrations, performance tips, and more <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Docs-only changes (plus internal Claude skill docs) with no runtime or API behavior changes; main risk is broken links or confusing guidance due to large rewrites/new pages. > > **Overview** > **Expands the SDK documentation footprint and refactors several core guides for clarity.** Adds a new `AI integrations` doc and introduces/updates multiple `sdk-features` pages (including published guides like `cursor-chat`/`cursors`, plus new draft placeholders such as `arrow-shape` and `cross-tab-sync`). > > **Rewrites and trims several existing docs pages** (`editor`, `persistence`, `tools`, `user-interface`, `collaboration`, `assets`, `shapes`, `sync`) to be more task-focused, reduce long-form duplication, and point readers to the new `sdk-features` reference articles and examples. > > **Maintenance/doc process updates:** improves the internal `.claude/skills/review-docs` workflow by adding a state-file tracker with fix verification rounds and a “complete and finish” path; strengthens the writing guide with explicit guidance on removing trailing gerund phrases; and updates release notes metadata (e.g., `status: published`, refreshed `releases/next`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8c61b1277b02ca9e4c3f49abf62895641ad1fcbc. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(docs): correct starter-kits overview page article ID check (#7792) The starter-kits overview page was incorrectly showing a broken embed because the article ID check compared against `'overview'` instead of the full article key `'starter-kits/starter-kits_ucg/overview'`. Article IDs in the docs system use the format `sectionId/categoryId/articleId` (generated by `getArticleKey()`), not just the filename slug. The overview page's embed was rendering with a malformed URL like `https://starter-kits/starter-kits_ucg/overview.templates.tldraw.dev/`. ### Change type - [x] `bugfix` ### Test plan 1. Run `yarn dev-docs` 2. Navigate to `/starter-kits/overview` 3. Verify no embed is shown at the top of the page ### Release notes - Fixed starter-kits overview page showing a broken embed <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: a small conditional change in docs rendering logic that only affects whether the starter-kits embed is shown for the overview article. > > **Overview** > Fixes the `starter-kits` docs page conditional to compare against the full article key (`starter-kits/starter-kits_ucg/overview`) instead of just `overview`, preventing the `StarterKitEmbed` from rendering (and generating a broken URL) on the overview page. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8fb1db2f138f77d8e06d68709af87e3057b40784. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * feat(docs): add copy markdown and open with AI buttons to examples (#7771) Closes #6720 Adds "Copy markdown" and "Open with AI" buttons to the examples documentation header. This makes it easier for developers to copy example markdown to use as context in AI tools, or to open examples directly in Claude or ChatGPT with pre-filled prompts. ### Change type - [x] `feature` ### Test plan 1. Go to https://localhost:3000/examples/custom-stroke-and-font-sizes (or any example page) 2. Verify "Copy markdown" and "Open with AI" buttons appear next to the title 3. Click "Copy markdown" - verify the page's markdown content is copied to clipboard 4. Click "Open with AI" - verify dropdown shows Claude and ChatGPT options 5. Click Claude or ChatGPT - verify it opens the AI tool with a pre-filled prompt about the page - [ ] Unit tests - [ ] End to end tests ### Release notes - Added "Copy markdown" and "Open with AI" buttons to examples documentation pages <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Updates docs rendering and content generation by adding new `Article` fields and new llms.txt outputs, which could affect build/runtime if any article producers/consumers aren’t updated consistently. Clipboard/analytics usage is client-side but broadly scoped to all docs headers. > > **Overview** > Adds a new client-side `CopyMarkdownButton` (with clipboard + analytics tracking) and wires it into `DocsHeader`, generating a single markdown payload that concatenates the article body plus embedded code files (including filenames and fenced language tags). > > Extends docs content/build pipeline by introducing `Article.componentCodeFilename`, populating it during section generation, and updating `generateLlmsTxt` to emit `llms-releases.txt` and include releases in `llms-full.txt`; also adds a new `LLM documentation` page describing these exports. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5447a933415804d8f34d64a92beb56a7319259e8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Agent fairy backport (#7640) Things I'd like specific eyes on. - Is the agent app / agent app provider / agent provider . agent lifecycle management good? No memory leaks? - Does the prompt part util registry and agent action util registry architecture make sense? - Does the agent action schema registry make sense as a way to allow multiple modes to have actions with the same type? (we want this because some modes might want different behaviors and schemas for different action types, ie if a dev wants to add a mode where the message action also lets the agent decide to send the message to a slack channel, we still just want that action to be called 'message' in the agent's eyes) - Is the readme good? Potential follow on work - Should we add memory levels and memory transitions from fairies? - Should we add notifications and waiting from fairies? --- In order to improve maintainability and extensibility of the agent template, this PR restructures it around a manager-based architecture with clear separation of concerns. This is a clean-copy of the [original branch](https://github.com/tldraw/tldraw/tree/max/agent-fairy-backport) with a narrative commit history. ## Summary - **Manager pattern**: Decompose TldrawAgent into focused managers (chat, context, actions, mode, etc.) - **Mode system**: Define what agents can see (prompt parts) and do (actions) per mode - **Schema separation**: Split schemas (shared) from implementations (client) - **Multi-agent support**: TldrawAgentApp coordinates multiple agent instances - **Terminology**: Rename "Simple" to "Focused" for shape format ## Architecture ``` TldrawAgentApp (app-level coordinator) ├── AgentAppAgentsManager (multi-agent registry) ├── AgentAppPersistenceManager (IndexedDB persistence) └── TldrawAgent (per-agent) ├── AgentActionManager ├── AgentChatManager ├── AgentContextManager ├── AgentModeManager ├── AgentRequestManager ├── AgentLintManager ├── AgentUserActionTracker └── ... ``` ## Key changes 1. **FocusedShape terminology**: Rename SimpleShape → FocusedShape to clarify purpose 2. **Shared resources**: Move models.ts and icons to shared/ 3. **Action schema system**: Zod-based schemas with automatic type derivation 4. **Prompt part definitions**: Type-safe definitions with priority ordering 5. **Modular system prompt**: Worker builds prompts from sections based on mode flags 6. **Base manager classes**: Consistent lifecycle (reset, dispose, disposables) 7. **Mode-based action masking**: Only show available actions to the model 8. **Canvas linting**: Detect visual problems (text overflow, overlapping, etc.) 9. **User action tracking**: Record user changes between agent requests ### Change type - [x] `improvement` ### Test plan This is a pure refactoring - the final state is identical to the original branch. 1. Run `yarn typecheck` - should pass 2. Run `yarn dev-template agent` and verify the agent works 3. Compare branches: `git diff max/agent-fairy-backport max/agent-fairy-backport-clean` should be empty ### Release notes - Restructured agent template with manager-based architecture for better modularity - Added mode system for controlling agent capabilities - Renamed SimpleShape to FocusedShape for clarity <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk due to large-scale refactor of core agent lifecycle/prompting/action execution plus new persistence and mode gating; regressions could break prompting loops, action application, or state restoration. > > **Overview** > Refactors the agent template to an app/manager architecture: introduces `TldrawAgentApp` + `TldrawAgentAppProvider` for agent lifecycle and localStorage persistence, and decomposes `TldrawAgent` state into managers (requests, chat, context, mode, actions, lints, debug, todos, user-action tracking). > > Adds a mode system (`AgentModeDefinitions`/`AgentModeChart`) that explicitly controls which prompt parts and action types are available per mode, including mode lifecycle hooks and support for mode-scoped action implementations via new self-registering registries (`registerPromptPartUtil`, `registerActionUtil`). Also updates shape/data terminology and plumbing (`Simple*` �� `Focused*`), expands helper APIs (offset/rounding helpers), adds canvas lint reporting, and refreshes the README/documentation to match the new structure and APIs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c521002389dc0a4de66b9ed2623c97d498c71ec0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * cleanup: rm core-js usage (#7769) these functions have baseline support now, we don't need this dependency anymore fixes https://github.com/tldraw/tldraw/issues/5945 ### Change type - [ ] `bugfix` - [x] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Release notes - cleanup: rm core-js usage <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk cleanup that removes bundled polyfills and related types; the main risk is runtime regressions in older browsers/environments that relied on `core-js` for `at`, `flat`, `flatMap`, or `replaceAll`. > > **Overview** > Removes `core-js` usage from `@tldraw/editor` by dropping the `core-js` and `@types/core-js` dependencies and deleting the explicit polyfill imports from `src/index.ts`. > > Updates `yarn.lock` accordingly and trims the dependency list in `CONTEXT.md`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 48323f4a75316a344c14683259e19e10ba1c5060. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs(starter-kits): make bento images clickable and improve copy (#7800) In order to improve navigation on the starter kits overview page, this PR makes the images in `StarterKitBento` components clickable, linking to their respective starter kit detail pages. This allows users to click directly on the visual preview to learn more. Additionally: - Adds explicit "Try the X starter kit" links below several sections for clearer CTAs - Updates the "Why build with starter kits" section copy to better describe the value proposition - Fixes a typo in the branching image filename (`bramching.png` → `branching.png`) ### Change type - [x] `improvement` ### Test plan 1. Navigate to the starter kits overview page 2. Verify each bento image is clickable and links to the correct starter kit page 3. Verify the "Try the X starter kit" links work correctly - [ ] Unit tests - [ ] End to end tests ### Release notes - Improved starter kits overview page with clickable images and clearer calls to action <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk docs/UI change: adds a required link prop and updates MDX content/copy with no backend, auth, or data-handling impact. > > **Overview** > Improves navigation on the starter kits overview by making `StarterKitBento` preview images linkable via a new required `href` prop and wrapping the image in an anchor. > > Updates `starter-kits/overview.mdx` to pass `href` to each bento, adds clearer “Try the … starter kit” CTAs under several kits, and refreshes the *Why build with starter kits* copy to better describe the SDK-focused value proposition. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 717d6aeb9cbdca81f2e16aa35f7702e92f22e923. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * feat(zoom): add quick zoom navigation (#7801) Adds a "quick zoom" or "eagle eye" feature to the zoom tool for fast canvas navigation. When in zoom mode, pressing Shift zooms out to 5% and shows a viewport brush. Move the cursor to select where to zoom, then release Shift to zoom to that location. Press Escape to cancel. This is a reimplementation of the `mime/eagle-eye` branch with a clean commit history for easier review. Original branch: https://github.com/tldraw/tldraw/tree/mime/eagle-eye ### Change type - [x] `feature` ### Test plan 1. Open the editor with some shapes 2. Press `z` to enter zoom mode 3. Press Shift to zoom out to 5% ("eagle eye" view) 4. A viewport brush appears at 1/4 screen size 5. Move cursor to reposition where you'll zoom to 6. Release Shift to zoom to the brush location 7. Alternatively, press Escape to cancel and return to original view 8. Verify it works from any tool (draw, select, etc.) - [x] Unit tests ### API changes - Added `'action.select-zoom-tool'` to `TLUiTranslationKey` type ### Release notes - Added quick zoom navigation: press `z` then hold Shift to zoom out and see the whole canvas, move cursor to pick a location, release to zoom there. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds new zoom-tool state transitions and keyboard shortcut handling (`z`/Shift/Escape) plus camera adjustments, which could regress existing input/shortcut behavior and tool-return logic. Changes are localized to the zoom tool/UI and covered by updated tests. > > **Overview** > Adds a new *quick zoom (“eagle eye”)* interaction to `ZoomTool`: while in zoom mode, holding Shift zooms out to 5%, shows a movable viewport brush, and on release zooms back into the brushed area (Escape cancels back to the prior view/tool). > > Refactors zoom-tool entry/exit to use full tool-state paths for `onInteractionEnd`, updates the `select-zoom-tool` action/shortcut wiring (including undo-safe guards), and extends translations/API types plus the keyboard shortcuts dialog/docs to expose the new `select-zoom-tool` action and behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 130bc3e98146edadf2bd1b20afc0256fa35e66f3. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Mime Čuvalo <[email protected]> * fix(menu): add useCanApplySelectionAction hook to disable menu items when not in select tool (#7811) In order to properly disable menu items when selection-dependent actions cannot be applied, this PR adds a reusable `useCanApplySelectionAction` hook that checks whether the user is in the select tool AND has shapes selected. This corresponds to the `canApplySelectionAction()` check used by many actions in `actions.tsx`. Closes #7810 ### Changes Updated menu items to use the new hook: - `ZoomToSelectionMenuItem` - now uses `useCanApplySelectionAction` - `CutMenuItem` - now checks `useCanApplySelectionAction` + unlocked shapes - `CopyMenuItem` - now uses `useCanApplySelectionAction` - `DeleteMenuItem` - now checks `useCanApplySelectionAction` + unlocked shapes ### Change type - [x] `bugfix` ### Test plan 1. Create some shapes on the canvas 2. Select one or more shapes with the select tool 3. Switch to a different tool (e.g., press 'D' for draw tool) 4. Open menus and verify that selection-dependent items (zoom to selection, cut, copy, delete) are disabled 5. Switch back to select tool and verify items are enabled again - [ ] Unit tests - [ ] End to end tests ### API changes - Added `useCanApplySelectionAction()` hook that returns true when in select tool with shapes selected ### Release notes - Add `useCanApplySelectionAction` hook for checking if selection actions should be enabled - Fix menu items (zoom to selection, cut, copy, delete) being enabled when not in select tool --------- Co-authored-by: Steve Ruiz <[email protected]> * add tldraw-y claude verbs (#7807) Replaces bad claude verbs with good tldraw claude verbs ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk configuration-only change affecting Claude UI spinner wording; no runtime application logic is modified. > > **Overview** > Updates `.claude/settings.json` to **replace** the Claude `spinnerVerbs` list with a new set of tldraw-style verbs (e.g., panning/zooming/drawing/etc.), leaving existing permissions/hooks unchanged. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 645b99ca4b9d1931f8486d49ac0225e77c135d5a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Steve Ruiz <[email protected]> * docs: add comprehensive handles / indicators documentation (#7817) This PR adds a new documentation page for handles in tldraw, covering how to create and customize interactive control points on shapes. ## Overview The new `handles.mdx` documentation provides a complete guide to working with handles in tldraw, including: - **Handle basics**: How to define handles using `getHandles` on ShapeUtil - **Handle types**: Explanation of `vertex`, `virtual`, `create`, and `clone` handle types - **Drag handling**: How to respond to handle drags with `onHandleDrag` and lifecycle callbacks - **Snapping behavior**: Configuration of point and alignment snapping, angle snapping with Shift, and custom snap geometry via `getHandleSnapGeometry` - **Complete example**: A fully functional speech bubble shape with a draggable tail handle - **API reference**: How to read handles using `Editor#getShapeHandles` - **Examples**: Links to example implementations ### Change type - [x] `docs` ### Test plan - [x] Documentation review - [x] Code examples are syntactically correct and follow tldraw patterns - [x] All referenced APIs and methods exist in the codebase ### Release notes - Add comprehensive documentation for handles, including creation, customization, snapping, and lifecycle management --------- Co-authored-by: Claude <[email protected]> * perf(bindings): skip unnecessary arrow updates when translating (#7733) In order to improve performance when translating arrows together with their bound shapes, this PR adds an early-return check in `ArrowBindingUtil.onAfterChangeFromShape` to skip unnecessary updates. https://github.com/user-attachments/assets/e8d3d131-33e5-4b14-b813-12e81fd8a4f6 Previously, `onAfterChangeFromShape` would always call `arrowDidUpdate()` which performs expensive `reparentArrow()` operations involving common ancestor lookups, sibling searches, and index recalculations. When arrows and their bound shapes are moved together, the bindings remain valid and no reparenting is needed. This optimization mirrors the existing check in `onAfterChangeToShape`, now applied to the arrow's own changes. ### Change type - [x] `improvement` ### Test plan 1. Create multiple shapes and connect them with arrows 2. Select all shapes and arrows together 3. Drag/translate the selection 4. Verify the arrows maintain their bindings correctly 5. Verify performance improvement when moving many connected shapes ### API changes - Changed `ArrowBindingUtil.onAfterChangeFromShape` to use `shapeBefore` and `reason` parameters from options (internal implementation change, no breaking changes to public API) ### Release notes - Improve performance when translating arrows together with their bound shapes Co-authored-by: Claude <[email protected]> * feat(tldraw): add TldrawUiSelect component (#7566) This PR adds a new `TldrawUiSelect` component - a select dropdown primitive wrapping Radix UI's Select, following existing tldraw UI patterns. Closes #7560 ## Components - `TldrawUiSelect` - Root component with value/onChange - `TldrawUiSelectTrigger` - Trigger button - `TldrawUiSelectValue` - Displays selected value (with optional icon) - `TldrawUiSelectContent` - Dropdown container - `TldrawUiSelectItem` - Individual item (styled like checkbox menu items with check indicator) ## Usage ```tsx <TldrawUiSelect value={value} onValueChange={setValue}> <TldrawUiSelectTrigger> <TldrawUiSelectValue placeholder="Select...">{value}</TldrawUiSelectValue> </TldrawUiSelectTrigger> <TldrawUiSelectContent> <TldrawUiSelectItem value="small" label="Small" icon="size-small" /> <TldrawUiSelectItem value="medium" label="Medium" icon="size-medium" /> <TldrawUiSelectItem value="large" label="Large" icon="size-large" /> </TldrawUiSelectContent> </TldrawUiSelect> ``` ## UI primitives example This PR also adds a new "UI primitives" example that showcases all tldraw UI components in one place: - Buttons (normal, primary, danger, disabled, icon buttons) - Dropdown menus (with items, checkbox items, submenus) - Select dropdowns (with and without icons) - Text inputs - Sliders - Popovers - All available icons (displayed in a grid with tooltips) - Tooltips - Keyboard shortcut badges The example uses `OnTheCanvas` to render the UI showcase directly on the canvas, making it easy to zoom in and inspect components at different scales (useful for pixel peeping). ## Also included - Export of `iconTypes` array for enumerating all available icons ### Change type - [x] `feature` - [x] `api` ### Test plan 1. Run `yarn dev` and navigate to the "UI primitives" example 2. Test the select dropdowns - verify they open, close, and show the check indicator on selected items 3. Verify the select items have left-aligned text matching checkbox menu items 4. Explore the various UI primitives shown in the example ### Release notes - Added new `TldrawUiSelect` component for building custom select dropdowns - Added UI primitives example showcasing all tldraw UI components - Exported `iconTypes` array for enumerating available icons ### API changes - Added `TldrawUiSelect`, `TldrawUiSelectTrigger`, `TldrawUiSelectValue`, `TldrawUiSelectContent`, `TldrawUiSelectItem` components - Added `TLUiSelectProps`, `TLUiSelectTriggerProps`, `TLUiSelectValueProps`, `TLUiSelectContentProps`, `TLUiSelectItemProps` types - Added `iconTypes` export (array of all icon type strings) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a selectable dropdown primitive and a comprehensive example to showcase UI components. > > - New select primitives: `TldrawUiSelect`, `TldrawUiSelectTrigger`, `TldrawUiSelectValue`, `TldrawUiSelectContent`, `TldrawUiSelectItem` with Radix-backed behavior and tldraw styling > - Exposes `TldrawUiDropdownMenuSubContent` and associated `*Props` types; updates `index.ts` exports and API report > - Select styles in `lib/ui.css` (trigger, content, items) and new component at `lib/ui/components/primitives/TldrawUiSelect.tsx` > - Example: `apps/examples/src/examples/ui-primitives` with README, `UiPrimitivesExample.tsx`, and `ui-primitives.css` demonstrating buttons, dropdowns, select, input, slider, popover, icons, tooltips, kbd > - Export `iconTypes` array from `tldraw` for enumerating available icons > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1572a89807a16034d157e498c2c0394930ec6bc5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> * fix(actions): add selection check to toggle-lock action (#7815) The toggle-lock action was missing the `canApplySelectionAction()` guard that other selection-dependent actions have. This caused the action to fire even when no shapes were selected, which is inconsistent with similar actions like group, duplicate, etc. ### Change type - [x] `bugfix` ### Test plan 1. Open the editor with some shapes on the canvas 2. Click on empty space to deselect all shapes 3. Press `Shift+L` - verify nothing happens 4. Select a shape 5. Press `Shift+L` - verify the shape toggles locked state - [ ] Unit tests - [x] End to end tests ### Release notes - Fixed toggle-lock action (Shift+L) firing when no shapes are selected. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk behavior change: adds early returns so selection-dependent keyboard actions no longer fire (or emit UI events) when nothing is selected; main risk is minor UX regression if any workflows relied on the old no-op event emission. > > **Overview** > Prevents selection-dependent actions from running when no shapes are selected by adding `canApplySelectionAction()` guards to `toggle-lock`, `enlarge-shapes`, and `shrink-shapes`. > > Updates the Playwright keyboard shortcut E2E test to assert these shortcuts do **not** emit events when nothing is selected, and still emit the expected events once shapes are selected. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bccc5282f259e1a1632c271f94c8eb201a106bb7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(editor): reduce tab width in rich text to 2 spaces (#7796) In order to reduce the excessive tab indentation in text shapes, this PR adds a `tab-size: 2` CSS rule to `.tl-rich-text .ProseMirror` so tabs render at 2 space widths instead of the browser default of 8. Closes #7703 ### Change type - [x] `bugfix` ### Test plan 1. Run `yarn dev` 2. Create a text shape (press T or select text tool) 3. Type some text and press Tab to insert indentation 4. Verify the tab renders at 2 space widths instead of 8 ### Release notes - Fixed excessive tab indentation in text shapes (now 2 spaces instead of 8) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk styling-only change that affects how tab characters render in rich text (including SVG export), with minimal chance of regressions beyond text layout differences. > > **Overview** > Reduces rich-text tab indentation by introducing a shared `--tl-tab-size` CSS variable (default `2`) and applying `tab-size` to `.tl-rich-text` so Tab characters render at 2-space width instead of the browser default. > > Ensures exported SVG rich text matches in-editor rendering by adding `tabSize: var(--tl-tab-size, 2)` to `RichTextSVG`, and updates the `getSvgString` snapshot accordingly. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4482b9ab0ceede350187b5c248868537c56a6ba6. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix: Safari pinch zoom resetting selection to previous shapes (#7777) fixes https://github.com/tldraw/tldraw/issues/6907 ### Change type - [x] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Release notes - fix: Safari pinch zoom resetting selection to previous shapes <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches core input/selection state during pinch and pointer events; small but behavior-sensitive and could cause selection changes across browsers/devices if assumptions differ. > > **Overview** > Prevents Safari pinch-zoom from restoring an outdated selection by **always snapshotting** `pageState.selectedShapeIds` at `pinch_start` (instead of reusing a previously-stashed value). > > Also **clears** `_selectedShapeIdsAtPointerDown` on `pointer_up` so subsequent pinch gestures capture fresh selection state rather than reapplying stale IDs. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 996531da05c45a7d58103e5743e63152af649e8d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Steve Ruiz <[email protected]> * fix(dotcom): provide compiled messages to ErrorPage IntlProvider (#7820) Fixes #7799 The `ErrorPage` component was passing an empty messages object (`messages={{}}`) to its `IntlProvider`, causing react-intl `FORMAT_ERROR` when rendering translated strings in `GoBackLink`: ``` [@formatjs/intl Error FORMAT_ERROR] Error formatting default message for: "324a0f3182", rendering default message verbatim ``` This imports the compiled English translations (same file used by `TlaRootProviders`) and passes them to the `IntlProvider`. ### Change type - [x] `bugfix` ### Test plan 1. Navigate to an error page (e.g., invalid file URL) 2. Open browser console 3. Verify no FORMAT_ERROR is logged ### Release notes - Fixed react-intl console errors on error pages --- Co-authored-by: Kai Gritun <[email protected]> Co-authored-by: Kai Gritun <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]> * chore(sync): re-enable rate limiting (#7822) The Cloudflare rate limiting issue from #7780 has been resolved. This PR re-enables rate limiting by restoring the original `isRateLimited` implementation that calls `env.RATE_LIMITER.limit()`. https://www.cloudflarestatus.com/incidents/dk0d6pjt9vjx ### Change type - [x] `improvement` ### Test plan 1. Deploy to staging 2. Verify sync connections work normally 3. Verify rate limiting kicks in under heavy load <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Re-enables enforcement of request limits in the sync worker; misconfigured limiter settings or unexpected limiter behavior could cause elevated 429s and disrupt sync/feedback flows under load. > > **Overview** > Re-enables rate limiting in the sync worker by restoring `isRateLimited` to call `env.RATE_LIMITER.limit({ key })` and returning `!success`, instead of always allowing requests. > > This changes runtime behavior for all call sites (e.g., websocket connections/mutations and `submitFeedback`) to actively enforce limits again. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 17f882a626978fe85314d047634da4fb90db205c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * perf(editor): skip hover updates while panning (#7826) This PR improves performance when panning in large documents by skipping expensive hover hit-testing while the camera is moving. Riffing on https://github.com/tldraw/tldraw/pull/5603 ### How it works Hit-testing shapes is expensive in large documents. When panning, we don't need continuous hover updates—we just need to resume when the camera stops. The logic: 1. Camera idle → update hover normally 2. Camera moving + locked → skip entirely (no hit-testing) 3. Camera moving + no current hover → lock immediately 4. Camera moving + same shape → keep current hover 5. Camera moving + different shape → clear hover and lock This means: when you start panning over a shape, it stays hovered until your cursor moves off it, then hover clears and we stop hit-testing until the camera stops. ### Changes - Added `cameraState: 'idle' | 'moving'` to `TLInstance` (promoted from private atom) - Added side effect that triggers `updateHoveredShapeId` when camera becomes idle - Added hover-locking logic in `updateHoveredShapeId.ts` ### Change type - [x] `improvement` ### API changes - Added `TLInstance.cameraState: 'idle' | 'moving'` - tracks whether the camera is currently moving or idle ### Test plan 1. Open a document with many shapes 2. Pan around the canvas 3. Verify hover states don't flicker or cause slowdown 4. Verify hover resumes correctly when panning stops ### Release notes - Improved performance when panning in large documents by skipping hover updates during camera movement. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes how `cameraState` is stored/migrated on `TLInstance` and alters hover hit-testing behavior during camera movement, which could cause hover/selection regressions in edge cases. > > **Overview** > Improves panning performance by **skipping expensive hover hit-testing while the camera is moving** and only resuming hover updates once the camera returns to idle. > > Promotes camera movement state into `TLInstance.cameraState` (with defaults + migration), updates `Editor.getCameraState()` to read/write via instance state, and adds a default side effect to run `updateHoveredShapeId` when `cameraState` transitions to `idle`. > > Reworks `updateHoveredShapeId` to implement a per-editor “hover lock” during camera movement: keep the current hovered shape if unchanged, otherwise clear hover and stop hit-testing until the camera stops; adds tests covering these scenarios. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit af79115add89f9648a46a66703035def02d57d19. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> * fix(sync): fix SQLite migration for multiplayer template (#7829) The multiplayer template's wrangler.toml was using `new_sqlite_classes` in its v1 migration, which doesn't work for existing deployments that were originally created with `new_classes` (KV-backed Durable Objects). Cloudflare skips already-applied migration tags, so the SQLite switch was silently ignored on redeploy. This fixes the migrations to be append-only: v1 creates the DO with `new_classes`, and v2 enables SQLite via `classes_with_sqlite`. ### Change type - [x] `bugfix` ### Test plan 1. Deploy the multiplayer template to an existing Cloudflare worker that was previously using KV-backed DOs 2. Verify the v2 migration applies and SQLite storage works ### Release notes - Fixed SQLite migration for the multiplayer Cloudflare template to work with existing deployments <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adjusts Cloudflare Durable Object migration configuration; misconfiguration could affect deploy/upgrade behavior for existing rooms, but change is limited to `wrangler.toml` and is straightforward. > > **Overview** > Fixes `templates/sync-cloudflare/wrangler.toml` Durable Object migrations to be *append-only* and compatible with existing deployments. > > `v1` now uses `new_classes` (matching original KV-backed creation), and a new `v2` migration enables SQLite via `classes_with_sqlite` so redeploys actually apply the storage switch. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1d908f6a5ec4c23d0e1705412fbd46b337282f4a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(sync): fix Durable Object SQLite migration in multiplayer template (#7832) In order to fix the multiplayer template's broken Durable Object migrations (where `classes_with_sqlite` was used as an invalid Cloudflare migration directive), this PR replaces the old `TldrawDurableObject` with a new `TldrawDurableObjectSqlite` class using proper `new_sqlite_classes` migration. Follows up on #7829 which attempted to fix this by collapsing migrations, but that approach doesn't work for existing deployments that already ran v1/v2. Instead, this adds a v3 migration that deletes the old class and creates a new SQLite-backed one. Closes #7804 ### Change type - [x] `bugfix` ### Test plan 1. Run `yarn dev-template sync-cloudflare` 2. Verify the Durable Object deploys and rooms work correctly 3. Verify existing deployments can migrate from v1/v2 to v3 ### Release notes - Fix Durable Object SQLite migration in the multiplayer Cloudflare template <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes Cloudflare Durable Object class names and migration directives, including deleting the previous class and introducing a new SQLite-backed class, which can affect existing deployments during upgrade. > > **Overview** > Fixes the `sync-cloudflare` multiplayer template’s broken Durable Object SQLite rollout by switching the durable object binding/export from `TldrawDurableObject` to a new `TldrawDurableObjectSqlite` implementation. > > Updates `wrangler.toml` migrations to add a `v3` step that **deletes** the old class and creates the replacement via Cloudflare’s supported `new_sqlite_classes` directive (and annotates `v2` as a no-op), and refreshes generated types in `worker-configuration.d.ts` to point at the new class. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e1f73f0b8a74ff73bb3d69b02cffcd2a3f7ea218. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(sync): remove deleted_classes from multiplayer template migration (#7834) Cloudflare rejects `--delete-class` migrations when the class was previously referenced by a binding, even if the binding now points to a different class. This removes `deleted_classes = ["TldrawDurableObject"]` from the v3 migration so the deploy succeeds. The old class stays around unused. Follows the same pattern used in the production sync worker when migrating `TLDR_DOC` from `TLDrawDurableObject` to `TLFileDurableObject`. Relates to #7832 ### Change type - [x] `bugfix` ### Test plan 1. Deploy the multiplayer template to Cloudflare 2. Verify the deploy succeeds without the "Cannot apply --delete-class migration" error ### Release notes - Fix multiplayer template deployment error caused by deleting a previously-bound Durable Object class <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk configuration-only change to Cloudflare `wrangler.toml` migrations; the main impact is on deployment/migration behavior, where it now avoids a deploy-time rejection. > > **Overview** > Fixes the multiplayer Cloudflare template’s Durable Object migration sequence so deployments don’t fail on a `--delete-class` operation. > > Removes the `deleted_classes` directive from the `v3` migration (leaving the old class undeleted) and clarifies the `v2` comment while keeping the `v2` migration tag for already-applied deployments. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 78f9c2783d685e91cecd0d7899c96ab54ff008db. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Revert back to what we had. (#7835) We'll delete the worker and make it redeploy so it picks up the v1 again. ### Change type - [x] `bugfix` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Updates the Durable Object class name and wrangler migrations, which can affect existing deployments’ object class mapping and stored state if the migration history differs. Runtime logic is unchanged but misconfiguration could break room connectivity or data persistence. > > **Overview** > Reverts the Cloudflare sync template to use a single SQLite-backed Durable Object class named `TldrawDurableObject` (renaming from `TldrawDurableObjectSqlite`) and updates exports and generated env typings accordingly. > > Adjusts `wrangler.toml` to bind `TLDRAW_DURABLE_OBJECT` to the reverted class and collapses migrations back to a single `v1` `new_sqlite_classes` entry, removing the prior `v2`/`v3` migration history. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b9bf9529300e87ae9ce445db5a02fda7b951711a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs: add drag and drop SDK documentation (#7830) Adds new documentation for the shape-to-shape drag and drop system in tldraw. This covers the `ShapeUtil` callbacks (`onDragShapesIn`, `onDragShapesOver`, `onDragShapesOut`, `onDropShapesOver`) that shapes can implement to respond to other shapes being dragged over them. This is distinct from the existing "External content handling" documentation which covers content dragged from outside the browser (files, URLs, etc.). ### Change type - [x] `docs` ### Test plan 1. Run `yarn dev-docs` 2. Navigate to SDK Features > Drag and drop 3. Verify the article renders correctly with all code examples and tables ### Release notes - Add documentation for the shape-to-shape drag and drop system <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: adds a new MDX documentation page only, with no runtime code or behavior changes. > > **Overview** > Adds a new `sdk-features/drag-and-drop.mdx` article documenting the shape-to-shape drag-and-drop system for custom shapes. > > Covers `ShapeUtil` drag/drop callbacks (`onDragShapesIn`, `onDragShapesOver`, `onDragShapesOut`, `onDropShapesOver`), the associated info objects, guidance for determining drop targets and filtering acceptable child types via `canReceiveNewChildrenOfType`, plus a complete slot-container example and links to related docs/examples. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 55eb4b25cfc50bde0c2d836d29ed848defb7ffe8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * Remove deprecated downlevelIteration option (#7813) This option is deprecated in TypeScript 6.0. It doesn't do anything when `target` is `esnext`, so can be safely removed from this config file. ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk config cleanup: removes a deprecated TypeScript compiler option that is a no-op when targeting `ESNext`, so it should not affect builds or runtime behavior. > > **Overview** > Removes the deprecated `downlevelIteration` setting from `apps/dotcom/zero-cache/tsconfig.json` (a no-op with `target: ESNext`) to keep the TypeScript config compatible with newer TypeScript versions. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ac9912efaa9134d96eafac3b74eff9730d4a4985. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * chore: remove fairy feature (#7809) Remove fairy feature completely from frontend and backend while preserving database tables. Closes #7808 ### Change type - [x] `other` ### Test plan - [x] Verify `/pricing` route returns 404 - [x] Verify `/fairy-invite/:token` route returns 404 - [x] Verify admin page loads without fairy section - [x] Verify editor loads without fairy UI - [x] Verify no build/lint/type errors ### Manual cleanup required (post-merge) #### GitHub secrets to delete - [ ] `FAIRY_MODEL` - [ ] `FAIRY_WORKER` - [ ] `FAIRY_WORKER_SENTRY_DSN` - [ ] `DISCORD_FAIRY_PURCHASE_WEBHOOK_URL` - [ ] `PADDLE_FAIRY_PRICE_ID` - [ ] Any other `FAIRY_*` prefixed secrets #### Cloudflare sync-worker env vars - [ ] `PADDLE_WEBHOOK_SECRET` — keep if used for other Paddle products - [ ] `PADDLE_ENVIRONMENT` — keep if used for other Paddle products #### Cloudflare workers to delete - [ ] Delete fairy worker deployments (production, staging, preview matching `*-tldraw-fairy`) - [ ] Delete associated KV namespaces, R2 buckets, Durable Objects (AgentDurableObject) - [ ] Delete custom domains matching `*-fairy.tldraw.xyz` #### Cloudflare KV feature flags - [ ] Remove `fairies` key from `FEATURE_FLAGS` KV - [ ] Remove `fairies_purchase` key from `FEATURE_FLAGS` KV #### DNS/routing - [ ] Remove any custom domains or routes for `fairy.tldraw.com` or `/api/fairy/*` #### Paddle - [ ] Archive Paddle product if no longer needed - [ ] Remove webhook endpoints in Paddle dashboard #### Monitoring - [ ] Remove fairy worker health check alerts - [ ] Remove Paddle webhook failure alerts - [ ] Remove fairy-related error rate alerts #### Database tables (DO NOT DELETE) These tables are preserved for data integrity and can be cleaned up later: - `user_fairies` - `file_fairies` - `fairy_invite` - `file_fairy_messages` - `paddle_transactions` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes deployment environment configuration and removes dependencies/assets; if any remaining code paths still reference the removed env vars or assets, builds or deploys could fail. > > **Overview** > **Removes the "fairy" feature surface area from dotcom.** The deploy workflow no longer passes `FAIRY_*`, fairy Discord webhook, or `PADDLE_*` fairy-related secrets into the deployment environment. > > On the client, `@tldraw/fairy-shared` and `public/fairy/*` SVG assets are removed, and i18n extraction/compiled locale bundles are updated to drop fairy-related message IDs (and other now-unused strings). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit b07f83276aa4799bd8da4ac77004e0bbef833a62. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs(examples): add conditional culling example (#7847) Adds a new example demonstrating how to use the `canCull()` method to conditionally prevent shapes from being culled based on their props. The example shows two shapes with glow effects that extend beyond their bounds. One shape has culling disabled (stays visible when panned off-screen), while the other can be culled (disappears abruptly). This makes the visual "pop" artifact obvious when comparing the two. https://github.com/user-attachments/assets/622430ff-2c0c-4d3a-b4cb-4ec72c080ca1 Resolves https://github.com/tldraw/tldraw/issues/7462 ### Change type - [x] `improvement` ### Test plan 1. Run `yarn dev` and navigate to the "Conditional culling" example under Editor API 2. Pan the canvas horizontally so both shapes move toward the viewport edge 3. Observe: the shape with "Prevent culling" checked stays visible, the other disappears at the edge ### Release notes - Add example showing conditional culling with `canCull()` for shapes with overflow effects <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Docs/example-only addition with no changes to core library/runtime behavior; risk is limited to example build/regression in the examples app. > > **Overview** > Adds a new **Conditional culling** example that introduces a custom `glow-shape` with a `preventCulling` prop and overrides `ShapeUtil.canCull()` to keep the shape rendered even when off-screen. > > The example mounts two glowing shapes and provides an in-shape checkbox that toggles `preventCulling`, making it easy to compare “always rendered” vs “culled at viewport edge” behavior; accompanying README documents the use case and performance tradeoff. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0e2527f673769786514e37844e8f32de96f7663c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * chore: remove CONTEXT.md files and context management scripts (#7852) In order to reduce maintenance overhead, this PR removes all 33 CONTEXT.md files and the two scripts used to manage them (`yarn context` and `yarn refresh-context`). Closes #7851. The CONTEXT.md system required keeping files in sync across the monorepo, with ~930 lines of script code and a dependency on the Claude Code CLI. The CLAUDE.md file already provides sufficient guidance for working with the codebase. ### Change type - [x] `other` ### Test plan - [x] Typecheck passes (`yarn typecheck`) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation and developer-tooling removal only; no runtime/product code paths are affected beyond removing unused scripts from `package.json`. > > **Overview** > Removes the monorepo’s AI-focused `CONTEXT.md` documentation system: deletes the root `CONTEXT.md` plus all package/app `CONTEXT.md` files. > > Eliminates the supporting maintenance tooling by deleting `internal/scripts/context.ts` and `internal/scripts/refresh-context.ts`, and drops the `context`/`refresh-context` npm scripts (including any per-package `context` script usage). Updates `README.md` and `CLAUDE.md` to remove references to the deleted context workflow and keep agent guidance centralized in `CLAUDE.md`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit e4226e308502a055a27880fedd092818fc12ef6f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * docs: add LOD to performance doc and create a performance example (#7859) - expand the performance doc - fix the sorting order - @steveruizok we might consider adding something to the marketing site actually, under the Product dropdown - add an example for performance, came up in a sales call and we didn't have something we could show off: <img width="1214" height="1067" alt="Screenshot 2026-02-06 at 18 43 58" src="https://github.com/user-attachments/assets/60c6e25c-414c-49ad-9dbb-8fa55275923f" /> ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Docs and example additions with only a small comment/default-threshold documentation tweak in editor options; no runtime logic changes apparent. > > **Overview** > Expands SDK performance documentation to cover **level-of-detail (LOD)** behavior, including image resolution scaling via `TLAssetStore.resolve`/`TLAssetContext.steppedScreenScale` and examples of built-in LOD simplifications. > > Adds a new `ManyShapesExample` that can generate/clear hundreds to thousands of shapes to showcase culling, batched updates (`editor.run()`), debounced/efficient zoom behavior, and LOD transitions. Also fixes docs frontmatter ordering metadata and updates `TldrawOptions` docs to reference `editor.getEfficientZoomLevel()` and a 500-shape default threshold. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit df78eefa0644c70a50154b04ac3e7aa45e8a895b. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Steve Ruiz <[email protected]> Co-authored-by: Claude Opus 4.6 <[email protected]> * Fix serving of svg assets (#7872) ### Change type - [x] `bugfix` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes response security headers for all served uploads, which could affect client rendering/embedding behavior, but is scoped to asset download endpoints and reduces XSS risk. > > **Overview** > Adds defense-in-depth headers when serving user-uploaded assets to prevent SVG/executable content from running when accessed from the app origin. > > Cloudflare R2-backed download handlers and the Fastify/Express template `/uploads/:id` routes now set `Content-Security-Policy: default-src 'none'` and `X-Content-Type-Options: nosniff` on asset responses. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3ac8fe3c453fe39c2024a6c202c59639fbc4016e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * [HOTFIX] Fix serving of svg assets (#7873) This is an automated hotfix PR for dotcom deployment. **Original PR:** [#7872](https://github.com/tldraw/tldraw/pull/7872) **Original Title:** Fix serving of svg assets **Original Author:** @MitjaBezensek This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment. /cc @MitjaBezensek <!-- CURSOR_SUMMARY --> --- > [!NOTE] > <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is generating a summary for commit c30364f927dbd65041914850faa8aac7a81f3a3e. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Mitja Bezenšek <[email protected]> * Add VSCode extension v2.203.0 [skip ci] * license: fix console message colors for warnings/errors (#7850) oof, i had messed this up in https://github.com/tldraw/tldraw/pull/6844 🤦 i'll have to backport this to the 3.x branch as well, doh ### Change type - [x] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` ### Release notes - license: fix console message colors for warnings/errors <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Only affects verbose console logging styles for license warnings/errors; no licensing logic or data handling changes. > > **Overview** > Fixes console output styling for license validation messages so *warnings* and *errors* render with consistent, type-appropriate colors. > > `outputDelimiter` now accepts the message `type` and uses the same background color as the message output, and message text is standardized to white for readability. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6d83c190585f9ea3a2f8d488a6e4ec7bd97f0ea2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> * fix(dotcom): prevent flash of white background in dark mode (#7842) In order to prevent the jarring flash of white background when loading tldraw.com with dark mode enabled, this PR adds early theme detection that runs before React hydration. Closes #7542 ### Approach The fix uses a combination of techniques to eliminate the flashbang: 1. **External theme-init.js script** - Loaded in `<head>` before CSS, this script reads the user's theme preference from localStorage and immediately sets `data-theme` attribute and inline styles on `<html>`. Using an external file avoids CSP violations that caused the previous inline script approach to be reverted. 2. **CSS fallback styles** - New CSS rules in `globals.css` use the `data-theme` attr…
This PR adds a new
TldrawUiSelectcomponent - a select dropdown primitive wrapping Radix UI's Select, following existing tldraw UI patterns.Closes #7560
Components
TldrawUiSelect- Root component with value/onChangeTldrawUiSelectTrigger- Trigger buttonTldrawUiSelectValue- Displays selected value (with optional icon)TldrawUiSelectContent- Dropdown containerTldrawUiSelectItem- Individual item (styled like checkbox menu items with check indicator)Usage
UI primitives example
This PR also adds a new "UI primitives" example that showcases all tldraw UI components in one place:
The example uses
OnTheCanvasto render the UI showcase directly on the canvas, making it easy to zoom in and inspect components at different scales (useful for pixel peeping).Also included
iconTypesarray for enumerating all available iconsChange type
featureapiTest plan
yarn devand navigate to the "UI primitives" exampleRelease notes
TldrawUiSelectcomponent for building custom select dropdownsiconTypesarray for enumerating available iconsAPI changes
TldrawUiSelect,TldrawUiSelectTrigger,TldrawUiSelectValue,TldrawUiSelectContent,TldrawUiSelectItemcomponentsTLUiSelectProps,TLUiSelectTriggerProps,TLUiSelectValueProps,TLUiSelectContentProps,TLUiSelectItemPropstypesiconTypesexport (array of all icon type strings)Note
Adds a selectable dropdown primitive and a comprehensive example to showcase UI components.
TldrawUiSelect,TldrawUiSelectTrigger,TldrawUiSelectValue,TldrawUiSelectContent,TldrawUiSelectItemwith Radix-backed behavior and tldraw stylingTldrawUiDropdownMenuSubContentand associated*Propstypes; updatesindex.tsexports and API reportlib/ui.css(trigger, content, items) and new component atlib/ui/components/primitives/TldrawUiSelect.tsxapps/examples/src/examples/ui-primitiveswith README,UiPrimitivesExample.tsx, andui-primitives.cssdemonstrating buttons, dropdowns, select, input, slider, popover, icons, tooltips, kbdiconTypesarray fromtldrawfor enumerating available iconsWritten by Cursor Bugbot for commit 1572a89. This will update automatically on new commits. Configure here.