@tldraw/editor 3.16.0-canary.7facbd2d2b7f → 3.16.0-canary.806d674b7d7a

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 (69) hide show
  1. package/dist-cjs/index.d.ts +28 -27
  2. package/dist-cjs/index.js +4 -2
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +2 -0
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -4
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  8. package/dist-cjs/lib/editor/Editor.js +0 -29
  9. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  10. package/dist-cjs/lib/hooks/useCanvasEvents.js +17 -17
  11. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  12. package/dist-cjs/lib/hooks/useDocumentEvents.js +4 -4
  13. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  14. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -1
  15. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  16. package/dist-cjs/lib/hooks/useHandleEvents.js +6 -6
  17. package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
  18. package/dist-cjs/lib/hooks/useSelectionEvents.js +8 -8
  19. package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
  20. package/dist-cjs/lib/license/Watermark.js +90 -97
  21. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  22. package/dist-cjs/lib/utils/dom.js +12 -1
  23. package/dist-cjs/lib/utils/dom.js.map +2 -2
  24. package/dist-cjs/lib/utils/getPointerInfo.js +3 -2
  25. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  26. package/dist-cjs/version.js +3 -3
  27. package/dist-cjs/version.js.map +1 -1
  28. package/dist-esm/index.d.mts +28 -27
  29. package/dist-esm/index.mjs +7 -3
  30. package/dist-esm/index.mjs.map +2 -2
  31. package/dist-esm/lib/TldrawEditor.mjs +2 -0
  32. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  33. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -5
  34. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  35. package/dist-esm/lib/editor/Editor.mjs +0 -29
  36. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  37. package/dist-esm/lib/hooks/useCanvasEvents.mjs +24 -18
  38. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  39. package/dist-esm/lib/hooks/useDocumentEvents.mjs +10 -5
  40. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  41. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -2
  42. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  43. package/dist-esm/lib/hooks/useHandleEvents.mjs +12 -7
  44. package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
  45. package/dist-esm/lib/hooks/useSelectionEvents.mjs +15 -9
  46. package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
  47. package/dist-esm/lib/license/Watermark.mjs +91 -98
  48. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  49. package/dist-esm/lib/utils/dom.mjs +12 -1
  50. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  51. package/dist-esm/lib/utils/getPointerInfo.mjs +3 -2
  52. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  53. package/dist-esm/version.mjs +3 -3
  54. package/dist-esm/version.mjs.map +1 -1
  55. package/package.json +7 -7
  56. package/src/index.ts +2 -0
  57. package/src/lib/TldrawEditor.tsx +2 -0
  58. package/src/lib/components/default-components/DefaultCanvas.tsx +5 -5
  59. package/src/lib/editor/Editor.ts +0 -33
  60. package/src/lib/hooks/useCanvasEvents.ts +24 -18
  61. package/src/lib/hooks/useDocumentEvents.ts +10 -5
  62. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
  63. package/src/lib/hooks/useHandleEvents.ts +12 -7
  64. package/src/lib/hooks/useSelectionEvents.ts +15 -9
  65. package/src/lib/license/Watermark.tsx +92 -100
  66. package/src/lib/utils/dom.test.ts +24 -33
  67. package/src/lib/utils/dom.ts +31 -1
  68. package/src/lib/utils/getPointerInfo.ts +3 -3
  69. package/src/version.ts +3 -3
@@ -1,7 +1,13 @@
1
1
  import { useValue } from '@tldraw/state-react'
2
2
  import React, { useEffect, useMemo } from 'react'
3
3
  import { RIGHT_MOUSE_BUTTON } from '../constants'
4
- import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
4
+ import {
5
+ markEventAsHandled,
6
+ preventDefault,
7
+ releasePointerCapture,
8
+ setPointerCapture,
9
+ wasEventAlreadyHandled,
10
+ } from '../utils/dom'
5
11
  import { getPointerInfo } from '../utils/getPointerInfo'
6
12
  import { useEditor } from './useEditor'
7
13
 
@@ -12,14 +18,14 @@ export function useCanvasEvents() {
12
18
  const events = useMemo(
13
19
  function canvasEvents() {
14
20
  function onPointerDown(e: React.PointerEvent) {
15
- if (editor.wasEventAlreadyHandled(e)) return
21
+ if (wasEventAlreadyHandled(e)) return
16
22
 
17
23
  if (e.button === RIGHT_MOUSE_BUTTON) {
18
24
  editor.dispatch({
19
25
  type: 'pointer',
20
26
  target: 'canvas',
21
27
  name: 'right_click',
22
- ...getPointerInfo(editor, e),
28
+ ...getPointerInfo(e),
23
29
  })
24
30
  return
25
31
  }
@@ -32,12 +38,12 @@ export function useCanvasEvents() {
32
38
  type: 'pointer',
33
39
  target: 'canvas',
34
40
  name: 'pointer_down',
35
- ...getPointerInfo(editor, e),
41
+ ...getPointerInfo(e),
36
42
  })
37
43
  }
38
44
 
39
45
  function onPointerUp(e: React.PointerEvent) {
40
- if (editor.wasEventAlreadyHandled(e)) return
46
+ if (wasEventAlreadyHandled(e)) return
41
47
  if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return
42
48
 
43
49
  releasePointerCapture(e.currentTarget, e)
@@ -46,33 +52,33 @@ export function useCanvasEvents() {
46
52
  type: 'pointer',
47
53
  target: 'canvas',
48
54
  name: 'pointer_up',
49
- ...getPointerInfo(editor, e),
55
+ ...getPointerInfo(e),
50
56
  })
51
57
  }
52
58
 
53
59
  function onPointerEnter(e: React.PointerEvent) {
54
- if (editor.wasEventAlreadyHandled(e)) return
60
+ if (wasEventAlreadyHandled(e)) return
55
61
  if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
56
62
  const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
57
63
  editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
58
64
  }
59
65
 
60
66
  function onPointerLeave(e: React.PointerEvent) {
61
- if (editor.wasEventAlreadyHandled(e)) return
67
+ if (wasEventAlreadyHandled(e)) return
62
68
  if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
63
69
  const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
64
70
  editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
65
71
  }
66
72
 
67
73
  function onTouchStart(e: React.TouchEvent) {
68
- if (editor.wasEventAlreadyHandled(e)) return
69
- editor.markEventAsHandled(e)
74
+ if (wasEventAlreadyHandled(e)) return
75
+ markEventAsHandled(e)
70
76
  preventDefault(e)
71
77
  }
72
78
 
73
79
  function onTouchEnd(e: React.TouchEvent) {
74
- if (editor.wasEventAlreadyHandled(e)) return
75
- editor.markEventAsHandled(e)
80
+ if (wasEventAlreadyHandled(e)) return
81
+ markEventAsHandled(e)
76
82
  // check that e.target is an HTMLElement
77
83
  if (!(e.target instanceof HTMLElement)) return
78
84
 
@@ -91,12 +97,12 @@ export function useCanvasEvents() {
91
97
  }
92
98
 
93
99
  function onDragOver(e: React.DragEvent<Element>) {
94
- if (editor.wasEventAlreadyHandled(e)) return
100
+ if (wasEventAlreadyHandled(e)) return
95
101
  preventDefault(e)
96
102
  }
97
103
 
98
104
  async function onDrop(e: React.DragEvent<Element>) {
99
- if (editor.wasEventAlreadyHandled(e)) return
105
+ if (wasEventAlreadyHandled(e)) return
100
106
  preventDefault(e)
101
107
  e.stopPropagation()
102
108
 
@@ -123,7 +129,7 @@ export function useCanvasEvents() {
123
129
  }
124
130
 
125
131
  function onClick(e: React.MouseEvent) {
126
- if (editor.wasEventAlreadyHandled(e)) return
132
+ if (wasEventAlreadyHandled(e)) return
127
133
  e.stopPropagation()
128
134
  }
129
135
 
@@ -151,8 +157,8 @@ export function useCanvasEvents() {
151
157
  let lastX: number, lastY: number
152
158
 
153
159
  function onPointerMove(e: PointerEvent) {
154
- if (editor.wasEventAlreadyHandled(e)) return
155
- editor.markEventAsHandled(e)
160
+ if (wasEventAlreadyHandled(e)) return
161
+ markEventAsHandled(e)
156
162
 
157
163
  if (e.clientX === lastX && e.clientY === lastY) return
158
164
  lastX = e.clientX
@@ -168,7 +174,7 @@ export function useCanvasEvents() {
168
174
  type: 'pointer',
169
175
  target: 'canvas',
170
176
  name: 'pointer_move',
171
- ...getPointerInfo(editor, singleEvent),
177
+ ...getPointerInfo(singleEvent),
172
178
  })
173
179
  }
174
180
  }
@@ -2,7 +2,12 @@ import { useValue } from '@tldraw/state-react'
2
2
  import { useEffect } from 'react'
3
3
  import { Editor } from '../editor/Editor'
4
4
  import { TLKeyboardEventInfo } from '../editor/types/event-types'
5
- import { activeElementShouldCaptureKeys, preventDefault } from '../utils/dom'
5
+ import {
6
+ activeElementShouldCaptureKeys,
7
+ markEventAsHandled,
8
+ preventDefault,
9
+ wasEventAlreadyHandled,
10
+ } from '../utils/dom'
6
11
  import { isAccelKey } from '../utils/keyboard'
7
12
  import { useContainer } from './useContainer'
8
13
  import { useEditor } from './useEditor'
@@ -103,8 +108,8 @@ export function useDocumentEvents() {
103
108
  preventDefault(e)
104
109
  }
105
110
 
106
- if (editor.wasEventAlreadyHandled(e)) return
107
- editor.markEventAsHandled(e)
111
+ if (wasEventAlreadyHandled(e)) return
112
+ markEventAsHandled(e)
108
113
  const hasSelectedShapes = !!editor.getSelectedShapeIds().length
109
114
 
110
115
  switch (e.key) {
@@ -211,8 +216,8 @@ export function useDocumentEvents() {
211
216
  }
212
217
 
213
218
  const handleKeyUp = (e: KeyboardEvent) => {
214
- if (editor.wasEventAlreadyHandled(e)) return
215
- editor.markEventAsHandled(e)
219
+ if (wasEventAlreadyHandled(e)) return
220
+ markEventAsHandled(e)
216
221
 
217
222
  if (areShortcutsDisabled(editor)) {
218
223
  return
@@ -1,5 +1,5 @@
1
1
  import { useEffect } from 'react'
2
- import { preventDefault } from '../utils/dom'
2
+ import { markEventAsHandled, preventDefault } from '../utils/dom'
3
3
  import { useEditor } from './useEditor'
4
4
 
5
5
  const IGNORED_TAGS = ['textarea', 'input']
@@ -19,7 +19,7 @@ export function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLE
19
19
 
20
20
  const handleEvent = (e: PointerEvent | TouchEvent) => {
21
21
  if (e instanceof PointerEvent && e.pointerType === 'pen') {
22
- editor.markEventAsHandled(e)
22
+ markEventAsHandled(e)
23
23
  const { target } = e
24
24
 
25
25
  // Allow events to propagate if the app is editing a shape, or if the event is occurring in a text area or input
@@ -1,7 +1,12 @@
1
1
  import { TLArrowShape, TLLineShape, TLShapeId } from '@tldraw/tlschema'
2
2
  import * as React from 'react'
3
3
  import { Editor } from '../editor/Editor'
4
- import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
4
+ import {
5
+ loopToHtmlElement,
6
+ releasePointerCapture,
7
+ setPointerCapture,
8
+ wasEventAlreadyHandled,
9
+ } from '../utils/dom'
5
10
  import { getPointerInfo } from '../utils/getPointerInfo'
6
11
  import { useEditor } from './useEditor'
7
12
 
@@ -16,7 +21,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
16
21
 
17
22
  return React.useMemo(() => {
18
23
  const onPointerDown = (e: React.PointerEvent) => {
19
- if (editor.wasEventAlreadyHandled(e)) return
24
+ if (wasEventAlreadyHandled(e)) return
20
25
 
21
26
  // Must set pointer capture on an HTML element!
22
27
  const target = loopToHtmlElement(e.currentTarget)
@@ -32,7 +37,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
32
37
  handle,
33
38
  shape,
34
39
  name: 'pointer_down',
35
- ...getPointerInfo(editor, e),
40
+ ...getPointerInfo(e),
36
41
  })
37
42
  }
38
43
 
@@ -40,7 +45,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
40
45
  let lastX: number, lastY: number
41
46
 
42
47
  const onPointerMove = (e: React.PointerEvent) => {
43
- if (editor.wasEventAlreadyHandled(e)) return
48
+ if (wasEventAlreadyHandled(e)) return
44
49
  if (e.clientX === lastX && e.clientY === lastY) return
45
50
  lastX = e.clientX
46
51
  lastY = e.clientY
@@ -55,12 +60,12 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
55
60
  handle,
56
61
  shape,
57
62
  name: 'pointer_move',
58
- ...getPointerInfo(editor, e),
63
+ ...getPointerInfo(e),
59
64
  })
60
65
  }
61
66
 
62
67
  const onPointerUp = (e: React.PointerEvent) => {
63
- if (editor.wasEventAlreadyHandled(e)) return
68
+ if (wasEventAlreadyHandled(e)) return
64
69
 
65
70
  const target = loopToHtmlElement(e.currentTarget)
66
71
  releasePointerCapture(target, e)
@@ -75,7 +80,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
75
80
  handle,
76
81
  shape,
77
82
  name: 'pointer_up',
78
- ...getPointerInfo(editor, e),
83
+ ...getPointerInfo(e),
79
84
  })
80
85
  }
81
86
 
@@ -1,7 +1,13 @@
1
1
  import { useMemo } from 'react'
2
2
  import { RIGHT_MOUSE_BUTTON } from '../constants'
3
3
  import { TLSelectionHandle } from '../editor/types/selection-types'
4
- import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
4
+ import {
5
+ loopToHtmlElement,
6
+ markEventAsHandled,
7
+ releasePointerCapture,
8
+ setPointerCapture,
9
+ wasEventAlreadyHandled,
10
+ } from '../utils/dom'
5
11
  import { getPointerInfo } from '../utils/getPointerInfo'
6
12
  import { useEditor } from './useEditor'
7
13
 
@@ -12,7 +18,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
12
18
  const events = useMemo(
13
19
  function selectionEvents() {
14
20
  const onPointerDown: React.PointerEventHandler = (e) => {
15
- if (editor.wasEventAlreadyHandled(e)) return
21
+ if (wasEventAlreadyHandled(e)) return
16
22
 
17
23
  if (e.button === RIGHT_MOUSE_BUTTON) {
18
24
  editor.dispatch({
@@ -20,7 +26,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
20
26
  target: 'selection',
21
27
  handle,
22
28
  name: 'right_click',
23
- ...getPointerInfo(editor, e),
29
+ ...getPointerInfo(e),
24
30
  })
25
31
  return
26
32
  }
@@ -47,16 +53,16 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
47
53
  type: 'pointer',
48
54
  target: 'selection',
49
55
  handle,
50
- ...getPointerInfo(editor, e),
56
+ ...getPointerInfo(e),
51
57
  })
52
- editor.markEventAsHandled(e)
58
+ markEventAsHandled(e)
53
59
  }
54
60
 
55
61
  // Track the last screen point
56
62
  let lastX: number, lastY: number
57
63
 
58
64
  function onPointerMove(e: React.PointerEvent) {
59
- if (editor.wasEventAlreadyHandled(e)) return
65
+ if (wasEventAlreadyHandled(e)) return
60
66
  if (e.button !== 0) return
61
67
  if (e.clientX === lastX && e.clientY === lastY) return
62
68
  lastX = e.clientX
@@ -67,12 +73,12 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
67
73
  type: 'pointer',
68
74
  target: 'selection',
69
75
  handle,
70
- ...getPointerInfo(editor, e),
76
+ ...getPointerInfo(e),
71
77
  })
72
78
  }
73
79
 
74
80
  const onPointerUp: React.PointerEventHandler = (e) => {
75
- if (editor.wasEventAlreadyHandled(e)) return
81
+ if (wasEventAlreadyHandled(e)) return
76
82
  if (e.button !== 0) return
77
83
 
78
84
  editor.dispatch({
@@ -80,7 +86,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
80
86
  type: 'pointer',
81
87
  target: 'selection',
82
88
  handle,
83
- ...getPointerInfo(editor, e),
89
+ ...getPointerInfo(e),
84
90
  })
85
91
  }
86
92
 
@@ -3,7 +3,7 @@ import { memo, useRef } from 'react'
3
3
  import { useCanvasEvents } from '../hooks/useCanvasEvents'
4
4
  import { useEditor } from '../hooks/useEditor'
5
5
  import { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'
6
- import { preventDefault } from '../utils/dom'
6
+ import { markEventAsHandled, preventDefault } from '../utils/dom'
7
7
  import { runtime } from '../utils/runtime'
8
8
  import { watermarkDesktopSvg, watermarkMobileSvg } from '../watermarks'
9
9
  import { LicenseManager } from './LicenseManager'
@@ -43,13 +43,11 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
43
43
  isDebugMode: boolean
44
44
  isMobile: boolean
45
45
  }) {
46
- const editor = useEditor()
47
46
  const events = useCanvasEvents()
48
47
  const ref = useRef<HTMLDivElement>(null)
49
48
  usePassThroughWheelEvents(ref)
50
49
 
51
- const url =
52
- 'https://tldraw.dev/pricing?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'
50
+ const url = 'https://tldraw.dev/?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'
53
51
 
54
52
  return (
55
53
  <div
@@ -66,13 +64,26 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
66
64
  draggable={false}
67
65
  role="button"
68
66
  onPointerDown={(e) => {
69
- editor.markEventAsHandled(e)
67
+ markEventAsHandled(e)
70
68
  preventDefault(e)
71
69
  }}
72
- title="The tldraw SDK requires a license key to work in production. You can get a free 100-day trial license at tldraw.dev/pricing."
70
+ title="Unlicensed - click to get a license"
73
71
  onClick={() => runtime.openWindow(url, '_blank')}
72
+ style={{
73
+ position: 'absolute',
74
+ pointerEvents: 'all',
75
+ cursor: 'pointer',
76
+ color: 'var(--tl-color-text)',
77
+ opacity: 0.8,
78
+ border: 0,
79
+ padding: 0,
80
+ backgroundColor: 'transparent',
81
+ fontSize: '11px',
82
+ fontWeight: '600',
83
+ textAlign: 'center',
84
+ }}
74
85
  >
75
- Get a license for production
86
+ Unlicensed
76
87
  </button>
77
88
  </div>
78
89
  )
@@ -116,10 +127,10 @@ const WatermarkInner = memo(function WatermarkInner({
116
127
  draggable={false}
117
128
  role="button"
118
129
  onPointerDown={(e) => {
119
- editor.markEventAsHandled(e)
130
+ markEventAsHandled(e)
120
131
  preventDefault(e)
121
132
  }}
122
- title="Build infinite canvas applications with the tldraw SDK. Learn more at https://tldraw.dev."
133
+ title="made with tldraw"
123
134
  onClick={() => runtime.openWindow(url, '_blank')}
124
135
  style={{ mask: maskCss, WebkitMask: maskCss }}
125
136
  />
@@ -131,8 +142,7 @@ const LicenseStyles = memo(function LicenseStyles() {
131
142
  const editor = useEditor()
132
143
  const className = LicenseManager.className
133
144
 
134
- const CSS = `
135
- /* ------------------- SEE LICENSE -------------------
145
+ const CSS = `/* ------------------- SEE LICENSE -------------------
136
146
  The tldraw watermark is part of tldraw's license. It is shown for unlicensed
137
147
  or "licensed-with-watermark" users. By using this library, you agree to
138
148
  preserve the watermark's behavior, keeping it visible, unobscured, and
@@ -141,105 +151,87 @@ available to user-interaction.
141
151
  To remove the watermark, please purchase a license at tldraw.dev.
142
152
  */
143
153
 
144
- .${className} {
145
- position: absolute;
146
- bottom: max(var(--tl-space-2), env(safe-area-inset-bottom));
147
- right: max(var(--tl-space-2), env(safe-area-inset-right));
148
- width: 96px;
149
- height: 32px;
150
- display: flex;
151
- align-items: center;
152
- justify-content: center;
153
- z-index: var(--tl-layer-watermark) !important;
154
- background-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);
155
- opacity: 1;
156
- border-radius: 5px;
157
- pointer-events: all;
158
- padding: 2px;
159
- box-sizing: content-box;
160
- }
161
-
162
- .${className} > button {
163
- position: absolute;
164
- width: 96px;
165
- height: 32px;
166
- pointer-events: all;
167
- cursor: inherit;
168
- color: var(--tl-color-text);
169
- opacity: .38;
170
- border: 0;
171
- padding: 0;
172
- background-color: currentColor;
173
- }
174
-
175
- .${className}[data-debug='true'] {
176
- bottom: max(46px, env(safe-area-inset-bottom));
177
- }
178
-
179
- .${className}[data-mobile='true'] {
180
- border-radius: 4px 0px 0px 4px;
181
- right: max(-2px, calc(env(safe-area-inset-right) - 2px));
182
- width: 8px;
183
- height: 48px;
184
- }
185
-
186
- .${className}[data-mobile='true'] > button {
187
- width: 8px;
188
- height: 32px;
189
- }
190
-
191
- .${className}[data-unlicensed='true'] > button {
192
- font-size: 100px;
193
- position: absolute;
194
- pointer-events: all;
195
- cursor: pointer;
196
- color: var(--tl-color-text);
197
- opacity: 0.8;
198
- border: 0;
199
- padding: 0;
200
- background-color: transparent;
201
- font-size: 11px;
202
- font-weight: 600;
203
- text-align: center;
204
- }
205
-
206
- .${className}[data-mobile='true'][data-unlicensed='true'] > button {
207
- display: none;
208
- }
209
-
210
- @media (hover: hover) {
211
- .${className}[data-licensed='false'] > button {
212
- pointer-events: none;
154
+ .${className} {
155
+ position: absolute;
156
+ bottom: max(var(--tl-space-2), env(safe-area-inset-bottom));
157
+ right: max(var(--tl-space-2), env(safe-area-inset-right));
158
+ width: 96px;
159
+ height: 32px;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ z-index: var(--tl-layer-watermark) !important;
164
+ background-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);
165
+ opacity: 1;
166
+ border-radius: 5px;
167
+ pointer-events: all;
168
+ padding: 2px;
169
+ box-sizing: content-box;
213
170
  }
214
171
 
215
- .${className}[data-licensed='false']:hover {
216
- background-color: var(--tl-color-background);
217
- transition: background-color 0.2s ease-in-out;
218
- transition-delay: 0.32s;
172
+ .${className} > button {
173
+ position: absolute;
174
+ width: 96px;
175
+ height: 32px;
176
+ pointer-events: all;
177
+ cursor: inherit;
178
+ color: var(--tl-color-text);
179
+ opacity: .38;
180
+ border: 0;
181
+ padding: 0;
182
+ background-color: currentColor;
219
183
  }
220
184
 
221
- .${className}[data-licensed='false']:hover > button {
222
- animation: ${className}_delayed_link 0.2s forwards ease-in-out;
223
- animation-delay: 0.32s;
185
+ .${className}[data-debug='true'] {
186
+ bottom: max(46px, env(safe-area-inset-bottom));
224
187
  }
225
188
 
226
- .${className}[data-licensed='false'] > button:focus-visible {
227
- opacity: 1;
189
+ .${className}[data-mobile='true'] {
190
+ border-radius: 4px 0px 0px 4px;
191
+ right: max(-2px, calc(env(safe-area-inset-right) - 2px));
192
+ width: 8px;
193
+ height: 48px;
228
194
  }
229
- }
230
195
 
231
- @keyframes ${className}_delayed_link {
232
- 0% {
233
- cursor: inherit;
234
- opacity: .38;
235
- pointer-events: none;
196
+ .${className}[data-mobile='true'] > button {
197
+ width: 8px;
198
+ height: 32px;
236
199
  }
237
- 100% {
238
- cursor: pointer;
239
- opacity: 1;
240
- pointer-events: all;
200
+
201
+ @media (hover: hover) {
202
+ .${className} > button {
203
+ pointer-events: none;
204
+ }
205
+
206
+ .${className}:hover {
207
+ background-color: var(--tl-color-background);
208
+ transition: background-color 0.2s ease-in-out;
209
+ transition-delay: 0.32s;
210
+ }
211
+
212
+ .${className}:hover > button {
213
+ animation: ${className}_delayed_link 0.2s forwards ease-in-out;
214
+ animation-delay: 0.32s;
215
+ }
216
+
217
+ .${className} > button:focus-visible {
218
+ opacity: 1;
219
+ }
241
220
  }
242
- }`
221
+
222
+
223
+ @keyframes ${className}_delayed_link {
224
+ 0% {
225
+ cursor: inherit;
226
+ opacity: .38;
227
+ pointer-events: none;
228
+ }
229
+ 100% {
230
+ cursor: pointer;
231
+ opacity: 1;
232
+ pointer-events: all;
233
+ }
234
+ }`
243
235
 
244
236
  return <style nonce={editor.options.nonce}>{CSS}</style>
245
237
  })
@@ -1,27 +1,18 @@
1
- import { TestEditor } from '../test/TestEditor'
1
+ import { markEventAsHandled, wasEventAlreadyHandled } from './dom'
2
2
 
3
3
  describe('Event handling utilities', () => {
4
- let editor: TestEditor
5
-
6
- beforeEach(() => {
7
- editor = new TestEditor()
8
- })
9
-
10
- afterEach(() => {
11
- editor.dispose()
12
- })
13
4
  describe('markEventAsHandled and wasEventAlreadyHandled', () => {
14
5
  it('should track events as handled', () => {
15
6
  const mockEvent = new PointerEvent('pointerdown', { pointerId: 1 })
16
7
 
17
8
  // Initially, event should not be marked as handled
18
- expect(editor.wasEventAlreadyHandled(mockEvent)).toBe(false)
9
+ expect(wasEventAlreadyHandled(mockEvent)).toBe(false)
19
10
 
20
11
  // Mark the event as handled
21
- editor.markEventAsHandled(mockEvent)
12
+ markEventAsHandled(mockEvent)
22
13
 
23
14
  // Now it should be marked as handled
24
- expect(editor.wasEventAlreadyHandled(mockEvent)).toBe(true)
15
+ expect(wasEventAlreadyHandled(mockEvent)).toBe(true)
25
16
  })
26
17
 
27
18
  it('should work with React synthetic events', () => {
@@ -29,15 +20,15 @@ describe('Event handling utilities', () => {
29
20
  const syntheticEvent = { nativeEvent }
30
21
 
31
22
  // Initially not handled
32
- expect(editor.wasEventAlreadyHandled(syntheticEvent)).toBe(false)
33
- expect(editor.wasEventAlreadyHandled(nativeEvent)).toBe(false)
23
+ expect(wasEventAlreadyHandled(syntheticEvent)).toBe(false)
24
+ expect(wasEventAlreadyHandled(nativeEvent)).toBe(false)
34
25
 
35
26
  // Mark synthetic event as handled
36
- editor.markEventAsHandled(syntheticEvent)
27
+ markEventAsHandled(syntheticEvent)
37
28
 
38
29
  // Both synthetic and native should be marked as handled
39
- expect(editor.wasEventAlreadyHandled(syntheticEvent)).toBe(true)
40
- expect(editor.wasEventAlreadyHandled(nativeEvent)).toBe(true)
30
+ expect(wasEventAlreadyHandled(syntheticEvent)).toBe(true)
31
+ expect(wasEventAlreadyHandled(nativeEvent)).toBe(true)
41
32
  })
42
33
 
43
34
  it('should handle multiple different events independently', () => {
@@ -46,18 +37,18 @@ describe('Event handling utilities', () => {
46
37
  const event3 = new MouseEvent('click')
47
38
 
48
39
  // Mark only event1 as handled
49
- editor.markEventAsHandled(event1)
40
+ markEventAsHandled(event1)
50
41
 
51
- expect(editor.wasEventAlreadyHandled(event1)).toBe(true)
52
- expect(editor.wasEventAlreadyHandled(event2)).toBe(false)
53
- expect(editor.wasEventAlreadyHandled(event3)).toBe(false)
42
+ expect(wasEventAlreadyHandled(event1)).toBe(true)
43
+ expect(wasEventAlreadyHandled(event2)).toBe(false)
44
+ expect(wasEventAlreadyHandled(event3)).toBe(false)
54
45
 
55
46
  // Mark event2 as handled
56
- editor.markEventAsHandled(event2)
47
+ markEventAsHandled(event2)
57
48
 
58
- expect(editor.wasEventAlreadyHandled(event1)).toBe(true)
59
- expect(editor.wasEventAlreadyHandled(event2)).toBe(true)
60
- expect(editor.wasEventAlreadyHandled(event3)).toBe(false)
49
+ expect(wasEventAlreadyHandled(event1)).toBe(true)
50
+ expect(wasEventAlreadyHandled(event2)).toBe(true)
51
+ expect(wasEventAlreadyHandled(event3)).toBe(false)
61
52
  })
62
53
 
63
54
  it('should not interfere with event properties', () => {
@@ -68,7 +59,7 @@ describe('Event handling utilities', () => {
68
59
  })
69
60
 
70
61
  // Mark as handled
71
- editor.markEventAsHandled(event)
62
+ markEventAsHandled(event)
72
63
 
73
64
  // Event properties should remain unchanged
74
65
  expect(event.pointerId).toBe(1)
@@ -87,17 +78,17 @@ describe('Event handling utilities', () => {
87
78
  ],
88
79
  })
89
80
 
90
- expect(editor.wasEventAlreadyHandled(touchEvent)).toBe(false)
91
- editor.markEventAsHandled(touchEvent)
92
- expect(editor.wasEventAlreadyHandled(touchEvent)).toBe(true)
81
+ expect(wasEventAlreadyHandled(touchEvent)).toBe(false)
82
+ markEventAsHandled(touchEvent)
83
+ expect(wasEventAlreadyHandled(touchEvent)).toBe(true)
93
84
  })
94
85
 
95
86
  it('should work with keyboard events', () => {
96
87
  const keyEvent = new KeyboardEvent('keydown', { key: 'Enter' })
97
88
 
98
- expect(editor.wasEventAlreadyHandled(keyEvent)).toBe(false)
99
- editor.markEventAsHandled(keyEvent)
100
- expect(editor.wasEventAlreadyHandled(keyEvent)).toBe(true)
89
+ expect(wasEventAlreadyHandled(keyEvent)).toBe(false)
90
+ markEventAsHandled(keyEvent)
91
+ expect(wasEventAlreadyHandled(keyEvent)).toBe(true)
101
92
  })
102
93
  })
103
94
  })