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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const tokens = {
|
|
2
|
+
/** CSS var so dark mode flips automatically. */
|
|
3
|
+
stroke: "var(--text-color)",
|
|
4
|
+
weight: 2,
|
|
5
|
+
thinWeight: 1.5,
|
|
6
|
+
corner: 2,
|
|
7
|
+
font: "'New CM', monospace",
|
|
8
|
+
/** Stack of fonts with OpenType MATH tables. */
|
|
9
|
+
mathFont: "'New CM Math', 'Cambria Math', 'STIXTwoMath-Regular', 'NotoSansMath-Regular', 'New CM', math, serif",
|
|
10
|
+
fontSize: 14,
|
|
11
|
+
/** Approximate glyph aspect (SVG can't measure). */
|
|
12
|
+
charWidth: 0.6,
|
|
13
|
+
subFontSize: "0.75em",
|
|
14
|
+
mutedOpacity: 0.5,
|
|
15
|
+
tex: {
|
|
16
|
+
size: 26,
|
|
17
|
+
highlightColor: "rgba(255, 220, 80, 0.45)",
|
|
18
|
+
highlightDurationMs: 120,
|
|
19
|
+
highlightCorner: 2,
|
|
20
|
+
},
|
|
21
|
+
decoration: {
|
|
22
|
+
gap: 2,
|
|
23
|
+
braceHeight: 5,
|
|
24
|
+
braceGap: 3,
|
|
25
|
+
crossGap: 1,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Easing, type Yieldable } from "../animation/index.js";
|
|
2
|
+
import { type Inner, type Val, type Vec } from "../core/index.js";
|
|
3
|
+
import type { Has } from "./shape.js";
|
|
4
|
+
/** Fade opacity 0 → 1. */
|
|
5
|
+
export declare const fadeIn: (s: Has<"opacity">, sec?: Val<number>, ease?: Easing) => Yieldable;
|
|
6
|
+
/** Fade opacity 1 → 0. */
|
|
7
|
+
export declare const fadeOut: (s: Has<"opacity">, sec?: Val<number>, ease?: Easing) => Yieldable;
|
|
8
|
+
/** Slide up from `dy` below + fade in. */
|
|
9
|
+
export declare function fadeUp(s: Has<"translate" | "opacity">, sec?: number, dy?: number): Yieldable;
|
|
10
|
+
/** Slide up + fade out. Mirror of `fadeUp`. */
|
|
11
|
+
export declare const fadeUpOut: (s: Has<"translate" | "opacity">, sec?: number, dy?: number) => Yieldable;
|
|
12
|
+
/** Slide in from `dir` + fade in. */
|
|
13
|
+
export declare function slideIn(s: Has<"translate" | "opacity">, dir?: Inner<Vec>, sec?: number, dist?: number): Yieldable;
|
|
14
|
+
/** Slide out toward a side + fade out. */
|
|
15
|
+
export declare const slideOut: (s: Has<"translate" | "opacity">, dir?: Inner<Vec>, sec?: number, dist?: number) => Yieldable;
|
|
16
|
+
/** Scale 0 → 1 + fade in. */
|
|
17
|
+
export declare function scaleIn(s: Has<"scale" | "opacity">, sec?: number): Yieldable;
|
|
18
|
+
/** Scale 1 → 0 + fade out. */
|
|
19
|
+
export declare const zoomOut: (s: Has<"scale" | "opacity">, sec?: number) => Yieldable;
|
|
20
|
+
/** Overshoot-and-settle scale + fade in. */
|
|
21
|
+
export declare function bounceIn(s: Has<"scale" | "opacity">, sec?: number): Yieldable;
|
|
22
|
+
/** Spin in: rotate -π → 0 + scale 0.5 → 1 + fade in. */
|
|
23
|
+
export declare function spinIn(s: Has<"rotate" | "scale" | "opacity">, sec?: number): Yieldable;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Bounded transitions. Initial pose is written synchronously; the return value
|
|
2
|
+
// is the time-varying part only — a `Tween` (single-axis) or `Yieldable[]`
|
|
3
|
+
// (multi-axis). Either way callers `yield transitionName(s)`.
|
|
4
|
+
import { easeIn, easeInOut, easeOut } from "../animation/index.js";
|
|
5
|
+
import { Dir, tween } from "../core/index.js";
|
|
6
|
+
/** Fade opacity 0 → 1. */
|
|
7
|
+
export const fadeIn = (s, sec = 0.3, ease = easeOut) => s.opacity.to(1, sec, ease).from(0);
|
|
8
|
+
/** Fade opacity 1 → 0. */
|
|
9
|
+
export const fadeOut = (s, sec = 0.3, ease = easeIn) => tween(s.opacity, 0, sec, ease);
|
|
10
|
+
/** Slide up from `dy` below + fade in. */
|
|
11
|
+
export function fadeUp(s, sec = 0.4, dy = 16) {
|
|
12
|
+
s.translate.value = { x: 0, y: dy };
|
|
13
|
+
s.opacity.value = 0;
|
|
14
|
+
return [tween(s.translate, { x: 0, y: 0 }, sec, easeOut), tween(s.opacity, 1, sec * 0.8)];
|
|
15
|
+
}
|
|
16
|
+
/** Slide up + fade out. Mirror of `fadeUp`. */
|
|
17
|
+
export const fadeUpOut = (s, sec = 0.3, dy = 16) => [
|
|
18
|
+
tween(s.translate, { x: 0, y: -dy }, sec, easeIn),
|
|
19
|
+
tween(s.opacity, 0, sec, easeIn),
|
|
20
|
+
];
|
|
21
|
+
/** Slide in from `dir` + fade in. */
|
|
22
|
+
export function slideIn(s, dir = Dir.Left, sec = 0.4, dist = 30) {
|
|
23
|
+
s.translate.value = { x: dir.x * dist, y: dir.y * dist };
|
|
24
|
+
s.opacity.value = 0;
|
|
25
|
+
return [tween(s.translate, { x: 0, y: 0 }, sec, easeOut), tween(s.opacity, 1, sec * 0.7)];
|
|
26
|
+
}
|
|
27
|
+
/** Slide out toward a side + fade out. */
|
|
28
|
+
export const slideOut = (s, dir = Dir.Right, sec = 0.3, dist = 30) => [
|
|
29
|
+
tween(s.translate, { x: dir.x * dist, y: dir.y * dist }, sec, easeIn),
|
|
30
|
+
tween(s.opacity, 0, sec, easeIn),
|
|
31
|
+
];
|
|
32
|
+
/** Scale 0 → 1 + fade in. */
|
|
33
|
+
export function scaleIn(s, sec = 0.3) {
|
|
34
|
+
s.scale.value = { x: 0, y: 0 };
|
|
35
|
+
s.opacity.value = 0;
|
|
36
|
+
return [tween(s.scale, { x: 1, y: 1 }, sec, easeOut), tween(s.opacity, 1, sec * 0.7)];
|
|
37
|
+
}
|
|
38
|
+
/** Scale 1 → 0 + fade out. */
|
|
39
|
+
export const zoomOut = (s, sec = 0.3) => [
|
|
40
|
+
tween(s.scale, { x: 0, y: 0 }, sec, easeIn),
|
|
41
|
+
tween(s.opacity, 0, sec, easeIn),
|
|
42
|
+
];
|
|
43
|
+
/** Overshoot-and-settle scale + fade in. */
|
|
44
|
+
export function bounceIn(s, sec = 0.5) {
|
|
45
|
+
s.scale.value = { x: 0, y: 0 };
|
|
46
|
+
s.opacity.value = 0;
|
|
47
|
+
return [
|
|
48
|
+
tween(s.opacity, 1, sec * 0.5),
|
|
49
|
+
s.scale.to({ x: 1.18, y: 1.18 }, sec * 0.7, easeOut).to({ x: 1, y: 1 }, sec * 0.3, easeInOut),
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
/** Spin in: rotate -π → 0 + scale 0.5 → 1 + fade in. */
|
|
53
|
+
export function spinIn(s, sec = 0.5) {
|
|
54
|
+
s.rotate.value = -Math.PI;
|
|
55
|
+
s.scale.value = { x: 0.5, y: 0.5 };
|
|
56
|
+
s.opacity.value = 0;
|
|
57
|
+
return [
|
|
58
|
+
tween(s.rotate, 0, sec, easeOut),
|
|
59
|
+
tween(s.scale, { x: 1, y: 1 }, sec, easeOut),
|
|
60
|
+
tween(s.opacity, 1, sec * 0.7),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Shape } from "../shapes/index.js";
|
|
2
|
+
import type { Part } from "./parts.js";
|
|
3
|
+
export interface DecorationOpts {
|
|
4
|
+
/** Stroke color. Default: `tokens.stroke`. */
|
|
5
|
+
stroke?: string;
|
|
6
|
+
/** Stroke width. Default: `tokens.thinWeight`. */
|
|
7
|
+
weight?: number;
|
|
8
|
+
/** Pad between the part's bounds and the decoration. Default per
|
|
9
|
+
* decoration (see `tokens.decoration`). */
|
|
10
|
+
gap?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Curly brace below (or above) a part. Reactive on `part.box`. */
|
|
13
|
+
export declare function brace(part: Part, opts?: DecorationOpts & {
|
|
14
|
+
/** "below" (default) or "above". */
|
|
15
|
+
placement?: "above" | "below";
|
|
16
|
+
/** Brace amplitude in local-frame units. */
|
|
17
|
+
height?: number;
|
|
18
|
+
}): Shape;
|
|
19
|
+
/** Rectangle around a part, inset by `gap`. (Not `box`: that factory exists.) */
|
|
20
|
+
export declare function frame(part: Part, opts?: DecorationOpts & {
|
|
21
|
+
corner?: number;
|
|
22
|
+
}): Shape;
|
|
23
|
+
/** Underline at the baseline of a part. */
|
|
24
|
+
export declare function underline(part: Part, opts?: DecorationOpts): Shape;
|
|
25
|
+
/** Diagonal strikethrough, bottom-left to top-right. */
|
|
26
|
+
export declare function cross(part: Part, opts?: DecorationOpts): Shape;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Derived shapes that decorate a tex Part (tracks `part.box` reactively).
|
|
2
|
+
import { derive } from "../core/index.js";
|
|
3
|
+
import { Shape, tokens } from "../shapes/index.js";
|
|
4
|
+
const applyStroke = (s, opts) => {
|
|
5
|
+
s.attrs({
|
|
6
|
+
stroke: opts.stroke ?? tokens.stroke,
|
|
7
|
+
"stroke-width": opts.weight ?? tokens.thinWeight,
|
|
8
|
+
"vector-effect": "non-scaling-stroke",
|
|
9
|
+
fill: "none",
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
/** A `<rect>` whose attrs and Box derive from one layout signal. */
|
|
13
|
+
function rectFromBox(layout) {
|
|
14
|
+
const s = new Shape("rect", () => layout.value);
|
|
15
|
+
s.attrs({
|
|
16
|
+
x: derive(() => layout.value.x),
|
|
17
|
+
y: derive(() => layout.value.y),
|
|
18
|
+
width: derive(() => layout.value.w),
|
|
19
|
+
height: derive(() => layout.value.h),
|
|
20
|
+
});
|
|
21
|
+
return s;
|
|
22
|
+
}
|
|
23
|
+
/** A `<line>` whose endpoints and Box derive from one layout signal. */
|
|
24
|
+
function lineFromEnds(layout) {
|
|
25
|
+
const s = new Shape("line", () => {
|
|
26
|
+
const e = layout.value;
|
|
27
|
+
const x = Math.min(e.x1, e.x2);
|
|
28
|
+
const y = Math.min(e.y1, e.y2);
|
|
29
|
+
return { x, y, w: Math.abs(e.x2 - e.x1), h: Math.abs(e.y2 - e.y1) };
|
|
30
|
+
});
|
|
31
|
+
s.attrs({
|
|
32
|
+
x1: derive(() => layout.value.x1),
|
|
33
|
+
y1: derive(() => layout.value.y1),
|
|
34
|
+
x2: derive(() => layout.value.x2),
|
|
35
|
+
y2: derive(() => layout.value.y2),
|
|
36
|
+
});
|
|
37
|
+
return s;
|
|
38
|
+
}
|
|
39
|
+
/** Curly brace below (or above) a part. Reactive on `part.box`. */
|
|
40
|
+
export function brace(part, opts = {}) {
|
|
41
|
+
const placement = opts.placement ?? "below";
|
|
42
|
+
const height = opts.height ?? tokens.decoration.braceHeight;
|
|
43
|
+
const gap = opts.gap ?? tokens.decoration.braceGap;
|
|
44
|
+
const d = derive(() => {
|
|
45
|
+
const b = part.box.value;
|
|
46
|
+
const x0 = b.x;
|
|
47
|
+
const x1 = b.x + b.w;
|
|
48
|
+
const baseY = placement === "below" ? b.y + b.h + gap : b.y - gap;
|
|
49
|
+
const dir = placement === "below" ? 1 : -1;
|
|
50
|
+
const tip = baseY + dir * height;
|
|
51
|
+
const mid = baseY + dir * (height / 2);
|
|
52
|
+
const cx = (x0 + x1) / 2;
|
|
53
|
+
const r = Math.min(height / 2, b.w / 4, 4);
|
|
54
|
+
return [
|
|
55
|
+
`M ${x0} ${baseY}`,
|
|
56
|
+
`Q ${x0} ${mid} ${x0 + r} ${mid}`,
|
|
57
|
+
`L ${cx - r} ${mid}`,
|
|
58
|
+
`Q ${cx} ${mid} ${cx} ${tip}`,
|
|
59
|
+
`Q ${cx} ${mid} ${cx + r} ${mid}`,
|
|
60
|
+
`L ${x1 - r} ${mid}`,
|
|
61
|
+
`Q ${x1} ${mid} ${x1} ${baseY}`,
|
|
62
|
+
].join(" ");
|
|
63
|
+
});
|
|
64
|
+
const s = new Shape("path", () => {
|
|
65
|
+
const b = part.box.value;
|
|
66
|
+
const baseY = placement === "below" ? b.y + b.h + gap : b.y - gap;
|
|
67
|
+
const tip = baseY + (placement === "below" ? height : -height);
|
|
68
|
+
return { x: b.x, y: Math.min(baseY, tip), w: b.w, h: Math.abs(tip - baseY) };
|
|
69
|
+
});
|
|
70
|
+
s.attrs({ d, "stroke-linecap": "round", "stroke-linejoin": "round" });
|
|
71
|
+
applyStroke(s, opts);
|
|
72
|
+
return s;
|
|
73
|
+
}
|
|
74
|
+
/** Rectangle around a part, inset by `gap`. (Not `box`: that factory exists.) */
|
|
75
|
+
export function frame(part, opts = {}) {
|
|
76
|
+
const gap = opts.gap ?? tokens.decoration.gap;
|
|
77
|
+
const corner = opts.corner ?? tokens.corner;
|
|
78
|
+
const layout = derive(() => {
|
|
79
|
+
const b = part.box.value;
|
|
80
|
+
return { x: b.x - gap, y: b.y - gap, w: b.w + 2 * gap, h: b.h + 2 * gap };
|
|
81
|
+
});
|
|
82
|
+
const s = rectFromBox(layout);
|
|
83
|
+
s.attrs({ rx: corner, ry: corner });
|
|
84
|
+
applyStroke(s, opts);
|
|
85
|
+
return s;
|
|
86
|
+
}
|
|
87
|
+
/** Underline at the baseline of a part. */
|
|
88
|
+
export function underline(part, opts = {}) {
|
|
89
|
+
const gap = opts.gap ?? tokens.decoration.gap;
|
|
90
|
+
const layout = derive(() => {
|
|
91
|
+
const b = part.box.value;
|
|
92
|
+
const y = b.y + b.h + gap;
|
|
93
|
+
return { x1: b.x, y1: y, x2: b.x + b.w, y2: y };
|
|
94
|
+
});
|
|
95
|
+
const s = lineFromEnds(layout);
|
|
96
|
+
s.attr("stroke-linecap", "round");
|
|
97
|
+
applyStroke(s, opts);
|
|
98
|
+
return s;
|
|
99
|
+
}
|
|
100
|
+
/** Diagonal strikethrough, bottom-left to top-right. */
|
|
101
|
+
export function cross(part, opts = {}) {
|
|
102
|
+
const gap = opts.gap ?? tokens.decoration.crossGap;
|
|
103
|
+
const layout = derive(() => {
|
|
104
|
+
const b = part.box.value;
|
|
105
|
+
return {
|
|
106
|
+
x1: b.x - gap,
|
|
107
|
+
y1: b.y + b.h + gap,
|
|
108
|
+
x2: b.x + b.w + gap,
|
|
109
|
+
y2: b.y - gap,
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
const s = lineFromEnds(layout);
|
|
113
|
+
s.attr("stroke-linecap", "round");
|
|
114
|
+
applyStroke(s, opts);
|
|
115
|
+
return s;
|
|
116
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { brace, cross, type DecorationOpts, frame, underline, } from "./decorations.js";
|
|
2
|
+
export { getMarker, highlightTint, hover, marker, palette, registerMarker, } from "./marker.js";
|
|
3
|
+
export { highlight, morph, Plucked, pluck, unpluck, write, writeOut, } from "./motion.js";
|
|
4
|
+
export { bindParts, type Marker, Part, type PartContent, type PartList, PartMarker, part, parts, tint, } from "./parts.js";
|
|
5
|
+
export { type NamesOf, renderToMathML, type TexInterp, type TexOpts, TexShape, tex, } from "./tex.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { brace, cross, frame, underline, } from "./decorations.js";
|
|
2
|
+
export { getMarker, highlightTint, hover, marker, palette, registerMarker, } from "./marker.js";
|
|
3
|
+
export { highlight, morph, Plucked, pluck, unpluck, write, writeOut, } from "./motion.js";
|
|
4
|
+
export { bindParts, Part, PartMarker, part, parts, tint, } from "./parts.js";
|
|
5
|
+
export { renderToMathML, TexShape, tex, } from "./tex.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Cell, type Writable } from "../core/index.js";
|
|
2
|
+
export declare function getMarker(id: string): Marker | undefined;
|
|
3
|
+
export declare function registerMarker(id: string, m: Marker): void;
|
|
4
|
+
/** Identity shared across renderings; `active` is OR over bound locals. */
|
|
5
|
+
export type Marker = {
|
|
6
|
+
color: Writable<Cell<string | null>>;
|
|
7
|
+
active: Cell<boolean>;
|
|
8
|
+
bind(local: Writable<Cell<boolean>>): () => void;
|
|
9
|
+
register(id: string): Marker;
|
|
10
|
+
};
|
|
11
|
+
export declare function marker(color?: string): Marker;
|
|
12
|
+
/** N perceptually-equidistant OKLCH colors. */
|
|
13
|
+
export declare function palette(n: number): Marker[];
|
|
14
|
+
/** 15%-opacity background tint used for marker / part highlights. */
|
|
15
|
+
export declare const highlightTint: (color: string) => string;
|
|
16
|
+
/** Wire a DOM element's hover into a Marker. */
|
|
17
|
+
export declare function hover(el: Element, m: Marker): () => void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Named reactive identity linking diagram parts to prose. Prefer the
|
|
2
|
+
// scoped registration on `Diagram` over the global registry below.
|
|
3
|
+
import { cell, derive } from "../core/index.js";
|
|
4
|
+
const registry = new Map();
|
|
5
|
+
export function getMarker(id) {
|
|
6
|
+
return registry.get(id);
|
|
7
|
+
}
|
|
8
|
+
export function registerMarker(id, m) {
|
|
9
|
+
registry.set(id, m);
|
|
10
|
+
}
|
|
11
|
+
export function marker(color) {
|
|
12
|
+
const colorCell = cell(color ?? null);
|
|
13
|
+
const locals = new Set();
|
|
14
|
+
const v = cell(0);
|
|
15
|
+
const active = derive(() => {
|
|
16
|
+
v.value;
|
|
17
|
+
for (const s of locals)
|
|
18
|
+
if (s.value)
|
|
19
|
+
return true;
|
|
20
|
+
return false;
|
|
21
|
+
});
|
|
22
|
+
const m = {
|
|
23
|
+
color: colorCell,
|
|
24
|
+
active,
|
|
25
|
+
bind(local) {
|
|
26
|
+
locals.add(local);
|
|
27
|
+
v.value++;
|
|
28
|
+
return () => {
|
|
29
|
+
locals.delete(local);
|
|
30
|
+
v.value++;
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
register(id) {
|
|
34
|
+
registry.set(id, m);
|
|
35
|
+
return m;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return m;
|
|
39
|
+
}
|
|
40
|
+
/** N perceptually-equidistant OKLCH colors. */
|
|
41
|
+
export function palette(n) {
|
|
42
|
+
return Array.from({ length: n }, (_, i) => marker(`oklch(0.65 0.15 ${((i / n) * 360).toFixed(1)})`));
|
|
43
|
+
}
|
|
44
|
+
/** 15%-opacity background tint used for marker / part highlights. */
|
|
45
|
+
export const highlightTint = (color) => `color-mix(in srgb, ${color} 15%, transparent)`;
|
|
46
|
+
/** Wire a DOM element's hover into a Marker. */
|
|
47
|
+
export function hover(el, m) {
|
|
48
|
+
const local = cell(false);
|
|
49
|
+
const unbind = m.bind(local);
|
|
50
|
+
const on = () => {
|
|
51
|
+
local.value = true;
|
|
52
|
+
};
|
|
53
|
+
const off = () => {
|
|
54
|
+
local.value = false;
|
|
55
|
+
};
|
|
56
|
+
el.addEventListener("mouseenter", on);
|
|
57
|
+
el.addEventListener("mouseleave", off);
|
|
58
|
+
return () => {
|
|
59
|
+
unbind();
|
|
60
|
+
el.removeEventListener("mouseenter", on);
|
|
61
|
+
el.removeEventListener("mouseleave", off);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Animator, type Easing } from "../animation/index.js";
|
|
2
|
+
import { Shape } from "../shapes/index.js";
|
|
3
|
+
import type { Part } from "./parts.js";
|
|
4
|
+
import type { TexShape } from "./tex.js";
|
|
5
|
+
/** Wildcard TexShape so cross-cycle morphs (differing `Names`) typecheck. */
|
|
6
|
+
type AnyTex = TexShape<any>;
|
|
7
|
+
/** Pulse a part's `highlighted` signal for `dt` seconds. */
|
|
8
|
+
export declare function highlight(part: Part, dt?: number): Animator;
|
|
9
|
+
/** Reveal an eq left-to-right via a clip-path sweep on the inner HTML
|
|
10
|
+
* wrapper. (Animated clip-path on the outer `<g>` tears foreignObject
|
|
11
|
+
* content in Chromium.) */
|
|
12
|
+
export declare function write(eq: AnyTex, dt?: number, ease?: Easing): Animator;
|
|
13
|
+
/** Reverse of `write`; ends hidden (`opacity: 0`, clip-path cleared). */
|
|
14
|
+
export declare function writeOut(eq: AnyTex, dt?: number, ease?: Easing): Animator;
|
|
15
|
+
/** A Part lifted out of its TexShape into a free Shape. `translate` is
|
|
16
|
+
* the matched mrow's TL in parent coords; `scale` pivots around it.
|
|
17
|
+
* Zeroes the source's opacity until `dispose()`. */
|
|
18
|
+
export declare class Plucked extends Shape {
|
|
19
|
+
#private;
|
|
20
|
+
readonly source: Part;
|
|
21
|
+
constructor(source: Part);
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
/** Lift `part` out of its TexShape, mount under the same parent,
|
|
25
|
+
* return the Plucked. Restore via `plucked.dispose()` or `unpluck`. */
|
|
26
|
+
export declare function pluck(part: Part): Plucked;
|
|
27
|
+
/** Animate `plucked` into `target`'s pose (or back to its source), then
|
|
28
|
+
* dispose. Translates only; animate `scale` yourself to fit a target. */
|
|
29
|
+
export declare function unpluck(plucked: Plucked, target?: Part, dt?: number, ease?: Easing): Animator;
|
|
30
|
+
/** Animate `from` → `to`, matching Parts by marker identity (same
|
|
31
|
+
* marker reference, or markers sharing a `group` root). Branches
|
|
32
|
+
* by cardinality of each identity:
|
|
33
|
+
*
|
|
34
|
+
* 1↔1 same content → single rider, scaled to dest
|
|
35
|
+
* 1↔1 different → dual rider, source fades out, dest fades in
|
|
36
|
+
* 1↔N → N riders emerge from source, fan to dests
|
|
37
|
+
* N↔1 → N riders converge to dest, fade out
|
|
38
|
+
* N↔M → pair by index; extras parent-crossfade
|
|
39
|
+
*
|
|
40
|
+
* Unmatched parts cross-fade with the parent. Assumes both shapes
|
|
41
|
+
* share a parent and have translate-only transforms. */
|
|
42
|
+
export declare function morph(from: AnyTex, to: AnyTex, dt?: number, ease?: Easing): Animator;
|
|
43
|
+
export {};
|