tldraw 3.16.0-canary.a2491e00987a → 3.16.0-canary.a531b80e1ddf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist-cjs/index.d.ts +3 -1
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +4 -4
  4. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  5. package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
  6. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  7. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  8. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  9. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  10. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  11. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +68 -91
  12. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  13. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  14. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +0 -10
  15. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  16. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +1 -18
  17. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  18. package/dist-cjs/lib/ui/hooks/useTools.js +21 -3
  19. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  20. package/dist-cjs/lib/ui/version.js +3 -3
  21. package/dist-cjs/lib/ui/version.js.map +1 -1
  22. package/dist-esm/index.d.mts +3 -1
  23. package/dist-esm/index.mjs +1 -1
  24. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +4 -4
  25. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  26. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +1 -1
  27. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  28. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  29. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  30. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  31. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  32. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +77 -93
  33. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  34. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  35. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +0 -10
  36. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  37. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +1 -18
  38. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  39. package/dist-esm/lib/ui/hooks/useTools.mjs +22 -3
  40. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  41. package/dist-esm/lib/ui/version.mjs +3 -3
  42. package/dist-esm/lib/ui/version.mjs.map +1 -1
  43. package/package.json +3 -3
  44. package/src/lib/shapes/frame/FrameShapeUtil.tsx +12 -4
  45. package/src/lib/shapes/shared/ShapeFill.tsx +1 -1
  46. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  47. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  48. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +98 -114
  49. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  50. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +0 -10
  51. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +2 -16
  52. package/src/lib/ui/hooks/useTools.tsx +25 -3
  53. package/src/lib/ui/version.ts +3 -3
  54. package/src/lib/ui.css +5 -6
  55. package/src/test/EraserTool.test.ts +176 -6
  56. package/tldraw.css +5 -6
@@ -3,6 +3,7 @@ import {
3
3
  assertExists,
4
4
  createShapeId,
5
5
  GeoShapeGeoStyle,
6
+ getIndicesBetween,
6
7
  toRichText,
7
8
  useMaybeEditor
8
9
  } from "@tldraw/editor";
@@ -93,7 +94,7 @@ function ToolsProvider({ overrides, children }) {
93
94
  },
94
95
  onDragStart(source, info) {
95
96
  onDragFromToolbarToCreateShape(editor, info, {
96
- createShape: (id) => editor.createShape({ id, type: "geo", props: { geo } })
97
+ createShape: (id) => editor.createShape({ id, type: "geo", props: { w: 200, h: 200, geo } })
97
98
  });
98
99
  trackEvent("drag-tool", { source, id: "geo" });
99
100
  }
@@ -126,6 +127,24 @@ function ToolsProvider({ overrides, children }) {
126
127
  onSelect(source) {
127
128
  editor.setCurrentTool("line");
128
129
  onToolSelect(source, this);
130
+ },
131
+ onDragStart(source, info) {
132
+ onDragFromToolbarToCreateShape(editor, info, {
133
+ createShape: (id) => {
134
+ const [start, end] = getIndicesBetween(null, null, 2);
135
+ editor.createShape({
136
+ id,
137
+ type: "line",
138
+ props: {
139
+ points: {
140
+ [start]: { id: start, index: start, x: 0, y: 200 },
141
+ [end]: { id: end, index: end, x: 200, y: 0 }
142
+ }
143
+ }
144
+ });
145
+ }
146
+ });
147
+ trackEvent("drag-tool", { source, id: "line" });
129
148
  }
130
149
  },
131
150
  {
@@ -157,8 +176,8 @@ function ToolsProvider({ overrides, children }) {
157
176
  onDragFromToolbarToCreateShape(editor, info, {
158
177
  createShape: (id) => editor.createShape({ id, type: "text", props: { richText: toRichText("Text") } }),
159
178
  onDragEnd: (id) => {
160
- editor.emit("select-all-text", { shapeId: id });
161
179
  editor.setEditingShape(id);
180
+ editor.emit("select-all-text", { shapeId: id });
162
181
  }
163
182
  });
164
183
  trackEvent("drag-tool", { source, id: "text" });
@@ -187,8 +206,8 @@ function ToolsProvider({ overrides, children }) {
187
206
  onDragFromToolbarToCreateShape(editor, info, {
188
207
  createShape: (id) => editor.createShape({ id, type: "note" }),
189
208
  onDragEnd: (id) => {
190
- editor.emit("select-all-text", { shapeId: id });
191
209
  editor.setEditingShape(id);
210
+ editor.emit("select-all-text", { shapeId: id });
192
211
  }
193
212
  });
194
213
  trackEvent("drag-tool", { source, id: "note" });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/ui/hooks/useTools.tsx"],
4
- "sourcesContent": ["import {\n\tassertExists,\n\tcreateShapeId,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\ttoRichText,\n\tuseMaybeEditor,\n} from '@tldraw/editor'\nimport * as React from 'react'\nimport { EmbedDialog } from '../components/EmbedDialog'\nimport { TLUiIconJsx } from '../components/primitives/TldrawUiIcon'\nimport { useA11y } from '../context/a11y'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { TLUiIconType } from '../icon-types'\nimport { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'\nimport { TLUiTranslationKey } from './useTranslation/TLUiTranslationKey'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport interface TLUiToolItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\tlabel: TranslationKey\n\tshortcutsLabel?: TranslationKey\n\ticon: IconType | TLUiIconJsx\n\tonSelect(source: TLUiEventSource): void\n\tonDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void\n\t/**\n\t * The keyboard shortcut for this tool. This is a string that can be a single key,\n\t * or a combination of keys.\n\t * For example, `cmd+z` or `cmd+shift+z` or `cmd+u,ctrl+u`, or just `v` or `a`.\n\t * We have backwards compatibility with the old system, where we used to use\n\t * symbols to denote cmd/alt/shift, using `!` for shift, `$` for cmd, and `?` for alt.\n\t */\n\tkbd?: string\n\treadonlyOk?: boolean\n\tmeta?: {\n\t\t[key: string]: any\n\t}\n}\n\n/** @public */\nexport type TLUiToolsContextType = Record<string, TLUiToolItem>\n\n/** @internal */\nexport const ToolsContext = React.createContext<null | TLUiToolsContextType>(null)\n\n/** @public */\nexport interface TLUiToolsProviderProps {\n\toverrides?(\n\t\teditor: Editor,\n\t\ttools: TLUiToolsContextType,\n\t\thelpers: Partial<TLUiOverrideHelpers>\n\t): TLUiToolsContextType\n\tchildren: React.ReactNode\n}\n\n/** @internal */\nexport function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst a11y = useA11y()\n\tconst msg = useTranslation()\n\tconst helpers = useDefaultHelpers()\n\n\tconst onToolSelect = React.useCallback(\n\t\t(\n\t\t\tsource: TLUiEventSource,\n\t\t\ttool: TLUiToolItem<TLUiTranslationKey, TLUiIconType>,\n\t\t\tid?: string\n\t\t) => {\n\t\t\ta11y.announce({ msg: msg(tool.label) })\n\t\t\ttrackEvent('select-tool', { source, id: id ?? tool.id })\n\t\t},\n\t\t[a11y, msg, trackEvent]\n\t)\n\n\tconst tools = React.useMemo<TLUiToolsContextType>(() => {\n\t\tif (!editor) return {}\n\t\tconst toolsArray: TLUiToolItem<TLUiTranslationKey, TLUiIconType>[] = [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: 'tool.select',\n\t\t\t\ticon: 'tool-pointer',\n\t\t\t\tkbd: 'v',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\tif (editor.isIn('select')) {\n\t\t\t\t\t\t// There's a quirk of select mode, where editing a shape is a sub-state of select.\n\t\t\t\t\t\t// Because the text tool can be locked/sticky, we need to make sure we exit the\n\t\t\t\t\t\t// text tool.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// psst, if you're changing this code, also change the code\n\t\t\t\t\t\t// in strange-tools.test.ts! Sadly it's duplicated there.\n\t\t\t\t\t\tconst currentNode = editor.root.getCurrent()!\n\t\t\t\t\t\tcurrentNode.exit({}, currentNode.id)\n\t\t\t\t\t\tcurrentNode.enter({}, currentNode.id)\n\t\t\t\t\t}\n\t\t\t\t\teditor.setCurrentTool('select')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'hand',\n\t\t\t\tlabel: 'tool.hand',\n\t\t\t\ticon: 'tool-hand',\n\t\t\t\tkbd: 'h',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('hand')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'eraser',\n\t\t\t\tlabel: 'tool.eraser',\n\t\t\t\ticon: 'tool-eraser',\n\t\t\t\tkbd: 'e',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('eraser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'draw',\n\t\t\t\tlabel: 'tool.draw',\n\t\t\t\ticon: 'tool-pencil',\n\t\t\t\tkbd: 'd,b,x',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('draw')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t...[...GeoShapeGeoStyle.values].map((geo) => ({\n\t\t\t\tid: geo,\n\t\t\t\tlabel: `tool.${geo}` as TLUiTranslationKey,\n\t\t\t\tmeta: {\n\t\t\t\t\tgeo,\n\t\t\t\t},\n\t\t\t\tkbd: geo === 'rectangle' ? 'r' : geo === 'ellipse' ? 'o' : undefined,\n\t\t\t\ticon: ('geo-' + geo) as TLUiIconType,\n\t\t\t\tonSelect(source: TLUiEventSource) {\n\t\t\t\t\teditor.run(() => {\n\t\t\t\t\t\teditor.setStyleForNextShapes(GeoShapeGeoStyle, geo)\n\t\t\t\t\t\teditor.setCurrentTool('geo')\n\t\t\t\t\t\tonToolSelect(source, this, `geo-${geo}`)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'geo', props: { geo } }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'geo' })\n\t\t\t\t},\n\t\t\t})),\n\t\t\t{\n\t\t\t\tid: 'arrow',\n\t\t\t\tlabel: 'tool.arrow',\n\t\t\t\ticon: 'tool-arrow',\n\t\t\t\tkbd: 'a',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('arrow')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\t\tprops: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'arrow' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'line',\n\t\t\t\tlabel: 'tool.line',\n\t\t\t\ticon: 'tool-line',\n\t\t\t\tkbd: 'l',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('line')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'frame',\n\t\t\t\tlabel: 'tool.frame',\n\t\t\t\ticon: 'tool-frame',\n\t\t\t\tkbd: 'f',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('frame')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'frame' }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'frame' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'text',\n\t\t\t\tlabel: 'tool.text',\n\t\t\t\ticon: 'tool-text',\n\t\t\t\tkbd: 't',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('text')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'text', props: { richText: toRichText('Text') } }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'text' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'asset',\n\t\t\t\tlabel: 'tool.media',\n\t\t\t\ticon: 'tool-media',\n\t\t\t\tkbd: 'cmd+u,ctrl+u',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.insertMedia()\n\t\t\t\t\tonToolSelect(source, this, 'media')\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'note',\n\t\t\t\tlabel: 'tool.note',\n\t\t\t\ticon: 'tool-note',\n\t\t\t\tkbd: 'n',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('note')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'note' }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'note' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'laser',\n\t\t\t\tlabel: 'tool.laser',\n\t\t\t\treadonlyOk: true,\n\t\t\t\ticon: 'tool-laser',\n\t\t\t\tkbd: 'k',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('laser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'embed',\n\t\t\t\tlabel: 'tool.embed',\n\t\t\t\ticon: 'dot',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.addDialog({ component: EmbedDialog })\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'highlight',\n\t\t\t\tlabel: 'tool.highlight',\n\t\t\t\ticon: 'tool-highlight',\n\t\t\t\t// TODO: pick a better shortcut\n\t\t\t\tkbd: 'shift+d',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('highlight')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t]\n\n\t\ttoolsArray.forEach((t) => (t.onSelect = t.onSelect.bind(t)))\n\n\t\tconst tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))\n\n\t\tif (overrides) {\n\t\t\treturn overrides(editor, tools, helpers)\n\t\t}\n\n\t\treturn tools\n\t}, [overrides, editor, helpers, onToolSelect, trackEvent])\n\n\treturn <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>\n}\n\n/** @public */\nexport function useTools() {\n\tconst ctx = React.useContext(ToolsContext)\n\n\tif (!ctx) {\n\t\tthrow new Error('useTools must be used within a ToolProvider')\n\t}\n\n\treturn ctx\n}\n\n/**\n * Options for {@link onDragFromToolbarToCreateShape}.\n * @public\n */\nexport interface OnDragFromToolbarToCreateShapesOpts {\n\t/**\n\t * Create the shape being dragged. You don't need to worry about positioning it, as it'll be\n\t * immediately updated with the correct position.\n\t */\n\tcreateShape(id: TLShapeId): void\n\t/**\n\t * Called once the drag interaction has finished.\n\t */\n\tonDragEnd?(id: TLShapeId): void\n}\n\n/**\n * A helper method to use in {@link TLUiToolItem#onDragStart} to create a shape by dragging it from\n * the toolbar.\n * @public\n */\nexport function onDragFromToolbarToCreateShape(\n\teditor: Editor,\n\tinfo: TLPointerEventInfo,\n\topts: OnDragFromToolbarToCreateShapesOpts\n) {\n\tconst { x, y } = editor.inputs.currentPagePoint\n\n\tconst stoppingPoint = editor.markHistoryStoppingPoint('drag shape tool')\n\teditor.setCurrentTool('select.translating')\n\n\tconst id = createShapeId()\n\topts.createShape(id)\n\tconst shape = assertExists(editor.getShape(id), 'Shape not found')\n\n\tconst { w, h } = editor.getShapePageBounds(id)!\n\teditor.updateShape({ id, type: shape.type, x: x - w / 2, y: y - h / 2 })\n\teditor.select(id)\n\n\teditor.setCurrentTool('select.translating', {\n\t\t...info,\n\t\ttarget: 'shape',\n\t\tshape: editor.getShape(id),\n\t\tisCreating: true,\n\t\tcreatingMarkId: stoppingPoint,\n\t\tonCreate() {\n\t\t\teditor.setCurrentTool('select.idle')\n\t\t\teditor.select(id)\n\t\t\topts.onDragEnd?.(id)\n\t\t},\n\t})\n\teditor.getCurrentTool().setCurrentToolIdMask(shape.type)\n}\n"],
5
- "mappings": "AA8SQ;AA9SR;AAAA,EACC;AAAA,EACA;AAAA,EAEA;AAAA,EAGA;AAAA,EACA;AAAA,OACM;AACP,YAAY,WAAW;AACvB,SAAS,mBAAmB;AAE5B,SAAS,eAAe;AACxB,SAA0B,mBAAmB;AAE7C,SAA8B,yBAAyB;AAEvD,SAAS,sBAAsB;AA+BxB,MAAM,eAAe,MAAM,cAA2C,IAAI;AAa1E,SAAS,cAAc,EAAE,WAAW,SAAS,GAA2B;AAC9E,QAAM,SAAS,eAAe;AAC9B,QAAM,aAAa,YAAY;AAE/B,QAAM,OAAO,QAAQ;AACrB,QAAM,MAAM,eAAe;AAC3B,QAAM,UAAU,kBAAkB;AAElC,QAAM,eAAe,MAAM;AAAA,IAC1B,CACC,QACA,MACA,OACI;AACJ,WAAK,SAAS,EAAE,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC;AACtC,iBAAW,eAAe,EAAE,QAAQ,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,IACxD;AAAA,IACA,CAAC,MAAM,KAAK,UAAU;AAAA,EACvB;AAEA,QAAM,QAAQ,MAAM,QAA8B,MAAM;AACvD,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,UAAM,aAA+D;AAAA,MACpE;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,YAAY;AAAA,QACZ,SAAS,QAAQ;AAChB,cAAI,OAAO,KAAK,QAAQ,GAAG;AAO1B,kBAAM,cAAc,OAAO,KAAK,WAAW;AAC3C,wBAAY,KAAK,CAAC,GAAG,YAAY,EAAE;AACnC,wBAAY,MAAM,CAAC,GAAG,YAAY,EAAE;AAAA,UACrC;AACA,iBAAO,eAAe,QAAQ;AAC9B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,YAAY;AAAA,QACZ,SAAS,QAAQ;AAChB,iBAAO,eAAe,MAAM;AAC5B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,QAAQ;AAC9B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,MAAM;AAC5B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA,GAAG,CAAC,GAAG,iBAAiB,MAAM,EAAE,IAAI,CAAC,SAAS;AAAA,QAC7C,IAAI;AAAA,QACJ,OAAO,QAAQ,GAAG;AAAA,QAClB,MAAM;AAAA,UACL;AAAA,QACD;AAAA,QACA,KAAK,QAAQ,cAAc,MAAM,QAAQ,YAAY,MAAM;AAAA,QAC3D,MAAO,SAAS;AAAA,QAChB,SAAS,QAAyB;AACjC,iBAAO,IAAI,MAAM;AAChB,mBAAO,sBAAsB,kBAAkB,GAAG;AAClD,mBAAO,eAAe,KAAK;AAC3B,yBAAa,QAAQ,MAAM,OAAO,GAAG,EAAE;AAAA,UACxC,CAAC;AAAA,QACF;AAAA,QACA,YAAY,QAAyB,MAA0B;AAC9D,yCAA+B,QAAQ,MAAM;AAAA,YAC5C,aAAa,CAAC,OAAO,OAAO,YAAY,EAAE,IAAI,MAAM,OAAO,OAAO,EAAE,IAAI,EAAE,CAAC;AAAA,UAC5E,CAAC;AACD,qBAAW,aAAa,EAAE,QAAQ,IAAI,MAAM,CAAC;AAAA,QAC9C;AAAA,MACD,EAAE;AAAA,MACF;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,OAAO;AAC7B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,QACA,YAAY,QAAyB,MAA0B;AAC9D,yCAA+B,QAAQ,MAAM;AAAA,YAC5C,aAAa,CAAC,OACb,OAAO,YAAY;AAAA,cAClB;AAAA,cACA,MAAM;AAAA,cACN,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,GAAG,EAAE,EAAE;AAAA,YACvD,CAAC;AAAA,UACH,CAAC;AACD,qBAAW,aAAa,EAAE,QAAQ,IAAI,QAAQ,CAAC;AAAA,QAChD;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,MAAM;AAC5B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,OAAO;AAC7B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,QACA,YAAY,QAAQ,MAAM;AACzB,yCAA+B,QAAQ,MAAM;AAAA,YAC5C,aAAa,CAAC,OAAO,OAAO,YAAY,EAAE,IAAI,MAAM,QAAQ,CAAC;AAAA,UAC9D,CAAC;AACD,qBAAW,aAAa,EAAE,QAAQ,IAAI,QAAQ,CAAC;AAAA,QAChD;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,MAAM;AAC5B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,QACA,YAAY,QAAQ,MAAM;AACzB,yCAA+B,QAAQ,MAAM;AAAA,YAC5C,aAAa,CAAC,OACb,OAAO,YAAY,EAAE,IAAI,MAAM,QAAQ,OAAO,EAAE,UAAU,WAAW,MAAM,EAAE,EAAE,CAAC;AAAA,YACjF,WAAW,CAAC,OAAO;AAClB,qBAAO,KAAK,mBAAmB,EAAE,SAAS,GAAG,CAAC;AAC9C,qBAAO,gBAAgB,EAAE;AAAA,YAC1B;AAAA,UACD,CAAC;AACD,qBAAW,aAAa,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,QAC/C;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,kBAAQ,YAAY;AACpB,uBAAa,QAAQ,MAAM,OAAO;AAAA,QACnC;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,MAAM;AAC5B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,QACA,YAAY,QAAQ,MAAM;AACzB,yCAA+B,QAAQ,MAAM;AAAA,YAC5C,aAAa,CAAC,OAAO,OAAO,YAAY,EAAE,IAAI,MAAM,OAAO,CAAC;AAAA,YAC5D,WAAW,CAAC,OAAO;AAClB,qBAAO,KAAK,mBAAmB,EAAE,SAAS,GAAG,CAAC;AAC9C,qBAAO,gBAAgB,EAAE;AAAA,YAC1B;AAAA,UACD,CAAC;AACD,qBAAW,aAAa,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,QAC/C;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,MAAM;AAAA,QACN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,OAAO;AAC7B,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,QAAQ;AAChB,kBAAQ,UAAU,EAAE,WAAW,YAAY,CAAC;AAC5C,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA;AAAA,QAEN,KAAK;AAAA,QACL,SAAS,QAAQ;AAChB,iBAAO,eAAe,WAAW;AACjC,uBAAa,QAAQ,IAAI;AAAA,QAC1B;AAAA,MACD;AAAA,IACD;AAEA,eAAW,QAAQ,CAAC,MAAO,EAAE,WAAW,EAAE,SAAS,KAAK,CAAC,CAAE;AAE3D,UAAMA,SAAQ,OAAO,YAAY,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEjE,QAAI,WAAW;AACd,aAAO,UAAU,QAAQA,QAAO,OAAO;AAAA,IACxC;AAEA,WAAOA;AAAA,EACR,GAAG,CAAC,WAAW,QAAQ,SAAS,cAAc,UAAU,CAAC;AAEzD,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS;AACvD;AAGO,SAAS,WAAW;AAC1B,QAAM,MAAM,MAAM,WAAW,YAAY;AAEzC,MAAI,CAAC,KAAK;AACT,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC9D;AAEA,SAAO;AACR;AAuBO,SAAS,+BACf,QACA,MACA,MACC;AACD,QAAM,EAAE,GAAG,EAAE,IAAI,OAAO,OAAO;AAE/B,QAAM,gBAAgB,OAAO,yBAAyB,iBAAiB;AACvE,SAAO,eAAe,oBAAoB;AAE1C,QAAM,KAAK,cAAc;AACzB,OAAK,YAAY,EAAE;AACnB,QAAM,QAAQ,aAAa,OAAO,SAAS,EAAE,GAAG,iBAAiB;AAEjE,QAAM,EAAE,GAAG,EAAE,IAAI,OAAO,mBAAmB,EAAE;AAC7C,SAAO,YAAY,EAAE,IAAI,MAAM,MAAM,MAAM,GAAG,IAAI,IAAI,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;AACvE,SAAO,OAAO,EAAE;AAEhB,SAAO,eAAe,sBAAsB;AAAA,IAC3C,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,OAAO,OAAO,SAAS,EAAE;AAAA,IACzB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,WAAW;AACV,aAAO,eAAe,aAAa;AACnC,aAAO,OAAO,EAAE;AAChB,WAAK,YAAY,EAAE;AAAA,IACpB;AAAA,EACD,CAAC;AACD,SAAO,eAAe,EAAE,qBAAqB,MAAM,IAAI;AACxD;",
4
+ "sourcesContent": ["import {\n\tassertExists,\n\tcreateShapeId,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tgetIndicesBetween,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\ttoRichText,\n\tuseMaybeEditor,\n} from '@tldraw/editor'\nimport * as React from 'react'\nimport { EmbedDialog } from '../components/EmbedDialog'\nimport { TLUiIconJsx } from '../components/primitives/TldrawUiIcon'\nimport { useA11y } from '../context/a11y'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { TLUiIconType } from '../icon-types'\nimport { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'\nimport { TLUiTranslationKey } from './useTranslation/TLUiTranslationKey'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport interface TLUiToolItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\tlabel: TranslationKey\n\tshortcutsLabel?: TranslationKey\n\ticon: IconType | TLUiIconJsx\n\tonSelect(source: TLUiEventSource): void\n\tonDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void\n\t/**\n\t * The keyboard shortcut for this tool. This is a string that can be a single key,\n\t * or a combination of keys.\n\t * For example, `cmd+z` or `cmd+shift+z` or `cmd+u,ctrl+u`, or just `v` or `a`.\n\t * We have backwards compatibility with the old system, where we used to use\n\t * symbols to denote cmd/alt/shift, using `!` for shift, `$` for cmd, and `?` for alt.\n\t */\n\tkbd?: string\n\treadonlyOk?: boolean\n\tmeta?: {\n\t\t[key: string]: any\n\t}\n}\n\n/** @public */\nexport type TLUiToolsContextType = Record<string, TLUiToolItem>\n\n/** @internal */\nexport const ToolsContext = React.createContext<null | TLUiToolsContextType>(null)\n\n/** @public */\nexport interface TLUiToolsProviderProps {\n\toverrides?(\n\t\teditor: Editor,\n\t\ttools: TLUiToolsContextType,\n\t\thelpers: Partial<TLUiOverrideHelpers>\n\t): TLUiToolsContextType\n\tchildren: React.ReactNode\n}\n\n/** @internal */\nexport function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst a11y = useA11y()\n\tconst msg = useTranslation()\n\tconst helpers = useDefaultHelpers()\n\n\tconst onToolSelect = React.useCallback(\n\t\t(\n\t\t\tsource: TLUiEventSource,\n\t\t\ttool: TLUiToolItem<TLUiTranslationKey, TLUiIconType>,\n\t\t\tid?: string\n\t\t) => {\n\t\t\ta11y.announce({ msg: msg(tool.label) })\n\t\t\ttrackEvent('select-tool', { source, id: id ?? tool.id })\n\t\t},\n\t\t[a11y, msg, trackEvent]\n\t)\n\n\tconst tools = React.useMemo<TLUiToolsContextType>(() => {\n\t\tif (!editor) return {}\n\t\tconst toolsArray: TLUiToolItem<TLUiTranslationKey, TLUiIconType>[] = [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: 'tool.select',\n\t\t\t\ticon: 'tool-pointer',\n\t\t\t\tkbd: 'v',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\tif (editor.isIn('select')) {\n\t\t\t\t\t\t// There's a quirk of select mode, where editing a shape is a sub-state of select.\n\t\t\t\t\t\t// Because the text tool can be locked/sticky, we need to make sure we exit the\n\t\t\t\t\t\t// text tool.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// psst, if you're changing this code, also change the code\n\t\t\t\t\t\t// in strange-tools.test.ts! Sadly it's duplicated there.\n\t\t\t\t\t\tconst currentNode = editor.root.getCurrent()!\n\t\t\t\t\t\tcurrentNode.exit({}, currentNode.id)\n\t\t\t\t\t\tcurrentNode.enter({}, currentNode.id)\n\t\t\t\t\t}\n\t\t\t\t\teditor.setCurrentTool('select')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'hand',\n\t\t\t\tlabel: 'tool.hand',\n\t\t\t\ticon: 'tool-hand',\n\t\t\t\tkbd: 'h',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('hand')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'eraser',\n\t\t\t\tlabel: 'tool.eraser',\n\t\t\t\ticon: 'tool-eraser',\n\t\t\t\tkbd: 'e',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('eraser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'draw',\n\t\t\t\tlabel: 'tool.draw',\n\t\t\t\ticon: 'tool-pencil',\n\t\t\t\tkbd: 'd,b,x',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('draw')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t...[...GeoShapeGeoStyle.values].map((geo) => ({\n\t\t\t\tid: geo,\n\t\t\t\tlabel: `tool.${geo}` as TLUiTranslationKey,\n\t\t\t\tmeta: {\n\t\t\t\t\tgeo,\n\t\t\t\t},\n\t\t\t\tkbd: geo === 'rectangle' ? 'r' : geo === 'ellipse' ? 'o' : undefined,\n\t\t\t\ticon: ('geo-' + geo) as TLUiIconType,\n\t\t\t\tonSelect(source: TLUiEventSource) {\n\t\t\t\t\teditor.run(() => {\n\t\t\t\t\t\teditor.setStyleForNextShapes(GeoShapeGeoStyle, geo)\n\t\t\t\t\t\teditor.setCurrentTool('geo')\n\t\t\t\t\t\tonToolSelect(source, this, `geo-${geo}`)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'geo', props: { w: 200, h: 200, geo } }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'geo' })\n\t\t\t\t},\n\t\t\t})),\n\t\t\t{\n\t\t\t\tid: 'arrow',\n\t\t\t\tlabel: 'tool.arrow',\n\t\t\t\ticon: 'tool-arrow',\n\t\t\t\tkbd: 'a',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('arrow')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\t\tprops: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'arrow' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'line',\n\t\t\t\tlabel: 'tool.line',\n\t\t\t\ticon: 'tool-line',\n\t\t\t\tkbd: 'l',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('line')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => {\n\t\t\t\t\t\t\tconst [start, end] = getIndicesBetween(null, null, 2)\n\t\t\t\t\t\t\teditor.createShape<TLLineShape>({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'line',\n\t\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\t\tpoints: {\n\t\t\t\t\t\t\t\t\t\t[start]: { id: start, index: start, x: 0, y: 200 },\n\t\t\t\t\t\t\t\t\t\t[end]: { id: end, index: end, x: 200, y: 0 },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'line' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'frame',\n\t\t\t\tlabel: 'tool.frame',\n\t\t\t\ticon: 'tool-frame',\n\t\t\t\tkbd: 'f',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('frame')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'frame' }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'frame' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'text',\n\t\t\t\tlabel: 'tool.text',\n\t\t\t\ticon: 'tool-text',\n\t\t\t\tkbd: 't',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('text')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'text', props: { richText: toRichText('Text') } }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'text' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'asset',\n\t\t\t\tlabel: 'tool.media',\n\t\t\t\ticon: 'tool-media',\n\t\t\t\tkbd: 'cmd+u,ctrl+u',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.insertMedia()\n\t\t\t\t\tonToolSelect(source, this, 'media')\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'note',\n\t\t\t\tlabel: 'tool.note',\n\t\t\t\ticon: 'tool-note',\n\t\t\t\tkbd: 'n',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('note')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'note' }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'note' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'laser',\n\t\t\t\tlabel: 'tool.laser',\n\t\t\t\treadonlyOk: true,\n\t\t\t\ticon: 'tool-laser',\n\t\t\t\tkbd: 'k',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('laser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'embed',\n\t\t\t\tlabel: 'tool.embed',\n\t\t\t\ticon: 'dot',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.addDialog({ component: EmbedDialog })\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'highlight',\n\t\t\t\tlabel: 'tool.highlight',\n\t\t\t\ticon: 'tool-highlight',\n\t\t\t\t// TODO: pick a better shortcut\n\t\t\t\tkbd: 'shift+d',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('highlight')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t]\n\n\t\ttoolsArray.forEach((t) => (t.onSelect = t.onSelect.bind(t)))\n\n\t\tconst tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))\n\n\t\tif (overrides) {\n\t\t\treturn overrides(editor, tools, helpers)\n\t\t}\n\n\t\treturn tools\n\t}, [overrides, editor, helpers, onToolSelect, trackEvent])\n\n\treturn <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>\n}\n\n/** @public */\nexport function useTools() {\n\tconst ctx = React.useContext(ToolsContext)\n\n\tif (!ctx) {\n\t\tthrow new Error('useTools must be used within a ToolProvider')\n\t}\n\n\treturn ctx\n}\n\n/**\n * Options for {@link onDragFromToolbarToCreateShape}.\n * @public\n */\nexport interface OnDragFromToolbarToCreateShapesOpts {\n\t/**\n\t * Create the shape being dragged. You don't need to worry about positioning it, as it'll be\n\t * immediately updated with the correct position.\n\t */\n\tcreateShape(id: TLShapeId): void\n\t/**\n\t * Called once the drag interaction has finished.\n\t */\n\tonDragEnd?(id: TLShapeId): void\n}\n\n/**\n * A helper method to use in {@link TLUiToolItem#onDragStart} to create a shape by dragging it from\n * the toolbar.\n * @public\n */\nexport function onDragFromToolbarToCreateShape(\n\teditor: Editor,\n\tinfo: TLPointerEventInfo,\n\topts: OnDragFromToolbarToCreateShapesOpts\n) {\n\tconst { x, y } = editor.inputs.currentPagePoint\n\n\tconst stoppingPoint = editor.markHistoryStoppingPoint('drag shape tool')\n\teditor.setCurrentTool('select.translating')\n\n\tconst id = createShapeId()\n\topts.createShape(id)\n\tconst shape = assertExists(editor.getShape(id), 'Shape not found')\n\n\tconst { w, h } = editor.getShapePageBounds(id)!\n\teditor.updateShape({ id, type: shape.type, x: x - w / 2, y: y - h / 2 })\n\teditor.select(id)\n\n\teditor.setCurrentTool('select.translating', {\n\t\t...info,\n\t\ttarget: 'shape',\n\t\tshape: editor.getShape(id),\n\t\tisCreating: true,\n\t\tcreatingMarkId: stoppingPoint,\n\t\tonCreate() {\n\t\t\teditor.setCurrentTool('select.idle')\n\t\t\teditor.select(id)\n\t\t\topts.onDragEnd?.(id)\n\t\t},\n\t})\n\n\teditor.getCurrentTool().setCurrentToolIdMask(shape.type)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["tools"]
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "3.16.0-canary.a2491e00987a";
1
+ const version = "3.16.0-canary.a531b80e1ddf";
2
2
  const publishDates = {
3
3
  major: "2024-09-13T14:36:29.063Z",
4
- minor: "2025-08-12T12:23:37.583Z",
5
- patch: "2025-08-12T12:23:37.583Z"
4
+ minor: "2025-08-14T14:05:39.476Z",
5
+ patch: "2025-08-14T14:05:39.476Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/ui/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.16.0-canary.a2491e00987a'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-08-12T12:23:37.583Z',\n\tpatch: '2025-08-12T12:23:37.583Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.16.0-canary.a531b80e1ddf'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-08-14T14:05:39.476Z',\n\tpatch: '2025-08-14T14:05:39.476Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tldraw",
3
3
  "description": "A tiny little drawing editor.",
4
- "version": "3.16.0-canary.a2491e00987a",
4
+ "version": "3.16.0-canary.a531b80e1ddf",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -54,8 +54,8 @@
54
54
  "@tiptap/pm": "^2.9.1",
55
55
  "@tiptap/react": "^2.9.1",
56
56
  "@tiptap/starter-kit": "^2.9.1",
57
- "@tldraw/editor": "3.16.0-canary.a2491e00987a",
58
- "@tldraw/store": "3.16.0-canary.a2491e00987a",
57
+ "@tldraw/editor": "3.16.0-canary.a531b80e1ddf",
58
+ "@tldraw/store": "3.16.0-canary.a531b80e1ddf",
59
59
  "classnames": "^2.5.1",
60
60
  "hotkeys-js": "^3.13.9",
61
61
  "idb": "^7.1.1",
@@ -224,8 +224,12 @@ export class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {
224
224
  const colorToUse = showFrameColors ? shape.props.color : 'black'
225
225
  const frameFill = getColorValue(theme, colorToUse, 'frameFill')
226
226
  const frameStroke = getColorValue(theme, colorToUse, 'frameStroke')
227
- const frameHeadingStroke = getColorValue(theme, colorToUse, 'frameHeadingStroke')
228
- const frameHeadingFill = getColorValue(theme, colorToUse, 'frameHeadingFill')
227
+ const frameHeadingStroke = showFrameColors
228
+ ? getColorValue(theme, colorToUse, 'frameHeadingStroke')
229
+ : theme.background
230
+ const frameHeadingFill = showFrameColors
231
+ ? getColorValue(theme, colorToUse, 'frameHeadingFill')
232
+ : theme.background
229
233
  const frameHeadingText = getColorValue(theme, colorToUse, 'frameText')
230
234
 
231
235
  return (
@@ -280,8 +284,12 @@ export class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {
280
284
  const colorToUse = showFrameColors ? shape.props.color : 'black'
281
285
  const frameFill = getColorValue(theme, colorToUse, 'frameFill')
282
286
  const frameStroke = getColorValue(theme, colorToUse, 'frameStroke')
283
- const frameHeadingStroke = getColorValue(theme, colorToUse, 'frameHeadingStroke')
284
- const frameHeadingFill = getColorValue(theme, colorToUse, 'frameHeadingFill')
287
+ const frameHeadingStroke = showFrameColors
288
+ ? getColorValue(theme, colorToUse, 'frameHeadingStroke')
289
+ : theme.background
290
+ const frameHeadingFill = showFrameColors
291
+ ? getColorValue(theme, colorToUse, 'frameHeadingFill')
292
+ : theme.background
285
293
  const frameHeadingText = getColorValue(theme, colorToUse, 'frameText')
286
294
 
287
295
  return (
@@ -33,7 +33,7 @@ export const ShapeFill = React.memo(function ShapeFill({
33
33
  return <path fill={getColorValue(theme, color, 'semi')} d={d} />
34
34
  }
35
35
  case 'semi': {
36
- return <path fill={getColorValue(theme, color, 'solid')} d={d} />
36
+ return <path fill={theme.solid} d={d} />
37
37
  }
38
38
  case 'fill': {
39
39
  return <path fill={getColorValue(theme, color, 'fill')} d={d} />
@@ -4,6 +4,7 @@ import {
4
4
  TLGroupShape,
5
5
  TLPointerEventInfo,
6
6
  TLShapeId,
7
+ isAccelKey,
7
8
  pointInPolygon,
8
9
  } from '@tldraw/editor'
9
10
 
@@ -15,7 +16,15 @@ export class Erasing extends StateNode {
15
16
  private markId = ''
16
17
  private excludedShapeIds = new Set<TLShapeId>()
17
18
 
19
+ _isHoldingAccelKey = false
20
+ _firstErasingShapeId: TLShapeId | null = null
21
+ _erasingShapeIds: TLShapeId[] = []
22
+
18
23
  override onEnter(info: TLPointerEventInfo) {
24
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
25
+ this._firstErasingShapeId = this.editor.getErasingShapeIds()[0] // the first one should be the first one we hit... is it?
26
+ this._erasingShapeIds = this.editor.getErasingShapeIds()
27
+
19
28
  this.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')
20
29
  this.info = info
21
30
 
@@ -76,6 +85,16 @@ export class Erasing extends StateNode {
76
85
  this.complete()
77
86
  }
78
87
 
88
+ override onKeyUp() {
89
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
90
+ this.update()
91
+ }
92
+
93
+ override onKeyDown() {
94
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
95
+ this.update()
96
+ }
97
+
79
98
  update() {
80
99
  const { editor, excludedShapeIds } = this
81
100
  const erasingShapeIds = editor.getErasingShapeIds()
@@ -87,6 +106,7 @@ export class Erasing extends StateNode {
87
106
 
88
107
  this.pushPointToScribble()
89
108
 
109
+ // Otherwise, erasing shapes are all the shapes that were hit before plus any new shapes that are hit
90
110
  const erasing = new Set<TLShapeId>(erasingShapeIds)
91
111
  const minDist = this.editor.options.hitTestMargin / zoomLevel
92
112
 
@@ -121,18 +141,31 @@ export class Erasing extends StateNode {
121
141
  if (geometry.hitTestLineSegment(A, B, minDist)) {
122
142
  erasing.add(editor.getOutermostSelectableShape(shape).id)
123
143
  }
144
+
145
+ this._erasingShapeIds = [...erasing]
146
+ }
147
+
148
+ // If the user is holding the meta / ctrl key, we should only erase the first shape we hit
149
+ if (this._isHoldingAccelKey && this._firstErasingShapeId) {
150
+ const erasingShapeId = this._firstErasingShapeId
151
+ if (erasingShapeId && this.editor.getShape(erasingShapeId)) {
152
+ editor.setErasingShapes([erasingShapeId])
153
+ }
154
+ return
124
155
  }
125
156
 
126
157
  // Remove the hit shapes, except if they're in the list of excluded shapes
127
158
  // (these excluded shapes will be any frames or groups the pointer was inside of
128
159
  // when the user started erasing)
129
- this.editor.setErasingShapes([...erasing].filter((id) => !excludedShapeIds.has(id)))
160
+ this.editor.setErasingShapes(this._erasingShapeIds.filter((id) => !excludedShapeIds.has(id)))
130
161
  }
131
162
 
132
163
  complete() {
133
164
  const { editor } = this
134
165
  editor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)
135
166
  this.parent.transition('idle')
167
+ this._erasingShapeIds = []
168
+ this._firstErasingShapeId = null
136
169
  }
137
170
 
138
171
  cancel() {
@@ -1,4 +1,5 @@
1
1
  import {
2
+ isAccelKey,
2
3
  StateNode,
3
4
  TLFrameShape,
4
5
  TLGroupShape,
@@ -9,7 +10,11 @@ import {
9
10
  export class Pointing extends StateNode {
10
11
  static override id = 'pointing'
11
12
 
13
+ _isHoldingAccelKey = false
14
+
12
15
  override onEnter() {
16
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
17
+
13
18
  const zoomLevel = this.editor.getZoomLevel()
14
19
  const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()
15
20
  const {
@@ -45,12 +50,25 @@ export class Pointing extends StateNode {
45
50
  }
46
51
 
47
52
  erasing.add(hitShape.id)
53
+
54
+ // If the user is holding the meta / ctrl key, stop after the first shape
55
+ if (this._isHoldingAccelKey) {
56
+ break
57
+ }
48
58
  }
49
59
  }
50
60
 
51
61
  this.editor.setErasingShapes([...erasing])
52
62
  }
53
63
 
64
+ override onKeyUp() {
65
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
66
+ }
67
+
68
+ override onKeyDown() {
69
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
70
+ }
71
+
54
72
  override onLongPress(info: TLPointerEventInfo) {
55
73
  this.startErasing(info)
56
74
  }
@@ -62,6 +80,8 @@ export class Pointing extends StateNode {
62
80
  }
63
81
 
64
82
  override onPointerMove(info: TLPointerEventInfo) {
83
+ if (this._isHoldingAccelKey) return
84
+
65
85
  if (this.editor.inputs.isDragging) {
66
86
  this.startErasing(info)
67
87
  }