@tldraw/editor 3.11.0-canary.de52f4d709d2 → 3.11.0-canary.e999671f7c64

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 (36) hide show
  1. package/dist-cjs/index.d.ts +8 -8
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/config/TLUserPreferences.js +1 -1
  4. package/dist-cjs/lib/config/TLUserPreferences.js.map +1 -1
  5. package/dist-cjs/lib/editor/Editor.js +11 -9
  6. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  7. package/dist-cjs/lib/editor/managers/FocusManager.js +15 -0
  8. package/dist-cjs/lib/editor/managers/FocusManager.js.map +2 -2
  9. package/dist-cjs/lib/editor/managers/UserPreferencesManager.js +1 -1
  10. package/dist-cjs/lib/editor/managers/UserPreferencesManager.js.map +2 -2
  11. package/dist-cjs/lib/license/Watermark.js +5 -0
  12. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  13. package/dist-cjs/version.js +3 -3
  14. package/dist-cjs/version.js.map +1 -1
  15. package/dist-esm/index.d.mts +8 -8
  16. package/dist-esm/index.mjs +1 -1
  17. package/dist-esm/lib/config/TLUserPreferences.mjs +1 -1
  18. package/dist-esm/lib/config/TLUserPreferences.mjs.map +1 -1
  19. package/dist-esm/lib/editor/Editor.mjs +11 -9
  20. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  21. package/dist-esm/lib/editor/managers/FocusManager.mjs +15 -0
  22. package/dist-esm/lib/editor/managers/FocusManager.mjs.map +2 -2
  23. package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs +1 -1
  24. package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs.map +2 -2
  25. package/dist-esm/lib/license/Watermark.mjs +5 -0
  26. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  27. package/dist-esm/version.mjs +3 -3
  28. package/dist-esm/version.mjs.map +1 -1
  29. package/editor.css +1 -1
  30. package/package.json +7 -7
  31. package/src/lib/config/TLUserPreferences.ts +1 -1
  32. package/src/lib/editor/Editor.ts +13 -10
  33. package/src/lib/editor/managers/FocusManager.ts +18 -0
  34. package/src/lib/editor/managers/UserPreferencesManager.ts +1 -1
  35. package/src/lib/license/Watermark.tsx +5 -0
  36. package/src/version.ts +3 -3
@@ -14,6 +14,8 @@ class FocusManager {
14
14
  editor.updateInstanceState({ isFocused: !!autoFocus });
15
15
  }
16
16
  this.updateContainerClass();
17
+ document.body.addEventListener("keydown", this.handleKeyDown.bind(this));
18
+ document.body.addEventListener("mousedown", this.handleMouseDown.bind(this));
17
19
  }
18
20
  disposeSideEffectListener;
19
21
  /**
@@ -33,6 +35,17 @@ class FocusManager {
33
35
  } else {
34
36
  container.classList.remove("tl-container__focused");
35
37
  }
38
+ container.classList.add("tl-container__no-focus-ring");
39
+ }
40
+ handleKeyDown(keyEvent) {
41
+ const container = this.editor.getContainer();
42
+ if (keyEvent.key === "Tab") {
43
+ container.classList.remove("tl-container__no-focus-ring");
44
+ }
45
+ }
46
+ handleMouseDown() {
47
+ const container = this.editor.getContainer();
48
+ container.classList.add("tl-container__no-focus-ring");
36
49
  }
37
50
  focus() {
38
51
  this.editor.getContainer().focus();
@@ -42,6 +55,8 @@ class FocusManager {
42
55
  this.editor.getContainer().blur();
43
56
  }
44
57
  dispose() {
58
+ document.body.removeEventListener("keydown", this.handleKeyDown.bind(this));
59
+ document.body.removeEventListener("mousedown", this.handleMouseDown.bind(this));
45
60
  this.disposeSideEffectListener?.();
46
61
  }
47
62
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/managers/FocusManager.ts"],
4
- "sourcesContent": ["import type { Editor } from '../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur() {\n\t\tthis.editor.complete() // stop any interaction\n\t\tthis.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
- "mappings": "AAWO,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAGP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAAA,EAC3B;AAAA,EApBQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BA,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AAAA,EACD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,OAAO;AACN,SAAK,OAAO,SAAS;AACrB,SAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,UAAU;AACT,SAAK,4BAA4B;AAAA,EAClC;AACD;",
4
+ "sourcesContent": ["import type { Editor } from '../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\n\t\tdocument.body.addEventListener('keydown', this.handleKeyDown.bind(this))\n\t\tdocument.body.addEventListener('mousedown', this.handleMouseDown.bind(this))\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tprivate handleKeyDown(keyEvent: KeyboardEvent) {\n\t\tconst container = this.editor.getContainer()\n\t\tif (keyEvent.key === 'Tab') {\n\t\t\tcontainer.classList.remove('tl-container__no-focus-ring')\n\t\t}\n\t}\n\n\tprivate handleMouseDown() {\n\t\tconst container = this.editor.getContainer()\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur() {\n\t\tthis.editor.complete() // stop any interaction\n\t\tthis.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tdocument.body.removeEventListener('keydown', this.handleKeyDown.bind(this))\n\t\tdocument.body.removeEventListener('mousedown', this.handleMouseDown.bind(this))\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
+ "mappings": "AAWO,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAGP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAE1B,aAAS,KAAK,iBAAiB,WAAW,KAAK,cAAc,KAAK,IAAI,CAAC;AACvE,aAAS,KAAK,iBAAiB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAAA,EAC5E;AAAA,EAvBQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkCA,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AACA,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEQ,cAAc,UAAyB;AAC9C,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,QAAI,SAAS,QAAQ,OAAO;AAC3B,gBAAU,UAAU,OAAO,6BAA6B;AAAA,IACzD;AAAA,EACD;AAAA,EAEQ,kBAAkB;AACzB,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,OAAO;AACN,SAAK,OAAO,SAAS;AACrB,SAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,UAAU;AACT,aAAS,KAAK,oBAAoB,WAAW,KAAK,cAAc,KAAK,IAAI,CAAC;AAC1E,aAAS,KAAK,oBAAoB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAC9E,SAAK,4BAA4B;AAAA,EAClC;AACD;",
6
6
  "names": []
7
7
  }
@@ -117,7 +117,7 @@ class UserPreferencesManager {
117
117
  return this.user.userPreferences.get().id;
118
118
  }
119
119
  getName() {
120
- return this.user.userPreferences.get().name ?? defaultUserPreferences.name;
120
+ return this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name;
121
121
  }
122
122
  getLocale() {
123
123
  return this.user.userPreferences.get().locale ?? defaultUserPreferences.locale;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/managers/UserPreferencesManager.ts"],
4
- "sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../config/TLUserPreferences'\nimport { TLUser } from '../../config/createTLUser'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !('matchMedia' in window)) return\n\n\t\tconst darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tif (darkModeMediaQuery?.matches) {\n\t\t\tthis.systemColorScheme.set('dark')\n\t\t}\n\t\tconst handleChange = (e: MediaQueryListEvent) => {\n\t\t\tif (e.matches) {\n\t\t\t\tthis.systemColorScheme.set('dark')\n\t\t\t} else {\n\t\t\t\tthis.systemColorScheme.set('light')\n\t\t\t}\n\t\t}\n\t\tdarkModeMediaQuery?.addEventListener('change', handleChange)\n\t\tthis.disposables.add(() => darkModeMediaQuery?.removeEventListener('change', handleChange))\n\t}\n\n\tupdateUserPreferences(userPreferences: Partial<TLUserPreferences>) {\n\t\tthis.user.setUserPreferences({\n\t\t\t...this.user.userPreferences.get(),\n\t\t\t...userPreferences,\n\t\t})\n\t}\n\t@computed getUserPreferences() {\n\t\treturn {\n\t\t\tid: this.getId(),\n\t\t\tname: this.getName(),\n\t\t\tlocale: this.getLocale(),\n\t\t\tcolor: this.getColor(),\n\t\t\tanimationSpeed: this.getAnimationSpeed(),\n\t\t\tisSnapMode: this.getIsSnapMode(),\n\t\t\tcolorScheme: this.user.userPreferences.get().colorScheme,\n\t\t\tisDarkMode: this.getIsDarkMode(),\n\t\t\tisWrapMode: this.getIsWrapMode(),\n\t\t\tisDynamicResizeMode: this.getIsDynamicResizeMode(),\n\t\t}\n\t}\n\n\t@computed getIsDarkMode() {\n\t\tswitch (this.user.userPreferences.get().colorScheme) {\n\t\t\tcase 'dark':\n\t\t\t\treturn true\n\t\t\tcase 'light':\n\t\t\t\treturn false\n\t\t\tcase 'system':\n\t\t\t\treturn this.systemColorScheme.get() === 'dark'\n\t\t\tdefault:\n\t\t\t\treturn this.inferDarkMode ? this.systemColorScheme.get() === 'dark' : false\n\t\t}\n\t}\n\n\t/**\n\t * The speed at which the user can scroll by dragging toward the edge of the screen.\n\t */\n\t@computed getEdgeScrollSpeed() {\n\t\treturn this.user.userPreferences.get().edgeScrollSpeed ?? defaultUserPreferences.edgeScrollSpeed\n\t}\n\n\t@computed getAnimationSpeed() {\n\t\treturn this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed\n\t}\n\n\t@computed getId() {\n\t\treturn this.user.userPreferences.get().id\n\t}\n\n\t@computed getName() {\n\t\treturn this.user.userPreferences.get().name ?? defaultUserPreferences.name\n\t}\n\n\t@computed getLocale() {\n\t\treturn this.user.userPreferences.get().locale ?? defaultUserPreferences.locale\n\t}\n\n\t@computed getColor() {\n\t\treturn this.user.userPreferences.get().color ?? defaultUserPreferences.color\n\t}\n\n\t@computed getIsSnapMode() {\n\t\treturn this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode\n\t}\n\n\t@computed getIsWrapMode() {\n\t\treturn this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode\n\t}\n\n\t@computed getIsDynamicResizeMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isDynamicSizeMode ?? defaultUserPreferences.isDynamicSizeMode\n\t\t)\n\t}\n\n\t@computed getIsPasteAtCursorMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isPasteAtCursorMode ??\n\t\t\tdefaultUserPreferences.isPasteAtCursorMode\n\t\t)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../config/TLUserPreferences'\nimport { TLUser } from '../../config/createTLUser'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !('matchMedia' in window)) return\n\n\t\tconst darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tif (darkModeMediaQuery?.matches) {\n\t\t\tthis.systemColorScheme.set('dark')\n\t\t}\n\t\tconst handleChange = (e: MediaQueryListEvent) => {\n\t\t\tif (e.matches) {\n\t\t\t\tthis.systemColorScheme.set('dark')\n\t\t\t} else {\n\t\t\t\tthis.systemColorScheme.set('light')\n\t\t\t}\n\t\t}\n\t\tdarkModeMediaQuery?.addEventListener('change', handleChange)\n\t\tthis.disposables.add(() => darkModeMediaQuery?.removeEventListener('change', handleChange))\n\t}\n\n\tupdateUserPreferences(userPreferences: Partial<TLUserPreferences>) {\n\t\tthis.user.setUserPreferences({\n\t\t\t...this.user.userPreferences.get(),\n\t\t\t...userPreferences,\n\t\t})\n\t}\n\t@computed getUserPreferences() {\n\t\treturn {\n\t\t\tid: this.getId(),\n\t\t\tname: this.getName(),\n\t\t\tlocale: this.getLocale(),\n\t\t\tcolor: this.getColor(),\n\t\t\tanimationSpeed: this.getAnimationSpeed(),\n\t\t\tisSnapMode: this.getIsSnapMode(),\n\t\t\tcolorScheme: this.user.userPreferences.get().colorScheme,\n\t\t\tisDarkMode: this.getIsDarkMode(),\n\t\t\tisWrapMode: this.getIsWrapMode(),\n\t\t\tisDynamicResizeMode: this.getIsDynamicResizeMode(),\n\t\t}\n\t}\n\n\t@computed getIsDarkMode() {\n\t\tswitch (this.user.userPreferences.get().colorScheme) {\n\t\t\tcase 'dark':\n\t\t\t\treturn true\n\t\t\tcase 'light':\n\t\t\t\treturn false\n\t\t\tcase 'system':\n\t\t\t\treturn this.systemColorScheme.get() === 'dark'\n\t\t\tdefault:\n\t\t\t\treturn this.inferDarkMode ? this.systemColorScheme.get() === 'dark' : false\n\t\t}\n\t}\n\n\t/**\n\t * The speed at which the user can scroll by dragging toward the edge of the screen.\n\t */\n\t@computed getEdgeScrollSpeed() {\n\t\treturn this.user.userPreferences.get().edgeScrollSpeed ?? defaultUserPreferences.edgeScrollSpeed\n\t}\n\n\t@computed getAnimationSpeed() {\n\t\treturn this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed\n\t}\n\n\t@computed getId() {\n\t\treturn this.user.userPreferences.get().id\n\t}\n\n\t@computed getName() {\n\t\treturn this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name\n\t}\n\n\t@computed getLocale() {\n\t\treturn this.user.userPreferences.get().locale ?? defaultUserPreferences.locale\n\t}\n\n\t@computed getColor() {\n\t\treturn this.user.userPreferences.get().color ?? defaultUserPreferences.color\n\t}\n\n\t@computed getIsSnapMode() {\n\t\treturn this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode\n\t}\n\n\t@computed getIsWrapMode() {\n\t\treturn this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode\n\t}\n\n\t@computed getIsDynamicResizeMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isDynamicSizeMode ?? defaultUserPreferences.isDynamicSizeMode\n\t\t)\n\t}\n\n\t@computed getIsPasteAtCursorMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isPasteAtCursorMode ??\n\t\t\tdefaultUserPreferences.isPasteAtCursorMode\n\t\t)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -146,8 +146,13 @@ To remove the watermark, please purchase a license at tldraw.dev.
146
146
  animation: delayed_link 0.2s forwards ease-in-out;
147
147
  animation-delay: 0.32s;
148
148
  }
149
+
150
+ .${className} > a:focus-visible {
151
+ opacity: 1;
152
+ }
149
153
  }
150
154
 
155
+
151
156
  @keyframes delayed_link {
152
157
  0% {
153
158
  cursor: inherit;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/Watermark.tsx"],
4
- "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { memo, useRef } from 'react'\nimport { tlenv } from '../globals/environment'\nimport { useCanvasEvents } from '../hooks/useCanvasEvents'\nimport { useEditor } from '../hooks/useEditor'\nimport { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'\nimport { preventDefault, stopEventPropagation } from '../utils/dom'\nimport { runtime } from '../utils/runtime'\nimport { watermarkDesktopSvg, watermarkMobileSvg } from '../watermarks'\nimport { LicenseManager } from './LicenseManager'\nimport { useLicenseContext } from './LicenseProvider'\nimport { useLicenseManagerState } from './useLicenseManagerState'\n\nconst WATERMARK_DESKTOP_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkDesktopSvg)}`\nconst WATERMARK_MOBILE_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkMobileSvg)}`\n\n/** @internal */\nexport const Watermark = memo(function Watermark() {\n\tconst licenseManager = useLicenseContext()\n\tconst editor = useEditor()\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\n\tconst licenseManagerState = useLicenseManagerState(licenseManager)\n\n\tif (!['licensed-with-watermark', 'unlicensed'].includes(licenseManagerState)) return null\n\n\treturn (\n\t\t<>\n\t\t\t<LicenseStyles />\n\t\t\t<WatermarkInner src={isMobile ? WATERMARK_MOBILE_LOCAL_SRC : WATERMARK_DESKTOP_LOCAL_SRC} />\n\t\t</>\n\t)\n})\n\nconst WatermarkInner = memo(function WatermarkInner({ src }: { src: string }) {\n\tconst editor = useEditor()\n\tconst isDebugMode = useValue('debug mode', () => editor.getInstanceState().isDebugMode, [editor])\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\tconst events = useCanvasEvents()\n\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\tconst maskCss = `url('${src}') center 100% / 100% no-repeat`\n\tconst url = 'https://tldraw.dev/?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={LicenseManager.className}\n\t\t\tdata-debug={isDebugMode}\n\t\t\tdata-mobile={isMobile}\n\t\t\tdraggable={false}\n\t\t\t{...events}\n\t\t>\n\t\t\t{tlenv.isWebview ? (\n\t\t\t\t<a\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\trole=\"button\"\n\t\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}}\n\t\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<a\n\t\t\t\t\thref={url}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</div>\n\t)\n})\n\nconst LicenseStyles = memo(function LicenseStyles() {\n\tconst editor = useEditor()\n\tconst className = LicenseManager.className\n\n\tconst CSS = `/* ------------------- SEE LICENSE -------------------\nThe tldraw watermark is part of tldraw's license. It is shown for unlicensed\nor \"licensed-with-watermark\" users. By using this library, you agree to\npreserve the watermark's behavior, keeping it visible, unobscured, and\navailable to user-interaction.\n\nTo remove the watermark, please purchase a license at tldraw.dev.\n*/\n\n\t.${className} {\n\t\tposition: absolute;\n\t\tbottom: var(--space-2);\n\t\tright: var(--space-2);\n\t\twidth: 96px;\n\t\theight: 32px;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tz-index: var(--layer-watermark) !important;\n\t\tbackground-color: color-mix(in srgb, var(--color-background) 62%, transparent);\n\t\topacity: 1;\n\t\tborder-radius: 5px;\n\t\tpointer-events: all;\n\t\tpadding: 2px;\n\t\tbox-sizing: content-box;\n\t}\n\n\t.${className} > a {\n\t\tposition: absolute;\n\t\twidth: 96px;\n\t\theight: 32px;\n\t\tpointer-events: all;\n\t\tcursor: inherit;\n\t\tcolor: var(--color-text);\n\t\topacity: .38;\n\t\tbackground-color: currentColor;\n\t}\n\n\t.${className}[data-debug='true'] {\n\t\tbottom: 46px;\n\t}\n\n\t.${className}[data-mobile='true'] {\n\t\tborder-radius: 4px 0px 0px 4px;\n\t\tright: -2px;\n\t\twidth: 8px;\n\t\theight: 48px;\n\t}\n\n\t.${className}[data-mobile='true'] > a {\n\t\twidth: 8px;\n\t\theight: 32px;\n\t}\n\n\t@media (hover: hover) {\n\t\t.${className} > a {\n\t\t\tpointer-events: none;\n\t\t}\n\n\t\t.${className}:hover {\n\t\t\tbackground-color: var(--color-background);\n\t\t\ttransition: background-color 0.2s ease-in-out;\n\t\t\ttransition-delay: 0.32s;\n\t\t}\n\n\t\t.${className}:hover > a {\n\t\t\tanimation: delayed_link 0.2s forwards ease-in-out;\n\t\t\tanimation-delay: 0.32s;\n\t\t}\n\t}\n\n\t@keyframes delayed_link {\n\t\t0% {\n\t\t\tcursor: inherit;\n\t\t\topacity: .38;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t100% {\n\t\t\tcursor: pointer;\n\t\t\topacity: 1;\n\t\t\tpointer-events: all;\n\t\t}\n\t}`\n\n\treturn <style nonce={editor.options.nonce}>{CSS}</style>\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { memo, useRef } from 'react'\nimport { tlenv } from '../globals/environment'\nimport { useCanvasEvents } from '../hooks/useCanvasEvents'\nimport { useEditor } from '../hooks/useEditor'\nimport { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'\nimport { preventDefault, stopEventPropagation } from '../utils/dom'\nimport { runtime } from '../utils/runtime'\nimport { watermarkDesktopSvg, watermarkMobileSvg } from '../watermarks'\nimport { LicenseManager } from './LicenseManager'\nimport { useLicenseContext } from './LicenseProvider'\nimport { useLicenseManagerState } from './useLicenseManagerState'\n\nconst WATERMARK_DESKTOP_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkDesktopSvg)}`\nconst WATERMARK_MOBILE_LOCAL_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(watermarkMobileSvg)}`\n\n/** @internal */\nexport const Watermark = memo(function Watermark() {\n\tconst licenseManager = useLicenseContext()\n\tconst editor = useEditor()\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\n\tconst licenseManagerState = useLicenseManagerState(licenseManager)\n\n\tif (!['licensed-with-watermark', 'unlicensed'].includes(licenseManagerState)) return null\n\n\treturn (\n\t\t<>\n\t\t\t<LicenseStyles />\n\t\t\t<WatermarkInner src={isMobile ? WATERMARK_MOBILE_LOCAL_SRC : WATERMARK_DESKTOP_LOCAL_SRC} />\n\t\t</>\n\t)\n})\n\nconst WatermarkInner = memo(function WatermarkInner({ src }: { src: string }) {\n\tconst editor = useEditor()\n\tconst isDebugMode = useValue('debug mode', () => editor.getInstanceState().isDebugMode, [editor])\n\tconst isMobile = useValue('is mobile', () => editor.getViewportScreenBounds().width < 700, [\n\t\teditor,\n\t])\n\tconst events = useCanvasEvents()\n\n\tconst ref = useRef<HTMLDivElement>(null)\n\tusePassThroughWheelEvents(ref)\n\n\tconst maskCss = `url('${src}') center 100% / 100% no-repeat`\n\tconst url = 'https://tldraw.dev/?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={LicenseManager.className}\n\t\t\tdata-debug={isDebugMode}\n\t\t\tdata-mobile={isMobile}\n\t\t\tdraggable={false}\n\t\t\t{...events}\n\t\t>\n\t\t\t{tlenv.isWebview ? (\n\t\t\t\t<a\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\trole=\"button\"\n\t\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}}\n\t\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<a\n\t\t\t\t\thref={url}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</div>\n\t)\n})\n\nconst LicenseStyles = memo(function LicenseStyles() {\n\tconst editor = useEditor()\n\tconst className = LicenseManager.className\n\n\tconst CSS = `/* ------------------- SEE LICENSE -------------------\nThe tldraw watermark is part of tldraw's license. It is shown for unlicensed\nor \"licensed-with-watermark\" users. By using this library, you agree to\npreserve the watermark's behavior, keeping it visible, unobscured, and\navailable to user-interaction.\n\nTo remove the watermark, please purchase a license at tldraw.dev.\n*/\n\n\t.${className} {\n\t\tposition: absolute;\n\t\tbottom: var(--space-2);\n\t\tright: var(--space-2);\n\t\twidth: 96px;\n\t\theight: 32px;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tz-index: var(--layer-watermark) !important;\n\t\tbackground-color: color-mix(in srgb, var(--color-background) 62%, transparent);\n\t\topacity: 1;\n\t\tborder-radius: 5px;\n\t\tpointer-events: all;\n\t\tpadding: 2px;\n\t\tbox-sizing: content-box;\n\t}\n\n\t.${className} > a {\n\t\tposition: absolute;\n\t\twidth: 96px;\n\t\theight: 32px;\n\t\tpointer-events: all;\n\t\tcursor: inherit;\n\t\tcolor: var(--color-text);\n\t\topacity: .38;\n\t\tbackground-color: currentColor;\n\t}\n\n\t.${className}[data-debug='true'] {\n\t\tbottom: 46px;\n\t}\n\n\t.${className}[data-mobile='true'] {\n\t\tborder-radius: 4px 0px 0px 4px;\n\t\tright: -2px;\n\t\twidth: 8px;\n\t\theight: 48px;\n\t}\n\n\t.${className}[data-mobile='true'] > a {\n\t\twidth: 8px;\n\t\theight: 32px;\n\t}\n\n\t@media (hover: hover) {\n\t\t.${className} > a {\n\t\t\tpointer-events: none;\n\t\t}\n\n\t\t.${className}:hover {\n\t\t\tbackground-color: var(--color-background);\n\t\t\ttransition: background-color 0.2s ease-in-out;\n\t\t\ttransition-delay: 0.32s;\n\t\t}\n\n\t\t.${className}:hover > a {\n\t\t\tanimation: delayed_link 0.2s forwards ease-in-out;\n\t\t\tanimation-delay: 0.32s;\n\t\t}\n\n\t\t.${className} > a:focus-visible {\n\t\t\topacity: 1;\n\t\t}\n\t}\n\n\n\t@keyframes delayed_link {\n\t\t0% {\n\t\t\tcursor: inherit;\n\t\t\topacity: .38;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t100% {\n\t\t\tcursor: pointer;\n\t\t\topacity: 1;\n\t\t\tpointer-events: all;\n\t\t}\n\t}`\n\n\treturn <style nonce={editor.options.nonce}>{CSS}</style>\n})\n"],
5
+ "mappings": "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",
6
6
  "names": ["Watermark", "WatermarkInner", "LicenseStyles"]
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "3.11.0-canary.de52f4d709d2";
1
+ const version = "3.11.0-canary.e999671f7c64";
2
2
  const publishDates = {
3
3
  major: "2024-09-13T14:36:29.063Z",
4
- minor: "2025-03-12T13:04:27.234Z",
5
- patch: "2025-03-12T13:04:27.234Z"
4
+ minor: "2025-03-15T12:23:31.016Z",
5
+ patch: "2025-03-15T12:23:31.016Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/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.11.0-canary.de52f4d709d2'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-12T13:04:27.234Z',\n\tpatch: '2025-03-12T13:04:27.234Z',\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.11.0-canary.e999671f7c64'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-15T12:23:31.016Z',\n\tpatch: '2025-03-15T12:23:31.016Z',\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/editor.css CHANGED
@@ -147,7 +147,7 @@
147
147
  --color-panel-contrast: hsl(0, 0%, 100%);
148
148
  --color-panel-overlay: hsl(0, 0%, 100%, 82%);
149
149
  --color-panel: hsl(0, 0%, 99%);
150
- --color-focus: hsl(214, 100%, 29%);
150
+ --color-focus: hsl(219, 65%, 50%);
151
151
  --color-selected: hsl(214, 84%, 56%);
152
152
  --color-selected-contrast: hsl(0, 0%, 100%);
153
153
  --color-selection-fill: hsl(210, 100%, 56%, 24%);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "A tiny little drawing app (editor).",
4
- "version": "3.11.0-canary.de52f4d709d2",
4
+ "version": "3.11.0-canary.e999671f7c64",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -48,12 +48,12 @@
48
48
  "@tiptap/core": "^2.9.1",
49
49
  "@tiptap/pm": "^2.9.1",
50
50
  "@tiptap/react": "^2.9.1",
51
- "@tldraw/state": "3.11.0-canary.de52f4d709d2",
52
- "@tldraw/state-react": "3.11.0-canary.de52f4d709d2",
53
- "@tldraw/store": "3.11.0-canary.de52f4d709d2",
54
- "@tldraw/tlschema": "3.11.0-canary.de52f4d709d2",
55
- "@tldraw/utils": "3.11.0-canary.de52f4d709d2",
56
- "@tldraw/validate": "3.11.0-canary.de52f4d709d2",
51
+ "@tldraw/state": "3.11.0-canary.e999671f7c64",
52
+ "@tldraw/state-react": "3.11.0-canary.e999671f7c64",
53
+ "@tldraw/store": "3.11.0-canary.e999671f7c64",
54
+ "@tldraw/tlschema": "3.11.0-canary.e999671f7c64",
55
+ "@tldraw/utils": "3.11.0-canary.e999671f7c64",
56
+ "@tldraw/validate": "3.11.0-canary.e999671f7c64",
57
57
  "@types/core-js": "^2.5.8",
58
58
  "@use-gesture/react": "^10.3.1",
59
59
  "classnames": "^2.5.1",
@@ -132,7 +132,7 @@ export function userPrefersReducedMotion() {
132
132
 
133
133
  /** @public */
134
134
  export const defaultUserPreferences = Object.freeze({
135
- name: 'New User',
135
+ name: '',
136
136
  locale: getDefaultTranslationLocale(),
137
137
  color: getRandomColor(),
138
138
 
@@ -6328,21 +6328,22 @@ export class Editor extends EventEmitter<TLEventMap> {
6328
6328
  *
6329
6329
  * @example
6330
6330
  * ```ts
6331
- * editor.stackShapes([box1, box2], 'horizontal', 32)
6332
- * editor.stackShapes(editor.getSelectedShapeIds(), 'horizontal', 32)
6331
+ * editor.stackShapes([box1, box2], 'horizontal')
6332
+ * editor.stackShapes(editor.getSelectedShapeIds(), 'horizontal')
6333
6333
  * ```
6334
6334
  *
6335
6335
  * @param shapes - The shapes (or shape ids) to stack.
6336
6336
  * @param operation - Whether to stack horizontally or vertically.
6337
- * @param gap - The gap to leave between shapes.
6337
+ * @param gap - The gap to leave between shapes. By default, uses the editor's `adjacentShapeMargin` option.
6338
6338
  *
6339
6339
  * @public
6340
6340
  */
6341
6341
  stackShapes(
6342
6342
  shapes: TLShapeId[] | TLShape[],
6343
6343
  operation: 'horizontal' | 'vertical',
6344
- gap: number
6344
+ gap?: number
6345
6345
  ): this {
6346
+ const _gap = gap ?? this.options.adjacentShapeMargin
6346
6347
  const ids =
6347
6348
  typeof shapes[0] === 'string'
6348
6349
  ? (shapes as TLShapeId[])
@@ -6400,7 +6401,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6400
6401
  }
6401
6402
 
6402
6403
  const len = shapeClustersToStack.length
6403
- if ((gap === 0 && len < 3) || len < 2) return this
6404
+ if ((_gap === 0 && len < 3) || len < 2) return this
6404
6405
 
6405
6406
  let val: 'x' | 'y'
6406
6407
  let min: 'minX' | 'minY'
@@ -6421,7 +6422,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6421
6422
 
6422
6423
  let shapeGap: number = 0
6423
6424
 
6424
- if (gap === 0) {
6425
+ if (_gap === 0) {
6425
6426
  // note: this is not used in the current tldraw.com; there we use a specified stack
6426
6427
 
6427
6428
  const gaps: Record<number, number> = {}
@@ -6461,7 +6462,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6461
6462
  }
6462
6463
  } else {
6463
6464
  // If a gap was provided, then use that instead.
6464
- shapeGap = gap
6465
+ shapeGap = _gap
6465
6466
  }
6466
6467
 
6467
6468
  const changes: TLShapePartial[] = []
@@ -6500,17 +6501,19 @@ export class Editor extends EventEmitter<TLEventMap> {
6500
6501
  *
6501
6502
  * @example
6502
6503
  * ```ts
6503
- * editor.packShapes([box1, box2], 32)
6504
+ * editor.packShapes([box1, box2])
6504
6505
  * editor.packShapes(editor.getSelectedShapeIds(), 32)
6505
6506
  * ```
6506
6507
  *
6507
6508
  *
6508
6509
  * @param shapes - The shapes (or shape ids) to pack.
6509
- * @param gap - The padding to apply to the packed shapes. Defaults to 16.
6510
+ * @param gap - The padding to apply to the packed shapes. Defaults to the editor's `adjacentShapeMargin` option.
6510
6511
  */
6511
- packShapes(shapes: TLShapeId[] | TLShape[], gap: number): this {
6512
+ packShapes(shapes: TLShapeId[] | TLShape[], _gap?: number): this {
6512
6513
  if (this.getIsReadonly()) return this
6513
6514
 
6515
+ const gap = _gap ?? this.options.adjacentShapeMargin
6516
+
6514
6517
  const ids =
6515
6518
  typeof shapes[0] === 'string'
6516
6519
  ? (shapes as TLShapeId[])
@@ -30,6 +30,9 @@ export class FocusManager {
30
30
  editor.updateInstanceState({ isFocused: !!autoFocus })
31
31
  }
32
32
  this.updateContainerClass()
33
+
34
+ document.body.addEventListener('keydown', this.handleKeyDown.bind(this))
35
+ document.body.addEventListener('mousedown', this.handleMouseDown.bind(this))
33
36
  }
34
37
 
35
38
  /**
@@ -50,6 +53,19 @@ export class FocusManager {
50
53
  } else {
51
54
  container.classList.remove('tl-container__focused')
52
55
  }
56
+ container.classList.add('tl-container__no-focus-ring')
57
+ }
58
+
59
+ private handleKeyDown(keyEvent: KeyboardEvent) {
60
+ const container = this.editor.getContainer()
61
+ if (keyEvent.key === 'Tab') {
62
+ container.classList.remove('tl-container__no-focus-ring')
63
+ }
64
+ }
65
+
66
+ private handleMouseDown() {
67
+ const container = this.editor.getContainer()
68
+ container.classList.add('tl-container__no-focus-ring')
53
69
  }
54
70
 
55
71
  focus() {
@@ -62,6 +78,8 @@ export class FocusManager {
62
78
  }
63
79
 
64
80
  dispose() {
81
+ document.body.removeEventListener('keydown', this.handleKeyDown.bind(this))
82
+ document.body.removeEventListener('mousedown', this.handleMouseDown.bind(this))
65
83
  this.disposeSideEffectListener?.()
66
84
  }
67
85
  }
@@ -80,7 +80,7 @@ export class UserPreferencesManager {
80
80
  }
81
81
 
82
82
  @computed getName() {
83
- return this.user.userPreferences.get().name ?? defaultUserPreferences.name
83
+ return this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name
84
84
  }
85
85
 
86
86
  @computed getLocale() {
@@ -157,8 +157,13 @@ To remove the watermark, please purchase a license at tldraw.dev.
157
157
  animation: delayed_link 0.2s forwards ease-in-out;
158
158
  animation-delay: 0.32s;
159
159
  }
160
+
161
+ .${className} > a:focus-visible {
162
+ opacity: 1;
163
+ }
160
164
  }
161
165
 
166
+
162
167
  @keyframes delayed_link {
163
168
  0% {
164
169
  cursor: inherit;
package/src/version.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '3.11.0-canary.de52f4d709d2'
4
+ export const version = '3.11.0-canary.e999671f7c64'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-03-12T13:04:27.234Z',
8
- patch: '2025-03-12T13:04:27.234Z',
7
+ minor: '2025-03-15T12:23:31.016Z',
8
+ patch: '2025-03-15T12:23:31.016Z',
9
9
  }