@tldraw/editor 5.3.0-canary.e857c8e412be → 5.3.0-canary.eb4ecbf40c4a
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.js +1 -1
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +25 -1
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +25 -1
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/hooks/usePassThroughWheelEvents.ts +44 -2
- package/src/version.ts +3 -3
package/dist-cjs/index.js
CHANGED
|
@@ -379,7 +379,7 @@ var import_uniq = require("./lib/utils/uniq");
|
|
|
379
379
|
var import_defaultThemes2 = require("./lib/editor/managers/ThemeManager/defaultThemes");
|
|
380
380
|
(0, import_utils.registerTldrawLibraryVersion)(
|
|
381
381
|
"@tldraw/editor",
|
|
382
|
-
"5.3.0-canary.
|
|
382
|
+
"5.3.0-canary.eb4ecbf40c4a",
|
|
383
383
|
"cjs"
|
|
384
384
|
);
|
|
385
385
|
//# sourceMappingURL=index.js.map
|
|
@@ -25,6 +25,30 @@ var import_react = require("react");
|
|
|
25
25
|
var import_dom = require("../utils/dom");
|
|
26
26
|
var import_useContainer = require("./useContainer");
|
|
27
27
|
var import_useEditor = require("./useEditor");
|
|
28
|
+
function isScrollableOverflow(overflow) {
|
|
29
|
+
return overflow === "auto" || overflow === "scroll" || overflow === "overlay";
|
|
30
|
+
}
|
|
31
|
+
function isScrollable(elm) {
|
|
32
|
+
const overflowsY = elm.scrollHeight > elm.clientHeight;
|
|
33
|
+
const overflowsX = elm.scrollWidth > elm.clientWidth;
|
|
34
|
+
if (!overflowsY && !overflowsX) return false;
|
|
35
|
+
const style = getComputedStyle(elm);
|
|
36
|
+
return overflowsY && isScrollableOverflow(style.overflowY) || overflowsX && isScrollableOverflow(style.overflowX);
|
|
37
|
+
}
|
|
38
|
+
function hasScrollableElement(target, root) {
|
|
39
|
+
if (!(target instanceof Node)) {
|
|
40
|
+
return isScrollable(root);
|
|
41
|
+
}
|
|
42
|
+
let elm = target instanceof Element ? target : target.parentElement;
|
|
43
|
+
while (elm) {
|
|
44
|
+
if (elm instanceof HTMLElement && isScrollable(elm)) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (elm === root) return false;
|
|
48
|
+
elm = elm.parentElement;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
28
52
|
function usePassThroughWheelEvents(ref) {
|
|
29
53
|
if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
|
|
30
54
|
const container = (0, import_useContainer.useContainer)();
|
|
@@ -34,7 +58,7 @@ function usePassThroughWheelEvents(ref) {
|
|
|
34
58
|
if (!editor?.getInstanceState().isFocused) return;
|
|
35
59
|
if (e.isSpecialRedispatchedEvent) return;
|
|
36
60
|
const elm2 = ref.current;
|
|
37
|
-
if (elm2 &&
|
|
61
|
+
if (elm2 && hasScrollableElement(e.target, elm2)) {
|
|
38
62
|
return;
|
|
39
63
|
}
|
|
40
64
|
(0, import_dom.preventDefault)(e);
|
|
@@ -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'\nimport { useMaybeEditor } from './useEditor'\n\n/** @public */\nexport function usePassThroughWheelEvents(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 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//
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqC;AACrC,iBAA+B;AAC/B,0BAA6B;AAC7B,uBAA+B;
|
|
4
|
+
"sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\nimport { useMaybeEditor } from './useEditor'\n\nfunction isScrollableOverflow(overflow: string) {\n\treturn overflow === 'auto' || overflow === 'scroll' || overflow === 'overlay'\n}\n\n// An element only consumes a wheel event when it's a real scroll container: its content overflows\n// AND its computed overflow is scrollable. Checking scrollHeight/scrollWidth alone is not enough \u2014\n// an `overflow: visible` element whose content merely overflows (e.g. a comment pin whose hover\n// `transform: scale()` inflates scrollHeight past clientHeight) never scrolls, so the wheel must\n// still pass through to the canvas.\nfunction isScrollable(elm: HTMLElement) {\n\t// Cheap first: if nothing overflows, it can't scroll \u2014 skip the getComputedStyle read. This runs\n\t// per ancestor on every wheel event, so avoid resolving styles for the common (non-overflowing) case.\n\tconst overflowsY = elm.scrollHeight > elm.clientHeight\n\tconst overflowsX = elm.scrollWidth > elm.clientWidth\n\tif (!overflowsY && !overflowsX) return false\n\n\tconst style = getComputedStyle(elm)\n\treturn (\n\t\t(overflowsY && isScrollableOverflow(style.overflowY)) ||\n\t\t(overflowsX && isScrollableOverflow(style.overflowX))\n\t)\n}\n\n// Walk from the wheeled element up to (and including) the pass-through root, looking for a scroll\n// container. If one is found, the wheel belongs to it \u2014 don't redispatch it to the canvas.\nfunction hasScrollableElement(target: EventTarget | null, root: HTMLElement) {\n\tif (!(target instanceof Node)) {\n\t\treturn isScrollable(root)\n\t}\n\n\tlet elm: Element | null = target instanceof Element ? target : target.parentElement\n\twhile (elm) {\n\t\tif (elm instanceof HTMLElement && isScrollable(elm)) {\n\t\t\treturn true\n\t\t}\n\t\tif (elm === root) return false\n\t\telm = elm.parentElement\n\t}\n\n\treturn false\n}\n\n/** @public */\nexport function usePassThroughWheelEvents(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 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 wheel is over a scrollable element, let it scroll instead of redispatching.\n\t\t\tconst elm = ref.current\n\t\t\tif (elm && hasScrollableElement(e.target, elm)) {\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;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqC;AACrC,iBAA+B;AAC/B,0BAA6B;AAC7B,uBAA+B;AAE/B,SAAS,qBAAqB,UAAkB;AAC/C,SAAO,aAAa,UAAU,aAAa,YAAY,aAAa;AACrE;AAOA,SAAS,aAAa,KAAkB;AAGvC,QAAM,aAAa,IAAI,eAAe,IAAI;AAC1C,QAAM,aAAa,IAAI,cAAc,IAAI;AACzC,MAAI,CAAC,cAAc,CAAC,WAAY,QAAO;AAEvC,QAAM,QAAQ,iBAAiB,GAAG;AAClC,SACE,cAAc,qBAAqB,MAAM,SAAS,KAClD,cAAc,qBAAqB,MAAM,SAAS;AAErD;AAIA,SAAS,qBAAqB,QAA4B,MAAmB;AAC5E,MAAI,EAAE,kBAAkB,OAAO;AAC9B,WAAO,aAAa,IAAI;AAAA,EACzB;AAEA,MAAI,MAAsB,kBAAkB,UAAU,SAAS,OAAO;AACtE,SAAO,KAAK;AACX,QAAI,eAAe,eAAe,aAAa,GAAG,GAAG;AACpD,aAAO;AAAA,IACR;AACA,QAAI,QAAQ,KAAM,QAAO;AACzB,UAAM,IAAI;AAAA,EACX;AAEA,SAAO;AACR;AAGO,SAAS,0BAA0B,KAAoC;AAC7E,MAAI,CAAC,IAAK,OAAM,MAAM,gDAAgD;AACtE,QAAM,gBAAY,kCAAa;AAC/B,QAAM,aAAS,iCAAe;AAE9B,8BAAU,MAAM;AACf,aAAS,QAAQ,GAAe;AAE/B,UAAI,CAAC,QAAQ,iBAAiB,EAAE,UAAW;AAE3C,UAAK,EAAU,2BAA4B;AAG3C,YAAMA,OAAM,IAAI;AAChB,UAAIA,QAAO,qBAAqB,EAAE,QAAQA,IAAG,GAAG;AAC/C;AAAA,MACD;AAEA,qCAAe,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
|
}
|
package/dist-cjs/version.js
CHANGED
|
@@ -22,10 +22,10 @@ __export(version_exports, {
|
|
|
22
22
|
version: () => version
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(version_exports);
|
|
25
|
-
const version = "5.3.0-canary.
|
|
25
|
+
const version = "5.3.0-canary.eb4ecbf40c4a";
|
|
26
26
|
const publishDates = {
|
|
27
27
|
major: "2026-05-06T16:28:18.473Z",
|
|
28
|
-
minor: "2026-07-
|
|
29
|
-
patch: "2026-07-
|
|
28
|
+
minor: "2026-07-29T12:59:20.060Z",
|
|
29
|
+
patch: "2026-07-29T12:59:20.060Z"
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=version.js.map
|
package/dist-cjs/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.eb4ecbf40c4a'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-29T12:59:20.060Z',\n\tpatch: '2026-07-29T12:59:20.060Z',\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.mjs
CHANGED
|
@@ -296,7 +296,7 @@ import { LocalIndexedDb, Table } from "./lib/utils/sync/LocalIndexedDb.mjs";
|
|
|
296
296
|
import { uniq } from "./lib/utils/uniq.mjs";
|
|
297
297
|
registerTldrawLibraryVersion(
|
|
298
298
|
"@tldraw/editor",
|
|
299
|
-
"5.3.0-canary.
|
|
299
|
+
"5.3.0-canary.eb4ecbf40c4a",
|
|
300
300
|
"esm"
|
|
301
301
|
);
|
|
302
302
|
import { getColorValue } from "./lib/editor/managers/ThemeManager/defaultThemes.mjs";
|
|
@@ -2,6 +2,30 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { preventDefault } from "../utils/dom.mjs";
|
|
3
3
|
import { useContainer } from "./useContainer.mjs";
|
|
4
4
|
import { useMaybeEditor } from "./useEditor.mjs";
|
|
5
|
+
function isScrollableOverflow(overflow) {
|
|
6
|
+
return overflow === "auto" || overflow === "scroll" || overflow === "overlay";
|
|
7
|
+
}
|
|
8
|
+
function isScrollable(elm) {
|
|
9
|
+
const overflowsY = elm.scrollHeight > elm.clientHeight;
|
|
10
|
+
const overflowsX = elm.scrollWidth > elm.clientWidth;
|
|
11
|
+
if (!overflowsY && !overflowsX) return false;
|
|
12
|
+
const style = getComputedStyle(elm);
|
|
13
|
+
return overflowsY && isScrollableOverflow(style.overflowY) || overflowsX && isScrollableOverflow(style.overflowX);
|
|
14
|
+
}
|
|
15
|
+
function hasScrollableElement(target, root) {
|
|
16
|
+
if (!(target instanceof Node)) {
|
|
17
|
+
return isScrollable(root);
|
|
18
|
+
}
|
|
19
|
+
let elm = target instanceof Element ? target : target.parentElement;
|
|
20
|
+
while (elm) {
|
|
21
|
+
if (elm instanceof HTMLElement && isScrollable(elm)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (elm === root) return false;
|
|
25
|
+
elm = elm.parentElement;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
5
29
|
function usePassThroughWheelEvents(ref) {
|
|
6
30
|
if (!ref) throw Error("usePassThroughWheelEvents must be passed a ref");
|
|
7
31
|
const container = useContainer();
|
|
@@ -11,7 +35,7 @@ function usePassThroughWheelEvents(ref) {
|
|
|
11
35
|
if (!editor?.getInstanceState().isFocused) return;
|
|
12
36
|
if (e.isSpecialRedispatchedEvent) return;
|
|
13
37
|
const elm2 = ref.current;
|
|
14
|
-
if (elm2 &&
|
|
38
|
+
if (elm2 && hasScrollableElement(e.target, elm2)) {
|
|
15
39
|
return;
|
|
16
40
|
}
|
|
17
41
|
preventDefault(e);
|
|
@@ -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'\nimport { useMaybeEditor } from './useEditor'\n\n/** @public */\nexport function usePassThroughWheelEvents(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 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//
|
|
5
|
-
"mappings": "AAAA,SAAoB,iBAAiB;AACrC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import { RefObject, useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useContainer } from './useContainer'\nimport { useMaybeEditor } from './useEditor'\n\nfunction isScrollableOverflow(overflow: string) {\n\treturn overflow === 'auto' || overflow === 'scroll' || overflow === 'overlay'\n}\n\n// An element only consumes a wheel event when it's a real scroll container: its content overflows\n// AND its computed overflow is scrollable. Checking scrollHeight/scrollWidth alone is not enough \u2014\n// an `overflow: visible` element whose content merely overflows (e.g. a comment pin whose hover\n// `transform: scale()` inflates scrollHeight past clientHeight) never scrolls, so the wheel must\n// still pass through to the canvas.\nfunction isScrollable(elm: HTMLElement) {\n\t// Cheap first: if nothing overflows, it can't scroll \u2014 skip the getComputedStyle read. This runs\n\t// per ancestor on every wheel event, so avoid resolving styles for the common (non-overflowing) case.\n\tconst overflowsY = elm.scrollHeight > elm.clientHeight\n\tconst overflowsX = elm.scrollWidth > elm.clientWidth\n\tif (!overflowsY && !overflowsX) return false\n\n\tconst style = getComputedStyle(elm)\n\treturn (\n\t\t(overflowsY && isScrollableOverflow(style.overflowY)) ||\n\t\t(overflowsX && isScrollableOverflow(style.overflowX))\n\t)\n}\n\n// Walk from the wheeled element up to (and including) the pass-through root, looking for a scroll\n// container. If one is found, the wheel belongs to it \u2014 don't redispatch it to the canvas.\nfunction hasScrollableElement(target: EventTarget | null, root: HTMLElement) {\n\tif (!(target instanceof Node)) {\n\t\treturn isScrollable(root)\n\t}\n\n\tlet elm: Element | null = target instanceof Element ? target : target.parentElement\n\twhile (elm) {\n\t\tif (elm instanceof HTMLElement && isScrollable(elm)) {\n\t\t\treturn true\n\t\t}\n\t\tif (elm === root) return false\n\t\telm = elm.parentElement\n\t}\n\n\treturn false\n}\n\n/** @public */\nexport function usePassThroughWheelEvents(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 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 wheel is over a scrollable element, let it scroll instead of redispatching.\n\t\t\tconst elm = ref.current\n\t\t\tif (elm && hasScrollableElement(e.target, elm)) {\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;AAE/B,SAAS,qBAAqB,UAAkB;AAC/C,SAAO,aAAa,UAAU,aAAa,YAAY,aAAa;AACrE;AAOA,SAAS,aAAa,KAAkB;AAGvC,QAAM,aAAa,IAAI,eAAe,IAAI;AAC1C,QAAM,aAAa,IAAI,cAAc,IAAI;AACzC,MAAI,CAAC,cAAc,CAAC,WAAY,QAAO;AAEvC,QAAM,QAAQ,iBAAiB,GAAG;AAClC,SACE,cAAc,qBAAqB,MAAM,SAAS,KAClD,cAAc,qBAAqB,MAAM,SAAS;AAErD;AAIA,SAAS,qBAAqB,QAA4B,MAAmB;AAC5E,MAAI,EAAE,kBAAkB,OAAO;AAC9B,WAAO,aAAa,IAAI;AAAA,EACzB;AAEA,MAAI,MAAsB,kBAAkB,UAAU,SAAS,OAAO;AACtE,SAAO,KAAK;AACX,QAAI,eAAe,eAAe,aAAa,GAAG,GAAG;AACpD,aAAO;AAAA,IACR;AACA,QAAI,QAAQ,KAAM,QAAO;AACzB,UAAM,IAAI;AAAA,EACX;AAEA,SAAO;AACR;AAGO,SAAS,0BAA0B,KAAoC;AAC7E,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,QAAO,qBAAqB,EAAE,QAAQA,IAAG,GAAG;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
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "5.3.0-canary.
|
|
1
|
+
const version = "5.3.0-canary.eb4ecbf40c4a";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2026-05-06T16:28:18.473Z",
|
|
4
|
-
minor: "2026-07-
|
|
5
|
-
patch: "2026-07-
|
|
4
|
+
minor: "2026-07-29T12:59:20.060Z",
|
|
5
|
+
patch: "2026-07-29T12:59:20.060Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.eb4ecbf40c4a'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-29T12:59:20.060Z',\n\tpatch: '2026-07-29T12:59:20.060Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (editor).",
|
|
4
|
-
"version": "5.3.0-canary.
|
|
4
|
+
"version": "5.3.0-canary.eb4ecbf40c4a",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@tiptap/core": "^3.12.1",
|
|
50
50
|
"@tiptap/pm": "^3.12.1",
|
|
51
51
|
"@tiptap/react": "^3.12.1",
|
|
52
|
-
"@tldraw/state": "5.3.0-canary.
|
|
53
|
-
"@tldraw/state-react": "5.3.0-canary.
|
|
54
|
-
"@tldraw/store": "5.3.0-canary.
|
|
55
|
-
"@tldraw/tlschema": "5.3.0-canary.
|
|
56
|
-
"@tldraw/utils": "5.3.0-canary.
|
|
57
|
-
"@tldraw/validate": "5.3.0-canary.
|
|
52
|
+
"@tldraw/state": "5.3.0-canary.eb4ecbf40c4a",
|
|
53
|
+
"@tldraw/state-react": "5.3.0-canary.eb4ecbf40c4a",
|
|
54
|
+
"@tldraw/store": "5.3.0-canary.eb4ecbf40c4a",
|
|
55
|
+
"@tldraw/tlschema": "5.3.0-canary.eb4ecbf40c4a",
|
|
56
|
+
"@tldraw/utils": "5.3.0-canary.eb4ecbf40c4a",
|
|
57
|
+
"@tldraw/validate": "5.3.0-canary.eb4ecbf40c4a",
|
|
58
58
|
"classnames": "^2.5.1",
|
|
59
59
|
"eventemitter3": "^4.0.7",
|
|
60
60
|
"idb": "^7.1.1",
|
|
@@ -3,6 +3,48 @@ import { preventDefault } from '../utils/dom'
|
|
|
3
3
|
import { useContainer } from './useContainer'
|
|
4
4
|
import { useMaybeEditor } from './useEditor'
|
|
5
5
|
|
|
6
|
+
function isScrollableOverflow(overflow: string) {
|
|
7
|
+
return overflow === 'auto' || overflow === 'scroll' || overflow === 'overlay'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// An element only consumes a wheel event when it's a real scroll container: its content overflows
|
|
11
|
+
// AND its computed overflow is scrollable. Checking scrollHeight/scrollWidth alone is not enough —
|
|
12
|
+
// an `overflow: visible` element whose content merely overflows (e.g. a comment pin whose hover
|
|
13
|
+
// `transform: scale()` inflates scrollHeight past clientHeight) never scrolls, so the wheel must
|
|
14
|
+
// still pass through to the canvas.
|
|
15
|
+
function isScrollable(elm: HTMLElement) {
|
|
16
|
+
// Cheap first: if nothing overflows, it can't scroll — skip the getComputedStyle read. This runs
|
|
17
|
+
// per ancestor on every wheel event, so avoid resolving styles for the common (non-overflowing) case.
|
|
18
|
+
const overflowsY = elm.scrollHeight > elm.clientHeight
|
|
19
|
+
const overflowsX = elm.scrollWidth > elm.clientWidth
|
|
20
|
+
if (!overflowsY && !overflowsX) return false
|
|
21
|
+
|
|
22
|
+
const style = getComputedStyle(elm)
|
|
23
|
+
return (
|
|
24
|
+
(overflowsY && isScrollableOverflow(style.overflowY)) ||
|
|
25
|
+
(overflowsX && isScrollableOverflow(style.overflowX))
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Walk from the wheeled element up to (and including) the pass-through root, looking for a scroll
|
|
30
|
+
// container. If one is found, the wheel belongs to it — don't redispatch it to the canvas.
|
|
31
|
+
function hasScrollableElement(target: EventTarget | null, root: HTMLElement) {
|
|
32
|
+
if (!(target instanceof Node)) {
|
|
33
|
+
return isScrollable(root)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let elm: Element | null = target instanceof Element ? target : target.parentElement
|
|
37
|
+
while (elm) {
|
|
38
|
+
if (elm instanceof HTMLElement && isScrollable(elm)) {
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
if (elm === root) return false
|
|
42
|
+
elm = elm.parentElement
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
6
48
|
/** @public */
|
|
7
49
|
export function usePassThroughWheelEvents(ref: RefObject<HTMLElement | null>) {
|
|
8
50
|
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
@@ -16,9 +58,9 @@ export function usePassThroughWheelEvents(ref: RefObject<HTMLElement | null>) {
|
|
|
16
58
|
|
|
17
59
|
if ((e as any).isSpecialRedispatchedEvent) return
|
|
18
60
|
|
|
19
|
-
//
|
|
61
|
+
// If the wheel is over a scrollable element, let it scroll instead of redispatching.
|
|
20
62
|
const elm = ref.current
|
|
21
|
-
if (elm &&
|
|
63
|
+
if (elm && hasScrollableElement(e.target, elm)) {
|
|
22
64
|
return
|
|
23
65
|
}
|
|
24
66
|
|
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-canary.
|
|
4
|
+
export const version = '5.3.0-canary.eb4ecbf40c4a'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2026-05-06T16:28:18.473Z',
|
|
7
|
-
minor: '2026-07-
|
|
8
|
-
patch: '2026-07-
|
|
7
|
+
minor: '2026-07-29T12:59:20.060Z',
|
|
8
|
+
patch: '2026-07-29T12:59:20.060Z',
|
|
9
9
|
}
|