@vectojs/core 1.4.0 → 1.5.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/README.md +25 -0
- package/dist/index.js +30 -5
- package/dist/index.mjs +30 -5
- package/dist/tree/Scene.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -112,6 +112,31 @@ This projection is intentionally thin. Applications still own accessible names,
|
|
|
112
112
|
focus order, contrast, and correct control semantics. See the
|
|
113
113
|
[accessibility guide](https://vectojs.org/learn/accessibility/).
|
|
114
114
|
|
|
115
|
+
## Static content projection
|
|
116
|
+
|
|
117
|
+
Canvas-rendered text can opt into browser-native find, translation, selection, and copy without
|
|
118
|
+
turning the application into a DOM layout. Override `getContentProjection()` on the owning Entity;
|
|
119
|
+
the Scene creates a transparent, position-synchronized mirror while the VMT remains authoritative:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
class SelectableLabel extends Entity {
|
|
123
|
+
getContentProjection() {
|
|
124
|
+
return {
|
|
125
|
+
text: 'Selectable canvas text',
|
|
126
|
+
font: '18px Inter',
|
|
127
|
+
lineHeight: 24,
|
|
128
|
+
selectable: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`selectable` controls whether the mirror receives pointer input. The Scene keeps projection order
|
|
135
|
+
aligned with VMT order, removes descendant mirrors with their subtree, and hides mirrors fully
|
|
136
|
+
outside the viewport or a `clipChildren` ancestor. Tooling can inspect the currently materialized
|
|
137
|
+
node with `scene.getContentElement(entityId)`. Virtualized or non-materialized off-viewport text is
|
|
138
|
+
not searchable until the application brings it into the active scene.
|
|
139
|
+
|
|
115
140
|
## Performance model
|
|
116
141
|
|
|
117
142
|
Useful levers include on-demand rendering, viewport culling, spatial hashing, prepared text layout,
|
package/dist/index.js
CHANGED
|
@@ -549,6 +549,12 @@ var Scene = (_class2 = class _Scene {
|
|
|
549
549
|
this.activePortalsThisFrame.delete(node.id);
|
|
550
550
|
this.activePortalsPrevFrame.delete(node.id);
|
|
551
551
|
}
|
|
552
|
+
const contentEl = this.contentElements.get(node.id);
|
|
553
|
+
if (contentEl) {
|
|
554
|
+
contentEl.remove();
|
|
555
|
+
this.contentElements.delete(node.id);
|
|
556
|
+
this.a11yNeedsReorder = true;
|
|
557
|
+
}
|
|
552
558
|
const el = this.a11yElements.get(node.id);
|
|
553
559
|
if (el) {
|
|
554
560
|
if (el === this.focusedA11yElement) {
|
|
@@ -588,11 +594,6 @@ var Scene = (_class2 = class _Scene {
|
|
|
588
594
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
589
595
|
*/
|
|
590
596
|
detachA11y(entity) {
|
|
591
|
-
const contentEl = this.contentElements.get(entity.id);
|
|
592
|
-
if (contentEl) {
|
|
593
|
-
contentEl.remove();
|
|
594
|
-
this.contentElements.delete(entity.id);
|
|
595
|
-
}
|
|
596
597
|
this.removeA11yRecursively(entity);
|
|
597
598
|
}
|
|
598
599
|
/**
|
|
@@ -1028,6 +1029,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
1028
1029
|
if (el) {
|
|
1029
1030
|
el.remove();
|
|
1030
1031
|
this.contentElements.delete(node.id);
|
|
1032
|
+
this.a11yNeedsReorder = true;
|
|
1031
1033
|
}
|
|
1032
1034
|
return;
|
|
1033
1035
|
}
|
|
@@ -1052,6 +1054,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
1052
1054
|
);
|
|
1053
1055
|
this.a11yRoot.appendChild(el);
|
|
1054
1056
|
this.contentElements.set(node.id, el);
|
|
1057
|
+
this.a11yNeedsReorder = true;
|
|
1055
1058
|
}
|
|
1056
1059
|
if (el.textContent !== projection.text) el.textContent = projection.text;
|
|
1057
1060
|
const font = _nullishCoalesce(projection.font, () => ( ""));
|
|
@@ -1078,6 +1081,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
1078
1081
|
el.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0)`;
|
|
1079
1082
|
let visible = true;
|
|
1080
1083
|
if (node.width > 0 && node.height > 0) {
|
|
1084
|
+
const worldCorners = [];
|
|
1081
1085
|
let minX = Infinity;
|
|
1082
1086
|
let minY = Infinity;
|
|
1083
1087
|
let maxX = -Infinity;
|
|
@@ -1087,12 +1091,29 @@ var Scene = (_class2 = class _Scene {
|
|
|
1087
1091
|
const ly = i & 2 ? node.height : 0;
|
|
1088
1092
|
const wx = a * lx + c * ly + e;
|
|
1089
1093
|
const wy = b * lx + d * ly + f;
|
|
1094
|
+
worldCorners.push({ x: wx, y: wy });
|
|
1090
1095
|
if (wx < minX) minX = wx;
|
|
1091
1096
|
if (wx > maxX) maxX = wx;
|
|
1092
1097
|
if (wy < minY) minY = wy;
|
|
1093
1098
|
if (wy > maxY) maxY = wy;
|
|
1094
1099
|
}
|
|
1095
1100
|
visible = maxX >= 0 && minX <= this.width && maxY >= 0 && minY <= this.height;
|
|
1101
|
+
for (let ancestor = node.parent; visible && ancestor; ancestor = ancestor.parent) {
|
|
1102
|
+
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1103
|
+
let localMinX = Infinity;
|
|
1104
|
+
let localMinY = Infinity;
|
|
1105
|
+
let localMaxX = -Infinity;
|
|
1106
|
+
let localMaxY = -Infinity;
|
|
1107
|
+
for (const corner of worldCorners) {
|
|
1108
|
+
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1109
|
+
if (!local) continue;
|
|
1110
|
+
localMinX = Math.min(localMinX, local.x);
|
|
1111
|
+
localMinY = Math.min(localMinY, local.y);
|
|
1112
|
+
localMaxX = Math.max(localMaxX, local.x);
|
|
1113
|
+
localMaxY = Math.max(localMaxY, local.y);
|
|
1114
|
+
}
|
|
1115
|
+
visible = localMaxX >= 0 && localMinX <= ancestor.width && localMaxY >= 0 && localMinY <= ancestor.height;
|
|
1116
|
+
}
|
|
1096
1117
|
}
|
|
1097
1118
|
const display = visible ? "" : "none";
|
|
1098
1119
|
if (el.style.display !== display) el.style.display = display;
|
|
@@ -1640,6 +1661,10 @@ var Scene = (_class2 = class _Scene {
|
|
|
1640
1661
|
getA11yElement(entityId) {
|
|
1641
1662
|
return this.a11yElements.get(entityId);
|
|
1642
1663
|
}
|
|
1664
|
+
/** Gets the static-content DOM projection for an entity ID, when materialized. */
|
|
1665
|
+
getContentElement(entityId) {
|
|
1666
|
+
return this.contentElements.get(entityId);
|
|
1667
|
+
}
|
|
1643
1668
|
/**
|
|
1644
1669
|
* Gets the root entity of the scene.
|
|
1645
1670
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -549,6 +549,12 @@ var Scene = class _Scene {
|
|
|
549
549
|
this.activePortalsThisFrame.delete(node.id);
|
|
550
550
|
this.activePortalsPrevFrame.delete(node.id);
|
|
551
551
|
}
|
|
552
|
+
const contentEl = this.contentElements.get(node.id);
|
|
553
|
+
if (contentEl) {
|
|
554
|
+
contentEl.remove();
|
|
555
|
+
this.contentElements.delete(node.id);
|
|
556
|
+
this.a11yNeedsReorder = true;
|
|
557
|
+
}
|
|
552
558
|
const el = this.a11yElements.get(node.id);
|
|
553
559
|
if (el) {
|
|
554
560
|
if (el === this.focusedA11yElement) {
|
|
@@ -588,11 +594,6 @@ var Scene = class _Scene {
|
|
|
588
594
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
589
595
|
*/
|
|
590
596
|
detachA11y(entity) {
|
|
591
|
-
const contentEl = this.contentElements.get(entity.id);
|
|
592
|
-
if (contentEl) {
|
|
593
|
-
contentEl.remove();
|
|
594
|
-
this.contentElements.delete(entity.id);
|
|
595
|
-
}
|
|
596
597
|
this.removeA11yRecursively(entity);
|
|
597
598
|
}
|
|
598
599
|
/**
|
|
@@ -1028,6 +1029,7 @@ var Scene = class _Scene {
|
|
|
1028
1029
|
if (el) {
|
|
1029
1030
|
el.remove();
|
|
1030
1031
|
this.contentElements.delete(node.id);
|
|
1032
|
+
this.a11yNeedsReorder = true;
|
|
1031
1033
|
}
|
|
1032
1034
|
return;
|
|
1033
1035
|
}
|
|
@@ -1052,6 +1054,7 @@ var Scene = class _Scene {
|
|
|
1052
1054
|
);
|
|
1053
1055
|
this.a11yRoot.appendChild(el);
|
|
1054
1056
|
this.contentElements.set(node.id, el);
|
|
1057
|
+
this.a11yNeedsReorder = true;
|
|
1055
1058
|
}
|
|
1056
1059
|
if (el.textContent !== projection.text) el.textContent = projection.text;
|
|
1057
1060
|
const font = projection.font ?? "";
|
|
@@ -1078,6 +1081,7 @@ var Scene = class _Scene {
|
|
|
1078
1081
|
el.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0)`;
|
|
1079
1082
|
let visible = true;
|
|
1080
1083
|
if (node.width > 0 && node.height > 0) {
|
|
1084
|
+
const worldCorners = [];
|
|
1081
1085
|
let minX = Infinity;
|
|
1082
1086
|
let minY = Infinity;
|
|
1083
1087
|
let maxX = -Infinity;
|
|
@@ -1087,12 +1091,29 @@ var Scene = class _Scene {
|
|
|
1087
1091
|
const ly = i & 2 ? node.height : 0;
|
|
1088
1092
|
const wx = a * lx + c * ly + e;
|
|
1089
1093
|
const wy = b * lx + d * ly + f;
|
|
1094
|
+
worldCorners.push({ x: wx, y: wy });
|
|
1090
1095
|
if (wx < minX) minX = wx;
|
|
1091
1096
|
if (wx > maxX) maxX = wx;
|
|
1092
1097
|
if (wy < minY) minY = wy;
|
|
1093
1098
|
if (wy > maxY) maxY = wy;
|
|
1094
1099
|
}
|
|
1095
1100
|
visible = maxX >= 0 && minX <= this.width && maxY >= 0 && minY <= this.height;
|
|
1101
|
+
for (let ancestor = node.parent; visible && ancestor; ancestor = ancestor.parent) {
|
|
1102
|
+
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1103
|
+
let localMinX = Infinity;
|
|
1104
|
+
let localMinY = Infinity;
|
|
1105
|
+
let localMaxX = -Infinity;
|
|
1106
|
+
let localMaxY = -Infinity;
|
|
1107
|
+
for (const corner of worldCorners) {
|
|
1108
|
+
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1109
|
+
if (!local) continue;
|
|
1110
|
+
localMinX = Math.min(localMinX, local.x);
|
|
1111
|
+
localMinY = Math.min(localMinY, local.y);
|
|
1112
|
+
localMaxX = Math.max(localMaxX, local.x);
|
|
1113
|
+
localMaxY = Math.max(localMaxY, local.y);
|
|
1114
|
+
}
|
|
1115
|
+
visible = localMaxX >= 0 && localMinX <= ancestor.width && localMaxY >= 0 && localMinY <= ancestor.height;
|
|
1116
|
+
}
|
|
1096
1117
|
}
|
|
1097
1118
|
const display = visible ? "" : "none";
|
|
1098
1119
|
if (el.style.display !== display) el.style.display = display;
|
|
@@ -1640,6 +1661,10 @@ var Scene = class _Scene {
|
|
|
1640
1661
|
getA11yElement(entityId) {
|
|
1641
1662
|
return this.a11yElements.get(entityId);
|
|
1642
1663
|
}
|
|
1664
|
+
/** Gets the static-content DOM projection for an entity ID, when materialized. */
|
|
1665
|
+
getContentElement(entityId) {
|
|
1666
|
+
return this.contentElements.get(entityId);
|
|
1667
|
+
}
|
|
1643
1668
|
/**
|
|
1644
1669
|
* Gets the root entity of the scene.
|
|
1645
1670
|
*/
|
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -330,6 +330,8 @@ export declare class Scene {
|
|
|
330
330
|
* Gets the accessibility DOM element projected for the given entity ID.
|
|
331
331
|
*/
|
|
332
332
|
getA11yElement(entityId: string): HTMLElement | undefined;
|
|
333
|
+
/** Gets the static-content DOM projection for an entity ID, when materialized. */
|
|
334
|
+
getContentElement(entityId: string): HTMLElement | undefined;
|
|
333
335
|
/**
|
|
334
336
|
* Gets the root entity of the scene.
|
|
335
337
|
*/
|