diff --git a/src/uix/eidos/generated/base.css b/src/uix/eidos/generated/base.css index 750dd66cb..5da5ff9a0 100644 --- a/src/uix/eidos/generated/base.css +++ b/src/uix/eidos/generated/base.css @@ -154,13 +154,15 @@ --control-height-lg: calc(44px * var(--density-control-scale) * var(--scaling)); --control-height-xl: calc(52px * var(--density-control-scale) * var(--scaling)); --control-height-xxl: calc(60px * var(--density-control-scale) * var(--scaling)); + --radius-factor: 1; --radius-none: 0px; - --radius-sm: 4px; - --radius-md: 6px; - --radius-lg: 10px; - --radius-xl: 16px; - --radius-xxl: 20px; + --radius-sm: calc(4px * var(--radius-factor) * var(--scaling)); + --radius-md: calc(6px * var(--radius-factor) * var(--scaling)); + --radius-lg: calc(10px * var(--radius-factor) * var(--scaling)); + --radius-xl: calc(16px * var(--radius-factor) * var(--scaling)); + --radius-xxl: calc(20px * var(--radius-factor) * var(--scaling)); --radius-full: 9999px; + --radius-default: var(--radius-sm); --border-width-none: 0px; --border-width-thin: 1px; --border-width-medium: 2px; diff --git a/src/uix/eidos/lib/render-css.ts b/src/uix/eidos/lib/render-css.ts index 52247be9d..891506d2a 100644 --- a/src/uix/eidos/lib/render-css.ts +++ b/src/uix/eidos/lib/render-css.ts @@ -166,7 +166,7 @@ export function renderStaticCss(options: EidosConfig): string { primitives.controlHeight, 'density-control-scale' ) - appendRecordDeclarations(declarations, 'radius', primitives.radius) + appendRadiusDeclarations(declarations, primitives.radius) if (primitives.border) { appendBorderDeclarations(declarations, primitives.border) @@ -2248,6 +2248,33 @@ function appendScaledMetricDeclarations( } } +// Radius takes the global `--radius-factor` (Radix-style roundness knob, default 1) +// AND the `--scaling` zoom, multiplicatively — corners stay proportional when a theme +// dials roundness or the user zooms. At factor=1 + scaling=100 both are 1, so output +// equals the raw value (no regression). `none` (0) and `full` (the pill sentinel) are +// emitted verbatim — a factor/zoom must not curve a square corner nor shrink the pill. +// Also emits `--radius-default` (= sm), the archetype default for components without a +// radius reason of their own (Decisión 2 / §13). +function appendRadiusDeclarations( + declarations: string[], + radius: Record | undefined +): void { + if (!radius) return + declarations.push(cssVar('radius-factor', '1')) + for (const [name, value] of Object.entries(radius)) { + const raw = String(value).trim() + const num = parseFloat(raw) + const scalable = name !== 'none' && name !== 'full' && Number.isFinite(num) && num !== 0 + declarations.push( + cssVar( + `radius-${name}`, + scalable ? `calc(${raw} * var(--radius-factor) * var(--scaling))` : raw + ) + ) + } + declarations.push(cssVar('radius-default', 'var(--radius-sm)')) +} + function mergeThemeColor( primitiveScales: ColorScales | undefined, semanticColor: EidosConfig['semantics']['color'],