@lumencast/runtime 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/animate/frame-coalescer.d.ts +13 -0
- package/dist/animate/frame-coalescer.d.ts.map +1 -0
- package/dist/animate/frame-coalescer.js +46 -0
- package/dist/animate/frame-coalescer.js.map +1 -0
- package/dist/animate/keyframes.d.ts +1 -1
- package/dist/animate/keyframes.d.ts.map +1 -1
- package/dist/animate/keyframes.js +20 -6
- package/dist/animate/keyframes.js.map +1 -1
- package/dist/animate/transitions.d.ts +4 -1
- package/dist/animate/transitions.d.ts.map +1 -1
- package/dist/animate/transitions.js +30 -3
- package/dist/animate/transitions.js.map +1 -1
- package/dist/{broadcast-DzZ8TVGZ.js → broadcast-3vYij4k-.js} +3 -3
- package/dist/{broadcast-DzZ8TVGZ.js.map → broadcast-3vYij4k-.js.map} +1 -1
- package/dist/{control-gbDGvdR0.js → control-BFNkY7-6.js} +4 -4
- package/dist/{control-gbDGvdR0.js.map → control-BFNkY7-6.js.map} +1 -1
- package/dist/{index-oteiocFe.js → index-CyOlpZAL.js} +305 -150
- package/dist/index-CyOlpZAL.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/lumencast.js +9 -2
- package/dist/mount.d.ts.map +1 -1
- package/dist/mount.js +11 -1
- package/dist/mount.js.map +1 -1
- package/dist/render/bind-animate.d.ts +40 -0
- package/dist/render/bind-animate.d.ts.map +1 -0
- package/dist/render/bind-animate.js +329 -0
- package/dist/render/bind-animate.js.map +1 -0
- package/dist/render/bundle.d.ts +48 -6
- package/dist/render/bundle.d.ts.map +1 -1
- package/dist/render/bundle.js +71 -4
- package/dist/render/bundle.js.map +1 -1
- package/dist/render/color-interp.d.ts +18 -0
- package/dist/render/color-interp.d.ts.map +1 -0
- package/dist/render/color-interp.js +303 -0
- package/dist/render/color-interp.js.map +1 -0
- package/dist/render/css-color.d.ts +16 -0
- package/dist/render/css-color.d.ts.map +1 -0
- package/dist/render/css-color.js +130 -0
- package/dist/render/css-color.js.map +1 -0
- package/dist/render/diagnostics.d.ts +26 -0
- package/dist/render/diagnostics.d.ts.map +1 -0
- package/dist/render/diagnostics.js +58 -0
- package/dist/render/diagnostics.js.map +1 -0
- package/dist/render/fill.d.ts +15 -3
- package/dist/render/fill.d.ts.map +1 -1
- package/dist/render/fill.js +81 -14
- package/dist/render/fill.js.map +1 -1
- package/dist/render/filter-clamp.d.ts +35 -0
- package/dist/render/filter-clamp.d.ts.map +1 -0
- package/dist/render/filter-clamp.js +90 -0
- package/dist/render/filter-clamp.js.map +1 -0
- package/dist/render/keyframe-player.d.ts +4 -1
- package/dist/render/keyframe-player.d.ts.map +1 -1
- package/dist/render/keyframe-player.js +2 -2
- package/dist/render/keyframe-player.js.map +1 -1
- package/dist/render/primitives/frame.d.ts +16 -1
- package/dist/render/primitives/frame.d.ts.map +1 -1
- package/dist/render/primitives/frame.js +42 -7
- package/dist/render/primitives/frame.js.map +1 -1
- package/dist/render/primitives/image.d.ts +1 -1
- package/dist/render/primitives/image.d.ts.map +1 -1
- package/dist/render/primitives/image.js +6 -3
- package/dist/render/primitives/image.js.map +1 -1
- package/dist/render/primitives/index.d.ts +3 -0
- package/dist/render/primitives/index.d.ts.map +1 -1
- package/dist/render/primitives/index.js.map +1 -1
- package/dist/render/primitives/instance.d.ts +1 -1
- package/dist/render/primitives/instance.d.ts.map +1 -1
- package/dist/render/primitives/instance.js +10 -13
- package/dist/render/primitives/instance.js.map +1 -1
- package/dist/render/primitives/shape.d.ts +9 -3
- package/dist/render/primitives/shape.d.ts.map +1 -1
- package/dist/render/primitives/shape.js +56 -12
- package/dist/render/primitives/shape.js.map +1 -1
- package/dist/render/primitives/text.d.ts +35 -4
- package/dist/render/primitives/text.d.ts.map +1 -1
- package/dist/render/primitives/text.js +179 -7
- package/dist/render/primitives/text.js.map +1 -1
- package/dist/render/prop-allowlist.d.ts +10 -0
- package/dist/render/prop-allowlist.d.ts.map +1 -0
- package/dist/render/prop-allowlist.js +112 -0
- package/dist/render/prop-allowlist.js.map +1 -0
- package/dist/render/svg-path.d.ts +35 -0
- package/dist/render/svg-path.d.ts.map +1 -0
- package/dist/render/svg-path.js +211 -0
- package/dist/render/svg-path.js.map +1 -0
- package/dist/render/tree.d.ts.map +1 -1
- package/dist/render/tree.js +30 -5
- package/dist/render/tree.js.map +1 -1
- package/dist/{status-pill-Cgdl9FtP.js → status-pill-DIpXc5du.js} +2 -2
- package/dist/{status-pill-Cgdl9FtP.js.map → status-pill-DIpXc5du.js.map} +1 -1
- package/dist/{test-CAnkHA0n.js → test-ByRec1kd.js} +4 -4
- package/dist/{test-CAnkHA0n.js.map → test-ByRec1kd.js.map} +1 -1
- package/dist/tree-D5wYHpPu.js +1230 -0
- package/dist/tree-D5wYHpPu.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/animate/frame-coalescer.ts +63 -0
- package/src/animate/keyframes.ts +24 -5
- package/src/animate/transitions.ts +33 -3
- package/src/index.ts +24 -0
- package/src/mount.ts +12 -1
- package/src/render/bind-animate.tsx +370 -0
- package/src/render/bundle.ts +102 -10
- package/src/render/color-interp.ts +303 -0
- package/src/render/css-color.ts +145 -0
- package/src/render/diagnostics.ts +75 -0
- package/src/render/fill.tsx +85 -14
- package/src/render/filter-clamp.ts +99 -0
- package/src/render/keyframe-player.tsx +10 -2
- package/src/render/primitives/frame.tsx +47 -7
- package/src/render/primitives/image.tsx +6 -2
- package/src/render/primitives/index.ts +3 -0
- package/src/render/primitives/instance.tsx +14 -15
- package/src/render/primitives/shape.tsx +76 -12
- package/src/render/primitives/text.tsx +224 -7
- package/src/render/prop-allowlist.ts +119 -0
- package/src/render/svg-path.ts +215 -0
- package/src/render/tree.tsx +41 -6
- package/src/types.ts +27 -0
- package/dist/index-oteiocFe.js.map +0 -1
- package/dist/tree-DVYXwItH.js +0 -512
- package/dist/tree-DVYXwItH.js.map +0 -1
package/dist/render/fill.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { parseCssColor, warnRejectedColor } from "./css-color";
|
|
3
|
+
import { emitDiagnostic } from "./diagnostics";
|
|
2
4
|
let gradientIdSeq = 0;
|
|
3
5
|
function nextGradientId() {
|
|
4
6
|
gradientIdSeq = (gradientIdSeq + 1) % 1_000_000;
|
|
@@ -40,25 +42,39 @@ export function renderFill(fill) {
|
|
|
40
42
|
/** Compile an array of Fill into a CSS `background-image` value usable
|
|
41
43
|
* on a `<div>` (frame backgrounds — non-SVG context). Returns the CSS
|
|
42
44
|
* string + opacity. Stops use percentages in CSS gradient syntax. */
|
|
43
|
-
export function backgroundsToCss(fills) {
|
|
45
|
+
export function backgroundsToCss(fills, nodeId) {
|
|
44
46
|
// Per §4.12, fills[0] renders on top — CSS background-image stacks
|
|
45
47
|
// first → top-most. Match by passing in the same order.
|
|
46
|
-
const layers = fills.map(fillToCss).filter(Boolean);
|
|
48
|
+
const layers = fills.map((f) => fillToCss(f, nodeId)).filter(Boolean);
|
|
47
49
|
if (layers.length === 0)
|
|
48
50
|
return {};
|
|
49
51
|
return { backgroundImage: layers.join(", ") };
|
|
50
52
|
}
|
|
51
|
-
function fillToCss(fill) {
|
|
53
|
+
function fillToCss(fill, nodeId) {
|
|
54
|
+
// RC#11 — every colour interpolated into an inline CSS string MUST
|
|
55
|
+
// pass the strict parser first (fills/stops arrive from untrusted
|
|
56
|
+
// bundles AND live LSDP deltas). A rejected colour drops the whole
|
|
57
|
+
// layer : never passthrough, never a half-built gradient.
|
|
52
58
|
if (fill.kind === "solid") {
|
|
59
|
+
const color = parseCssColor(fill.color);
|
|
60
|
+
if (color === null) {
|
|
61
|
+
warnRejectedColor("fill.color", nodeId);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
53
64
|
// Wrap solid in linear-gradient so it can stack with other layers.
|
|
54
|
-
return `linear-gradient(${
|
|
65
|
+
return `linear-gradient(${color}, ${color})`;
|
|
55
66
|
}
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
const safeStops = [];
|
|
68
|
+
for (const s of fill.stops) {
|
|
69
|
+
const color = parseCssColor(s.color);
|
|
70
|
+
if (color === null) {
|
|
71
|
+
warnRejectedColor("fill.stops.color", nodeId);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const c = s.opacity !== undefined ? cssWithOpacity(color, s.opacity) : color;
|
|
75
|
+
safeStops.push(`${c} ${(s.offset * 100).toFixed(2)}%`);
|
|
76
|
+
}
|
|
77
|
+
const stops = safeStops.join(", ");
|
|
62
78
|
if (fill.kind === "linear-gradient") {
|
|
63
79
|
const angle = fill.angle_deg ?? 0;
|
|
64
80
|
return `linear-gradient(${angle}deg, ${stops})`;
|
|
@@ -68,9 +84,13 @@ function fillToCss(fill) {
|
|
|
68
84
|
const cy = (fill.center?.y ?? 0.5) * 100;
|
|
69
85
|
return `radial-gradient(circle at ${cx}% ${cy}%, ${stops})`;
|
|
70
86
|
}
|
|
87
|
+
/** Apply a stop opacity to an ALREADY-VALIDATED colour (callers must
|
|
88
|
+
* have run `parseCssColor` first — fillToCss is the single entry).
|
|
89
|
+
* For 6-digit hex we append the alpha byte ; every other accepted
|
|
90
|
+
* form goes through color-mix, which is safe because the interpolated
|
|
91
|
+
* string can only be a strict-grammar colour (RC#11 fix : this used
|
|
92
|
+
* to interpolate the raw, unparsed input). */
|
|
71
93
|
function cssWithOpacity(color, opacity) {
|
|
72
|
-
// Best-effort wrapper — for hex/rgb we can append alpha. For
|
|
73
|
-
// unrecognised forms, fall back to color-mix.
|
|
74
94
|
const hex = color.match(/^#([0-9a-f]{6})$/i);
|
|
75
95
|
if (hex) {
|
|
76
96
|
const a = Math.round(opacity * 255)
|
|
@@ -80,10 +100,57 @@ function cssWithOpacity(color, opacity) {
|
|
|
80
100
|
}
|
|
81
101
|
return `color-mix(in srgb, ${color} ${opacity * 100}%, transparent)`;
|
|
82
102
|
}
|
|
83
|
-
/**
|
|
84
|
-
|
|
103
|
+
/** Validate every colour carried by a Fill array through the strict
|
|
104
|
+
* parser (RC#11 — issue #30 contractual comment : SVG `fill`/`stroke`
|
|
105
|
+
* attributes and `<stop stop-color>` are injection sites too, since
|
|
106
|
+
* fills arrive from untrusted bundles AND live LSDP deltas). A fill
|
|
107
|
+
* whose solid colour — or ANY gradient stop colour — is rejected drops
|
|
108
|
+
* the whole layer with a diagnostic : never passthrough, never a
|
|
109
|
+
* half-built gradient. Returned fills carry canonicalised colours. */
|
|
110
|
+
export function sanitizeFills(fills, field, nodeId) {
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const fill of fills) {
|
|
113
|
+
if (fill.kind === "solid") {
|
|
114
|
+
const color = parseCssColor(fill.color);
|
|
115
|
+
if (color === null) {
|
|
116
|
+
warnRejectedColor(`${field}.color`, nodeId);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
out.push({ ...fill, color });
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const stops = [];
|
|
123
|
+
let rejected = false;
|
|
124
|
+
for (const s of fill.stops ?? []) {
|
|
125
|
+
const color = parseCssColor(s.color);
|
|
126
|
+
if (color === null) {
|
|
127
|
+
warnRejectedColor(`${field}.stops.color`, nodeId);
|
|
128
|
+
rejected = true;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
stops.push({ ...s, color });
|
|
132
|
+
}
|
|
133
|
+
if (rejected)
|
|
134
|
+
continue;
|
|
135
|
+
out.push({ ...fill, stops });
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
/** Coerce loose JSON into a Fill array. Returns [] for non-arrays.
|
|
140
|
+
* A structurally-valid fill entry whose `kind` is not renderable by
|
|
141
|
+
* this runtime (e.g. `angular-gradient` / `diamond-gradient`, promoted
|
|
142
|
+
* to core by the LSML 1.2 RFC) is dropped WITH a diagnostic — never
|
|
143
|
+
* silently (ADR 001 §3.4, issue #34). */
|
|
144
|
+
export function parseFills(value, field, nodeId) {
|
|
85
145
|
if (!Array.isArray(value))
|
|
86
146
|
return [];
|
|
147
|
+
if (field !== undefined) {
|
|
148
|
+
for (const v of value) {
|
|
149
|
+
if (!isFill(v)) {
|
|
150
|
+
emitDiagnostic(nodeId, `${field}.kind`, "fill kind is not renderable by this runtime ; layer dropped (angular/diamond gradients land with LSML 1.2)");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
87
154
|
return value.filter(isFill);
|
|
88
155
|
}
|
|
89
156
|
function isFill(v) {
|
package/dist/render/fill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fill.js","sourceRoot":"","sources":["../../src/render/fill.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"fill.js","sourceRoot":"","sources":["../../src/render/fill.tsx"],"names":[],"mappings":";AAYA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAwB/C,IAAI,aAAa,GAAG,CAAC,CAAC;AACtB,SAAS,cAAc;IACrB,aAAa,GAAG,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;IAChD,OAAO,cAAc,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACpD,CAAC;AASD;iEACiE;AACjE,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,6DAA6D;QAC7D,kEAAkE;QAClE,iCAAiC;QACjC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACvC,CAAC;IACD,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACpC,0EAA0E;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QAClC,sEAAsE;QACtE,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,6BAA6B;QACzE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG;YACX,yBAEE,EAAE,EAAE,EAAE,EACN,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAClB,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAClB,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAClB,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,YAEjB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACxB,eAEE,MAAM,EAAE,CAAC,CAAC,MAAM,EAChB,SAAS,EAAE,CAAC,CAAC,KAAK,KACd,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAH1D,CAAC,CAIN,CACH,CAAC,IAdG,EAAE,CAeQ;SAClB,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACtC,CAAC;IACD,kBAAkB;IAClB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,CAAC;IACjC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,CAAC;IACjC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAC7B,MAAM,IAAI,GAAG;QACX,yBAAyB,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,YACtF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACxB,eAEE,MAAM,EAAE,CAAC,CAAC,MAAM,EAChB,SAAS,EAAE,CAAC,CAAC,KAAK,KACd,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAH1D,CAAC,CAIN,CACH,CAAC,IARiB,EAAE,CASN;KAClB,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AACtC,CAAC;AAED;;qEAEqE;AACrE,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAe;IAC7D,mEAAmE;IACnE,wDAAwD;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAClF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,IAAU,EAAE,MAAe;IAC5C,mEAAmE;IACnE,kEAAkE;IAClE,mEAAmE;IACnE,0DAA0D;IAC1D,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,iBAAiB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,mEAAmE;QACnE,OAAO,mBAAmB,KAAK,KAAK,KAAK,GAAG,CAAC;IAC/C,CAAC;IACD,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,iBAAiB,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7E,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QAClC,OAAO,mBAAmB,KAAK,QAAQ,KAAK,GAAG,CAAC;IAClD,CAAC;IACD,kBAAkB;IAClB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC;IACzC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC;IACzC,OAAO,6BAA6B,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC;AAC9D,CAAC;AAED;;;;;8CAK8C;AAC9C,SAAS,cAAc,CAAC,KAAa,EAAE,OAAe;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC7C,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;aAChC,QAAQ,CAAC,EAAE,CAAC;aACZ,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpB,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,sBAAsB,KAAK,IAAI,OAAO,GAAG,GAAG,iBAAiB,CAAC;AACvE,CAAC;AAED;;;;;;sEAMsE;AACtE,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,KAAa,EAAE,MAAe;IACzE,MAAM,GAAG,GAAW,EAAE,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,iBAAiB,CAAC,GAAG,KAAK,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC5C,SAAS;YACX,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7B,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,iBAAiB,CAAC,GAAG,KAAK,cAAc,EAAE,MAAM,CAAC,CAAC;gBAClD,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,QAAQ;YAAE,SAAS;QACvB,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;yCAIyC;AACzC,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,KAAc,EAAE,MAAe;IACxE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,cAAc,CACZ,MAAM,EACN,GAAG,KAAK,OAAO,EACf,4GAA4G,CAC7G,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,MAAM,CAAW,CAAC;AACxC,CAAC;AAED,SAAS,MAAM,CAAC,CAAU;IACxB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,CAAC,GAAI,CAAwB,CAAC,IAAI,CAAC;IACzC,OAAO,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,iBAAiB,IAAI,CAAC,KAAK,iBAAiB,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Max CSS `blur()` radius accepted at runtime, in px (mirror of the
|
|
2
|
+
* compiler cap — see issue #41). */
|
|
3
|
+
export declare const MAX_FILTER_BLUR_PX = 100;
|
|
4
|
+
/** Max CSS `brightness()` factor accepted at runtime (mirror of the
|
|
5
|
+
* compiler cap — see issue #41 ; spec §6.1 blesses clamping to 4). */
|
|
6
|
+
export declare const MAX_FILTER_BRIGHTNESS = 4;
|
|
7
|
+
export type FilterChannel = "blur" | "brightness";
|
|
8
|
+
/**
|
|
9
|
+
* Gate one live numeric filter channel (R8 runtime half).
|
|
10
|
+
*
|
|
11
|
+
* Returns the clamped value, or `null` when the value is rejected
|
|
12
|
+
* (non-number, non-finite, negative — including `-0`, which would
|
|
13
|
+
* stringify to an accepted `0`). A `null` MUST be handled as "keep the
|
|
14
|
+
* last known-good value / identity" — never apply the raw input.
|
|
15
|
+
*/
|
|
16
|
+
export declare function clampFilterChannel(channel: FilterChannel, value: unknown): number | null;
|
|
17
|
+
/** Identity filter — matches the compiler's neutral emission and
|
|
18
|
+
* `INITIAL_IDENTITY.filter` in transitions.ts. */
|
|
19
|
+
export declare const FILTER_IDENTITY = "blur(0px) brightness(1)";
|
|
20
|
+
/**
|
|
21
|
+
* Gate a CSS filter STRING reaching framer-motion at runtime
|
|
22
|
+
* (`animate_initial.filter`, keyframe `steps[].filter`). Hand-crafted
|
|
23
|
+
* bundles bypass the compiler clamps, so the runtime re-validates and
|
|
24
|
+
* re-clamps (R8). Returns the safe, clamped canonical string or `null`
|
|
25
|
+
* on rejection — never the raw input.
|
|
26
|
+
*/
|
|
27
|
+
export declare function sanitizeCssFilterString(value: unknown): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Diagnostic for a rejected filter value. Bastion R9 (ADR 001 §5.1) :
|
|
30
|
+
* the rejected VALUE is never logged nor forwarded — only `node.id`
|
|
31
|
+
* (RC#7, issue #34), the field name and a static reason. Routed through
|
|
32
|
+
* the structured diagnostics channel (events, no logs in `broadcast`).
|
|
33
|
+
*/
|
|
34
|
+
export declare function warnRejectedFilter(field: string, nodeId?: string): void;
|
|
35
|
+
//# sourceMappingURL=filter-clamp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-clamp.d.ts","sourceRoot":"","sources":["../../src/render/filter-clamp.ts"],"names":[],"mappings":"AA0BA;qCACqC;AACrC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC;uEACuE;AACvE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AASvC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKxF;AASD;mDACmD;AACnD,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CASrE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAMvE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Runtime half of the R8 filter gate (ADR 001 §5.1 R8, issue #42).
|
|
2
|
+
//
|
|
3
|
+
// The compiler clamps `filter` values at lowering (`lowerFilter`,
|
|
4
|
+
// packages/compiler/src/compile.ts) — but a filter value pushed by a
|
|
5
|
+
// LIVE LSDP delta reaches the runtime through `resolveProps` /
|
|
6
|
+
// `animateBindings` without ever passing through the compiler. R8
|
|
7
|
+
// requires the clamp at compile AND at runtime : an unbounded filter is
|
|
8
|
+
// a compositing DoS in CEF. Every filter value that can reach an inline
|
|
9
|
+
// style at render time MUST pass through this module.
|
|
10
|
+
//
|
|
11
|
+
// NOTE on duplication : these caps intentionally mirror the compiler's
|
|
12
|
+
// `MAX_FILTER_BLUR_PX` / `MAX_FILTER_BRIGHTNESS` constants. Unifying
|
|
13
|
+
// them behind a single shared module is tracked by issue #41 (same
|
|
14
|
+
// model as the shared colour module) — do NOT change one side without
|
|
15
|
+
// the other until #41 lands.
|
|
16
|
+
//
|
|
17
|
+
// ── Linear-time justification (RC#12) ────────────────────────────────
|
|
18
|
+
// The string form is validated by a single ANCHORED regex made of
|
|
19
|
+
// literals and bounded quantifiers ({1,7} / {1,4} digit runs, one
|
|
20
|
+
// optional space run) — exactly one possible parse per input, no
|
|
21
|
+
// backtracking blow-up. Inputs longer than MAX_FILTER_STRING_LEN are
|
|
22
|
+
// rejected before the regex runs.
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
24
|
+
import { emitDiagnostic } from "./diagnostics";
|
|
25
|
+
/** Max CSS `blur()` radius accepted at runtime, in px (mirror of the
|
|
26
|
+
* compiler cap — see issue #41). */
|
|
27
|
+
export const MAX_FILTER_BLUR_PX = 100;
|
|
28
|
+
/** Max CSS `brightness()` factor accepted at runtime (mirror of the
|
|
29
|
+
* compiler cap — see issue #41 ; spec §6.1 blesses clamping to 4). */
|
|
30
|
+
export const MAX_FILTER_BRIGHTNESS = 4;
|
|
31
|
+
const MAX_FILTER_STRING_LEN = 64;
|
|
32
|
+
const CAPS = {
|
|
33
|
+
blur: MAX_FILTER_BLUR_PX,
|
|
34
|
+
brightness: MAX_FILTER_BRIGHTNESS,
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Gate one live numeric filter channel (R8 runtime half).
|
|
38
|
+
*
|
|
39
|
+
* Returns the clamped value, or `null` when the value is rejected
|
|
40
|
+
* (non-number, non-finite, negative — including `-0`, which would
|
|
41
|
+
* stringify to an accepted `0`). A `null` MUST be handled as "keep the
|
|
42
|
+
* last known-good value / identity" — never apply the raw input.
|
|
43
|
+
*/
|
|
44
|
+
export function clampFilterChannel(channel, value) {
|
|
45
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
46
|
+
return null;
|
|
47
|
+
if (value < 0 || Object.is(value, -0))
|
|
48
|
+
return null;
|
|
49
|
+
const cap = CAPS[channel];
|
|
50
|
+
return value > cap ? cap : value;
|
|
51
|
+
}
|
|
52
|
+
// The ONLY string form the compiler ever emits (`lowerFilter`) :
|
|
53
|
+
// `blur(<n>px) brightness(<n>)`. Anything else — extra functions,
|
|
54
|
+
// `url(`, negative signs, exponents — is rejected by construction
|
|
55
|
+
// (the grammar has no `-`, no `e`, no second parenthesis pair).
|
|
56
|
+
const FILTER_STRING_RE = /^blur\((\d{1,7}(?:\.\d{1,4})?)px\) brightness\((\d{1,7}(?:\.\d{1,4})?)\)$/;
|
|
57
|
+
/** Identity filter — matches the compiler's neutral emission and
|
|
58
|
+
* `INITIAL_IDENTITY.filter` in transitions.ts. */
|
|
59
|
+
export const FILTER_IDENTITY = "blur(0px) brightness(1)";
|
|
60
|
+
/**
|
|
61
|
+
* Gate a CSS filter STRING reaching framer-motion at runtime
|
|
62
|
+
* (`animate_initial.filter`, keyframe `steps[].filter`). Hand-crafted
|
|
63
|
+
* bundles bypass the compiler clamps, so the runtime re-validates and
|
|
64
|
+
* re-clamps (R8). Returns the safe, clamped canonical string or `null`
|
|
65
|
+
* on rejection — never the raw input.
|
|
66
|
+
*/
|
|
67
|
+
export function sanitizeCssFilterString(value) {
|
|
68
|
+
if (typeof value !== "string")
|
|
69
|
+
return null;
|
|
70
|
+
if (value.length === 0 || value.length > MAX_FILTER_STRING_LEN)
|
|
71
|
+
return null;
|
|
72
|
+
const m = FILTER_STRING_RE.exec(value);
|
|
73
|
+
if (!m)
|
|
74
|
+
return null;
|
|
75
|
+
const blur = clampFilterChannel("blur", Number(m[1]));
|
|
76
|
+
const brightness = clampFilterChannel("brightness", Number(m[2]));
|
|
77
|
+
if (blur === null || brightness === null)
|
|
78
|
+
return null;
|
|
79
|
+
return `blur(${blur}px) brightness(${brightness})`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Diagnostic for a rejected filter value. Bastion R9 (ADR 001 §5.1) :
|
|
83
|
+
* the rejected VALUE is never logged nor forwarded — only `node.id`
|
|
84
|
+
* (RC#7, issue #34), the field name and a static reason. Routed through
|
|
85
|
+
* the structured diagnostics channel (events, no logs in `broadcast`).
|
|
86
|
+
*/
|
|
87
|
+
export function warnRejectedFilter(field, nodeId) {
|
|
88
|
+
emitDiagnostic(nodeId, field, "rejected unsafe filter value : outside the R8 caps or not a finite number >= 0");
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=filter-clamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-clamp.js","sourceRoot":"","sources":["../../src/render/filter-clamp.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,+DAA+D;AAC/D,kEAAkE;AAClE,wEAAwE;AACxE,wEAAwE;AACxE,sDAAsD;AACtD,EAAE;AACF,uEAAuE;AACvE,qEAAqE;AACrE,mEAAmE;AACnE,sEAAsE;AACtE,6BAA6B;AAC7B,EAAE;AACF,wEAAwE;AACxE,kEAAkE;AAClE,kEAAkE;AAClE,iEAAiE;AACjE,qEAAqE;AACrE,kCAAkC;AAClC,wEAAwE;AAExE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C;qCACqC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC;uEACuE;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEvC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC,MAAM,IAAI,GAAkC;IAC1C,IAAI,EAAE,kBAAkB;IACxB,UAAU,EAAE,qBAAqB;CAClC,CAAC;AAIF;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,KAAc;IACvE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,IAAI,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AACnC,CAAC;AAED,iEAAiE;AACjE,kEAAkE;AAClE,kEAAkE;AAClE,gEAAgE;AAChE,MAAM,gBAAgB,GACpB,2EAA2E,CAAC;AAE9E;mDACmD;AACnD,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,qBAAqB;QAAE,OAAO,IAAI,CAAC;IAC5E,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,kBAAkB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,IAAI,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,QAAQ,IAAI,kBAAkB,UAAU,GAAG,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAAe;IAC/D,cAAc,CACZ,MAAM,EACN,KAAK,EACL,gFAAgF,CACjF,CAAC;AACJ,CAAC"}
|
|
@@ -4,7 +4,10 @@ import { type Keyframes } from "../animate/keyframes";
|
|
|
4
4
|
export interface KeyframePlayerProps {
|
|
5
5
|
keyframes: Keyframes;
|
|
6
6
|
store: Store;
|
|
7
|
+
/** `RenderNode.id` of the owning node — threaded into keyframe
|
|
8
|
+
* diagnostics (ADR 001 RC#7, issue #34). */
|
|
9
|
+
nodeId?: string;
|
|
7
10
|
children: ReactNode;
|
|
8
11
|
}
|
|
9
|
-
export declare function KeyframePlayer({ keyframes, store, children }: KeyframePlayerProps): ReactNode;
|
|
12
|
+
export declare function KeyframePlayer({ keyframes, store, nodeId, children, }: KeyframePlayerProps): ReactNode;
|
|
10
13
|
//# sourceMappingURL=keyframe-player.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyframe-player.d.ts","sourceRoot":"","sources":["../../src/render/keyframe-player.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIxE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"keyframe-player.d.ts","sourceRoot":"","sources":["../../src/render/keyframe-player.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIxE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb;iDAC6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,GACT,EAAE,mBAAmB,GAAG,SAAS,CAwCjC"}
|
|
@@ -17,7 +17,7 @@ import { useSignals } from "@preact/signals-react/runtime";
|
|
|
17
17
|
import { compileForFramer } from "../animate/keyframes";
|
|
18
18
|
import { StaggerContext } from "./stagger-context";
|
|
19
19
|
import { scopedPath, usePathScope } from "./scope";
|
|
20
|
-
export function KeyframePlayer({ keyframes, store, children }) {
|
|
20
|
+
export function KeyframePlayer({ keyframes, store, nodeId, children, }) {
|
|
21
21
|
useSignals();
|
|
22
22
|
const scope = usePathScope();
|
|
23
23
|
const staggerDelayMs = useContext(StaggerContext);
|
|
@@ -33,7 +33,7 @@ export function KeyframePlayer({ keyframes, store, children }) {
|
|
|
33
33
|
replayTokenRef.current += 1;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
const compiled = compileForFramer(keyframes);
|
|
36
|
+
const compiled = compileForFramer(keyframes, nodeId);
|
|
37
37
|
if (!compiled) {
|
|
38
38
|
return _jsx(_Fragment, { children: children });
|
|
39
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyframe-player.js","sourceRoot":"","sources":["../../src/render/keyframe-player.tsx"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,qEAAqE;AACrE,uEAAuE;AACvE,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,0EAA0E;AAC1E,0BAA0B;AAE1B,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAkB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"keyframe-player.js","sourceRoot":"","sources":["../../src/render/keyframe-player.tsx"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,qEAAqE;AACrE,uEAAuE;AACvE,sEAAsE;AACtE,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,0EAA0E;AAC1E,0BAA0B;AAE1B,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAkB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAWnD,MAAM,UAAU,cAAc,CAAC,EAC7B,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,GACY;IACpB,UAAU,EAAE,CAAC;IACb,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAElD,+DAA+D;IAC/D,kEAAkE;IAClE,iEAAiE;IACjE,MAAM,YAAY,GAAG,MAAM,CAAU,SAAS,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,SAAS,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;QAC/D,IAAI,YAAY,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC/B,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC;YACzB,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACzB,CAAC;IAED,MAAM,UAAU,GACd,cAAc,GAAG,CAAC;QAChB,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,EAAE;QAC1D,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;IAE1B,OAAO,CACL,MAAC,MAAM,CAAC,GAAG,IAET,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAC9B,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EACrC,OAAO,EAAE,QAAQ,CAAC,OAAO,EACzB,UAAU,EAAE,UAAU,aAEtB,KAAC,aAAa,KAAG,EAChB,QAAQ,KAPJ,cAAc,CAAC,OAAO,CAQhB,CACd,CAAC;AACJ,CAAC;AAED;qDACqD;AACrD,SAAS,aAAa;IACpB,SAAS,CAAC,GAAG,EAAE;QACb,oBAAoB;IACtB,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;uCAGuC;AACvC,SAAS,UAAU,CAAC,OAA4C;IAC9D,MAAM,GAAG,GAAoC,EAAE,CAAC;IAChD,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -7,6 +7,21 @@ import type { PrimitiveProps } from "./index";
|
|
|
7
7
|
* LSML 1.1 §4.3 + §4.12 add `backgrounds[]` as an alternative to the
|
|
8
8
|
* legacy `background` (single color). The array form supports stacked
|
|
9
9
|
* fills with linear / radial gradients ; first entry renders on top.
|
|
10
|
+
*
|
|
11
|
+
* LSML 1.1 §4.3 `clipsContent` (default `true`) clips children outside
|
|
12
|
+
* the frame's bounds via `overflow: hidden` (ADR 001 §3.2.5, RC#5).
|
|
13
|
+
*/
|
|
14
|
+
export declare function Frame({ resolved, nodeId, transitionFor, animateInitial, children, }: PrimitiveProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve `clipsContent` (LSML 1.1 §4.3, schema default `true`).
|
|
17
|
+
*
|
|
18
|
+
* The prop is wire-drivable (static bundle prop OR live LSDP delta via
|
|
19
|
+
* `resolveProps`, tree.tsx), so a non-boolean is treated as hostile :
|
|
20
|
+
* R9 diagnostic (value withheld) + fall back to the spec default
|
|
21
|
+
* (`true`, i.e. clipped — the safe state for broadcast). The returned
|
|
22
|
+
* value only ever selects between two literal style fragments — no
|
|
23
|
+
* untrusted value can reach inline CSS through this path (RC#11 by
|
|
24
|
+
* construction). Exported for boundary testing.
|
|
10
25
|
*/
|
|
11
|
-
export declare function
|
|
26
|
+
export declare function resolveClipsContent(v: unknown, nodeId?: string): boolean;
|
|
12
27
|
//# sourceMappingURL=frame.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/frame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/frame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAM9C;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,EACpB,QAAQ,EACR,MAAM,EACN,aAAa,EACb,cAAc,EACd,QAAQ,GACT,EAAE,cAAc,2CA2DhB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAKxE"}
|
|
@@ -2,6 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { motion } from "framer-motion";
|
|
3
3
|
import { toFramer, mountPlay, resolveTransition } from "../../animate/transitions";
|
|
4
4
|
import { backgroundsToCss, parseFills } from "../fill";
|
|
5
|
+
import { parseCssColor, warnRejectedColor } from "../css-color";
|
|
6
|
+
import { emitDiagnostic } from "../diagnostics";
|
|
5
7
|
/** Absolute-positioned container with size + transform + opacity.
|
|
6
8
|
* Animatable on `transform` and `opacity` only — width/height/position
|
|
7
9
|
* changes are intentionally *not* animatable to keep the broadcast
|
|
@@ -10,8 +12,11 @@ import { backgroundsToCss, parseFills } from "../fill";
|
|
|
10
12
|
* LSML 1.1 §4.3 + §4.12 add `backgrounds[]` as an alternative to the
|
|
11
13
|
* legacy `background` (single color). The array form supports stacked
|
|
12
14
|
* fills with linear / radial gradients ; first entry renders on top.
|
|
15
|
+
*
|
|
16
|
+
* LSML 1.1 §4.3 `clipsContent` (default `true`) clips children outside
|
|
17
|
+
* the frame's bounds via `overflow: hidden` (ADR 001 §3.2.5, RC#5).
|
|
13
18
|
*/
|
|
14
|
-
export function Frame({ resolved, transitionFor, animateInitial, children }) {
|
|
19
|
+
export function Frame({ resolved, nodeId, transitionFor, animateInitial, children, }) {
|
|
15
20
|
const x = numberOr(resolved.x, 0);
|
|
16
21
|
const y = numberOr(resolved.y, 0);
|
|
17
22
|
const width = sizeProp(resolved.width);
|
|
@@ -20,9 +25,15 @@ export function Frame({ resolved, transitionFor, animateInitial, children }) {
|
|
|
20
25
|
const scale = numberOr(resolved.scale, 1);
|
|
21
26
|
const rotate = numberOr(resolved.rotate, 0);
|
|
22
27
|
// 1.0 single-fill prop — used as fallback when 1.1 `backgrounds[]`
|
|
23
|
-
// is empty.
|
|
24
|
-
|
|
25
|
-
const
|
|
28
|
+
// is empty. RC#11 : the value is untrusted (static prop OR live LSDP
|
|
29
|
+
// delta) and lands in inline CSS — strict-parse, never passthrough.
|
|
30
|
+
const rawBackground = resolved.background;
|
|
31
|
+
const legacyBackground = rawBackground === undefined ? undefined : parseCssColor(rawBackground);
|
|
32
|
+
if (rawBackground !== undefined && legacyBackground === null) {
|
|
33
|
+
warnRejectedColor("frame.background", nodeId);
|
|
34
|
+
}
|
|
35
|
+
const backgrounds = parseFills(resolved.backgrounds, "frame.backgrounds", nodeId);
|
|
36
|
+
const clipsContent = resolveClipsContent(resolved.clipsContent, nodeId);
|
|
26
37
|
// Pick the most expressive declared transition among the animated
|
|
27
38
|
// bindings (transform / opacity). If none, no animation.
|
|
28
39
|
const tx = resolveTransition(transitionFor, ["opacity", "scale", "rotate", "x", "y"], animateInitial);
|
|
@@ -33,16 +44,40 @@ export function Frame({ resolved, transitionFor, animateInitial, children }) {
|
|
|
33
44
|
width,
|
|
34
45
|
height,
|
|
35
46
|
willChange: "transform, opacity",
|
|
47
|
+
// LSML 1.1 §4.3 `clipsContent` (default `true`) — children outside
|
|
48
|
+
// the frame's `size` are clipped. Static layout property : it never
|
|
49
|
+
// animates, so it stays off the 0-layout-event hot path (ADR 001
|
|
50
|
+
// §3.2.5). `false` => omit the declaration (CSS initial = visible).
|
|
51
|
+
...(clipsContent ? { overflow: "hidden" } : {}),
|
|
36
52
|
};
|
|
37
53
|
if (backgrounds.length > 0) {
|
|
38
|
-
Object.assign(style, backgroundsToCss(backgrounds));
|
|
54
|
+
Object.assign(style, backgroundsToCss(backgrounds, nodeId));
|
|
39
55
|
}
|
|
40
|
-
else if (legacyBackground !== undefined) {
|
|
56
|
+
else if (legacyBackground !== undefined && legacyBackground !== null) {
|
|
41
57
|
style.background = legacyBackground;
|
|
42
58
|
}
|
|
43
|
-
const play = mountPlay({ opacity, x, y, scale, rotate }, animateInitial);
|
|
59
|
+
const play = mountPlay({ opacity, x, y, scale, rotate }, animateInitial, nodeId);
|
|
44
60
|
return (_jsx(motion.div, { style: style, initial: play.initial, animate: play.animate, transition: toFramer(tx), children: children }));
|
|
45
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve `clipsContent` (LSML 1.1 §4.3, schema default `true`).
|
|
64
|
+
*
|
|
65
|
+
* The prop is wire-drivable (static bundle prop OR live LSDP delta via
|
|
66
|
+
* `resolveProps`, tree.tsx), so a non-boolean is treated as hostile :
|
|
67
|
+
* R9 diagnostic (value withheld) + fall back to the spec default
|
|
68
|
+
* (`true`, i.e. clipped — the safe state for broadcast). The returned
|
|
69
|
+
* value only ever selects between two literal style fragments — no
|
|
70
|
+
* untrusted value can reach inline CSS through this path (RC#11 by
|
|
71
|
+
* construction). Exported for boundary testing.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveClipsContent(v, nodeId) {
|
|
74
|
+
if (v === undefined)
|
|
75
|
+
return true;
|
|
76
|
+
if (typeof v === "boolean")
|
|
77
|
+
return v;
|
|
78
|
+
emitDiagnostic(nodeId, "frame.clipsContent", "rejected value : not a boolean");
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
46
81
|
function numberOr(v, fallback) {
|
|
47
82
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
48
83
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../../src/render/primitives/frame.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAGvC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../../src/render/primitives/frame.tsx"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,5 @@ import type { PrimitiveProps } from "./index";
|
|
|
3
3
|
* `opacity`. Opacity is animated when a transition is declared. When an
|
|
4
4
|
* `animate.from` is lowered onto the node, it mounts at that state and
|
|
5
5
|
* plays to its target on mount (mount-play). */
|
|
6
|
-
export declare function Image({ resolved, transitionFor, animateInitial }: PrimitiveProps): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export declare function Image({ resolved, nodeId, transitionFor, animateInitial }: PrimitiveProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
7
|
//# sourceMappingURL=image.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/image.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C;;;iDAGiD;AACjD,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/image.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C;;;iDAGiD;AACjD,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,EAAE,cAAc,kDAmCxF"}
|
|
@@ -5,10 +5,13 @@ import { toFramer, mountPlay, resolveTransition } from "../../animate/transition
|
|
|
5
5
|
* `opacity`. Opacity is animated when a transition is declared. When an
|
|
6
6
|
* `animate.from` is lowered onto the node, it mounts at that state and
|
|
7
7
|
* plays to its target on mount (mount-play). */
|
|
8
|
-
export function Image({ resolved, transitionFor, animateInitial }) {
|
|
8
|
+
export function Image({ resolved, nodeId, transitionFor, animateInitial }) {
|
|
9
9
|
const src = resolved.src;
|
|
10
10
|
if (!src)
|
|
11
11
|
return null;
|
|
12
|
+
// LSML §4.5 `alt` is required and was silently unrendered until
|
|
13
|
+
// issue #34's allowlist audit surfaced it — now forwarded to the DOM.
|
|
14
|
+
const alt = typeof resolved.alt === "string" ? resolved.alt : "";
|
|
12
15
|
const fit = resolved.fit ?? "contain";
|
|
13
16
|
const position = resolved.position ?? "center";
|
|
14
17
|
const opacity = numberOr(resolved.opacity, 1);
|
|
@@ -18,8 +21,8 @@ export function Image({ resolved, transitionFor, animateInitial }) {
|
|
|
18
21
|
const width = dimOr(resolved.width, "100%");
|
|
19
22
|
const height = dimOr(resolved.height, "100%");
|
|
20
23
|
const tx = resolveTransition(transitionFor, ["opacity", "src"], animateInitial);
|
|
21
|
-
const play = mountPlay({ opacity }, animateInitial);
|
|
22
|
-
return (_jsx(motion.img, { src: src, style: {
|
|
24
|
+
const play = mountPlay({ opacity }, animateInitial, nodeId);
|
|
25
|
+
return (_jsx(motion.img, { src: src, alt: alt, style: {
|
|
23
26
|
objectFit: fit,
|
|
24
27
|
objectPosition: position,
|
|
25
28
|
width,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../../src/render/primitives/image.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnF;;;iDAGiD;AACjD,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAkB;
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../../src/render/primitives/image.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnF;;;iDAGiD;AACjD,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAkB;IACvF,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAyB,CAAC;IAC/C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,gEAAgE;IAChE,sEAAsE;IACtE,MAAM,GAAG,GAAG,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,GAAG,GAAI,QAAQ,CAAC,GAA0B,IAAI,SAAS,CAAC;IAC9D,MAAM,QAAQ,GAAI,QAAQ,CAAC,QAA+B,IAAI,QAAQ,CAAC;IACvE,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC9C,mFAAmF;IACnF,0EAA0E;IAC1E,sEAAsE;IACtE,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE9C,MAAM,EAAE,GAAG,iBAAiB,CAAC,aAAa,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,cAAc,CAAC,CAAC;IAChF,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;IAE5D,OAAO,CACL,KAAC,MAAM,CAAC,GAAG,IACT,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,KAAK,EAAE;YACL,SAAS,EAAE,GAAuC;YAClD,cAAc,EAAE,QAAQ;YACxB,KAAK;YACL,MAAM;YACN,UAAU,EAAE,oBAAoB;SACjC,EACD,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,EACxB,SAAS,EAAE,KAAK,GAChB,CACH,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU,EAAE,QAAgB;IAC5C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpE,CAAC;AAED;mDACmD;AACnD,SAAS,KAAK,CAAC,CAAU,EAAE,QAAgB;IACzC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IACjE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -3,6 +3,9 @@ import type { RenderKind } from "../bundle";
|
|
|
3
3
|
import type { Transition } from "../../animate/transitions";
|
|
4
4
|
export interface PrimitiveProps {
|
|
5
5
|
resolved: Record<string, unknown>;
|
|
6
|
+
/** `RenderNode.id` of the node being rendered — threaded into every
|
|
7
|
+
* diagnostic the primitive emits (ADR 001 RC#7, issue #34). */
|
|
8
|
+
nodeId?: string;
|
|
6
9
|
transitionFor: (key: string) => Transition | undefined;
|
|
7
10
|
/** LSML 1.1 `animate.from` lowered to a flat framer `initial` map
|
|
8
11
|
* (keys: `opacity`, `scale`, `rotate`, `x`, `y`). When present, a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAa5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACvD;;;;0EAIsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC,CASjF,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAa5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;oEACgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACvD;;;;0EAIsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC,CASjF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/render/primitives/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,uEAAuE;AACvE,0DAA0D;AAK1D,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/render/primitives/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,uEAAuE;AACvE,0DAA0D;AAK1D,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoBtC,MAAM,CAAC,MAAM,UAAU,GAA+D;IACpF,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,QAAQ;CACnB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
2
|
import type { PrimitiveProps } from "./index";
|
|
3
|
-
export declare function Instance({ resolved }: PrimitiveProps): ReactElement | null;
|
|
3
|
+
export declare function Instance({ resolved, nodeId }: PrimitiveProps): ReactElement | null;
|
|
4
4
|
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/instance.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../src/render/primitives/instance.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,YAAY,GAAG,IAAI,CAwClF"}
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { emitDiagnostic } from "../diagnostics";
|
|
2
3
|
const warned = new Set();
|
|
3
|
-
export function Instance({ resolved }) {
|
|
4
|
+
export function Instance({ resolved, nodeId }) {
|
|
4
5
|
const sceneId = resolved.scene_id;
|
|
5
6
|
const sceneVersion = resolved.scene_version;
|
|
6
7
|
if (!sceneId || !sceneVersion) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Structured diagnostic — never dump `resolved` (R9 : prop values,
|
|
9
|
+
// including bound params, must not transit a diagnostic channel).
|
|
10
|
+
emitDiagnostic(nodeId, "instance.scene_id", "missing scene_id or scene_version ; not rendered");
|
|
10
11
|
return null;
|
|
11
12
|
}
|
|
12
|
-
// One-time
|
|
13
|
+
// One-time diagnostic per (sceneId,version) so authors know the
|
|
13
14
|
// scaffold limitation.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
console.warn(`[lumencast/instance] scaffold render — async bundle fetch + ` +
|
|
19
|
-
`__params.* injection are not yet wired (LSML 1.1 §4.9). ` +
|
|
20
|
-
`scene_id=${sceneId}`);
|
|
21
|
-
}
|
|
15
|
+
const key = `${sceneId}:${sceneVersion}`;
|
|
16
|
+
if (!warned.has(key)) {
|
|
17
|
+
warned.add(key);
|
|
18
|
+
emitDiagnostic(nodeId, "instance", "scaffold render — async bundle fetch + __params.* injection are not yet wired (LSML 1.1 §4.9)");
|
|
22
19
|
}
|
|
23
20
|
const size = resolved.size;
|
|
24
21
|
const position = resolved.position;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../../src/render/primitives/instance.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../../src/render/primitives/instance.tsx"],"names":[],"mappings":";AAwBA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjC,MAAM,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAkB;IAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,QAA8B,CAAC;IACxD,MAAM,YAAY,GAAG,QAAQ,CAAC,aAAmC,CAAC;IAClE,IAAI,CAAC,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;QAC9B,mEAAmE;QACnE,kEAAkE;QAClE,cAAc,CAAC,MAAM,EAAE,mBAAmB,EAAE,kDAAkD,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gEAAgE;IAChE,uBAAuB;IACvB,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,YAAY,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,cAAc,CACZ,MAAM,EACN,UAAU,EACV,+FAA+F,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,IAA8C,CAAC;IACrE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAkD,CAAC;IAE7E,OAAO,CACL,yCAC2B,OAAO,4BACR,YAAY,EACpC,KAAK,EAAE;YACL,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;YAC5C,IAAI,EAAE,QAAQ,EAAE,CAAC;YACjB,GAAG,EAAE,QAAQ,EAAE,CAAC;YAChB,KAAK,EAAE,IAAI,EAAE,CAAC;YACd,MAAM,EAAE,IAAI,EAAE,CAAC;YACf,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,MAAM;YACxE,SAAS,EAAE,YAAY;SACxB,GACD,CACH,CAAC;AACJ,CAAC"}
|