@vectojs/core 1.28.1 → 1.30.0
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/{chunk-MVFPN4Y5.mjs → chunk-2WXZCPYQ.mjs} +47 -1
- package/dist/{chunk-Z3HFY75R.js → chunk-7PI7LVWW.js} +124 -78
- package/dist/{chunk-TI5EMJGL.mjs → chunk-IFSFHYF7.mjs} +44 -1
- package/dist/{chunk-K2UGEIT6.js → chunk-M73XB4ZK.js} +98 -55
- package/dist/index.js +432 -223
- package/dist/index.mjs +225 -16
- package/dist/renderer/CanvasRenderer.d.ts +23 -0
- package/dist/renderer/GlyphRasterAtlas.d.ts +12 -0
- package/dist/renderer/IRenderer.d.ts +17 -0
- package/dist/renderer.js +2 -2
- package/dist/renderer.mjs +1 -1
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +78 -1
- package/dist/tree/Scene.d.ts +88 -0
- package/package.json +1 -1
|
@@ -12,6 +12,10 @@ var ANIMATABLE_PROPS = /* @__PURE__ */ new Set([
|
|
|
12
12
|
"rotation",
|
|
13
13
|
"opacity"
|
|
14
14
|
]);
|
|
15
|
+
function contentLineInHint(hint, y, height) {
|
|
16
|
+
if (hint?.minY === void 0 || hint.maxY === void 0) return true;
|
|
17
|
+
return y + height >= hint.minY && y <= hint.maxY;
|
|
18
|
+
}
|
|
15
19
|
var VectoJSEvent = class {
|
|
16
20
|
/** The event name. */
|
|
17
21
|
type;
|
|
@@ -251,6 +255,42 @@ var Entity = class {
|
|
|
251
255
|
* nodes, so on-top components stay clickable.
|
|
252
256
|
*/
|
|
253
257
|
a11yFullViewport = false;
|
|
258
|
+
/**
|
|
259
|
+
* When this entity's a11y shadow node is materialized.
|
|
260
|
+
*
|
|
261
|
+
* `'eager'` (the default) keeps today's behaviour: a shadow node exists for as
|
|
262
|
+
* long as the entity is `interactive` with a box. That is right for a button or
|
|
263
|
+
* a link, and wrong for thousands of ephemeral, individually-meaningless
|
|
264
|
+
* entities — particles, danmaku, graph nodes — where it produces one DOM node
|
|
265
|
+
* per entity every frame.
|
|
266
|
+
*
|
|
267
|
+
* Measured on 5,000 moving interactive entities (`benchmarks/lazy-a11y/`):
|
|
268
|
+
* eager costs **72.2 ms/frame on Chrome and 114.3 ms on Firefox**, missing even
|
|
269
|
+
* 60 Hz, against **1.55/1.63 ms** for the same scene with one node projected —
|
|
270
|
+
* within noise of the 1.26/1.65 ms floor of projecting nothing at all.
|
|
271
|
+
*
|
|
272
|
+
* `'onDemand'` projects a node only while {@link Scene} considers the entity
|
|
273
|
+
* *engaged*: it is focused, it is the current pointer target, or it has been
|
|
274
|
+
* explicitly requested via {@link Scene.requestA11yProjection}. Crucially the
|
|
275
|
+
* trigger is not hover alone — a keyboard or assistive-technology user
|
|
276
|
+
* generates no hover, so a hover-only gate would remove exactly those users'
|
|
277
|
+
* access. Engagement therefore includes focus and an explicit request, and the
|
|
278
|
+
* entity stays hit-testable on canvas throughout, so a click still reaches it
|
|
279
|
+
* and promotes it.
|
|
280
|
+
*
|
|
281
|
+
* `'never'` suppresses the node entirely. Prefer `interactive = false` unless
|
|
282
|
+
* the entity genuinely needs pointer events without any semantic presence;
|
|
283
|
+
* this exists so a purely decorative interactive surface can opt out without
|
|
284
|
+
* losing canvas hit-testing.
|
|
285
|
+
*
|
|
286
|
+
* **This does not replace an aggregate description.** A thousand `'onDemand'`
|
|
287
|
+
* danmaku are individually reachable but say nothing collectively. The proven
|
|
288
|
+
* pattern is one aggregate live region (`role: 'status'`, `a11yFullViewport`)
|
|
289
|
+
* plus a small pool of persistent hotspots for the current selection — see
|
|
290
|
+
* `vectojs-native/danmaku`. Use `'onDemand'` to stop paying per entity, not as
|
|
291
|
+
* the whole accessibility story.
|
|
292
|
+
*/
|
|
293
|
+
a11yProjection = "eager";
|
|
254
294
|
/**
|
|
255
295
|
* Hide this entity AND its whole subtree from the accessibility/automation
|
|
256
296
|
* projection, regardless of each node's own `interactive` flag.
|
|
@@ -1045,9 +1085,14 @@ var Entity = class {
|
|
|
1045
1085
|
* `selectable` is set — natively selectable. Returns `null` by default.
|
|
1046
1086
|
* Read on the a11y sync cadence, so text changes propagate automatically.
|
|
1047
1087
|
*
|
|
1088
|
+
* @param hint - Optional advice about which part of the entity is worth
|
|
1089
|
+
* describing. Purely an optimization: ignoring it is always correct, which
|
|
1090
|
+
* is why it is a parameter rather than a required contract change. See
|
|
1091
|
+
* {@link ContentProjectionHint}.
|
|
1048
1092
|
* @returns The projection descriptor, or `null` to project nothing.
|
|
1049
1093
|
*/
|
|
1050
|
-
getContentProjection() {
|
|
1094
|
+
getContentProjection(hint) {
|
|
1095
|
+
void hint;
|
|
1051
1096
|
return null;
|
|
1052
1097
|
}
|
|
1053
1098
|
/**
|
|
@@ -1634,6 +1679,7 @@ var SVGEntity = class extends Entity {
|
|
|
1634
1679
|
};
|
|
1635
1680
|
|
|
1636
1681
|
export {
|
|
1682
|
+
contentLineInHint,
|
|
1637
1683
|
VectoJSEvent,
|
|
1638
1684
|
Entity,
|
|
1639
1685
|
MSDFTextEntity,
|
|
@@ -14,6 +14,10 @@ var ANIMATABLE_PROPS = /* @__PURE__ */ new Set([
|
|
|
14
14
|
"rotation",
|
|
15
15
|
"opacity"
|
|
16
16
|
]);
|
|
17
|
+
function contentLineInHint(hint, y, height) {
|
|
18
|
+
if (_optionalChain([hint, 'optionalAccess', _ => _.minY]) === void 0 || hint.maxY === void 0) return true;
|
|
19
|
+
return y + height >= hint.minY && y <= hint.maxY;
|
|
20
|
+
}
|
|
17
21
|
var VectoJSEvent = (_class = class {
|
|
18
22
|
/** The event name. */
|
|
19
23
|
|
|
@@ -47,7 +51,7 @@ var VectoJSEvent = (_class = class {
|
|
|
47
51
|
}
|
|
48
52
|
/** Forward to the native event's `preventDefault` (e.g. stop page scroll). */
|
|
49
53
|
preventDefault() {
|
|
50
|
-
_optionalChain([this, 'access',
|
|
54
|
+
_optionalChain([this, 'access', _2 => _2.nativeEvent, 'optionalAccess', _3 => _3.preventDefault, 'optionalCall', _4 => _4()]);
|
|
51
55
|
}
|
|
52
56
|
/** Whether {@link stopPropagation} has been called. */
|
|
53
57
|
get propagationStopped() {
|
|
@@ -59,72 +63,72 @@ var VectoJSEvent = (_class = class {
|
|
|
59
63
|
}
|
|
60
64
|
/** Whether the native event's default action was prevented. */
|
|
61
65
|
get defaultPrevented() {
|
|
62
|
-
return !!_optionalChain([this, 'access',
|
|
66
|
+
return !!_optionalChain([this, 'access', _5 => _5.nativeEvent, 'optionalAccess', _6 => _6.defaultPrevented]);
|
|
63
67
|
}
|
|
64
68
|
/** Native horizontal wheel delta, if this wraps a `WheelEvent`. */
|
|
65
69
|
get deltaX() {
|
|
66
|
-
return _optionalChain([this, 'access',
|
|
70
|
+
return _optionalChain([this, 'access', _7 => _7.nativeEvent, 'optionalAccess', _8 => _8.deltaX]);
|
|
67
71
|
}
|
|
68
72
|
/** Native vertical wheel delta, if this wraps a `WheelEvent`. */
|
|
69
73
|
get deltaY() {
|
|
70
|
-
return _optionalChain([this, 'access',
|
|
74
|
+
return _optionalChain([this, 'access', _9 => _9.nativeEvent, 'optionalAccess', _10 => _10.deltaY]);
|
|
71
75
|
}
|
|
72
76
|
/** Native pointer X, if this wraps a pointer/mouse event. */
|
|
73
77
|
get clientX() {
|
|
74
|
-
return _optionalChain([this, 'access',
|
|
78
|
+
return _optionalChain([this, 'access', _11 => _11.nativeEvent, 'optionalAccess', _12 => _12.clientX]);
|
|
75
79
|
}
|
|
76
80
|
/** Native pointer Y, if this wraps a pointer/mouse event. */
|
|
77
81
|
get clientY() {
|
|
78
|
-
return _optionalChain([this, 'access',
|
|
82
|
+
return _optionalChain([this, 'access', _13 => _13.nativeEvent, 'optionalAccess', _14 => _14.clientY]);
|
|
79
83
|
}
|
|
80
84
|
get resolvedScenePoint() {
|
|
81
85
|
if (this.explicitScenePoint) return this.explicitScenePoint;
|
|
82
86
|
const native = this.nativeEvent;
|
|
83
|
-
if (_optionalChain([native, 'optionalAccess',
|
|
87
|
+
if (_optionalChain([native, 'optionalAccess', _15 => _15.vectoSceneX]) !== void 0 && native.vectoSceneY !== void 0) {
|
|
84
88
|
return { x: native.vectoSceneX, y: native.vectoSceneY };
|
|
85
89
|
}
|
|
86
|
-
if (_optionalChain([native, 'optionalAccess',
|
|
90
|
+
if (_optionalChain([native, 'optionalAccess', _16 => _16.clientX]) === void 0 || native.clientY === void 0) return void 0;
|
|
87
91
|
const scene = this.target.scene;
|
|
88
|
-
return _nullishCoalesce(_optionalChain([scene, 'optionalAccess',
|
|
92
|
+
return _nullishCoalesce(_optionalChain([scene, 'optionalAccess', _17 => _17.clientToScene, 'optionalCall', _18 => _18(native.clientX, native.clientY)]), () => ( {
|
|
89
93
|
x: native.clientX,
|
|
90
94
|
y: native.clientY
|
|
91
95
|
}));
|
|
92
96
|
}
|
|
93
97
|
/** Pointer X in the Scene's logical coordinate space. */
|
|
94
98
|
get sceneX() {
|
|
95
|
-
return _optionalChain([this, 'access',
|
|
99
|
+
return _optionalChain([this, 'access', _19 => _19.resolvedScenePoint, 'optionalAccess', _20 => _20.x]);
|
|
96
100
|
}
|
|
97
101
|
/** Pointer Y in the Scene's logical coordinate space. */
|
|
98
102
|
get sceneY() {
|
|
99
|
-
return _optionalChain([this, 'access',
|
|
103
|
+
return _optionalChain([this, 'access', _21 => _21.resolvedScenePoint, 'optionalAccess', _22 => _22.y]);
|
|
100
104
|
}
|
|
101
105
|
/** Pointer X local to the entity whose listener is currently running. */
|
|
102
106
|
get localX() {
|
|
103
107
|
const point = this.resolvedScenePoint;
|
|
104
108
|
if (!point) return void 0;
|
|
105
|
-
return _optionalChain([this, 'access',
|
|
109
|
+
return _optionalChain([this, 'access', _23 => _23.currentTarget, 'access', _24 => _24.worldToLocal, 'call', _25 => _25(point.x, point.y), 'optionalAccess', _26 => _26.x]);
|
|
106
110
|
}
|
|
107
111
|
/** Pointer Y local to the entity whose listener is currently running. */
|
|
108
112
|
get localY() {
|
|
109
113
|
const point = this.resolvedScenePoint;
|
|
110
114
|
if (!point) return void 0;
|
|
111
|
-
return _optionalChain([this, 'access',
|
|
115
|
+
return _optionalChain([this, 'access', _27 => _27.currentTarget, 'access', _28 => _28.worldToLocal, 'call', _29 => _29(point.x, point.y), 'optionalAccess', _30 => _30.y]);
|
|
112
116
|
}
|
|
113
117
|
get shiftKey() {
|
|
114
|
-
return !!_optionalChain([this, 'access',
|
|
118
|
+
return !!_optionalChain([this, 'access', _31 => _31.nativeEvent, 'optionalAccess', _32 => _32.shiftKey]);
|
|
115
119
|
}
|
|
116
120
|
get ctrlKey() {
|
|
117
|
-
return !!_optionalChain([this, 'access',
|
|
121
|
+
return !!_optionalChain([this, 'access', _33 => _33.nativeEvent, 'optionalAccess', _34 => _34.ctrlKey]);
|
|
118
122
|
}
|
|
119
123
|
get altKey() {
|
|
120
|
-
return !!_optionalChain([this, 'access',
|
|
124
|
+
return !!_optionalChain([this, 'access', _35 => _35.nativeEvent, 'optionalAccess', _36 => _36.altKey]);
|
|
121
125
|
}
|
|
122
126
|
get metaKey() {
|
|
123
|
-
return !!_optionalChain([this, 'access',
|
|
127
|
+
return !!_optionalChain([this, 'access', _37 => _37.nativeEvent, 'optionalAccess', _38 => _38.metaKey]);
|
|
124
128
|
}
|
|
125
129
|
/** Native key, if this wraps a keyboard event. */
|
|
126
130
|
get key() {
|
|
127
|
-
return _optionalChain([this, 'access',
|
|
131
|
+
return _optionalChain([this, 'access', _39 => _39.nativeEvent, 'optionalAccess', _40 => _40.key]);
|
|
128
132
|
}
|
|
129
133
|
}, _class);
|
|
130
134
|
var Entity = (_class2 = class {
|
|
@@ -253,6 +257,42 @@ var Entity = (_class2 = class {
|
|
|
253
257
|
* nodes, so on-top components stay clickable.
|
|
254
258
|
*/
|
|
255
259
|
__init33() {this.a11yFullViewport = false}
|
|
260
|
+
/**
|
|
261
|
+
* When this entity's a11y shadow node is materialized.
|
|
262
|
+
*
|
|
263
|
+
* `'eager'` (the default) keeps today's behaviour: a shadow node exists for as
|
|
264
|
+
* long as the entity is `interactive` with a box. That is right for a button or
|
|
265
|
+
* a link, and wrong for thousands of ephemeral, individually-meaningless
|
|
266
|
+
* entities — particles, danmaku, graph nodes — where it produces one DOM node
|
|
267
|
+
* per entity every frame.
|
|
268
|
+
*
|
|
269
|
+
* Measured on 5,000 moving interactive entities (`benchmarks/lazy-a11y/`):
|
|
270
|
+
* eager costs **72.2 ms/frame on Chrome and 114.3 ms on Firefox**, missing even
|
|
271
|
+
* 60 Hz, against **1.55/1.63 ms** for the same scene with one node projected —
|
|
272
|
+
* within noise of the 1.26/1.65 ms floor of projecting nothing at all.
|
|
273
|
+
*
|
|
274
|
+
* `'onDemand'` projects a node only while {@link Scene} considers the entity
|
|
275
|
+
* *engaged*: it is focused, it is the current pointer target, or it has been
|
|
276
|
+
* explicitly requested via {@link Scene.requestA11yProjection}. Crucially the
|
|
277
|
+
* trigger is not hover alone — a keyboard or assistive-technology user
|
|
278
|
+
* generates no hover, so a hover-only gate would remove exactly those users'
|
|
279
|
+
* access. Engagement therefore includes focus and an explicit request, and the
|
|
280
|
+
* entity stays hit-testable on canvas throughout, so a click still reaches it
|
|
281
|
+
* and promotes it.
|
|
282
|
+
*
|
|
283
|
+
* `'never'` suppresses the node entirely. Prefer `interactive = false` unless
|
|
284
|
+
* the entity genuinely needs pointer events without any semantic presence;
|
|
285
|
+
* this exists so a purely decorative interactive surface can opt out without
|
|
286
|
+
* losing canvas hit-testing.
|
|
287
|
+
*
|
|
288
|
+
* **This does not replace an aggregate description.** A thousand `'onDemand'`
|
|
289
|
+
* danmaku are individually reachable but say nothing collectively. The proven
|
|
290
|
+
* pattern is one aggregate live region (`role: 'status'`, `a11yFullViewport`)
|
|
291
|
+
* plus a small pool of persistent hotspots for the current selection — see
|
|
292
|
+
* `vectojs-native/danmaku`. Use `'onDemand'` to stop paying per entity, not as
|
|
293
|
+
* the whole accessibility story.
|
|
294
|
+
*/
|
|
295
|
+
__init34() {this.a11yProjection = "eager"}
|
|
256
296
|
/**
|
|
257
297
|
* Hide this entity AND its whole subtree from the accessibility/automation
|
|
258
298
|
* projection, regardless of each node's own `interactive` flag.
|
|
@@ -270,21 +310,21 @@ var Entity = (_class2 = class {
|
|
|
270
310
|
* `=== 0` test never fires; a threshold would instead silently un-project a
|
|
271
311
|
* faint-but-live control.
|
|
272
312
|
*/
|
|
273
|
-
|
|
313
|
+
__init35() {this.a11yHidden = false}
|
|
274
314
|
/**
|
|
275
315
|
* Clip this node's children to its local box (`[0,0]–[width,height]`) while
|
|
276
316
|
* rendering. Combined with translating a content child, this is how
|
|
277
317
|
* scroll/overflow containers (e.g. `ScrollView`) keep their content inside a
|
|
278
318
|
* fixed viewport. Off by default (children render unclipped). Canvas2D only.
|
|
279
319
|
*/
|
|
280
|
-
|
|
320
|
+
__init36() {this.clipChildren = false}
|
|
281
321
|
// Lazily allocated (see _drivers above). Most entities never register a
|
|
282
322
|
// listener or an imperative animate() tween.
|
|
283
|
-
|
|
323
|
+
__init37() {this.listeners = null}
|
|
284
324
|
/** Capture-phase listeners (fired root→target before bubble). */
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
constructor(id) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);_class2.prototype.__init12.call(this);_class2.prototype.__init13.call(this);_class2.prototype.__init14.call(this);_class2.prototype.__init15.call(this);_class2.prototype.__init16.call(this);_class2.prototype.__init17.call(this);_class2.prototype.__init18.call(this);_class2.prototype.__init19.call(this);_class2.prototype.__init20.call(this);_class2.prototype.__init21.call(this);_class2.prototype.__init22.call(this);_class2.prototype.__init23.call(this);_class2.prototype.__init24.call(this);_class2.prototype.__init25.call(this);_class2.prototype.__init26.call(this);_class2.prototype.__init27.call(this);_class2.prototype.__init28.call(this);_class2.prototype.__init29.call(this);_class2.prototype.__init30.call(this);_class2.prototype.__init31.call(this);_class2.prototype.__init32.call(this);_class2.prototype.__init33.call(this);_class2.prototype.__init34.call(this);_class2.prototype.__init35.call(this);_class2.prototype.__init36.call(this);_class2.prototype.__init37.call(this);_class2.prototype.__init38.call(this);
|
|
325
|
+
__init38() {this.captureListeners = null}
|
|
326
|
+
__init39() {this.animations = null}
|
|
327
|
+
constructor(id) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);_class2.prototype.__init11.call(this);_class2.prototype.__init12.call(this);_class2.prototype.__init13.call(this);_class2.prototype.__init14.call(this);_class2.prototype.__init15.call(this);_class2.prototype.__init16.call(this);_class2.prototype.__init17.call(this);_class2.prototype.__init18.call(this);_class2.prototype.__init19.call(this);_class2.prototype.__init20.call(this);_class2.prototype.__init21.call(this);_class2.prototype.__init22.call(this);_class2.prototype.__init23.call(this);_class2.prototype.__init24.call(this);_class2.prototype.__init25.call(this);_class2.prototype.__init26.call(this);_class2.prototype.__init27.call(this);_class2.prototype.__init28.call(this);_class2.prototype.__init29.call(this);_class2.prototype.__init30.call(this);_class2.prototype.__init31.call(this);_class2.prototype.__init32.call(this);_class2.prototype.__init33.call(this);_class2.prototype.__init34.call(this);_class2.prototype.__init35.call(this);_class2.prototype.__init36.call(this);_class2.prototype.__init37.call(this);_class2.prototype.__init38.call(this);_class2.prototype.__init39.call(this);
|
|
288
328
|
this.id = id || `entity_${Math.random().toString(36).substring(2, 9)}`;
|
|
289
329
|
}
|
|
290
330
|
/**
|
|
@@ -318,7 +358,7 @@ var Entity = (_class2 = class {
|
|
|
318
358
|
const s = this.scene;
|
|
319
359
|
if (s) {
|
|
320
360
|
s.a11yNeedsReorder = true;
|
|
321
|
-
_optionalChain([s, 'access',
|
|
361
|
+
_optionalChain([s, 'access', _41 => _41.markStructureChanged, 'optionalCall', _42 => _42()]);
|
|
322
362
|
s.markDirty({ entity: this.id, reason: "child-added" });
|
|
323
363
|
child._notifyMounted();
|
|
324
364
|
}
|
|
@@ -348,7 +388,7 @@ var Entity = (_class2 = class {
|
|
|
348
388
|
if (s) {
|
|
349
389
|
s.detachA11y(child);
|
|
350
390
|
s.a11yNeedsReorder = true;
|
|
351
|
-
_optionalChain([s, 'access',
|
|
391
|
+
_optionalChain([s, 'access', _43 => _43.markStructureChanged, 'optionalCall', _44 => _44()]);
|
|
352
392
|
s.markDirty({ entity: this.id, reason: "child-removed" });
|
|
353
393
|
}
|
|
354
394
|
}
|
|
@@ -403,7 +443,7 @@ var Entity = (_class2 = class {
|
|
|
403
443
|
startTime: -1,
|
|
404
444
|
startProps: {}
|
|
405
445
|
});
|
|
406
|
-
_optionalChain([this, 'access',
|
|
446
|
+
_optionalChain([this, 'access', _45 => _45.scene, 'optionalAccess', _46 => _46.markDirty, 'call', _47 => _47({ entity: this.id, reason: "animation-start" })]);
|
|
407
447
|
return this;
|
|
408
448
|
}
|
|
409
449
|
/** Write a driver-computed value to a backing field without re-triggering the setter. */
|
|
@@ -450,26 +490,26 @@ var Entity = (_class2 = class {
|
|
|
450
490
|
* that need to seed a starting state (e.g. the presence helper's enter `from`).
|
|
451
491
|
*/
|
|
452
492
|
setImmediate(prop, v) {
|
|
453
|
-
const existing = _optionalChain([this, 'access',
|
|
493
|
+
const existing = _optionalChain([this, 'access', _48 => _48._drivers, 'optionalAccess', _49 => _49.get, 'call', _50 => _50(prop)]);
|
|
454
494
|
if (existing) this._settleDriver(existing);
|
|
455
|
-
_optionalChain([this, 'access',
|
|
495
|
+
_optionalChain([this, 'access', _51 => _51._drivers, 'optionalAccess', _52 => _52.delete, 'call', _53 => _53(prop)]);
|
|
456
496
|
this._applyAnimated(prop, v);
|
|
457
497
|
}
|
|
458
498
|
_settleDriver(driver) {
|
|
459
499
|
const active = driver;
|
|
460
500
|
const onDone = active.onDone;
|
|
461
501
|
active.onDone = void 0;
|
|
462
|
-
_optionalChain([onDone, 'optionalCall',
|
|
502
|
+
_optionalChain([onDone, 'optionalCall', _54 => _54()]);
|
|
463
503
|
}
|
|
464
504
|
_spawnDriver(prop, to, cfg) {
|
|
465
|
-
if (prop !== "opacity" && _optionalChain([this, 'access',
|
|
466
|
-
const existing2 = _optionalChain([this, 'access',
|
|
505
|
+
if (prop !== "opacity" && _optionalChain([this, 'access', _55 => _55.scene, 'optionalAccess', _56 => _56.prefersReducedMotion])) {
|
|
506
|
+
const existing2 = _optionalChain([this, 'access', _57 => _57._drivers, 'optionalAccess', _58 => _58.get, 'call', _59 => _59(prop)]);
|
|
467
507
|
if (existing2) this._settleDriver(existing2);
|
|
468
|
-
_optionalChain([this, 'access',
|
|
508
|
+
_optionalChain([this, 'access', _60 => _60._drivers, 'optionalAccess', _61 => _61.delete, 'call', _62 => _62(prop)]);
|
|
469
509
|
this._applyAnimated(prop, to);
|
|
470
510
|
return;
|
|
471
511
|
}
|
|
472
|
-
const existing = _optionalChain([this, 'access',
|
|
512
|
+
const existing = _optionalChain([this, 'access', _63 => _63._drivers, 'optionalAccess', _64 => _64.get, 'call', _65 => _65(prop)]);
|
|
473
513
|
if (existing) {
|
|
474
514
|
this._settleDriver(existing);
|
|
475
515
|
existing.retarget(to);
|
|
@@ -478,12 +518,12 @@ var Entity = (_class2 = class {
|
|
|
478
518
|
const from = this._currentOf(prop);
|
|
479
519
|
const driver = _animation.isTweenConfig.call(void 0, cfg) ? new (0, _animation.TweenDriver)(from, to, cfg) : new (0, _animation.SpringDriver)(from, to, cfg === "spring" ? {} : cfg);
|
|
480
520
|
(this._drivers ??= /* @__PURE__ */ new Map()).set(prop, driver);
|
|
481
|
-
_optionalChain([this, 'access',
|
|
482
|
-
_optionalChain([this, 'access',
|
|
521
|
+
_optionalChain([this, 'access', _66 => _66.scene, 'optionalAccess', _67 => _67.markDirty, 'call', _68 => _68({ entity: this.id, reason: "driver-added" })]);
|
|
522
|
+
_optionalChain([this, 'access', _69 => _69.scene, 'optionalAccess', _70 => _70._registerActiveDriverEntity, 'call', _71 => _71(this)]);
|
|
483
523
|
}
|
|
484
524
|
/** Assignment path when a declarative transition is configured for `prop`. */
|
|
485
525
|
_animateProp(prop, to) {
|
|
486
|
-
const cfg = _optionalChain([this, 'access',
|
|
526
|
+
const cfg = _optionalChain([this, 'access', _72 => _72._transitions, 'optionalAccess', _73 => _73.get, 'call', _74 => _74(prop)]);
|
|
487
527
|
if (!cfg) {
|
|
488
528
|
this._applyAnimated(prop, to);
|
|
489
529
|
return;
|
|
@@ -512,7 +552,7 @@ var Entity = (_class2 = class {
|
|
|
512
552
|
entries.map(
|
|
513
553
|
(e) => new Promise((resolve) => {
|
|
514
554
|
this._spawnDriver(e[0], e[1], cfg);
|
|
515
|
-
const d = _optionalChain([this, 'access',
|
|
555
|
+
const d = _optionalChain([this, 'access', _75 => _75._drivers, 'optionalAccess', _76 => _76.get, 'call', _77 => _77(e[0])]);
|
|
516
556
|
if (!d)
|
|
517
557
|
resolve();
|
|
518
558
|
else d.onDone = resolve;
|
|
@@ -534,7 +574,7 @@ var Entity = (_class2 = class {
|
|
|
534
574
|
this._applyAnimated(prop, driver.value);
|
|
535
575
|
}
|
|
536
576
|
}
|
|
537
|
-
_optionalChain([this, 'access',
|
|
577
|
+
_optionalChain([this, 'access', _78 => _78.scene, 'optionalAccess', _79 => _79.markDirty, 'call', _80 => _80({ entity: this.id, reason: "driver-tick" })]);
|
|
538
578
|
}
|
|
539
579
|
/**
|
|
540
580
|
* Internal: this entity's active-driver map (read-only view), or `null` if
|
|
@@ -559,7 +599,7 @@ var Entity = (_class2 = class {
|
|
|
559
599
|
if (driver.isDone()) {
|
|
560
600
|
this._applyAnimated(prop, driver.target);
|
|
561
601
|
this._settleDriver(driver);
|
|
562
|
-
_optionalChain([this, 'access',
|
|
602
|
+
_optionalChain([this, 'access', _81 => _81._drivers, 'optionalAccess', _82 => _82.delete, 'call', _83 => _83(prop)]);
|
|
563
603
|
} else {
|
|
564
604
|
this._applyAnimated(prop, driver.value);
|
|
565
605
|
}
|
|
@@ -620,7 +660,7 @@ var Entity = (_class2 = class {
|
|
|
620
660
|
* @example entity.on('click', (e) => console.log('clicked', e));
|
|
621
661
|
*/
|
|
622
662
|
on(event, callback, options) {
|
|
623
|
-
const map = _optionalChain([options, 'optionalAccess',
|
|
663
|
+
const map = _optionalChain([options, 'optionalAccess', _84 => _84.capture]) ? this.captureListeners ??= /* @__PURE__ */ new Map() : this.listeners ??= /* @__PURE__ */ new Map();
|
|
624
664
|
if (!map.has(event)) {
|
|
625
665
|
map.set(event, []);
|
|
626
666
|
}
|
|
@@ -636,7 +676,7 @@ var Entity = (_class2 = class {
|
|
|
636
676
|
* @returns `this` for method chaining.
|
|
637
677
|
*/
|
|
638
678
|
off(event, callback, options) {
|
|
639
|
-
const handlers = _optionalChain([(_optionalChain([options, 'optionalAccess',
|
|
679
|
+
const handlers = _optionalChain([(_optionalChain([options, 'optionalAccess', _85 => _85.capture]) ? this.captureListeners : this.listeners), 'optionalAccess', _86 => _86.get, 'call', _87 => _87(event)]);
|
|
640
680
|
if (handlers) {
|
|
641
681
|
const idx = handlers.indexOf(callback);
|
|
642
682
|
if (idx !== -1) handlers.splice(idx, 1);
|
|
@@ -673,8 +713,8 @@ var Entity = (_class2 = class {
|
|
|
673
713
|
}
|
|
674
714
|
this._drivers.clear();
|
|
675
715
|
}
|
|
676
|
-
_optionalChain([this, 'access',
|
|
677
|
-
_optionalChain([this, 'access',
|
|
716
|
+
_optionalChain([this, 'access', _88 => _88.listeners, 'optionalAccess', _89 => _89.clear, 'call', _90 => _90()]);
|
|
717
|
+
_optionalChain([this, 'access', _91 => _91.captureListeners, 'optionalAccess', _92 => _92.clear, 'call', _93 => _93()]);
|
|
678
718
|
if (this.parent) {
|
|
679
719
|
this.parent.remove(this);
|
|
680
720
|
}
|
|
@@ -689,7 +729,7 @@ var Entity = (_class2 = class {
|
|
|
689
729
|
* @param payload - Arbitrary data forwarded to each listener.
|
|
690
730
|
*/
|
|
691
731
|
emit(event, payload) {
|
|
692
|
-
const handlers = _optionalChain([this, 'access',
|
|
732
|
+
const handlers = _optionalChain([this, 'access', _94 => _94.listeners, 'optionalAccess', _95 => _95.get, 'call', _96 => _96(event)]);
|
|
693
733
|
if (handlers) {
|
|
694
734
|
handlers.forEach((h) => h(payload));
|
|
695
735
|
}
|
|
@@ -703,19 +743,19 @@ var Entity = (_class2 = class {
|
|
|
703
743
|
* with `requestAnimationFrame(() => document.getElementById(id)?.focus())`.
|
|
704
744
|
*/
|
|
705
745
|
focus() {
|
|
706
|
-
const el = _optionalChain([this, 'access',
|
|
746
|
+
const el = _optionalChain([this, 'access', _97 => _97.scene, 'optionalAccess', _98 => _98.getA11yElement, 'call', _99 => _99(this.id)]);
|
|
707
747
|
if (el) {
|
|
708
748
|
el.focus();
|
|
709
749
|
return;
|
|
710
750
|
}
|
|
711
751
|
requestAnimationFrame(() => {
|
|
712
|
-
const retry = _optionalChain([this, 'access',
|
|
752
|
+
const retry = _optionalChain([this, 'access', _100 => _100.scene, 'optionalAccess', _101 => _101.getA11yElement, 'call', _102 => _102(this.id)]);
|
|
713
753
|
if (retry) retry.focus();
|
|
714
754
|
});
|
|
715
755
|
}
|
|
716
756
|
/** Run one node's listeners for the event, honoring stopImmediatePropagation. */
|
|
717
757
|
fireListeners(node, map, event) {
|
|
718
|
-
const handlers = _optionalChain([map, 'optionalAccess',
|
|
758
|
+
const handlers = _optionalChain([map, 'optionalAccess', _103 => _103.get, 'call', _104 => _104(event.type)]);
|
|
719
759
|
if (!handlers) return;
|
|
720
760
|
event.currentTarget = node;
|
|
721
761
|
for (const h of handlers.slice()) {
|
|
@@ -1047,9 +1087,14 @@ var Entity = (_class2 = class {
|
|
|
1047
1087
|
* `selectable` is set — natively selectable. Returns `null` by default.
|
|
1048
1088
|
* Read on the a11y sync cadence, so text changes propagate automatically.
|
|
1049
1089
|
*
|
|
1090
|
+
* @param hint - Optional advice about which part of the entity is worth
|
|
1091
|
+
* describing. Purely an optimization: ignoring it is always correct, which
|
|
1092
|
+
* is why it is a parameter rather than a required contract change. See
|
|
1093
|
+
* {@link ContentProjectionHint}.
|
|
1050
1094
|
* @returns The projection descriptor, or `null` to project nothing.
|
|
1051
1095
|
*/
|
|
1052
|
-
getContentProjection() {
|
|
1096
|
+
getContentProjection(hint) {
|
|
1097
|
+
void hint;
|
|
1053
1098
|
return null;
|
|
1054
1099
|
}
|
|
1055
1100
|
/**
|
|
@@ -1069,7 +1114,7 @@ var Entity = (_class2 = class {
|
|
|
1069
1114
|
* @returns `true` if at least one animation or property driver remains.
|
|
1070
1115
|
*/
|
|
1071
1116
|
hasPendingAnimations() {
|
|
1072
|
-
return (_nullishCoalesce(_optionalChain([this, 'access',
|
|
1117
|
+
return (_nullishCoalesce(_optionalChain([this, 'access', _105 => _105.animations, 'optionalAccess', _106 => _106.length]), () => ( 0))) > 0 || (_nullishCoalesce(_optionalChain([this, 'access', _107 => _107._drivers, 'optionalAccess', _108 => _108.size]), () => ( 0))) > 0;
|
|
1073
1118
|
}
|
|
1074
1119
|
}, _class2);
|
|
1075
1120
|
|
|
@@ -1091,20 +1136,20 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1091
1136
|
// joined by soft hyphens (U+00AD); the worker then treats those as break
|
|
1092
1137
|
// opportunities. `text` keeps the original string for a11y/content
|
|
1093
1138
|
// projection; `layoutText` is the soft-hyphen-annotated string sent to layout.
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1139
|
+
__init40() {this.hyphenator = null}
|
|
1140
|
+
__init41() {this.layoutText = ""}
|
|
1141
|
+
__init42() {this.text = ""}
|
|
1142
|
+
__init43() {this.lastRenderedSeqId = 0}
|
|
1098
1143
|
// Atlas-decode subscription (see watchAtlasDecode). Held so `destroy()` can
|
|
1099
1144
|
// release it: the handler closes over `this`, so leaving it attached to a
|
|
1100
1145
|
// long-lived shared atlas image would retain the whole entity.
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1146
|
+
__init44() {this.atlasDecodeTarget = null}
|
|
1147
|
+
__init45() {this.atlasDecodeHandler = null}
|
|
1148
|
+
__init46() {this.rgbColorCache = /* @__PURE__ */ new Map()}
|
|
1149
|
+
__init47() {this.fontStringCache = []}
|
|
1150
|
+
__init48() {this.layoutResult = null}
|
|
1106
1151
|
constructor(text, options) {
|
|
1107
|
-
super();_class3.prototype.
|
|
1152
|
+
super();_class3.prototype.__init40.call(this);_class3.prototype.__init41.call(this);_class3.prototype.__init42.call(this);_class3.prototype.__init43.call(this);_class3.prototype.__init44.call(this);_class3.prototype.__init45.call(this);_class3.prototype.__init46.call(this);_class3.prototype.__init47.call(this);_class3.prototype.__init48.call(this);;
|
|
1108
1153
|
this.font = options.font;
|
|
1109
1154
|
this.texture = options.texture;
|
|
1110
1155
|
this.fallbackFont = _nullishCoalesce(options.fallbackFont, () => ( "sans-serif"));
|
|
@@ -1149,7 +1194,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1149
1194
|
const target = this.texture;
|
|
1150
1195
|
this.atlasDecodeHandler = () => {
|
|
1151
1196
|
this.detachAtlasDecodeListener();
|
|
1152
|
-
_optionalChain([this, 'access',
|
|
1197
|
+
_optionalChain([this, 'access', _109 => _109.scene, 'optionalAccess', _110 => _110.markDirty, 'call', _111 => _111()]);
|
|
1153
1198
|
};
|
|
1154
1199
|
target.addEventListener("load", this.atlasDecodeHandler);
|
|
1155
1200
|
target.addEventListener("error", this.atlasDecodeHandler);
|
|
@@ -1227,7 +1272,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1227
1272
|
if (res.seqId < this.lastRenderedSeqId) return;
|
|
1228
1273
|
this.lastRenderedSeqId = res.seqId;
|
|
1229
1274
|
this.layoutResult = res;
|
|
1230
|
-
_optionalChain([this, 'access',
|
|
1275
|
+
_optionalChain([this, 'access', _112 => _112.scene, 'optionalAccess', _113 => _113.markDirty, 'call', _114 => _114()]);
|
|
1231
1276
|
}
|
|
1232
1277
|
});
|
|
1233
1278
|
}
|
|
@@ -1376,23 +1421,23 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1376
1421
|
* rasterized. Set to `'transparent'` to opt out and keep the box empty.
|
|
1377
1422
|
* Default `'rgba(248,113,113,0.9)'`.
|
|
1378
1423
|
*/
|
|
1379
|
-
|
|
1424
|
+
__init49() {this.fallbackStroke = "rgba(248,113,113,0.9)"}
|
|
1380
1425
|
/** Fill behind the fallback marker. Default `'rgba(248,113,113,0.12)'`. */
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1426
|
+
__init50() {this.fallbackFill = "rgba(248,113,113,0.12)"}
|
|
1427
|
+
__init51() {this.svgSource = ""}
|
|
1428
|
+
__init52() {this.imageBitmap = null}
|
|
1429
|
+
__init53() {this.imageElement = null}
|
|
1430
|
+
__init54() {this.blobURL = null}
|
|
1431
|
+
__init55() {this.currentImg = null}
|
|
1432
|
+
__init56() {this.lodTimeout = null}
|
|
1433
|
+
__init57() {this.rasterFailed = false}
|
|
1434
|
+
__init58() {this.cachedDoc = null}
|
|
1435
|
+
__init59() {this.baseWidth = 100}
|
|
1436
|
+
__init60() {this.baseHeight = 100}
|
|
1437
|
+
__init61() {this.lastRasterizedScale = 1}
|
|
1438
|
+
__init62() {this.targetScale = 1}
|
|
1394
1439
|
constructor(svgSource, id) {
|
|
1395
|
-
super(id);_class4.prototype.
|
|
1440
|
+
super(id);_class4.prototype.__init49.call(this);_class4.prototype.__init50.call(this);_class4.prototype.__init51.call(this);_class4.prototype.__init52.call(this);_class4.prototype.__init53.call(this);_class4.prototype.__init54.call(this);_class4.prototype.__init55.call(this);_class4.prototype.__init56.call(this);_class4.prototype.__init57.call(this);_class4.prototype.__init58.call(this);_class4.prototype.__init59.call(this);_class4.prototype.__init60.call(this);_class4.prototype.__init61.call(this);_class4.prototype.__init62.call(this);;
|
|
1396
1441
|
this.setSVGSource(svgSource);
|
|
1397
1442
|
}
|
|
1398
1443
|
setSVGSource(svgSource) {
|
|
@@ -1640,4 +1685,5 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1640
1685
|
|
|
1641
1686
|
|
|
1642
1687
|
|
|
1643
|
-
|
|
1688
|
+
|
|
1689
|
+
exports.contentLineInHint = contentLineInHint; exports.VectoJSEvent = VectoJSEvent; exports.Entity = Entity; exports.MSDFTextEntity = MSDFTextEntity; exports.SVGEntity = SVGEntity;
|
|
@@ -86,6 +86,12 @@ var CanvasRenderer = class _CanvasRenderer {
|
|
|
86
86
|
* change at runtime (e.g. a window dragged between displays).
|
|
87
87
|
*/
|
|
88
88
|
maxDPR;
|
|
89
|
+
/**
|
|
90
|
+
* The ratio the context is actually scaled by, i.e. the last value the
|
|
91
|
+
* constructor or {@link resize} applied. Backs {@link pixelRatio}; see there
|
|
92
|
+
* for why this is recorded rather than recomputed on read.
|
|
93
|
+
*/
|
|
94
|
+
appliedDPR = 1;
|
|
89
95
|
/**
|
|
90
96
|
* Max circles per batched `fill()`. A single Canvas 2D `fill()` over a path is
|
|
91
97
|
* superlinear in sub-path count, so an unbounded batch is *slower* than many
|
|
@@ -124,6 +130,7 @@ var CanvasRenderer = class _CanvasRenderer {
|
|
|
124
130
|
constructor(canvas, size, maxDPR) {
|
|
125
131
|
this.maxDPR = maxDPR;
|
|
126
132
|
const dpr = this.effectiveDPR();
|
|
133
|
+
this.appliedDPR = dpr;
|
|
127
134
|
this.width = size?.width ?? (typeof window !== "undefined" ? window.innerWidth : canvas.width || 0);
|
|
128
135
|
this.height = size?.height ?? (typeof window !== "undefined" ? window.innerHeight : canvas.height || 0);
|
|
129
136
|
canvas.width = this.width * dpr;
|
|
@@ -162,7 +169,9 @@ var CanvasRenderer = class _CanvasRenderer {
|
|
|
162
169
|
if (!ctx) return;
|
|
163
170
|
this.ctx = ctx;
|
|
164
171
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
165
|
-
|
|
172
|
+
const restoredDPR = this.effectiveDPR();
|
|
173
|
+
this.appliedDPR = restoredDPR;
|
|
174
|
+
ctx.scale(restoredDPR, restoredDPR);
|
|
166
175
|
this._cachedFont = "";
|
|
167
176
|
this._cachedFill = "";
|
|
168
177
|
this.batchActive = false;
|
|
@@ -185,6 +194,25 @@ var CanvasRenderer = class _CanvasRenderer {
|
|
|
185
194
|
const real = getDevicePixelRatio();
|
|
186
195
|
return this.maxDPR !== void 0 ? Math.min(real, this.maxDPR) : real;
|
|
187
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* @inheritdoc
|
|
199
|
+
*
|
|
200
|
+
* The ratio the context is **currently scaled by**, recorded by the constructor
|
|
201
|
+
* and {@link resize} — deliberately not a live `effectiveDPR()` call.
|
|
202
|
+
*
|
|
203
|
+
* The distinction is load-bearing rather than pedantic. `devicePixelRatio`
|
|
204
|
+
* changes the instant a zoom lands, but the backing store is only reallocated
|
|
205
|
+
* when something calls {@link resize} (in a `Scene`, the `(resolution: Ndppx)`
|
|
206
|
+
* media query). A live getter therefore reports the *future* ratio during that
|
|
207
|
+
* window, and a caller rasterizing pixels from it produces a texture that the
|
|
208
|
+
* still-old context scale resamples — the same defect this property exists to
|
|
209
|
+
* let callers avoid, merely inverted. Reporting the applied ratio means a
|
|
210
|
+
* cache keyed on it is always consistent with the pixels it is blitted into,
|
|
211
|
+
* and it simply re-keys on the next `resize`.
|
|
212
|
+
*/
|
|
213
|
+
get pixelRatio() {
|
|
214
|
+
return this.appliedDPR;
|
|
215
|
+
}
|
|
188
216
|
/**
|
|
189
217
|
* Resize the backing canvas buffer and re-apply DPR scaling.
|
|
190
218
|
*
|
|
@@ -195,6 +223,7 @@ var CanvasRenderer = class _CanvasRenderer {
|
|
|
195
223
|
*/
|
|
196
224
|
resize(width, height) {
|
|
197
225
|
const dpr = this.effectiveDPR();
|
|
226
|
+
this.appliedDPR = dpr;
|
|
198
227
|
this.width = width;
|
|
199
228
|
this.height = height;
|
|
200
229
|
this.ctx.canvas.width = width * dpr;
|
|
@@ -2075,6 +2104,20 @@ var GlyphRasterAtlas = class {
|
|
|
2075
2104
|
this.dpr = Math.max(1, options.dpr ?? 1);
|
|
2076
2105
|
this.maxSize = Math.min(HARD_MAX_SIZE, Math.max(256, options.maxSize ?? 2048));
|
|
2077
2106
|
}
|
|
2107
|
+
/**
|
|
2108
|
+
* The device-pixel-ratio these slots were rasterized at.
|
|
2109
|
+
*
|
|
2110
|
+
* Immutable by design. Slot `sx`/`sy`/`sw`/`sh` are device pixels at *this*
|
|
2111
|
+
* ratio while `w`/`h` are CSS pixels, so changing it would invalidate every
|
|
2112
|
+
* resident slot — an atlas is therefore keyed by DPR and replaced on a change,
|
|
2113
|
+
* not mutated (see `Markdown`'s code atlas pool). Exposed so a caller can
|
|
2114
|
+
* compare it against {@link IRenderer.pixelRatio} and assert the blit is
|
|
2115
|
+
* 1:1 rather than resampled: `blitScale = renderer.pixelRatio / atlas.dpr`,
|
|
2116
|
+
* which must be 1 for the pixels to land crisp.
|
|
2117
|
+
*/
|
|
2118
|
+
get pixelRatio() {
|
|
2119
|
+
return this.dpr;
|
|
2120
|
+
}
|
|
2078
2121
|
/** Live instrumentation snapshot. */
|
|
2079
2122
|
get stats() {
|
|
2080
2123
|
return {
|