@getrheo/flow-runtime 1.0.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.
Files changed (126) hide show
  1. package/dist/agentPrompt/index.d.ts +72 -0
  2. package/dist/agentPrompt/index.js +739 -0
  3. package/dist/agentPrompt/index.js.map +1 -0
  4. package/dist/aiFlowGenerationMerge.d.ts +32 -0
  5. package/dist/aiFlowGenerationMerge.js +120 -0
  6. package/dist/aiFlowGenerationMerge.js.map +1 -0
  7. package/dist/animations.d.ts +110 -0
  8. package/dist/animations.js +312 -0
  9. package/dist/animations.js.map +1 -0
  10. package/dist/assignment.d.ts +7 -0
  11. package/dist/assignment.js +25 -0
  12. package/dist/assignment.js.map +1 -0
  13. package/dist/brandGradient.d.ts +57 -0
  14. package/dist/brandGradient.js +137 -0
  15. package/dist/brandGradient.js.map +1 -0
  16. package/dist/brandGradientManifestIssues.d.ts +11 -0
  17. package/dist/brandGradientManifestIssues.js +302 -0
  18. package/dist/brandGradientManifestIssues.js.map +1 -0
  19. package/dist/buildFlowPreview.d.ts +7 -0
  20. package/dist/buildFlowPreview.js +81 -0
  21. package/dist/buildFlowPreview.js.map +1 -0
  22. package/dist/buttonVariantChrome.d.ts +26 -0
  23. package/dist/buttonVariantChrome.js +59 -0
  24. package/dist/buttonVariantChrome.js.map +1 -0
  25. package/dist/checkboxGlyphStyle.d.ts +31 -0
  26. package/dist/checkboxGlyphStyle.js +241 -0
  27. package/dist/checkboxGlyphStyle.js.map +1 -0
  28. package/dist/choiceOptionSelection.d.ts +11 -0
  29. package/dist/choiceOptionSelection.js +120 -0
  30. package/dist/choiceOptionSelection.js.map +1 -0
  31. package/dist/colorAlpha.d.ts +8 -0
  32. package/dist/colorAlpha.js +48 -0
  33. package/dist/colorAlpha.js.map +1 -0
  34. package/dist/counterLayer.d.ts +42 -0
  35. package/dist/counterLayer.js +95 -0
  36. package/dist/counterLayer.js.map +1 -0
  37. package/dist/decisionEval.d.ts +27 -0
  38. package/dist/decisionEval.js +197 -0
  39. package/dist/decisionEval.js.map +1 -0
  40. package/dist/dropShadow.d.ts +26 -0
  41. package/dist/dropShadow.js +76 -0
  42. package/dist/dropShadow.js.map +1 -0
  43. package/dist/emailPasswordAuthValidation.d.ts +16 -0
  44. package/dist/emailPasswordAuthValidation.js +25 -0
  45. package/dist/emailPasswordAuthValidation.js.map +1 -0
  46. package/dist/flowBuilderRules.d.ts +15 -0
  47. package/dist/flowBuilderRules.js +368 -0
  48. package/dist/flowBuilderRules.js.map +1 -0
  49. package/dist/flowGraph.d.ts +19 -0
  50. package/dist/flowGraph.js +373 -0
  51. package/dist/flowGraph.js.map +1 -0
  52. package/dist/hyperlinkLabel.d.ts +19 -0
  53. package/dist/hyperlinkLabel.js +232 -0
  54. package/dist/hyperlinkLabel.js.map +1 -0
  55. package/dist/index.d.ts +48 -0
  56. package/dist/index.js +4200 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/interpolateTemplate.d.ts +44 -0
  59. package/dist/interpolateTemplate.js +188 -0
  60. package/dist/interpolateTemplate.js.map +1 -0
  61. package/dist/layerRotate.d.ts +10 -0
  62. package/dist/layerRotate.js +9 -0
  63. package/dist/layerRotate.js.map +1 -0
  64. package/dist/layerTypography.d.ts +36 -0
  65. package/dist/layerTypography.js +68 -0
  66. package/dist/layerTypography.js.map +1 -0
  67. package/dist/layers.d.ts +69 -0
  68. package/dist/layers.js +257 -0
  69. package/dist/layers.js.map +1 -0
  70. package/dist/layout/index.d.ts +57 -0
  71. package/dist/layout/index.js +151 -0
  72. package/dist/layout/index.js.map +1 -0
  73. package/dist/manifestBillingSlice.d.ts +17 -0
  74. package/dist/manifestBillingSlice.js +102 -0
  75. package/dist/manifestBillingSlice.js.map +1 -0
  76. package/dist/prepareAiGeneratedScreen.d.ts +17 -0
  77. package/dist/prepareAiGeneratedScreen.js +99 -0
  78. package/dist/prepareAiGeneratedScreen.js.map +1 -0
  79. package/dist/publish-exports.json +166 -0
  80. package/dist/responsive/breakpoints.d.ts +34 -0
  81. package/dist/responsive/breakpoints.js +52 -0
  82. package/dist/responsive/breakpoints.js.map +1 -0
  83. package/dist/responsive/index.d.ts +8 -0
  84. package/dist/responsive/index.js +307 -0
  85. package/dist/responsive/index.js.map +1 -0
  86. package/dist/responsive/layerResolve.d.ts +43 -0
  87. package/dist/responsive/layerResolve.js +168 -0
  88. package/dist/responsive/layerResolve.js.map +1 -0
  89. package/dist/responsive/merge.d.ts +19 -0
  90. package/dist/responsive/merge.js +74 -0
  91. package/dist/responsive/merge.js.map +1 -0
  92. package/dist/responsive/previewSafeAreaInsets.d.ts +14 -0
  93. package/dist/responsive/previewSafeAreaInsets.js +24 -0
  94. package/dist/responsive/previewSafeAreaInsets.js.map +1 -0
  95. package/dist/responsive/screenContainerResolve.d.ts +11 -0
  96. package/dist/responsive/screenContainerResolve.js +122 -0
  97. package/dist/responsive/screenContainerResolve.js.map +1 -0
  98. package/dist/responsive/screenShellInsets.d.ts +11 -0
  99. package/dist/responsive/screenShellInsets.js +26 -0
  100. package/dist/responsive/screenShellInsets.js.map +1 -0
  101. package/dist/restingMotion.d.ts +167 -0
  102. package/dist/restingMotion.js +484 -0
  103. package/dist/restingMotion.js.map +1 -0
  104. package/dist/rheoAgentManifestMerge.d.ts +33 -0
  105. package/dist/rheoAgentManifestMerge.js +55 -0
  106. package/dist/rheoAgentManifestMerge.js.map +1 -0
  107. package/dist/scaleInputStyle.d.ts +35 -0
  108. package/dist/scaleInputStyle.js +77 -0
  109. package/dist/scaleInputStyle.js.map +1 -0
  110. package/dist/scaleValidation.d.ts +9 -0
  111. package/dist/scaleValidation.js +21 -0
  112. package/dist/scaleValidation.js.map +1 -0
  113. package/dist/stateMachine.d.ts +105 -0
  114. package/dist/stateMachine.js +674 -0
  115. package/dist/stateMachine.js.map +1 -0
  116. package/dist/stepResponse-BXgoZ7o-.d.ts +112 -0
  117. package/dist/textInputValidation.d.ts +14 -0
  118. package/dist/textInputValidation.js +46 -0
  119. package/dist/textInputValidation.js.map +1 -0
  120. package/dist/translationPlaceholders.d.ts +9 -0
  121. package/dist/translationPlaceholders.js +52 -0
  122. package/dist/translationPlaceholders.js.map +1 -0
  123. package/dist/validation.d.ts +31 -0
  124. package/dist/validation.js +233 -0
  125. package/dist/validation.js.map +1 -0
  126. package/package.json +242 -0
@@ -0,0 +1,312 @@
1
+ import '@getrheo/contracts/localized';
2
+ import '@getrheo/contracts/layers';
3
+
4
+ // src/layers.ts
5
+ var walkLayers = (root, fn) => {
6
+ const visit = (l, depth) => {
7
+ fn(l, depth);
8
+ if (l.kind === "stack") l.children.forEach((c) => visit(c, depth + 1));
9
+ else if (l.kind === "carousel") l.slides.forEach((c) => visit(c, depth + 1));
10
+ else if (l.kind === "button") l.children.forEach((c) => visit(c, depth + 1));
11
+ else if (l.kind === "back_button") l.children.forEach((c) => visit(c, depth + 1));
12
+ else if (l.kind === "hyperlink") l.children.forEach((c) => visit(c, depth + 1));
13
+ else if (l.kind === "single_choice" || l.kind === "multiple_choice") {
14
+ l.children.forEach((c) => visit(c, depth + 1));
15
+ } else if (l.kind === "text_input" || l.kind === "scale_input") {
16
+ l.children?.forEach((c) => visit(c, depth + 1));
17
+ } else if (l.kind === "oauth_login") {
18
+ l.children.forEach((c) => visit(c, depth + 1));
19
+ } else if (l.kind === "oauth_provider" && l.variant === "custom") {
20
+ l.children.forEach((c) => visit(c, depth + 1));
21
+ } else if (l.kind === "email_password_auth") {
22
+ l.children.forEach((c) => visit(c, depth + 1));
23
+ } else if (l.kind === "email_password_field") {
24
+ l.children?.forEach((c) => visit(c, depth + 1));
25
+ } else if (l.kind === "email_password_submit") {
26
+ l.children.forEach((c) => visit(c, depth + 1));
27
+ }
28
+ };
29
+ visit(root, 0);
30
+ };
31
+ var walkScreen = (screen, fn) => {
32
+ if (screen.regions.header) walkLayers(screen.regions.header, fn);
33
+ walkLayers(screen.regions.body, fn);
34
+ if (screen.regions.footer) walkLayers(screen.regions.footer, fn);
35
+ };
36
+
37
+ // src/animations.ts
38
+ var EASING_BEZIERS = {
39
+ linear: [0, 0, 1, 1],
40
+ "ease-in": [0.42, 0, 1, 1],
41
+ "ease-out": [0, 0, 0.58, 1],
42
+ "ease-in-out": [0.42, 0, 0.58, 1],
43
+ // Material-style "standard" / "emphasized" curves — useful defaults
44
+ // for product animations without inviting per-platform divergence.
45
+ standard: [0.2, 0, 0, 1],
46
+ emphasized: [0.3, 0, 0, 1]
47
+ };
48
+ var sampleBezier = (t, [x1, y1, x2, y2]) => {
49
+ if (x1 === y1 && x2 === y2) return t;
50
+ const ax = 3 * x1 - 3 * x2 + 1;
51
+ const bx = 3 * x2 - 6 * x1;
52
+ const cx = 3 * x1;
53
+ const ay = 3 * y1 - 3 * y2 + 1;
54
+ const by = 3 * y2 - 6 * y1;
55
+ const cy = 3 * y1;
56
+ const xAt = (s2) => ((ax * s2 + bx) * s2 + cx) * s2;
57
+ const yAt = (s2) => ((ay * s2 + by) * s2 + cy) * s2;
58
+ const dxAt = (s2) => (3 * ax * s2 + 2 * bx) * s2 + cx;
59
+ let s = t;
60
+ for (let i = 0; i < 8; i++) {
61
+ const x = xAt(s) - t;
62
+ const dx = dxAt(s);
63
+ if (Math.abs(x) < 1e-6) return yAt(s);
64
+ if (Math.abs(dx) < 1e-6) break;
65
+ s -= x / dx;
66
+ }
67
+ let lo = 0;
68
+ let hi = 1;
69
+ s = t;
70
+ for (let i = 0; i < 24; i++) {
71
+ const x = xAt(s);
72
+ if (Math.abs(x - t) < 1e-6) return yAt(s);
73
+ if (x < t) lo = s;
74
+ else hi = s;
75
+ s = (lo + hi) / 2;
76
+ }
77
+ return yAt(s);
78
+ };
79
+ var sampleTrack = (track, tNorm) => {
80
+ const ks = track.keyframes;
81
+ if (tNorm <= ks[0].t) return ks[0].value;
82
+ if (tNorm >= ks[ks.length - 1].t) return ks[ks.length - 1].value;
83
+ let prev = ks[0];
84
+ let next = ks[ks.length - 1];
85
+ for (let i = 0; i < ks.length - 1; i++) {
86
+ if (ks[i].t <= tNorm && ks[i + 1].t >= tNorm) {
87
+ prev = ks[i];
88
+ next = ks[i + 1];
89
+ break;
90
+ }
91
+ }
92
+ const span = next.t - prev.t;
93
+ const localT = span === 0 ? 0 : (tNorm - prev.t) / span;
94
+ const eased = sampleBezier(localT, EASING_BEZIERS[prev.easing ?? "linear"]);
95
+ return prev.value + (next.value - prev.value) * eased;
96
+ };
97
+ var effectiveDelayMs = (clip, screen) => {
98
+ const base = clip.delayMs ?? 0;
99
+ if (clip.trigger === "stagger" && clip.staggerIndex !== void 0) {
100
+ const step = screen.stagger?.stepMs ?? 60;
101
+ return base + clip.staggerIndex * step;
102
+ }
103
+ return base;
104
+ };
105
+ var sampleClipAt = (clip, screen, tMs) => {
106
+ const delay = effectiveDelayMs(clip, screen);
107
+ const local = clip.durationMs > 0 ? (tMs - delay) / clip.durationMs : 1;
108
+ const tNorm = Math.min(1, Math.max(0, local));
109
+ const out = {};
110
+ for (const track of clip.tracks) {
111
+ out[track.property] = sampleTrack(track, tNorm);
112
+ }
113
+ return out;
114
+ };
115
+ var mergeSampledClips = (base, overlay) => {
116
+ const out = { ...base };
117
+ for (const k of Object.keys(overlay)) {
118
+ const v = overlay[k];
119
+ if (v !== void 0) out[k] = v;
120
+ }
121
+ return out;
122
+ };
123
+ var sampleLayerAnimAt = (screen, layerId, tMs) => {
124
+ const list = clipsByLayerId(screen).get(layerId) ?? [];
125
+ if (list.length === 0) return {};
126
+ const sorted = [...list].sort((a, b) => {
127
+ const da = effectiveDelayMs(a, screen);
128
+ const db = effectiveDelayMs(b, screen);
129
+ if (da !== db) return da - db;
130
+ return a.id.localeCompare(b.id);
131
+ });
132
+ let state = {};
133
+ for (let i = 0; i < sorted.length; i++) {
134
+ const clip = sorted[i];
135
+ const d = effectiveDelayMs(clip, screen);
136
+ const end = d + clip.durationMs;
137
+ if (tMs < d) {
138
+ if (clip.trigger === "unmount") continue;
139
+ if (clip.trigger !== "mount" && clip.trigger !== "stagger") continue;
140
+ const earlierAnimating = sorted.slice(0, i).some((earlier) => {
141
+ const dE = effectiveDelayMs(earlier, screen);
142
+ const endE = dE + earlier.durationMs;
143
+ return tMs >= dE && tMs < endE;
144
+ });
145
+ if (earlierAnimating) continue;
146
+ const pending = sampleClipAt(clip, screen, d);
147
+ state = mergeSampledClips(state, pending);
148
+ continue;
149
+ }
150
+ const at = tMs <= end ? tMs : end;
151
+ state = mergeSampledClips(state, sampleClipAt(clip, screen, at));
152
+ }
153
+ return state;
154
+ };
155
+ var layerHasAnimationClips = (screen, layerId) => (screen?.animations ?? []).some((c) => c.targetLayerId === layerId);
156
+ var screenAnimationsDurationMs = (screen) => {
157
+ if (!screen.animations || screen.animations.length === 0) return 0;
158
+ let max = 0;
159
+ for (const clip of screen.animations) {
160
+ const total = effectiveDelayMs(clip, screen) + clip.durationMs;
161
+ if (total > max) max = total;
162
+ }
163
+ return max;
164
+ };
165
+ var loaderLayerFillTimelineEndMs = (layer) => (layer.fillDelayMs ?? 0) + (layer.durationMs ?? 2e3);
166
+ var screenLoaderTimelineExtentMs = (screen) => {
167
+ let max = 0;
168
+ walkScreen(screen, (l) => {
169
+ if (l.kind !== "loader") return;
170
+ const end = loaderLayerFillTimelineEndMs(l);
171
+ if (end > max) max = end;
172
+ });
173
+ return max;
174
+ };
175
+ var loaderFillProgressAtGlobalMs = (tMs, fillDelayMs, durationMs) => {
176
+ if (durationMs <= 0) return tMs >= fillDelayMs ? 1 : 0;
177
+ return Math.min(1, Math.max(0, (tMs - fillDelayMs) / durationMs));
178
+ };
179
+ var DEFAULT_LOTTIE_PLAY_DURATION_MS = 2e3;
180
+ var lottieJsonDurationMs = (animationData) => {
181
+ const j = animationData;
182
+ const fr = typeof j.fr === "number" && j.fr > 0 ? j.fr : 60;
183
+ const ip = typeof j.ip === "number" ? j.ip : 0;
184
+ const op = typeof j.op === "number" ? j.op : 60;
185
+ const frames = Math.max(0, op - ip);
186
+ return Math.max(1, Math.round(frames / fr * 1e3));
187
+ };
188
+ var MIN_ANIMATION_TIMELINE_AUTHORING_SPAN_MS = 1e4;
189
+ var animationTimelineAuthoringEndMs = (screen) => screenAnimationsDurationMs(screen);
190
+ var migrateStaggerClipsToMount = (screen) => {
191
+ const staggerClipPresent = screen.animations?.some((c) => c.trigger === "stagger");
192
+ const staggerFieldPresent = screen.stagger !== void 0;
193
+ if (!staggerClipPresent && !staggerFieldPresent) return screen;
194
+ const step = screen.stagger?.stepMs ?? 60;
195
+ const { stagger: _st, ...rest } = screen;
196
+ if (!staggerClipPresent) {
197
+ return { ...rest };
198
+ }
199
+ const nextAnimations = (screen.animations ?? []).map((c) => {
200
+ if (c.trigger !== "stagger") return c;
201
+ const base = c.delayMs ?? 0;
202
+ const extra = (c.staggerIndex ?? 0) * step;
203
+ return {
204
+ ...c,
205
+ trigger: "mount",
206
+ delayMs: base + extra,
207
+ staggerIndex: void 0
208
+ };
209
+ });
210
+ return { ...rest, animations: nextAnimations };
211
+ };
212
+ var hasStaggerClip = (screen, layerId) => (screen.animations ?? []).some((c) => c.targetLayerId === layerId && c.trigger === "stagger");
213
+ var applyStaggerIndicesFromTreeOrder = (screen) => {
214
+ if (!screen.animations?.some((c) => c.trigger === "stagger")) return screen;
215
+ const staggerIndexByLayerId = /* @__PURE__ */ new Map();
216
+ const visitStackChildren = (stack) => {
217
+ let idx = 0;
218
+ for (const ch of stack.children) {
219
+ if (hasStaggerClip(screen, ch.id)) {
220
+ staggerIndexByLayerId.set(ch.id, idx);
221
+ idx += 1;
222
+ }
223
+ visit(ch);
224
+ }
225
+ };
226
+ const visit = (l) => {
227
+ if (l.kind === "stack") {
228
+ visitStackChildren(l);
229
+ return;
230
+ }
231
+ if (l.kind === "carousel") {
232
+ for (const s of l.slides) visit(s);
233
+ return;
234
+ }
235
+ if (l.kind === "button" || l.kind === "back_button") {
236
+ l.children.forEach(visit);
237
+ return;
238
+ }
239
+ if (l.kind === "hyperlink") {
240
+ l.children.forEach(visit);
241
+ return;
242
+ }
243
+ if (l.kind === "single_choice" || l.kind === "multiple_choice") {
244
+ l.children.forEach(visit);
245
+ return;
246
+ }
247
+ if (l.kind === "text_input" || l.kind === "scale_input") {
248
+ l.children?.forEach(visit);
249
+ return;
250
+ }
251
+ if (l.kind === "oauth_login") {
252
+ l.children.forEach(visit);
253
+ return;
254
+ }
255
+ if (l.kind === "oauth_provider" && l.variant === "custom") {
256
+ l.children.forEach(visit);
257
+ return;
258
+ }
259
+ if (l.kind === "email_password_auth") {
260
+ l.children.forEach(visit);
261
+ return;
262
+ }
263
+ if (l.kind === "email_password_field") {
264
+ l.children?.forEach(visit);
265
+ return;
266
+ }
267
+ if (l.kind === "email_password_submit") {
268
+ l.children.forEach(visit);
269
+ return;
270
+ }
271
+ };
272
+ if (screen.regions.header) visit(screen.regions.header);
273
+ visit(screen.regions.body);
274
+ if (screen.regions.footer) visit(screen.regions.footer);
275
+ const nextAnimations = screen.animations.map((c) => {
276
+ if (c.trigger !== "stagger") return c;
277
+ const nextIdx = staggerIndexByLayerId.get(c.targetLayerId);
278
+ if (nextIdx === void 0) return c;
279
+ if (c.staggerIndex === nextIdx) return c;
280
+ return { ...c, staggerIndex: nextIdx };
281
+ });
282
+ if (nextAnimations.every((c, i) => c === screen.animations[i])) return screen;
283
+ return { ...screen, animations: nextAnimations };
284
+ };
285
+ var clipsByLayerId = (screen) => {
286
+ const map = /* @__PURE__ */ new Map();
287
+ if (!screen.animations) return map;
288
+ for (const clip of screen.animations) {
289
+ const list = map.get(clip.targetLayerId) ?? [];
290
+ list.push(clip);
291
+ map.set(clip.targetLayerId, list);
292
+ }
293
+ return map;
294
+ };
295
+ var applyReducedMotion = (clip, policy) => {
296
+ if (policy === "play") return clip;
297
+ return {
298
+ ...clip,
299
+ durationMs: 0,
300
+ delayMs: 0,
301
+ tracks: clip.tracks.map((t) => ({
302
+ ...t,
303
+ keyframes: t.keyframes.map((k) => ({ ...k, t: k.t === 0 ? 0 : 1 }))
304
+ }))
305
+ };
306
+ };
307
+ var listAnimatablePropsForLayerKind = (_kind) => ["opacity", "translateX", "translateY", "scale"];
308
+ var isPropertyAllowedOnLayer = (layer, property) => listAnimatablePropsForLayerKind(layer.kind).includes(property);
309
+
310
+ export { DEFAULT_LOTTIE_PLAY_DURATION_MS, EASING_BEZIERS, MIN_ANIMATION_TIMELINE_AUTHORING_SPAN_MS, animationTimelineAuthoringEndMs, applyReducedMotion, applyStaggerIndicesFromTreeOrder, clipsByLayerId, effectiveDelayMs, isPropertyAllowedOnLayer, layerHasAnimationClips, listAnimatablePropsForLayerKind, loaderFillProgressAtGlobalMs, loaderLayerFillTimelineEndMs, lottieJsonDurationMs, mergeSampledClips, migrateStaggerClipsToMount, sampleClipAt, sampleLayerAnimAt, sampleTrack, screenAnimationsDurationMs, screenLoaderTimelineExtentMs };
311
+ //# sourceMappingURL=animations.js.map
312
+ //# sourceMappingURL=animations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layers.ts","../src/animations.ts"],"names":["s"],"mappings":"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","file":"animations.js","sourcesContent":["import type { Branding } from '@getrheo/contracts/dashboard';\nimport type { FlowManifest, Theme } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport {\n brandGradientFromThemedColor,\n brandGradientNativeLinear,\n brandGradientSolidFallback,\n isStoredLinearGradientCss,\n nativeLinearFromAngleAndStops,\n parseLinearGradientCss,\n resolveBrandGradientToken,\n type BrandGradientNativeLinear,\n} from './brandGradient';\nimport type {\n InputLayer,\n Layer,\n MultipleChoiceLayer,\n ScaleInputLayer,\n SingleChoiceLayer,\n StackLayer,\n TextInputLayer,\n ThemedColor,\n} from '@getrheo/contracts/layers';\nimport type { LocalizedText } from '@getrheo/contracts/localized';\nimport { resolveLocalizedText } from '@getrheo/contracts/localized';\nimport { isInputLayer } from '@getrheo/contracts/layers';\n\n/** Walk a layer tree depth-first. */\nexport const walkLayers = (root: Layer, fn: (l: Layer, depth: number) => void): void => {\n const visit = (l: Layer, depth: number): void => {\n fn(l, depth);\n if (l.kind === 'stack') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'carousel') l.slides.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'back_button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'hyperlink') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'single_choice' || l.kind === 'multiple_choice') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'text_input' || l.kind === 'scale_input') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_login') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_provider' && l.variant === 'custom') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_auth') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_field') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_submit') {\n l.children.forEach((c) => visit(c, depth + 1));\n }\n };\n visit(root, 0);\n};\n\n/** Walk every layer in a screen's regions (header → body → footer). */\nexport const walkScreen = (screen: Screen, fn: (l: Layer) => void): void => {\n if (screen.regions.header) walkLayers(screen.regions.header, fn);\n walkLayers(screen.regions.body, fn);\n if (screen.regions.footer) walkLayers(screen.regions.footer, fn);\n};\n\n/** Find the screen's lone input layer (if any). Schema enforces ≤1. */\nexport const findInputLayer = (screen: Screen): InputLayer | null => {\n let found: InputLayer | null = null;\n walkScreen(screen, (l) => {\n if (!found && isInputLayer(l)) found = l;\n });\n return found;\n};\n\n/** Input kinds that use a screen draft and require an explicit Continue to submit. */\nexport const findManualSubmitInputLayer = (\n screen: Screen,\n): MultipleChoiceLayer | TextInputLayer | ScaleInputLayer | null => {\n const input = findInputLayer(screen);\n if (!input) return null;\n if (input.kind === 'multiple_choice' || input.kind === 'text_input' || input.kind === 'scale_input') {\n return input;\n }\n return null;\n};\n\n/**\n * Whether the screen contains any Button layer that submits the screen\n * (i.e. `action.kind === 'continue'`). Used by input layers to decide\n * between auto-submit-on-tap (legacy behaviour for choice-only screens)\n * and writing into the screen-level draft for a Button to submit.\n */\nexport const screenHasContinueButton = (screen: Screen): boolean => {\n let found = false;\n walkScreen(screen, (l) => {\n if (l.kind === 'button' && l.action.kind === 'continue') found = true;\n });\n return found;\n};\n\n/**\n * Resolve a choice layer's option stack by stable optionId via its\n * binding. Returns null when the binding is missing or the bound child\n * was removed (manifest validation rejects that, but runtime stays safe).\n */\nexport const findOptionStackForChoice = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n): StackLayer | null => {\n const binding = layer.optionBindings.find((b) => b.optionId === optionId);\n if (!binding) return null;\n const stack = layer.children.find((c) => c.id === binding.rootLayerId);\n return stack ?? null;\n};\n\n/**\n * Best-effort textual label for a choice option, used by interpolation\n * (e.g. `{{ goal }}` rendering the chosen option's label) and by editor\n * surfaces that show option rows. Walks the option's child subtree\n * depth-first and returns the first `text` layer's content; falls back\n * to the option's stable id when no text is present.\n */\nexport const choiceOptionLabel = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n locale: string,\n): string => {\n const stack = findOptionStackForChoice(layer, optionId);\n if (!stack) return '';\n let foundText: LocalizedText | null = null;\n walkLayers(stack, (l) => {\n if (foundText) return;\n if (l.kind === 'text') foundText = l.text;\n });\n if (foundText) return resolveLocalizedText(foundText, locale);\n return optionId;\n};\n\n/** Find a layer in a screen by id, including nested children/slides. */\nexport const findLayerById = (screen: Screen, id: string): Layer | null => {\n let found: Layer | null = null;\n walkScreen(screen, (l) => {\n if (!found && l.id === id) found = l;\n });\n return found;\n};\n\n/** Collect all input fieldKeys across a manifest. */\nexport const collectFieldKeys = (manifest: FlowManifest): { fieldKey: string; screenId: string }[] => {\n const out: { fieldKey: string; screenId: string }[] = [];\n for (const screen of manifest.screens) {\n walkScreen(screen as unknown as Screen, (l) => {\n if (isInputLayer(l)) out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'checkbox') out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'email_password_auth') {\n out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n }\n });\n }\n return out;\n};\n\n/**\n * Pick a snake_case field key starting from `base` that is not in `used`\n * (e.g. `text` → `text_2` → `text_3` when `text` is taken).\n */\nexport const nextUniqueFieldKey = (base: string, used: Iterable<string>): string => {\n const set = used instanceof Set ? used : new Set(used);\n if (!set.has(base)) return base;\n let n = 2;\n while (set.has(`${base}_${n}`)) n += 1;\n return `${base}_${n}`;\n};\n\n/**\n * Resolve a token reference like `$primary` to a literal value from `theme`.\n * Pass-through for non-token strings; returns undefined for `undefined`.\n */\nexport const resolveTokens = <T extends string | undefined>(\n theme: Theme | undefined,\n value: T,\n): T | string => {\n if (value === undefined) return value;\n if (typeof value !== 'string' || !value.startsWith('$')) return value;\n const key = value.slice(1) as keyof Theme;\n const literal = theme?.[key];\n if (typeof literal === 'string') return literal;\n return value;\n};\n\n/**\n * Resolve a layer color for the current appearance (`light` | `dark`).\n * Plain string uses `resolveTokens` for both modes (legacy). Object form\n * picks `light` / `dark` with fallback to the other key when one is omitted.\n */\nexport const resolveThemedColor = (\n theme: Theme | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') return resolveTokens(theme, value) as string;\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n return resolveTokens(theme, raw) as string;\n};\n\n/**\n * Resolve a themed value used for CSS `background` (or RN background fill).\n * Supports `$brandGradient:<uuid>` when branding presets are provided; other values match {@link resolveThemedColor}.\n */\nexport const resolveThemedBackground = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') {\n if (value.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, value);\n }\n return resolveTokens(theme, value) as string;\n }\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n if (raw.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, raw);\n }\n return resolveTokens(theme, raw) as string;\n};\n\nexport const nativeBrandBackgroundFromThemedColor = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): { solid?: string; linear?: BrandGradientNativeLinear } => {\n const preset = brandGradientFromThemedColor(branding, palette, value);\n if (preset) {\n const lin = brandGradientNativeLinear(preset);\n if (lin) return { linear: lin };\n return { solid: brandGradientSolidFallback(preset) };\n }\n const bg = resolveThemedBackground(theme, branding, palette, value) as string | undefined;\n if (!bg) return {};\n const parsed = parseLinearGradientCss(bg);\n if (parsed) {\n return {\n linear: nativeLinearFromAngleAndStops(\n parsed.angleDeg,\n parsed.stops.map((s) => ({ color: s.color, offsetPct: s.offsetPct })),\n ),\n };\n }\n if (isStoredLinearGradientCss(bg)) {\n const first = bg.match(/#[0-9a-fA-F]{3,8}/);\n return { solid: first ? first[0] : '#808080' };\n }\n return { solid: bg };\n};\n","import {\n type AnimatableProperty,\n type AnimationClip,\n type EasingToken,\n type Keyframe,\n type KeyframeTrack,\n} from '@getrheo/contracts/animations';\nimport type { Layer, LayerKind, StackLayer } from '@getrheo/contracts/layers';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport { walkScreen } from './layers';\n\n/**\n * Cubic-bezier control points for every named easing token. The exact\n * numbers are shared between web (CSS keyframes / `cubic-bezier(...)`)\n * and native (Reanimated `Easing.bezier`) so playback matches sample by\n * sample.\n */\nexport const EASING_BEZIERS: Record<EasingToken, [number, number, number, number]> = {\n linear: [0, 0, 1, 1],\n 'ease-in': [0.42, 0, 1, 1],\n 'ease-out': [0, 0, 0.58, 1],\n 'ease-in-out': [0.42, 0, 0.58, 1],\n // Material-style \"standard\" / \"emphasized\" curves — useful defaults\n // for product animations without inviting per-platform divergence.\n standard: [0.2, 0, 0, 1],\n emphasized: [0.3, 0, 0, 1],\n};\n\nconst sampleBezier = (\n t: number,\n [x1, y1, x2, y2]: [number, number, number, number],\n): number => {\n // Robust numeric solver for the parametric cubic-bezier curve. We need\n // to find the parameter `s` such that `bezierX(s) === t`, then return\n // `bezierY(s)`. Newton-Raphson with a fallback bisection keeps us\n // accurate at the curve endpoints (where derivatives near zero make\n // pure Newton flaky).\n if (x1 === y1 && x2 === y2) return t;\n const ax = 3 * x1 - 3 * x2 + 1;\n const bx = 3 * x2 - 6 * x1;\n const cx = 3 * x1;\n const ay = 3 * y1 - 3 * y2 + 1;\n const by = 3 * y2 - 6 * y1;\n const cy = 3 * y1;\n const xAt = (s: number) => ((ax * s + bx) * s + cx) * s;\n const yAt = (s: number) => ((ay * s + by) * s + cy) * s;\n const dxAt = (s: number) => (3 * ax * s + 2 * bx) * s + cx;\n let s = t;\n for (let i = 0; i < 8; i++) {\n const x = xAt(s) - t;\n const dx = dxAt(s);\n if (Math.abs(x) < 1e-6) return yAt(s);\n if (Math.abs(dx) < 1e-6) break;\n s -= x / dx;\n }\n let lo = 0;\n let hi = 1;\n s = t;\n for (let i = 0; i < 24; i++) {\n const x = xAt(s);\n if (Math.abs(x - t) < 1e-6) return yAt(s);\n if (x < t) lo = s;\n else hi = s;\n s = (lo + hi) / 2;\n }\n return yAt(s);\n};\n\n/**\n * Map an authoring time `tNorm ∈ [0,1]` to the eased value for a single\n * track. Returns the final value when t ≥ last keyframe and the first\n * value when t ≤ first keyframe so renderers can hold pre/post values\n * without special-casing edges.\n */\nexport const sampleTrack = (track: KeyframeTrack, tNorm: number): number => {\n const ks = track.keyframes;\n if (tNorm <= ks[0]!.t) return ks[0]!.value;\n if (tNorm >= ks[ks.length - 1]!.t) return ks[ks.length - 1]!.value;\n let prev: Keyframe = ks[0]!;\n let next: Keyframe = ks[ks.length - 1]!;\n for (let i = 0; i < ks.length - 1; i++) {\n if (ks[i]!.t <= tNorm && ks[i + 1]!.t >= tNorm) {\n prev = ks[i]!;\n next = ks[i + 1]!;\n break;\n }\n }\n const span = next.t - prev.t;\n const localT = span === 0 ? 0 : (tNorm - prev.t) / span;\n const eased = sampleBezier(localT, EASING_BEZIERS[prev.easing ?? 'linear']);\n return prev.value + (next.value - prev.value) * eased;\n};\n\nexport type SampledClip = Partial<Record<AnimatableProperty, number>>;\n\n/** Effective delay for a clip given its owning screen's stagger config. */\nexport const effectiveDelayMs = (clip: AnimationClip, screen: Screen): number => {\n const base = clip.delayMs ?? 0;\n if (clip.trigger === 'stagger' && clip.staggerIndex !== undefined) {\n const step = screen.stagger?.stepMs ?? 60;\n return base + clip.staggerIndex * step;\n }\n return base;\n};\n\n/**\n * Sample every track of a clip at an absolute time `tMs` measured from\n * the clip's mount. Honors `delayMs` (incl. stagger). Always returns the\n * authored property keys, even if the clip has not yet started, so\n * renderers can treat the result as a stable style overlay.\n */\nexport const sampleClipAt = (\n clip: AnimationClip,\n screen: Screen,\n tMs: number,\n): SampledClip => {\n const delay = effectiveDelayMs(clip, screen);\n const local = clip.durationMs > 0 ? (tMs - delay) / clip.durationMs : 1;\n const tNorm = Math.min(1, Math.max(0, local));\n const out: SampledClip = {};\n for (const track of clip.tracks) {\n out[track.property] = sampleTrack(track, tNorm);\n }\n return out;\n};\n\n/** Merge sampled clips: later keys override; only defined keys from `overlay` win. */\nexport const mergeSampledClips = (base: SampledClip, overlay: SampledClip): SampledClip => {\n const out: SampledClip = { ...base };\n for (const k of Object.keys(overlay) as (keyof SampledClip)[]) {\n const v = overlay[k];\n if (v !== undefined) out[k] = v;\n }\n return out;\n};\n\n/**\n * Sample all clips for `layerId` at global screen time `tMs`.\n *\n * Clips are applied in order of increasing start time (`effectiveDelayMs`),\n * then stable `id`. Each clip contributes once its start time has been\n * reached; after it ends, its **final** sampled values stay merged into\n * state so later clips override animating properties. For **mount** and\n * **stagger** clips, while `tMs` is before that clip's delay, we merge its\n * **start** keyframe values unless some **earlier** clip is inside its own\n * `[delay, delay + duration)` window — so a delayed fade-in stays at opacity\n * 0 during the wait, but a move that overlaps the fade's delay still shows\n * default opacity until the fade segment begins. **Unmount** clips never\n * apply pre-delay sampling. This supports multiple appear / hide segments on\n * the same layer (web sim / builder scrub).\n *\n * **Native:** `LayerMotionShell` still uses the first mount + first unmount\n * clip only until RN playback is extended for arbitrary sequences.\n */\nexport const sampleLayerAnimAt = (screen: Screen, layerId: string, tMs: number): SampledClip => {\n const list = clipsByLayerId(screen).get(layerId) ?? [];\n if (list.length === 0) return {};\n\n const sorted = [...list].sort((a, b) => {\n const da = effectiveDelayMs(a, screen);\n const db = effectiveDelayMs(b, screen);\n if (da !== db) return da - db;\n return a.id.localeCompare(b.id);\n });\n\n let state: SampledClip = {};\n for (let i = 0; i < sorted.length; i++) {\n const clip = sorted[i]!;\n const d = effectiveDelayMs(clip, screen);\n const end = d + clip.durationMs;\n if (tMs < d) {\n if (clip.trigger === 'unmount') continue;\n if (clip.trigger !== 'mount' && clip.trigger !== 'stagger') continue;\n const earlierAnimating = sorted.slice(0, i).some((earlier) => {\n const dE = effectiveDelayMs(earlier, screen);\n const endE = dE + earlier.durationMs;\n return tMs >= dE && tMs < endE;\n });\n if (earlierAnimating) continue;\n const pending = sampleClipAt(clip, screen, d);\n state = mergeSampledClips(state, pending);\n continue;\n }\n const at = tMs <= end ? tMs : end;\n state = mergeSampledClips(state, sampleClipAt(clip, screen, at));\n }\n return state;\n};\n\n/** True if this layer has any animation clip (mount, unmount, or legacy stagger). */\nexport const layerHasAnimationClips = (screen: Screen | undefined, layerId: string): boolean =>\n (screen?.animations ?? []).some((c) => c.targetLayerId === layerId);\n\n/** Total time (ms) before the screen's animations are visually settled. */\nexport const screenAnimationsDurationMs = (screen: Screen): number => {\n if (!screen.animations || screen.animations.length === 0) return 0;\n let max = 0;\n for (const clip of screen.animations) {\n const total = effectiveDelayMs(clip, screen) + clip.durationMs;\n if (total > max) max = total;\n }\n return max;\n};\n\n/** End of the loader fill segment on the timeline (ms from screen mount), for one loader layer. */\nexport const loaderLayerFillTimelineEndMs = (layer: Extract<Layer, { kind: 'loader' }>): number =>\n (layer.fillDelayMs ?? 0) + (layer.durationMs ?? 2000);\n\n/** Latest end time (ms from screen mount) of any loader timed fill on this screen. */\nexport const screenLoaderTimelineExtentMs = (screen: Screen): number => {\n let max = 0;\n walkScreen(screen, (l) => {\n if (l.kind !== 'loader') return;\n const end = loaderLayerFillTimelineEndMs(l);\n if (end > max) max = end;\n });\n return max;\n};\n\n/**\n * Fill progress 0–1 for scrubber / motion clock time `tMs` (linear; no easing).\n */\nexport const loaderFillProgressAtGlobalMs = (\n tMs: number,\n fillDelayMs: number,\n durationMs: number,\n): number => {\n if (durationMs <= 0) return tMs >= fillDelayMs ? 1 : 0;\n return Math.min(1, Math.max(0, (tMs - fillDelayMs) / durationMs));\n};\n\n/** Default timeline play span when a Lottie layer has no {@link durationMs}. */\nexport const DEFAULT_LOTTIE_PLAY_DURATION_MS = 2_000;\n\ntype LottieJsonMeta = { fr?: number; ip?: number; op?: number };\n\n/** Duration (ms) from Lottie JSON `ip` / `op` / `fr` when present. */\nexport const lottieJsonDurationMs = (animationData: object): number => {\n const j = animationData as LottieJsonMeta;\n const fr = typeof j.fr === 'number' && j.fr > 0 ? j.fr : 60;\n const ip = typeof j.ip === 'number' ? j.ip : 0;\n const op = typeof j.op === 'number' ? j.op : 60;\n const frames = Math.max(0, op - ip);\n return Math.max(1, Math.round((frames / fr) * 1000));\n};\n\n/**\n * @deprecated Prefer {@link workbenchTimelineTotalMs} from `@getrheo/flow-runtime/restingMotion`.\n * Kept for tests; returns mount/unmount clip extent only (no 10s floor).\n */\nexport const MIN_ANIMATION_TIMELINE_AUTHORING_SPAN_MS = 10_000;\n\n/** Mount/unmount clip extent only — does not include loader/Lottie/video/resting spans. */\nexport const animationTimelineAuthoringEndMs = (screen: Screen): number =>\n screenAnimationsDurationMs(screen);\n\n/**\n * Convert legacy `stagger` clips to `mount` with combined delay and drop\n * `screen.stagger` so authoring uses a single delay per clip.\n */\nexport const migrateStaggerClipsToMount = (screen: Screen): Screen => {\n const staggerClipPresent = screen.animations?.some((c) => c.trigger === 'stagger');\n const staggerFieldPresent = screen.stagger !== undefined;\n if (!staggerClipPresent && !staggerFieldPresent) return screen;\n\n const step = screen.stagger?.stepMs ?? 60;\n const { stagger: _st, ...rest } = screen;\n\n if (!staggerClipPresent) {\n return { ...rest };\n }\n\n const nextAnimations = (screen.animations ?? []).map((c) => {\n if (c.trigger !== 'stagger') return c;\n const base = c.delayMs ?? 0;\n const extra = (c.staggerIndex ?? 0) * step;\n return {\n ...c,\n trigger: 'mount' as const,\n delayMs: base + extra,\n staggerIndex: undefined,\n };\n });\n\n return { ...rest, animations: nextAnimations };\n};\n\nconst hasStaggerClip = (screen: Screen, layerId: string): boolean =>\n (screen.animations ?? []).some((c) => c.targetLayerId === layerId && c.trigger === 'stagger');\n\n/**\n * Reassigns `staggerIndex` on every stagger clip from **direct child order**\n * under each {@link StackLayer}. Matches how authors think about sibling\n * sequencing in the layer tree.\n */\nexport const applyStaggerIndicesFromTreeOrder = (screen: Screen): Screen => {\n if (!screen.animations?.some((c) => c.trigger === 'stagger')) return screen;\n\n const staggerIndexByLayerId = new Map<string, number>();\n\n const visitStackChildren = (stack: StackLayer): void => {\n let idx = 0;\n for (const ch of stack.children) {\n if (hasStaggerClip(screen, ch.id)) {\n staggerIndexByLayerId.set(ch.id, idx);\n idx += 1;\n }\n visit(ch);\n }\n };\n\n const visit = (l: Layer): void => {\n if (l.kind === 'stack') {\n visitStackChildren(l);\n return;\n }\n if (l.kind === 'carousel') {\n for (const s of l.slides) visit(s);\n return;\n }\n if (l.kind === 'button' || l.kind === 'back_button') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'hyperlink') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'single_choice' || l.kind === 'multiple_choice') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'text_input' || l.kind === 'scale_input') {\n l.children?.forEach(visit);\n return;\n }\n if (l.kind === 'oauth_login') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'oauth_provider' && l.variant === 'custom') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'email_password_auth') {\n l.children.forEach(visit);\n return;\n }\n if (l.kind === 'email_password_field') {\n l.children?.forEach(visit);\n return;\n }\n if (l.kind === 'email_password_submit') {\n l.children.forEach(visit);\n return;\n }\n };\n\n if (screen.regions.header) visit(screen.regions.header);\n visit(screen.regions.body);\n if (screen.regions.footer) visit(screen.regions.footer);\n\n const nextAnimations = screen.animations.map((c) => {\n if (c.trigger !== 'stagger') return c;\n const nextIdx = staggerIndexByLayerId.get(c.targetLayerId);\n if (nextIdx === undefined) return c;\n if (c.staggerIndex === nextIdx) return c;\n return { ...c, staggerIndex: nextIdx };\n });\n\n if (nextAnimations.every((c, i) => c === screen.animations![i])) return screen;\n return { ...screen, animations: nextAnimations };\n};\n\n/**\n * Index clips by `targetLayerId` so renderers don't re-walk the full\n * animations array per layer per frame.\n */\nexport const clipsByLayerId = (screen: Screen): Map<string, AnimationClip[]> => {\n const map = new Map<string, AnimationClip[]>();\n if (!screen.animations) return map;\n for (const clip of screen.animations) {\n const list = map.get(clip.targetLayerId) ?? [];\n list.push(clip);\n map.set(clip.targetLayerId, list);\n }\n return map;\n};\n\n/**\n * Reduced-motion policy used by every runtime. The default behavior is\n * conservative: animations snap to their final keyframe (no movement),\n * and screen transitions become instantaneous. Authors who want more\n * latitude can extend this in the future without diverging the\n * renderers.\n */\nexport type ReducedMotionPolicy = 'play' | 'snap-to-end';\n\nexport const applyReducedMotion = (\n clip: AnimationClip,\n policy: ReducedMotionPolicy,\n): AnimationClip => {\n if (policy === 'play') return clip;\n return {\n ...clip,\n durationMs: 0,\n delayMs: 0,\n tracks: clip.tracks.map((t) => ({\n ...t,\n keyframes: t.keyframes.map((k) => ({ ...k, t: k.t === 0 ? 0 : 1 })),\n })),\n };\n};\n\n/**\n * Whitelist of animatable properties per layer kind. Keep this in sync\n * with renderer support so the editor can disable unsupported tracks\n * before they hit the manifest. Today every layer supports the same\n * style-token subset; we keep the function shape so future layer kinds\n * can opt-in / opt-out without schema changes.\n */\nexport const listAnimatablePropsForLayerKind = (\n _kind: LayerKind,\n): readonly AnimatableProperty[] => ['opacity', 'translateX', 'translateY', 'scale'];\n\nexport const isPropertyAllowedOnLayer = (\n layer: Layer,\n property: AnimatableProperty,\n): boolean => listAnimatablePropsForLayerKind(layer.kind).includes(property);\n"]}
@@ -0,0 +1,7 @@
1
+ import { Variant } from '@getrheo/contracts';
2
+
3
+ /** Stable string hash (FNV-1a 32-bit). Suitable for non-cryptographic bucketing. */
4
+ declare const fnv1a: (input: string) => number;
5
+ declare const assignVariant: (experimentId: string, appUserId: string, variants: Variant[]) => Variant | null;
6
+
7
+ export { assignVariant, fnv1a };
@@ -0,0 +1,25 @@
1
+ // src/assignment.ts
2
+ var fnv1a = (input) => {
3
+ let hash = 2166136261;
4
+ for (let i = 0; i < input.length; i++) {
5
+ hash ^= input.charCodeAt(i);
6
+ hash = hash * 16777619 >>> 0;
7
+ }
8
+ return hash >>> 0;
9
+ };
10
+ var assignVariant = (experimentId, appUserId, variants) => {
11
+ if (variants.length === 0) return null;
12
+ const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
13
+ if (totalWeight <= 0) return variants[0] ?? null;
14
+ const bucket = fnv1a(`${experimentId}:${appUserId}`) % totalWeight;
15
+ let acc = 0;
16
+ for (const v of variants) {
17
+ acc += v.weight;
18
+ if (bucket < acc) return v;
19
+ }
20
+ return variants[variants.length - 1] ?? null;
21
+ };
22
+
23
+ export { assignVariant, fnv1a };
24
+ //# sourceMappingURL=assignment.js.map
25
+ //# sourceMappingURL=assignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/assignment.ts"],"names":[],"mappings":";AAGO,IAAM,KAAA,GAAQ,CAAC,KAAA,KAA0B;AAC9C,EAAA,IAAI,IAAA,GAAO,UAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,IAAA,IAAQ,KAAA,CAAM,WAAW,CAAC,CAAA;AAC1B,IAAA,IAAA,GAAQ,OAAO,QAAA,KAAgB,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,IAAA,KAAS,CAAA;AAClB;AAEO,IAAM,aAAA,GAAgB,CAC3B,YAAA,EACA,SAAA,EACA,QAAA,KACmB;AACnB,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAClC,EAAA,MAAM,WAAA,GAAc,SAAS,MAAA,CAAO,CAAC,KAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AACjE,EAAA,IAAI,WAAA,IAAe,CAAA,EAAG,OAAO,QAAA,CAAS,CAAC,CAAA,IAAK,IAAA;AAC5C,EAAA,MAAM,SAAS,KAAA,CAAM,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,SAAS,EAAE,CAAA,GAAI,WAAA;AACvD,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,GAAA,IAAO,CAAA,CAAE,MAAA;AACT,IAAA,IAAI,MAAA,GAAS,KAAK,OAAO,CAAA;AAAA,EAC3B;AACA,EAAA,OAAO,QAAA,CAAS,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA,IAAK,IAAA;AAC1C","file":"assignment.js","sourcesContent":["import type { Variant } from '@getrheo/contracts';\n\n/** Stable string hash (FNV-1a 32-bit). Suitable for non-cryptographic bucketing. */\nexport const fnv1a = (input: string): number => {\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = (hash * 0x01000193) >>> 0;\n }\n return hash >>> 0;\n};\n\nexport const assignVariant = (\n experimentId: string,\n appUserId: string,\n variants: Variant[],\n): Variant | null => {\n if (variants.length === 0) return null;\n const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);\n if (totalWeight <= 0) return variants[0] ?? null;\n const bucket = fnv1a(`${experimentId}:${appUserId}`) % totalWeight;\n let acc = 0;\n for (const v of variants) {\n acc += v.weight;\n if (bucket < acc) return v;\n }\n return variants[variants.length - 1] ?? null;\n};\n"]}
@@ -0,0 +1,57 @@
1
+ import { Branding, BrandGradient } from '@getrheo/contracts/dashboard';
2
+ import { ThemedColor } from '@getrheo/contracts/layers';
3
+
4
+ declare const BRAND_GRADIENT_PREFIX: "$brandGradient:";
5
+ /** Serialize a branding gradient preset to a CSS `background` value. */
6
+ declare const brandGradientToCss: (g: BrandGradient) => string;
7
+ declare const isBrandGradientToken: (s: string) => boolean;
8
+ /**
9
+ * Resolve `$brandGradient:<uuid>` using app branding presets.
10
+ * Unknown or missing preset id → `undefined`.
11
+ */
12
+ declare const resolveBrandGradientToken: (branding: Branding | undefined, token: string) => string | undefined;
13
+ /** Resolve a manifest themed color to a branding gradient preset if it references `$brandGradient:`. */
14
+ declare const brandGradientFromThemedColor: (branding: Branding | undefined, palette: "light" | "dark", value: ThemedColor | undefined) => BrandGradient | undefined;
15
+ /** Native `LinearGradient` props for linear brand presets; `null` for radial (use solid fallback). */
16
+ type BrandGradientNativeLinear = {
17
+ colors: string[];
18
+ locations: number[];
19
+ start: {
20
+ x: number;
21
+ y: number;
22
+ };
23
+ end: {
24
+ x: number;
25
+ y: number;
26
+ };
27
+ };
28
+ declare const brandGradientNativeLinear: (g: BrandGradient) => BrandGradientNativeLinear | null;
29
+ declare const brandGradientSolidFallback: (g: BrandGradient) => string;
30
+ /** Normalize hex for stored CSS gradients (3 → 6 chars; strip alpha channel for 8-char hex). */
31
+ declare const normalizeHexForGradient: (hex: string) => string;
32
+ /** One color stop in a dashboard-authored `linear-gradient(...)` (percent along the axis). */
33
+ type LinearGradientStopModel = {
34
+ color: string;
35
+ offsetPct: number;
36
+ };
37
+ /** Build canonical `linear-gradient(<deg>deg, #hex <pct>%, ...)` with at least two stops. */
38
+ declare const buildLinearGradientCss: (angleDeg: number, stops: LinearGradientStopModel[]) => string;
39
+ declare const buildTwoStopLinearGradientCss: (angleDeg: number, color0: string, color1: string) => string;
40
+ declare const isStoredLinearGradientCss: (s: string) => boolean;
41
+ /** Parse dashboard-authored linear gradients with hex stops and explicit `%` positions. */
42
+ declare const parseLinearGradientCss: (s: string) => {
43
+ angleDeg: number;
44
+ stops: LinearGradientStopModel[];
45
+ } | null;
46
+ declare const parseTwoStopLinearGradientCss: (s: string) => {
47
+ angleDeg: number;
48
+ color0: string;
49
+ color1: string;
50
+ } | null;
51
+ declare const nativeLinearFromAngleAndStops: (angleDeg: number, stops: {
52
+ color: string;
53
+ offsetPct: number;
54
+ }[]) => BrandGradientNativeLinear;
55
+ declare const nativeLinearFromAngleAndTwoColors: (angleDeg: number, color0: string, color1: string) => BrandGradientNativeLinear;
56
+
57
+ export { BRAND_GRADIENT_PREFIX, type BrandGradientNativeLinear, type LinearGradientStopModel, brandGradientFromThemedColor, brandGradientNativeLinear, brandGradientSolidFallback, brandGradientToCss, buildLinearGradientCss, buildTwoStopLinearGradientCss, isBrandGradientToken, isStoredLinearGradientCss, nativeLinearFromAngleAndStops, nativeLinearFromAngleAndTwoColors, normalizeHexForGradient, parseLinearGradientCss, parseTwoStopLinearGradientCss, resolveBrandGradientToken };
@@ -0,0 +1,137 @@
1
+ // src/brandGradient.ts
2
+ var BRAND_GRADIENT_PREFIX = "$brandGradient:";
3
+ var brandGradientToCss = (g) => {
4
+ const stops = g.stops.map((s) => `${s.color} ${(s.offset * 100).toFixed(0)}%`).join(", ");
5
+ if (g.type === "linear") {
6
+ const angle = g.angle ?? 180;
7
+ return `linear-gradient(${angle}deg, ${stops})`;
8
+ }
9
+ return `radial-gradient(circle, ${stops})`;
10
+ };
11
+ var isBrandGradientToken = (s) => s.startsWith(BRAND_GRADIENT_PREFIX);
12
+ var resolveBrandGradientToken = (branding, token) => {
13
+ if (!isBrandGradientToken(token)) return void 0;
14
+ const id = token.slice(BRAND_GRADIENT_PREFIX.length);
15
+ const preset = branding?.gradientPresets.find((x) => x.id === id);
16
+ return preset ? brandGradientToCss(preset) : void 0;
17
+ };
18
+ var rawThemedString = (palette, value) => {
19
+ if (value === void 0) return void 0;
20
+ if (typeof value === "string") return value;
21
+ return palette === "dark" ? value.dark ?? value.light : value.light ?? value.dark;
22
+ };
23
+ var brandGradientFromThemedColor = (branding, palette, value) => {
24
+ const raw = rawThemedString(palette, value);
25
+ if (raw === void 0 || !isBrandGradientToken(raw)) return void 0;
26
+ const id = raw.slice(BRAND_GRADIENT_PREFIX.length);
27
+ return branding?.gradientPresets.find((x) => x.id === id);
28
+ };
29
+ var brandGradientNativeLinear = (g) => {
30
+ if (g.type !== "linear") return null;
31
+ const angleDeg = g.angle ?? 180;
32
+ const \u03B8 = angleDeg * Math.PI / 180;
33
+ const ux = Math.sin(\u03B8);
34
+ const uy = -Math.cos(\u03B8);
35
+ return {
36
+ colors: g.stops.map((s) => s.color),
37
+ locations: g.stops.map((s) => s.offset),
38
+ start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },
39
+ end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 }
40
+ };
41
+ };
42
+ var brandGradientSolidFallback = (g) => g.stops[0]?.color ?? "#808080";
43
+ var HEX_FOR_GRADIENT = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
44
+ var normalizeHexForGradient = (hex) => {
45
+ const t = hex.trim();
46
+ if (!HEX_FOR_GRADIENT.test(t)) return t;
47
+ if (t.length === 4) {
48
+ const [, r, g, b] = t;
49
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
50
+ }
51
+ if (t.length === 9) return t.slice(0, 7).toLowerCase();
52
+ return t.toLowerCase();
53
+ };
54
+ var clampPct = (n) => Math.min(100, Math.max(0, n));
55
+ var buildLinearGradientCss = (angleDeg, stops) => {
56
+ const a = Number.isFinite(angleDeg) ? angleDeg : 180;
57
+ const sorted = [...stops].map((s) => ({
58
+ offsetPct: clampPct(Number.isFinite(s.offsetPct) ? s.offsetPct : 0),
59
+ color: normalizeHexForGradient(s.color)
60
+ })).sort((x, y) => x.offsetPct - y.offsetPct);
61
+ if (sorted.length < 2) {
62
+ throw new Error("linear gradient requires at least 2 color stops");
63
+ }
64
+ for (const s of sorted) {
65
+ if (!HEX_FOR_GRADIENT.test(s.color)) {
66
+ throw new Error(`invalid gradient stop color: ${s.color}`);
67
+ }
68
+ }
69
+ const body = sorted.map((s) => `${s.color} ${s.offsetPct.toFixed(0)}%`).join(", ");
70
+ return `linear-gradient(${a}deg, ${body})`;
71
+ };
72
+ var buildTwoStopLinearGradientCss = (angleDeg, color0, color1) => buildLinearGradientCss(angleDeg, [
73
+ { color: color0, offsetPct: 0 },
74
+ { color: color1, offsetPct: 100 }
75
+ ]);
76
+ var isStoredLinearGradientCss = (s) => /^\s*linear-gradient\s*\(/i.test(s.trim());
77
+ var parseLinearGradientCss = (s) => {
78
+ const t = s.trim();
79
+ const head = t.match(/^\s*linear-gradient\s*\(\s*([-0-9.]+)\s*deg\s*,\s*(.*)\)\s*$/is);
80
+ if (!head) return null;
81
+ const angleStr = head[1];
82
+ const innerRaw = head[2];
83
+ if (angleStr === void 0 || innerRaw === void 0) return null;
84
+ const angleDeg = Number(angleStr);
85
+ if (!Number.isFinite(angleDeg)) return null;
86
+ const inner = innerRaw.trim();
87
+ if (!inner) return null;
88
+ const parts = inner.split(/,(?=\s*#)/);
89
+ const stops = [];
90
+ for (const part of parts) {
91
+ const p = part.trim();
92
+ const m = p.match(/^(#[0-9a-fA-F]{3,8})\s+([-0-9.]+)\s*%$/i);
93
+ if (!m) return null;
94
+ const hex = m[1];
95
+ const offsetStr = m[2];
96
+ if (hex === void 0 || offsetStr === void 0) return null;
97
+ const color = normalizeHexForGradient(hex);
98
+ const offsetPct = Number(offsetStr);
99
+ if (!Number.isFinite(offsetPct)) return null;
100
+ if (!HEX_FOR_GRADIENT.test(color)) return null;
101
+ stops.push({ color, offsetPct });
102
+ }
103
+ if (stops.length < 2) return null;
104
+ return { angleDeg, stops };
105
+ };
106
+ var parseTwoStopLinearGradientCss = (s) => {
107
+ const p = parseLinearGradientCss(s);
108
+ if (!p || p.stops.length !== 2) return null;
109
+ const sorted = [...p.stops].sort((a, b) => a.offsetPct - b.offsetPct);
110
+ const s0 = sorted[0];
111
+ const s1 = sorted[1];
112
+ if (!s0 || !s1 || s0.offsetPct !== 0 || s1.offsetPct !== 100) return null;
113
+ return { angleDeg: p.angleDeg, color0: s0.color, color1: s1.color };
114
+ };
115
+ var nativeLinearFromAngleAndStops = (angleDeg, stops) => {
116
+ const sorted = [...stops].map((s) => ({
117
+ color: normalizeHexForGradient(s.color),
118
+ offsetPct: clampPct(Number.isFinite(s.offsetPct) ? s.offsetPct : 0)
119
+ })).sort((a, b) => a.offsetPct - b.offsetPct);
120
+ const \u03B8 = angleDeg * Math.PI / 180;
121
+ const ux = Math.sin(\u03B8);
122
+ const uy = -Math.cos(\u03B8);
123
+ return {
124
+ colors: sorted.map((s) => s.color),
125
+ locations: sorted.map((s) => s.offsetPct / 100),
126
+ start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },
127
+ end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 }
128
+ };
129
+ };
130
+ var nativeLinearFromAngleAndTwoColors = (angleDeg, color0, color1) => nativeLinearFromAngleAndStops(angleDeg, [
131
+ { color: color0, offsetPct: 0 },
132
+ { color: color1, offsetPct: 100 }
133
+ ]);
134
+
135
+ export { BRAND_GRADIENT_PREFIX, brandGradientFromThemedColor, brandGradientNativeLinear, brandGradientSolidFallback, brandGradientToCss, buildLinearGradientCss, buildTwoStopLinearGradientCss, isBrandGradientToken, isStoredLinearGradientCss, nativeLinearFromAngleAndStops, nativeLinearFromAngleAndTwoColors, normalizeHexForGradient, parseLinearGradientCss, parseTwoStopLinearGradientCss, resolveBrandGradientToken };
136
+ //# sourceMappingURL=brandGradient.js.map
137
+ //# sourceMappingURL=brandGradient.js.map