@vectojs/core 1.16.2 → 1.16.3
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/index.js +43 -9
- package/dist/index.mjs +43 -9
- package/dist/tree/Scene.d.ts +33 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2162,17 +2162,17 @@ var Scene = (_class6 = class _Scene {
|
|
|
2162
2162
|
this._devFrameCount++;
|
|
2163
2163
|
if (this._devFrameCount % 120 !== 0) return;
|
|
2164
2164
|
if (this.a11yElements) {
|
|
2165
|
-
let
|
|
2165
|
+
let projectableCount = 0;
|
|
2166
2166
|
const walk = (node) => {
|
|
2167
|
-
if (
|
|
2167
|
+
if (this.shouldProjectA11y(node)) projectableCount++;
|
|
2168
2168
|
for (const c of node.children) walk(c);
|
|
2169
2169
|
};
|
|
2170
2170
|
walk(this.root);
|
|
2171
2171
|
for (const c of this.overlayRoot.children) walk(c);
|
|
2172
2172
|
const shadowCount = this.a11yElements.size;
|
|
2173
|
-
if (shadowCount >
|
|
2173
|
+
if (shadowCount > projectableCount) {
|
|
2174
2174
|
this._devWarn(
|
|
2175
|
-
`a11yElements (${shadowCount}) exceeds
|
|
2175
|
+
`a11yElements (${shadowCount}) exceeds projectable entities (${projectableCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
|
|
2176
2176
|
);
|
|
2177
2177
|
}
|
|
2178
2178
|
}
|
|
@@ -2643,7 +2643,19 @@ var Scene = (_class6 = class _Scene {
|
|
|
2643
2643
|
* without removing it from the scene graph. Components that manage dynamic
|
|
2644
2644
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
2645
2645
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
2646
|
-
* leak
|
|
2646
|
+
* leak.
|
|
2647
|
+
*
|
|
2648
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
2649
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
2650
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
2651
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
2652
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
2653
|
+
* frame without any explicit call.
|
|
2654
|
+
*
|
|
2655
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
2656
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
2657
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
2658
|
+
* pooled children.
|
|
2647
2659
|
*
|
|
2648
2660
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
2649
2661
|
*/
|
|
@@ -2932,12 +2944,34 @@ var Scene = (_class6 = class _Scene {
|
|
|
2932
2944
|
}
|
|
2933
2945
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
2934
2946
|
}
|
|
2947
|
+
/**
|
|
2948
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
2949
|
+
*
|
|
2950
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
2951
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
2952
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
2953
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
2954
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
2955
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
2956
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
2957
|
+
*
|
|
2958
|
+
* A box is required because a zero-size element is unfocusable and
|
|
2959
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
2960
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
2961
|
+
*
|
|
2962
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
2963
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
2964
|
+
* predicate, which is only tractable while it has one home.
|
|
2965
|
+
*/
|
|
2966
|
+
shouldProjectA11y(node) {
|
|
2967
|
+
return node.interactive && (node.width > 0 || node.a11yFullViewport);
|
|
2968
|
+
}
|
|
2935
2969
|
syncA11y(node) {
|
|
2936
2970
|
if (!this.a11yRoot) return;
|
|
2937
2971
|
if (node.isDOMPortal) {
|
|
2938
2972
|
return;
|
|
2939
2973
|
}
|
|
2940
|
-
if (
|
|
2974
|
+
if (this.shouldProjectA11y(node)) {
|
|
2941
2975
|
let el = this.a11yElements.get(node.id);
|
|
2942
2976
|
const attrs = node.getA11yAttributes();
|
|
2943
2977
|
const expectedTag = attrs.tag || "div";
|
|
@@ -3713,7 +3747,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
3713
3747
|
if (node.a11yFullViewport) this.fullViewportElements.push(contentEl);
|
|
3714
3748
|
else this.normalElements.push(contentEl);
|
|
3715
3749
|
}
|
|
3716
|
-
if (
|
|
3750
|
+
if (this.shouldProjectA11y(node)) {
|
|
3717
3751
|
const el = this.a11yElements.get(node.id);
|
|
3718
3752
|
if (el) {
|
|
3719
3753
|
this.activeIds.add(node.id);
|
|
@@ -3852,7 +3886,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
3852
3886
|
const traverse = (node, parentNode) => {
|
|
3853
3887
|
if (node.isDOMPortal) return;
|
|
3854
3888
|
let currentA11yNode = null;
|
|
3855
|
-
if (
|
|
3889
|
+
if (this.shouldProjectA11y(node)) {
|
|
3856
3890
|
const el = this.a11yElements.get(node.id);
|
|
3857
3891
|
if (el) {
|
|
3858
3892
|
const attrs = node.getA11yAttributes();
|
|
@@ -4222,7 +4256,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
4222
4256
|
const orthogonalTolerance = Math.max(1, worldScaleX * worldScaleY) * 1e-6;
|
|
4223
4257
|
const isSimilarityTransform = Number.isFinite(worldScaleX) && Number.isFinite(worldScaleY) && Math.abs(worldScaleX - worldScaleY) <= scaleTolerance && Math.abs(a * c + b * d) <= orthogonalTolerance;
|
|
4224
4258
|
const a11yEl = isMainRenderer ? this.a11yElements.get(node.id) : void 0;
|
|
4225
|
-
const willProjectA11y = isMainRenderer &&
|
|
4259
|
+
const willProjectA11y = isMainRenderer && this.shouldProjectA11y(node);
|
|
4226
4260
|
if (a11yEl || willProjectA11y) {
|
|
4227
4261
|
const renderOrder = this.renderOrderCounter++;
|
|
4228
4262
|
if (willProjectA11y) this.a11yRenderOrders.set(node.id, renderOrder);
|
package/dist/index.mjs
CHANGED
|
@@ -2161,17 +2161,17 @@ var Scene = class _Scene {
|
|
|
2161
2161
|
this._devFrameCount++;
|
|
2162
2162
|
if (this._devFrameCount % 120 !== 0) return;
|
|
2163
2163
|
if (this.a11yElements) {
|
|
2164
|
-
let
|
|
2164
|
+
let projectableCount = 0;
|
|
2165
2165
|
const walk = (node) => {
|
|
2166
|
-
if (
|
|
2166
|
+
if (this.shouldProjectA11y(node)) projectableCount++;
|
|
2167
2167
|
for (const c of node.children) walk(c);
|
|
2168
2168
|
};
|
|
2169
2169
|
walk(this.root);
|
|
2170
2170
|
for (const c of this.overlayRoot.children) walk(c);
|
|
2171
2171
|
const shadowCount = this.a11yElements.size;
|
|
2172
|
-
if (shadowCount >
|
|
2172
|
+
if (shadowCount > projectableCount) {
|
|
2173
2173
|
this._devWarn(
|
|
2174
|
-
`a11yElements (${shadowCount}) exceeds
|
|
2174
|
+
`a11yElements (${shadowCount}) exceeds projectable entities (${projectableCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
|
|
2175
2175
|
);
|
|
2176
2176
|
}
|
|
2177
2177
|
}
|
|
@@ -2642,7 +2642,19 @@ var Scene = class _Scene {
|
|
|
2642
2642
|
* without removing it from the scene graph. Components that manage dynamic
|
|
2643
2643
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
2644
2644
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
2645
|
-
* leak
|
|
2645
|
+
* leak.
|
|
2646
|
+
*
|
|
2647
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
2648
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
2649
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
2650
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
2651
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
2652
|
+
* frame without any explicit call.
|
|
2653
|
+
*
|
|
2654
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
2655
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
2656
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
2657
|
+
* pooled children.
|
|
2646
2658
|
*
|
|
2647
2659
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
2648
2660
|
*/
|
|
@@ -2931,12 +2943,34 @@ var Scene = class _Scene {
|
|
|
2931
2943
|
}
|
|
2932
2944
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
2933
2945
|
}
|
|
2946
|
+
/**
|
|
2947
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
2948
|
+
*
|
|
2949
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
2950
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
2951
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
2952
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
2953
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
2954
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
2955
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
2956
|
+
*
|
|
2957
|
+
* A box is required because a zero-size element is unfocusable and
|
|
2958
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
2959
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
2960
|
+
*
|
|
2961
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
2962
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
2963
|
+
* predicate, which is only tractable while it has one home.
|
|
2964
|
+
*/
|
|
2965
|
+
shouldProjectA11y(node) {
|
|
2966
|
+
return node.interactive && (node.width > 0 || node.a11yFullViewport);
|
|
2967
|
+
}
|
|
2934
2968
|
syncA11y(node) {
|
|
2935
2969
|
if (!this.a11yRoot) return;
|
|
2936
2970
|
if (node.isDOMPortal) {
|
|
2937
2971
|
return;
|
|
2938
2972
|
}
|
|
2939
|
-
if (
|
|
2973
|
+
if (this.shouldProjectA11y(node)) {
|
|
2940
2974
|
let el = this.a11yElements.get(node.id);
|
|
2941
2975
|
const attrs = node.getA11yAttributes();
|
|
2942
2976
|
const expectedTag = attrs.tag || "div";
|
|
@@ -3712,7 +3746,7 @@ var Scene = class _Scene {
|
|
|
3712
3746
|
if (node.a11yFullViewport) this.fullViewportElements.push(contentEl);
|
|
3713
3747
|
else this.normalElements.push(contentEl);
|
|
3714
3748
|
}
|
|
3715
|
-
if (
|
|
3749
|
+
if (this.shouldProjectA11y(node)) {
|
|
3716
3750
|
const el = this.a11yElements.get(node.id);
|
|
3717
3751
|
if (el) {
|
|
3718
3752
|
this.activeIds.add(node.id);
|
|
@@ -3851,7 +3885,7 @@ var Scene = class _Scene {
|
|
|
3851
3885
|
const traverse = (node, parentNode) => {
|
|
3852
3886
|
if (node.isDOMPortal) return;
|
|
3853
3887
|
let currentA11yNode = null;
|
|
3854
|
-
if (
|
|
3888
|
+
if (this.shouldProjectA11y(node)) {
|
|
3855
3889
|
const el = this.a11yElements.get(node.id);
|
|
3856
3890
|
if (el) {
|
|
3857
3891
|
const attrs = node.getA11yAttributes();
|
|
@@ -4221,7 +4255,7 @@ var Scene = class _Scene {
|
|
|
4221
4255
|
const orthogonalTolerance = Math.max(1, worldScaleX * worldScaleY) * 1e-6;
|
|
4222
4256
|
const isSimilarityTransform = Number.isFinite(worldScaleX) && Number.isFinite(worldScaleY) && Math.abs(worldScaleX - worldScaleY) <= scaleTolerance && Math.abs(a * c + b * d) <= orthogonalTolerance;
|
|
4223
4257
|
const a11yEl = isMainRenderer ? this.a11yElements.get(node.id) : void 0;
|
|
4224
|
-
const willProjectA11y = isMainRenderer &&
|
|
4258
|
+
const willProjectA11y = isMainRenderer && this.shouldProjectA11y(node);
|
|
4225
4259
|
if (a11yEl || willProjectA11y) {
|
|
4226
4260
|
const renderOrder = this.renderOrderCounter++;
|
|
4227
4261
|
if (willProjectA11y) this.a11yRenderOrders.set(node.id, renderOrder);
|
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -673,7 +673,19 @@ export declare class Scene {
|
|
|
673
673
|
* without removing it from the scene graph. Components that manage dynamic
|
|
674
674
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
675
675
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
676
|
-
* leak
|
|
676
|
+
* leak.
|
|
677
|
+
*
|
|
678
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
679
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
680
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
681
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
682
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
683
|
+
* frame without any explicit call.
|
|
684
|
+
*
|
|
685
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
686
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
687
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
688
|
+
* pooled children.
|
|
677
689
|
*
|
|
678
690
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
679
691
|
*/
|
|
@@ -756,6 +768,26 @@ export declare class Scene {
|
|
|
756
768
|
/** True when any node in the subtree has a pending animation. */
|
|
757
769
|
/** True when any node in the subtree is interactive (drives a11y sync). */
|
|
758
770
|
private syncOptionalAttribute;
|
|
771
|
+
/**
|
|
772
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
773
|
+
*
|
|
774
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
775
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
776
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
777
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
778
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
779
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
780
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
781
|
+
*
|
|
782
|
+
* A box is required because a zero-size element is unfocusable and
|
|
783
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
784
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
785
|
+
*
|
|
786
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
787
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
788
|
+
* predicate, which is only tractable while it has one home.
|
|
789
|
+
*/
|
|
790
|
+
private shouldProjectA11y;
|
|
759
791
|
private syncA11y;
|
|
760
792
|
/**
|
|
761
793
|
* Mirror one entity's static text ({@link Entity.getContentProjection}) as a
|