UNPKG

igniteui-theming

Version:

A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.

276 lines (275 loc) 9.97 kB
import "./blazor.js"; import "./react.js"; import "./webcomponents.js"; import "./angular.js"; import { resolve } from "node:path"; import { existsSync, readFileSync, readdirSync } from "node:fs"; //#region src/knowledge/platforms/index.ts /** * Platform-specific knowledge for theme generation * * This module exports platform-specific configurations and generators * for all supported Ignite UI platforms: * - Ignite UI for Angular * - Ignite UI for Web Components * - Ignite UI for React * - Ignite UI for Blazor * * It also provides platform detection functionality with multi-signal analysis * for automatic platform identification from project files. */ /** * Ignite UI package patterns for each platform. * These are HIGH confidence indicators (100). */ var IGNITE_PACKAGE_PATTERNS = { angular: ["igniteui-angular", "@infragistics/igniteui-angular"], webcomponents: ["igniteui-webcomponents", "@infragistics/igniteui-webcomponents"], react: ["igniteui-react", "@infragistics/igniteui-react"], blazor: [], generic: [] }; /** * Framework package patterns for fallback detection. * These are LOW confidence indicators (40) - only used when no Ignite UI package found. */ var FRAMEWORK_PACKAGE_PATTERNS = { "@angular/core": "angular", lit: "webcomponents", react: "react", "react-dom": "react" }; /** * Detect platform from config files in the project root. * Fast detection that only checks root directory, no deep scanning. * * @param projectRoot - Path to the project root directory * @returns Array of detected config file signals */ function detectConfigFiles(projectRoot = ".") { const signals = []; const root = resolve(projectRoot); if (existsSync(resolve(root, "angular.json"))) signals.push({ platform: "angular", file: "angular.json", confidence: 80 }); for (const viteConfig of [ "vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs" ]) { const configPath = resolve(root, viteConfig); if (existsSync(configPath)) try { const content = readFileSync(configPath, "utf-8"); if (content.includes("@vitejs/plugin-react") || content.includes("plugin-react")) { signals.push({ platform: "react", file: viteConfig, confidence: 80 }); break; } } catch {} } for (const nextConfig of [ "next.config.js", "next.config.mjs", "next.config.ts" ]) if (existsSync(resolve(root, nextConfig))) { signals.push({ platform: "react", file: nextConfig, confidence: 80 }); break; } try { const csprojFiles = readdirSync(root).filter((f) => f.endsWith(".csproj")).slice(0, 5); for (const csproj of csprojFiles) try { const content = readFileSync(resolve(root, csproj), "utf-8"); if (content.includes("IgniteUI.Blazor")) { signals.push({ platform: "blazor", file: csproj, confidence: 100 }); break; } if (content.includes("Microsoft.NET.Sdk.BlazorWebAssembly") || content.includes("Microsoft.NET.Sdk.Razor")) { signals.push({ platform: "blazor", file: csproj, confidence: 40 }); break; } } catch {} } catch {} return signals; } /** * Detect platform from package.json dependencies and project config files. * * Uses a multi-signal approach with confidence scoring: * 1. Ignite UI packages (HIGH - 100): Definitive platform match * 2. Config files (MEDIUM-HIGH - 80): Strong platform indicator * 3. Framework packages (LOW - 40): Fallback when no Ignite UI found * * When multiple platforms are detected with significant confidence (≥60), * returns an ambiguous result asking the user to specify explicitly. * * @param dependencies - package.json dependencies * @param devDependencies - package.json devDependencies * @param projectRoot - Project root directory for config file detection * @returns Platform detection result with signals and confidence */ function detectPlatformFromDependencies(dependencies = {}, devDependencies = {}, projectRoot = ".") { const allDeps = { ...dependencies, ...devDependencies }; const signals = []; const platformScores = /* @__PURE__ */ new Map(); for (const [platform, patterns] of Object.entries(IGNITE_PACKAGE_PATTERNS)) for (const pattern of patterns) if (pattern in allDeps) { signals.push({ type: "ignite_package", package: pattern, confidence: 100 }); const current = platformScores.get(platform) || 0; platformScores.set(platform, Math.max(current, 100)); } const configSignals = detectConfigFiles(projectRoot); for (const signal of configSignals) { signals.push({ type: "config_file", file: signal.file, confidence: signal.confidence }); const current = platformScores.get(signal.platform) || 0; platformScores.set(signal.platform, Math.max(current, signal.confidence)); } for (const [pkg, platform] of Object.entries(FRAMEWORK_PACKAGE_PATTERNS)) if (pkg in allDeps) { const currentScore = platformScores.get(platform) || 0; if (currentScore < 60) { signals.push({ type: "framework_package", package: pkg, confidence: 40 }); platformScores.set(platform, Math.max(currentScore, 40)); } } const hasIgniteProduct = signals.some((s) => s.type === "ignite_package") || signals.some((s) => s.type === "config_file" && s.confidence === 100); if (platformScores.size === 0) return { platform: "generic", confidence: "none", signals: [], reason: "No Ignite UI packages, framework packages, or config files detected. Using generic (standalone) mode." }; if (!hasIgniteProduct) return { platform: "generic", confidence: "low", signals, reason: "No Ignite UI product package detected. Framework or config signals found but no Ignite UI product in use. Using generic (standalone) mode." }; const sorted = Array.from(platformScores.entries()).sort((a, b) => b[1] - a[1]); const [topPlatform, topScore] = sorted[0]; const ambiguousThreshold = 60; const significantPlatforms = sorted.filter(([, score]) => score >= ambiguousThreshold); if (significantPlatforms.length > 1) { const alternatives = significantPlatforms.map(([platform, score]) => { return { platform, confidence: score, signals: signals.filter((s) => { if (s.type === "ignite_package") return IGNITE_PACKAGE_PATTERNS[platform]?.includes(s.package); if (s.type === "config_file") return configSignals.some((cs) => cs.platform === platform && cs.file === s.file); if (s.type === "framework_package") return FRAMEWORK_PACKAGE_PATTERNS[s.package] === platform; return false; }) }; }); return { platform: null, confidence: "none", ambiguous: true, alternatives, signals, reason: `Multiple platforms detected: ${alternatives.map((a) => a.platform).join(", ")}. Please specify platform explicitly.` }; } let confidenceLevel; if (topScore >= 80) confidenceLevel = "high"; else if (topScore >= 60) confidenceLevel = "medium"; else confidenceLevel = "low"; const detectedPackageSignal = signals.find((s) => s.type === "ignite_package" && IGNITE_PACKAGE_PATTERNS[topPlatform]?.includes(s.package)); return { platform: topPlatform, confidence: confidenceLevel, signals, detectedPackage: detectedPackageSignal?.package, reason: `Detected ${topPlatform} with ${confidenceLevel} confidence (score: ${topScore})` }; } /** * Determine if a detected package is a licensed @infragistics package. * Only applies to Angular - other platforms always use the free igniteui-theming package. * * @param detectedPackage - The package name detected from package.json * @returns True if the package is a licensed @infragistics package */ function isLicensedPackage(detectedPackage) { return detectedPackage?.startsWith("@infragistics/") ?? false; } /** * Platform metadata for display purposes */ var PLATFORM_METADATA = { angular: { id: "angular", name: "Ignite UI for Angular", shortName: "Angular", packageName: "igniteui-angular", licensedPackageName: "@infragistics/igniteui-angular", themingModule: "igniteui-angular/theming", licensedThemingModule: "@infragistics/igniteui-angular/theming", description: "Uses core() and theme() mixins from igniteui-angular/theming module. Requires ig-typography CSS class on root element. Available as OSS (igniteui-angular) or licensed (@infragistics/igniteui-angular) package." }, webcomponents: { id: "webcomponents", name: "Ignite UI for Web Components", shortName: "Web Components", packageName: "igniteui-webcomponents", themingModule: "igniteui-theming", description: "Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Supports runtime theme switching via configureTheme(). The igniteui-theming package is always free/OSS." }, react: { id: "react", name: "Ignite UI for React", shortName: "React", packageName: "igniteui-react", themingModule: "igniteui-theming", description: "Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Common with Vite or Next.js projects. The igniteui-theming package is always free/OSS." }, blazor: { id: "blazor", name: "Ignite UI for Blazor", shortName: "Blazor", packageName: "IgniteUI.Blazor", themingModule: "igniteui-theming", description: "Uses igniteui-theming for Sass compilation in .NET Blazor projects. Theme styles are compiled to CSS and referenced in Blazor components. The igniteui-theming package is always free/OSS." }, generic: { id: "generic", name: "Ignite UI Theming (Standalone)", shortName: "Generic", packageName: "igniteui-theming", themingModule: "igniteui-theming", description: "Platform-agnostic output using igniteui-theming directly. For projects that do not use a specific Ignite UI product framework (Angular, Web Components, React, or Blazor). Supports palette, typography, elevations, and theme generation. Component theming is not available in generic mode." } }; //#endregion export { PLATFORM_METADATA, detectConfigFiles, detectPlatformFromDependencies, isLicensedPackage };