feat(eidos): radius foundation — --radius-default + --radius-factor + scaling-responsive (A2)

First increment of the A2 (radius) phase. The radius scale was fixed px; now:

- `--radius-default` (= var(--radius-sm)) — the archetype default radius for
  components without a radius reason of their own (Decisión 2 / §13).
- `--radius-factor` (default 1) — a global Radix-style roundness knob; a theme
  sets it on :root to dial all corners up/down at once.
- Radius responds to `--scaling`: each real radius emits
  `calc(base * var(--radius-factor) * var(--scaling))`. `none` (0) and `full`
  (the pill sentinel) stay verbatim.

At factor=1 + scaling=100 both resolve to 1 → identical output (zero regression).
Verified in-browser: md=6px default · --radius-default=4px · factor 1.5→9px (at
:root) · scaling 1.1→6.6px · full=9999px. check 0.

Pending (A2 increment 2): components consume --radius-default + adopt
[data-shape-nest] (drop the hand-rolled calc(--radius-md − space)); panel-radius
sub-decision (modal xl vs overlay lg).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
active-uix
dev 4 months ago
parent 5f14793b62
commit 845d6579d1

@ -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;

@ -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<string, string | number> | 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'],

Loading…
Cancel
Save

Powered by TurnKey Linux.