bireactive 0.2.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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/animation/anim.d.ts +57 -0
- package/dist/animation/anim.js +318 -0
- package/dist/animation/combinators.d.ts +39 -0
- package/dist/animation/combinators.js +113 -0
- package/dist/animation/easings.d.ts +5 -0
- package/dist/animation/easings.js +5 -0
- package/dist/animation/index.d.ts +3 -0
- package/dist/animation/index.js +3 -0
- package/dist/assert/algebra.d.ts +20 -0
- package/dist/assert/algebra.js +79 -0
- package/dist/assert/claim.d.ts +40 -0
- package/dist/assert/claim.js +129 -0
- package/dist/assert/index.d.ts +7 -0
- package/dist/assert/index.js +19 -0
- package/dist/assert/predicates.d.ts +18 -0
- package/dist/assert/predicates.js +43 -0
- package/dist/assert/record.d.ts +20 -0
- package/dist/assert/record.js +78 -0
- package/dist/assert/scope.d.ts +42 -0
- package/dist/assert/scope.js +233 -0
- package/dist/assert/span.d.ts +37 -0
- package/dist/assert/span.js +68 -0
- package/dist/assert/tree.d.ts +22 -0
- package/dist/assert/tree.js +65 -0
- package/dist/code/code.d.ts +70 -0
- package/dist/code/code.js +361 -0
- package/dist/code/index.d.ts +2 -0
- package/dist/code/index.js +9 -0
- package/dist/code/morph.d.ts +5 -0
- package/dist/code/morph.js +194 -0
- package/dist/code/tokenize.d.ts +8 -0
- package/dist/code/tokenize.js +51 -0
- package/dist/constraints/cluster.d.ts +83 -0
- package/dist/constraints/cluster.js +213 -0
- package/dist/constraints/drivers.d.ts +15 -0
- package/dist/constraints/drivers.js +40 -0
- package/dist/constraints/factories.d.ts +73 -0
- package/dist/constraints/factories.js +248 -0
- package/dist/constraints/index.d.ts +11 -0
- package/dist/constraints/index.js +39 -0
- package/dist/constraints/interaction.d.ts +21 -0
- package/dist/constraints/interaction.js +148 -0
- package/dist/constraints/linalg.d.ts +18 -0
- package/dist/constraints/linalg.js +141 -0
- package/dist/constraints/phases.d.ts +21 -0
- package/dist/constraints/phases.js +60 -0
- package/dist/constraints/physics.d.ts +34 -0
- package/dist/constraints/physics.js +128 -0
- package/dist/constraints/rigid.d.ts +210 -0
- package/dist/constraints/rigid.js +835 -0
- package/dist/constraints/solver.d.ts +107 -0
- package/dist/constraints/solver.js +510 -0
- package/dist/constraints/term.d.ts +50 -0
- package/dist/constraints/term.js +80 -0
- package/dist/constraints/terms.d.ts +80 -0
- package/dist/constraints/terms.js +302 -0
- package/dist/constraints/world.d.ts +31 -0
- package/dist/constraints/world.js +245 -0
- package/dist/core/aggregates.d.ts +64 -0
- package/dist/core/aggregates.js +198 -0
- package/dist/core/anim.d.ts +84 -0
- package/dist/core/anim.js +301 -0
- package/dist/core/index.d.ts +38 -0
- package/dist/core/index.js +38 -0
- package/dist/core/introspect.d.ts +5 -0
- package/dist/core/introspect.js +31 -0
- package/dist/core/lenses/closed-form-policies.d.ts +64 -0
- package/dist/core/lenses/closed-form-policies.js +452 -0
- package/dist/core/lenses/domain-aggregates.d.ts +54 -0
- package/dist/core/lenses/domain-aggregates.js +259 -0
- package/dist/core/lenses/factor-lens.d.ts +42 -0
- package/dist/core/lenses/factor-lens.js +419 -0
- package/dist/core/lenses/index.d.ts +5 -0
- package/dist/core/lenses/index.js +16 -0
- package/dist/core/lenses/memory.d.ts +47 -0
- package/dist/core/lenses/memory.js +102 -0
- package/dist/core/lenses/typed-factor.d.ts +45 -0
- package/dist/core/lenses/typed-factor.js +376 -0
- package/dist/core/network-utils.d.ts +14 -0
- package/dist/core/network-utils.js +62 -0
- package/dist/core/new-primitives.d.ts +33 -0
- package/dist/core/new-primitives.js +113 -0
- package/dist/core/signal.d.ts +254 -0
- package/dist/core/signal.js +1349 -0
- package/dist/core/traits.d.ts +61 -0
- package/dist/core/traits.js +56 -0
- package/dist/core/tree.d.ts +23 -0
- package/dist/core/tree.js +62 -0
- package/dist/core/values/anchor.d.ts +23 -0
- package/dist/core/values/anchor.js +23 -0
- package/dist/core/values/audio.d.ts +33 -0
- package/dist/core/values/audio.js +107 -0
- package/dist/core/values/bool.d.ts +37 -0
- package/dist/core/values/bool.js +75 -0
- package/dist/core/values/box.d.ts +77 -0
- package/dist/core/values/box.js +211 -0
- package/dist/core/values/canvas.d.ts +71 -0
- package/dist/core/values/canvas.js +495 -0
- package/dist/core/values/color.d.ts +49 -0
- package/dist/core/values/color.js +106 -0
- package/dist/core/values/flags.d.ts +18 -0
- package/dist/core/values/flags.js +50 -0
- package/dist/core/values/gpu.d.ts +74 -0
- package/dist/core/values/gpu.js +426 -0
- package/dist/core/values/matrix.d.ts +53 -0
- package/dist/core/values/matrix.js +140 -0
- package/dist/core/values/num.d.ts +62 -0
- package/dist/core/values/num.js +166 -0
- package/dist/core/values/pose.d.ts +31 -0
- package/dist/core/values/pose.js +83 -0
- package/dist/core/values/range.d.ts +83 -0
- package/dist/core/values/range.js +167 -0
- package/dist/core/values/str.d.ts +76 -0
- package/dist/core/values/str.js +346 -0
- package/dist/core/values/template.d.ts +49 -0
- package/dist/core/values/template.js +148 -0
- package/dist/core/values/transform.d.ts +49 -0
- package/dist/core/values/transform.js +115 -0
- package/dist/core/values/tri.d.ts +31 -0
- package/dist/core/values/tri.js +95 -0
- package/dist/core/values/vec.d.ts +72 -0
- package/dist/core/values/vec.js +219 -0
- package/dist/core/writable.d.ts +15 -0
- package/dist/core/writable.js +29 -0
- package/dist/ext/events.d.ts +10 -0
- package/dist/ext/events.js +31 -0
- package/dist/ext/index.d.ts +4 -0
- package/dist/ext/index.js +4 -0
- package/dist/ext/snapshot.d.ts +8 -0
- package/dist/ext/snapshot.js +29 -0
- package/dist/ext/timeline.d.ts +56 -0
- package/dist/ext/timeline.js +94 -0
- package/dist/ext/waapi.d.ts +25 -0
- package/dist/ext/waapi.js +198 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/propagators/index.d.ts +6 -0
- package/dist/propagators/index.js +6 -0
- package/dist/propagators/layout.d.ts +68 -0
- package/dist/propagators/layout.js +336 -0
- package/dist/propagators/network.d.ts +52 -0
- package/dist/propagators/network.js +185 -0
- package/dist/propagators/propagator.d.ts +12 -0
- package/dist/propagators/propagator.js +16 -0
- package/dist/propagators/range.d.ts +45 -0
- package/dist/propagators/range.js +147 -0
- package/dist/propagators/relations.d.ts +60 -0
- package/dist/propagators/relations.js +343 -0
- package/dist/shapes/annular-sector.d.ts +15 -0
- package/dist/shapes/annular-sector.js +64 -0
- package/dist/shapes/button.d.ts +14 -0
- package/dist/shapes/button.js +31 -0
- package/dist/shapes/choreographers.d.ts +22 -0
- package/dist/shapes/choreographers.js +69 -0
- package/dist/shapes/circle.d.ts +17 -0
- package/dist/shapes/circle.js +57 -0
- package/dist/shapes/clip.d.ts +5 -0
- package/dist/shapes/clip.js +31 -0
- package/dist/shapes/connect.d.ts +16 -0
- package/dist/shapes/connect.js +70 -0
- package/dist/shapes/curve.d.ts +60 -0
- package/dist/shapes/curve.js +285 -0
- package/dist/shapes/dashed.d.ts +16 -0
- package/dist/shapes/dashed.js +142 -0
- package/dist/shapes/debug.d.ts +43 -0
- package/dist/shapes/debug.js +97 -0
- package/dist/shapes/group.d.ts +5 -0
- package/dist/shapes/group.js +10 -0
- package/dist/shapes/handle.d.ts +32 -0
- package/dist/shapes/handle.js +88 -0
- package/dist/shapes/index.d.ts +23 -0
- package/dist/shapes/index.js +23 -0
- package/dist/shapes/interaction.d.ts +32 -0
- package/dist/shapes/interaction.js +187 -0
- package/dist/shapes/label.d.ts +20 -0
- package/dist/shapes/label.js +42 -0
- package/dist/shapes/layout.d.ts +29 -0
- package/dist/shapes/layout.js +74 -0
- package/dist/shapes/line.d.ts +21 -0
- package/dist/shapes/line.js +79 -0
- package/dist/shapes/list.d.ts +18 -0
- package/dist/shapes/list.js +51 -0
- package/dist/shapes/mount.d.ts +7 -0
- package/dist/shapes/mount.js +10 -0
- package/dist/shapes/path.d.ts +77 -0
- package/dist/shapes/path.js +227 -0
- package/dist/shapes/rect.d.ts +30 -0
- package/dist/shapes/rect.js +131 -0
- package/dist/shapes/shape.d.ts +132 -0
- package/dist/shapes/shape.js +306 -0
- package/dist/shapes/text.d.ts +24 -0
- package/dist/shapes/text.js +53 -0
- package/dist/shapes/tokens.d.ts +28 -0
- package/dist/shapes/tokens.js +27 -0
- package/dist/shapes/transitions.d.ts +23 -0
- package/dist/shapes/transitions.js +62 -0
- package/dist/tex/decorations.d.ts +26 -0
- package/dist/tex/decorations.js +116 -0
- package/dist/tex/index.d.ts +5 -0
- package/dist/tex/index.js +5 -0
- package/dist/tex/marker.d.ts +17 -0
- package/dist/tex/marker.js +63 -0
- package/dist/tex/motion.d.ts +43 -0
- package/dist/tex/motion.js +290 -0
- package/dist/tex/parts.d.ts +65 -0
- package/dist/tex/parts.js +149 -0
- package/dist/tex/tex.d.ts +45 -0
- package/dist/tex/tex.js +244 -0
- package/dist/web/attr.d.ts +16 -0
- package/dist/web/attr.js +98 -0
- package/dist/web/diagram.d.ts +49 -0
- package/dist/web/diagram.js +260 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +6 -0
- package/dist/web/md-marker.d.ts +6 -0
- package/dist/web/md-marker.js +39 -0
- package/dist/web/md-tex.d.ts +6 -0
- package/dist/web/md-tex.js +61 -0
- package/dist/web/raf.d.ts +6 -0
- package/dist/web/raf.js +24 -0
- package/dist/web/viewport.d.ts +7 -0
- package/dist/web/viewport.js +13 -0
- package/package.json +87 -0
package/dist/tex/tex.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// LaTeX → MathML shape, rendered via Temml.
|
|
2
|
+
import { Box, cell, derive } from "../core/index.js";
|
|
3
|
+
import { Shape, tokens } from "../shapes/index.js";
|
|
4
|
+
import temml from "temml";
|
|
5
|
+
import { Part, PartMarker } from "./parts.js";
|
|
6
|
+
/** Class on the rendered `<mrow>`, to re-find Parts in cloned subtrees. */
|
|
7
|
+
const partClass = (name) => `bireactive-part-${name}`;
|
|
8
|
+
/** Build LaTeX source + PartMarker list. Reads `strings.raw` so authors
|
|
9
|
+
* write single-backslash LaTeX without JS eating `\f`, `\t`, etc. */
|
|
10
|
+
const compileTemplate = (strings, values) => {
|
|
11
|
+
const chunks = strings.raw ?? strings;
|
|
12
|
+
let source = "";
|
|
13
|
+
const markers = [];
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
16
|
+
source += chunks[i];
|
|
17
|
+
if (i >= values.length)
|
|
18
|
+
continue;
|
|
19
|
+
const v = values[i];
|
|
20
|
+
if (v instanceof PartMarker) {
|
|
21
|
+
if (seen.has(v.name)) {
|
|
22
|
+
throw new Error(`tex: duplicate part name "${v.name}" — names must be unique within a single template`);
|
|
23
|
+
}
|
|
24
|
+
seen.add(v.name);
|
|
25
|
+
markers.push(v);
|
|
26
|
+
source += `\\class{${partClass(v.name)}}{${v.content.peek()}}`;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
source += v;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return { source, markers };
|
|
33
|
+
};
|
|
34
|
+
/** Render LaTeX → MathML via Temml (trust on, lenient errors). */
|
|
35
|
+
export const renderToMathML = (source, opts = {}) => {
|
|
36
|
+
try {
|
|
37
|
+
return temml.renderToString(source, {
|
|
38
|
+
trust: true,
|
|
39
|
+
displayMode: opts.displayMode ?? false,
|
|
40
|
+
strict: false,
|
|
41
|
+
throwOnError: false,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return `<span style="color:#c33;font:13px monospace">${e.message}</span>`;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/** Wrapper CSS — identical for the measurement div and the live
|
|
49
|
+
* foreignObject child, so measured and live offsets agree. */
|
|
50
|
+
const wrapperCss = (fontSize, fontFamily) => [
|
|
51
|
+
`font-family:${fontFamily}`,
|
|
52
|
+
`font-size:${fontSize}px`,
|
|
53
|
+
`color:${tokens.stroke}`,
|
|
54
|
+
"line-height:1",
|
|
55
|
+
"white-space:nowrap",
|
|
56
|
+
"padding:0",
|
|
57
|
+
"margin:0",
|
|
58
|
+
"display:inline-block",
|
|
59
|
+
].join(";");
|
|
60
|
+
/** Font styles must live on `<math>` itself: MathML doesn't reliably
|
|
61
|
+
* inherit `font-family`, and surd/vinculum thickness comes from the
|
|
62
|
+
* font's OpenType MATH table. Never set `display` (MathML Core only
|
|
63
|
+
* honors `inline math` / `block math`). */
|
|
64
|
+
const styleMathRoot = (mathEl, fontSize, fontFamily) => {
|
|
65
|
+
mathEl.style.fontFamily = fontFamily;
|
|
66
|
+
mathEl.style.fontSize = `${fontSize}px`;
|
|
67
|
+
mathEl.style.color = tokens.stroke;
|
|
68
|
+
mathEl.style.lineHeight = "1";
|
|
69
|
+
mathEl.style.fontStyle = "normal";
|
|
70
|
+
mathEl.style.fontWeight = "normal";
|
|
71
|
+
};
|
|
72
|
+
/** Force a part's layout to be context-independent so a matched mrow
|
|
73
|
+
* renders the same regardless of ambient context — morph rides it with
|
|
74
|
+
* one scale factor, no pop. Overrides the `compact` style `<msqrt>` /
|
|
75
|
+
* `<mfrac>` cascade; inherited, so propagates to descendants. */
|
|
76
|
+
const stabilizePart = (el) => {
|
|
77
|
+
el.style.setProperty("math-shift", "normal");
|
|
78
|
+
el.style.setProperty("math-style", "normal");
|
|
79
|
+
el.style.borderRadius = `${tokens.tex.highlightCorner}px`;
|
|
80
|
+
el.style.transition = `background-color ${tokens.tex.highlightDurationMs}ms ease-out`;
|
|
81
|
+
};
|
|
82
|
+
const measureMathML = (mathml, fontSize, fontFamily) => {
|
|
83
|
+
const div = document.createElement("div");
|
|
84
|
+
div.style.cssText = `position:absolute;left:-99999px;top:0;visibility:hidden;${wrapperCss(fontSize, fontFamily)}`;
|
|
85
|
+
div.innerHTML = mathml;
|
|
86
|
+
const mathEl = div.querySelector("math");
|
|
87
|
+
if (mathEl)
|
|
88
|
+
styleMathRoot(mathEl, fontSize, fontFamily);
|
|
89
|
+
div.querySelectorAll("[class*='bireactive-part-']").forEach(stabilizePart);
|
|
90
|
+
document.body.appendChild(div);
|
|
91
|
+
try {
|
|
92
|
+
const root = mathEl ?? div.firstElementChild ?? div;
|
|
93
|
+
const rootRect = root.getBoundingClientRect();
|
|
94
|
+
// Anchor part rects to the wrapper, not `<math>`: `<mfrac>` can
|
|
95
|
+
// overflow its line-box upward, throwing off math-relative bounds.
|
|
96
|
+
const wrapperRect = div.getBoundingClientRect();
|
|
97
|
+
const rects = new Map();
|
|
98
|
+
div.querySelectorAll("[class*='bireactive-part-']").forEach(el => {
|
|
99
|
+
const cls = Array.from(el.classList).find(c => c.startsWith("bireactive-part-"));
|
|
100
|
+
if (!cls)
|
|
101
|
+
return;
|
|
102
|
+
const r = el.getBoundingClientRect();
|
|
103
|
+
rects.set(cls, {
|
|
104
|
+
x: r.left - wrapperRect.left,
|
|
105
|
+
y: r.top - wrapperRect.top,
|
|
106
|
+
w: r.width,
|
|
107
|
+
h: r.height,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
return { width: rootRect.width, height: rootRect.height, rects };
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
document.body.removeChild(div);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/** A LaTeX-rendered shape with addressable Parts. See `tex` (factory)
|
|
117
|
+
* and `parts.ts` (Part / PartMarker). */
|
|
118
|
+
export class TexShape extends Shape {
|
|
119
|
+
parts;
|
|
120
|
+
/** Width in local-frame user units (the rendered MathML bounding rect). */
|
|
121
|
+
width;
|
|
122
|
+
/** Height in local-frame user units. */
|
|
123
|
+
height;
|
|
124
|
+
constructor(strings, values, opts = {}) {
|
|
125
|
+
const fontSize = opts.size ?? tokens.tex.size;
|
|
126
|
+
const fontFamily = opts.font ?? tokens.mathFont;
|
|
127
|
+
const highlightColor = opts.highlightColor ?? tokens.tex.highlightColor;
|
|
128
|
+
const displayMode = opts.display === "block";
|
|
129
|
+
const { source, markers } = compileTemplate(strings, values);
|
|
130
|
+
const initialMathml = renderToMathML(source, { displayMode });
|
|
131
|
+
const measured = measureMathML(initialMathml, fontSize, fontFamily);
|
|
132
|
+
const w = cell(measured.width);
|
|
133
|
+
const h = cell(measured.height);
|
|
134
|
+
super("foreignObject", () => ({ x: 0, y: 0, w: w.value, h: h.value }), opts, {
|
|
135
|
+
origin: derive(() => ({ x: w.value / 2, y: h.value / 2 })),
|
|
136
|
+
});
|
|
137
|
+
this.width = w;
|
|
138
|
+
this.height = h;
|
|
139
|
+
const fo = this.intrinsic;
|
|
140
|
+
fo.setAttribute("x", "0");
|
|
141
|
+
fo.setAttribute("y", "0");
|
|
142
|
+
fo.style.overflow = "visible";
|
|
143
|
+
this.attrs({ width: w, height: h });
|
|
144
|
+
// Inline-block wrapper, same CSS as the measurement div.
|
|
145
|
+
const wrapper = document.createElement("div");
|
|
146
|
+
wrapper.style.cssText = wrapperCss(fontSize, fontFamily);
|
|
147
|
+
fo.appendChild(wrapper);
|
|
148
|
+
// Parts built up front; `mountInto` populates the wrapper and binds
|
|
149
|
+
// each. `boxWriters` holds the writable bounds for re-measure.
|
|
150
|
+
const list = [];
|
|
151
|
+
const boxWriters = new Map();
|
|
152
|
+
for (const m of markers) {
|
|
153
|
+
const cls = partClass(m.name);
|
|
154
|
+
const boxSig = new Box(measured.rects.get(cls) ?? { x: 0, y: 0, w: 0, h: 0 });
|
|
155
|
+
boxWriters.set(cls, boxSig);
|
|
156
|
+
list.push(new Part(m.name, m.content, boxSig, m, this));
|
|
157
|
+
}
|
|
158
|
+
this.parts = buildPartList(list);
|
|
159
|
+
/** Render into the wrapper, push fresh bounds, rebind parts.
|
|
160
|
+
* `bounds` lets the initial mount skip re-measuring. */
|
|
161
|
+
const mountInto = (mathml, bounds) => {
|
|
162
|
+
wrapper.innerHTML = mathml;
|
|
163
|
+
const m = wrapper.querySelector("math");
|
|
164
|
+
if (m)
|
|
165
|
+
styleMathRoot(m, fontSize, fontFamily);
|
|
166
|
+
wrapper.querySelectorAll("[class*='bireactive-part-']").forEach(stabilizePart);
|
|
167
|
+
const fresh = bounds ?? measureMathML(mathml, fontSize, fontFamily);
|
|
168
|
+
if (fresh.width !== w.peek())
|
|
169
|
+
w.value = fresh.width;
|
|
170
|
+
if (fresh.height !== h.peek())
|
|
171
|
+
h.value = fresh.height;
|
|
172
|
+
for (const p of list) {
|
|
173
|
+
const cls = partClass(p.name);
|
|
174
|
+
const r = fresh.rects.get(cls);
|
|
175
|
+
const sig = boxWriters.get(cls);
|
|
176
|
+
if (r && sig) {
|
|
177
|
+
const cur = sig.peek();
|
|
178
|
+
if (r.x !== cur.x || r.y !== cur.y || r.w !== cur.w || r.h !== cur.h)
|
|
179
|
+
sig.value = r;
|
|
180
|
+
}
|
|
181
|
+
p.bind(wrapper.querySelector(`.${cls}`), highlightColor);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
mountInto(initialMathml, measured);
|
|
185
|
+
let firstRun = true;
|
|
186
|
+
this.effect(() => {
|
|
187
|
+
for (const m of markers)
|
|
188
|
+
void m.content.value; // track
|
|
189
|
+
if (firstRun) {
|
|
190
|
+
firstRun = false;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const next = compileTemplate(strings, values);
|
|
194
|
+
mountInto(renderToMathML(next.source, { displayMode }));
|
|
195
|
+
});
|
|
196
|
+
// Re-measure once webfonts load: synchronous measurement uses
|
|
197
|
+
// fallback metrics until the CDN font arrives, else first morph pops.
|
|
198
|
+
const fonts = document.fonts;
|
|
199
|
+
if (fonts?.ready) {
|
|
200
|
+
void fonts.ready.then(() => {
|
|
201
|
+
const cur = compileTemplate(strings, values);
|
|
202
|
+
const fresh = measureMathML(renderToMathML(cur.source, { displayMode }), fontSize, fontFamily);
|
|
203
|
+
if (fresh.width !== w.peek())
|
|
204
|
+
w.value = fresh.width;
|
|
205
|
+
if (fresh.height !== h.peek())
|
|
206
|
+
h.value = fresh.height;
|
|
207
|
+
for (const [cls, sig] of boxWriters) {
|
|
208
|
+
const r = fresh.rects.get(cls);
|
|
209
|
+
if (!r)
|
|
210
|
+
continue;
|
|
211
|
+
const c = sig.peek();
|
|
212
|
+
if (r.x !== c.x || r.y !== c.y || r.w !== c.w || r.h !== c.h)
|
|
213
|
+
sig.value = r;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
this.track(() => {
|
|
218
|
+
for (const p of list)
|
|
219
|
+
p.dispose();
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/** Sugar: `eq.highlight("a")` → `eq.parts.a.highlighted.value = true`. */
|
|
223
|
+
highlight(name, on = true) {
|
|
224
|
+
const p = this.parts[name];
|
|
225
|
+
if (p)
|
|
226
|
+
p.highlighted.value = on;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** Positional array with named keys: template-order iteration, name-indexable. */
|
|
230
|
+
const buildPartList = (list) => {
|
|
231
|
+
const out = list.slice();
|
|
232
|
+
for (const p of list)
|
|
233
|
+
out[p.name] = p;
|
|
234
|
+
return out;
|
|
235
|
+
};
|
|
236
|
+
const isTemplateStrings = (v) => Array.isArray(v) && Object.prototype.hasOwnProperty.call(v, "raw");
|
|
237
|
+
export function tex(...args) {
|
|
238
|
+
if (isTemplateStrings(args[0])) {
|
|
239
|
+
const [strings, ...values] = args;
|
|
240
|
+
return new TexShape(strings, values);
|
|
241
|
+
}
|
|
242
|
+
const opts = typeof args[0] === "number" ? { size: args[0] } : args[0];
|
|
243
|
+
return (strings, ...values) => new TexShape(strings, values, opts);
|
|
244
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare function str(): PropertyDecorator;
|
|
2
|
+
declare function str(default_: string): PropertyDecorator;
|
|
3
|
+
declare function num(): PropertyDecorator;
|
|
4
|
+
declare function num(default_: number): PropertyDecorator;
|
|
5
|
+
declare function bool(): PropertyDecorator;
|
|
6
|
+
declare function bool(default_: boolean): PropertyDecorator;
|
|
7
|
+
export declare const attr: {
|
|
8
|
+
str: typeof str;
|
|
9
|
+
num: typeof num;
|
|
10
|
+
bool: typeof bool;
|
|
11
|
+
};
|
|
12
|
+
/** Collect `_attributes` up the prototype chain (subclasses see parent decls). */
|
|
13
|
+
export declare function observedAttributesOf(ctor: Function): string[];
|
|
14
|
+
/** Push a coerced HTML-attribute value into its signal (lazy-creating it). */
|
|
15
|
+
export declare function syncAttrSignal(instance: HTMLElement, name: string, raw: string | null): void;
|
|
16
|
+
export {};
|
package/dist/web/attr.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// HTML attributes mapped to reactive signals on a custom element. The
|
|
2
|
+
// decorated field IS the signal.
|
|
3
|
+
//
|
|
4
|
+
// @attr.str() declare width: Cell<string | undefined>;
|
|
5
|
+
// @attr.str("a") declare mode: Cell<string>; // default "a"
|
|
6
|
+
// @attr.num(4) declare cells: Cell<number>; // default 4
|
|
7
|
+
// @attr.bool() declare flag: Cell<boolean>; // default false
|
|
8
|
+
import { cell } from "../core/index.js";
|
|
9
|
+
const SIGNALS = Symbol("attrSignals");
|
|
10
|
+
function coerce(raw, type, default_) {
|
|
11
|
+
if (type === "boolean") {
|
|
12
|
+
if (raw !== null)
|
|
13
|
+
return true;
|
|
14
|
+
return default_ === undefined ? false : default_;
|
|
15
|
+
}
|
|
16
|
+
if (type === "number") {
|
|
17
|
+
return raw === null ? default_ : Number(raw);
|
|
18
|
+
}
|
|
19
|
+
return raw === null ? default_ : raw;
|
|
20
|
+
}
|
|
21
|
+
function bagOf(instance) {
|
|
22
|
+
const carrier = instance;
|
|
23
|
+
let bag = carrier[SIGNALS];
|
|
24
|
+
if (!bag) {
|
|
25
|
+
bag = new Map();
|
|
26
|
+
carrier[SIGNALS] = bag;
|
|
27
|
+
}
|
|
28
|
+
return bag;
|
|
29
|
+
}
|
|
30
|
+
function register(target, propertyKey, type, default_) {
|
|
31
|
+
const ctor = target.constructor;
|
|
32
|
+
if (!ctor._attributes)
|
|
33
|
+
ctor._attributes = [];
|
|
34
|
+
if (!ctor._attributes.includes(propertyKey))
|
|
35
|
+
ctor._attributes.push(propertyKey);
|
|
36
|
+
if (!ctor._attrTypes)
|
|
37
|
+
ctor._attrTypes = {};
|
|
38
|
+
ctor._attrTypes[propertyKey] = type;
|
|
39
|
+
if (default_ !== undefined) {
|
|
40
|
+
if (!ctor._attrDefaults)
|
|
41
|
+
ctor._attrDefaults = {};
|
|
42
|
+
ctor._attrDefaults[propertyKey] = default_;
|
|
43
|
+
}
|
|
44
|
+
Object.defineProperty(target, propertyKey, {
|
|
45
|
+
get() {
|
|
46
|
+
const bag = bagOf(this);
|
|
47
|
+
let sig = bag.get(propertyKey);
|
|
48
|
+
if (!sig) {
|
|
49
|
+
sig = cell(coerce(this.getAttribute(propertyKey), type, default_));
|
|
50
|
+
bag.set(propertyKey, sig);
|
|
51
|
+
}
|
|
52
|
+
return sig;
|
|
53
|
+
},
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function str(default_) {
|
|
59
|
+
return (target, key) => register(target, key, "string", default_);
|
|
60
|
+
}
|
|
61
|
+
function num(default_) {
|
|
62
|
+
return (target, key) => register(target, key, "number", default_);
|
|
63
|
+
}
|
|
64
|
+
function bool(default_) {
|
|
65
|
+
return (target, key) => register(target, key, "boolean", default_);
|
|
66
|
+
}
|
|
67
|
+
export const attr = { str, num, bool };
|
|
68
|
+
/** Collect `_attributes` up the prototype chain (subclasses see parent decls). */
|
|
69
|
+
export function observedAttributesOf(ctor) {
|
|
70
|
+
const acc = [];
|
|
71
|
+
let c = ctor;
|
|
72
|
+
while (c && c !== HTMLElement && c !== Object) {
|
|
73
|
+
if (Object.prototype.hasOwnProperty.call(c, "_attributes") && c._attributes) {
|
|
74
|
+
for (const a of c._attributes)
|
|
75
|
+
if (!acc.includes(a))
|
|
76
|
+
acc.push(a);
|
|
77
|
+
}
|
|
78
|
+
c = Object.getPrototypeOf(c);
|
|
79
|
+
}
|
|
80
|
+
return acc;
|
|
81
|
+
}
|
|
82
|
+
/** Push a coerced HTML-attribute value into its signal (lazy-creating it). */
|
|
83
|
+
export function syncAttrSignal(instance, name, raw) {
|
|
84
|
+
const ctor = instance.constructor;
|
|
85
|
+
const type = ctor._attrTypes?.[name];
|
|
86
|
+
if (!type)
|
|
87
|
+
return;
|
|
88
|
+
const default_ = ctor._attrDefaults?.[name];
|
|
89
|
+
const bag = bagOf(instance);
|
|
90
|
+
const next = coerce(raw, type, default_);
|
|
91
|
+
const sig = bag.get(name);
|
|
92
|
+
if (sig) {
|
|
93
|
+
sig.value = next;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
bag.set(name, cell(next));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Anim } from "../animation/index.js";
|
|
2
|
+
import { Box, type Val } from "../core/index.js";
|
|
3
|
+
import { type Mount, Shape } from "../shapes/index.js";
|
|
4
|
+
import type { Marker } from "../tex/index.js";
|
|
5
|
+
export declare const css: (template: {
|
|
6
|
+
raw: readonly string[] | ArrayLike<string>;
|
|
7
|
+
}, ...substitutions: any[]) => string;
|
|
8
|
+
export type Padding = number | {
|
|
9
|
+
top?: number;
|
|
10
|
+
right?: number;
|
|
11
|
+
bottom?: number;
|
|
12
|
+
left?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class Diagram extends HTMLElement {
|
|
15
|
+
#private;
|
|
16
|
+
static get observedAttributes(): string[];
|
|
17
|
+
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
18
|
+
protected shadow: ShadowRoot;
|
|
19
|
+
protected anim: Anim;
|
|
20
|
+
protected svg: SVGSVGElement;
|
|
21
|
+
/** Scene-graph root. All user-mounted shapes are children of this. */
|
|
22
|
+
protected root: Shape;
|
|
23
|
+
/** Callable mount handle for `scene(s)`; `s(shape)` adds to root. */
|
|
24
|
+
protected s: Mount;
|
|
25
|
+
/** Register a marker for this instance; call in `scene()` so
|
|
26
|
+
* `<… for="this-id">` can resolve it. */
|
|
27
|
+
registerMarker(id: string, m: Marker): void;
|
|
28
|
+
/** Look up a marker registered on this instance. */
|
|
29
|
+
getMarker(id: string): Marker | undefined;
|
|
30
|
+
private static styleSheets;
|
|
31
|
+
static styles: string;
|
|
32
|
+
constructor();
|
|
33
|
+
/** Build the scene graph. Runs once per connect; override in subclasses. */
|
|
34
|
+
protected scene(_s: Mount): void;
|
|
35
|
+
connectedCallback(): void;
|
|
36
|
+
disconnectedCallback(): void;
|
|
37
|
+
/** Set the viewBox to `(0, 0, w, h)` (reactive inputs). First call
|
|
38
|
+
* wins; returns a reactive `Box` for layout. */
|
|
39
|
+
view(w: Val<number>, h: Val<number>): Box;
|
|
40
|
+
/** Fit viewBox to the root's bounds + padding (auto-called after
|
|
41
|
+
* `scene()` if `view()` wasn't). */
|
|
42
|
+
fit(padding?: Padding): Box;
|
|
43
|
+
static get tagName(): string;
|
|
44
|
+
static define(): void;
|
|
45
|
+
private setViewBox;
|
|
46
|
+
private mountSvg;
|
|
47
|
+
/** Combine base + subclass styles. Cached per subclass. */
|
|
48
|
+
private initializeStyles;
|
|
49
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// Custom-element scaffold. Subclasses override `scene(s)`; signals drive
|
|
2
|
+
// updates. Owns the SVG, the viewBox (`view`/`fit`), and host CSS sizing
|
|
3
|
+
// (`--d-w`/`--d-h`).
|
|
4
|
+
//
|
|
5
|
+
// Visibility-gated rAF: the per-instance Anim ticks only while near the
|
|
6
|
+
// viewport (IntersectionObserver). Cell-driven updates keep working —
|
|
7
|
+
// only the animator clock pauses and resumes, so `anim.clock` tracks
|
|
8
|
+
// on-screen time. Opt out via `always-animate`; eager-attach when
|
|
9
|
+
// IntersectionObserver is absent (SSR/tests).
|
|
10
|
+
var _a;
|
|
11
|
+
import { Anim } from "../animation/index.js";
|
|
12
|
+
import { Box, effect, Num } from "../core/index.js";
|
|
13
|
+
import { ensureArrowMarker, mount, Shape, SVG_NS } from "../shapes/index.js";
|
|
14
|
+
import { observedAttributesOf, syncAttrSignal } from "./attr.js";
|
|
15
|
+
import { attachRaf } from "./raf.js";
|
|
16
|
+
export const css = String.raw;
|
|
17
|
+
function resolvePadding(p) {
|
|
18
|
+
if (p === undefined || p === 0)
|
|
19
|
+
return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
20
|
+
if (typeof p === "number")
|
|
21
|
+
return { top: p, right: p, bottom: p, left: p };
|
|
22
|
+
return {
|
|
23
|
+
top: p.top ?? 0,
|
|
24
|
+
right: p.right ?? 0,
|
|
25
|
+
bottom: p.bottom ?? 0,
|
|
26
|
+
left: p.left ?? 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export class Diagram extends HTMLElement {
|
|
30
|
+
static get observedAttributes() {
|
|
31
|
+
return observedAttributesOf(this);
|
|
32
|
+
}
|
|
33
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
34
|
+
if (oldVal === newVal)
|
|
35
|
+
return;
|
|
36
|
+
syncAttrSignal(this, name, newVal);
|
|
37
|
+
}
|
|
38
|
+
shadow;
|
|
39
|
+
anim = new Anim();
|
|
40
|
+
#detachRaf = null;
|
|
41
|
+
#io = null;
|
|
42
|
+
svg;
|
|
43
|
+
/** Scene-graph root. All user-mounted shapes are children of this. */
|
|
44
|
+
root;
|
|
45
|
+
/** Callable mount handle for `scene(s)`; `s(shape)` adds to root. */
|
|
46
|
+
s;
|
|
47
|
+
// Per-instance marker registry; recleared each connectedCallback so
|
|
48
|
+
// `<md-tex for="id">` always sees fresh markers.
|
|
49
|
+
#markers = new Map();
|
|
50
|
+
/** Register a marker for this instance; call in `scene()` so
|
|
51
|
+
* `<… for="this-id">` can resolve it. */
|
|
52
|
+
registerMarker(id, m) {
|
|
53
|
+
this.#markers.set(id, m);
|
|
54
|
+
}
|
|
55
|
+
/** Look up a marker registered on this instance. */
|
|
56
|
+
getMarker(id) {
|
|
57
|
+
return this.#markers.get(id);
|
|
58
|
+
}
|
|
59
|
+
// `#viewSet` flips on the first `view()`/`fit()`; `connectedCallback`
|
|
60
|
+
// auto-fits if still false.
|
|
61
|
+
#viewSet = false;
|
|
62
|
+
#viewSig = signal0Box();
|
|
63
|
+
#viewBox = Box.derive(() => this.#viewSig.value);
|
|
64
|
+
static styleSheets = new Map();
|
|
65
|
+
static styles = css `
|
|
66
|
+
:host {
|
|
67
|
+
display: block;
|
|
68
|
+
margin: 1rem auto;
|
|
69
|
+
width: 100%;
|
|
70
|
+
max-width: calc(var(--d-w, 600) * 1px);
|
|
71
|
+
}
|
|
72
|
+
svg {
|
|
73
|
+
display: block;
|
|
74
|
+
width: 100%;
|
|
75
|
+
height: auto;
|
|
76
|
+
overflow: visible;
|
|
77
|
+
}
|
|
78
|
+
::slotted(details.diagram-source) {
|
|
79
|
+
margin-top: 0.5rem;
|
|
80
|
+
font-size: 0.85em;
|
|
81
|
+
/* Wide enough for code on desktop, but never wider than the
|
|
82
|
+
column — a fixed 90ch overflowed narrow viewports and gave the
|
|
83
|
+
page a horizontal scroll. */
|
|
84
|
+
min-width: min(90ch, 100%);
|
|
85
|
+
max-width: 100%;
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
margin: 0 auto;
|
|
88
|
+
color: var(--text-secondary, #888);
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
constructor() {
|
|
92
|
+
super();
|
|
93
|
+
this.shadow = this.attachShadow({ mode: "open" });
|
|
94
|
+
this.initializeStyles();
|
|
95
|
+
}
|
|
96
|
+
/** Build the scene graph. Runs once per connect; override in subclasses. */
|
|
97
|
+
scene(_s) { }
|
|
98
|
+
connectedCallback() {
|
|
99
|
+
if (!this.svg)
|
|
100
|
+
this.mountSvg();
|
|
101
|
+
this.#detachRaf?.();
|
|
102
|
+
this.#io?.disconnect();
|
|
103
|
+
this.#io = null;
|
|
104
|
+
this.anim.stop();
|
|
105
|
+
this.root?.dispose();
|
|
106
|
+
this.#viewSet = false;
|
|
107
|
+
this.#markers.clear();
|
|
108
|
+
this.root = new Shape();
|
|
109
|
+
this.svg.replaceChildren(this.root.el);
|
|
110
|
+
ensureArrowMarker(this.svg);
|
|
111
|
+
this.s = mount(this.root);
|
|
112
|
+
this.scene(this.s);
|
|
113
|
+
if (!this.#viewSet)
|
|
114
|
+
this.fit();
|
|
115
|
+
this.#ensureSourcePanel();
|
|
116
|
+
this.#startRaf();
|
|
117
|
+
}
|
|
118
|
+
disconnectedCallback() {
|
|
119
|
+
this.#detachRaf?.();
|
|
120
|
+
this.#detachRaf = null;
|
|
121
|
+
this.#io?.disconnect();
|
|
122
|
+
this.#io = null;
|
|
123
|
+
this.anim.stop();
|
|
124
|
+
this.root?.dispose();
|
|
125
|
+
}
|
|
126
|
+
// Gate rAF on viewport intersection; `rootMargin: "200px 0px"` warms
|
|
127
|
+
// the loop before visible so the first frame isn't a cold start.
|
|
128
|
+
#startRaf() {
|
|
129
|
+
if (this.hasAttribute("always-animate") || typeof IntersectionObserver === "undefined") {
|
|
130
|
+
this.#detachRaf = attachRaf(this.anim);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this.#io = new IntersectionObserver(entries => {
|
|
134
|
+
const inView = entries[entries.length - 1].isIntersecting;
|
|
135
|
+
if (inView && !this.#detachRaf)
|
|
136
|
+
this.#detachRaf = attachRaf(this.anim);
|
|
137
|
+
else if (!inView && this.#detachRaf) {
|
|
138
|
+
this.#detachRaf();
|
|
139
|
+
this.#detachRaf = null;
|
|
140
|
+
}
|
|
141
|
+
}, { rootMargin: "200px 0px" });
|
|
142
|
+
this.#io.observe(this);
|
|
143
|
+
}
|
|
144
|
+
/** Set the viewBox to `(0, 0, w, h)` (reactive inputs). First call
|
|
145
|
+
* wins; returns a reactive `Box` for layout. */
|
|
146
|
+
view(w, h) {
|
|
147
|
+
if (this.#viewSet)
|
|
148
|
+
return this.#viewBox;
|
|
149
|
+
const ws = Num.from(w);
|
|
150
|
+
const hs = Num.from(h);
|
|
151
|
+
effect(() => this.setViewBox(0, 0, ws.value, hs.value));
|
|
152
|
+
this.#viewSet = true;
|
|
153
|
+
return this.#viewBox;
|
|
154
|
+
}
|
|
155
|
+
/** Fit viewBox to the root's bounds + padding (auto-called after
|
|
156
|
+
* `scene()` if `view()` wasn't). */
|
|
157
|
+
fit(padding) {
|
|
158
|
+
if (this.#viewSet)
|
|
159
|
+
return this.#viewBox;
|
|
160
|
+
const p = resolvePadding(padding);
|
|
161
|
+
const b = this.root.box.value;
|
|
162
|
+
this.setViewBox(b.x - p.left, b.y - p.top, b.w + p.left + p.right, b.h + p.top + p.bottom);
|
|
163
|
+
this.#viewSet = true;
|
|
164
|
+
return this.#viewBox;
|
|
165
|
+
}
|
|
166
|
+
static get tagName() {
|
|
167
|
+
return this.name
|
|
168
|
+
.replace(/([A-Z])/g, "-$1")
|
|
169
|
+
.toLowerCase()
|
|
170
|
+
.slice(1);
|
|
171
|
+
}
|
|
172
|
+
static define() {
|
|
173
|
+
customElements.define(this.tagName, this);
|
|
174
|
+
}
|
|
175
|
+
setViewBox(x, y, w, h) {
|
|
176
|
+
this.#viewSig.value = { x, y, w, h };
|
|
177
|
+
this.svg.setAttribute("viewBox", `${x} ${y} ${w} ${h}`);
|
|
178
|
+
this.svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
179
|
+
this.svg.setAttribute("width", String(w));
|
|
180
|
+
this.svg.setAttribute("height", String(h));
|
|
181
|
+
// `:host` reads `--d-w` for max-width; override via `style="--d-w: N"`.
|
|
182
|
+
this.style.setProperty("--d-w", String(w));
|
|
183
|
+
this.style.setProperty("--d-h", String(h));
|
|
184
|
+
}
|
|
185
|
+
mountSvg() {
|
|
186
|
+
this.svg = document.createElementNS(SVG_NS, "svg");
|
|
187
|
+
this.shadow.appendChild(this.svg);
|
|
188
|
+
// Named slot projects the source panel without picking up incidental
|
|
189
|
+
// light-DOM children that use `textContent` as data, not display.
|
|
190
|
+
const slot = document.createElement("slot");
|
|
191
|
+
slot.name = "source";
|
|
192
|
+
this.shadow.appendChild(slot);
|
|
193
|
+
}
|
|
194
|
+
/** Append a `<details>` with the subclass's `scene()` source, projected
|
|
195
|
+
* through `slot[name=source]`. No-op for the base class / `[no-source]`
|
|
196
|
+
* / already-added. */
|
|
197
|
+
#ensureSourcePanel() {
|
|
198
|
+
if (this.hasAttribute("no-source"))
|
|
199
|
+
return;
|
|
200
|
+
if (this.querySelector(":scope > details[slot='source']"))
|
|
201
|
+
return;
|
|
202
|
+
const ctor = this.constructor;
|
|
203
|
+
if (ctor.prototype.scene === _a.prototype.scene)
|
|
204
|
+
return;
|
|
205
|
+
const src = dedent(this.scene.toString());
|
|
206
|
+
const details = document.createElement("details");
|
|
207
|
+
details.slot = "source";
|
|
208
|
+
details.className = "diagram-source";
|
|
209
|
+
const summary = document.createElement("summary");
|
|
210
|
+
summary.textContent = "source";
|
|
211
|
+
const code = document.createElement("md-syntax");
|
|
212
|
+
code.setAttribute("lang", "ts");
|
|
213
|
+
code.textContent = src;
|
|
214
|
+
details.append(summary, code);
|
|
215
|
+
// `md-syntax.paint()` reads `innerText`, empty while hidden in a
|
|
216
|
+
// closed `<details>` in some UAs; repaint on first open.
|
|
217
|
+
let painted = false;
|
|
218
|
+
details.addEventListener("toggle", () => {
|
|
219
|
+
if (details.open && !painted) {
|
|
220
|
+
code.update?.();
|
|
221
|
+
painted = true;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
this.appendChild(details);
|
|
225
|
+
}
|
|
226
|
+
/** Combine base + subclass styles. Cached per subclass. */
|
|
227
|
+
initializeStyles() {
|
|
228
|
+
const ctor = this.constructor;
|
|
229
|
+
const cacheKey = ctor.name;
|
|
230
|
+
if (!_a.styleSheets.has(cacheKey)) {
|
|
231
|
+
const baseStyles = _a.styles ?? "";
|
|
232
|
+
const ownStyles = ctor === _a ? "" : (ctor.styles ?? "");
|
|
233
|
+
const sheet = new CSSStyleSheet();
|
|
234
|
+
sheet.replaceSync(`${baseStyles}\n${ownStyles}`);
|
|
235
|
+
_a.styleSheets.set(cacheKey, sheet);
|
|
236
|
+
}
|
|
237
|
+
this.shadow.adoptedStyleSheets = [_a.styleSheets.get(cacheKey)];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
_a = Diagram;
|
|
241
|
+
// A fresh writable Box signal seeded with the zero box.
|
|
242
|
+
function signal0Box() {
|
|
243
|
+
return new Box({
|
|
244
|
+
x: 0,
|
|
245
|
+
y: 0,
|
|
246
|
+
w: 0,
|
|
247
|
+
h: 0,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
// Strip the common leading indent that `Function.prototype.toString()`
|
|
251
|
+
// leaves on a class method's body (line 0 has none).
|
|
252
|
+
function dedent(s) {
|
|
253
|
+
const lines = s.split("\n");
|
|
254
|
+
const indents = lines
|
|
255
|
+
.slice(1)
|
|
256
|
+
.filter(l => l.trim().length > 0)
|
|
257
|
+
.map(l => (l.match(/^ */) ?? [""])[0].length);
|
|
258
|
+
const min = indents.length ? Math.min(...indents) : 0;
|
|
259
|
+
return lines.map((l, i) => (i === 0 ? l : l.slice(min))).join("\n");
|
|
260
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { attr, observedAttributesOf, syncAttrSignal } from "./attr.js";
|
|
2
|
+
export { css, Diagram, type Padding } from "./diagram.js";
|
|
3
|
+
export { MdMarker } from "./md-marker.js";
|
|
4
|
+
export { MdTex } from "./md-tex.js";
|
|
5
|
+
export { attachRaf } from "./raf.js";
|
|
6
|
+
export { viewport } from "./viewport.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { attr, observedAttributesOf, syncAttrSignal } from "./attr.js";
|
|
2
|
+
export { css, Diagram } from "./diagram.js";
|
|
3
|
+
export { MdMarker } from "./md-marker.js";
|
|
4
|
+
export { MdTex } from "./md-tex.js";
|
|
5
|
+
export { attachRaf } from "./raf.js";
|
|
6
|
+
export { viewport } from "./viewport.js";
|