@tamilvananmurugan/xlibs
Version:
Comprehensive UI component library with Aceternity, MagicUI, and ShadCN components
140 lines (117 loc) • 4.28 kB
text/typescript
// Smart Component Selector with Priority System
// Priority: Magic UI (40%) > Aceternity (30%) > Charts (20%) > UI (10%)
// Preference: Composite components > Primitives
import { componentRegistry, ComponentMetadata, priorityWeights } from './component-registry';
import { FuzzyMatcher } from './fuzzy-matcher';
export interface ComponentSelectionCriteria {
useCase: string;
variant?: string;
size?: string;
props?: Record<string, any>;
isComposite?: boolean;
}
export interface ComponentSelectionResult {
component: ComponentMetadata;
confidence: number;
alternatives: ComponentMetadata[];
}
export class SmartComponentSelector {
// Select the best component based on criteria
static select(
useCase: string
): ComponentSelectionResult {
const criteria: ComponentSelectionCriteria = {
useCase,
isComposite: true // Prefer composite components
};
const candidates = this.findCandidates(criteria);
const scoredCandidates = this.scoreCandidates(candidates, criteria);
if (scoredCandidates.length === 0) {
return {
component: null as any,
confidence: 0,
alternatives: []
};
}
const bestMatch = this.selectBestMatch(scoredCandidates);
return {
component: bestMatch.component,
confidence: bestMatch.score / 100,
alternatives: scoredCandidates
.slice(1, 4)
.map(c => c.component)
};
}
// Find candidate components
private static findCandidates(criteria: ComponentSelectionCriteria): ComponentMetadata[] {
const candidates: ComponentMetadata[] = [];
for (const [, component] of Object.entries(componentRegistry)) {
// Check if component matches use case
if (component.useCases.some(uc => criteria.useCase.includes(uc))) {
candidates.push(component);
}
}
return candidates;
}
// Score candidates based on criteria
private static scoreCandidates(
candidates: ComponentMetadata[],
criteria: ComponentSelectionCriteria
): Array<{ component: ComponentMetadata; score: number; reason: string }> {
return candidates.map(component => {
let score = 0;
const reasons: string[] = [];
// Priority score (based on component library)
const priorityScore = priorityWeights[component.category] * 100;
score += priorityScore;
reasons.push(`Priority: ${priorityScore}`);
// Use case match score
if (component.useCases.some(uc => criteria.useCase.includes(uc))) {
score += 50;
reasons.push('Use case match: +50');
}
// Composite component bonus
if (criteria.isComposite && component.isComposite) {
score += 25;
reasons.push('Composite component: +25');
}
return {
component,
score,
reason: reasons.join(', ')
};
}).sort((a, b) => b.score - a.score);
}
// Select the best match from scored candidates
private static selectBestMatch(
scoredCandidates: Array<{ component: ComponentMetadata; score: number; reason: string }>
): { component: ComponentMetadata; score: number; reason: string } {
return scoredCandidates[0];
}
// Utility methods for component discovery
static getComponentsByCategory(category: 'aceternity' | 'magicui' | 'shadcn' | 'charts' | 'ui'): ComponentMetadata[] {
return Object.values(componentRegistry).filter(c => c.category === category);
}
static getComponentsByUseCase(useCase: string): ComponentMetadata[] {
return Object.values(componentRegistry).filter(c =>
c.useCases.some(uc => uc.includes(useCase))
);
}
static getComponentsByTag(tag: string): ComponentMetadata[] {
return Object.values(componentRegistry).filter(c =>
c.tags.includes(tag)
);
}
static getAnimationComponents(): ComponentMetadata[] {
return Object.values(componentRegistry).filter(c =>
c.animationLevel === 'high' || c.animationLevel === 'medium'
);
}
static getGradientComponents(): ComponentMetadata[] {
return Object.values(componentRegistry).filter(c => c.hasGradient);
}
// Resolve component name using fuzzy matching
static resolve(componentName: string) {
return FuzzyMatcher.findBestMatch(componentName);
}
}