@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.
- package/dist/agentPrompt/index.d.ts +72 -0
- package/dist/agentPrompt/index.js +739 -0
- package/dist/agentPrompt/index.js.map +1 -0
- package/dist/aiFlowGenerationMerge.d.ts +32 -0
- package/dist/aiFlowGenerationMerge.js +120 -0
- package/dist/aiFlowGenerationMerge.js.map +1 -0
- package/dist/animations.d.ts +110 -0
- package/dist/animations.js +312 -0
- package/dist/animations.js.map +1 -0
- package/dist/assignment.d.ts +7 -0
- package/dist/assignment.js +25 -0
- package/dist/assignment.js.map +1 -0
- package/dist/brandGradient.d.ts +57 -0
- package/dist/brandGradient.js +137 -0
- package/dist/brandGradient.js.map +1 -0
- package/dist/brandGradientManifestIssues.d.ts +11 -0
- package/dist/brandGradientManifestIssues.js +302 -0
- package/dist/brandGradientManifestIssues.js.map +1 -0
- package/dist/buildFlowPreview.d.ts +7 -0
- package/dist/buildFlowPreview.js +81 -0
- package/dist/buildFlowPreview.js.map +1 -0
- package/dist/buttonVariantChrome.d.ts +26 -0
- package/dist/buttonVariantChrome.js +59 -0
- package/dist/buttonVariantChrome.js.map +1 -0
- package/dist/checkboxGlyphStyle.d.ts +31 -0
- package/dist/checkboxGlyphStyle.js +241 -0
- package/dist/checkboxGlyphStyle.js.map +1 -0
- package/dist/choiceOptionSelection.d.ts +11 -0
- package/dist/choiceOptionSelection.js +120 -0
- package/dist/choiceOptionSelection.js.map +1 -0
- package/dist/colorAlpha.d.ts +8 -0
- package/dist/colorAlpha.js +48 -0
- package/dist/colorAlpha.js.map +1 -0
- package/dist/counterLayer.d.ts +42 -0
- package/dist/counterLayer.js +95 -0
- package/dist/counterLayer.js.map +1 -0
- package/dist/decisionEval.d.ts +27 -0
- package/dist/decisionEval.js +197 -0
- package/dist/decisionEval.js.map +1 -0
- package/dist/dropShadow.d.ts +26 -0
- package/dist/dropShadow.js +76 -0
- package/dist/dropShadow.js.map +1 -0
- package/dist/emailPasswordAuthValidation.d.ts +16 -0
- package/dist/emailPasswordAuthValidation.js +25 -0
- package/dist/emailPasswordAuthValidation.js.map +1 -0
- package/dist/flowBuilderRules.d.ts +15 -0
- package/dist/flowBuilderRules.js +368 -0
- package/dist/flowBuilderRules.js.map +1 -0
- package/dist/flowGraph.d.ts +19 -0
- package/dist/flowGraph.js +373 -0
- package/dist/flowGraph.js.map +1 -0
- package/dist/hyperlinkLabel.d.ts +19 -0
- package/dist/hyperlinkLabel.js +232 -0
- package/dist/hyperlinkLabel.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +4200 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolateTemplate.d.ts +44 -0
- package/dist/interpolateTemplate.js +188 -0
- package/dist/interpolateTemplate.js.map +1 -0
- package/dist/layerRotate.d.ts +10 -0
- package/dist/layerRotate.js +9 -0
- package/dist/layerRotate.js.map +1 -0
- package/dist/layerTypography.d.ts +36 -0
- package/dist/layerTypography.js +68 -0
- package/dist/layerTypography.js.map +1 -0
- package/dist/layers.d.ts +69 -0
- package/dist/layers.js +257 -0
- package/dist/layers.js.map +1 -0
- package/dist/layout/index.d.ts +57 -0
- package/dist/layout/index.js +151 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/manifestBillingSlice.d.ts +17 -0
- package/dist/manifestBillingSlice.js +102 -0
- package/dist/manifestBillingSlice.js.map +1 -0
- package/dist/prepareAiGeneratedScreen.d.ts +17 -0
- package/dist/prepareAiGeneratedScreen.js +99 -0
- package/dist/prepareAiGeneratedScreen.js.map +1 -0
- package/dist/publish-exports.json +166 -0
- package/dist/responsive/breakpoints.d.ts +34 -0
- package/dist/responsive/breakpoints.js +52 -0
- package/dist/responsive/breakpoints.js.map +1 -0
- package/dist/responsive/index.d.ts +8 -0
- package/dist/responsive/index.js +307 -0
- package/dist/responsive/index.js.map +1 -0
- package/dist/responsive/layerResolve.d.ts +43 -0
- package/dist/responsive/layerResolve.js +168 -0
- package/dist/responsive/layerResolve.js.map +1 -0
- package/dist/responsive/merge.d.ts +19 -0
- package/dist/responsive/merge.js +74 -0
- package/dist/responsive/merge.js.map +1 -0
- package/dist/responsive/previewSafeAreaInsets.d.ts +14 -0
- package/dist/responsive/previewSafeAreaInsets.js +24 -0
- package/dist/responsive/previewSafeAreaInsets.js.map +1 -0
- package/dist/responsive/screenContainerResolve.d.ts +11 -0
- package/dist/responsive/screenContainerResolve.js +122 -0
- package/dist/responsive/screenContainerResolve.js.map +1 -0
- package/dist/responsive/screenShellInsets.d.ts +11 -0
- package/dist/responsive/screenShellInsets.js +26 -0
- package/dist/responsive/screenShellInsets.js.map +1 -0
- package/dist/restingMotion.d.ts +167 -0
- package/dist/restingMotion.js +484 -0
- package/dist/restingMotion.js.map +1 -0
- package/dist/rheoAgentManifestMerge.d.ts +33 -0
- package/dist/rheoAgentManifestMerge.js +55 -0
- package/dist/rheoAgentManifestMerge.js.map +1 -0
- package/dist/scaleInputStyle.d.ts +35 -0
- package/dist/scaleInputStyle.js +77 -0
- package/dist/scaleInputStyle.js.map +1 -0
- package/dist/scaleValidation.d.ts +9 -0
- package/dist/scaleValidation.js +21 -0
- package/dist/scaleValidation.js.map +1 -0
- package/dist/stateMachine.d.ts +105 -0
- package/dist/stateMachine.js +674 -0
- package/dist/stateMachine.js.map +1 -0
- package/dist/stepResponse-BXgoZ7o-.d.ts +112 -0
- package/dist/textInputValidation.d.ts +14 -0
- package/dist/textInputValidation.js +46 -0
- package/dist/textInputValidation.js.map +1 -0
- package/dist/translationPlaceholders.d.ts +9 -0
- package/dist/translationPlaceholders.js +52 -0
- package/dist/translationPlaceholders.js.map +1 -0
- package/dist/validation.d.ts +31 -0
- package/dist/validation.js +233 -0
- package/dist/validation.js.map +1 -0
- package/package.json +242 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { deepMergeStyle } from '@getrheo/flow-runtime/responsive/merge';
|
|
2
|
+
|
|
3
|
+
// src/buttonVariantChrome.ts
|
|
4
|
+
var FG_LIGHT = "#0a0a0a";
|
|
5
|
+
var FG_DARK = "#fafafa";
|
|
6
|
+
var buttonVariantChromeForTheme = (variant, theme) => {
|
|
7
|
+
const dark = theme === "dark";
|
|
8
|
+
switch (variant) {
|
|
9
|
+
case "primary":
|
|
10
|
+
return dark ? { bg: FG_DARK, color: FG_LIGHT, border: "transparent" } : { bg: FG_LIGHT, color: FG_DARK, border: "transparent" };
|
|
11
|
+
case "secondary":
|
|
12
|
+
return dark ? { bg: "transparent", color: FG_DARK, border: "#27272a" } : { bg: "transparent", color: FG_LIGHT, border: "#e4e4e7" };
|
|
13
|
+
case "ghost":
|
|
14
|
+
return dark ? { bg: "transparent", color: FG_DARK, border: "transparent" } : { bg: "transparent", color: FG_LIGHT, border: "transparent" };
|
|
15
|
+
case "destructive":
|
|
16
|
+
return dark ? { bg: "#ef4444", color: FG_DARK, border: "transparent" } : { bg: "#dc2626", color: FG_DARK, border: "transparent" };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var pairThemedColor = (light, dark) => light === dark ? light : { light, dark };
|
|
20
|
+
var buttonVariantAuthoringStyleDefaults = (variant) => {
|
|
21
|
+
const l = buttonVariantChromeForTheme(variant, "light");
|
|
22
|
+
const d = buttonVariantChromeForTheme(variant, "dark");
|
|
23
|
+
return {
|
|
24
|
+
/** Matches web sim `buttonBaseStyle` (radius, type scale, width). */
|
|
25
|
+
radius: 10,
|
|
26
|
+
fontSize: 13,
|
|
27
|
+
fontWeight: 600,
|
|
28
|
+
width: "full",
|
|
29
|
+
height: "auto",
|
|
30
|
+
background: pairThemedColor(l.bg, d.bg),
|
|
31
|
+
color: pairThemedColor(l.color, d.color),
|
|
32
|
+
border: {
|
|
33
|
+
width: 1,
|
|
34
|
+
color: pairThemedColor(l.border, d.border)
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
var mergeAuthoringButtonStyleWithLayer = (variant, style) => deepMergeStyle(
|
|
39
|
+
buttonVariantAuthoringStyleDefaults(variant),
|
|
40
|
+
style ?? {}
|
|
41
|
+
);
|
|
42
|
+
var buttonPaletteBorderFallback = (variant, theme, authoredStyle, resolvedBackground) => {
|
|
43
|
+
const authoredWidth = authoredStyle?.border?.width;
|
|
44
|
+
if (authoredWidth !== void 0) {
|
|
45
|
+
return { borderWidth: authoredWidth, borderColor: void 0 };
|
|
46
|
+
}
|
|
47
|
+
if (resolvedBackground === "transparent") {
|
|
48
|
+
return { borderWidth: 0, borderColor: void 0 };
|
|
49
|
+
}
|
|
50
|
+
const chrome = buttonVariantChromeForTheme(variant, theme);
|
|
51
|
+
return {
|
|
52
|
+
borderWidth: chrome.border === "transparent" ? 0 : 1,
|
|
53
|
+
borderColor: chrome.border === "transparent" ? void 0 : chrome.border
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export { buttonPaletteBorderFallback, buttonVariantAuthoringStyleDefaults, buttonVariantChromeForTheme, mergeAuthoringButtonStyleWithLayer };
|
|
58
|
+
//# sourceMappingURL=buttonVariantChrome.js.map
|
|
59
|
+
//# sourceMappingURL=buttonVariantChrome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/buttonVariantChrome.ts"],"names":[],"mappings":"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","file":"buttonVariantChrome.js","sourcesContent":["import type { ButtonLayerVariant, ButtonStyle, ThemedColor, WidthValue } from '@getrheo/contracts/layers';\nimport { deepMergeStyle } from '@getrheo/flow-runtime/responsive/merge';\n\nexport type ResolvedButtonVariantChrome = {\n bg: string;\n color: string;\n border: string;\n};\n\nconst FG_LIGHT = '#0a0a0a';\nconst FG_DARK = '#fafafa';\n\n/** Default fill, label, and outline for a preset — used by web sim and native previews. */\nexport const buttonVariantChromeForTheme = (\n variant: ButtonLayerVariant,\n theme: 'light' | 'dark',\n): ResolvedButtonVariantChrome => {\n const dark = theme === 'dark';\n switch (variant) {\n case 'primary':\n return dark\n ? { bg: FG_DARK, color: FG_LIGHT, border: 'transparent' }\n : { bg: FG_LIGHT, color: FG_DARK, border: 'transparent' };\n case 'secondary':\n return dark\n ? { bg: 'transparent', color: FG_DARK, border: '#27272a' }\n : { bg: 'transparent', color: FG_LIGHT, border: '#e4e4e7' };\n case 'ghost':\n return dark\n ? { bg: 'transparent', color: FG_DARK, border: 'transparent' }\n : { bg: 'transparent', color: FG_LIGHT, border: 'transparent' };\n case 'destructive':\n return dark\n ? { bg: '#ef4444', color: FG_DARK, border: 'transparent' }\n : { bg: '#dc2626', color: FG_DARK, border: 'transparent' };\n }\n};\n\nconst pairThemedColor = (light: string, dark: string): ThemedColor =>\n light === dark ? light : { light, dark };\n\n/**\n * Full variant chrome for manifests and variant-switch patches: themed fill/label/outline\n * plus layout/type tokens that match web sim `buttonBaseStyle` / native `buttonPalette` rows.\n */\nexport const buttonVariantAuthoringStyleDefaults = (\n variant: ButtonLayerVariant,\n): Partial<ButtonStyle> => {\n const l = buttonVariantChromeForTheme(variant, 'light');\n const d = buttonVariantChromeForTheme(variant, 'dark');\n return {\n /** Matches web sim `buttonBaseStyle` (radius, type scale, width). */\n radius: 10,\n fontSize: 13,\n fontWeight: 600,\n width: 'full' as WidthValue,\n height: 'auto',\n background: pairThemedColor(l.bg, d.bg),\n color: pairThemedColor(l.color, d.color),\n border: {\n width: 1,\n color: pairThemedColor(l.border, d.border),\n },\n };\n};\n\n/**\n * Deep-merge variant chrome under an authored `style` so manifests include everything\n * the sim paints by default (padding and other keys from `style` win on conflict).\n */\nexport const mergeAuthoringButtonStyleWithLayer = (\n variant: ButtonLayerVariant,\n style: ButtonStyle | undefined,\n): ButtonStyle =>\n deepMergeStyle(\n buttonVariantAuthoringStyleDefaults(variant) as Record<string, unknown>,\n (style ?? {}) as Record<string, unknown>,\n ) as ButtonStyle;\n\n/** Variant outline fallback when authored style omits `border` (flat iOS alert rows use transparent fill). */\nexport const buttonPaletteBorderFallback = (\n variant: ButtonLayerVariant,\n theme: 'light' | 'dark',\n authoredStyle: Pick<ButtonStyle, 'border' | 'background'> | undefined,\n resolvedBackground: string | undefined,\n): { borderWidth: number; borderColor?: string } => {\n const authoredWidth = authoredStyle?.border?.width;\n if (authoredWidth !== undefined) {\n return { borderWidth: authoredWidth, borderColor: undefined };\n }\n if (resolvedBackground === 'transparent') {\n return { borderWidth: 0, borderColor: undefined };\n }\n const chrome = buttonVariantChromeForTheme(variant, theme);\n return {\n borderWidth: chrome.border === 'transparent' ? 0 : 1,\n borderColor: chrome.border === 'transparent' ? undefined : chrome.border,\n };\n};\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CheckboxGlyphStyle } from '@getrheo/contracts/layers';
|
|
2
|
+
import { Theme } from '@getrheo/contracts/manifest';
|
|
3
|
+
import { Branding } from '@getrheo/contracts/dashboard';
|
|
4
|
+
import { BrandGradientNativeLinear } from './brandGradient.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Merge author patches into stored checkbox glyph style (inspector).
|
|
8
|
+
* `undefined` values in `patch` remove that key so defaults apply at render time.
|
|
9
|
+
*/
|
|
10
|
+
declare const mergeCheckboxGlyphStyle: (prev: CheckboxGlyphStyle | undefined, patch: Partial<CheckboxGlyphStyle>) => CheckboxGlyphStyle | undefined;
|
|
11
|
+
type ResolvedCheckboxGlyph = {
|
|
12
|
+
sizePx: number;
|
|
13
|
+
radiusPx: number;
|
|
14
|
+
/** CSS `background` (solid or gradient string). Web sim applies this directly. */
|
|
15
|
+
background: string | undefined;
|
|
16
|
+
/** Solid fill for native, or underlay when {@link nativeLinearGradient} is null. */
|
|
17
|
+
nativeBackgroundColor: string | undefined;
|
|
18
|
+
/** Brand linear gradient for native; radial presets use solid fallback only. */
|
|
19
|
+
nativeLinearGradient: BrandGradientNativeLinear | null;
|
|
20
|
+
borderWidth: number | undefined;
|
|
21
|
+
borderColor: string | undefined;
|
|
22
|
+
opacity: number;
|
|
23
|
+
checkColor: string | undefined;
|
|
24
|
+
shadow: CheckboxGlyphStyle['shadow'];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Resolved colors and numbers for painting the checkbox square (web or native).
|
|
28
|
+
*/
|
|
29
|
+
declare const resolveCheckboxGlyphForRender: (theme: Theme | undefined, palette: "light" | "dark", unchecked: CheckboxGlyphStyle | undefined, checkedOverlay: CheckboxGlyphStyle | undefined, isChecked: boolean, branding?: Branding) => ResolvedCheckboxGlyph;
|
|
30
|
+
|
|
31
|
+
export { type ResolvedCheckboxGlyph, mergeCheckboxGlyphStyle, resolveCheckboxGlyphForRender };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import '@getrheo/contracts/localized';
|
|
2
|
+
import '@getrheo/contracts/layers';
|
|
3
|
+
|
|
4
|
+
// src/brandGradient.ts
|
|
5
|
+
var BRAND_GRADIENT_PREFIX = "$brandGradient:";
|
|
6
|
+
var brandGradientToCss = (g) => {
|
|
7
|
+
const stops = g.stops.map((s) => `${s.color} ${(s.offset * 100).toFixed(0)}%`).join(", ");
|
|
8
|
+
if (g.type === "linear") {
|
|
9
|
+
const angle = g.angle ?? 180;
|
|
10
|
+
return `linear-gradient(${angle}deg, ${stops})`;
|
|
11
|
+
}
|
|
12
|
+
return `radial-gradient(circle, ${stops})`;
|
|
13
|
+
};
|
|
14
|
+
var isBrandGradientToken = (s) => s.startsWith(BRAND_GRADIENT_PREFIX);
|
|
15
|
+
var resolveBrandGradientToken = (branding, token) => {
|
|
16
|
+
if (!isBrandGradientToken(token)) return void 0;
|
|
17
|
+
const id = token.slice(BRAND_GRADIENT_PREFIX.length);
|
|
18
|
+
const preset = branding?.gradientPresets.find((x) => x.id === id);
|
|
19
|
+
return preset ? brandGradientToCss(preset) : void 0;
|
|
20
|
+
};
|
|
21
|
+
var rawThemedString = (palette, value) => {
|
|
22
|
+
if (value === void 0) return void 0;
|
|
23
|
+
if (typeof value === "string") return value;
|
|
24
|
+
return palette === "dark" ? value.dark ?? value.light : value.light ?? value.dark;
|
|
25
|
+
};
|
|
26
|
+
var brandGradientFromThemedColor = (branding, palette, value) => {
|
|
27
|
+
const raw = rawThemedString(palette, value);
|
|
28
|
+
if (raw === void 0 || !isBrandGradientToken(raw)) return void 0;
|
|
29
|
+
const id = raw.slice(BRAND_GRADIENT_PREFIX.length);
|
|
30
|
+
return branding?.gradientPresets.find((x) => x.id === id);
|
|
31
|
+
};
|
|
32
|
+
var brandGradientNativeLinear = (g) => {
|
|
33
|
+
if (g.type !== "linear") return null;
|
|
34
|
+
const angleDeg = g.angle ?? 180;
|
|
35
|
+
const \u03B8 = angleDeg * Math.PI / 180;
|
|
36
|
+
const ux = Math.sin(\u03B8);
|
|
37
|
+
const uy = -Math.cos(\u03B8);
|
|
38
|
+
return {
|
|
39
|
+
colors: g.stops.map((s) => s.color),
|
|
40
|
+
locations: g.stops.map((s) => s.offset),
|
|
41
|
+
start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },
|
|
42
|
+
end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 }
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
var brandGradientSolidFallback = (g) => g.stops[0]?.color ?? "#808080";
|
|
46
|
+
var HEX_FOR_GRADIENT = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
47
|
+
var normalizeHexForGradient = (hex) => {
|
|
48
|
+
const t = hex.trim();
|
|
49
|
+
if (!HEX_FOR_GRADIENT.test(t)) return t;
|
|
50
|
+
if (t.length === 4) {
|
|
51
|
+
const [, r, g, b] = t;
|
|
52
|
+
return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
if (t.length === 9) return t.slice(0, 7).toLowerCase();
|
|
55
|
+
return t.toLowerCase();
|
|
56
|
+
};
|
|
57
|
+
var clampPct = (n) => Math.min(100, Math.max(0, n));
|
|
58
|
+
var isStoredLinearGradientCss = (s) => /^\s*linear-gradient\s*\(/i.test(s.trim());
|
|
59
|
+
var parseLinearGradientCss = (s) => {
|
|
60
|
+
const t = s.trim();
|
|
61
|
+
const head = t.match(/^\s*linear-gradient\s*\(\s*([-0-9.]+)\s*deg\s*,\s*(.*)\)\s*$/is);
|
|
62
|
+
if (!head) return null;
|
|
63
|
+
const angleStr = head[1];
|
|
64
|
+
const innerRaw = head[2];
|
|
65
|
+
if (angleStr === void 0 || innerRaw === void 0) return null;
|
|
66
|
+
const angleDeg = Number(angleStr);
|
|
67
|
+
if (!Number.isFinite(angleDeg)) return null;
|
|
68
|
+
const inner = innerRaw.trim();
|
|
69
|
+
if (!inner) return null;
|
|
70
|
+
const parts = inner.split(/,(?=\s*#)/);
|
|
71
|
+
const stops = [];
|
|
72
|
+
for (const part of parts) {
|
|
73
|
+
const p = part.trim();
|
|
74
|
+
const m = p.match(/^(#[0-9a-fA-F]{3,8})\s+([-0-9.]+)\s*%$/i);
|
|
75
|
+
if (!m) return null;
|
|
76
|
+
const hex = m[1];
|
|
77
|
+
const offsetStr = m[2];
|
|
78
|
+
if (hex === void 0 || offsetStr === void 0) return null;
|
|
79
|
+
const color = normalizeHexForGradient(hex);
|
|
80
|
+
const offsetPct = Number(offsetStr);
|
|
81
|
+
if (!Number.isFinite(offsetPct)) return null;
|
|
82
|
+
if (!HEX_FOR_GRADIENT.test(color)) return null;
|
|
83
|
+
stops.push({ color, offsetPct });
|
|
84
|
+
}
|
|
85
|
+
if (stops.length < 2) return null;
|
|
86
|
+
return { angleDeg, stops };
|
|
87
|
+
};
|
|
88
|
+
var nativeLinearFromAngleAndStops = (angleDeg, stops) => {
|
|
89
|
+
const sorted = [...stops].map((s) => ({
|
|
90
|
+
color: normalizeHexForGradient(s.color),
|
|
91
|
+
offsetPct: clampPct(Number.isFinite(s.offsetPct) ? s.offsetPct : 0)
|
|
92
|
+
})).sort((a, b) => a.offsetPct - b.offsetPct);
|
|
93
|
+
const \u03B8 = angleDeg * Math.PI / 180;
|
|
94
|
+
const ux = Math.sin(\u03B8);
|
|
95
|
+
const uy = -Math.cos(\u03B8);
|
|
96
|
+
return {
|
|
97
|
+
colors: sorted.map((s) => s.color),
|
|
98
|
+
locations: sorted.map((s) => s.offsetPct / 100),
|
|
99
|
+
start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },
|
|
100
|
+
end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 }
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
var resolveTokens = (theme, value) => {
|
|
104
|
+
if (value === void 0) return value;
|
|
105
|
+
if (typeof value !== "string" || !value.startsWith("$")) return value;
|
|
106
|
+
const key = value.slice(1);
|
|
107
|
+
const literal = theme?.[key];
|
|
108
|
+
if (typeof literal === "string") return literal;
|
|
109
|
+
return value;
|
|
110
|
+
};
|
|
111
|
+
var resolveThemedColor = (theme, palette, value) => {
|
|
112
|
+
if (value === void 0) return void 0;
|
|
113
|
+
if (typeof value === "string") return resolveTokens(theme, value);
|
|
114
|
+
const raw = palette === "dark" ? value.dark ?? value.light : value.light ?? value.dark;
|
|
115
|
+
if (raw === void 0) return void 0;
|
|
116
|
+
return resolveTokens(theme, raw);
|
|
117
|
+
};
|
|
118
|
+
var resolveThemedBackground = (theme, branding, palette, value) => {
|
|
119
|
+
if (value === void 0) return void 0;
|
|
120
|
+
if (typeof value === "string") {
|
|
121
|
+
if (value.startsWith("$brandGradient:")) {
|
|
122
|
+
return resolveBrandGradientToken(branding, value);
|
|
123
|
+
}
|
|
124
|
+
return resolveTokens(theme, value);
|
|
125
|
+
}
|
|
126
|
+
const raw = palette === "dark" ? value.dark ?? value.light : value.light ?? value.dark;
|
|
127
|
+
if (raw === void 0) return void 0;
|
|
128
|
+
if (raw.startsWith("$brandGradient:")) {
|
|
129
|
+
return resolveBrandGradientToken(branding, raw);
|
|
130
|
+
}
|
|
131
|
+
return resolveTokens(theme, raw);
|
|
132
|
+
};
|
|
133
|
+
var nativeBrandBackgroundFromThemedColor = (theme, branding, palette, value) => {
|
|
134
|
+
const preset = brandGradientFromThemedColor(branding, palette, value);
|
|
135
|
+
if (preset) {
|
|
136
|
+
const lin = brandGradientNativeLinear(preset);
|
|
137
|
+
if (lin) return { linear: lin };
|
|
138
|
+
return { solid: brandGradientSolidFallback(preset) };
|
|
139
|
+
}
|
|
140
|
+
const bg = resolveThemedBackground(theme, branding, palette, value);
|
|
141
|
+
if (!bg) return {};
|
|
142
|
+
const parsed = parseLinearGradientCss(bg);
|
|
143
|
+
if (parsed) {
|
|
144
|
+
return {
|
|
145
|
+
linear: nativeLinearFromAngleAndStops(
|
|
146
|
+
parsed.angleDeg,
|
|
147
|
+
parsed.stops.map((s) => ({ color: s.color, offsetPct: s.offsetPct }))
|
|
148
|
+
)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (isStoredLinearGradientCss(bg)) {
|
|
152
|
+
const first = bg.match(/#[0-9a-fA-F]{3,8}/);
|
|
153
|
+
return { solid: first ? first[0] : "#808080" };
|
|
154
|
+
}
|
|
155
|
+
return { solid: bg };
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/checkboxGlyphStyle.ts
|
|
159
|
+
var DEFAULT_UNCHECKED = {
|
|
160
|
+
size: 18,
|
|
161
|
+
radius: 4,
|
|
162
|
+
border: { width: 2, color: { light: "#71717a", dark: "#a1a1aa" } },
|
|
163
|
+
background: "transparent",
|
|
164
|
+
opacity: 1
|
|
165
|
+
};
|
|
166
|
+
var DEFAULT_CHECKED_OVERLAY = {
|
|
167
|
+
background: { light: "#18181b", dark: "#e4e4e7" },
|
|
168
|
+
checkColor: { light: "#ffffff", dark: "#18181b" }
|
|
169
|
+
};
|
|
170
|
+
var mergeBorder = (a, b) => {
|
|
171
|
+
if (!a && !b) return void 0;
|
|
172
|
+
return { ...a, ...b };
|
|
173
|
+
};
|
|
174
|
+
var mergeGlyph = (a, b) => {
|
|
175
|
+
if (!b) return { ...a };
|
|
176
|
+
const out = { ...a };
|
|
177
|
+
Object.keys(b).forEach((k) => {
|
|
178
|
+
const v = b[k];
|
|
179
|
+
if (v === void 0) return;
|
|
180
|
+
if (k === "border") {
|
|
181
|
+
const merged = mergeBorder(out.border, v);
|
|
182
|
+
if (merged && Object.values(merged).some((x) => x !== void 0)) out.border = merged;
|
|
183
|
+
else delete out.border;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (k === "shadow") {
|
|
187
|
+
out.shadow = v;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
out[k] = v;
|
|
191
|
+
});
|
|
192
|
+
return out;
|
|
193
|
+
};
|
|
194
|
+
var mergeCheckboxGlyphStyle = (prev, patch) => {
|
|
195
|
+
const out = { ...prev ?? {} };
|
|
196
|
+
for (const key of Object.keys(patch)) {
|
|
197
|
+
const v = patch[key];
|
|
198
|
+
if (key === "border") {
|
|
199
|
+
if (v === void 0) delete out.border;
|
|
200
|
+
else out.border = mergeBorder(out.border, v);
|
|
201
|
+
if (out.border && !Object.values(out.border).some((x) => x !== void 0)) delete out.border;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (key === "shadow") {
|
|
205
|
+
if (v === void 0) delete out.shadow;
|
|
206
|
+
else out.shadow = v;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (v === void 0) delete out[key];
|
|
210
|
+
else out[key] = v;
|
|
211
|
+
}
|
|
212
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
213
|
+
};
|
|
214
|
+
var resolveCheckboxGlyphForRender = (theme, palette, unchecked, checkedOverlay, isChecked, branding) => {
|
|
215
|
+
const base = mergeGlyph(DEFAULT_UNCHECKED, unchecked);
|
|
216
|
+
const merged = isChecked ? mergeGlyph(mergeGlyph(base, DEFAULT_CHECKED_OVERLAY), checkedOverlay) : base;
|
|
217
|
+
const sizePx = merged.size ?? 18;
|
|
218
|
+
const radiusPx = merged.radius ?? 4;
|
|
219
|
+
const borderWidth = merged.border?.width;
|
|
220
|
+
const borderColor = resolveThemedColor(theme, palette, merged.border?.color);
|
|
221
|
+
const background = resolveThemedBackground(theme, branding, palette, merged.background);
|
|
222
|
+
const nb = nativeBrandBackgroundFromThemedColor(theme, branding, palette, merged.background);
|
|
223
|
+
const opacity = merged.opacity ?? 1;
|
|
224
|
+
const checkColor = isChecked ? resolveThemedColor(theme, palette, merged.checkColor) : void 0;
|
|
225
|
+
return {
|
|
226
|
+
sizePx,
|
|
227
|
+
radiusPx,
|
|
228
|
+
background,
|
|
229
|
+
nativeBackgroundColor: nb.solid,
|
|
230
|
+
nativeLinearGradient: nb.linear ?? null,
|
|
231
|
+
borderWidth,
|
|
232
|
+
borderColor,
|
|
233
|
+
opacity,
|
|
234
|
+
checkColor,
|
|
235
|
+
shadow: merged.shadow
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export { mergeCheckboxGlyphStyle, resolveCheckboxGlyphForRender };
|
|
240
|
+
//# sourceMappingURL=checkboxGlyphStyle.js.map
|
|
241
|
+
//# sourceMappingURL=checkboxGlyphStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/brandGradient.ts","../src/layers.ts","../src/checkboxGlyphStyle.ts"],"names":[],"mappings":"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","file":"checkboxGlyphStyle.js","sourcesContent":["import type { BrandGradient, Branding } from '@getrheo/contracts/dashboard';\nimport type { ThemedColor } from '@getrheo/contracts/layers';\n\nexport const BRAND_GRADIENT_PREFIX = '$brandGradient:' as const;\n\n/** Serialize a branding gradient preset to a CSS `background` value. */\nexport const brandGradientToCss = (g: BrandGradient): string => {\n const stops = g.stops.map((s) => `${s.color} ${(s.offset * 100).toFixed(0)}%`).join(', ');\n if (g.type === 'linear') {\n const angle = g.angle ?? 180;\n return `linear-gradient(${angle}deg, ${stops})`;\n }\n return `radial-gradient(circle, ${stops})`;\n};\n\nexport const isBrandGradientToken = (s: string): boolean => s.startsWith(BRAND_GRADIENT_PREFIX);\n\n/**\n * Resolve `$brandGradient:<uuid>` using app branding presets.\n * Unknown or missing preset id → `undefined`.\n */\nexport const resolveBrandGradientToken = (\n branding: Branding | undefined,\n token: string,\n): string | undefined => {\n if (!isBrandGradientToken(token)) return undefined;\n const id = token.slice(BRAND_GRADIENT_PREFIX.length);\n const preset = branding?.gradientPresets.find((x) => x.id === id);\n return preset ? brandGradientToCss(preset) : undefined;\n};\n\nconst rawThemedString = (\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') return value;\n return palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n};\n\n/** Resolve a manifest themed color to a branding gradient preset if it references `$brandGradient:`. */\nexport const brandGradientFromThemedColor = (\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): BrandGradient | undefined => {\n const raw = rawThemedString(palette, value);\n if (raw === undefined || !isBrandGradientToken(raw)) return undefined;\n const id = raw.slice(BRAND_GRADIENT_PREFIX.length);\n return branding?.gradientPresets.find((x) => x.id === id);\n};\n\n/** Native `LinearGradient` props for linear brand presets; `null` for radial (use solid fallback). */\nexport type BrandGradientNativeLinear = {\n colors: string[];\n locations: number[];\n start: { x: number; y: number };\n end: { x: number; y: number };\n};\n\nexport const brandGradientNativeLinear = (g: BrandGradient): BrandGradientNativeLinear | null => {\n if (g.type !== 'linear') return null;\n const angleDeg = g.angle ?? 180;\n const θ = (angleDeg * Math.PI) / 180;\n const ux = Math.sin(θ);\n const uy = -Math.cos(θ);\n return {\n colors: g.stops.map((s) => s.color),\n locations: g.stops.map((s) => s.offset),\n start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },\n end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 },\n };\n};\n\nexport const brandGradientSolidFallback = (g: BrandGradient): string => g.stops[0]?.color ?? '#808080';\n\nconst HEX_FOR_GRADIENT = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n\n/** Normalize hex for stored CSS gradients (3 → 6 chars; strip alpha channel for 8-char hex). */\nexport const normalizeHexForGradient = (hex: string): string => {\n const t = hex.trim();\n if (!HEX_FOR_GRADIENT.test(t)) return t;\n if (t.length === 4) {\n const [, r, g, b] = t;\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n if (t.length === 9) return t.slice(0, 7).toLowerCase();\n return t.toLowerCase();\n};\n\n/** One color stop in a dashboard-authored `linear-gradient(...)` (percent along the axis). */\nexport type LinearGradientStopModel = { color: string; offsetPct: number };\n\nconst clampPct = (n: number): number => Math.min(100, Math.max(0, n));\n\n/** Build canonical `linear-gradient(<deg>deg, #hex <pct>%, ...)` with at least two stops. */\nexport const buildLinearGradientCss = (angleDeg: number, stops: LinearGradientStopModel[]): string => {\n const a = Number.isFinite(angleDeg) ? angleDeg : 180;\n const sorted = [...stops]\n .map((s) => ({\n offsetPct: clampPct(Number.isFinite(s.offsetPct) ? s.offsetPct : 0),\n color: normalizeHexForGradient(s.color),\n }))\n .sort((x, y) => x.offsetPct - y.offsetPct);\n if (sorted.length < 2) {\n throw new Error('linear gradient requires at least 2 color stops');\n }\n for (const s of sorted) {\n if (!HEX_FOR_GRADIENT.test(s.color)) {\n throw new Error(`invalid gradient stop color: ${s.color}`);\n }\n }\n const body = sorted.map((s) => `${s.color} ${s.offsetPct.toFixed(0)}%`).join(', ');\n return `linear-gradient(${a}deg, ${body})`;\n};\n\nexport const buildTwoStopLinearGradientCss = (\n angleDeg: number,\n color0: string,\n color1: string,\n): string =>\n buildLinearGradientCss(angleDeg, [\n { color: color0, offsetPct: 0 },\n { color: color1, offsetPct: 100 },\n ]);\n\nexport const isStoredLinearGradientCss = (s: string): boolean =>\n /^\\s*linear-gradient\\s*\\(/i.test(s.trim());\n\n/** Parse dashboard-authored linear gradients with hex stops and explicit `%` positions. */\nexport const parseLinearGradientCss = (s: string): { angleDeg: number; stops: LinearGradientStopModel[] } | null => {\n const t = s.trim();\n const head = t.match(/^\\s*linear-gradient\\s*\\(\\s*([-0-9.]+)\\s*deg\\s*,\\s*(.*)\\)\\s*$/is);\n if (!head) return null;\n const angleStr = head[1];\n const innerRaw = head[2];\n if (angleStr === undefined || innerRaw === undefined) return null;\n const angleDeg = Number(angleStr);\n if (!Number.isFinite(angleDeg)) return null;\n const inner = innerRaw.trim();\n if (!inner) return null;\n const parts = inner.split(/,(?=\\s*#)/);\n const stops: LinearGradientStopModel[] = [];\n for (const part of parts) {\n const p = part.trim();\n const m = p.match(/^(#[0-9a-fA-F]{3,8})\\s+([-0-9.]+)\\s*%$/i);\n if (!m) return null;\n const hex = m[1];\n const offsetStr = m[2];\n if (hex === undefined || offsetStr === undefined) return null;\n const color = normalizeHexForGradient(hex);\n const offsetPct = Number(offsetStr);\n if (!Number.isFinite(offsetPct)) return null;\n if (!HEX_FOR_GRADIENT.test(color)) return null;\n stops.push({ color, offsetPct });\n }\n if (stops.length < 2) return null;\n return { angleDeg, stops };\n};\n\nexport const parseTwoStopLinearGradientCss = (\n s: string,\n): { angleDeg: number; color0: string; color1: string } | null => {\n const p = parseLinearGradientCss(s);\n if (!p || p.stops.length !== 2) return null;\n const sorted = [...p.stops].sort((a, b) => a.offsetPct - b.offsetPct);\n const s0 = sorted[0];\n const s1 = sorted[1];\n if (!s0 || !s1 || s0.offsetPct !== 0 || s1.offsetPct !== 100) return null;\n return { angleDeg: p.angleDeg, color0: s0.color, color1: s1.color };\n};\n\nexport const nativeLinearFromAngleAndStops = (\n angleDeg: number,\n stops: { color: string; offsetPct: number }[],\n): BrandGradientNativeLinear => {\n const sorted = [...stops]\n .map((s) => ({\n color: normalizeHexForGradient(s.color),\n offsetPct: clampPct(Number.isFinite(s.offsetPct) ? s.offsetPct : 0),\n }))\n .sort((a, b) => a.offsetPct - b.offsetPct);\n const θ = (angleDeg * Math.PI) / 180;\n const ux = Math.sin(θ);\n const uy = -Math.cos(θ);\n return {\n colors: sorted.map((s) => s.color),\n locations: sorted.map((s) => s.offsetPct / 100),\n start: { x: 0.5 - ux * 0.5, y: 0.5 - uy * 0.5 },\n end: { x: 0.5 + ux * 0.5, y: 0.5 + uy * 0.5 },\n };\n};\n\nexport const nativeLinearFromAngleAndTwoColors = (\n angleDeg: number,\n color0: string,\n color1: string,\n): BrandGradientNativeLinear =>\n nativeLinearFromAngleAndStops(angleDeg, [\n { color: color0, offsetPct: 0 },\n { color: color1, offsetPct: 100 },\n ]);\n","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 type { CheckboxGlyphStyle, Border, DropShadow } from '@getrheo/contracts/layers';\nimport type { Theme } from '@getrheo/contracts/manifest';\nimport type { Branding } from '@getrheo/contracts/dashboard';\nimport type { BrandGradientNativeLinear } from './brandGradient';\nimport {\n nativeBrandBackgroundFromThemedColor,\n resolveThemedColor,\n resolveThemedBackground,\n} from './layers';\n\nconst DEFAULT_UNCHECKED: CheckboxGlyphStyle = {\n size: 18,\n radius: 4,\n border: { width: 2, color: { light: '#71717a', dark: '#a1a1aa' } },\n background: 'transparent',\n opacity: 1,\n};\n\nconst DEFAULT_CHECKED_OVERLAY: CheckboxGlyphStyle = {\n background: { light: '#18181b', dark: '#e4e4e7' },\n checkColor: { light: '#ffffff', dark: '#18181b' },\n};\n\nconst mergeBorder = (a: Border | undefined, b: Border | undefined): Border | undefined => {\n if (!a && !b) return undefined;\n return { ...a, ...b };\n};\n\nconst mergeGlyph = (a: CheckboxGlyphStyle, b?: CheckboxGlyphStyle): CheckboxGlyphStyle => {\n if (!b) return { ...a };\n const out: CheckboxGlyphStyle = { ...a };\n (Object.keys(b) as (keyof CheckboxGlyphStyle)[]).forEach((k) => {\n const v = b[k];\n if (v === undefined) return;\n if (k === 'border') {\n const merged = mergeBorder(out.border, v as Border);\n if (merged && Object.values(merged).some((x) => x !== undefined)) out.border = merged;\n else delete out.border;\n return;\n }\n if (k === 'shadow') {\n out.shadow = v as DropShadow;\n return;\n }\n (out as Record<string, unknown>)[k] = v;\n });\n return out;\n};\n\n/**\n * Merge author patches into stored checkbox glyph style (inspector).\n * `undefined` values in `patch` remove that key so defaults apply at render time.\n */\nexport const mergeCheckboxGlyphStyle = (\n prev: CheckboxGlyphStyle | undefined,\n patch: Partial<CheckboxGlyphStyle>,\n): CheckboxGlyphStyle | undefined => {\n const out: CheckboxGlyphStyle = { ...(prev ?? {}) };\n for (const key of Object.keys(patch) as (keyof CheckboxGlyphStyle)[]) {\n const v = patch[key];\n if (key === 'border') {\n if (v === undefined) delete out.border;\n else out.border = mergeBorder(out.border, v as Border);\n if (out.border && !Object.values(out.border).some((x) => x !== undefined)) delete out.border;\n continue;\n }\n if (key === 'shadow') {\n if (v === undefined) delete out.shadow;\n else out.shadow = v as DropShadow;\n continue;\n }\n if (v === undefined) delete (out as Record<string, unknown>)[key];\n else (out as Record<string, unknown>)[key] = v;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n};\n\nexport type ResolvedCheckboxGlyph = {\n sizePx: number;\n radiusPx: number;\n /** CSS `background` (solid or gradient string). Web sim applies this directly. */\n background: string | undefined;\n /** Solid fill for native, or underlay when {@link nativeLinearGradient} is null. */\n nativeBackgroundColor: string | undefined;\n /** Brand linear gradient for native; radial presets use solid fallback only. */\n nativeLinearGradient: BrandGradientNativeLinear | null;\n borderWidth: number | undefined;\n borderColor: string | undefined;\n opacity: number;\n checkColor: string | undefined;\n shadow: CheckboxGlyphStyle['shadow'];\n};\n\n/**\n * Resolved colors and numbers for painting the checkbox square (web or native).\n */\nexport const resolveCheckboxGlyphForRender = (\n theme: Theme | undefined,\n palette: 'light' | 'dark',\n unchecked: CheckboxGlyphStyle | undefined,\n checkedOverlay: CheckboxGlyphStyle | undefined,\n isChecked: boolean,\n branding?: Branding,\n): ResolvedCheckboxGlyph => {\n const base = mergeGlyph(DEFAULT_UNCHECKED, unchecked);\n const merged = isChecked ? mergeGlyph(mergeGlyph(base, DEFAULT_CHECKED_OVERLAY), checkedOverlay) : base;\n\n const sizePx = merged.size ?? 18;\n const radiusPx = merged.radius ?? 4;\n const borderWidth = merged.border?.width;\n const borderColor = resolveThemedColor(theme, palette, merged.border?.color);\n const background = resolveThemedBackground(theme, branding, palette, merged.background);\n const nb = nativeBrandBackgroundFromThemedColor(theme, branding, palette, merged.background);\n const opacity = merged.opacity ?? 1;\n const checkColor = isChecked\n ? resolveThemedColor(theme, palette, merged.checkColor)\n : undefined;\n\n return {\n sizePx,\n radiusPx,\n background,\n nativeBackgroundColor: nb.solid,\n nativeLinearGradient: nb.linear ?? null,\n borderWidth,\n borderColor,\n opacity,\n checkColor,\n shadow: merged.shadow,\n };\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StackLayer } from '@getrheo/contracts/layers';
|
|
2
|
+
|
|
3
|
+
/** Icon id suffix: visible only when the containing choice option is selected. */
|
|
4
|
+
declare const CHOICE_OPTION_SELECTED_ICON_SUFFIX = "_sel";
|
|
5
|
+
/** Icon id suffix: visible only when the containing choice option is unselected. */
|
|
6
|
+
declare const CHOICE_OPTION_UNSELECTED_ICON_SUFFIX = "_unsel";
|
|
7
|
+
declare const stackWithSelectedStyle: (stack: StackLayer, isSelected: boolean, widthPx: number) => StackLayer;
|
|
8
|
+
/** Applies root + nested `selectedStyle` and toggles `_sel` / `_unsel` indicator icons. */
|
|
9
|
+
declare const applyChoiceOptionSelectionToStack: (stack: StackLayer, isSelected: boolean, widthPx: number) => StackLayer;
|
|
10
|
+
|
|
11
|
+
export { CHOICE_OPTION_SELECTED_ICON_SUFFIX, CHOICE_OPTION_UNSELECTED_ICON_SUFFIX, applyChoiceOptionSelectionToStack, stackWithSelectedStyle };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// src/responsive/breakpoints.ts
|
|
2
|
+
var TAILWIND_DEFAULT_BREAKPOINTS = {
|
|
3
|
+
sm: 640,
|
|
4
|
+
md: 768,
|
|
5
|
+
lg: 1024,
|
|
6
|
+
xl: 1280,
|
|
7
|
+
"2xl": 1536
|
|
8
|
+
};
|
|
9
|
+
var STYLE_BREAKPOINT_MERGE_ORDER = ["sm", "md", "lg", "xl", "2xl"];
|
|
10
|
+
var getScreenSizeBucketForWidth = (width) => {
|
|
11
|
+
const { sm, md, lg, xl, "2xl": xxl } = TAILWIND_DEFAULT_BREAKPOINTS;
|
|
12
|
+
if (width < sm) return "default";
|
|
13
|
+
if (width < md) return "sm";
|
|
14
|
+
if (width < lg) return "md";
|
|
15
|
+
if (width < xl) return "lg";
|
|
16
|
+
if (width < xxl) return "xl";
|
|
17
|
+
return "2xl";
|
|
18
|
+
};
|
|
19
|
+
var getActiveStyleBreakpointChain = (widthPx) => {
|
|
20
|
+
const bucket = getScreenSizeBucketForWidth(widthPx);
|
|
21
|
+
if (bucket === "default") return [];
|
|
22
|
+
const idx = STYLE_BREAKPOINT_MERGE_ORDER.indexOf(bucket);
|
|
23
|
+
if (idx < 0) return [];
|
|
24
|
+
return STYLE_BREAKPOINT_MERGE_ORDER.slice(0, idx + 1);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/responsive/merge.ts
|
|
28
|
+
var isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
29
|
+
var deepMergeStyle = (base, ...overrides) => {
|
|
30
|
+
let acc = base ? { ...base } : void 0;
|
|
31
|
+
for (const o of overrides) {
|
|
32
|
+
if (!o) continue;
|
|
33
|
+
acc = acc ?? {};
|
|
34
|
+
for (const [k, v] of Object.entries(o)) {
|
|
35
|
+
if (v === void 0) continue;
|
|
36
|
+
const prev = acc[k];
|
|
37
|
+
if (isPlainObject(v) && isPlainObject(prev)) {
|
|
38
|
+
const merged = deepMergeStyle(prev, v);
|
|
39
|
+
if (merged !== void 0) acc[k] = merged;
|
|
40
|
+
} else {
|
|
41
|
+
acc[k] = v;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return acc;
|
|
46
|
+
};
|
|
47
|
+
var mergeResponsivePartial = (base, breakpoints, widthPx) => {
|
|
48
|
+
const chain = getActiveStyleBreakpointChain(widthPx);
|
|
49
|
+
if (chain.length === 0) return base ? { ...base } : void 0;
|
|
50
|
+
let acc = base ? { ...base } : void 0;
|
|
51
|
+
for (const key of chain) {
|
|
52
|
+
const patch = breakpoints?.[key];
|
|
53
|
+
if (!patch) continue;
|
|
54
|
+
acc = deepMergeStyle(acc, patch);
|
|
55
|
+
}
|
|
56
|
+
return acc;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// src/responsive/layerResolve.ts
|
|
60
|
+
var resolveCommonStyleAtWidth = (base, breakpoints, widthPx) => mergeResponsivePartial(
|
|
61
|
+
base,
|
|
62
|
+
breakpoints,
|
|
63
|
+
widthPx
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// src/choiceOptionSelection.ts
|
|
67
|
+
var CHOICE_OPTION_SELECTED_ICON_SUFFIX = "_sel";
|
|
68
|
+
var CHOICE_OPTION_UNSELECTED_ICON_SUFFIX = "_unsel";
|
|
69
|
+
var stackWithSelectedStyle = (stack, isSelected, widthPx) => {
|
|
70
|
+
if (!isSelected || !stack.selectedStyle) return stack;
|
|
71
|
+
const resolved = resolveCommonStyleAtWidth(stack.style, stack.styleBreakpoints, widthPx);
|
|
72
|
+
return {
|
|
73
|
+
...stack,
|
|
74
|
+
style: { ...resolved ?? {}, ...stack.selectedStyle },
|
|
75
|
+
styleBreakpoints: void 0
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
var iconVisibilityForChoiceOption = (layer, isSelected) => {
|
|
79
|
+
const baseOpacity = layer.style?.opacity ?? 1;
|
|
80
|
+
if (layer.id.endsWith(CHOICE_OPTION_SELECTED_ICON_SUFFIX)) {
|
|
81
|
+
return {
|
|
82
|
+
...layer,
|
|
83
|
+
style: { ...layer.style, opacity: isSelected ? baseOpacity : 0 }
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (layer.id.endsWith(CHOICE_OPTION_UNSELECTED_ICON_SUFFIX)) {
|
|
87
|
+
return {
|
|
88
|
+
...layer,
|
|
89
|
+
style: { ...layer.style, opacity: isSelected ? 0 : baseOpacity }
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return layer;
|
|
93
|
+
};
|
|
94
|
+
var mapChoiceOptionChildForSelection = (child, isSelected, widthPx) => {
|
|
95
|
+
if (child.kind === "stack") {
|
|
96
|
+
const stack = child;
|
|
97
|
+
const nestedSelected = isSelected && !!stack.selectedStyle;
|
|
98
|
+
const styled = stackWithSelectedStyle(stack, nestedSelected, widthPx);
|
|
99
|
+
const children = styled.children?.map(
|
|
100
|
+
(c) => mapChoiceOptionChildForSelection(c, isSelected, widthPx)
|
|
101
|
+
);
|
|
102
|
+
return children ? { ...styled, children } : styled;
|
|
103
|
+
}
|
|
104
|
+
if (child.kind === "icon") {
|
|
105
|
+
return iconVisibilityForChoiceOption(child, isSelected);
|
|
106
|
+
}
|
|
107
|
+
return child;
|
|
108
|
+
};
|
|
109
|
+
var applyChoiceOptionSelectionToStack = (stack, isSelected, widthPx) => {
|
|
110
|
+
const styled = stackWithSelectedStyle(stack, isSelected, widthPx);
|
|
111
|
+
if (!styled.children) return styled;
|
|
112
|
+
return {
|
|
113
|
+
...styled,
|
|
114
|
+
children: styled.children.map((c) => mapChoiceOptionChildForSelection(c, isSelected, widthPx))
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export { CHOICE_OPTION_SELECTED_ICON_SUFFIX, CHOICE_OPTION_UNSELECTED_ICON_SUFFIX, applyChoiceOptionSelectionToStack, stackWithSelectedStyle };
|
|
119
|
+
//# sourceMappingURL=choiceOptionSelection.js.map
|
|
120
|
+
//# sourceMappingURL=choiceOptionSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/responsive/breakpoints.ts","../src/responsive/merge.ts","../src/responsive/layerResolve.ts","../src/choiceOptionSelection.ts"],"names":[],"mappings":"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","file":"choiceOptionSelection.js","sourcesContent":["/**\n * Tailwind CSS default `screens` min-width values (px). Single source of truth\n * for preview buckets, manifest breakpoints, and runtime style resolution.\n *\n * @see https://tailwindcss.com/docs/screens\n */\nexport const TAILWIND_DEFAULT_BREAKPOINTS = {\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n '2xl': 1536,\n} as const;\n\n/** Viewport classification used by preview UI and editing scope. */\nexport type ScreenSizeBucket = 'default' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n/** Ordered keys stored on layers (`styleBreakpoints`) and merged mobile-first. */\nexport const STYLE_BREAKPOINT_MERGE_ORDER = ['sm', 'md', 'lg', 'xl', '2xl'] as const;\nexport type StyleBreakpointKey = (typeof STYLE_BREAKPOINT_MERGE_ORDER)[number];\n\nexport const SCREEN_SIZE_BUCKET_ORDER: readonly ScreenSizeBucket[] = [\n 'default',\n 'sm',\n 'md',\n 'lg',\n 'xl',\n '2xl',\n] as const;\n\n/** Buckets shown in the flow builder inspector (xl / 2xl omitted from authoring UI). */\nexport const BUILDER_INSPECTOR_BUCKET_ORDER: readonly ScreenSizeBucket[] = [\n 'default',\n 'sm',\n 'md',\n 'lg',\n] as const;\n\n/** Human-readable bucket titles; ranges lie between consecutive breakpoints. */\nexport const SCREEN_SIZE_BUCKET_LABEL: Record<ScreenSizeBucket, string> = {\n default: 'Default (< 640px)',\n sm: 'sm (640–767px)',\n md: 'md (768–1023px)',\n lg: 'lg (1024–1279px)',\n xl: 'xl (1280–1535px)',\n '2xl': '2xl (1536px+)',\n};\n\n/** Fallback viewport width when no `previewWidthPx` is passed (simulator / static previews). */\nexport const DEFAULT_PREVIEW_VIEWPORT_WIDTH_PX = 390;\n\n/** Maps viewport width (CSS px) to the Tailwind viewport bucket. */\nexport const getScreenSizeBucketForWidth = (width: number): ScreenSizeBucket => {\n const { sm, md, lg, xl, '2xl': xxl } = TAILWIND_DEFAULT_BREAKPOINTS;\n if (width < sm) return 'default';\n if (width < md) return 'sm';\n if (width < lg) return 'md';\n if (width < xl) return 'lg';\n if (width < xxl) return 'xl';\n return '2xl';\n};\n\n/**\n * Breakpoint keys whose partials apply at this width (mobile-first), e.g.\n * width 800 → `['sm','md']`.\n */\nexport const getActiveStyleBreakpointChain = (widthPx: number): StyleBreakpointKey[] => {\n const bucket = getScreenSizeBucketForWidth(widthPx);\n if (bucket === 'default') return [];\n const idx = STYLE_BREAKPOINT_MERGE_ORDER.indexOf(bucket as StyleBreakpointKey);\n if (idx < 0) return [];\n return STYLE_BREAKPOINT_MERGE_ORDER.slice(0, idx + 1) as StyleBreakpointKey[];\n};\n","import {\n STYLE_BREAKPOINT_MERGE_ORDER,\n getActiveStyleBreakpointChain,\n} from './breakpoints';\nimport type { StyleBreakpointKey } from './breakpoints';\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n v !== null && typeof v === 'object' && !Array.isArray(v);\n\n/**\n * Deep-merge style-like objects: nested plain objects merge per-key; scalars\n * and arrays replace. Suitable for padding/margin/border/shadow objects.\n */\nexport const deepMergeStyle = <T extends Record<string, unknown>>(\n base: T | undefined,\n ...overrides: (Partial<T> | undefined)[]\n): T | undefined => {\n let acc: T | undefined = base ? ({ ...base } as T) : undefined;\n for (const o of overrides) {\n if (!o) continue;\n acc = acc ?? ({} as T);\n for (const [k, v] of Object.entries(o) as [keyof T, T[keyof T] | undefined][]) {\n if (v === undefined) continue;\n const prev = acc[k as keyof T] as unknown;\n if (isPlainObject(v) && isPlainObject(prev)) {\n const merged = deepMergeStyle(prev as Record<string, unknown>, v as Partial<T>);\n if (merged !== undefined) (acc as Record<string, unknown>)[k as string] = merged;\n } else {\n (acc as Record<string, unknown>)[k as string] = v as unknown;\n }\n }\n }\n return acc;\n};\n\n/**\n * Mobile-first merge: `base` applies below `sm`; each breakpoint partial stacks\n * from `sm` through the bucket implied by `widthPx`.\n */\nexport const mergeResponsivePartial = <T extends Record<string, unknown>>(\n base: Partial<T> | undefined,\n breakpoints: Partial<Record<StyleBreakpointKey, Partial<T>>> | undefined,\n widthPx: number,\n): Partial<T> | undefined => {\n const chain = getActiveStyleBreakpointChain(widthPx);\n if (chain.length === 0) return base ? { ...base } : undefined;\n let acc = base ? ({ ...base } as Partial<T>) : undefined;\n for (const key of chain) {\n const patch = breakpoints?.[key];\n if (!patch) continue;\n acc = deepMergeStyle(acc as Record<string, unknown> | undefined, patch as Partial<T>) as\n | Partial<T>\n | undefined;\n }\n return acc;\n};\n\n/**\n * Merge breakpoint partials up to and including `bucket` (not using viewport width).\n * Use when editing a specific bucket's effective preview.\n */\nexport const mergeResponsivePartialUpToBucket = <T extends Record<string, unknown>>(\n base: Partial<T> | undefined,\n breakpoints: Partial<Record<StyleBreakpointKey, Partial<T>>> | undefined,\n bucket: StyleBreakpointKey | 'default',\n): Partial<T> | undefined => {\n if (bucket === 'default') return base ? { ...base } : undefined;\n const end = STYLE_BREAKPOINT_MERGE_ORDER.indexOf(bucket);\n if (end < 0) return base ? { ...base } : undefined;\n let acc = base ? ({ ...base } as Partial<T>) : undefined;\n for (let i = 0; i <= end; i++) {\n const key = STYLE_BREAKPOINT_MERGE_ORDER[i]!;\n const patch = breakpoints?.[key];\n if (!patch) continue;\n acc = deepMergeStyle(acc as Record<string, unknown> | undefined, patch as Partial<T>) as\n | Partial<T>\n | undefined;\n }\n return acc;\n};\n","import type {\n BackButtonLayer,\n ButtonLayer,\n ButtonStyle,\n CommonLayoutHeight,\n CommonStyle,\n IconStyle,\n ImageStyle,\n LayerKind,\n StackLayer,\n TextLayer,\n TextStyle,\n WidthValue,\n} from '@getrheo/contracts/layers';\nimport {\n DEFAULT_LOADER_CIRCULAR_SIZE_PX,\n DEFAULT_LOADER_LINEAR_HEIGHT_PX,\n DEFAULT_LOADER_STROKE_WIDTH_PX,\n DEFAULT_PROGRESS_LINEAR_HEIGHT_PX,\n defaultGapForLayerKind,\n} from '../layout/scalarLayoutDefaults';\nimport type { StyleBreakpointKey } from './breakpoints';\nimport { getActiveStyleBreakpointChain } from './breakpoints';\nimport { mergeResponsivePartial, mergeResponsivePartialUpToBucket } from './merge';\n\n/**\n * Effective child spacing (px) for a layer, falling back to the per-kind\n * default and finally `0`. Single runtime source of truth so renderers stop\n * hard-coding `?? 8` / `?? 0`.\n */\nexport const resolveLayerGap = (kind: LayerKind, gap: number | undefined): number =>\n gap ?? defaultGapForLayerKind(kind) ?? 0;\n\n/** Effective bar thickness (px) for a linear progress bar. */\nexport const resolveProgressLinearHeightPx = (\n height: CommonLayoutHeight | undefined,\n): number => (typeof height === 'number' ? height : DEFAULT_PROGRESS_LINEAR_HEIGHT_PX);\n\n/** Effective bar thickness (px) for a linear loader. */\nexport const resolveLoaderLinearHeightPx = (\n height: CommonLayoutHeight | undefined,\n): number => (typeof height === 'number' ? height : DEFAULT_LOADER_LINEAR_HEIGHT_PX);\n\n/** Effective diameter (px) for a circular loader (sized via `style.width`). */\nexport const resolveLoaderCircularSizePx = (width: WidthValue | undefined): number =>\n typeof width === 'number' ? width : DEFAULT_LOADER_CIRCULAR_SIZE_PX;\n\n/** Effective ring thickness (px) for a circular loader. */\nexport const resolveLoaderStrokeWidthPx = (strokeWidth: number | undefined): number =>\n strokeWidth ?? DEFAULT_LOADER_STROKE_WIDTH_PX;\n\nexport type StackLayoutBreakpointPatch = {\n gap?: number;\n direction?: 'vertical' | 'horizontal';\n};\n\nexport type ButtonLayoutBreakpointPatch = {\n gap?: number;\n direction?: 'vertical' | 'horizontal';\n};\n\nexport const resolveCommonStyleAtWidth = (\n base: CommonStyle | undefined,\n breakpoints:\n | Partial<Record<StyleBreakpointKey, Partial<CommonStyle>>>\n | undefined,\n widthPx: number,\n): CommonStyle | undefined =>\n mergeResponsivePartial(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n widthPx,\n ) as CommonStyle | undefined;\n\nexport const resolveTextStyleAtWidth = (\n base: TextStyle | undefined,\n breakpoints:\n | Partial<Record<StyleBreakpointKey, Partial<TextStyle>>>\n | undefined,\n widthPx: number,\n): TextStyle | undefined =>\n mergeResponsivePartial(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n widthPx,\n ) as TextStyle | undefined;\n\nexport const resolveImageStyleAtWidth = (\n base: ImageStyle | undefined,\n breakpoints:\n | Partial<Record<StyleBreakpointKey, Partial<ImageStyle>>>\n | undefined,\n widthPx: number,\n): ImageStyle | undefined =>\n mergeResponsivePartial(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n widthPx,\n ) as ImageStyle | undefined;\n\nexport const resolveIconStyleAtWidth = (\n base: IconStyle | undefined,\n breakpoints:\n | Partial<Record<StyleBreakpointKey, Partial<IconStyle>>>\n | undefined,\n widthPx: number,\n): IconStyle | undefined =>\n mergeResponsivePartial(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n widthPx,\n ) as IconStyle | undefined;\n\nexport const resolveButtonStyleAtWidth = (\n base: ButtonStyle | undefined,\n breakpoints:\n | Partial<Record<StyleBreakpointKey, Partial<ButtonStyle>>>\n | undefined,\n widthPx: number,\n): ButtonStyle | undefined =>\n mergeResponsivePartial(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n widthPx,\n ) as ButtonStyle | undefined;\n\nconst mergeLayoutScalars = <T extends Record<string, unknown>>(\n base: T,\n breakpoints: Partial<Record<StyleBreakpointKey, Partial<T>>> | undefined,\n widthPx: number,\n): T => {\n const chain = getActiveStyleBreakpointChain(widthPx);\n let acc = { ...base };\n for (const key of chain) {\n const p = breakpoints?.[key];\n if (!p) continue;\n acc = { ...acc, ...p };\n }\n return acc;\n};\n\nexport const resolveStackLayoutAtWidth = (\n layer: Pick<\n StackLayer,\n 'gap' | 'direction' | 'stackLayoutBreakpoints'\n >,\n widthPx: number,\n): { gap: number | undefined; direction: StackLayer['direction'] } => {\n const base = {\n gap: layer.gap,\n direction: layer.direction,\n };\n const merged = mergeLayoutScalars(\n base,\n layer.stackLayoutBreakpoints as\n | Partial<Record<StyleBreakpointKey, Partial<{ gap?: number; direction?: StackLayer['direction'] }>>>\n | undefined,\n widthPx,\n );\n return {\n gap: merged.gap,\n direction: merged.direction ?? layer.direction,\n };\n};\n\nexport const resolveButtonLayoutAtWidth = (\n layer: Pick<ButtonLayer | BackButtonLayer, 'gap' | 'direction' | 'buttonLayoutBreakpoints'>,\n widthPx: number,\n): { gap: number | undefined; direction: ButtonLayer['direction'] | undefined } => {\n const merged = mergeLayoutScalars(\n { gap: layer.gap, direction: layer.direction },\n layer.buttonLayoutBreakpoints as\n | Partial<\n Record<\n StyleBreakpointKey,\n Partial<{ gap?: number; direction?: ButtonLayer['direction'] }>\n >\n >\n | undefined,\n widthPx,\n );\n return { gap: merged.gap, direction: merged.direction };\n};\n\n/** Effective styles for editor preview at the bucket implied by device width. */\nexport const resolveTextStyleForEditBucket = (\n base: TextStyle | undefined,\n breakpoints: TextLayer['styleBreakpoints'],\n bucket: StyleBreakpointKey | 'default',\n): TextStyle | undefined =>\n mergeResponsivePartialUpToBucket(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n bucket,\n ) as TextStyle | undefined;\n\nexport const resolveCommonStyleForEditBucket = (\n base: CommonStyle | undefined,\n breakpoints: StackLayer['styleBreakpoints'],\n bucket: StyleBreakpointKey | 'default',\n): CommonStyle | undefined =>\n mergeResponsivePartialUpToBucket(\n base as Record<string, unknown> | undefined,\n breakpoints as Partial<Record<StyleBreakpointKey, Partial<Record<string, unknown>>>> | undefined,\n bucket,\n ) as CommonStyle | undefined;\n","import type { IconLayer, Layer, StackLayer } from '@getrheo/contracts/layers';\nimport { resolveCommonStyleAtWidth } from './responsive/layerResolve';\n\n/** Icon id suffix: visible only when the containing choice option is selected. */\nexport const CHOICE_OPTION_SELECTED_ICON_SUFFIX = '_sel';\n\n/** Icon id suffix: visible only when the containing choice option is unselected. */\nexport const CHOICE_OPTION_UNSELECTED_ICON_SUFFIX = '_unsel';\n\nexport const stackWithSelectedStyle = (\n stack: StackLayer,\n isSelected: boolean,\n widthPx: number,\n): StackLayer => {\n if (!isSelected || !stack.selectedStyle) return stack;\n const resolved = resolveCommonStyleAtWidth(stack.style, stack.styleBreakpoints, widthPx);\n return {\n ...stack,\n style: { ...(resolved ?? {}), ...stack.selectedStyle },\n styleBreakpoints: undefined,\n };\n};\n\nconst iconVisibilityForChoiceOption = (layer: IconLayer, isSelected: boolean): IconLayer => {\n const baseOpacity = layer.style?.opacity ?? 1;\n if (layer.id.endsWith(CHOICE_OPTION_SELECTED_ICON_SUFFIX)) {\n return {\n ...layer,\n style: { ...layer.style, opacity: isSelected ? baseOpacity : 0 },\n };\n }\n if (layer.id.endsWith(CHOICE_OPTION_UNSELECTED_ICON_SUFFIX)) {\n return {\n ...layer,\n style: { ...layer.style, opacity: isSelected ? 0 : baseOpacity },\n };\n }\n return layer;\n};\n\nconst mapChoiceOptionChildForSelection = (\n child: Layer,\n isSelected: boolean,\n widthPx: number,\n): Layer => {\n if (child.kind === 'stack') {\n const stack = child as StackLayer;\n const nestedSelected = isSelected && !!stack.selectedStyle;\n const styled = stackWithSelectedStyle(stack, nestedSelected, widthPx);\n const children = styled.children?.map((c) =>\n mapChoiceOptionChildForSelection(c, isSelected, widthPx),\n );\n return children ? ({ ...styled, children } as StackLayer) : styled;\n }\n if (child.kind === 'icon') {\n return iconVisibilityForChoiceOption(child, isSelected);\n }\n return child;\n};\n\n/** Applies root + nested `selectedStyle` and toggles `_sel` / `_unsel` indicator icons. */\nexport const applyChoiceOptionSelectionToStack = (\n stack: StackLayer,\n isSelected: boolean,\n widthPx: number,\n): StackLayer => {\n const styled = stackWithSelectedStyle(stack, isSelected, widthPx);\n if (!styled.children) return styled;\n return {\n ...styled,\n children: styled.children.map((c) => mapChoiceOptionChildForSelection(c, isSelected, widthPx)),\n };\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multiply the alpha of a resolved CSS color by `factor` (0–1).
|
|
3
|
+
* Used so text layers can dim only the background fill without applying `opacity` to the whole node.
|
|
4
|
+
* Supports #RGB, #RRGGBB, #RRGGBBAA, rgb(), rgba(). Unrecognized strings are returned as-is (no alpha change).
|
|
5
|
+
*/
|
|
6
|
+
declare const multiplyColorAlpha: (color: string | undefined, factor: number | undefined) => string | undefined;
|
|
7
|
+
|
|
8
|
+
export { multiplyColorAlpha };
|