Conversation
In order to demonstrate the full range of reactive inputs available in the editor's InputsManager (closes #7713), this PR adds modifier key indicators to the reactive inputs example and moves the panel into the canvas UI as a TopPanel component. It also fixes a bug where modifier key state (particularly Meta/Cmd on macOS) could get stuck after key release, because on macOS the keyup event for Cmd can report `e.metaKey = true`. The fix force-clears a modifier key's state when its own explicit keyup event is received. ### Changes - Add shift, alt, meta, and accel key indicators using `useValue` with the InputsManager's reactive getter methods - Move the panel from a side panel layout to a `TopPanel` component inside the canvas UI, fixing the issue where the panel was below the fold and hidden - Fix modifier key state getting stuck on macOS by immediately clearing state on explicit keyup events for Shift, Alt, and Meta keys - Remove the `Ctrl` badge since `getCtrlKey()` is normalized to `e.metaKey || e.ctrlKey` (redundant with Accel) ### Change type - [x] `other` ### Test plan 1. Run `yarn dev` and open the "Reactive inputs" example 2. Verify the inputs panel renders in the top zone of the canvas 3. Press modifier keys (Shift, Alt, Cmd/Meta) and verify they light up 4. Release modifier keys and verify they immediately clear (no sticking) 5. Verify the "Accel" badge follows Cmd on Mac and Ctrl elsewhere ### Release notes - Add modifier key indicators (Shift, Alt, Meta, Accel) to the reactive inputs example. - Fix modifier key state getting stuck after key release on macOS. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Example-only UI changes that rewire how the panel is rendered and add a few new reactive subscriptions; no production logic or data handling is affected. > > **Overview** > Updates the Reactive Inputs example to render its panel inside the canvas UI by wiring `ReactiveInputsPanel` as a `TopPanel` via `components`, switching from storing the `editor` in local state to using `useEditor()`. > > Extends the panel to display reactive modifier key state (`Shift`, `Ctrl`, `Alt`, `Meta`, `Accel`) using `useValue`, and simplifies/compacts the coordinate and velocity readouts with a shared `formatNum` helper. > > Restyles the panel from a fixed side layout to a compact, wrap-friendly top bar and adds new styles for modifier key badges (including active-state styling). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6760056. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Closes #5613 When a custom shape has an `onClick` handler and is not yet selected, `PointingShape.onEnter` defers selection to pointer up (so that `onClick` can fire). However, if the user drags instead of clicking, the `Translating` state requires a selection to operate and immediately bails back to idle—making it impossible to drag unselected shapes that have an `onClick` handler. This PR fixes the issue by selecting the shape in `startTranslating` when the shape wasn't selected on enter and there is no existing selection. This ensures that dragging works correctly while preserving the existing behavior for shapes that are already selected or part of a multi-selection. https://github.com/user-attachments/assets/ff74b3c3-1c57-4810-8b9f-cf39213940bf ### Change type - [x] `bugfix` ### Test plan 1. Create a custom shape with an `onClick` handler 2. Make sure the shape is not selected 3. Attempt to drag the shape — it should translate as expected 4. Click (without dragging) — the `onClick` handler should still fire 5. Multi-select shapes and drag — existing behavior should be preserved - [x] Unit tests ### Release notes - Fix dragging unselected shapes that have an `onClick` handler. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches the `SelectTool` state machine to change when selection is applied during a drag, which could subtly affect selection/translation behavior in edge cases (e.g. grouped or multi-selected shapes). Covered by a new unit test, but still impacts core interaction logic. > > **Overview** > Fixes a selection/translation edge case where shapes with a `ShapeUtil.onClick` handler could not be dragged while unselected. > > `PointingShape.startTranslating` now ensures the hit shape is selected (only when it wasn’t selected on enter and there’s no existing selection) before transitioning to translating, preserving click-to-run-`onClick` behavior. > > Adds a regression unit test for dragging shapes with `onClick`, and introduces a new examples page (`shape-with-onClick`) demonstrating a clickable custom shape that increments a counter via `ShapeUtil.onClick`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c7f6206. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
omg ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: only adds a lint suppression for an intentionally deprecated API call and adjusts comment formatting, with no runtime behavior changes expected. > > **Overview** > Keeps backward compatibility for the deprecated `embeds` prop by explicitly suppressing the `@typescript-eslint/no-deprecated` warning before calling `EmbedShapeUtil.setEmbedDefinitions(embeds)`. > > Also applies a tiny formatting cleanup in the `embeds` prop JSDoc comment. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 71d460a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…mode (#7933) In order to fix a false positive "multiple instances" warning that fires in Next.js dev mode, this PR deduplicates registrations in `registerTldrawLibraryVersion()`. When Next.js re-evaluates modules on page refresh, each tldraw package re-registers itself via `registerTldrawLibraryVersion()`. Since `globalThis.__TLDRAW_LIBRARY_VERSIONS__` persists across module re-evaluations, duplicate entries accumulate and trigger the "multiple instances" warning — even though only one copy of each library is loaded (all entries show the same version and same module type). The fix skips registration when an identical entry (same name, version, and module type) already exists. Genuine conflicts (different versions or mixed ESM/CJS) are still detected correctly. Closes #4614 ### Change type - [x] `bugfix` ### Test plan 1. Use tldraw in a Next.js app with dev mode 2. Refresh the page — the false "multiple instances" warning should no longer appear 3. Genuine version mismatches or ESM/CJS conflicts should still produce warnings - [x] Unit tests ### Release notes - Fixed false positive "multiple instances" warning in Next.js dev mode caused by module re-evaluation <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small, well-scoped change to warning/dedup logic gated to Next.js dev mode with unit test coverage; main risk is inadvertently suppressing a real duplicate only under those conditions. > > **Overview** > Prevents false "multiple instances" warnings in Next.js *dev mode* by skipping re-registration when `registerTldrawLibraryVersion` sees an **exact duplicate** entry (same package, version, and module type) during Fast Refresh. > > Adds `isNextjsDev()` gating (checks `NODE_ENV === 'development'` and presence of `__NEXT_DATA__`) so duplicate tracking and warnings still occur in non-Next.js environments, and updates tests to cover both the Next.js dev dedupe behavior and the unchanged non-dev duplicate warning. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cc920c0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
update mcp app well-known token ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: only changes the static response body for the unauthenticated `/.well-known/openai-apps-challenge` endpoint, with no impact on auth or request handling logic. > > **Overview** > Updates the static token returned by the unauthenticated `/.well-known/openai-apps-challenge` route in `apps/mcp-app/src/worker.ts` for OpenAI app/domain verification. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5c6da77. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Summary - After 30 continuous seconds in debug mode, shows a toast prompting dotcom users to check out the tldraw SDK - Toast appears once (persisted via localStorage), dismisses automatically when debug mode is toggled off - Works for both signed-in and signed-out users ## Test plan - [ ] Sign out, enable debug mode, wait 30s — toast appears - [ ] Click "Get started" — opens tldraw.dev with UTM params - [ ] Toggle debug mode off — toast dismisses - [ ] Re-enable debug mode — toast does NOT reappear (localStorage flag set) - [ ] Clear `showDebugSdkToast` from localStorage, re-enable — toast reappears - [ ] Sign in, repeat above — works the same 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only changes (toast + menu item wiring) with minimal side effects beyond localStorage persistence and an external link/analytics event. > > **Overview** > Adds `SneakyDebugModeToast`, which watches `isDebugMode` and after a delay displays a persistent toast promoting the SDK; the toast click is tracked and opens `tldraw.dev` with UTM params, is dismissed when debug mode is turned off, and is shown only once via `localStorage`. > > Mounts this behavior in both the signed-in editor (`TlaEditor`) and the signed-out local editor page (`local.tsx`). Separately updates `DefaultMainMenuContent` / e2e menu fixture to remove the dedicated `ToggleDebugModeItem` from Preferences and instead render `toggle-debug-mode` via `TldrawUiMenuActionItem`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3aaa731. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Closes #8148 ## Summary - `npm create tldraw` now always creates a subdirectory from the project name instead of installing into the current directory - If a directory with that name already exists, appends `-1`, `-2`, etc. — never overwrites - Removes the `--overwrite` flag and "directory is not empty" prompt, since they're no longer needed This one change fixes both bugs from the issue: 1. **Files in wrong directory** — the name now determines the directory 2. **Ctrl+C writing files** — the prompt where this happened no longer exists ## Test plan - [ ] Run `cli.cjs` from a non-empty directory, type a name → verify files go into a new subdirectory - [ ] Run it again with the same name → verify it creates `<name>-1` instead of overwriting - [ ] Press Ctrl+C at any prompt → verify no files are created ### Change type - [ ] `bugfix` - [ ] `improvement` - [x] `feature` - [ ] `api` - [ ] `other` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Behavioral change to CLI output location and directory selection could affect existing user workflows/scripts, but it’s limited to project scaffolding and reduces risk of accidental overwrites. > > **Overview** > `create-tldraw` no longer scaffolds into the current directory or overwrites an existing target. It now derives a project directory from the provided/entered app name, and if that directory already exists it automatically picks the next available `-1`, `-2`, etc. suffix. > > This removes the `--overwrite` flag and the interactive “directory not empty” prompt/cleanup path, replaces it with `findAvailableDir`, and hardens `isDirEmpty` to treat non-directories as non-empty (with new unit tests covering file paths and `.git`-only dirs). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 846d76e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…8042) In order to make shapes dragged from the toolbar respect dynamic sizing (matching the behavior of click-to-create), this PR applies the same `scale` calculation to each toolbar `onDragStart` callback and centralizes the scale factor logic into a new `editor.getResizeScaleFactor()` method. When dynamic size mode is enabled, shapes created by clicking with a tool respect the zoom level via the `scale` prop, but shapes dragged out of the toolbar did not. This adds the same scaling to toolbar drag-create for geo, arrow, line, frame, text, and note tools, and refactors all Pointing states to use the shared helper. Closes #7998 ### Change type - [x] `bugfix` ### Test plan 1. Enable dynamic size mode in user preferences 2. Zoom in/out to a non-1x zoom level 3. Drag each shape type (geo, arrow, line, frame, text, note) out of the toolbar 4. Verify the created shapes appear at a consistent screen size regardless of zoom, matching the behavior of click-to-create - [ ] Unit tests - [ ] End to end tests ### API changes - Added `Editor.getResizeScaleFactor()` — returns `1 / zoomLevel` when dynamic sizing is enabled, `1` otherwise ### Release notes - Fix shapes dragged from the toolbar not respecting dynamic size mode --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
In order to provide a clear reference for z-order manipulation in the editor API, this PR adds a new example demonstrating all four reordering methods: `sendToBack`, `sendBackward`, `bringForward`, and `bringToFront`. The example creates overlapping colored shapes with button controls in a TopPanel so users can select shapes and visually see stacking order change. Includes comments covering relative order preservation, the `considerAllShapes` option, and automatic index management. Closes #7460 ### Change type - [x] `other` ### Test plan 1. Run `yarn dev`, navigate to the z-order example under editor-api 2. Verify four overlapping colored shapes are visible 3. Select a shape and test each of the four buttons — stacking order should visibly change 4. Select multiple shapes and verify they move as a group with relative order preserved - [ ] Unit tests - [ ] End to end tests ### Release notes - Add z-order manipulation example to editor-api examples <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Adds a self-contained examples-only demo with no changes to core editor behavior or data handling. > > **Overview** > Adds a new `editor-api/z-order` example that visually demonstrates z-order manipulation via `editor.sendToBack`, `sendBackward`, `bringForward`, and `bringToFront` on the current selection. > > The example auto-creates overlapping colored shapes on mount, provides TopPanel buttons to trigger each reorder action, and includes brief documentation/CSS for discoverability and layout. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 736bdbe. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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 : )