@vectojs/core 1.39.1 → 1.40.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-7PYD5UDX.mjs → chunk-CIRZ3S2Z.mjs} +48 -3
- package/dist/{chunk-POPXUPKR.js → chunk-HC5EZOZJ.js} +80 -35
- package/dist/components/VirtualizedSetAggregate.d.ts +110 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1040 -206
- package/dist/index.mjs +839 -5
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +59 -1
- package/dist/tree/Scene.d.ts +195 -1
- package/dist/tree/scene/HitResult.d.ts +50 -0
- package/dist/tree/scene/HitTester.d.ts +30 -0
- package/dist/tree/scene/ProjectionBackend.d.ts +64 -0
- package/dist/tree/scene/ProjectionPolicy.d.ts +162 -0
- package/dist/tree/scene/SemanticProjectionPolicy.d.ts +119 -0
- package/dist/wasm/vectojs_core.wasm +0 -0
- package/package.json +2 -2
|
@@ -27,16 +27,22 @@ var VectoJSEvent = class {
|
|
|
27
27
|
nativeEvent;
|
|
28
28
|
/** Whether the event bubbles past its target (capture always runs). */
|
|
29
29
|
bubbles;
|
|
30
|
+
/**
|
|
31
|
+
* Which transport delivered this event ({@link VectoEventSource}).
|
|
32
|
+
* `undefined` for unattributed legacy/synthetic dispatches.
|
|
33
|
+
*/
|
|
34
|
+
source;
|
|
30
35
|
explicitScenePoint;
|
|
31
36
|
stopped = false;
|
|
32
37
|
stoppedImmediate = false;
|
|
33
|
-
constructor(type, target, nativeEvent, bubbles = true, scenePoint) {
|
|
38
|
+
constructor(type, target, nativeEvent, bubbles = true, scenePoint, source) {
|
|
34
39
|
this.type = type;
|
|
35
40
|
this.target = target;
|
|
36
41
|
this.currentTarget = target;
|
|
37
42
|
this.nativeEvent = nativeEvent;
|
|
38
43
|
this.bubbles = bubbles;
|
|
39
44
|
this.explicitScenePoint = scenePoint;
|
|
45
|
+
this.source = source;
|
|
40
46
|
}
|
|
41
47
|
/** Stop the event from reaching the next node in the propagation path. */
|
|
42
48
|
stopPropagation() {
|
|
@@ -330,6 +336,41 @@ var Entity = class {
|
|
|
330
336
|
* faint-but-live control.
|
|
331
337
|
*/
|
|
332
338
|
a11yHidden = false;
|
|
339
|
+
/**
|
|
340
|
+
* Opt-in to the DOM visual projection (RFC2, implemented by `@vectojs/dom`).
|
|
341
|
+
* Plain data only — core never materializes an element from this; a
|
|
342
|
+
* registered `ProjectionBackend` does.
|
|
343
|
+
*
|
|
344
|
+
* Name mapping: this field IS the RFC4 §2 `projection` policy
|
|
345
|
+
* (`ProjectionPolicy`: `'canvas' | 'dom' | 'auto'` in
|
|
346
|
+
* `tree/scene/ProjectionPolicy.ts`) — predates the RFC, so the field keeps
|
|
347
|
+
* its name and the RFC spelling lives on the value type.
|
|
348
|
+
*
|
|
349
|
+
* - `'canvas'` (default): today's rendering. Zero behavior change.
|
|
350
|
+
* - `'dom'`: the node materializes as a live `HTMLElement` positioned by its
|
|
351
|
+
* world matrix. The live element replaces the transparent a11y mirror
|
|
352
|
+
* (same single-delivery reasoning as `DOMPortalEntity`), so opting in
|
|
353
|
+
* requires a DOM backend and a DOM environment for the AT representation.
|
|
354
|
+
* - `'auto'`: negotiated per node per frame by `Scene.resolveProjectionFor`
|
|
355
|
+
* (RFC4 §3: explicit beats automatic, fallbacks reported with reasons,
|
|
356
|
+
* hysteresis against flip-flop, no-DOM short-circuits to canvas).
|
|
357
|
+
*/
|
|
358
|
+
domPolicy = "canvas";
|
|
359
|
+
/**
|
|
360
|
+
* Backend-side creation hint for a `'dom'`-policy node (tag/content mapping
|
|
361
|
+
* key, e.g. `'text' | 'button' | 'input' | 'container' | 'transform'`). Plain
|
|
362
|
+
* string so custom nodes need no DOM types in core; `@vectojs/dom` owns the
|
|
363
|
+
* registry. `''` means a plain positioned `div` with no content sync.
|
|
364
|
+
*/
|
|
365
|
+
domKind = "";
|
|
366
|
+
/**
|
|
367
|
+
* Internal cache owned by the DOM backend: true while the node has a live
|
|
368
|
+
* projected element. The render walk reads it to skip canvas paint for
|
|
369
|
+
* DOM-resident nodes (so a mounted node is never double-drawn) and falls
|
|
370
|
+
* through to canvas while false (SSR / no backend registered). Do not set
|
|
371
|
+
* by hand — the backend sets it on mount and clears it on unmount.
|
|
372
|
+
*/
|
|
373
|
+
domResident = false;
|
|
333
374
|
/**
|
|
334
375
|
* Clip this node's children to its local box (`[0,0]–[width,height]`) while
|
|
335
376
|
* rendering. Combined with translating a content child, this is how
|
|
@@ -631,8 +672,7 @@ var Entity = class {
|
|
|
631
672
|
(e) => new Promise((resolve) => {
|
|
632
673
|
this._spawnDriver(e[0], e[1], cfg);
|
|
633
674
|
const d = this._drivers?.get(e[0]);
|
|
634
|
-
if (!d)
|
|
635
|
-
resolve();
|
|
675
|
+
if (!d) resolve();
|
|
636
676
|
else d.onDone = resolve;
|
|
637
677
|
})
|
|
638
678
|
)
|
|
@@ -822,6 +862,7 @@ var Entity = class {
|
|
|
822
862
|
el.focus();
|
|
823
863
|
return;
|
|
824
864
|
}
|
|
865
|
+
if (typeof requestAnimationFrame === "undefined") return;
|
|
825
866
|
requestAnimationFrame(() => {
|
|
826
867
|
const retry = this.scene?.getA11yElement(this.id);
|
|
827
868
|
if (retry) retry.focus();
|
|
@@ -1188,6 +1229,10 @@ var Entity = class {
|
|
|
1188
1229
|
* `selectable` is set — natively selectable. Returns `null` by default.
|
|
1189
1230
|
* Read on the a11y sync cadence, so text changes propagate automatically.
|
|
1190
1231
|
*
|
|
1232
|
+
* This is the descriptor half of the `ContentProjection` row of
|
|
1233
|
+
* `ProjectionBackend` (`tree/scene/ProjectionBackend.ts`): the entity
|
|
1234
|
+
* describes *what* to project, the scene owns *how* it is materialized.
|
|
1235
|
+
*
|
|
1191
1236
|
* @param hint - Optional advice about which part of the entity is worth
|
|
1192
1237
|
* describing. Purely an optimization: ignoring it is always correct, which
|
|
1193
1238
|
* is why it is a parameter rather than a required contract change. See
|
|
@@ -29,16 +29,22 @@ var VectoJSEvent = (_class = class {
|
|
|
29
29
|
|
|
30
30
|
/** Whether the event bubbles past its target (capture always runs). */
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Which transport delivered this event ({@link VectoEventSource}).
|
|
34
|
+
* `undefined` for unattributed legacy/synthetic dispatches.
|
|
35
|
+
*/
|
|
36
|
+
|
|
32
37
|
|
|
33
38
|
__init() {this.stopped = false}
|
|
34
39
|
__init2() {this.stoppedImmediate = false}
|
|
35
|
-
constructor(type, target, nativeEvent, bubbles = true, scenePoint) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
|
|
40
|
+
constructor(type, target, nativeEvent, bubbles = true, scenePoint, source) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
|
|
36
41
|
this.type = type;
|
|
37
42
|
this.target = target;
|
|
38
43
|
this.currentTarget = target;
|
|
39
44
|
this.nativeEvent = nativeEvent;
|
|
40
45
|
this.bubbles = bubbles;
|
|
41
46
|
this.explicitScenePoint = scenePoint;
|
|
47
|
+
this.source = source;
|
|
42
48
|
}
|
|
43
49
|
/** Stop the event from reaching the next node in the propagation path. */
|
|
44
50
|
stopPropagation() {
|
|
@@ -332,13 +338,48 @@ var Entity = (_class2 = class {
|
|
|
332
338
|
* faint-but-live control.
|
|
333
339
|
*/
|
|
334
340
|
__init36() {this.a11yHidden = false}
|
|
341
|
+
/**
|
|
342
|
+
* Opt-in to the DOM visual projection (RFC2, implemented by `@vectojs/dom`).
|
|
343
|
+
* Plain data only — core never materializes an element from this; a
|
|
344
|
+
* registered `ProjectionBackend` does.
|
|
345
|
+
*
|
|
346
|
+
* Name mapping: this field IS the RFC4 §2 `projection` policy
|
|
347
|
+
* (`ProjectionPolicy`: `'canvas' | 'dom' | 'auto'` in
|
|
348
|
+
* `tree/scene/ProjectionPolicy.ts`) — predates the RFC, so the field keeps
|
|
349
|
+
* its name and the RFC spelling lives on the value type.
|
|
350
|
+
*
|
|
351
|
+
* - `'canvas'` (default): today's rendering. Zero behavior change.
|
|
352
|
+
* - `'dom'`: the node materializes as a live `HTMLElement` positioned by its
|
|
353
|
+
* world matrix. The live element replaces the transparent a11y mirror
|
|
354
|
+
* (same single-delivery reasoning as `DOMPortalEntity`), so opting in
|
|
355
|
+
* requires a DOM backend and a DOM environment for the AT representation.
|
|
356
|
+
* - `'auto'`: negotiated per node per frame by `Scene.resolveProjectionFor`
|
|
357
|
+
* (RFC4 §3: explicit beats automatic, fallbacks reported with reasons,
|
|
358
|
+
* hysteresis against flip-flop, no-DOM short-circuits to canvas).
|
|
359
|
+
*/
|
|
360
|
+
__init37() {this.domPolicy = "canvas"}
|
|
361
|
+
/**
|
|
362
|
+
* Backend-side creation hint for a `'dom'`-policy node (tag/content mapping
|
|
363
|
+
* key, e.g. `'text' | 'button' | 'input' | 'container' | 'transform'`). Plain
|
|
364
|
+
* string so custom nodes need no DOM types in core; `@vectojs/dom` owns the
|
|
365
|
+
* registry. `''` means a plain positioned `div` with no content sync.
|
|
366
|
+
*/
|
|
367
|
+
__init38() {this.domKind = ""}
|
|
368
|
+
/**
|
|
369
|
+
* Internal cache owned by the DOM backend: true while the node has a live
|
|
370
|
+
* projected element. The render walk reads it to skip canvas paint for
|
|
371
|
+
* DOM-resident nodes (so a mounted node is never double-drawn) and falls
|
|
372
|
+
* through to canvas while false (SSR / no backend registered). Do not set
|
|
373
|
+
* by hand — the backend sets it on mount and clears it on unmount.
|
|
374
|
+
*/
|
|
375
|
+
__init39() {this.domResident = false}
|
|
335
376
|
/**
|
|
336
377
|
* Clip this node's children to its local box (`[0,0]–[width,height]`) while
|
|
337
378
|
* rendering. Combined with translating a content child, this is how
|
|
338
379
|
* scroll/overflow containers (e.g. `ScrollView`) keep their content inside a
|
|
339
380
|
* fixed viewport. Off by default (children render unclipped). Canvas2D only.
|
|
340
381
|
*/
|
|
341
|
-
|
|
382
|
+
__init40() {this.clipChildren = false}
|
|
342
383
|
/**
|
|
343
384
|
* Group this subtree's projected text into its own accessibility **region**,
|
|
344
385
|
* without clipping anything.
|
|
@@ -365,14 +406,14 @@ var Entity = (_class2 = class {
|
|
|
365
406
|
*
|
|
366
407
|
* Off by default. Regions nest: the nearest enclosing region wins.
|
|
367
408
|
*/
|
|
368
|
-
|
|
409
|
+
__init41() {this.a11yRegion = false}
|
|
369
410
|
// Lazily allocated (see _drivers above). Most entities never register a
|
|
370
411
|
// listener or an imperative animate() tween.
|
|
371
|
-
|
|
412
|
+
__init42() {this.listeners = null}
|
|
372
413
|
/** Capture-phase listeners (fired root→target before bubble). */
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
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);_class2.prototype.__init40.call(this);_class2.prototype.__init41.call(this);
|
|
414
|
+
__init43() {this.captureListeners = null}
|
|
415
|
+
__init44() {this.animations = null}
|
|
416
|
+
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);_class2.prototype.__init40.call(this);_class2.prototype.__init41.call(this);_class2.prototype.__init42.call(this);_class2.prototype.__init43.call(this);_class2.prototype.__init44.call(this);
|
|
376
417
|
this.id = id || `entity_${Math.random().toString(36).substring(2, 9)}`;
|
|
377
418
|
}
|
|
378
419
|
/**
|
|
@@ -633,8 +674,7 @@ var Entity = (_class2 = class {
|
|
|
633
674
|
(e) => new Promise((resolve) => {
|
|
634
675
|
this._spawnDriver(e[0], e[1], cfg);
|
|
635
676
|
const d = _optionalChain([this, 'access', _84 => _84._drivers, 'optionalAccess', _85 => _85.get, 'call', _86 => _86(e[0])]);
|
|
636
|
-
if (!d)
|
|
637
|
-
resolve();
|
|
677
|
+
if (!d) resolve();
|
|
638
678
|
else d.onDone = resolve;
|
|
639
679
|
})
|
|
640
680
|
)
|
|
@@ -824,6 +864,7 @@ var Entity = (_class2 = class {
|
|
|
824
864
|
el.focus();
|
|
825
865
|
return;
|
|
826
866
|
}
|
|
867
|
+
if (typeof requestAnimationFrame === "undefined") return;
|
|
827
868
|
requestAnimationFrame(() => {
|
|
828
869
|
const retry = _optionalChain([this, 'access', _109 => _109.scene, 'optionalAccess', _110 => _110.getA11yElement, 'call', _111 => _111(this.id)]);
|
|
829
870
|
if (retry) retry.focus();
|
|
@@ -1190,6 +1231,10 @@ var Entity = (_class2 = class {
|
|
|
1190
1231
|
* `selectable` is set — natively selectable. Returns `null` by default.
|
|
1191
1232
|
* Read on the a11y sync cadence, so text changes propagate automatically.
|
|
1192
1233
|
*
|
|
1234
|
+
* This is the descriptor half of the `ContentProjection` row of
|
|
1235
|
+
* `ProjectionBackend` (`tree/scene/ProjectionBackend.ts`): the entity
|
|
1236
|
+
* describes *what* to project, the scene owns *how* it is materialized.
|
|
1237
|
+
*
|
|
1193
1238
|
* @param hint - Optional advice about which part of the entity is worth
|
|
1194
1239
|
* describing. Purely an optimization: ignoring it is always correct, which
|
|
1195
1240
|
* is why it is a parameter rather than a required contract change. See
|
|
@@ -1267,27 +1312,27 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1267
1312
|
// joined by soft hyphens (U+00AD); the worker then treats those as break
|
|
1268
1313
|
// opportunities. `text` keeps the original string for a11y/content
|
|
1269
1314
|
// projection; `layoutText` is the soft-hyphen-annotated string sent to layout.
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1315
|
+
__init45() {this.hyphenator = null}
|
|
1316
|
+
__init46() {this.layoutText = ""}
|
|
1317
|
+
__init47() {this.text = ""}
|
|
1318
|
+
__init48() {this.lastRenderedSeqId = 0}
|
|
1274
1319
|
/** Bumped by {@link queueLayout}; read by `Scene` to skip an unchanged sync. */
|
|
1275
|
-
|
|
1320
|
+
__init49() {this.contentEpoch = 0}
|
|
1276
1321
|
// Atlas-decode subscription (see watchAtlasDecode). Held so `destroy()` can
|
|
1277
1322
|
// release it: the handler closes over `this`, so leaving it attached to a
|
|
1278
1323
|
// long-lived shared atlas image would retain the whole entity.
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1324
|
+
__init50() {this.atlasDecodeTarget = null}
|
|
1325
|
+
__init51() {this.atlasDecodeHandler = null}
|
|
1326
|
+
__init52() {this.fontStringCache = []}
|
|
1327
|
+
__init53() {this.layoutResult = null}
|
|
1283
1328
|
/**
|
|
1284
1329
|
* Visual rows rebuilt from {@link layoutResult} (see
|
|
1285
1330
|
* {@link rebuildProjectionLines}). Empty until a layout reply lands and the
|
|
1286
1331
|
* reply's shaped glyphs can be mapped back to the source text 1:1.
|
|
1287
1332
|
*/
|
|
1288
|
-
|
|
1333
|
+
__init54() {this.projectionLines = []}
|
|
1289
1334
|
constructor(text, options) {
|
|
1290
|
-
super();_class3.prototype.
|
|
1335
|
+
super();_class3.prototype.__init45.call(this);_class3.prototype.__init46.call(this);_class3.prototype.__init47.call(this);_class3.prototype.__init48.call(this);_class3.prototype.__init49.call(this);_class3.prototype.__init50.call(this);_class3.prototype.__init51.call(this);_class3.prototype.__init52.call(this);_class3.prototype.__init53.call(this);_class3.prototype.__init54.call(this);;
|
|
1291
1336
|
this.font = options.font;
|
|
1292
1337
|
this.texture = options.texture;
|
|
1293
1338
|
this.fallbackFont = _nullishCoalesce(options.fallbackFont, () => ( "sans-serif"));
|
|
@@ -1671,23 +1716,23 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1671
1716
|
* rasterized. Set to `'transparent'` to opt out and keep the box empty.
|
|
1672
1717
|
* Default `'rgba(248,113,113,0.9)'`.
|
|
1673
1718
|
*/
|
|
1674
|
-
|
|
1719
|
+
__init55() {this.fallbackStroke = "rgba(248,113,113,0.9)"}
|
|
1675
1720
|
/** Fill behind the fallback marker. Default `'rgba(248,113,113,0.12)'`. */
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1721
|
+
__init56() {this.fallbackFill = "rgba(248,113,113,0.12)"}
|
|
1722
|
+
__init57() {this.svgSource = ""}
|
|
1723
|
+
__init58() {this.imageBitmap = null}
|
|
1724
|
+
__init59() {this.imageElement = null}
|
|
1725
|
+
__init60() {this.blobURL = null}
|
|
1726
|
+
__init61() {this.currentImg = null}
|
|
1727
|
+
__init62() {this.lodTimeout = null}
|
|
1728
|
+
__init63() {this.rasterFailed = false}
|
|
1729
|
+
__init64() {this.cachedDoc = null}
|
|
1730
|
+
__init65() {this.baseWidth = 100}
|
|
1731
|
+
__init66() {this.baseHeight = 100}
|
|
1732
|
+
__init67() {this.lastRasterizedScale = 1}
|
|
1733
|
+
__init68() {this.targetScale = 1}
|
|
1689
1734
|
constructor(svgSource, id) {
|
|
1690
|
-
super(id);_class4.prototype.
|
|
1735
|
+
super(id);_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);_class4.prototype.__init63.call(this);_class4.prototype.__init64.call(this);_class4.prototype.__init65.call(this);_class4.prototype.__init66.call(this);_class4.prototype.__init67.call(this);_class4.prototype.__init68.call(this);;
|
|
1691
1736
|
this.setSVGSource(svgSource);
|
|
1692
1737
|
}
|
|
1693
1738
|
setSVGSource(svgSource) {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Entity, type A11yAttributes } from '../tree/Entity';
|
|
2
|
+
import type { IRenderer } from '../renderer/IRenderer';
|
|
3
|
+
/**
|
|
4
|
+
* One item in a {@link VirtualizedSetAggregate}: the stable identity and the
|
|
5
|
+
* accessible name a hotspot announces for it.
|
|
6
|
+
*/
|
|
7
|
+
export interface VirtualizedSetItem {
|
|
8
|
+
/** Stable identity across re-binds; survives reordering and filtering. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Accessible name announced for the item. */
|
|
11
|
+
label: string;
|
|
12
|
+
}
|
|
13
|
+
export interface VirtualizedSetAggregateOptions {
|
|
14
|
+
/** Full item set; the container label always states this count. Default `[]`. */
|
|
15
|
+
items?: VirtualizedSetItem[];
|
|
16
|
+
/** Container name; the count is appended (`'Messages, 10000 items'`). */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** Container role. Default `'list'` (owns `listitem` per `A11Y_REQUIRED_OWNED`). */
|
|
19
|
+
role?: string;
|
|
20
|
+
/** Hotspot role. Default `'listitem'`. */
|
|
21
|
+
itemRole?: string;
|
|
22
|
+
/** Row height in local px; hotspots stack vertically at this stride. Default `28`. */
|
|
23
|
+
rowHeight?: number;
|
|
24
|
+
/** Hotspot pool size. Default: enough slots to cover `height`, at least 1. */
|
|
25
|
+
visibleCapacity?: number;
|
|
26
|
+
/** Container width in local px. Default `0` (set it — a zero box never projects). */
|
|
27
|
+
width?: number;
|
|
28
|
+
/** Container height in local px. Default `0`. */
|
|
29
|
+
height?: number;
|
|
30
|
+
/** Called when an item is activated (Enter/Space/click-through). */
|
|
31
|
+
onActivate?: (item: VirtualizedSetItem, index: number) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Aggregate semantics for a virtualized set (RFC3 §4.4, CTX-0599).
|
|
35
|
+
*
|
|
36
|
+
* One persistent container (`role` + `aria-label` with the count) plus roving
|
|
37
|
+
* focus plus a small pool of hotspot entities re-bound to whichever items
|
|
38
|
+
* currently occupy each visible slot — O(viewport) DOM nodes for an
|
|
39
|
+
* arbitrarily large dataset. The pattern is the `Tree`/`Table` hotspot
|
|
40
|
+
* precedent (`packages/ui/src/Tree.ts:98-113`, `packages/table/src/Table.ts`):
|
|
41
|
+
* a transparent, focusable child per visible row with a roving `tabIndex` and
|
|
42
|
+
* `pointerEvents: 'none'`, while the parent owns the keyboard model and the
|
|
43
|
+
* pool.
|
|
44
|
+
*
|
|
45
|
+
* Pointer ownership: neither the container nor the hotspots take the pointer
|
|
46
|
+
* (both project `pointer-events: none`), so a real click/drag reaches the
|
|
47
|
+
* owner's canvas handling or an underlying selectable-text mirror underneath.
|
|
48
|
+
* Keyboard focus and AT-synthesized `click` still work — the same contract the
|
|
49
|
+
* `Tree`/`Table` hotspots rely on. A mouse/touch owner forwards its own tap
|
|
50
|
+
* path into {@link activateItem}; `'onDemand'` alone is deliberately not the
|
|
51
|
+
* story here (also `content/reference/core-a11y.md:207-214`).
|
|
52
|
+
*
|
|
53
|
+
* Painting belongs to the owner: `render` is a no-op (like `RowHotspot`), so
|
|
54
|
+
* pair this with canvas-painted rows or subclass and override `render`.
|
|
55
|
+
*/
|
|
56
|
+
export declare class VirtualizedSetAggregate extends Entity {
|
|
57
|
+
private _items;
|
|
58
|
+
private _label;
|
|
59
|
+
private _role;
|
|
60
|
+
private _itemRole;
|
|
61
|
+
private _rowHeight;
|
|
62
|
+
private _visibleCapacity;
|
|
63
|
+
private _onActivate;
|
|
64
|
+
/** First item index currently bound to the pool (the scroll window). */
|
|
65
|
+
private _visibleStart;
|
|
66
|
+
/** Item id owning the roving tab stop / keyboard focus. */
|
|
67
|
+
private _activeId;
|
|
68
|
+
private _selectedId;
|
|
69
|
+
/** One focusable hotspot per visible slot; re-bound, never rebuilt per item. */
|
|
70
|
+
private _hotspots;
|
|
71
|
+
constructor(opts?: VirtualizedSetAggregateOptions);
|
|
72
|
+
/** Full item count — the number the container label states. */
|
|
73
|
+
get itemCount(): number;
|
|
74
|
+
/** Live pool size (bounded by the visible capacity, never by the item count). */
|
|
75
|
+
get poolSize(): number;
|
|
76
|
+
/** First item index currently bound to the pool. */
|
|
77
|
+
get visibleStart(): number;
|
|
78
|
+
getA11yAttributes(): A11yAttributes;
|
|
79
|
+
render(_renderer: IRenderer): void;
|
|
80
|
+
/** Axis-aligned hit-test against the container box (the `UIComponent` default). */
|
|
81
|
+
isPointInside(globalX: number, globalY: number): boolean;
|
|
82
|
+
/** Replace the item set; the pool re-binds and the label count follows. */
|
|
83
|
+
setItems(items: VirtualizedSetItem[]): void;
|
|
84
|
+
/** Move the pool window to start at `start` (the scroll position). */
|
|
85
|
+
setVisibleStart(start: number): void;
|
|
86
|
+
/**
|
|
87
|
+
* Keep one hotspot per visible slot, positioned over it. The pool is sized
|
|
88
|
+
* to the viewport (capacity), each slot re-bound to whatever item currently
|
|
89
|
+
* occupies it — the `Tree._syncHotspots` shape, minus tree structure.
|
|
90
|
+
*/
|
|
91
|
+
private _syncHotspots;
|
|
92
|
+
/** Whether `id` owns the roving tab stop: active, else selected, else first. */
|
|
93
|
+
isTabStop(id: string): boolean;
|
|
94
|
+
isSelected(id: string): boolean;
|
|
95
|
+
/** Item role the hotspots announce (kept on the parent: one source of truth). */
|
|
96
|
+
get itemRole(): string;
|
|
97
|
+
/** Activate an item (pointer tap-through or Enter/Space): selects and notifies. */
|
|
98
|
+
activateItem(id: string, focusIt?: boolean): void;
|
|
99
|
+
/** Move keyboard focus to the hotspot currently bound to `id`, if any. */
|
|
100
|
+
focusItem(id: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Aggregate keyboard model: Up/Down move the active item (scrolling the pool
|
|
103
|
+
* window so it stays bound), Home/End jump, Enter/Space activate. The active
|
|
104
|
+
* item is focused as it moves so focus is never stranded on a re-bound slot.
|
|
105
|
+
*/
|
|
106
|
+
handleItemKey(e: KeyboardEvent, id: string): void;
|
|
107
|
+
/** Scroll the pool window just enough to keep `index` bound. */
|
|
108
|
+
private _ensureVisible;
|
|
109
|
+
update(_dt: number, _time: number): void;
|
|
110
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,12 @@ export * from './renderer/TextRasterCache';
|
|
|
10
10
|
export * from './performance/UserTiming';
|
|
11
11
|
export * from './tree/Entity';
|
|
12
12
|
export * from './tree/Scene';
|
|
13
|
+
export * from './tree/scene/HitResult';
|
|
14
|
+
export * from './tree/scene/ProjectionBackend';
|
|
15
|
+
export * from './tree/scene/ProjectionPolicy';
|
|
16
|
+
export * from './tree/scene/SemanticProjectionPolicy';
|
|
13
17
|
export * from './components/TextEntity';
|
|
18
|
+
export * from './components/VirtualizedSetAggregate';
|
|
14
19
|
export * from './components/GridTextEntity';
|
|
15
20
|
export * from './components/SplineEntity';
|
|
16
21
|
export * from './components/Rect';
|