igniteui-theming
Version:
A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.
148 lines (146 loc) • 5.98 kB
JavaScript
import { COMPONENT_METADATA, getComponentPlatformAvailability, getComponentSelector } from "../../knowledge/component-metadata.js";
import "../../knowledge/index.js";
//#region src/tools/handlers/layout.ts
/**
* Handlers for layout scale tools: set_size, set_spacing, set_roundness.
*/
var SIZE_KEYWORDS = {
small: 1,
medium: 2,
large: 3
};
function normalizeComponentName(component) {
return component ? component.toLowerCase().trim() : null;
}
function buildSelectorList(value) {
return Array.isArray(value) ? value : [value];
}
function resolveScope(component, scope, platform) {
const notes = [];
if (component) {
const normalized = normalizeComponentName(component);
if (!normalized || !COMPONENT_METADATA[normalized]) {
const available = Object.keys(COMPONENT_METADATA);
const suggestions = normalized ? available.filter((name) => name.includes(normalized)).slice(0, 10) : [];
const list = suggestions.length > 0 ? suggestions : available.slice(0, 15);
return { error: `**Error:** Component "${component}" not found.
${suggestions.length > 0 ? "**Similar components:**" : "**Available components:**"}
${list.map((name) => `- ${name}`).join("\n")}` };
}
if (scope) notes.push("Scope ignored because component was provided.");
const selectorsEntry = COMPONENT_METADATA[normalized].selectors;
let selectors = [];
if (!selectorsEntry) return { error: `**Error:** Component "${component}" does not have platform selectors. It may be a child sub-component — use its parent component for layout overrides.` };
if (platform && platform !== "generic") {
selectors = getComponentSelector(normalized, platform);
if (selectors.length === 0) {
const availability = getComponentPlatformAvailability(normalized);
const availablePlatforms = [];
if (availability?.angular) availablePlatforms.push("angular");
if (availability?.webcomponents) availablePlatforms.push("webcomponents");
return { error: `**Error:** Component "${component}" is not available on platform "${platform}".
${availablePlatforms.length > 0 ? `Available platforms: ${availablePlatforms.join(", ")}.` : ""}` };
}
} else {
if (selectorsEntry.angular) selectors = selectors.concat(buildSelectorList(selectorsEntry.angular));
if (selectorsEntry.webcomponents) selectors = selectors.concat(buildSelectorList(selectorsEntry.webcomponents));
if (selectorsEntry.angular && selectorsEntry.webcomponents) notes.push("Platform not specified; output includes Angular and Web Components selectors.");
}
return {
selectors: Array.from(new Set(selectors)),
notes,
scopeLabel: `component "${normalized}"`
};
}
if (scope) return {
selectors: [scope],
notes,
scopeLabel: `scope "${scope}"`
};
return {
selectors: [":root"],
notes,
scopeLabel: "global scope (:root)"
};
}
function formatSelectorBlock(selectors, declarations) {
return [
selectors.join(",\n"),
"{",
...declarations.map((line) => ` ${line}`),
"}"
].join("\n");
}
function buildResponse(description, output, code, notes, guidance) {
const responseParts = [description];
if (notes.length > 0) responseParts.push("", ...notes);
if (guidance.length > 0) responseParts.push("", ...guidance);
responseParts.push("");
responseParts.push(output === "sass" ? "```scss" : "```css");
responseParts.push(code);
responseParts.push("```");
return { content: [{
type: "text",
text: responseParts.join("\n")
}] };
}
function coerceSizeValue(size) {
if (typeof size === "number") return {
display: String(size),
value: size
};
const value = SIZE_KEYWORDS[size.toLowerCase()];
return {
display: `${size} (${value})`,
value
};
}
async function handleSetSize(params) {
const { component, scope, platform, size, output = "css" } = params;
const resolution = resolveScope(component, scope, platform);
if ("error" in resolution) return {
content: [{
type: "text",
text: resolution.error
}],
isError: true
};
const { selectors, notes, scopeLabel } = resolution;
const { display, value } = coerceSizeValue(size);
const code = formatSelectorBlock(selectors, [`--ig-size: ${value};`]);
return buildResponse(`Set size to ${display} in ${scopeLabel}.`, output, code, notes, output === "sass" ? ["Sass note: sizable() requires @include sizable() in component styles.", "Components map --ig-size to --component-size internally."] : []);
}
async function handleSetSpacing(params) {
const { component, scope, platform, spacing, inline, block, output = "css" } = params;
const resolution = resolveScope(component, scope, platform);
if ("error" in resolution) return {
content: [{
type: "text",
text: resolution.error
}],
isError: true
};
const { selectors, notes, scopeLabel } = resolution;
const declarations = [];
if (spacing !== void 0) declarations.push(`--ig-spacing: ${spacing};`);
if (inline !== void 0) declarations.push(`--ig-spacing-inline: ${inline};`);
if (block !== void 0) declarations.push(`--ig-spacing-block: ${block};`);
const code = formatSelectorBlock(selectors, declarations);
return buildResponse(`Set spacing in ${scopeLabel}.`, output, code, notes, output === "sass" ? ["Sass note: pad() functions require @include spacing() once at root scope."] : []);
}
async function handleSetRoundness(params) {
const { component, scope, platform, radiusFactor, output = "css" } = params;
const resolution = resolveScope(component, scope, platform);
if ("error" in resolution) return {
content: [{
type: "text",
text: resolution.error
}],
isError: true
};
const { selectors, notes, scopeLabel } = resolution;
const code = formatSelectorBlock(selectors, [`--ig-radius-factor: ${radiusFactor};`]);
return buildResponse(`Set roundness factor to ${radiusFactor} in ${scopeLabel}.`, output, code, notes, output === "sass" ? ["Sass note: border-radius() responds to --ig-radius-factor without extra mixins."] : []);
}
//#endregion
export { handleSetRoundness, handleSetSize, handleSetSpacing };