igniteui-theming
Version:
A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.
146 lines (141 loc) • 7.26 kB
JavaScript
import { COMPONENT_METADATA, getComponentSelector, getCompoundComponentInfo, getTokenDerivationsForChild, getVariants, hasVariants, isCompoundComponent } from "../../knowledge/component-metadata.js";
import { COMPONENT_NAMES, resolveComponentTheme, searchComponents } from "../../knowledge/component-themes.js";
import "../../knowledge/index.js";
//#region src/tools/handlers/component-tokens.ts
async function handleGetComponentDesignTokens(params) {
const { component } = params;
const normalizedName = component.toLowerCase().trim();
const resolution = resolveComponentTheme(normalizedName);
const theme = resolution?.theme;
if (!theme) {
if (resolution?.error) return {
content: [{
type: "text",
text: `**Error:** ${resolution.error}
Use a valid component name or update component metadata to point to a valid theme.`
}],
isError: true
};
const suggestions = searchComponents(normalizedName);
const componentList = suggestions.length > 0 ? suggestions.slice(0, 10) : COMPONENT_NAMES.slice(0, 20);
return { content: [{
type: "text",
text: `Component "${component}" not found.
${suggestions.length > 0 ? "**Similar components:**" : "**Available components (partial list):**"}
${componentList.map((c) => `- ${c}`).join("\n")}
${suggestions.length === 0 ? `\nTotal available: ${COMPONENT_NAMES.length} components. Use a more specific name to search.` : ""}
**Tip:** For button variants, use specific names like "flat-button", "contained-button", "outlined-button", or "fab-button".`
}] };
}
const responseParts = [];
responseParts.push(`Implement a theme for the \`${normalizedName}\` component using the following guidance.`);
responseParts.push("");
const metadata = COMPONENT_METADATA[normalizedName];
if (metadata?.childOf) {
const parentName = metadata.childOf;
responseParts.push(`**Note:** \`${normalizedName}\` is a child of the \`${parentName}\` component. Its styling is controlled through the \`${parentName}\` theme — all tokens below apply at the ${parentName} level.`);
responseParts.push("");
}
responseParts.push(`**Theme Function:** \`${theme.themeFunctionName}()\``);
responseParts.push("");
if (hasVariants(normalizedName)) {
const variants = getVariants(normalizedName);
responseParts.push("**Note:** This component has variant-specific themes:");
responseParts.push(variants.map((v) => `- \`${v}\``).join("\n"));
responseParts.push("");
responseParts.push("Consider using the specific variant theme for more targeted styling.");
responseParts.push("");
}
const primaryNames = new Set((theme.primaryTokens ?? []).map((pt) => pt.name));
if (theme.primaryTokens && theme.primaryTokens.length > 0) {
responseParts.push("**✅ Primary Tokens — USE THESE:**");
responseParts.push("");
responseParts.push("Use ONLY these tokens when creating the initial theme. The framework auto-derives all other tokens from these.");
responseParts.push("");
responseParts.push("| Token Name | Type | Description |");
responseParts.push("|------------|------|-------------|");
for (const token of theme.tokens) if (primaryNames.has(token.name)) {
const cleanDesc = token.description.replace(/\s+/g, " ").trim();
responseParts.push(`| \`${token.name}\` | ${token.type} | ${cleanDesc} |`);
}
if (theme.primaryTokensSummary) {
responseParts.push("");
responseParts.push(theme.primaryTokensSummary);
}
responseParts.push("");
}
if (isCompoundComponent(normalizedName)) {
const compoundInfo = getCompoundComponentInfo(normalizedName);
if (compoundInfo) if (compoundInfo.composed) {
responseParts.push("**Composed Compound Component:**");
responseParts.push(compoundInfo.description);
responseParts.push("");
responseParts.push("⚡ **This is a composed component.** The framework automatically generates internal derived themes for all child components from the PRIMARY tokens. **Do NOT create separate themes** for the related components listed below — unless instructed otherwise by the user.");
responseParts.push("");
responseParts.push(`**Internally themed children (auto-derived):** ${compoundInfo.relatedThemes.map((t) => `\`${t}\``).join(", ")}`);
responseParts.push("");
if (compoundInfo.guidance) {
responseParts.push("**Guidance:**");
responseParts.push(compoundInfo.guidance);
responseParts.push("");
}
} else {
responseParts.push("**Compound Component:**");
responseParts.push(compoundInfo.description);
responseParts.push("");
responseParts.push(`**Related themes:** ${compoundInfo.relatedThemes.map((t) => `\`${t}\``).join(", ")}`);
const angularSelectors = getComponentSelector(normalizedName, "angular");
const wcSelectors = getComponentSelector(normalizedName, "webcomponents");
const platformLines = [];
if (angularSelectors.length > 0) {
const selectorText = angularSelectors.length === 1 ? angularSelectors[0] : angularSelectors.join(" | ");
platformLines.push(`- **Angular:** \`${selectorText}\``);
}
if (wcSelectors.length > 0) {
const selectorText = wcSelectors.length === 1 ? wcSelectors[0] : wcSelectors.join(" | ");
platformLines.push(`- **Web Components / React / Blazor:** \`${selectorText}\``);
}
if (platformLines.length > 0) {
responseParts.push("Scope all related themes under the parent component selector:");
responseParts.push(platformLines.join("\n"));
}
responseParts.push("");
const derivationRows = compoundInfo.relatedThemes.flatMap((relatedTheme) => {
const derivations = getTokenDerivationsForChild(normalizedName, relatedTheme);
return Object.entries(derivations).map(([token, derivation]) => {
return `| \`${relatedTheme}\` | \`${token}\` | ${derivation.transform === "identity" ? `same as \`${derivation.from}\`` : `\`${derivation.transform}\` of \`${derivation.from}\``} |`;
});
});
responseParts.push("**Token derivations:**");
if (derivationRows.length > 0) {
responseParts.push("| Theme | Token | Derivation |");
responseParts.push("| --- | --- | --- |");
responseParts.push(derivationRows.join("\n"));
} else responseParts.push("None.");
responseParts.push("");
if (compoundInfo.guidance) {
responseParts.push("**Guidance:**");
responseParts.push(compoundInfo.guidance);
responseParts.push("");
}
}
}
const availableTokens = theme.tokens.filter((t) => !primaryNames.has(t.name));
if (availableTokens.length > 0) {
responseParts.push(`**\ud83d\udcd6 Available Tokens (${availableTokens.length}) \u2014 DO NOT USE unless the user explicitly requests a specific customization:**`);
responseParts.push("");
responseParts.push(availableTokens.map((t) => `\`${t.name}\``).join(", "));
responseParts.push("");
} else if (theme.tokens.length === 0) {
responseParts.push("**No customizable tokens available for this component.**");
responseParts.push("");
}
responseParts.push("---");
responseParts.push("**Next step:** Use `create_component_theme` with ONLY the **primary tokens** above. Do NOT add available tokens unless the user explicitly asks for a specific one.");
return { content: [{
type: "text",
text: responseParts.join("\n")
}] };
}
//#endregion
export { handleGetComponentDesignTokens };