igniteui-theming
Version:
A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.
163 lines (156 loc) • 5.77 kB
JavaScript
import { themingImporter } from "../utils/theming-resolve.js";
import * as sass from "sass-embedded";
//#region src/generators/css.ts
/**
* Generate CSS custom properties for a standard palette.
*
* This function compiles Sass code that uses the palette() function and
* @include palette() mixin, then returns the compiled CSS output.
*
* @example
* const result = await generatePaletteCss({
* primary: '#1976d2',
* secondary: '#ff9800',
* surface: '#fafafa',
* variant: 'light'
* });
* // result.css contains :root { --ig-primary-50: ...; --ig-primary-100: ...; ... }
*/
async function generatePaletteCss(options) {
const variant = options.variant ?? "light";
const paletteArgs = [
`$primary: ${options.primary}`,
`$secondary: ${options.secondary}`,
`$surface: ${options.surface}`
];
if (options.gray) paletteArgs.push(`$gray: ${options.gray}`);
if (options.info) paletteArgs.push(`$info: ${options.info}`);
if (options.success) paletteArgs.push(`$success: ${options.success}`);
if (options.warn) paletteArgs.push(`$warn: ${options.warn}`);
if (options.error) paletteArgs.push(`$error: ${options.error}`);
const sassCode = `
@use 'igniteui-theming/sass/color' as *;
$palette: palette(
${paletteArgs.join(",\n ")}
);
@include palette($palette);
`;
try {
const importers = options._importers ?? [themingImporter];
return {
css: (await sass.compileStringAsync(sassCode, {
importers,
style: "expanded"
})).css,
description: `Generated CSS custom properties for a ${variant} palette with primary color ${options.primary}`
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to compile palette CSS: ${message}`);
}
}
/**
* Generate CSS custom properties for a custom palette.
*
* This function generates Sass code for the custom palette structure
* (using either shades() function or explicit values), compiles it,
* and returns the CSS output.
*/
async function generateCustomPaletteCss(options) {
const variant = options.variant ?? "light";
const { generateCustomPaletteCode } = await import("../utils/sass.js");
const sassCode = `
@use 'igniteui-theming/sass/color' as *;
${generateCustomPaletteCode({
variant,
variableName: "custom",
surfaceColor: options.surfaceColor,
colors: options.colors
}).join("\n")}
@include palette($custom-palette);
`;
try {
const importers = options._importers ?? [themingImporter];
return {
css: (await sass.compileStringAsync(sassCode, {
importers,
style: "expanded"
})).css,
description: `Generated CSS custom properties for a custom ${variant} palette`
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to compile custom palette CSS: ${message}`);
}
}
/**
* Format CSS output for display.
* Adds a header comment and ensures consistent formatting.
*/
function formatCssOutput(css, description) {
return `/* Generated by Ignite UI Theming MCP Server */
/* ${description} */
` + css;
}
/**
* Generate CSS custom properties for a component theme.
*
* This function compiles Sass code that uses the component theme function
* and @include tokens() mixin, then returns the compiled CSS output.
*
* @example
* const result = await generateComponentThemeCss({
* platform: 'webcomponents',
* designSystem: 'bootstrap',
* variant: 'light',
* component: 'button',
* tokens: { background: '#1976d2', 'text-color': 'white' },
* selector: 'igc-button'
* });
* // result.css contains: igc-button { --ig-button-background: var(--ig-button-background, #1976d2); ... }
*/
async function generateComponentThemeCss(options) {
const { COMPONENT_METADATA, getComponentTheme, getThemingSelector, SCHEMA_PRESETS } = await import("../knowledge/index.js");
const { toVariableName } = await import("../utils/sass.js");
const theme = getComponentTheme(options.component);
if (!theme) throw new Error(`Unknown component: ${options.component}`);
const designSystem = options.designSystem ?? "material";
const variant = options.variant ?? "light";
const themeFn = theme.themeFunctionName;
const themeComponentName = COMPONENT_METADATA[options.component]?.childOf ?? options.component;
const themeName = options.name ? `$${toVariableName(options.name)}` : `$custom-${themeComponentName}-theme`;
const tokenArgs = [`$schema: ${SCHEMA_PRESETS[variant][designSystem]}`];
for (const [tokenName, value] of Object.entries(options.tokens)) {
const stringValue = typeof value === "number" ? String(value) : value;
tokenArgs.push(`$${tokenName}: ${stringValue}`);
}
const defaultSelectors = getThemingSelector(options.component, options.platform);
const selector = options.selector || (defaultSelectors.length > 0 ? defaultSelectors[0] : options.component);
const sassCode = `
@use 'igniteui-theming/sass/themes' as *;
@use 'igniteui-theming/sass/themes/schemas' as *;
// Custom ${themeComponentName} theme
${themeName}: ${themeFn}(
${tokenArgs.join(",\n ")}
);
// Apply the theme to ${selector}
${selector} {
@include tokens(${themeName});
}
`;
try {
const importers = options._importers ?? [themingImporter];
return {
css: (await sass.compileStringAsync(sassCode, {
importers,
style: "expanded"
})).css,
description: `Generated CSS custom properties for ${themeComponentName} component with ${Object.keys(options.tokens).length} token(s) using ${designSystem} design system (${variant} variant)`
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to compile component theme CSS: ${message}`);
}
}
//#endregion
export { formatCssOutput, generateComponentThemeCss, generateCustomPaletteCss, generatePaletteCss };