@vectojs/core 1.13.0 → 1.14.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/index.js +139 -109
- package/dist/index.mjs +67 -37
- package/dist/tree/Scene.d.ts +22 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -720,73 +720,76 @@ var Scene = (_class2 = class _Scene {
|
|
|
720
720
|
__init29() {this.contentMetricScaleEpoch = -1}
|
|
721
721
|
__init30() {this.contentMetricScaleX = 1}
|
|
722
722
|
__init31() {this.contentProjectionEnabled = true}
|
|
723
|
+
// Virtualization margin (px) for content projection; `undefined` → one
|
|
724
|
+
// viewport height, resolved at sync time. `Infinity` = materialize everything.
|
|
725
|
+
__init32() {this.contentProjectionMargin = void 0}
|
|
723
726
|
/**
|
|
724
727
|
* True while a text-selection drag that started on a projection's blank
|
|
725
728
|
* region (no text node under the press) is being driven manually — the
|
|
726
729
|
* browser has no native anchor for it, so mousemove extends the Selection
|
|
727
730
|
* from the position we resolved ourselves.
|
|
728
731
|
*/
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
+
__init33() {this.blankRegionSelectionDrag = false}
|
|
733
|
+
__init34() {this.contentSelectionAnchor = null}
|
|
734
|
+
__init35() {this.contentSelectionEndListener = null}
|
|
732
735
|
// Animation/interactive flags collected during the render walk (tree-walk
|
|
733
736
|
// fusion): the loop reads last frame's answers instead of re-walking the
|
|
734
737
|
// tree up to 4× per tick. Start true so the first tick stays conservative.
|
|
735
|
-
|
|
736
|
-
|
|
738
|
+
__init36() {this.frameHadAnimation = true}
|
|
739
|
+
__init37() {this.frameHadInteractive = true}
|
|
737
740
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
741
|
+
__init38() {this.focusedA11yElement = null}
|
|
742
|
+
__init39() {this.caretBlinkTimer = null}
|
|
743
|
+
__init40() {this.a11yNeedsReorder = true}
|
|
744
|
+
__init41() {this.portalRoot = null}
|
|
745
|
+
__init42() {this.fullViewportElements = []}
|
|
746
|
+
__init43() {this.normalElements = []}
|
|
747
|
+
__init44() {this.activeIds = /* @__PURE__ */ new Set()}
|
|
748
|
+
__init45() {this.activePortalsThisFrame = /* @__PURE__ */ new Set()}
|
|
749
|
+
__init46() {this.activePortalsPrevFrame = /* @__PURE__ */ new Set()}
|
|
750
|
+
__init47() {this.portalEntities = /* @__PURE__ */ new Map()}
|
|
751
|
+
__init48() {this.renderOrderCounter = 0}
|
|
749
752
|
/**
|
|
750
753
|
* Authoritative paint order for semantic nodes discovered during the main
|
|
751
754
|
* render. A node may not have a DOM projection until the following a11y
|
|
752
755
|
* sync, so retaining the order prevents a newly opened overlay from spending
|
|
753
756
|
* its first frame below previously projected controls.
|
|
754
757
|
*/
|
|
755
|
-
|
|
758
|
+
__init49() {this.a11yRenderOrders = /* @__PURE__ */ new Map()}
|
|
756
759
|
// Optional WebGL point-cloud layer (see SceneOptions.pointBackend).
|
|
757
|
-
|
|
758
|
-
|
|
760
|
+
__init50() {this.pointRenderer = null}
|
|
761
|
+
__init51() {this.glCanvas = null}
|
|
759
762
|
|
|
760
763
|
|
|
761
764
|
|
|
762
|
-
|
|
765
|
+
__init52() {this.disableWindowResize = false}
|
|
763
766
|
/** See {@link SceneOptions.maxDPR}. `undefined` = uncapped (real DPR). */
|
|
764
767
|
|
|
765
768
|
// WebGPU properties
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
769
|
+
__init53() {this.destroyed = false}
|
|
770
|
+
__init54() {this.device = null}
|
|
771
|
+
__init55() {this.deviceLost = false}
|
|
772
|
+
__init56() {this.particleBackend = "auto"}
|
|
773
|
+
__init57() {this._webgpuDisabled = false}
|
|
771
774
|
get webgpuDisabled() {
|
|
772
775
|
return this._webgpuDisabled || this.particleBackend === "cpu";
|
|
773
776
|
}
|
|
774
777
|
set webgpuDisabled(value) {
|
|
775
778
|
this._webgpuDisabled = value;
|
|
776
779
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
780
|
+
__init58() {this.recoveryTimerId = null}
|
|
781
|
+
__init59() {this.manager = null}
|
|
782
|
+
__init60() {this.initializingWebGPU = false}
|
|
783
|
+
__init61() {this.gpuCanvas = null}
|
|
784
|
+
__init62() {this.gpuContext = null}
|
|
782
785
|
/** True while the GPU canvas holds a presented particle frame (needs clearing when they leave). */
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
786
|
+
__init63() {this.gpuHasContent = false}
|
|
787
|
+
__init64() {this.mouseX = -9999}
|
|
788
|
+
__init65() {this.mouseY = -9999}
|
|
789
|
+
__init66() {this.pointerMoveListener = null}
|
|
790
|
+
__init67() {this.pointerLeaveListener = null}
|
|
791
|
+
__init68() {this.hasWarnedZeroSize = false}
|
|
792
|
+
__init69() {this.fontLoadHandler = null}
|
|
790
793
|
// ── Dev-mode warning infrastructure ──────────────────────────────
|
|
791
794
|
//
|
|
792
795
|
// Enable with `Scene.devMode = true` or by setting `globalThis.__DEV__`.
|
|
@@ -804,7 +807,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
804
807
|
return false;
|
|
805
808
|
}
|
|
806
809
|
|
|
807
|
-
|
|
810
|
+
__init70() {this._devFrameCount = 0}
|
|
808
811
|
_devWarn(message) {
|
|
809
812
|
if (!this._devActive) return;
|
|
810
813
|
console.warn(`[vectojs/dev] ${message}`);
|
|
@@ -848,7 +851,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
848
851
|
};
|
|
849
852
|
walkProjections(this.root);
|
|
850
853
|
}
|
|
851
|
-
constructor(canvas, options = {}) {;_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);_class2.prototype.__init45.call(this);_class2.prototype.__init46.call(this);_class2.prototype.__init47.call(this);_class2.prototype.__init48.call(this);_class2.prototype.__init49.call(this);_class2.prototype.__init50.call(this);_class2.prototype.__init51.call(this);_class2.prototype.__init52.call(this);_class2.prototype.__init53.call(this);_class2.prototype.__init54.call(this);_class2.prototype.__init55.call(this);_class2.prototype.__init56.call(this);_class2.prototype.__init57.call(this);_class2.prototype.__init58.call(this);_class2.prototype.__init59.call(this);_class2.prototype.__init60.call(this);_class2.prototype.__init61.call(this);_class2.prototype.__init62.call(this);_class2.prototype.__init63.call(this);_class2.prototype.__init64.call(this);_class2.prototype.__init65.call(this);_class2.prototype.__init66.call(this);_class2.prototype.__init67.call(this);_class2.prototype.__init68.call(this);_class2.prototype.__init69.call(this);
|
|
854
|
+
constructor(canvas, options = {}) {;_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);_class2.prototype.__init45.call(this);_class2.prototype.__init46.call(this);_class2.prototype.__init47.call(this);_class2.prototype.__init48.call(this);_class2.prototype.__init49.call(this);_class2.prototype.__init50.call(this);_class2.prototype.__init51.call(this);_class2.prototype.__init52.call(this);_class2.prototype.__init53.call(this);_class2.prototype.__init54.call(this);_class2.prototype.__init55.call(this);_class2.prototype.__init56.call(this);_class2.prototype.__init57.call(this);_class2.prototype.__init58.call(this);_class2.prototype.__init59.call(this);_class2.prototype.__init60.call(this);_class2.prototype.__init61.call(this);_class2.prototype.__init62.call(this);_class2.prototype.__init63.call(this);_class2.prototype.__init64.call(this);_class2.prototype.__init65.call(this);_class2.prototype.__init66.call(this);_class2.prototype.__init67.call(this);_class2.prototype.__init68.call(this);_class2.prototype.__init69.call(this);_class2.prototype.__init70.call(this);
|
|
852
855
|
this.canvas = canvas;
|
|
853
856
|
this.debugA11y = _nullishCoalesce(options.debugA11y, () => ( false));
|
|
854
857
|
this.disableWindowResize = _nullishCoalesce(options.disableWindowResize, () => ( false));
|
|
@@ -870,6 +873,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
870
873
|
this.particleBackend = _nullishCoalesce(options.particleBackend, () => ( "auto"));
|
|
871
874
|
this.a11ySyncInterval = _nullishCoalesce(options.a11ySyncInterval, () => ( 0));
|
|
872
875
|
this.contentProjectionEnabled = _nullishCoalesce(options.contentProjection, () => ( true));
|
|
876
|
+
this.contentProjectionMargin = options.contentProjectionMargin;
|
|
873
877
|
this._devActive = _Scene._devModeDetected();
|
|
874
878
|
this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
|
|
875
879
|
this.root = new class RootEntity extends _chunk2Z23LTH3js.Entity {
|
|
@@ -1661,6 +1665,56 @@ var Scene = (_class2 = class _Scene {
|
|
|
1661
1665
|
* hidden (`display: none`) so text-heavy scenes only materialize what is
|
|
1662
1666
|
* visible to the browser's text machinery anyway.
|
|
1663
1667
|
*/
|
|
1668
|
+
/**
|
|
1669
|
+
* Whether `node`'s world-space box, expanded by `margin` px on every side,
|
|
1670
|
+
* overlaps the scene viewport AND every `clipChildren` ancestor's box. Used
|
|
1671
|
+
* both to virtualize content projection (materialize only near-viewport text,
|
|
1672
|
+
* at `margin = contentProjectionMargin`) and for the exact `display:none`
|
|
1673
|
+
* visibility test (`margin = 0`). Boundless nodes (width/height 0) opt out of
|
|
1674
|
+
* culling and always count as visible, matching the legacy behavior.
|
|
1675
|
+
*/
|
|
1676
|
+
projectionBoxVisible(node, tf, margin) {
|
|
1677
|
+
if (!(node.width > 0 && node.height > 0)) return true;
|
|
1678
|
+
const { a, b, c, d, e, f } = tf;
|
|
1679
|
+
const worldCorners = [];
|
|
1680
|
+
let minX = Infinity;
|
|
1681
|
+
let minY = Infinity;
|
|
1682
|
+
let maxX = -Infinity;
|
|
1683
|
+
let maxY = -Infinity;
|
|
1684
|
+
for (let i = 0; i < 4; i++) {
|
|
1685
|
+
const lx = i & 1 ? node.width : 0;
|
|
1686
|
+
const ly = i & 2 ? node.height : 0;
|
|
1687
|
+
const wx = a * lx + c * ly + e;
|
|
1688
|
+
const wy = b * lx + d * ly + f;
|
|
1689
|
+
worldCorners.push({ x: wx, y: wy });
|
|
1690
|
+
if (wx < minX) minX = wx;
|
|
1691
|
+
if (wx > maxX) maxX = wx;
|
|
1692
|
+
if (wy < minY) minY = wy;
|
|
1693
|
+
if (wy > maxY) maxY = wy;
|
|
1694
|
+
}
|
|
1695
|
+
if (!(maxX >= -margin && minX <= this.width + margin && maxY >= -margin && minY <= this.height + margin)) {
|
|
1696
|
+
return false;
|
|
1697
|
+
}
|
|
1698
|
+
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
|
1699
|
+
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1700
|
+
let localMinX = Infinity;
|
|
1701
|
+
let localMinY = Infinity;
|
|
1702
|
+
let localMaxX = -Infinity;
|
|
1703
|
+
let localMaxY = -Infinity;
|
|
1704
|
+
for (const corner of worldCorners) {
|
|
1705
|
+
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1706
|
+
if (!local) continue;
|
|
1707
|
+
localMinX = Math.min(localMinX, local.x);
|
|
1708
|
+
localMinY = Math.min(localMinY, local.y);
|
|
1709
|
+
localMaxX = Math.max(localMaxX, local.x);
|
|
1710
|
+
localMaxY = Math.max(localMaxY, local.y);
|
|
1711
|
+
}
|
|
1712
|
+
if (!(localMaxX >= -margin && localMinX <= ancestor.width + margin && localMaxY >= -margin && localMinY <= ancestor.height + margin)) {
|
|
1713
|
+
return false;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
return true;
|
|
1717
|
+
}
|
|
1664
1718
|
syncContentProjection(node) {
|
|
1665
1719
|
if (!this.contentProjectionEnabled || !this.a11yRoot) return;
|
|
1666
1720
|
const projection = node.getContentProjection();
|
|
@@ -1674,6 +1728,17 @@ var Scene = (_class2 = class _Scene {
|
|
|
1674
1728
|
}
|
|
1675
1729
|
return;
|
|
1676
1730
|
}
|
|
1731
|
+
const worldTf = node.getWorldTransform();
|
|
1732
|
+
const margin = _nullishCoalesce(this.contentProjectionMargin, () => ( this.height));
|
|
1733
|
+
if (Number.isFinite(margin) && !this.projectionBoxVisible(node, worldTf, margin)) {
|
|
1734
|
+
if (el) {
|
|
1735
|
+
this.clearContentGridState(node.id, el);
|
|
1736
|
+
el.remove();
|
|
1737
|
+
this.contentElements.delete(node.id);
|
|
1738
|
+
this.a11yNeedsReorder = true;
|
|
1739
|
+
}
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1677
1742
|
if (!el) {
|
|
1678
1743
|
el = document.createElement("div");
|
|
1679
1744
|
el.setAttribute("data-vecto-content", node.id);
|
|
@@ -1770,7 +1835,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
1770
1835
|
el.style.userSelect = selectable ? "text" : "none";
|
|
1771
1836
|
el.style.cursor = selectable ? "text" : "";
|
|
1772
1837
|
}
|
|
1773
|
-
const { a, b, c, d, e, f } =
|
|
1838
|
+
const { a, b, c, d, e, f } = worldTf;
|
|
1774
1839
|
const contentX = _nullishCoalesce(projection.contentX, () => ( 0));
|
|
1775
1840
|
const contentY = _nullishCoalesce(projection.contentY, () => ( 0));
|
|
1776
1841
|
const baselineOffset = lines && lines.length > 0 ? 0 : projection.baseline === void 0 ? 0 : projection.baseline - _chunk2Z23LTH3js.cssLineBoxBaseline.call(void 0, font, _nullishCoalesce(projection.lineHeight, () => ( 16)));
|
|
@@ -1780,42 +1845,7 @@ var Scene = (_class2 = class _Scene {
|
|
|
1780
1845
|
if (node.width > 0) el.style.width = `${node.width}px`;
|
|
1781
1846
|
if (node.height > 0) el.style.height = `${node.height}px`;
|
|
1782
1847
|
el.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0)`;
|
|
1783
|
-
|
|
1784
|
-
if (node.width > 0 && node.height > 0) {
|
|
1785
|
-
const worldCorners = [];
|
|
1786
|
-
let minX = Infinity;
|
|
1787
|
-
let minY = Infinity;
|
|
1788
|
-
let maxX = -Infinity;
|
|
1789
|
-
let maxY = -Infinity;
|
|
1790
|
-
for (let i = 0; i < 4; i++) {
|
|
1791
|
-
const lx = i & 1 ? node.width : 0;
|
|
1792
|
-
const ly = i & 2 ? node.height : 0;
|
|
1793
|
-
const wx = a * lx + c * ly + e;
|
|
1794
|
-
const wy = b * lx + d * ly + f;
|
|
1795
|
-
worldCorners.push({ x: wx, y: wy });
|
|
1796
|
-
if (wx < minX) minX = wx;
|
|
1797
|
-
if (wx > maxX) maxX = wx;
|
|
1798
|
-
if (wy < minY) minY = wy;
|
|
1799
|
-
if (wy > maxY) maxY = wy;
|
|
1800
|
-
}
|
|
1801
|
-
visible = maxX >= 0 && minX <= this.width && maxY >= 0 && minY <= this.height;
|
|
1802
|
-
for (let ancestor = node.parent; visible && ancestor; ancestor = ancestor.parent) {
|
|
1803
|
-
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1804
|
-
let localMinX = Infinity;
|
|
1805
|
-
let localMinY = Infinity;
|
|
1806
|
-
let localMaxX = -Infinity;
|
|
1807
|
-
let localMaxY = -Infinity;
|
|
1808
|
-
for (const corner of worldCorners) {
|
|
1809
|
-
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1810
|
-
if (!local) continue;
|
|
1811
|
-
localMinX = Math.min(localMinX, local.x);
|
|
1812
|
-
localMinY = Math.min(localMinY, local.y);
|
|
1813
|
-
localMaxX = Math.max(localMaxX, local.x);
|
|
1814
|
-
localMaxY = Math.max(localMaxY, local.y);
|
|
1815
|
-
}
|
|
1816
|
-
visible = localMaxX >= 0 && localMinX <= ancestor.width && localMaxY >= 0 && localMinY <= ancestor.height;
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1848
|
+
const visible = this.projectionBoxVisible(node, worldTf, 0);
|
|
1819
1849
|
const display = visible ? "" : "none";
|
|
1820
1850
|
if (el.style.display !== display) el.style.display = display;
|
|
1821
1851
|
}
|
|
@@ -2818,15 +2848,15 @@ var TextEntity = (_class3 = class extends _chunk2Z23LTH3js.Entity {
|
|
|
2818
2848
|
|
|
2819
2849
|
|
|
2820
2850
|
|
|
2821
|
-
|
|
2851
|
+
__init71() {this.nodes = []}
|
|
2822
2852
|
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2853
|
+
__init72() {this.fillStyle = "#94a3b8"}
|
|
2854
|
+
__init73() {this.strokeStyle = null}
|
|
2855
|
+
__init74() {this.hoveredFillStyle = "#ffffff"}
|
|
2856
|
+
__init75() {this.lineWidth = 1}
|
|
2857
|
+
__init76() {this.isHovered = false}
|
|
2828
2858
|
constructor(text, atlas, maxWidth, fontSize = 24) {
|
|
2829
|
-
super();_class3.prototype.
|
|
2859
|
+
super();_class3.prototype.__init71.call(this);_class3.prototype.__init72.call(this);_class3.prototype.__init73.call(this);_class3.prototype.__init74.call(this);_class3.prototype.__init75.call(this);_class3.prototype.__init76.call(this);;
|
|
2830
2860
|
this.text = text;
|
|
2831
2861
|
this.atlas = atlas;
|
|
2832
2862
|
this.fontSize = fontSize;
|
|
@@ -2941,15 +2971,15 @@ var TextEntity = (_class3 = class extends _chunk2Z23LTH3js.Entity {
|
|
|
2941
2971
|
// src/components/GridTextEntity.ts
|
|
2942
2972
|
var GridTextEntity = (_class4 = class extends _chunk2Z23LTH3js.Entity {
|
|
2943
2973
|
|
|
2944
|
-
|
|
2945
|
-
|
|
2974
|
+
__init77() {this.fillStyle = "#ffffff"}
|
|
2975
|
+
__init78() {this.grid = []}
|
|
2946
2976
|
// Array of rows
|
|
2947
|
-
|
|
2948
|
-
|
|
2977
|
+
__init79() {this.cols = 0}
|
|
2978
|
+
__init80() {this.rows = 0}
|
|
2949
2979
|
|
|
2950
2980
|
|
|
2951
2981
|
constructor(_atlas, fontSize = 10) {
|
|
2952
|
-
super();_class4.prototype.
|
|
2982
|
+
super();_class4.prototype.__init77.call(this);_class4.prototype.__init78.call(this);_class4.prototype.__init79.call(this);_class4.prototype.__init80.call(this);;
|
|
2953
2983
|
this.fontSize = fontSize;
|
|
2954
2984
|
this.charWidth = fontSize * 1;
|
|
2955
2985
|
this.charHeight = fontSize * 1.1;
|
|
@@ -3041,23 +3071,23 @@ var SplineEntity = (_class5 = class extends _chunk2Z23LTH3js.Entity {
|
|
|
3041
3071
|
|
|
3042
3072
|
|
|
3043
3073
|
|
|
3044
|
-
|
|
3045
|
-
|
|
3074
|
+
__init81() {this.offscreen = null}
|
|
3075
|
+
__init82() {this.baked = false}
|
|
3046
3076
|
/** Logical (CSS-pixel) size of the baked bitmap — the blit destination size. */
|
|
3047
|
-
|
|
3048
|
-
|
|
3077
|
+
__init83() {this.bakedWidth = 0}
|
|
3078
|
+
__init84() {this.bakedHeight = 0}
|
|
3049
3079
|
/** Gradient strokes can't be baked to a solid-color bitmap; they render per-frame. */
|
|
3050
3080
|
|
|
3051
3081
|
/** Lazily-flattened polylines (one Float32Array of [x,y,...] per segment) for hit-testing. */
|
|
3052
|
-
|
|
3082
|
+
__init85() {this.polylines = null}
|
|
3053
3083
|
/**
|
|
3054
3084
|
* When `true`, the renderer draws a rounded-rect outline of the entity's
|
|
3055
3085
|
* local bounds after painting the curves. Useful for drag feedback and
|
|
3056
3086
|
* debugging hit areas. Defaults to `false`.
|
|
3057
3087
|
*/
|
|
3058
|
-
|
|
3088
|
+
__init86() {this.showBounds = false}
|
|
3059
3089
|
constructor(doc, opts = {}) {
|
|
3060
|
-
super();_class5.prototype.
|
|
3090
|
+
super();_class5.prototype.__init81.call(this);_class5.prototype.__init82.call(this);_class5.prototype.__init83.call(this);_class5.prototype.__init84.call(this);_class5.prototype.__init85.call(this);_class5.prototype.__init86.call(this);;
|
|
3061
3091
|
this.doc = doc;
|
|
3062
3092
|
this.lineWidth = _nullishCoalesce(opts.lineWidth, () => ( 2));
|
|
3063
3093
|
this.cache = _nullishCoalesce(opts.cache, () => ( true));
|
|
@@ -3432,9 +3462,9 @@ var Group = class extends _chunk2Z23LTH3js.Entity {
|
|
|
3432
3462
|
// src/math/SpatialHashGrid.ts
|
|
3433
3463
|
var SpatialHashGrid = (_class6 = class {
|
|
3434
3464
|
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
constructor(cellSize = 64) {;_class6.prototype.
|
|
3465
|
+
__init87() {this.grid = /* @__PURE__ */ new Map()}
|
|
3466
|
+
__init88() {this.entityCells = /* @__PURE__ */ new Map()}
|
|
3467
|
+
constructor(cellSize = 64) {;_class6.prototype.__init87.call(this);_class6.prototype.__init88.call(this);
|
|
3438
3468
|
this.cellSize = cellSize;
|
|
3439
3469
|
}
|
|
3440
3470
|
hash(cx, cy) {
|
|
@@ -3526,18 +3556,18 @@ var SpatialHashGrid = (_class6 = class {
|
|
|
3526
3556
|
// src/tree/DOMPortalEntity.ts
|
|
3527
3557
|
var DOMPortalEntity = (_class7 = class extends _chunk2Z23LTH3js.Entity {
|
|
3528
3558
|
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3559
|
+
__init89() {this.isDOMPortal = true}
|
|
3560
|
+
__init90() {this.domListeners = []}
|
|
3561
|
+
__init91() {this.resizeObserver = null}
|
|
3562
|
+
__init92() {this.cachedWidth = 100}
|
|
3563
|
+
__init93() {this.cachedHeight = 100}
|
|
3564
|
+
__init94() {this.lastWidth = ""}
|
|
3565
|
+
__init95() {this.lastHeight = ""}
|
|
3566
|
+
__init96() {this.lastTransform = ""}
|
|
3567
|
+
__init97() {this.lastZIndex = ""}
|
|
3568
|
+
__init98() {this.lastOpacity = ""}
|
|
3539
3569
|
constructor(domElement, width, height, id) {
|
|
3540
|
-
super(id);_class7.prototype.
|
|
3570
|
+
super(id);_class7.prototype.__init89.call(this);_class7.prototype.__init90.call(this);_class7.prototype.__init91.call(this);_class7.prototype.__init92.call(this);_class7.prototype.__init93.call(this);_class7.prototype.__init94.call(this);_class7.prototype.__init95.call(this);_class7.prototype.__init96.call(this);_class7.prototype.__init97.call(this);_class7.prototype.__init98.call(this);;
|
|
3541
3571
|
this.domElement = domElement;
|
|
3542
3572
|
this.width = _nullishCoalesce(width, () => ( 0));
|
|
3543
3573
|
this.height = _nullishCoalesce(height, () => ( 0));
|
package/dist/index.mjs
CHANGED
|
@@ -720,6 +720,9 @@ var Scene = class _Scene {
|
|
|
720
720
|
contentMetricScaleEpoch = -1;
|
|
721
721
|
contentMetricScaleX = 1;
|
|
722
722
|
contentProjectionEnabled = true;
|
|
723
|
+
// Virtualization margin (px) for content projection; `undefined` → one
|
|
724
|
+
// viewport height, resolved at sync time. `Infinity` = materialize everything.
|
|
725
|
+
contentProjectionMargin = void 0;
|
|
723
726
|
/**
|
|
724
727
|
* True while a text-selection drag that started on a projection's blank
|
|
725
728
|
* region (no text node under the press) is being driven manually — the
|
|
@@ -870,6 +873,7 @@ var Scene = class _Scene {
|
|
|
870
873
|
this.particleBackend = options.particleBackend ?? "auto";
|
|
871
874
|
this.a11ySyncInterval = options.a11ySyncInterval ?? 0;
|
|
872
875
|
this.contentProjectionEnabled = options.contentProjection ?? true;
|
|
876
|
+
this.contentProjectionMargin = options.contentProjectionMargin;
|
|
873
877
|
this._devActive = _Scene._devModeDetected();
|
|
874
878
|
this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
|
|
875
879
|
this.root = new class RootEntity extends Entity {
|
|
@@ -1661,6 +1665,56 @@ var Scene = class _Scene {
|
|
|
1661
1665
|
* hidden (`display: none`) so text-heavy scenes only materialize what is
|
|
1662
1666
|
* visible to the browser's text machinery anyway.
|
|
1663
1667
|
*/
|
|
1668
|
+
/**
|
|
1669
|
+
* Whether `node`'s world-space box, expanded by `margin` px on every side,
|
|
1670
|
+
* overlaps the scene viewport AND every `clipChildren` ancestor's box. Used
|
|
1671
|
+
* both to virtualize content projection (materialize only near-viewport text,
|
|
1672
|
+
* at `margin = contentProjectionMargin`) and for the exact `display:none`
|
|
1673
|
+
* visibility test (`margin = 0`). Boundless nodes (width/height 0) opt out of
|
|
1674
|
+
* culling and always count as visible, matching the legacy behavior.
|
|
1675
|
+
*/
|
|
1676
|
+
projectionBoxVisible(node, tf, margin) {
|
|
1677
|
+
if (!(node.width > 0 && node.height > 0)) return true;
|
|
1678
|
+
const { a, b, c, d, e, f } = tf;
|
|
1679
|
+
const worldCorners = [];
|
|
1680
|
+
let minX = Infinity;
|
|
1681
|
+
let minY = Infinity;
|
|
1682
|
+
let maxX = -Infinity;
|
|
1683
|
+
let maxY = -Infinity;
|
|
1684
|
+
for (let i = 0; i < 4; i++) {
|
|
1685
|
+
const lx = i & 1 ? node.width : 0;
|
|
1686
|
+
const ly = i & 2 ? node.height : 0;
|
|
1687
|
+
const wx = a * lx + c * ly + e;
|
|
1688
|
+
const wy = b * lx + d * ly + f;
|
|
1689
|
+
worldCorners.push({ x: wx, y: wy });
|
|
1690
|
+
if (wx < minX) minX = wx;
|
|
1691
|
+
if (wx > maxX) maxX = wx;
|
|
1692
|
+
if (wy < minY) minY = wy;
|
|
1693
|
+
if (wy > maxY) maxY = wy;
|
|
1694
|
+
}
|
|
1695
|
+
if (!(maxX >= -margin && minX <= this.width + margin && maxY >= -margin && minY <= this.height + margin)) {
|
|
1696
|
+
return false;
|
|
1697
|
+
}
|
|
1698
|
+
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
|
1699
|
+
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1700
|
+
let localMinX = Infinity;
|
|
1701
|
+
let localMinY = Infinity;
|
|
1702
|
+
let localMaxX = -Infinity;
|
|
1703
|
+
let localMaxY = -Infinity;
|
|
1704
|
+
for (const corner of worldCorners) {
|
|
1705
|
+
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1706
|
+
if (!local) continue;
|
|
1707
|
+
localMinX = Math.min(localMinX, local.x);
|
|
1708
|
+
localMinY = Math.min(localMinY, local.y);
|
|
1709
|
+
localMaxX = Math.max(localMaxX, local.x);
|
|
1710
|
+
localMaxY = Math.max(localMaxY, local.y);
|
|
1711
|
+
}
|
|
1712
|
+
if (!(localMaxX >= -margin && localMinX <= ancestor.width + margin && localMaxY >= -margin && localMinY <= ancestor.height + margin)) {
|
|
1713
|
+
return false;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
return true;
|
|
1717
|
+
}
|
|
1664
1718
|
syncContentProjection(node) {
|
|
1665
1719
|
if (!this.contentProjectionEnabled || !this.a11yRoot) return;
|
|
1666
1720
|
const projection = node.getContentProjection();
|
|
@@ -1674,6 +1728,17 @@ var Scene = class _Scene {
|
|
|
1674
1728
|
}
|
|
1675
1729
|
return;
|
|
1676
1730
|
}
|
|
1731
|
+
const worldTf = node.getWorldTransform();
|
|
1732
|
+
const margin = this.contentProjectionMargin ?? this.height;
|
|
1733
|
+
if (Number.isFinite(margin) && !this.projectionBoxVisible(node, worldTf, margin)) {
|
|
1734
|
+
if (el) {
|
|
1735
|
+
this.clearContentGridState(node.id, el);
|
|
1736
|
+
el.remove();
|
|
1737
|
+
this.contentElements.delete(node.id);
|
|
1738
|
+
this.a11yNeedsReorder = true;
|
|
1739
|
+
}
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1677
1742
|
if (!el) {
|
|
1678
1743
|
el = document.createElement("div");
|
|
1679
1744
|
el.setAttribute("data-vecto-content", node.id);
|
|
@@ -1770,7 +1835,7 @@ var Scene = class _Scene {
|
|
|
1770
1835
|
el.style.userSelect = selectable ? "text" : "none";
|
|
1771
1836
|
el.style.cursor = selectable ? "text" : "";
|
|
1772
1837
|
}
|
|
1773
|
-
const { a, b, c, d, e, f } =
|
|
1838
|
+
const { a, b, c, d, e, f } = worldTf;
|
|
1774
1839
|
const contentX = projection.contentX ?? 0;
|
|
1775
1840
|
const contentY = projection.contentY ?? 0;
|
|
1776
1841
|
const baselineOffset = lines && lines.length > 0 ? 0 : projection.baseline === void 0 ? 0 : projection.baseline - cssLineBoxBaseline(font, projection.lineHeight ?? 16);
|
|
@@ -1780,42 +1845,7 @@ var Scene = class _Scene {
|
|
|
1780
1845
|
if (node.width > 0) el.style.width = `${node.width}px`;
|
|
1781
1846
|
if (node.height > 0) el.style.height = `${node.height}px`;
|
|
1782
1847
|
el.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0)`;
|
|
1783
|
-
|
|
1784
|
-
if (node.width > 0 && node.height > 0) {
|
|
1785
|
-
const worldCorners = [];
|
|
1786
|
-
let minX = Infinity;
|
|
1787
|
-
let minY = Infinity;
|
|
1788
|
-
let maxX = -Infinity;
|
|
1789
|
-
let maxY = -Infinity;
|
|
1790
|
-
for (let i = 0; i < 4; i++) {
|
|
1791
|
-
const lx = i & 1 ? node.width : 0;
|
|
1792
|
-
const ly = i & 2 ? node.height : 0;
|
|
1793
|
-
const wx = a * lx + c * ly + e;
|
|
1794
|
-
const wy = b * lx + d * ly + f;
|
|
1795
|
-
worldCorners.push({ x: wx, y: wy });
|
|
1796
|
-
if (wx < minX) minX = wx;
|
|
1797
|
-
if (wx > maxX) maxX = wx;
|
|
1798
|
-
if (wy < minY) minY = wy;
|
|
1799
|
-
if (wy > maxY) maxY = wy;
|
|
1800
|
-
}
|
|
1801
|
-
visible = maxX >= 0 && minX <= this.width && maxY >= 0 && minY <= this.height;
|
|
1802
|
-
for (let ancestor = node.parent; visible && ancestor; ancestor = ancestor.parent) {
|
|
1803
|
-
if (!ancestor.clipChildren || ancestor.width <= 0 || ancestor.height <= 0) continue;
|
|
1804
|
-
let localMinX = Infinity;
|
|
1805
|
-
let localMinY = Infinity;
|
|
1806
|
-
let localMaxX = -Infinity;
|
|
1807
|
-
let localMaxY = -Infinity;
|
|
1808
|
-
for (const corner of worldCorners) {
|
|
1809
|
-
const local = ancestor.worldToLocal(corner.x, corner.y);
|
|
1810
|
-
if (!local) continue;
|
|
1811
|
-
localMinX = Math.min(localMinX, local.x);
|
|
1812
|
-
localMinY = Math.min(localMinY, local.y);
|
|
1813
|
-
localMaxX = Math.max(localMaxX, local.x);
|
|
1814
|
-
localMaxY = Math.max(localMaxY, local.y);
|
|
1815
|
-
}
|
|
1816
|
-
visible = localMaxX >= 0 && localMinX <= ancestor.width && localMaxY >= 0 && localMinY <= ancestor.height;
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1848
|
+
const visible = this.projectionBoxVisible(node, worldTf, 0);
|
|
1819
1849
|
const display = visible ? "" : "none";
|
|
1820
1850
|
if (el.style.display !== display) el.style.display = display;
|
|
1821
1851
|
}
|
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -98,6 +98,18 @@ export interface SceneOptions {
|
|
|
98
98
|
* scenes to skip the sync walk.
|
|
99
99
|
*/
|
|
100
100
|
contentProjection?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* How far outside the viewport (in CSS px, each side) content projections are
|
|
103
|
+
* materialized as DOM. Projections whose box is farther than this are not
|
|
104
|
+
* created — and are removed when they scroll past it — so a document taller
|
|
105
|
+
* than the viewport keeps only a bounded, near-viewport set of DOM nodes
|
|
106
|
+
* instead of one element (plus a `<span>` per line) per block for the whole
|
|
107
|
+
* document. A larger margin keeps more off-screen text ready for native
|
|
108
|
+
* find-in-page / selection at the cost of more DOM; `Infinity` restores the
|
|
109
|
+
* legacy "materialize the entire document" behavior. Default: one viewport
|
|
110
|
+
* height (`undefined` → resolved to `Scene.height` at sync time).
|
|
111
|
+
*/
|
|
112
|
+
contentProjectionMargin?: number;
|
|
101
113
|
}
|
|
102
114
|
/** Frame-rate the loop is capped to when the OS requests reduced motion. */
|
|
103
115
|
export declare const REDUCED_MOTION_FPS = 30;
|
|
@@ -216,6 +228,7 @@ export declare class Scene {
|
|
|
216
228
|
private contentMetricScaleEpoch;
|
|
217
229
|
private contentMetricScaleX;
|
|
218
230
|
private contentProjectionEnabled;
|
|
231
|
+
private contentProjectionMargin;
|
|
219
232
|
/**
|
|
220
233
|
* True while a text-selection drag that started on a projection's blank
|
|
221
234
|
* region (no text node under the press) is being driven manually — the
|
|
@@ -402,6 +415,15 @@ export declare class Scene {
|
|
|
402
415
|
* hidden (`display: none`) so text-heavy scenes only materialize what is
|
|
403
416
|
* visible to the browser's text machinery anyway.
|
|
404
417
|
*/
|
|
418
|
+
/**
|
|
419
|
+
* Whether `node`'s world-space box, expanded by `margin` px on every side,
|
|
420
|
+
* overlaps the scene viewport AND every `clipChildren` ancestor's box. Used
|
|
421
|
+
* both to virtualize content projection (materialize only near-viewport text,
|
|
422
|
+
* at `margin = contentProjectionMargin`) and for the exact `display:none`
|
|
423
|
+
* visibility test (`margin = 0`). Boundless nodes (width/height 0) opt out of
|
|
424
|
+
* culling and always count as visible, matching the legacy behavior.
|
|
425
|
+
*/
|
|
426
|
+
private projectionBoxVisible;
|
|
405
427
|
private syncContentProjection;
|
|
406
428
|
/**
|
|
407
429
|
* Materialize a prepared grid in logical source order while positioning each
|