|
|
|
|
@ -191,24 +191,8 @@ export function renderStaticCss(options: EidosConfig): string {
|
|
|
|
|
// Two-ring focus model: inner `inset` ring (width from token, 0 by
|
|
|
|
|
// default → invisible) + the outer ring. Every input component shares
|
|
|
|
|
// this so the focus affordance is uniform and theme-parameterised.
|
|
|
|
|
declarations.push(
|
|
|
|
|
cssVar(
|
|
|
|
|
'focus-ring',
|
|
|
|
|
'inset 0 0 0 var(--focus-ring-inner-width) var(--focus-ring-color), ' +
|
|
|
|
|
'0 0 0 var(--focus-ring-offset) var(--color-surface-default), ' +
|
|
|
|
|
'0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) ' +
|
|
|
|
|
'var(--focus-ring-color)'
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
declarations.push(
|
|
|
|
|
cssVar(
|
|
|
|
|
'focus-ring-error',
|
|
|
|
|
'inset 0 0 0 var(--focus-ring-inner-width) var(--focus-ring-color-error), ' +
|
|
|
|
|
'0 0 0 var(--focus-ring-offset) var(--color-surface-default), ' +
|
|
|
|
|
'0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) ' +
|
|
|
|
|
'var(--focus-ring-color-error)'
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
declarations.push(cssVar('focus-ring', focusRingShadow('focus-ring-color')));
|
|
|
|
|
declarations.push(cssVar('focus-ring-error', focusRingShadow('focus-ring-color-error')));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (primitives.press) {
|
|
|
|
|
@ -437,6 +421,15 @@ export function renderStaticCss(options: EidosConfig): string {
|
|
|
|
|
return blocks.join('\n\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function focusRingShadow(colorVar: string): string {
|
|
|
|
|
return (
|
|
|
|
|
`inset 0 0 0 var(--focus-ring-inner-width) var(--${colorVar}), ` +
|
|
|
|
|
'0 0 0 var(--focus-ring-offset) var(--color-surface-default), ' +
|
|
|
|
|
'0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) ' +
|
|
|
|
|
`var(--${colorVar})`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Accessibility — Windows High Contrast / `forced-colors`. The OS forces colors via
|
|
|
|
|
* `forced-color-adjust: auto`, which auto-maps borders / text / backgrounds to system
|
|
|
|
|
@ -740,16 +733,7 @@ export function renderThemeCss(
|
|
|
|
|
themeId: string,
|
|
|
|
|
renderOptions: RenderThemeCssOptions = {}
|
|
|
|
|
): string {
|
|
|
|
|
const theme = options.themes?.[themeId];
|
|
|
|
|
if (!theme) {
|
|
|
|
|
throw new EidosThemeNotFoundError(themeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const color = mergeThemeColor(
|
|
|
|
|
options.primitives.color?.scales,
|
|
|
|
|
options.semantics.color,
|
|
|
|
|
theme.color
|
|
|
|
|
);
|
|
|
|
|
const { theme, color } = resolveThemeColor(options, themeId);
|
|
|
|
|
// The theme SAYS what it is, so every block that paints it declares it:
|
|
|
|
|
// `color-scheme` rules the surface the UA paints and eidos cannot style
|
|
|
|
|
// (native `<select>` popup, form controls, scrollbars). First declaration,
|
|
|
|
|
@ -774,11 +758,7 @@ export function renderThemeCss(
|
|
|
|
|
? allScaleNames
|
|
|
|
|
: roleReferencedScaleNames(completedRoles, allScaleNames);
|
|
|
|
|
|
|
|
|
|
for (const scaleName of scaleNames) {
|
|
|
|
|
const scale = color.scales[scaleName];
|
|
|
|
|
if (scale) appendColorScaleDeclarations(declarations, scaleName, scale);
|
|
|
|
|
appendColorAlphaScaleDeclarations(declarations, scaleName, scale, color.alphaScales[scaleName]);
|
|
|
|
|
}
|
|
|
|
|
appendThemeScaleDeclarations(declarations, color, scaleNames);
|
|
|
|
|
|
|
|
|
|
for (const role of COLOR_ROLES) {
|
|
|
|
|
const definition = completedRoles[role];
|
|
|
|
|
@ -895,23 +875,10 @@ export function renderColorPaletteCss(
|
|
|
|
|
themeId: string,
|
|
|
|
|
renderOptions: RenderThemeCssOptions = {}
|
|
|
|
|
): string {
|
|
|
|
|
const theme = options.themes?.[themeId];
|
|
|
|
|
if (!theme) {
|
|
|
|
|
throw new EidosThemeNotFoundError(themeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const color = mergeThemeColor(
|
|
|
|
|
options.primitives.color?.scales,
|
|
|
|
|
options.semantics.color,
|
|
|
|
|
theme.color
|
|
|
|
|
);
|
|
|
|
|
const { color } = resolveThemeColor(options, themeId);
|
|
|
|
|
const declarations: string[] = [];
|
|
|
|
|
const scaleNames = new Set([...Object.keys(color.scales), ...Object.keys(color.alphaScales)]);
|
|
|
|
|
for (const scaleName of scaleNames) {
|
|
|
|
|
const scale = color.scales[scaleName];
|
|
|
|
|
if (scale) appendColorScaleDeclarations(declarations, scaleName, scale);
|
|
|
|
|
appendColorAlphaScaleDeclarations(declarations, scaleName, scale, color.alphaScales[scaleName]);
|
|
|
|
|
}
|
|
|
|
|
appendThemeScaleDeclarations(declarations, color, scaleNames);
|
|
|
|
|
return renderBlock(renderOptions.selector ?? getThemeSelector(themeId), declarations);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2018,6 +1985,18 @@ function appendThemeColorDeclarations(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function appendThemeScaleDeclarations(
|
|
|
|
|
declarations: string[],
|
|
|
|
|
color: ReturnType<typeof mergeThemeColor>,
|
|
|
|
|
scaleNames: ReadonlySet<string>
|
|
|
|
|
): void {
|
|
|
|
|
for (const scaleName of scaleNames) {
|
|
|
|
|
const scale = color.scales[scaleName];
|
|
|
|
|
if (scale) appendColorScaleDeclarations(declarations, scaleName, scale);
|
|
|
|
|
appendColorAlphaScaleDeclarations(declarations, scaleName, scale, color.alphaScales[scaleName]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function appendColorScaleDeclarations(
|
|
|
|
|
declarations: string[],
|
|
|
|
|
scaleName: string,
|
|
|
|
|
@ -2233,6 +2212,19 @@ function mergeThemeColor(
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveThemeColor(options: EidosConfig, themeId: string) {
|
|
|
|
|
const theme = options.themes?.[themeId];
|
|
|
|
|
if (!theme) {
|
|
|
|
|
throw new EidosThemeNotFoundError(themeId);
|
|
|
|
|
}
|
|
|
|
|
const color = mergeThemeColor(
|
|
|
|
|
options.primitives.color?.scales,
|
|
|
|
|
options.semantics.color,
|
|
|
|
|
theme.color
|
|
|
|
|
);
|
|
|
|
|
return { theme, color };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getThemeSelector(themeId: string): string {
|
|
|
|
|
return `[data-theme='${themeId}']`;
|
|
|
|
|
}
|
|
|
|
|
|