@tldraw/editor 5.3.0-next.d7d8ced023d5 → 5.3.0-next.df310c6196c0
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.
- package/dist-cjs/index.d.ts +57 -3
- package/dist-cjs/index.js +4 -3
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +24 -19
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/EditorPortal.js +44 -0
- package/dist-cjs/lib/components/EditorPortal.js.map +7 -0
- package/dist-cjs/lib/components/LiveCollaborators.js +7 -3
- package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +4 -4
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +25 -18
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +3 -3
- package/dist-cjs/lib/license/LicenseManager.js +3 -0
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +57 -3
- package/dist-esm/index.mjs +7 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +23 -18
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/EditorPortal.mjs +24 -0
- package/dist-esm/lib/components/EditorPortal.mjs.map +7 -0
- package/dist-esm/lib/components/LiveCollaborators.mjs +8 -4
- package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +5 -5
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +26 -19
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +3 -3
- package/dist-esm/lib/license/LicenseManager.mjs +3 -0
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +6 -0
- package/package.json +7 -7
- package/src/index.ts +5 -1
- package/src/lib/TldrawEditor.tsx +21 -13
- package/src/lib/components/EditorPortal.tsx +77 -0
- package/src/lib/components/LiveCollaborators.tsx +20 -6
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +46 -1
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +10 -5
- package/src/lib/hooks/usePassThroughWheelEvents.ts +39 -22
- package/src/lib/license/LicenseManager.test.ts +25 -0
- package/src/lib/license/LicenseManager.ts +7 -0
- package/src/lib/test/EditorPortal.test.tsx +48 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +77 -0
- package/src/version.ts +3 -3
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +0 -51
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +0 -7
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +0 -31
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +0 -7
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +0 -32
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMPTY_ARRAY, atom, computed } from '@tldraw/state'
|
|
2
2
|
import type { TLInstancePresence } from '@tldraw/tlschema'
|
|
3
|
-
import { maxBy } from '@tldraw/utils'
|
|
3
|
+
import { areArraysShallowEqual, maxBy } from '@tldraw/utils'
|
|
4
4
|
import type { Editor } from '../../Editor'
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -41,11 +41,16 @@ export class CollaboratorsManager {
|
|
|
41
41
|
}))
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// These queries all derive fresh arrays with map/filter, so they compare results with
|
|
45
|
+
// shallow (element-identity) equality: a presence update that leaves a derived list's
|
|
46
|
+
// elements unchanged — e.g. a peer moving on another page — keeps the previous array's
|
|
47
|
+
// identity and doesn't invalidate downstream subscribers such as the cursor layer.
|
|
48
|
+
|
|
44
49
|
/**
|
|
45
50
|
* Returns a list of presence records for all peer collaborators.
|
|
46
51
|
* This will return the latest presence record for each connected user.
|
|
47
52
|
*/
|
|
48
|
-
@computed
|
|
53
|
+
@computed({ isEqual: areArraysShallowEqual })
|
|
49
54
|
getCollaborators(): TLInstancePresence[] {
|
|
50
55
|
const allPresenceRecords = this._getCollaboratorsQuery().get()
|
|
51
56
|
if (!allPresenceRecords.length) return EMPTY_ARRAY
|
|
@@ -63,7 +68,7 @@ export class CollaboratorsManager {
|
|
|
63
68
|
* Returns a list of presence records for all peer collaborators on the current page.
|
|
64
69
|
* This will return the latest presence record for each connected user.
|
|
65
70
|
*/
|
|
66
|
-
@computed
|
|
71
|
+
@computed({ isEqual: areArraysShallowEqual })
|
|
67
72
|
getCollaboratorsOnCurrentPage(): TLInstancePresence[] {
|
|
68
73
|
const currentPageId = this.editor.getCurrentPageId()
|
|
69
74
|
return this.getCollaborators().filter((c) => c.currentPageId === currentPageId)
|
|
@@ -76,7 +81,7 @@ export class CollaboratorsManager {
|
|
|
76
81
|
* highlighted users. Re-evaluates on the visibility clock, so callers don't need to
|
|
77
82
|
* drive their own activity timer.
|
|
78
83
|
*/
|
|
79
|
-
@computed
|
|
84
|
+
@computed({ isEqual: areArraysShallowEqual })
|
|
80
85
|
getVisibleCollaborators(): TLInstancePresence[] {
|
|
81
86
|
const { editor } = this
|
|
82
87
|
const { collaboratorInactiveTimeoutMs, collaboratorIdleTimeoutMs } = editor.options
|
|
@@ -121,7 +126,7 @@ export class CollaboratorsManager {
|
|
|
121
126
|
* Returns a list of presence records for peer collaborators who should currently be
|
|
122
127
|
* shown in the UI, filtered to those on the current page.
|
|
123
128
|
*/
|
|
124
|
-
@computed
|
|
129
|
+
@computed({ isEqual: areArraysShallowEqual })
|
|
125
130
|
getVisibleCollaboratorsOnCurrentPage(): TLInstancePresence[] {
|
|
126
131
|
const currentPageId = this.editor.getCurrentPageId()
|
|
127
132
|
return this.getVisibleCollaborators().filter((c) => c.currentPageId === currentPageId)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { RefObject, useEffect } from 'react'
|
|
1
|
+
import { RefObject, useEffect, useRef } from 'react'
|
|
2
2
|
import { preventDefault } from '../utils/dom'
|
|
3
3
|
import { useContainer } from './useContainer'
|
|
4
4
|
import { useMaybeEditor } from './useEditor'
|
|
5
|
+
import { useEvent } from './useEvent'
|
|
5
6
|
|
|
6
7
|
function isScrollableOverflow(overflow: string) {
|
|
7
8
|
return overflow === 'auto' || overflow === 'scroll' || overflow === 'overlay'
|
|
@@ -51,33 +52,49 @@ export function usePassThroughWheelEvents(ref: RefObject<HTMLElement | null>) {
|
|
|
51
52
|
const container = useContainer()
|
|
52
53
|
const editor = useMaybeEditor()
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!editor?.getInstanceState().isFocused) return
|
|
58
|
-
|
|
59
|
-
if ((e as any).isSpecialRedispatchedEvent) return
|
|
55
|
+
const onWheel = useEvent((e: WheelEvent) => {
|
|
56
|
+
// Only pass through wheel events if the editor is focused
|
|
57
|
+
if (!editor?.getInstanceState().isFocused) return
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
const elm = ref.current
|
|
63
|
-
if (elm && hasScrollableElement(e.target, elm)) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
59
|
+
if ((e as any).isSpecialRedispatchedEvent) return
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
;(newEvent as any).isSpecialRedispatchedEvent = true
|
|
72
|
-
cvs.dispatchEvent(newEvent)
|
|
61
|
+
// If the wheel is over a scrollable element, let it scroll instead of redispatching.
|
|
62
|
+
const elm = ref.current
|
|
63
|
+
if (elm && hasScrollableElement(e.target, elm)) {
|
|
64
|
+
return
|
|
73
65
|
}
|
|
74
66
|
|
|
67
|
+
preventDefault(e)
|
|
68
|
+
const cvs = container.querySelector('.tl-canvas')
|
|
69
|
+
if (!cvs) return
|
|
70
|
+
const newEvent = new WheelEvent('wheel', e as any)
|
|
71
|
+
;(newEvent as any).isSpecialRedispatchedEvent = true
|
|
72
|
+
cvs.dispatchEvent(newEvent)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// The element the listener is currently on, which isn't necessarily `ref.current`: a `RefObject`
|
|
76
|
+
// gives no notification when its element changes.
|
|
77
|
+
const attached = useRef<HTMLElement | null>(null)
|
|
78
|
+
|
|
79
|
+
// Deliberately no dependency array — this re-checks the ref after every render of the component
|
|
80
|
+
// that owns it, and re-attaches when the element has been swapped. A component that keeps the
|
|
81
|
+
// hook mounted while unmounting and remounting the element it points at (a comment pin culled
|
|
82
|
+
// while its anchor is off screen, say) would otherwise leave the listener on the discarded node
|
|
83
|
+
// and silently lose pass-through once the element comes back.
|
|
84
|
+
useEffect(() => {
|
|
75
85
|
const elm = ref.current
|
|
76
|
-
if (
|
|
86
|
+
if (elm === attached.current) return
|
|
87
|
+
attached.current?.removeEventListener('wheel', onWheel)
|
|
88
|
+
attached.current = elm
|
|
89
|
+
elm?.addEventListener('wheel', onWheel, { passive: false })
|
|
90
|
+
})
|
|
77
91
|
|
|
78
|
-
|
|
92
|
+
// Teardown is its own effect so the re-attach check above can skip returning a cleanup that
|
|
93
|
+
// would tear the listener down and rebuild it on every render.
|
|
94
|
+
useEffect(() => {
|
|
79
95
|
return () => {
|
|
80
|
-
|
|
96
|
+
attached.current?.removeEventListener('wheel', onWheel)
|
|
97
|
+
attached.current = null
|
|
81
98
|
}
|
|
82
|
-
}, [
|
|
99
|
+
}, [onWheel])
|
|
83
100
|
}
|
|
@@ -1202,6 +1202,31 @@ describe('getEnabledFeatures', () => {
|
|
|
1202
1202
|
}
|
|
1203
1203
|
)
|
|
1204
1204
|
|
|
1205
|
+
it('enables every feature for an evaluation license regardless of flags', () => {
|
|
1206
|
+
const result = getDefaultLicenseResult({
|
|
1207
|
+
isEvaluationLicense: true,
|
|
1208
|
+
isCollaborationEnabled: false,
|
|
1209
|
+
isCommentingEnabled: false,
|
|
1210
|
+
})
|
|
1211
|
+
expect(getEnabledFeatures(result, 'licensed', false)).toEqual({
|
|
1212
|
+
collaboration: true,
|
|
1213
|
+
commenting: true,
|
|
1214
|
+
})
|
|
1215
|
+
})
|
|
1216
|
+
|
|
1217
|
+
it('disables all features for an expired evaluation license', () => {
|
|
1218
|
+
const result = getDefaultLicenseResult({
|
|
1219
|
+
isEvaluationLicense: true,
|
|
1220
|
+
isEvaluationLicenseExpired: true,
|
|
1221
|
+
isCollaborationEnabled: false,
|
|
1222
|
+
isCommentingEnabled: false,
|
|
1223
|
+
})
|
|
1224
|
+
expect(getEnabledFeatures(result, 'expired', false)).toEqual({
|
|
1225
|
+
collaboration: false,
|
|
1226
|
+
commenting: false,
|
|
1227
|
+
})
|
|
1228
|
+
})
|
|
1229
|
+
|
|
1205
1230
|
it('disables all features when the license is not parseable', () => {
|
|
1206
1231
|
expect(
|
|
1207
1232
|
getEnabledFeatures(
|
|
@@ -566,6 +566,13 @@ export function getEnabledFeatures(
|
|
|
566
566
|
return { ...NO_FEATURES }
|
|
567
567
|
}
|
|
568
568
|
|
|
569
|
+
// Evaluation licenses get every feature so prospects can trial the whole product without us
|
|
570
|
+
// having to mint per-feature evaluation keys. Expired evaluation licenses are already excluded
|
|
571
|
+
// above: they resolve to the 'expired' state.
|
|
572
|
+
if (result.isEvaluationLicense) {
|
|
573
|
+
return { ...ALL_FEATURES }
|
|
574
|
+
}
|
|
575
|
+
|
|
569
576
|
return {
|
|
570
577
|
collaboration: result.isCollaborationEnabled,
|
|
571
578
|
commenting: result.isCommentingEnabled,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { act, render, screen } from '@testing-library/react'
|
|
2
|
+
import { EditorPortal } from '../components/EditorPortal'
|
|
3
|
+
import { createTLStore } from '../config/createTLStore'
|
|
4
|
+
import { TL_CONTAINER_CLASS, TldrawEditor } from '../TldrawEditor'
|
|
5
|
+
|
|
6
|
+
/** Mounted in a canvas slot — the deep-in-the-tree case the portal exists for. */
|
|
7
|
+
function Portaled() {
|
|
8
|
+
return (
|
|
9
|
+
<EditorPortal>
|
|
10
|
+
<div data-testid="portaled" />
|
|
11
|
+
</EditorPortal>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('EditorPortal', () => {
|
|
16
|
+
async function renderEditor() {
|
|
17
|
+
const store = createTLStore({ shapeUtils: [], bindingUtils: [] })
|
|
18
|
+
await act(async () => {
|
|
19
|
+
render(<TldrawEditor store={store} components={{ InFrontOfTheCanvas: Portaled }} />)
|
|
20
|
+
})
|
|
21
|
+
return document.querySelector(`.${TL_CONTAINER_CLASS}`)!
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it('renders its children into the editor container', async () => {
|
|
25
|
+
const container = await renderEditor()
|
|
26
|
+
expect(container.contains(screen.getByTestId('portaled'))).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('renders into a host that comes after everything the editor renders', async () => {
|
|
30
|
+
const container = await renderEditor()
|
|
31
|
+
const host = container.querySelector('.tl-portal-host')!
|
|
32
|
+
expect(host.contains(screen.getByTestId('portaled'))).toBe(true)
|
|
33
|
+
// Last of the container's rendered children. Managers append their own nodes after this one
|
|
34
|
+
// (the text measurement element, say) but those are `tabIndex = -1` and out of the tab order.
|
|
35
|
+
const rendered = [...container.children].filter((el) => !el.matches('.tl-text-measure'))
|
|
36
|
+
expect(rendered.at(-1)).toBe(host)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// The tab order guarantee: mounted in a canvas slot, the portaled content still lands after
|
|
40
|
+
// everything the editor renders itself — including (in tldraw) the UI's skip link, which only
|
|
41
|
+
// works while nothing precedes it. Portaling straight into the container lands it ahead of them.
|
|
42
|
+
it('places its children after the rest of the editor in document order', async () => {
|
|
43
|
+
await renderEditor()
|
|
44
|
+
const portaled = screen.getByTestId('portaled')
|
|
45
|
+
const canvas = screen.getByTestId('canvas')
|
|
46
|
+
expect(canvas.compareDocumentPosition(portaled) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { act, cleanup, render } from '@testing-library/react'
|
|
2
|
+
import { useRef, useState } from 'react'
|
|
3
|
+
import { createTLStore } from '../config/createTLStore'
|
|
4
|
+
import { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'
|
|
5
|
+
import { TL_CONTAINER_CLASS, TldrawEditor } from '../TldrawEditor'
|
|
6
|
+
|
|
7
|
+
let setVisible: (visible: boolean) => void
|
|
8
|
+
let rerender: () => void
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The shape a comment pin has: the hook's owner stays mounted while the element the ref points at
|
|
12
|
+
* is culled and later remounted (the pin returns null when its anchor leaves the viewport).
|
|
13
|
+
*/
|
|
14
|
+
function Culled() {
|
|
15
|
+
const ref = useRef<HTMLButtonElement>(null)
|
|
16
|
+
usePassThroughWheelEvents(ref)
|
|
17
|
+
const [visible, _setVisible] = useState(true)
|
|
18
|
+
const [, setTick] = useState(0)
|
|
19
|
+
setVisible = _setVisible
|
|
20
|
+
rerender = () => setTick((t) => t + 1)
|
|
21
|
+
if (!visible) return null
|
|
22
|
+
return <button ref={ref} data-testid="marker" />
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('usePassThroughWheelEvents', () => {
|
|
26
|
+
async function renderEditor() {
|
|
27
|
+
const store = createTLStore({ shapeUtils: [], bindingUtils: [] })
|
|
28
|
+
await act(async () => {
|
|
29
|
+
render(<TldrawEditor store={store} components={{ InFrontOfTheCanvas: Culled }} />)
|
|
30
|
+
})
|
|
31
|
+
return document.querySelector(`.${TL_CONTAINER_CLASS}`)!
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function wheelOverMarker(container: Element) {
|
|
35
|
+
const canvas = container.querySelector('.tl-canvas')!
|
|
36
|
+
const received: Event[] = []
|
|
37
|
+
canvas.addEventListener('wheel', (e) => received.push(e))
|
|
38
|
+
const marker = container.querySelector('[data-testid="marker"]')!
|
|
39
|
+
marker.dispatchEvent(new WheelEvent('wheel', { bubbles: true, cancelable: true, deltaY: 10 }))
|
|
40
|
+
return received
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
it('redispatches wheel events over the element to the canvas', async () => {
|
|
44
|
+
const container = await renderEditor()
|
|
45
|
+
expect(wheelOverMarker(container)).toHaveLength(1)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// The regression: the owner stays mounted across the cull, so an effect keyed on its deps never
|
|
49
|
+
// re-runs and the listener is left on the discarded element.
|
|
50
|
+
it('still redispatches after the element unmounts and remounts', async () => {
|
|
51
|
+
const container = await renderEditor()
|
|
52
|
+
await act(async () => setVisible(false))
|
|
53
|
+
await act(async () => setVisible(true))
|
|
54
|
+
expect(wheelOverMarker(container)).toHaveLength(1)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// The re-attach check runs on every render, so it has to be a no-op when the element hasn't
|
|
58
|
+
// changed — otherwise each render stacks another listener and one wheel redispatches many.
|
|
59
|
+
it('does not stack listeners across renders that leave the element in place', async () => {
|
|
60
|
+
const container = await renderEditor()
|
|
61
|
+
for (let i = 0; i < 3; i++) {
|
|
62
|
+
await act(async () => rerender())
|
|
63
|
+
}
|
|
64
|
+
expect(wheelOverMarker(container)).toHaveLength(1)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('stops redispatching once the owner unmounts', async () => {
|
|
68
|
+
const container = await renderEditor()
|
|
69
|
+
const marker = container.querySelector('[data-testid="marker"]')!
|
|
70
|
+
const canvas = container.querySelector('.tl-canvas')!
|
|
71
|
+
const received: Event[] = []
|
|
72
|
+
canvas.addEventListener('wheel', (e) => received.push(e))
|
|
73
|
+
await act(async () => cleanup())
|
|
74
|
+
marker.dispatchEvent(new WheelEvent('wheel', { bubbles: true, cancelable: true, deltaY: 10 }))
|
|
75
|
+
expect(received).toHaveLength(0)
|
|
76
|
+
})
|
|
77
|
+
})
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '5.3.0-next.
|
|
4
|
+
export const version = '5.3.0-next.df310c6196c0'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2026-05-06T16:28:18.473Z',
|
|
7
|
-
minor: '2026-08-
|
|
8
|
-
patch: '2026-08-
|
|
7
|
+
minor: '2026-08-05T11:28:43.788Z',
|
|
8
|
+
patch: '2026-08-05T11:28:43.788Z',
|
|
9
9
|
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var usePassThroughMouseOverEvents_exports = {};
|
|
20
|
-
__export(usePassThroughMouseOverEvents_exports, {
|
|
21
|
-
usePassThroughMouseOverEvents: () => usePassThroughMouseOverEvents
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(usePassThroughMouseOverEvents_exports);
|
|
24
|
-
var import_react = require("react");
|
|
25
|
-
var import_dom = require("../utils/dom");
|
|
26
|
-
var import_useContainer = require("./useContainer");
|
|
27
|
-
var import_useEditor = require("./useEditor");
|
|
28
|
-
function usePassThroughMouseOverEvents(ref) {
|
|
29
|
-
if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
|
|
30
|
-
const container = (0, import_useContainer.useContainer)();
|
|
31
|
-
const editor = (0, import_useEditor.useMaybeEditor)();
|
|
32
|
-
(0, import_react.useEffect)(() => {
|
|
33
|
-
function onMouseOver(e) {
|
|
34
|
-
if (!editor?.getInstanceState().isFocused) return;
|
|
35
|
-
if (e.isSpecialRedispatchedEvent) return;
|
|
36
|
-
(0, import_dom.preventDefault)(e);
|
|
37
|
-
const cvs = container.querySelector(".tl-canvas");
|
|
38
|
-
if (!cvs) return;
|
|
39
|
-
const newEvent = new PointerEvent(e.type, e);
|
|
40
|
-
newEvent.isSpecialRedispatchedEvent = true;
|
|
41
|
-
cvs.dispatchEvent(newEvent);
|
|
42
|
-
}
|
|
43
|
-
const elm = ref.current;
|
|
44
|
-
if (!elm) return;
|
|
45
|
-
elm.addEventListener("mouseover", onMouseOver, { passive: false });
|
|
46
|
-
return () => {
|
|
47
|
-
elm.removeEventListener("mouseover", onMouseOver);
|
|
48
|
-
};
|
|
49
|
-
}, [container, editor, ref]);
|
|
50
|
-
}
|
|
51
|
-
//# sourceMappingURL=usePassThroughMouseOverEvents.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/lib/hooks/usePassThroughMouseOverEvents.ts"],
|
|
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 | null>) {\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;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqC;AACrC,iBAA+B;AAC/B,0BAA6B;AAC7B,uBAA+B;AAGxB,SAAS,8BAA8B,KAAoC;AACjF,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,gBAAY,kCAAa;AAC/B,QAAM,aAAS,iCAAe;AAE9B,8BAAU,MAAM;AACf,aAAS,YAAY,GAAe;AACnC,UAAI,CAAC,QAAQ,iBAAiB,EAAE,UAAW;AAC3C,UAAK,EAAU,2BAA4B;AAC3C,qCAAe,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
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { preventDefault } from "../utils/dom.mjs";
|
|
3
|
-
import { useContainer } from "./useContainer.mjs";
|
|
4
|
-
import { useMaybeEditor } from "./useEditor.mjs";
|
|
5
|
-
function usePassThroughMouseOverEvents(ref) {
|
|
6
|
-
if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
|
|
7
|
-
const container = useContainer();
|
|
8
|
-
const editor = useMaybeEditor();
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
function onMouseOver(e) {
|
|
11
|
-
if (!editor?.getInstanceState().isFocused) return;
|
|
12
|
-
if (e.isSpecialRedispatchedEvent) return;
|
|
13
|
-
preventDefault(e);
|
|
14
|
-
const cvs = container.querySelector(".tl-canvas");
|
|
15
|
-
if (!cvs) return;
|
|
16
|
-
const newEvent = new PointerEvent(e.type, e);
|
|
17
|
-
newEvent.isSpecialRedispatchedEvent = true;
|
|
18
|
-
cvs.dispatchEvent(newEvent);
|
|
19
|
-
}
|
|
20
|
-
const elm = ref.current;
|
|
21
|
-
if (!elm) return;
|
|
22
|
-
elm.addEventListener("mouseover", onMouseOver, { passive: false });
|
|
23
|
-
return () => {
|
|
24
|
-
elm.removeEventListener("mouseover", onMouseOver);
|
|
25
|
-
};
|
|
26
|
-
}, [container, editor, ref]);
|
|
27
|
-
}
|
|
28
|
-
export {
|
|
29
|
-
usePassThroughMouseOverEvents
|
|
30
|
-
};
|
|
31
|
-
//# sourceMappingURL=usePassThroughMouseOverEvents.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/lib/hooks/usePassThroughMouseOverEvents.ts"],
|
|
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 | null>) {\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,KAAoC;AACjF,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
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { RefObject, useEffect } from 'react'
|
|
2
|
-
import { preventDefault } from '../utils/dom'
|
|
3
|
-
import { useContainer } from './useContainer'
|
|
4
|
-
import { useMaybeEditor } from './useEditor'
|
|
5
|
-
|
|
6
|
-
/** @public */
|
|
7
|
-
export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement | null>) {
|
|
8
|
-
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
9
|
-
const container = useContainer()
|
|
10
|
-
const editor = useMaybeEditor()
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
function onMouseOver(e: MouseEvent) {
|
|
14
|
-
if (!editor?.getInstanceState().isFocused) return
|
|
15
|
-
if ((e as any).isSpecialRedispatchedEvent) return
|
|
16
|
-
preventDefault(e)
|
|
17
|
-
const cvs = container.querySelector('.tl-canvas')
|
|
18
|
-
if (!cvs) return
|
|
19
|
-
const newEvent = new PointerEvent(e.type, e as any)
|
|
20
|
-
;(newEvent as any).isSpecialRedispatchedEvent = true
|
|
21
|
-
cvs.dispatchEvent(newEvent)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const elm = ref.current
|
|
25
|
-
if (!elm) return
|
|
26
|
-
|
|
27
|
-
elm.addEventListener('mouseover', onMouseOver, { passive: false })
|
|
28
|
-
return () => {
|
|
29
|
-
elm.removeEventListener('mouseover', onMouseOver)
|
|
30
|
-
}
|
|
31
|
-
}, [container, editor, ref])
|
|
32
|
-
}
|