@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.
@@ -555,6 +555,14 @@ export declare class Scene {
555
555
  * mid-hover synthesize the `pointerleave` the browser never sends for a
556
556
  * detached element, so the entity doesn't keep its hover state. */
557
557
  private readonly hoveredA11yElements;
558
+ /**
559
+ * Entity ids the application has pinned via {@link requestA11yProjection}.
560
+ *
561
+ * Ids rather than entities so a removed entity cannot be retained by this set;
562
+ * a stale id simply never matches. Cleared per-entity by
563
+ * {@link releaseA11yProjection}.
564
+ */
565
+ private readonly a11yProjectionRequests;
558
566
  /** Persistent tabindex=-1 element in a11yRoot. When the focused a11y mirror is
559
567
  * pruned (virtualization/streaming/removal) while it holds focus, we move
560
568
  * focus here instead of letting the browser drop it to <body> — keeping the
@@ -1324,6 +1332,58 @@ export declare class Scene {
1324
1332
  * predicate, which is only tractable while it has one home.
1325
1333
  */
1326
1334
  private shouldProjectA11y;
1335
+ /**
1336
+ * Whether an `a11yProjection: 'onDemand'` entity is currently engaged enough to
1337
+ * deserve a shadow node.
1338
+ *
1339
+ * Deliberately **not** hover alone. A keyboard or assistive-technology user
1340
+ * generates no pointer events, so a hover-only trigger would withhold the
1341
+ * semantic node from precisely the users it exists for. Three signals, any of
1342
+ * which counts:
1343
+ *
1344
+ * - **Focus.** Covers keyboard traversal and AT-driven focus. Checked against
1345
+ * the live element so a node keeps its own focus rather than being pruned out
1346
+ * from under the user mid-interaction.
1347
+ * - **Pointer target.** The entity under the pointer, so a mouse user gets the
1348
+ * same node a hover-gated design would have given them.
1349
+ * - **Explicit request.** {@link Scene.requestA11yProjection}, for anything the
1350
+ * app knows is significant — the selected item, a search hit, a
1351
+ * just-announced element. This is the escape hatch that keeps the mode usable
1352
+ * when neither focus nor pointer applies.
1353
+ *
1354
+ * The entity stays hit-testable on canvas regardless, so a click always reaches
1355
+ * it and promotes it on the next sync.
1356
+ */
1357
+ private a11yEngaged;
1358
+ /**
1359
+ * Whether `node` mirrors selectable text of its own.
1360
+ *
1361
+ * Such an entity must not be promoted by the pointer: its interactive a11y node
1362
+ * would sit above the text mirror and eat the mousedown that starts a native
1363
+ * selection.
1364
+ */
1365
+ private projectsSelectableText;
1366
+ /**
1367
+ * Keep `entity`'s a11y shadow node projected while it has
1368
+ * `a11yProjection: 'onDemand'`.
1369
+ *
1370
+ * For anything the application knows matters but the engine cannot infer — the
1371
+ * selected danmaku, a search hit, a node just announced in a live region.
1372
+ * Without this, `'onDemand'` would be reachable only by focus or pointer, and
1373
+ * an app-driven selection change would leave the selected entity semantically
1374
+ * invisible.
1375
+ *
1376
+ * Idempotent. Has no effect on an `'eager'` entity, which is always projected.
1377
+ */
1378
+ requestA11yProjection(entity: Entity | string): void;
1379
+ /**
1380
+ * Drop a projection request made by {@link requestA11yProjection}.
1381
+ *
1382
+ * The node is not removed immediately: it survives while it is focused or under
1383
+ * the pointer, and is pruned on the next sync that finds it unengaged. Releasing
1384
+ * a request the scene does not hold is a no-op.
1385
+ */
1386
+ releaseA11yProjection(entity: Entity | string): void;
1327
1387
  private syncA11y;
1328
1388
  /**
1329
1389
  * Mirror one entity's static text ({@link Entity.getContentProjection}) as a
@@ -1341,6 +1401,34 @@ export declare class Scene {
1341
1401
  * culling and always count as visible, matching the legacy behavior.
1342
1402
  */
1343
1403
  private projectionBoxVisible;
1404
+ /**
1405
+ * The band of an entity's own y coordinates that is worth projecting, or
1406
+ * `null` to project everything.
1407
+ *
1408
+ * {@link projectionBoxVisible} answers "is this entity near the viewport",
1409
+ * which frees whole blocks that scroll away. It cannot help a single entity
1410
+ * *taller* than the viewport: that entity's box always intersects, so every
1411
+ * one of its visual lines was materialized — a `<span>` per line and, on the
1412
+ * grid path, a `<span>` per glyph cluster. That is where "14.8k elements for a
1413
+ * 346KB Markdown doc" comes from, and it is O(document) rather than
1414
+ * O(viewport) in both element count and per-frame walk cost.
1415
+ *
1416
+ * Measured on one entity scrolled to its middle, real headed browsers
1417
+ * (`benchmarks/projection-per-line/`): at 4000 lines, materializing every line
1418
+ * costs 6.28 ms/frame on Chrome and 6.51 ms on Firefox with 36,000 child
1419
+ * elements, against 0.28/0.16 ms and 963 elements when only the visible band
1420
+ * is emitted. The gated cost is *flat* across a 20x document-size range, so
1421
+ * this converts an asymptote rather than shaving a constant.
1422
+ *
1423
+ * Returns local-y bounds in the entity's own coordinate space, already
1424
+ * expanded by `margin` and intersected with every `clipChildren` ancestor, so
1425
+ * a line inside a scrolled container is measured against the container rather
1426
+ * than the window. `null` means "no useful bound" — a degenerate transform, a
1427
+ * rotation/skew that makes a y-band meaningless, or a boundless entity — and
1428
+ * the caller must then project every line, because emitting nothing would
1429
+ * silently drop text from selection, find-in-page and screen readers.
1430
+ */
1431
+ private projectionVisibleLocalYBand;
1344
1432
  private syncContentProjection;
1345
1433
  /**
1346
1434
  * Materialize a prepared grid in logical source order while positioning each
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectojs/core",
3
- "version": "1.28.1",
3
+ "version": "1.30.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },