@tldraw/editor 3.16.0-next.df90ce0ff566 → 3.16.0-next.e57e478c23e0

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 (175) hide show
  1. package/dist-cjs/index.d.ts +134 -110
  2. package/dist-cjs/index.js +3 -5
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +8 -6
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +0 -5
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/Shape.js +7 -10
  9. package/dist-cjs/lib/components/Shape.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -23
  11. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
  13. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +1 -1
  14. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultScribble.js +1 -1
  17. package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
  18. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +9 -1
  19. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  20. package/dist-cjs/lib/config/TLUserPreferences.js +9 -3
  21. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  22. package/dist-cjs/lib/editor/Editor.js +77 -133
  23. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  24. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +9 -4
  25. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  26. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +13 -0
  27. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  28. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  29. package/dist-cjs/lib/exports/getSvgJsx.js +35 -16
  30. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  31. package/dist-cjs/lib/hooks/useCanvasEvents.js +31 -25
  32. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  33. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
  34. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  35. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -1
  36. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  37. package/dist-cjs/lib/{utils/nearestMultiple.js → hooks/useStateAttribute.js} +15 -14
  38. package/dist-cjs/lib/hooks/useStateAttribute.js.map +7 -0
  39. package/dist-cjs/lib/license/LicenseManager.js +17 -22
  40. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  41. package/dist-cjs/lib/license/LicenseProvider.js +5 -0
  42. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  43. package/dist-cjs/lib/license/Watermark.js +8 -8
  44. package/dist-cjs/lib/license/Watermark.js.map +1 -1
  45. package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
  46. package/dist-cjs/lib/options.js +7 -0
  47. package/dist-cjs/lib/options.js.map +2 -2
  48. package/dist-cjs/lib/primitives/Box.js +3 -0
  49. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  50. package/dist-cjs/lib/primitives/Vec.js +0 -4
  51. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  52. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +26 -18
  53. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  54. package/dist-cjs/lib/primitives/geometry/Group2d.js +3 -0
  55. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  56. package/dist-cjs/lib/utils/EditorAtom.js +45 -0
  57. package/dist-cjs/lib/utils/EditorAtom.js.map +7 -0
  58. package/dist-cjs/lib/utils/reparenting.js +2 -35
  59. package/dist-cjs/lib/utils/reparenting.js.map +3 -3
  60. package/dist-cjs/version.js +3 -3
  61. package/dist-cjs/version.js.map +1 -1
  62. package/dist-esm/index.d.mts +134 -110
  63. package/dist-esm/index.mjs +3 -5
  64. package/dist-esm/index.mjs.map +2 -2
  65. package/dist-esm/lib/TldrawEditor.mjs +8 -6
  66. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  67. package/dist-esm/lib/components/MenuClickCapture.mjs +0 -5
  68. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  69. package/dist-esm/lib/components/Shape.mjs +7 -10
  70. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  71. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +4 -23
  72. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  73. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
  74. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +1 -1
  75. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
  76. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  77. package/dist-esm/lib/components/default-components/DefaultScribble.mjs +1 -1
  78. package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
  79. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +9 -1
  80. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  81. package/dist-esm/lib/config/TLUserPreferences.mjs +9 -3
  82. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  83. package/dist-esm/lib/editor/Editor.mjs +77 -133
  84. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  85. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +9 -4
  86. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  87. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +13 -0
  88. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  89. package/dist-esm/lib/exports/getSvgJsx.mjs +36 -16
  90. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  91. package/dist-esm/lib/hooks/useCanvasEvents.mjs +32 -26
  92. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  93. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
  94. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  95. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -1
  96. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  97. package/dist-esm/lib/hooks/useStateAttribute.mjs +15 -0
  98. package/dist-esm/lib/hooks/useStateAttribute.mjs.map +7 -0
  99. package/dist-esm/lib/license/LicenseManager.mjs +17 -22
  100. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  101. package/dist-esm/lib/license/LicenseProvider.mjs +5 -0
  102. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  103. package/dist-esm/lib/license/Watermark.mjs +8 -8
  104. package/dist-esm/lib/license/Watermark.mjs.map +1 -1
  105. package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
  106. package/dist-esm/lib/options.mjs +7 -0
  107. package/dist-esm/lib/options.mjs.map +2 -2
  108. package/dist-esm/lib/primitives/Box.mjs +4 -1
  109. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  110. package/dist-esm/lib/primitives/Vec.mjs +0 -4
  111. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  112. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +29 -19
  113. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  114. package/dist-esm/lib/primitives/geometry/Group2d.mjs +3 -0
  115. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  116. package/dist-esm/lib/utils/EditorAtom.mjs +25 -0
  117. package/dist-esm/lib/utils/EditorAtom.mjs.map +7 -0
  118. package/dist-esm/lib/utils/reparenting.mjs +3 -40
  119. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  120. package/dist-esm/version.mjs +3 -3
  121. package/dist-esm/version.mjs.map +1 -1
  122. package/editor.css +301 -288
  123. package/package.json +14 -37
  124. package/src/index.ts +3 -9
  125. package/src/lib/TldrawEditor.tsx +13 -17
  126. package/src/lib/components/MenuClickCapture.tsx +0 -8
  127. package/src/lib/components/Shape.tsx +6 -12
  128. package/src/lib/components/default-components/DefaultCanvas.tsx +5 -22
  129. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
  130. package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
  131. package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
  132. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +5 -1
  133. package/src/lib/config/TLUserPreferences.ts +8 -1
  134. package/src/lib/editor/Editor.test.ts +12 -11
  135. package/src/lib/editor/Editor.ts +108 -193
  136. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +15 -14
  137. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +16 -15
  138. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +49 -48
  139. package/src/lib/editor/managers/FontManager/FontManager.test.ts +24 -23
  140. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +7 -6
  141. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +12 -11
  142. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +57 -50
  143. package/src/lib/editor/managers/TextManager/TextManager.test.ts +51 -26
  144. package/src/lib/editor/managers/TickManager/TickManager.test.ts +14 -13
  145. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +34 -26
  146. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +6 -1
  147. package/src/lib/editor/shapes/ShapeUtil.ts +35 -0
  148. package/src/lib/editor/types/misc-types.ts +54 -7
  149. package/src/lib/exports/getSvgJsx.test.ts +868 -0
  150. package/src/lib/exports/getSvgJsx.tsx +78 -21
  151. package/src/lib/hooks/useCanvasEvents.ts +45 -38
  152. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
  153. package/src/lib/hooks/usePassThroughWheelEvents.ts +6 -1
  154. package/src/lib/hooks/useStateAttribute.ts +15 -0
  155. package/src/lib/license/LicenseManager.test.ts +61 -52
  156. package/src/lib/license/LicenseManager.ts +32 -24
  157. package/src/lib/license/LicenseProvider.tsx +8 -0
  158. package/src/lib/license/Watermark.test.tsx +2 -1
  159. package/src/lib/license/Watermark.tsx +8 -8
  160. package/src/lib/license/useLicenseManagerState.ts +2 -2
  161. package/src/lib/options.ts +8 -0
  162. package/src/lib/primitives/Box.test.ts +126 -0
  163. package/src/lib/primitives/Box.ts +10 -1
  164. package/src/lib/primitives/Vec.ts +0 -5
  165. package/src/lib/primitives/geometry/Geometry2d.ts +49 -19
  166. package/src/lib/primitives/geometry/Group2d.ts +4 -0
  167. package/src/lib/utils/EditorAtom.ts +37 -0
  168. package/src/lib/utils/reparenting.ts +3 -69
  169. package/src/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
  170. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
  171. package/src/version.ts +3 -3
  172. package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
  173. package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
  174. package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
  175. package/src/lib/utils/nearestMultiple.ts +0 -13
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/useCanvasEvents.ts"],
4
- "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport React, { useMemo } from 'react'\nimport { RIGHT_MOUSE_BUTTON } from '../constants'\nimport {\n\tpreventDefault,\n\treleasePointerCapture,\n\tsetPointerCapture,\n\tstopEventPropagation,\n} from '../utils/dom'\nimport { getPointerInfo } from '../utils/getPointerInfo'\nimport { useEditor } from './useEditor'\n\nexport function useCanvasEvents() {\n\tconst editor = useEditor()\n\tconst currentTool = useValue('current tool', () => editor.getCurrentTool(), [editor])\n\n\tconst events = useMemo(\n\t\tfunction canvasEvents() {\n\t\t\t// Track the last screen point\n\t\t\tlet lastX: number, lastY: number\n\n\t\t\tfunction onPointerDown(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\n\t\t\t\tif (e.button === RIGHT_MOUSE_BUTTON) {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\tname: 'right_click',\n\t\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 5) return\n\n\t\t\t\tsetPointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_down',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerMove(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\n\t\t\t\tif (e.clientX === lastX && e.clientY === lastY) return\n\t\t\t\tlastX = e.clientX\n\t\t\t\tlastY = e.clientY\n\n\t\t\t\t// For tools that benefit from a higher fidelity of events,\n\t\t\t\t// we dispatch the coalesced events.\n\t\t\t\t// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.\n\t\t\t\tconst events =\n\t\t\t\t\tcurrentTool.useCoalescedEvents && e.nativeEvent.getCoalescedEvents\n\t\t\t\t\t\t? e.nativeEvent.getCoalescedEvents()\n\t\t\t\t\t\t: [e]\n\t\t\t\tfor (const singleEvent of events) {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\tname: 'pointer_move',\n\t\t\t\t\t\t...getPointerInfo(singleEvent),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onPointerUp(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return\n\t\t\t\tlastX = e.clientX\n\t\t\t\tlastY = e.clientY\n\n\t\t\t\treleasePointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_up',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerEnter(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })\n\t\t\t}\n\n\t\t\tfunction onPointerLeave(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })\n\t\t\t}\n\n\t\t\tfunction onTouchStart(e: React.TouchEvent) {\n\t\t\t\t;(e as any).isKilled = true\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tfunction onTouchEnd(e: React.TouchEvent) {\n\t\t\t\t;(e as any).isKilled = true\n\t\t\t\t// check that e.target is an HTMLElement\n\t\t\t\tif (!(e.target instanceof HTMLElement)) return\n\n\t\t\t\tif (\n\t\t\t\t\te.target.tagName !== 'A' &&\n\t\t\t\t\te.target.tagName !== 'TEXTAREA' &&\n\t\t\t\t\t!e.target.isContentEditable &&\n\t\t\t\t\t// When in EditingShape state, we are actually clicking on a 'DIV'\n\t\t\t\t\t// not A/TEXTAREA/contenteditable element yet. So, to preserve cursor position\n\t\t\t\t\t// for edit mode on mobile we need to not preventDefault.\n\t\t\t\t\t// TODO: Find out if we still need this preventDefault in general though.\n\t\t\t\t\t!(editor.getEditingShape() && e.target.className.includes('tl-text-content'))\n\t\t\t\t) {\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onDragOver(e: React.DragEvent<Element>) {\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tasync function onDrop(e: React.DragEvent<Element>) {\n\t\t\t\tpreventDefault(e)\n\t\t\t\tstopEventPropagation(e)\n\n\t\t\t\tif (e.dataTransfer?.files?.length) {\n\t\t\t\t\tconst files = Array.from(e.dataTransfer.files)\n\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'files',\n\t\t\t\t\t\tfiles,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst url = e.dataTransfer.getData('url')\n\t\t\t\tif (url) {\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'url',\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onClick(e: React.MouseEvent) {\n\t\t\t\tstopEventPropagation(e)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tonPointerDown,\n\t\t\t\tonPointerMove,\n\t\t\t\tonPointerUp,\n\t\t\t\tonPointerEnter,\n\t\t\t\tonPointerLeave,\n\t\t\t\tonDragOver,\n\t\t\t\tonDrop,\n\t\t\t\tonTouchStart,\n\t\t\t\tonTouchEnd,\n\t\t\t\tonClick,\n\t\t\t}\n\t\t},\n\t\t[editor, currentTool]\n\t)\n\n\treturn events\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAgB,eAAe;AAC/B,SAAS,0BAA0B;AACnC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,sBAAsB;AAC/B,SAAS,iBAAiB;AAEnB,SAAS,kBAAkB;AACjC,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,SAAS,gBAAgB,MAAM,OAAO,eAAe,GAAG,CAAC,MAAM,CAAC;AAEpF,QAAM,SAAS;AAAA,IACd,SAAS,eAAe;AAEvB,UAAI,OAAe;AAEnB,eAAS,cAAc,GAAuB;AAC7C,YAAK,EAAU,SAAU;AAEzB,YAAI,EAAE,WAAW,oBAAoB;AACpC,iBAAO,SAAS;AAAA,YACf,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,GAAG,eAAe,CAAC;AAAA,UACpB,CAAC;AACD;AAAA,QACD;AAEA,YAAI,EAAE,WAAW,KAAK,EAAE,WAAW,KAAK,EAAE,WAAW,EAAG;AAExD,0BAAkB,EAAE,eAAe,CAAC;AAEpC,eAAO,SAAS;AAAA,UACf,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,GAAG,eAAe,CAAC;AAAA,QACpB,CAAC;AAAA,MACF;AAEA,eAAS,cAAc,GAAuB;AAC7C,YAAK,EAAU,SAAU;AAEzB,YAAI,EAAE,YAAY,SAAS,EAAE,YAAY,MAAO;AAChD,gBAAQ,EAAE;AACV,gBAAQ,EAAE;AAKV,cAAMA,UACL,YAAY,sBAAsB,EAAE,YAAY,qBAC7C,EAAE,YAAY,mBAAmB,IACjC,CAAC,CAAC;AACN,mBAAW,eAAeA,SAAQ;AACjC,iBAAO,SAAS;AAAA,YACf,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,GAAG,eAAe,WAAW;AAAA,UAC9B,CAAC;AAAA,QACF;AAAA,MACD;AAEA,eAAS,YAAY,GAAuB;AAC3C,YAAK,EAAU,SAAU;AACzB,YAAI,EAAE,WAAW,KAAK,EAAE,WAAW,KAAK,EAAE,WAAW,KAAK,EAAE,WAAW,EAAG;AAC1E,gBAAQ,EAAE;AACV,gBAAQ,EAAE;AAEV,8BAAsB,EAAE,eAAe,CAAC;AAExC,eAAO,SAAS;AAAA,UACf,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,GAAG,eAAe,CAAC;AAAA,QACpB,CAAC;AAAA,MACF;AAEA,eAAS,eAAe,GAAuB;AAC9C,YAAK,EAAU,SAAU;AACzB,YAAI,OAAO,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,MAAO;AACpE,cAAM,WAAW,EAAE,gBAAgB,WAAW,EAAE,gBAAgB;AAChE,eAAO,oBAAoB,EAAE,kBAAkB,WAAW,OAAO,KAAK,CAAC;AAAA,MACxE;AAEA,eAAS,eAAe,GAAuB;AAC9C,YAAK,EAAU,SAAU;AACzB,YAAI,OAAO,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,MAAO;AACpE,cAAM,WAAW,EAAE,gBAAgB,WAAW,EAAE,gBAAgB;AAChE,eAAO,oBAAoB,EAAE,kBAAkB,WAAW,QAAQ,KAAK,CAAC;AAAA,MACzE;AAEA,eAAS,aAAa,GAAqB;AAC1C;AAAC,QAAC,EAAU,WAAW;AACvB,uBAAe,CAAC;AAAA,MACjB;AAEA,eAAS,WAAW,GAAqB;AACxC;AAAC,QAAC,EAAU,WAAW;AAEvB,YAAI,EAAE,EAAE,kBAAkB,aAAc;AAExC,YACC,EAAE,OAAO,YAAY,OACrB,EAAE,OAAO,YAAY,cACrB,CAAC,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,QAKV,EAAE,OAAO,gBAAgB,KAAK,EAAE,OAAO,UAAU,SAAS,iBAAiB,IAC1E;AACD,yBAAe,CAAC;AAAA,QACjB;AAAA,MACD;AAEA,eAAS,WAAW,GAA6B;AAChD,uBAAe,CAAC;AAAA,MACjB;AAEA,qBAAe,OAAO,GAA6B;AAClD,uBAAe,CAAC;AAChB,6BAAqB,CAAC;AAEtB,YAAI,EAAE,cAAc,OAAO,QAAQ;AAClC,gBAAM,QAAQ,MAAM,KAAK,EAAE,aAAa,KAAK;AAE7C,gBAAM,OAAO,mBAAmB;AAAA,YAC/B,MAAM;AAAA,YACN;AAAA,YACA,OAAO,OAAO,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,UAC1D,CAAC;AACD;AAAA,QACD;AAEA,cAAM,MAAM,EAAE,aAAa,QAAQ,KAAK;AACxC,YAAI,KAAK;AACR,gBAAM,OAAO,mBAAmB;AAAA,YAC/B,MAAM;AAAA,YACN;AAAA,YACA,OAAO,OAAO,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,UAC1D,CAAC;AACD;AAAA,QACD;AAAA,MACD;AAEA,eAAS,QAAQ,GAAqB;AACrC,6BAAqB,CAAC;AAAA,MACvB;AAEA,aAAO;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,WAAW;AAAA,EACrB;AAEA,SAAO;AACR;",
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport React, { useEffect, useMemo } from 'react'\nimport { RIGHT_MOUSE_BUTTON } from '../constants'\nimport {\n\tpreventDefault,\n\treleasePointerCapture,\n\tsetPointerCapture,\n\tstopEventPropagation,\n} from '../utils/dom'\nimport { getPointerInfo } from '../utils/getPointerInfo'\nimport { useEditor } from './useEditor'\n\nexport function useCanvasEvents() {\n\tconst editor = useEditor()\n\tconst currentTool = useValue('current tool', () => editor.getCurrentTool(), [editor])\n\n\tconst events = useMemo(\n\t\tfunction canvasEvents() {\n\t\t\tfunction onPointerDown(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\n\t\t\t\tif (e.button === RIGHT_MOUSE_BUTTON) {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\tname: 'right_click',\n\t\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 5) return\n\n\t\t\t\tsetPointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_down',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerUp(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return\n\n\t\t\t\treleasePointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_up',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerEnter(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })\n\t\t\t}\n\n\t\t\tfunction onPointerLeave(e: React.PointerEvent) {\n\t\t\t\tif ((e as any).isKilled) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })\n\t\t\t}\n\n\t\t\tfunction onTouchStart(e: React.TouchEvent) {\n\t\t\t\t;(e as any).isKilled = true\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tfunction onTouchEnd(e: React.TouchEvent) {\n\t\t\t\t;(e as any).isKilled = true\n\t\t\t\t// check that e.target is an HTMLElement\n\t\t\t\tif (!(e.target instanceof HTMLElement)) return\n\n\t\t\t\tconst editingShapeId = editor.getEditingShape()?.id\n\t\t\t\tif (\n\t\t\t\t\t// if the target is not inside the editing shape\n\t\t\t\t\t!(editingShapeId && e.target.closest(`[data-shape-id=\"${editingShapeId}\"]`)) &&\n\t\t\t\t\t// and the target is not an clickable element\n\t\t\t\t\te.target.tagName !== 'A' &&\n\t\t\t\t\t// or a TextArea.tsx ?\n\t\t\t\t\te.target.tagName !== 'TEXTAREA' &&\n\t\t\t\t\t!e.target.isContentEditable\n\t\t\t\t) {\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onDragOver(e: React.DragEvent<Element>) {\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tasync function onDrop(e: React.DragEvent<Element>) {\n\t\t\t\tpreventDefault(e)\n\t\t\t\tstopEventPropagation(e)\n\n\t\t\t\tif (e.dataTransfer?.files?.length) {\n\t\t\t\t\tconst files = Array.from(e.dataTransfer.files)\n\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'files',\n\t\t\t\t\t\tfiles,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst url = e.dataTransfer.getData('url')\n\t\t\t\tif (url) {\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'url',\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onClick(e: React.MouseEvent) {\n\t\t\t\tstopEventPropagation(e)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tonPointerDown,\n\t\t\t\tonPointerUp,\n\t\t\t\tonPointerEnter,\n\t\t\t\tonPointerLeave,\n\t\t\t\tonDragOver,\n\t\t\t\tonDrop,\n\t\t\t\tonTouchStart,\n\t\t\t\tonTouchEnd,\n\t\t\t\tonClick,\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t// onPointerMove is special: where we're only interested in the other events when they're\n\t// happening _on_ the canvas (as opposed to outside of it, or on UI floating over it), we want\n\t// the pointer position to be up to date regardless of whether it's over the tldraw canvas or\n\t// not. So instead of returning a listener to be attached to the canvas, we directly attach a\n\t// listener to the whole document instead.\n\tuseEffect(() => {\n\t\tlet lastX: number, lastY: number\n\n\t\tfunction onPointerMove(e: PointerEvent) {\n\t\t\tif ((e as any).isKilled) return\n\t\t\t;(e as any).isKilled = true\n\n\t\t\tif (e.clientX === lastX && e.clientY === lastY) return\n\t\t\tlastX = e.clientX\n\t\t\tlastY = e.clientY\n\n\t\t\t// For tools that benefit from a higher fidelity of events,\n\t\t\t// we dispatch the coalesced events.\n\t\t\t// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.\n\t\t\tconst events =\n\t\t\t\tcurrentTool.useCoalescedEvents && e.getCoalescedEvents ? e.getCoalescedEvents() : [e]\n\t\t\tfor (const singleEvent of events) {\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_move',\n\t\t\t\t\t...getPointerInfo(singleEvent),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tdocument.body.addEventListener('pointermove', onPointerMove)\n\t\treturn () => {\n\t\t\tdocument.body.removeEventListener('pointermove', onPointerMove)\n\t\t}\n\t}, [editor, currentTool])\n\n\treturn events\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["events"]
7
7
  }
@@ -1,11 +1,14 @@
1
1
  import { useEffect } from "react";
2
2
  import { preventDefault } from "../utils/dom.mjs";
3
3
  import { useContainer } from "./useContainer.mjs";
4
+ import { useMaybeEditor } from "./useEditor.mjs";
4
5
  function usePassThroughMouseOverEvents(ref) {
5
6
  if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
6
7
  const container = useContainer();
8
+ const editor = useMaybeEditor();
7
9
  useEffect(() => {
8
10
  function onMouseOver(e) {
11
+ if (!editor?.getInstanceState().isFocused) return;
9
12
  if (e.isSpecialRedispatchedEvent) return;
10
13
  preventDefault(e);
11
14
  const cvs = container.querySelector(".tl-canvas");
@@ -20,7 +23,7 @@ function usePassThroughMouseOverEvents(ref) {
20
23
  return () => {
21
24
  elm.removeEventListener("mouseover", onMouseOver);
22
25
  };
23
- }, [container, ref]);
26
+ }, [container, editor, ref]);
24
27
  }
25
28
  export {
26
29
  usePassThroughMouseOverEvents
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/usePassThroughMouseOverEvents.ts"],
4
- "sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\n\n/** @public */\nexport function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {\n\tif (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')\n\tconst container = useContainer()\n\n\tuseEffect(() => {\n\t\tfunction onMouseOver(e: MouseEvent) {\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\t\t\tpreventDefault(e)\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new PointerEvent(e.type, e as any)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tconst elm = ref.current\n\t\tif (!elm) return\n\n\t\telm.addEventListener('mouseover', onMouseOver, { passive: false })\n\t\treturn () => {\n\t\t\telm.removeEventListener('mouseover', onMouseOver)\n\t\t}\n\t}, [container, ref])\n}\n"],
5
- "mappings": "AAAA,SAAoB,iBAAiB;AACrC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAGtB,SAAS,8BAA8B,KAA6B;AAC1E,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,YAAY,aAAa;AAE/B,YAAU,MAAM;AACf,aAAS,YAAY,GAAe;AACnC,UAAK,EAAU,2BAA4B;AAC3C,qBAAe,CAAC;AAChB,YAAM,MAAM,UAAU,cAAc,YAAY;AAChD,UAAI,CAAC,IAAK;AACV,YAAM,WAAW,IAAI,aAAa,EAAE,MAAM,CAAQ;AACjD,MAAC,SAAiB,6BAA6B;AAChD,UAAI,cAAc,QAAQ;AAAA,IAC3B;AAEA,UAAM,MAAM,IAAI;AAChB,QAAI,CAAC,IAAK;AAEV,QAAI,iBAAiB,aAAa,aAAa,EAAE,SAAS,MAAM,CAAC;AACjE,WAAO,MAAM;AACZ,UAAI,oBAAoB,aAAa,WAAW;AAAA,IACjD;AAAA,EACD,GAAG,CAAC,WAAW,GAAG,CAAC;AACpB;",
4
+ "sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\nimport { useMaybeEditor } from './useEditor'\n\n/** @public */\nexport function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {\n\tif (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')\n\tconst container = useContainer()\n\tconst editor = useMaybeEditor()\n\n\tuseEffect(() => {\n\t\tfunction onMouseOver(e: MouseEvent) {\n\t\t\tif (!editor?.getInstanceState().isFocused) return\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\t\t\tpreventDefault(e)\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new PointerEvent(e.type, e as any)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tconst elm = ref.current\n\t\tif (!elm) return\n\n\t\telm.addEventListener('mouseover', onMouseOver, { passive: false })\n\t\treturn () => {\n\t\t\telm.removeEventListener('mouseover', onMouseOver)\n\t\t}\n\t}, [container, editor, ref])\n}\n"],
5
+ "mappings": "AAAA,SAAoB,iBAAiB;AACrC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAGxB,SAAS,8BAA8B,KAA6B;AAC1E,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,eAAe;AAE9B,YAAU,MAAM;AACf,aAAS,YAAY,GAAe;AACnC,UAAI,CAAC,QAAQ,iBAAiB,EAAE,UAAW;AAC3C,UAAK,EAAU,2BAA4B;AAC3C,qBAAe,CAAC;AAChB,YAAM,MAAM,UAAU,cAAc,YAAY;AAChD,UAAI,CAAC,IAAK;AACV,YAAM,WAAW,IAAI,aAAa,EAAE,MAAM,CAAQ;AACjD,MAAC,SAAiB,6BAA6B;AAChD,UAAI,cAAc,QAAQ;AAAA,IAC3B;AAEA,UAAM,MAAM,IAAI;AAChB,QAAI,CAAC,IAAK;AAEV,QAAI,iBAAiB,aAAa,aAAa,EAAE,SAAS,MAAM,CAAC;AACjE,WAAO,MAAM;AACZ,UAAI,oBAAoB,aAAa,WAAW;AAAA,IACjD;AAAA,EACD,GAAG,CAAC,WAAW,QAAQ,GAAG,CAAC;AAC5B;",
6
6
  "names": []
7
7
  }
@@ -1,11 +1,14 @@
1
1
  import { useEffect } from "react";
2
2
  import { preventDefault } from "../utils/dom.mjs";
3
3
  import { useContainer } from "./useContainer.mjs";
4
+ import { useMaybeEditor } from "./useEditor.mjs";
4
5
  function usePassThroughWheelEvents(ref) {
5
6
  if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
6
7
  const container = useContainer();
8
+ const editor = useMaybeEditor();
7
9
  useEffect(() => {
8
10
  function onWheel(e) {
11
+ if (!editor?.getInstanceState().isFocused) return;
9
12
  if (e.isSpecialRedispatchedEvent) return;
10
13
  const elm2 = ref.current;
11
14
  if (elm2 && elm2.scrollHeight > elm2.clientHeight) {
@@ -24,7 +27,7 @@ function usePassThroughWheelEvents(ref) {
24
27
  return () => {
25
28
  elm.removeEventListener("wheel", onWheel);
26
29
  };
27
- }, [container, ref]);
30
+ }, [container, editor, ref]);
28
31
  }
29
32
  export {
30
33
  usePassThroughWheelEvents
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/usePassThroughWheelEvents.ts"],
4
- "sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\n\n/** @public */\nexport function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {\n\tif (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')\n\tconst container = useContainer()\n\n\tuseEffect(() => {\n\t\tfunction onWheel(e: WheelEvent) {\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\n\t\t\t// if the element is scrollable, don't redispatch the event\n\t\t\tconst elm = ref.current\n\t\t\tif (elm && elm.scrollHeight > elm.clientHeight) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new WheelEvent('wheel', e as any)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tconst elm = ref.current\n\t\tif (!elm) return\n\n\t\telm.addEventListener('wheel', onWheel, { passive: false })\n\t\treturn () => {\n\t\t\telm.removeEventListener('wheel', onWheel)\n\t\t}\n\t}, [container, ref])\n}\n"],
5
- "mappings": "AAAA,SAAoB,iBAAiB;AACrC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAGtB,SAAS,0BAA0B,KAA6B;AACtE,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,YAAY,aAAa;AAE/B,YAAU,MAAM;AACf,aAAS,QAAQ,GAAe;AAC/B,UAAK,EAAU,2BAA4B;AAG3C,YAAMA,OAAM,IAAI;AAChB,UAAIA,QAAOA,KAAI,eAAeA,KAAI,cAAc;AAC/C;AAAA,MACD;AAEA,qBAAe,CAAC;AAChB,YAAM,MAAM,UAAU,cAAc,YAAY;AAChD,UAAI,CAAC,IAAK;AACV,YAAM,WAAW,IAAI,WAAW,SAAS,CAAQ;AAChD,MAAC,SAAiB,6BAA6B;AAChD,UAAI,cAAc,QAAQ;AAAA,IAC3B;AAEA,UAAM,MAAM,IAAI;AAChB,QAAI,CAAC,IAAK;AAEV,QAAI,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;AACzD,WAAO,MAAM;AACZ,UAAI,oBAAoB,SAAS,OAAO;AAAA,IACzC;AAAA,EACD,GAAG,CAAC,WAAW,GAAG,CAAC;AACpB;",
4
+ "sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\nimport { useMaybeEditor } from './useEditor'\n\n/** @public */\nexport function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {\n\tif (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')\n\tconst container = useContainer()\n\tconst editor = useMaybeEditor()\n\n\tuseEffect(() => {\n\t\tfunction onWheel(e: WheelEvent) {\n\t\t\t// Only pass through wheel events if the editor is focused\n\t\t\tif (!editor?.getInstanceState().isFocused) return\n\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\n\t\t\t// if the element is scrollable, don't redispatch the event\n\t\t\tconst elm = ref.current\n\t\t\tif (elm && elm.scrollHeight > elm.clientHeight) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new WheelEvent('wheel', e as any)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tconst elm = ref.current\n\t\tif (!elm) return\n\n\t\telm.addEventListener('wheel', onWheel, { passive: false })\n\t\treturn () => {\n\t\t\telm.removeEventListener('wheel', onWheel)\n\t\t}\n\t}, [container, editor, ref])\n}\n"],
5
+ "mappings": "AAAA,SAAoB,iBAAiB;AACrC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAGxB,SAAS,0BAA0B,KAA6B;AACtE,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,eAAe;AAE9B,YAAU,MAAM;AACf,aAAS,QAAQ,GAAe;AAE/B,UAAI,CAAC,QAAQ,iBAAiB,EAAE,UAAW;AAE3C,UAAK,EAAU,2BAA4B;AAG3C,YAAMA,OAAM,IAAI;AAChB,UAAIA,QAAOA,KAAI,eAAeA,KAAI,cAAc;AAC/C;AAAA,MACD;AAEA,qBAAe,CAAC;AAChB,YAAM,MAAM,UAAU,cAAc,YAAY;AAChD,UAAI,CAAC,IAAK;AACV,YAAM,WAAW,IAAI,WAAW,SAAS,CAAQ;AAChD,MAAC,SAAiB,6BAA6B;AAChD,UAAI,cAAc,QAAQ;AAAA,IAC3B;AAEA,UAAM,MAAM,IAAI;AAChB,QAAI,CAAC,IAAK;AAEV,QAAI,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;AACzD,WAAO,MAAM;AACZ,UAAI,oBAAoB,SAAS,OAAO;AAAA,IACzC;AAAA,EACD,GAAG,CAAC,WAAW,QAAQ,GAAG,CAAC;AAC5B;",
6
6
  "names": ["elm"]
7
7
  }
@@ -0,0 +1,15 @@
1
+ import { react } from "@tldraw/state";
2
+ import { useLayoutEffect } from "react";
3
+ import { useEditor } from "./useEditor.mjs";
4
+ function useStateAttribute() {
5
+ const editor = useEditor();
6
+ useLayoutEffect(() => {
7
+ return react("stateAttribute", () => {
8
+ editor.getContainer().setAttribute("data-state", editor.getPath());
9
+ });
10
+ }, [editor]);
11
+ }
12
+ export {
13
+ useStateAttribute
14
+ };
15
+ //# sourceMappingURL=useStateAttribute.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/hooks/useStateAttribute.ts"],
4
+ "sourcesContent": ["import { react } from '@tldraw/state'\nimport { useLayoutEffect } from 'react'\nimport { useEditor } from './useEditor'\n\nexport function useStateAttribute() {\n\tconst editor = useEditor()\n\n\t// we use a layout effect because we don't want there to be any perceptible delay between the\n\t// editor mounting and this attribute being applied, because styles may depend on it:\n\tuseLayoutEffect(() => {\n\t\treturn react('stateAttribute', () => {\n\t\t\teditor.getContainer().setAttribute('data-state', editor.getPath())\n\t\t})\n\t}, [editor])\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAEnB,SAAS,oBAAoB;AACnC,QAAM,SAAS,UAAU;AAIzB,kBAAgB,MAAM;AACrB,WAAO,MAAM,kBAAkB,MAAM;AACpC,aAAO,aAAa,EAAE,aAAa,cAAc,OAAO,QAAQ,CAAC;AAAA,IAClE,CAAC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AACZ;",
6
+ "names": []
7
+ }
@@ -25,10 +25,7 @@ class LicenseManager {
25
25
  isDevelopment;
26
26
  isTest;
27
27
  isCryptoAvailable;
28
- state = atom(
29
- "license state",
30
- "pending"
31
- );
28
+ state = atom("license state", "pending");
32
29
  verbose = true;
33
30
  constructor(licenseKey, testPublicKey, testEnvironment) {
34
31
  this.isTest = process.env.NODE_ENV === "test";
@@ -36,17 +33,14 @@ class LicenseManager {
36
33
  this.publicKey = testPublicKey || this.publicKey;
37
34
  this.isCryptoAvailable = !!crypto.subtle;
38
35
  this.getLicenseFromKey(licenseKey).then((result) => {
39
- const isUnlicensed = isEditorUnlicensed(result);
40
- if (!this.isDevelopment && isUnlicensed) {
36
+ const licenseState = getLicenseState(result);
37
+ if (!this.isDevelopment && licenseState === "unlicensed") {
41
38
  fetch(WATERMARK_TRACK_SRC);
42
39
  }
43
- if (isUnlicensed) {
44
- this.state.set("unlicensed");
45
- } else if (result.isLicensedWithWatermark) {
46
- this.state.set("licensed-with-watermark");
47
- } else {
48
- this.state.set("licensed");
49
- }
40
+ this.state.set(licenseState);
41
+ }).catch((error) => {
42
+ console.error("License validation failed:", error);
43
+ this.state.set("unlicensed");
50
44
  });
51
45
  }
52
46
  getIsDevelopment(testEnvironment) {
@@ -244,21 +238,22 @@ class LicenseManager {
244
238
  }
245
239
  static className = "tl-watermark_SEE-LICENSE";
246
240
  }
247
- function isEditorUnlicensed(result) {
248
- if (!result.isLicenseParseable) return true;
249
- if (!result.isDomainValid && !result.isDevelopment) return true;
241
+ function getLicenseState(result) {
242
+ if (!result.isLicenseParseable) return "unlicensed";
243
+ if (!result.isDomainValid && !result.isDevelopment) return "unlicensed";
250
244
  if (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {
251
- if (result.isInternalLicense) {
252
- throw new Error("License: Internal license expired.");
253
- }
254
- return true;
245
+ const internalExpired = result.isInternalLicense && result.isDomainValid;
246
+ return internalExpired ? "internal-expired" : "unlicensed";
247
+ }
248
+ if (result.isLicensedWithWatermark) {
249
+ return "licensed-with-watermark";
255
250
  }
256
- return false;
251
+ return "licensed";
257
252
  }
258
253
  export {
259
254
  FLAGS,
260
255
  LicenseManager,
261
256
  PROPERTIES,
262
- isEditorUnlicensed
257
+ getLicenseState
263
258
  };
264
259
  //# sourceMappingURL=LicenseManager.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/LicenseManager.ts"],
4
- "sourcesContent": ["import { atom } from '@tldraw/state'\nimport { fetch } from '@tldraw/utils'\nimport { publishDates } from '../../version'\nimport { getDefaultCdnBaseUrl } from '../utils/assets'\nimport { importPublicKey, str2ab } from '../utils/licensing'\n\nconst GRACE_PERIOD_DAYS = 5\n\nexport const FLAGS = {\n\tANNUAL_LICENSE: 0x1,\n\tPERPETUAL_LICENSE: 0x2,\n\tINTERNAL_LICENSE: 0x4,\n\tWITH_WATERMARK: 0x8,\n}\nconst HIGHEST_FLAG = Math.max(...Object.values(FLAGS))\n\nexport const PROPERTIES = {\n\tID: 0,\n\tHOSTS: 1,\n\tFLAGS: 2,\n\tEXPIRY_DATE: 3,\n}\nconst NUMBER_OF_KNOWN_PROPERTIES = Object.keys(PROPERTIES).length\n\nconst LICENSE_EMAIL = 'sales@tldraw.com'\n\nconst WATERMARK_TRACK_SRC = `${getDefaultCdnBaseUrl()}/watermarks/watermark-track.svg`\n\n/** @internal */\nexport interface LicenseInfo {\n\tid: string\n\thosts: string[]\n\tflags: number\n\texpiryDate: string\n}\n/** @internal */\nexport type InvalidLicenseReason =\n\t| 'invalid-license-key'\n\t| 'no-key-provided'\n\t| 'has-key-development-mode'\n\n/** @internal */\nexport type LicenseFromKeyResult = InvalidLicenseKeyResult | ValidLicenseKeyResult\n\n/** @internal */\nexport interface InvalidLicenseKeyResult {\n\tisLicenseParseable: false\n\treason: InvalidLicenseReason\n}\n\n/** @internal */\nexport interface ValidLicenseKeyResult {\n\tisLicenseParseable: true\n\tlicense: LicenseInfo\n\tisDevelopment: boolean\n\tisDomainValid: boolean\n\texpiryDate: Date\n\tisAnnualLicense: boolean\n\tisAnnualLicenseExpired: boolean\n\tisPerpetualLicense: boolean\n\tisPerpetualLicenseExpired: boolean\n\tisInternalLicense: boolean\n\tisLicensedWithWatermark: boolean\n}\n\n/** @internal */\nexport type TestEnvironment = 'development' | 'production'\n\n/** @internal */\nexport class LicenseManager {\n\tprivate publicKey =\n\t\t'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHJh0uUfxHtCGyerXmmatE368Hd9rI6LH9oPDQihnaCryRFWEVeOvf9U/SPbyxX74LFyJs5tYeAHq5Nc0Ax25LQ'\n\tpublic isDevelopment: boolean\n\tpublic isTest: boolean\n\tpublic isCryptoAvailable: boolean\n\tstate = atom<'pending' | 'licensed' | 'licensed-with-watermark' | 'unlicensed'>(\n\t\t'license state',\n\t\t'pending'\n\t)\n\tpublic verbose = true\n\n\tconstructor(\n\t\tlicenseKey: string | undefined,\n\t\ttestPublicKey?: string,\n\t\ttestEnvironment?: TestEnvironment\n\t) {\n\t\tthis.isTest = process.env.NODE_ENV === 'test'\n\t\tthis.isDevelopment = this.getIsDevelopment(testEnvironment)\n\t\tthis.publicKey = testPublicKey || this.publicKey\n\t\tthis.isCryptoAvailable = !!crypto.subtle\n\n\t\tthis.getLicenseFromKey(licenseKey).then((result) => {\n\t\t\tconst isUnlicensed = isEditorUnlicensed(result)\n\n\t\t\tif (!this.isDevelopment && isUnlicensed) {\n\t\t\t\tfetch(WATERMARK_TRACK_SRC)\n\t\t\t}\n\n\t\t\tif (isUnlicensed) {\n\t\t\t\tthis.state.set('unlicensed')\n\t\t\t} else if ((result as ValidLicenseKeyResult).isLicensedWithWatermark) {\n\t\t\t\tthis.state.set('licensed-with-watermark')\n\t\t\t} else {\n\t\t\t\tthis.state.set('licensed')\n\t\t\t}\n\t\t})\n\t}\n\n\tprivate getIsDevelopment(testEnvironment?: TestEnvironment) {\n\t\tif (testEnvironment === 'development') return true\n\t\tif (testEnvironment === 'production') return false\n\n\t\t// If we are using https on a non-localhost domain we assume it's a production env and a development one otherwise\n\t\treturn (\n\t\t\t!['https:', 'vscode-webview:'].includes(window.location.protocol) ||\n\t\t\twindow.location.hostname === 'localhost'\n\t\t)\n\t}\n\n\tprivate async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {\n\t\tconst [data, signature] = licenseKey.split('.')\n\t\tconst [prefix, encodedData] = data.split('/')\n\n\t\tif (!prefix.startsWith('tldraw-')) {\n\t\t\tthrow new Error(`Unsupported prefix '${prefix}'`)\n\t\t}\n\n\t\tconst publicCryptoKey = await importPublicKey(this.publicKey)\n\n\t\tlet isVerified\n\t\ttry {\n\t\t\tisVerified = await crypto.subtle.verify(\n\t\t\t\t{\n\t\t\t\t\tname: 'ECDSA',\n\t\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t\t},\n\t\t\t\tpublicCryptoKey,\n\t\t\t\tnew Uint8Array(str2ab(atob(signature))),\n\t\t\t\tnew Uint8Array(str2ab(atob(encodedData)))\n\t\t\t)\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthrow new Error('Could not perform signature validation')\n\t\t}\n\n\t\tif (!isVerified) {\n\t\t\tthrow new Error('Invalid signature')\n\t\t}\n\n\t\tlet decodedData: any\n\t\ttry {\n\t\t\tdecodedData = JSON.parse(atob(encodedData))\n\t\t} catch {\n\t\t\tthrow new Error('Could not parse object')\n\t\t}\n\t\tif (decodedData.length > NUMBER_OF_KNOWN_PROPERTIES) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'License key contains some unknown properties.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\n\t\treturn {\n\t\t\tid: decodedData[PROPERTIES.ID],\n\t\t\thosts: decodedData[PROPERTIES.HOSTS],\n\t\t\tflags: decodedData[PROPERTIES.FLAGS],\n\t\t\texpiryDate: decodedData[PROPERTIES.EXPIRY_DATE],\n\t\t}\n\t}\n\n\tasync getLicenseFromKey(licenseKey?: string): Promise<LicenseFromKeyResult> {\n\t\tif (!licenseKey) {\n\t\t\tif (!this.isDevelopment) {\n\t\t\t\tthis.outputNoLicenseKeyProvided()\n\t\t\t}\n\n\t\t\treturn { isLicenseParseable: false, reason: 'no-key-provided' }\n\t\t}\n\n\t\tif (this.isDevelopment && !this.isCryptoAvailable) {\n\t\t\tif (this.verbose) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t'tldraw: you seem to be in a development environment that does not support crypto. License not verified.'\n\t\t\t\t)\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log('You should check that this works in production separately.')\n\t\t\t}\n\t\t\t// We can't parse the license if we are in development mode since crypto\n\t\t\t// is not available on http\n\t\t\treturn { isLicenseParseable: false, reason: 'has-key-development-mode' }\n\t\t}\n\n\t\t// Borrowed idea from AG Grid:\n\t\t// Copying from various sources (like PDFs) can include zero-width characters.\n\t\t// This helps makes sure the key validation doesn't fail.\n\t\tlet cleanedLicenseKey = licenseKey.replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n\t\tcleanedLicenseKey = cleanedLicenseKey.replace(/\\r?\\n|\\r/g, '')\n\n\t\ttry {\n\t\t\tconst licenseInfo = await this.extractLicenseKey(cleanedLicenseKey)\n\t\t\tconst expiryDate = new Date(licenseInfo.expiryDate)\n\t\t\tconst isAnnualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\tconst isPerpetualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.PERPETUAL_LICENSE)\n\n\t\t\tconst result: ValidLicenseKeyResult = {\n\t\t\t\tlicense: licenseInfo,\n\t\t\t\tisLicenseParseable: true,\n\t\t\t\tisDevelopment: this.isDevelopment,\n\t\t\t\tisDomainValid: this.isDomainValid(licenseInfo),\n\t\t\t\texpiryDate,\n\t\t\t\tisAnnualLicense,\n\t\t\t\tisAnnualLicenseExpired: isAnnualLicense && this.isAnnualLicenseExpired(expiryDate),\n\t\t\t\tisPerpetualLicense,\n\t\t\t\tisPerpetualLicenseExpired: isPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate),\n\t\t\t\tisInternalLicense: this.isFlagEnabled(licenseInfo.flags, FLAGS.INTERNAL_LICENSE),\n\t\t\t\tisLicensedWithWatermark: this.isFlagEnabled(licenseInfo.flags, FLAGS.WITH_WATERMARK),\n\t\t\t}\n\t\t\tthis.outputLicenseInfoIfNeeded(result)\n\n\t\t\treturn result\n\t\t} catch (e: any) {\n\t\t\tthis.outputInvalidLicenseKey(e.message)\n\t\t\t// If the license can't be parsed, it's invalid\n\t\t\treturn { isLicenseParseable: false, reason: 'invalid-license-key' }\n\t\t}\n\t}\n\n\tprivate isDomainValid(licenseInfo: LicenseInfo) {\n\t\tconst currentHostname = window.location.hostname.toLowerCase()\n\n\t\treturn licenseInfo.hosts.some((host) => {\n\t\t\tconst normalizedHost = host.toLowerCase().trim()\n\n\t\t\t// Allow the domain if listed and www variations, 'example.com' allows 'example.com' and 'www.example.com'\n\t\t\tif (\n\t\t\t\tnormalizedHost === currentHostname ||\n\t\t\t\t`www.${normalizedHost}` === currentHostname ||\n\t\t\t\tnormalizedHost === `www.${currentHostname}`\n\t\t\t) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// If host is '*', we allow all domains.\n\t\t\tif (host === '*') {\n\t\t\t\t// All domains allowed.\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Glob testing, we only support '*.somedomain.com' right now.\n\t\t\tif (host.includes('*')) {\n\t\t\t\tconst globToRegex = new RegExp(host.replace(/\\*/g, '.*?'))\n\t\t\t\treturn globToRegex.test(currentHostname) || globToRegex.test(`www.${currentHostname}`)\n\t\t\t}\n\n\t\t\t// VSCode support\n\t\t\tif (window.location.protocol === 'vscode-webview:') {\n\t\t\t\tconst currentUrl = new URL(window.location.href)\n\t\t\t\tconst extensionId = currentUrl.searchParams.get('extensionId')\n\t\t\t\tif (normalizedHost === extensionId) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t})\n\t}\n\n\tprivate getExpirationDateWithoutGracePeriod(expiryDate: Date) {\n\t\treturn new Date(expiryDate.getFullYear(), expiryDate.getMonth(), expiryDate.getDate())\n\t}\n\n\tprivate getExpirationDateWithGracePeriod(expiryDate: Date) {\n\t\treturn new Date(\n\t\t\texpiryDate.getFullYear(),\n\t\t\texpiryDate.getMonth(),\n\t\t\texpiryDate.getDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day\n\t\t)\n\t}\n\n\tprivate isAnnualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst isExpired = new Date() >= expiration\n\t\t// If it is not expired yet (including the grace period), but after the expiry date we warn the users\n\t\tif (!isExpired && new Date() >= this.getExpirationDateWithoutGracePeriod(expiryDate)) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'tldraw license is about to expire, you are in a grace period.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} if you would like to renew your license.`,\n\t\t\t])\n\t\t}\n\t\treturn isExpired\n\t}\n\n\tprivate isPerpetualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst dates = {\n\t\t\tmajor: new Date(publishDates.major),\n\t\t\tminor: new Date(publishDates.minor),\n\t\t}\n\t\t// We allow patch releases, but the major and minor releases should be within the expiration date\n\t\treturn dates.major >= expiration || dates.minor >= expiration\n\t}\n\n\tprivate isFlagEnabled(flags: number, flag: number) {\n\t\treturn (flags & flag) === flag\n\t}\n\n\tprivate outputNoLicenseKeyProvided() {\n\t\t// Noop, we don't need to show this message.\n\t\t// this.outputMessages([\n\t\t// \t'No tldraw license key provided!',\n\t\t// \t`Please reach out to ${LICENSE_EMAIL} if you would like to license tldraw or if you'd like a trial.`,\n\t\t// ])\n\t}\n\n\tprivate outputInvalidLicenseKey(msg: string) {\n\t\tthis.outputMessages(['Invalid tldraw license key', `Reason: ${msg}`])\n\t}\n\n\tprivate outputLicenseInfoIfNeeded(result: ValidLicenseKeyResult) {\n\t\tif (result.isAnnualLicenseExpired) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'Your tldraw license has expired!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew.`,\n\t\t\t])\n\t\t}\n\n\t\tif (!result.isDomainValid && !result.isDevelopment) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'This tldraw license key is not valid for this domain!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} if you would like to use tldraw on other domains.`,\n\t\t\t])\n\t\t}\n\t\t// If we added a new flag it will be twice the value of the currently highest flag.\n\t\t// And if all the current flags are on we would get the `HIGHEST_FLAG * 2 - 1`, so anything higher than that means there are new flags.\n\t\tif (result.license.flags >= HIGHEST_FLAG * 2) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'This tldraw license contains some unknown flags.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\t}\n\n\tprivate outputMessages(messages: string[]) {\n\t\tif (this.isTest) return\n\t\tif (this.verbose) {\n\t\t\tthis.outputDelimiter()\n\t\t\tfor (const message of messages) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t`%c${message}`,\n\t\t\t\t\t`color: white; background: crimson; padding: 2px; border-radius: 3px;`\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.outputDelimiter()\n\t\t}\n\t}\n\n\tprivate outputDelimiter() {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(\n\t\t\t'%c-------------------------------------------------------------------',\n\t\t\t`color: white; background: crimson; padding: 2px; border-radius: 3px;`\n\t\t)\n\t}\n\n\tstatic className = 'tl-watermark_SEE-LICENSE'\n}\n\nexport function isEditorUnlicensed(result: LicenseFromKeyResult) {\n\tif (!result.isLicenseParseable) return true\n\tif (!result.isDomainValid && !result.isDevelopment) return true\n\tif (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {\n\t\tif (result.isInternalLicense) {\n\t\t\tthrow new Error('License: Internal license expired.')\n\t\t}\n\t\treturn true\n\t}\n\n\treturn false\n}\n"],
5
- "mappings": "AAAA,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,oBAAoB;AAC7B,SAAS,4BAA4B;AACrC,SAAS,iBAAiB,cAAc;AAExC,MAAM,oBAAoB;AAEnB,MAAM,QAAQ;AAAA,EACpB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,gBAAgB;AACjB;AACA,MAAM,eAAe,KAAK,IAAI,GAAG,OAAO,OAAO,KAAK,CAAC;AAE9C,MAAM,aAAa;AAAA,EACzB,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,aAAa;AACd;AACA,MAAM,6BAA6B,OAAO,KAAK,UAAU,EAAE;AAE3D,MAAM,gBAAgB;AAEtB,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AA2C9C,MAAM,eAAe;AAAA,EACnB,YACP;AAAA,EACM;AAAA,EACA;AAAA,EACA;AAAA,EACP,QAAQ;AAAA,IACP;AAAA,IACA;AAAA,EACD;AAAA,EACO,UAAU;AAAA,EAEjB,YACC,YACA,eACA,iBACC;AACD,SAAK,SAAS,QAAQ,IAAI,aAAa;AACvC,SAAK,gBAAgB,KAAK,iBAAiB,eAAe;AAC1D,SAAK,YAAY,iBAAiB,KAAK;AACvC,SAAK,oBAAoB,CAAC,CAAC,OAAO;AAElC,SAAK,kBAAkB,UAAU,EAAE,KAAK,CAAC,WAAW;AACnD,YAAM,eAAe,mBAAmB,MAAM;AAE9C,UAAI,CAAC,KAAK,iBAAiB,cAAc;AACxC,cAAM,mBAAmB;AAAA,MAC1B;AAEA,UAAI,cAAc;AACjB,aAAK,MAAM,IAAI,YAAY;AAAA,MAC5B,WAAY,OAAiC,yBAAyB;AACrE,aAAK,MAAM,IAAI,yBAAyB;AAAA,MACzC,OAAO;AACN,aAAK,MAAM,IAAI,UAAU;AAAA,MAC1B;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEQ,iBAAiB,iBAAmC;AAC3D,QAAI,oBAAoB,cAAe,QAAO;AAC9C,QAAI,oBAAoB,aAAc,QAAO;AAG7C,WACC,CAAC,CAAC,UAAU,iBAAiB,EAAE,SAAS,OAAO,SAAS,QAAQ,KAChE,OAAO,SAAS,aAAa;AAAA,EAE/B;AAAA,EAEA,MAAc,kBAAkB,YAA0C;AACzE,UAAM,CAAC,MAAM,SAAS,IAAI,WAAW,MAAM,GAAG;AAC9C,UAAM,CAAC,QAAQ,WAAW,IAAI,KAAK,MAAM,GAAG;AAE5C,QAAI,CAAC,OAAO,WAAW,SAAS,GAAG;AAClC,YAAM,IAAI,MAAM,uBAAuB,MAAM,GAAG;AAAA,IACjD;AAEA,UAAM,kBAAkB,MAAM,gBAAgB,KAAK,SAAS;AAE5D,QAAI;AACJ,QAAI;AACH,mBAAa,MAAM,OAAO,OAAO;AAAA,QAChC;AAAA,UACC,MAAM;AAAA,UACN,MAAM,EAAE,MAAM,UAAU;AAAA,QACzB;AAAA,QACA;AAAA,QACA,IAAI,WAAW,OAAO,KAAK,SAAS,CAAC,CAAC;AAAA,QACtC,IAAI,WAAW,OAAO,KAAK,WAAW,CAAC,CAAC;AAAA,MACzC;AAAA,IACD,SAAS,GAAG;AACX,cAAQ,MAAM,CAAC;AACf,YAAM,IAAI,MAAM,wCAAwC;AAAA,IACzD;AAEA,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACpC;AAEA,QAAI;AACJ,QAAI;AACH,oBAAc,KAAK,MAAM,KAAK,WAAW,CAAC;AAAA,IAC3C,QAAQ;AACP,YAAM,IAAI,MAAM,wBAAwB;AAAA,IACzC;AACA,QAAI,YAAY,SAAS,4BAA4B;AACpD,WAAK,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AAEA,WAAO;AAAA,MACN,IAAI,YAAY,WAAW,EAAE;AAAA,MAC7B,OAAO,YAAY,WAAW,KAAK;AAAA,MACnC,OAAO,YAAY,WAAW,KAAK;AAAA,MACnC,YAAY,YAAY,WAAW,WAAW;AAAA,IAC/C;AAAA,EACD;AAAA,EAEA,MAAM,kBAAkB,YAAoD;AAC3E,QAAI,CAAC,YAAY;AAChB,UAAI,CAAC,KAAK,eAAe;AACxB,aAAK,2BAA2B;AAAA,MACjC;AAEA,aAAO,EAAE,oBAAoB,OAAO,QAAQ,kBAAkB;AAAA,IAC/D;AAEA,QAAI,KAAK,iBAAiB,CAAC,KAAK,mBAAmB;AAClD,UAAI,KAAK,SAAS;AAEjB,gBAAQ;AAAA,UACP;AAAA,QACD;AAEA,gBAAQ,IAAI,4DAA4D;AAAA,MACzE;AAGA,aAAO,EAAE,oBAAoB,OAAO,QAAQ,2BAA2B;AAAA,IACxE;AAKA,QAAI,oBAAoB,WAAW,QAAQ,0BAA0B,EAAE;AACvE,wBAAoB,kBAAkB,QAAQ,aAAa,EAAE;AAE7D,QAAI;AACH,YAAM,cAAc,MAAM,KAAK,kBAAkB,iBAAiB;AAClE,YAAM,aAAa,IAAI,KAAK,YAAY,UAAU;AAClD,YAAM,kBAAkB,KAAK,cAAc,YAAY,OAAO,MAAM,cAAc;AAClF,YAAM,qBAAqB,KAAK,cAAc,YAAY,OAAO,MAAM,iBAAiB;AAExF,YAAM,SAAgC;AAAA,QACrC,SAAS;AAAA,QACT,oBAAoB;AAAA,QACpB,eAAe,KAAK;AAAA,QACpB,eAAe,KAAK,cAAc,WAAW;AAAA,QAC7C;AAAA,QACA;AAAA,QACA,wBAAwB,mBAAmB,KAAK,uBAAuB,UAAU;AAAA,QACjF;AAAA,QACA,2BAA2B,sBAAsB,KAAK,0BAA0B,UAAU;AAAA,QAC1F,mBAAmB,KAAK,cAAc,YAAY,OAAO,MAAM,gBAAgB;AAAA,QAC/E,yBAAyB,KAAK,cAAc,YAAY,OAAO,MAAM,cAAc;AAAA,MACpF;AACA,WAAK,0BAA0B,MAAM;AAErC,aAAO;AAAA,IACR,SAAS,GAAQ;AAChB,WAAK,wBAAwB,EAAE,OAAO;AAEtC,aAAO,EAAE,oBAAoB,OAAO,QAAQ,sBAAsB;AAAA,IACnE;AAAA,EACD;AAAA,EAEQ,cAAc,aAA0B;AAC/C,UAAM,kBAAkB,OAAO,SAAS,SAAS,YAAY;AAE7D,WAAO,YAAY,MAAM,KAAK,CAAC,SAAS;AACvC,YAAM,iBAAiB,KAAK,YAAY,EAAE,KAAK;AAG/C,UACC,mBAAmB,mBACnB,OAAO,cAAc,OAAO,mBAC5B,mBAAmB,OAAO,eAAe,IACxC;AACD,eAAO;AAAA,MACR;AAGA,UAAI,SAAS,KAAK;AAEjB,eAAO;AAAA,MACR;AAGA,UAAI,KAAK,SAAS,GAAG,GAAG;AACvB,cAAM,cAAc,IAAI,OAAO,KAAK,QAAQ,OAAO,KAAK,CAAC;AACzD,eAAO,YAAY,KAAK,eAAe,KAAK,YAAY,KAAK,OAAO,eAAe,EAAE;AAAA,MACtF;AAGA,UAAI,OAAO,SAAS,aAAa,mBAAmB;AACnD,cAAM,aAAa,IAAI,IAAI,OAAO,SAAS,IAAI;AAC/C,cAAM,cAAc,WAAW,aAAa,IAAI,aAAa;AAC7D,YAAI,mBAAmB,aAAa;AACnC,iBAAO;AAAA,QACR;AAAA,MACD;AAEA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AAAA,EAEQ,oCAAoC,YAAkB;AAC7D,WAAO,IAAI,KAAK,WAAW,YAAY,GAAG,WAAW,SAAS,GAAG,WAAW,QAAQ,CAAC;AAAA,EACtF;AAAA,EAEQ,iCAAiC,YAAkB;AAC1D,WAAO,IAAI;AAAA,MACV,WAAW,YAAY;AAAA,MACvB,WAAW,SAAS;AAAA,MACpB,WAAW,QAAQ,IAAI,oBAAoB;AAAA;AAAA,IAC5C;AAAA,EACD;AAAA,EAEQ,uBAAuB,YAAkB;AAChD,UAAM,aAAa,KAAK,iCAAiC,UAAU;AACnE,UAAM,YAAY,oBAAI,KAAK,KAAK;AAEhC,QAAI,CAAC,aAAa,oBAAI,KAAK,KAAK,KAAK,oCAAoC,UAAU,GAAG;AACrF,WAAK,eAAe;AAAA,QACnB;AAAA,QACA,uBAAuB,aAAa;AAAA,MACrC,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAAA,EAEQ,0BAA0B,YAAkB;AACnD,UAAM,aAAa,KAAK,iCAAiC,UAAU;AACnE,UAAM,QAAQ;AAAA,MACb,OAAO,IAAI,KAAK,aAAa,KAAK;AAAA,MAClC,OAAO,IAAI,KAAK,aAAa,KAAK;AAAA,IACnC;AAEA,WAAO,MAAM,SAAS,cAAc,MAAM,SAAS;AAAA,EACpD;AAAA,EAEQ,cAAc,OAAe,MAAc;AAClD,YAAQ,QAAQ,UAAU;AAAA,EAC3B;AAAA,EAEQ,6BAA6B;AAAA,EAMrC;AAAA,EAEQ,wBAAwB,KAAa;AAC5C,SAAK,eAAe,CAAC,8BAA8B,WAAW,GAAG,EAAE,CAAC;AAAA,EACrE;AAAA,EAEQ,0BAA0B,QAA+B;AAChE,QAAI,OAAO,wBAAwB;AAClC,WAAK,eAAe;AAAA,QACnB;AAAA,QACA,uBAAuB,aAAa;AAAA,MACrC,CAAC;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,iBAAiB,CAAC,OAAO,eAAe;AACnD,WAAK,eAAe;AAAA,QACnB;AAAA,QACA,uBAAuB,aAAa;AAAA,MACrC,CAAC;AAAA,IACF;AAGA,QAAI,OAAO,QAAQ,SAAS,eAAe,GAAG;AAC7C,WAAK,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEQ,eAAe,UAAoB;AAC1C,QAAI,KAAK,OAAQ;AACjB,QAAI,KAAK,SAAS;AACjB,WAAK,gBAAgB;AACrB,iBAAW,WAAW,UAAU;AAE/B,gBAAQ;AAAA,UACP,KAAK,OAAO;AAAA,UACZ;AAAA,QACD;AAAA,MACD;AACA,WAAK,gBAAgB;AAAA,IACtB;AAAA,EACD;AAAA,EAEQ,kBAAkB;AAEzB,YAAQ;AAAA,MACP;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,OAAO,YAAY;AACpB;AAEO,SAAS,mBAAmB,QAA8B;AAChE,MAAI,CAAC,OAAO,mBAAoB,QAAO;AACvC,MAAI,CAAC,OAAO,iBAAiB,CAAC,OAAO,cAAe,QAAO;AAC3D,MAAI,OAAO,6BAA6B,OAAO,wBAAwB;AACtE,QAAI,OAAO,mBAAmB;AAC7B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACrD;AACA,WAAO;AAAA,EACR;AAEA,SAAO;AACR;",
4
+ "sourcesContent": ["import { atom } from '@tldraw/state'\nimport { fetch } from '@tldraw/utils'\nimport { publishDates } from '../../version'\nimport { getDefaultCdnBaseUrl } from '../utils/assets'\nimport { importPublicKey, str2ab } from '../utils/licensing'\n\nconst GRACE_PERIOD_DAYS = 5\n\nexport const FLAGS = {\n\tANNUAL_LICENSE: 0x1,\n\tPERPETUAL_LICENSE: 0x2,\n\tINTERNAL_LICENSE: 0x4,\n\tWITH_WATERMARK: 0x8,\n}\nconst HIGHEST_FLAG = Math.max(...Object.values(FLAGS))\n\nexport const PROPERTIES = {\n\tID: 0,\n\tHOSTS: 1,\n\tFLAGS: 2,\n\tEXPIRY_DATE: 3,\n}\nconst NUMBER_OF_KNOWN_PROPERTIES = Object.keys(PROPERTIES).length\n\nconst LICENSE_EMAIL = 'sales@tldraw.com'\n\nconst WATERMARK_TRACK_SRC = `${getDefaultCdnBaseUrl()}/watermarks/watermark-track.svg`\n\n/** @internal */\nexport interface LicenseInfo {\n\tid: string\n\thosts: string[]\n\tflags: number\n\texpiryDate: string\n}\n\n/** @internal */\nexport type LicenseState =\n\t| 'pending'\n\t| 'licensed'\n\t| 'licensed-with-watermark'\n\t| 'unlicensed'\n\t| 'internal-expired'\n/** @internal */\nexport type InvalidLicenseReason =\n\t| 'invalid-license-key'\n\t| 'no-key-provided'\n\t| 'has-key-development-mode'\n\n/** @internal */\nexport type LicenseFromKeyResult = InvalidLicenseKeyResult | ValidLicenseKeyResult\n\n/** @internal */\nexport interface InvalidLicenseKeyResult {\n\tisLicenseParseable: false\n\treason: InvalidLicenseReason\n}\n\n/** @internal */\nexport interface ValidLicenseKeyResult {\n\tisLicenseParseable: true\n\tlicense: LicenseInfo\n\tisDevelopment: boolean\n\tisDomainValid: boolean\n\texpiryDate: Date\n\tisAnnualLicense: boolean\n\tisAnnualLicenseExpired: boolean\n\tisPerpetualLicense: boolean\n\tisPerpetualLicenseExpired: boolean\n\tisInternalLicense: boolean\n\tisLicensedWithWatermark: boolean\n}\n\n/** @internal */\nexport type TestEnvironment = 'development' | 'production'\n\n/** @internal */\nexport class LicenseManager {\n\tprivate publicKey =\n\t\t'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHJh0uUfxHtCGyerXmmatE368Hd9rI6LH9oPDQihnaCryRFWEVeOvf9U/SPbyxX74LFyJs5tYeAHq5Nc0Ax25LQ'\n\tpublic isDevelopment: boolean\n\tpublic isTest: boolean\n\tpublic isCryptoAvailable: boolean\n\tstate = atom<LicenseState>('license state', 'pending')\n\tpublic verbose = true\n\n\tconstructor(\n\t\tlicenseKey: string | undefined,\n\t\ttestPublicKey?: string,\n\t\ttestEnvironment?: TestEnvironment\n\t) {\n\t\tthis.isTest = process.env.NODE_ENV === 'test'\n\t\tthis.isDevelopment = this.getIsDevelopment(testEnvironment)\n\t\tthis.publicKey = testPublicKey || this.publicKey\n\t\tthis.isCryptoAvailable = !!crypto.subtle\n\n\t\tthis.getLicenseFromKey(licenseKey)\n\t\t\t.then((result) => {\n\t\t\t\tconst licenseState = getLicenseState(result)\n\n\t\t\t\tif (!this.isDevelopment && licenseState === 'unlicensed') {\n\t\t\t\t\tfetch(WATERMARK_TRACK_SRC)\n\t\t\t\t}\n\n\t\t\t\tthis.state.set(licenseState)\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tconsole.error('License validation failed:', error)\n\t\t\t\tthis.state.set('unlicensed')\n\t\t\t})\n\t}\n\n\tprivate getIsDevelopment(testEnvironment?: TestEnvironment) {\n\t\tif (testEnvironment === 'development') return true\n\t\tif (testEnvironment === 'production') return false\n\n\t\t// If we are using https on a non-localhost domain we assume it's a production env and a development one otherwise\n\t\treturn (\n\t\t\t!['https:', 'vscode-webview:'].includes(window.location.protocol) ||\n\t\t\twindow.location.hostname === 'localhost'\n\t\t)\n\t}\n\n\tprivate async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {\n\t\tconst [data, signature] = licenseKey.split('.')\n\t\tconst [prefix, encodedData] = data.split('/')\n\n\t\tif (!prefix.startsWith('tldraw-')) {\n\t\t\tthrow new Error(`Unsupported prefix '${prefix}'`)\n\t\t}\n\n\t\tconst publicCryptoKey = await importPublicKey(this.publicKey)\n\n\t\tlet isVerified\n\t\ttry {\n\t\t\tisVerified = await crypto.subtle.verify(\n\t\t\t\t{\n\t\t\t\t\tname: 'ECDSA',\n\t\t\t\t\thash: { name: 'SHA-256' },\n\t\t\t\t},\n\t\t\t\tpublicCryptoKey,\n\t\t\t\tnew Uint8Array(str2ab(atob(signature))),\n\t\t\t\tnew Uint8Array(str2ab(atob(encodedData)))\n\t\t\t)\n\t\t} catch (e) {\n\t\t\tconsole.error(e)\n\t\t\tthrow new Error('Could not perform signature validation')\n\t\t}\n\n\t\tif (!isVerified) {\n\t\t\tthrow new Error('Invalid signature')\n\t\t}\n\n\t\tlet decodedData: any\n\t\ttry {\n\t\t\tdecodedData = JSON.parse(atob(encodedData))\n\t\t} catch {\n\t\t\tthrow new Error('Could not parse object')\n\t\t}\n\t\tif (decodedData.length > NUMBER_OF_KNOWN_PROPERTIES) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'License key contains some unknown properties.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\n\t\treturn {\n\t\t\tid: decodedData[PROPERTIES.ID],\n\t\t\thosts: decodedData[PROPERTIES.HOSTS],\n\t\t\tflags: decodedData[PROPERTIES.FLAGS],\n\t\t\texpiryDate: decodedData[PROPERTIES.EXPIRY_DATE],\n\t\t}\n\t}\n\n\tasync getLicenseFromKey(licenseKey?: string): Promise<LicenseFromKeyResult> {\n\t\tif (!licenseKey) {\n\t\t\tif (!this.isDevelopment) {\n\t\t\t\tthis.outputNoLicenseKeyProvided()\n\t\t\t}\n\n\t\t\treturn { isLicenseParseable: false, reason: 'no-key-provided' }\n\t\t}\n\n\t\tif (this.isDevelopment && !this.isCryptoAvailable) {\n\t\t\tif (this.verbose) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t'tldraw: you seem to be in a development environment that does not support crypto. License not verified.'\n\t\t\t\t)\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log('You should check that this works in production separately.')\n\t\t\t}\n\t\t\t// We can't parse the license if we are in development mode since crypto\n\t\t\t// is not available on http\n\t\t\treturn { isLicenseParseable: false, reason: 'has-key-development-mode' }\n\t\t}\n\n\t\t// Borrowed idea from AG Grid:\n\t\t// Copying from various sources (like PDFs) can include zero-width characters.\n\t\t// This helps makes sure the key validation doesn't fail.\n\t\tlet cleanedLicenseKey = licenseKey.replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n\t\tcleanedLicenseKey = cleanedLicenseKey.replace(/\\r?\\n|\\r/g, '')\n\n\t\ttry {\n\t\t\tconst licenseInfo = await this.extractLicenseKey(cleanedLicenseKey)\n\t\t\tconst expiryDate = new Date(licenseInfo.expiryDate)\n\t\t\tconst isAnnualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.ANNUAL_LICENSE)\n\t\t\tconst isPerpetualLicense = this.isFlagEnabled(licenseInfo.flags, FLAGS.PERPETUAL_LICENSE)\n\n\t\t\tconst result: ValidLicenseKeyResult = {\n\t\t\t\tlicense: licenseInfo,\n\t\t\t\tisLicenseParseable: true,\n\t\t\t\tisDevelopment: this.isDevelopment,\n\t\t\t\tisDomainValid: this.isDomainValid(licenseInfo),\n\t\t\t\texpiryDate,\n\t\t\t\tisAnnualLicense,\n\t\t\t\tisAnnualLicenseExpired: isAnnualLicense && this.isAnnualLicenseExpired(expiryDate),\n\t\t\t\tisPerpetualLicense,\n\t\t\t\tisPerpetualLicenseExpired: isPerpetualLicense && this.isPerpetualLicenseExpired(expiryDate),\n\t\t\t\tisInternalLicense: this.isFlagEnabled(licenseInfo.flags, FLAGS.INTERNAL_LICENSE),\n\t\t\t\tisLicensedWithWatermark: this.isFlagEnabled(licenseInfo.flags, FLAGS.WITH_WATERMARK),\n\t\t\t}\n\t\t\tthis.outputLicenseInfoIfNeeded(result)\n\n\t\t\treturn result\n\t\t} catch (e: any) {\n\t\t\tthis.outputInvalidLicenseKey(e.message)\n\t\t\t// If the license can't be parsed, it's invalid\n\t\t\treturn { isLicenseParseable: false, reason: 'invalid-license-key' }\n\t\t}\n\t}\n\n\tprivate isDomainValid(licenseInfo: LicenseInfo) {\n\t\tconst currentHostname = window.location.hostname.toLowerCase()\n\n\t\treturn licenseInfo.hosts.some((host) => {\n\t\t\tconst normalizedHost = host.toLowerCase().trim()\n\n\t\t\t// Allow the domain if listed and www variations, 'example.com' allows 'example.com' and 'www.example.com'\n\t\t\tif (\n\t\t\t\tnormalizedHost === currentHostname ||\n\t\t\t\t`www.${normalizedHost}` === currentHostname ||\n\t\t\t\tnormalizedHost === `www.${currentHostname}`\n\t\t\t) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// If host is '*', we allow all domains.\n\t\t\tif (host === '*') {\n\t\t\t\t// All domains allowed.\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Glob testing, we only support '*.somedomain.com' right now.\n\t\t\tif (host.includes('*')) {\n\t\t\t\tconst globToRegex = new RegExp(host.replace(/\\*/g, '.*?'))\n\t\t\t\treturn globToRegex.test(currentHostname) || globToRegex.test(`www.${currentHostname}`)\n\t\t\t}\n\n\t\t\t// VSCode support\n\t\t\tif (window.location.protocol === 'vscode-webview:') {\n\t\t\t\tconst currentUrl = new URL(window.location.href)\n\t\t\t\tconst extensionId = currentUrl.searchParams.get('extensionId')\n\t\t\t\tif (normalizedHost === extensionId) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t})\n\t}\n\n\tprivate getExpirationDateWithoutGracePeriod(expiryDate: Date) {\n\t\treturn new Date(expiryDate.getFullYear(), expiryDate.getMonth(), expiryDate.getDate())\n\t}\n\n\tprivate getExpirationDateWithGracePeriod(expiryDate: Date) {\n\t\treturn new Date(\n\t\t\texpiryDate.getFullYear(),\n\t\t\texpiryDate.getMonth(),\n\t\t\texpiryDate.getDate() + GRACE_PERIOD_DAYS + 1 // Add 1 day to include the expiration day\n\t\t)\n\t}\n\n\tprivate isAnnualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst isExpired = new Date() >= expiration\n\t\t// If it is not expired yet (including the grace period), but after the expiry date we warn the users\n\t\tif (!isExpired && new Date() >= this.getExpirationDateWithoutGracePeriod(expiryDate)) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'tldraw license is about to expire, you are in a grace period.',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} if you would like to renew your license.`,\n\t\t\t])\n\t\t}\n\t\treturn isExpired\n\t}\n\n\tprivate isPerpetualLicenseExpired(expiryDate: Date) {\n\t\tconst expiration = this.getExpirationDateWithGracePeriod(expiryDate)\n\t\tconst dates = {\n\t\t\tmajor: new Date(publishDates.major),\n\t\t\tminor: new Date(publishDates.minor),\n\t\t}\n\t\t// We allow patch releases, but the major and minor releases should be within the expiration date\n\t\treturn dates.major >= expiration || dates.minor >= expiration\n\t}\n\n\tprivate isFlagEnabled(flags: number, flag: number) {\n\t\treturn (flags & flag) === flag\n\t}\n\n\tprivate outputNoLicenseKeyProvided() {\n\t\t// Noop, we don't need to show this message.\n\t\t// this.outputMessages([\n\t\t// \t'No tldraw license key provided!',\n\t\t// \t`Please reach out to ${LICENSE_EMAIL} if you would like to license tldraw or if you'd like a trial.`,\n\t\t// ])\n\t}\n\n\tprivate outputInvalidLicenseKey(msg: string) {\n\t\tthis.outputMessages(['Invalid tldraw license key', `Reason: ${msg}`])\n\t}\n\n\tprivate outputLicenseInfoIfNeeded(result: ValidLicenseKeyResult) {\n\t\tif (result.isAnnualLicenseExpired) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'Your tldraw license has expired!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} to renew.`,\n\t\t\t])\n\t\t}\n\n\t\tif (!result.isDomainValid && !result.isDevelopment) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'This tldraw license key is not valid for this domain!',\n\t\t\t\t`Please reach out to ${LICENSE_EMAIL} if you would like to use tldraw on other domains.`,\n\t\t\t])\n\t\t}\n\t\t// If we added a new flag it will be twice the value of the currently highest flag.\n\t\t// And if all the current flags are on we would get the `HIGHEST_FLAG * 2 - 1`, so anything higher than that means there are new flags.\n\t\tif (result.license.flags >= HIGHEST_FLAG * 2) {\n\t\t\tthis.outputMessages([\n\t\t\t\t'This tldraw license contains some unknown flags.',\n\t\t\t\t'You may want to update tldraw packages to a newer version to get access to new functionality.',\n\t\t\t])\n\t\t}\n\t}\n\n\tprivate outputMessages(messages: string[]) {\n\t\tif (this.isTest) return\n\t\tif (this.verbose) {\n\t\t\tthis.outputDelimiter()\n\t\t\tfor (const message of messages) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(\n\t\t\t\t\t`%c${message}`,\n\t\t\t\t\t`color: white; background: crimson; padding: 2px; border-radius: 3px;`\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.outputDelimiter()\n\t\t}\n\t}\n\n\tprivate outputDelimiter() {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(\n\t\t\t'%c-------------------------------------------------------------------',\n\t\t\t`color: white; background: crimson; padding: 2px; border-radius: 3px;`\n\t\t)\n\t}\n\n\tstatic className = 'tl-watermark_SEE-LICENSE'\n}\n\nexport function getLicenseState(result: LicenseFromKeyResult): LicenseState {\n\tif (!result.isLicenseParseable) return 'unlicensed'\n\tif (!result.isDomainValid && !result.isDevelopment) return 'unlicensed'\n\tif (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {\n\t\t// Check if it's an expired internal license with valid domain\n\t\tconst internalExpired = result.isInternalLicense && result.isDomainValid\n\t\treturn internalExpired ? 'internal-expired' : 'unlicensed'\n\t}\n\n\t// License is valid, determine if it has watermark\n\tif (result.isLicensedWithWatermark) {\n\t\treturn 'licensed-with-watermark'\n\t}\n\n\treturn 'licensed'\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
+ import { useValue } from "@tldraw/state-react";
2
3
  import { createContext, useContext, useState } from "react";
3
4
  import { LicenseManager } from "./LicenseManager.mjs";
4
5
  const LicenseContext = createContext({});
@@ -8,6 +9,10 @@ function LicenseProvider({
8
9
  children
9
10
  }) {
10
11
  const [licenseManager] = useState(() => new LicenseManager(licenseKey));
12
+ const licenseState = useValue(licenseManager.state);
13
+ if (licenseState === "internal-expired") {
14
+ return /* @__PURE__ */ jsx("div", { "data-testid": "tl-license-expired", style: { display: "none" } });
15
+ }
11
16
  return /* @__PURE__ */ jsx(LicenseContext.Provider, { value: licenseManager, children });
12
17
  }
13
18
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/LicenseProvider.tsx"],
4
- "sourcesContent": ["import { createContext, ReactNode, useContext, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport const useLicenseContext = () => useContext(LicenseContext)\n\n/** @internal */\nexport function LicenseProvider({\n\tlicenseKey,\n\tchildren,\n}: {\n\tlicenseKey?: string\n\tchildren: ReactNode\n}) {\n\tconst [licenseManager] = useState(() => new LicenseManager(licenseKey))\n\treturn <LicenseContext.Provider value={licenseManager}>{children}</LicenseContext.Provider>\n}\n"],
5
- "mappings": "AAkBQ;AAlBR,SAAS,eAA0B,YAAY,gBAAgB;AAC/D,SAAS,sBAAsB;AAGxB,MAAM,iBAAiB,cAAc,CAAC,CAAmB;AAGzD,MAAM,oBAAoB,MAAM,WAAW,cAAc;AAGzD,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AACD,GAGG;AACF,QAAM,CAAC,cAAc,IAAI,SAAS,MAAM,IAAI,eAAe,UAAU,CAAC;AACtE,SAAO,oBAAC,eAAe,UAAf,EAAwB,OAAO,gBAAiB,UAAS;AAClE;",
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { createContext, ReactNode, useContext, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport const useLicenseContext = () => useContext(LicenseContext)\n\n/** @internal */\nexport function LicenseProvider({\n\tlicenseKey,\n\tchildren,\n}: {\n\tlicenseKey?: string\n\tchildren: ReactNode\n}) {\n\tconst [licenseManager] = useState(() => new LicenseManager(licenseKey))\n\tconst licenseState = useValue(licenseManager.state)\n\n\t// If internal license has expired, don't render the editor at all\n\tif (licenseState === 'internal-expired') {\n\t\treturn <div data-testid=\"tl-license-expired\" style={{ display: 'none' }} />\n\t}\n\n\treturn <LicenseContext.Provider value={licenseManager}>{children}</LicenseContext.Provider>\n}\n"],
5
+ "mappings": "AAuBS;AAvBT,SAAS,gBAAgB;AACzB,SAAS,eAA0B,YAAY,gBAAgB;AAC/D,SAAS,sBAAsB;AAGxB,MAAM,iBAAiB,cAAc,CAAC,CAAmB;AAGzD,MAAM,oBAAoB,MAAM,WAAW,cAAc;AAGzD,SAAS,gBAAgB;AAAA,EAC/B;AAAA,EACA;AACD,GAGG;AACF,QAAM,CAAC,cAAc,IAAI,SAAS,MAAM,IAAI,eAAe,UAAU,CAAC;AACtE,QAAM,eAAe,SAAS,eAAe,KAAK;AAGlD,MAAI,iBAAiB,oBAAoB;AACxC,WAAO,oBAAC,SAAI,eAAY,sBAAqB,OAAO,EAAE,SAAS,OAAO,GAAG;AAAA,EAC1E;AAEA,SAAO,oBAAC,eAAe,UAAf,EAAwB,OAAO,gBAAiB,UAAS;AAClE;",
6
6
  "names": []
7
7
  }
@@ -76,15 +76,15 @@ To remove the watermark, please purchase a license at tldraw.dev.
76
76
 
77
77
  .${className} {
78
78
  position: absolute;
79
- bottom: var(--space-2);
80
- right: var(--space-2);
79
+ bottom: max(var(--tl-space-2), env(safe-area-inset-bottom));
80
+ right: max(var(--tl-space-2), env(safe-area-inset-right));
81
81
  width: 96px;
82
82
  height: 32px;
83
83
  display: flex;
84
84
  align-items: center;
85
85
  justify-content: center;
86
- z-index: var(--layer-watermark) !important;
87
- background-color: color-mix(in srgb, var(--color-background) 62%, transparent);
86
+ z-index: var(--tl-layer-watermark) !important;
87
+ background-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);
88
88
  opacity: 1;
89
89
  border-radius: 5px;
90
90
  pointer-events: all;
@@ -98,7 +98,7 @@ To remove the watermark, please purchase a license at tldraw.dev.
98
98
  height: 32px;
99
99
  pointer-events: all;
100
100
  cursor: inherit;
101
- color: var(--color-text);
101
+ color: var(--tl-color-text);
102
102
  opacity: .38;
103
103
  border: 0;
104
104
  padding: 0;
@@ -106,12 +106,12 @@ To remove the watermark, please purchase a license at tldraw.dev.
106
106
  }
107
107
 
108
108
  .${className}[data-debug='true'] {
109
- bottom: 46px;
109
+ bottom: max(46px, env(safe-area-inset-bottom));
110
110
  }
111
111
 
112
112
  .${className}[data-mobile='true'] {
113
113
  border-radius: 4px 0px 0px 4px;
114
- right: -2px;
114
+ right: max(-2px, calc(env(safe-area-inset-right) - 2px));
115
115
  width: 8px;
116
116
  height: 48px;
117
117
  }
@@ -127,7 +127,7 @@ To remove the watermark, please purchase a license at tldraw.dev.
127
127
  }
128
128
 
129
129
  .${className}:hover {
130
- background-color: var(--color-background);
130
+ background-color: var(--tl-color-background);
131
131
  transition: background-color 0.2s ease-in-out;
132
132
  transition-delay: 0.32s;
133
133
  }
@@ -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 { 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<button\n\t\t\t\tdraggable={false}\n\t\t\t\trole=\"button\"\n\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}}\n\t\t\t\ttitle=\"made with tldraw\"\n\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\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} > button {\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\tborder: 0;\n\t\tpadding: 0;\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'] > button {\n\t\twidth: 8px;\n\t\theight: 32px;\n\t}\n\n\t@media (hover: hover) {\n\t\t.${className} > button {\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 > button {\n\t\t\tanimation: ${className}_delayed_link 0.2s forwards ease-in-out;\n\t\t\tanimation-delay: 0.32s;\n\t\t}\n\n\t\t.${className} > button:focus-visible {\n\t\t\topacity: 1;\n\t\t}\n\t}\n\n\n\t@keyframes ${className}_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"],
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { memo, useRef } from 'react'\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<button\n\t\t\t\tdraggable={false}\n\t\t\t\trole=\"button\"\n\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\tstopEventPropagation(e)\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}}\n\t\t\t\ttitle=\"made with tldraw\"\n\t\t\t\tonClick={() => runtime.openWindow(url, '_blank')}\n\t\t\t\tstyle={{ mask: maskCss, WebkitMask: maskCss }}\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: max(var(--tl-space-2), env(safe-area-inset-bottom));\n\t\tright: max(var(--tl-space-2), env(safe-area-inset-right));\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(--tl-layer-watermark) !important;\n\t\tbackground-color: color-mix(in srgb, var(--tl-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} > button {\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(--tl-color-text);\n\t\topacity: .38;\n\t\tborder: 0;\n\t\tpadding: 0;\n\t\tbackground-color: currentColor;\n\t}\n\n\t.${className}[data-debug='true'] {\n\t\tbottom: max(46px, env(safe-area-inset-bottom));\n\t}\n\n\t.${className}[data-mobile='true'] {\n\t\tborder-radius: 4px 0px 0px 4px;\n\t\tright: max(-2px, calc(env(safe-area-inset-right) - 2px));\n\t\twidth: 8px;\n\t\theight: 48px;\n\t}\n\n\t.${className}[data-mobile='true'] > button {\n\t\twidth: 8px;\n\t\theight: 32px;\n\t}\n\n\t@media (hover: hover) {\n\t\t.${className} > button {\n\t\t\tpointer-events: none;\n\t\t}\n\n\t\t.${className}:hover {\n\t\t\tbackground-color: var(--tl-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 > button {\n\t\t\tanimation: ${className}_delayed_link 0.2s forwards ease-in-out;\n\t\t\tanimation-delay: 0.32s;\n\t\t}\n\n\t\t.${className} > button:focus-visible {\n\t\t\topacity: 1;\n\t\t}\n\t}\n\n\n\t@keyframes ${className}_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
5
  "mappings": "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",
6
6
  "names": ["Watermark", "WatermarkInner", "LicenseStyles"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/license/useLicenseManagerState.ts"],
4
- "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport function useLicenseManagerState(licenseManager: LicenseManager) {\n\treturn useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AAIlB,SAAS,uBAAuB,gBAAgC;AACtE,SAAO,SAAS,kBAAkB,MAAM,eAAe,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC;AACrF;",
4
+ "sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { LicenseManager, LicenseState } from './LicenseManager'\n\n/** @internal */\nexport function useLicenseManagerState(licenseManager: LicenseManager): LicenseState {\n\treturn useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AAIlB,SAAS,uBAAuB,gBAA8C;AACpF,SAAO,SAAS,kBAAkB,MAAM,eAAe,MAAM,IAAI,GAAG,CAAC,cAAc,CAAC;AACrF;",
6
6
  "names": []
7
7
  }
@@ -11,6 +11,12 @@ const defaultTldrawOptions = {
11
11
  // 6 squared
12
12
  dragDistanceSquared: 16,
13
13
  // 4 squared
14
+ uiDragDistanceSquared: 16,
15
+ // 4 squared
16
+ // it's really easy to accidentally drag from the toolbar on mobile, so we use a much larger
17
+ // threshold than usual here to try and prevent accidental drags.
18
+ uiCoarseDragDistanceSquared: 625,
19
+ // 25 squared
14
20
  defaultSvgPadding: 32,
15
21
  cameraSlideFriction: 0.09,
16
22
  gridSteps: [
@@ -38,6 +44,7 @@ const defaultTldrawOptions = {
38
44
  flattenImageBoundsPadding: 16,
39
45
  laserDelayMs: 1200,
40
46
  maxExportDelayMs: 5e3,
47
+ tooltipDelayMs: 700,
41
48
  temporaryAssetPreviewLifetimeMs: 18e4,
42
49
  actionShortcutsLocation: "swap",
43
50
  createTextOnCanvasDoubleClick: true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/options.ts"],
4
- "sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n\t/**\n\t * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.\n\t */\n\treadonly enableToolbarKeyboardShortcuts: boolean\n\t/**\n\t * The maximum number of fonts that will be loaded while blocking the main rendering of the\n\t * canvas. If there are more than this number of fonts needed, we'll just show the canvas right\n\t * away and let the fonts load in in the background.\n\t */\n\treadonly maxFontsToLoadBeforeRender: number\n\t/**\n\t * If you have a CSP policy that blocks inline styles, you can use this prop to provide a\n\t * nonce to use in the editor's styles.\n\t */\n\treadonly nonce: string | undefined\n\t/**\n\t * Branding name of the app, currently only used for adding aria-label for the application.\n\t */\n\treadonly branding?: string\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n\tenableToolbarKeyboardShortcuts: true,\n\tmaxFontsToLoadBeforeRender: Infinity,\n\tnonce: undefined,\n} as const satisfies TldrawOptions\n"],
5
- "mappings": "AAAA,SAAwB,gBAAgB;AAyFjC,MAAM,uBAAuB;AAAA,EACnC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAC3B,qBAAqB;AAAA;AAAA,EACrB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,WAAW;AAAA,IACV,EAAE,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG;AAAA,IAC/B,EAAE,KAAK,MAAM,KAAK,OAAO,MAAM,GAAG;AAAA,IAClC,EAAE,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE;AAAA,IAC7B,EAAE,KAAK,KAAK,KAAK,KAAK,MAAM,EAAE;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,iCAAiC;AAAA,EACjC,yBAAyB;AAAA,EACzB,+BAA+B;AAAA,EAC/B,gBAAgB;AAAA,EAChB,gCAAgC;AAAA,EAChC,4BAA4B;AAAA,EAC5B,OAAO;AACR;",
4
+ "sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly uiDragDistanceSquared: number\n\treadonly uiCoarseDragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\treadonly tooltipDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n\t/**\n\t * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.\n\t */\n\treadonly enableToolbarKeyboardShortcuts: boolean\n\t/**\n\t * The maximum number of fonts that will be loaded while blocking the main rendering of the\n\t * canvas. If there are more than this number of fonts needed, we'll just show the canvas right\n\t * away and let the fonts load in in the background.\n\t */\n\treadonly maxFontsToLoadBeforeRender: number\n\t/**\n\t * If you have a CSP policy that blocks inline styles, you can use this prop to provide a\n\t * nonce to use in the editor's styles.\n\t */\n\treadonly nonce: string | undefined\n\t/**\n\t * Branding name of the app, currently only used for adding aria-label for the application.\n\t */\n\treadonly branding?: string\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tuiDragDistanceSquared: 16, // 4 squared\n\t// it's really easy to accidentally drag from the toolbar on mobile, so we use a much larger\n\t// threshold than usual here to try and prevent accidental drags.\n\tuiCoarseDragDistanceSquared: 625, // 25 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttooltipDelayMs: 700,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n\tenableToolbarKeyboardShortcuts: true,\n\tmaxFontsToLoadBeforeRender: Infinity,\n\tnonce: undefined,\n} as const satisfies TldrawOptions\n"],
5
+ "mappings": "AAAA,SAAwB,gBAAgB;AA4FjC,MAAM,uBAAuB;AAAA,EACnC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAC3B,qBAAqB;AAAA;AAAA,EACrB,uBAAuB;AAAA;AAAA;AAAA;AAAA,EAGvB,6BAA6B;AAAA;AAAA,EAC7B,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,WAAW;AAAA,IACV,EAAE,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG;AAAA,IAC/B,EAAE,KAAK,MAAM,KAAK,OAAO,MAAM,GAAG;AAAA,IAClC,EAAE,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE;AAAA,IAC7B,EAAE,KAAK,KAAK,KAAK,KAAK,MAAM,EAAE;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,iCAAiC;AAAA,EACjC,yBAAyB;AAAA,EACzB,+BAA+B;AAAA,EAC/B,gBAAgB;AAAA,EAChB,gCAAgC;AAAA,EAChC,4BAA4B;AAAA,EAC5B,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { Vec } from "./Vec.mjs";
2
- import { PI, PI2, toPrecision } from "./utils.mjs";
2
+ import { approximatelyLte, PI, PI2, toPrecision } from "./utils.mjs";
3
3
  class Box {
4
4
  constructor(x = 0, y = 0, w = 0, h = 0) {
5
5
  this.x = x;
@@ -329,6 +329,9 @@ class Box {
329
329
  static Contains(A, B) {
330
330
  return A.minX < B.minX && A.minY < B.minY && A.maxY > B.maxY && A.maxX > B.maxX;
331
331
  }
332
+ static ContainsApproximately(A, B, precision) {
333
+ return approximatelyLte(A.minX, B.minX, precision) && approximatelyLte(A.minY, B.minY, precision) && approximatelyLte(B.maxX, A.maxX, precision) && approximatelyLte(B.maxY, A.maxY, precision);
334
+ }
332
335
  static Includes(A, B) {
333
336
  return Box.Collides(A, B) || Box.Contains(A, B);
334
337
  }