WIDGET CONSOLIDATION ANALYSIS
Comprehensive guidelines for AI-assisted development within the Editor platform
π Widget/Embeddable Duplication Analysis
Date: December 6, 2024
Status: π¨ DUPLICATES FOUND
Impact: HIGH (code maintenance, bundle size, confusion)
π― The Problem
We have SIGNIFICANT DUPLICATION across our component libraries:
β Same component exists in MULTIPLE places:
βββ libs-widgets/widgets (full widgets)
βββ libs-ui-core/ui-core (embeddables)
βββ libs-ui-core/ui-forms (form embeddables)
π Duplicate Components Found
Category 1: UI Components (12 duplicates)
| Component | widgets/widgets | ui-core | ui-forms | Status |
|---|---|---|---|---|
| breadcrumb | β | β | β | β οΈ DUPLICATE |
| card | β (card-widget) | β | β | β οΈ DUPLICATE |
| chip | β | β | β | β οΈ DUPLICATE |
| chip-list | β | β | β | β οΈ DUPLICATE |
| clipboard | β | β | β | β οΈ DUPLICATE |
| context-menu | β | β | β | β οΈ DUPLICATE |
| editable-slug | β | β | β | β οΈ DUPLICATE |
| icon/icons | β (icon-widget) | β | β | β οΈ DUPLICATE |
| input | β (input-widget) | β | β | β οΈ DUPLICATE |
| module-dock-slot | β | β | β | β οΈ DUPLICATE |
| simple-tabs | β | β | β | β οΈ DUPLICATE |
| ux-tabs | β | β | β | β οΈ DUPLICATE |
Category 2: Form Components (2 duplicates)
| Component | widgets/widgets | ui-core | ui-forms | Status |
|---|---|---|---|---|
| checkbox | β (checkbox-widget) | β | β | β οΈ DUPLICATE |
| select | β (select-widget) | β | β (ux-select) | β οΈ DUPLICATE |
Category 3: Unique to libs-widgets (Clean β )
- button-widget β (uses ui-button embeddable)
- text-widget β
- image-widget β
- video-widget β
- link-widget β
- divider-widget β
- spacer-widget β
- shape-widget β
- hero-widget β
- testimonial-widget β
- feature-widget β
- pricing-widget β
- gallery-widget β
- container-widget β
- simple-widget β
- range-widget β
- radio-widget β
- embeddable-host-widget β
Category 4: Unique to ui-core (Embeddables β )
- ui-button β (used by button-widget - CORRECT pattern!)
Category 5: Unique to ui-forms (Form Embeddables β )
- color-picker β
- form-field β
- multi-select β
- toggle β
- ux-option β
ποΈ Correct Architecture (What It Should Be)
Design Principle
Embeddables (ui-core, ui-forms)
β used by
Widgets (libs-widgets)
β used in
Editor/Canvas
Library Responsibilities
1. ui-core (Pure Embeddables)
Purpose: Reusable UI components with NO widget logic
Should contain:
- ui-button β (embeddable button)
- ui-card β (embeddable card)
- ui-input β (embeddable input)
- ui-icon β (embeddable icon)
- ui-tabs β (embeddable tabs)
- etc.
Should NOT contain: Widget lifecycle, BaseWidgetComponent, property groups
2. ui-forms (Form Embeddables)
Purpose: Form-specific reusable components
Should contain:
- checkbox β
- toggle β
- select β
- multi-select β
- color-picker β
- form-field β
Should NOT contain: Widget wrappers
3. libs-widgets/widgets (Full Widgets)
Purpose: Editor-aware widgets that extend BaseWidgetComponent
Should contain:
- button-widget β (wraps ui-button)
- card-widget β (wraps ui-card)
- input-widget β (wraps ui-input)
- checkbox-widget β (wraps ui-forms/checkbox)
- text-widget β
- image-widget β
- etc.
Should: Use embeddables from ui-core and ui-forms, add widget logic
β οΈ Current Issues
Issue 1: Duplicate Implementation
Problem: Same component logic exists in multiple places
Example:
libs-widgets/widgets/src/lib/components/icon-widget/
libs-ui-core/ui-core/src/lib/components/icon/
Both implement icon rendering - which is correct?
Issue 2: Unclear Separation
Problem: No clear rule about what goes where
Questions:
- Should
breadcrumbbe in widgets or ui-core? - Should
context-menube in widgets or ui-core? - Should
editable-slugbe in widgets or ui-core?
Issue 3: Maintenance Burden
Problem: Changes must be made in multiple places
Example: Fix a bug in chip β Must fix in:
- libs-widgets/widgets/chip/
- libs-ui-core/ui-core/chip/
β Violates DRY principle
Issue 4: Bundle Size
Problem: Same code shipped multiple times
Impact: Larger bundle, slower loads
π‘ Recommended Consolidation Strategy
Phase 1: Categorize (Define Source of Truth)
For each duplicate, decide:
Option A: Embeddable Only (Keep in ui-core/ui-forms)
- Component is pure UI, no widget logic
- Used across multiple contexts (not just editor)
- Examples: icon, breadcrumb, context-menu
Option B: Widget Only (Keep in libs-widgets)
- Component is editor-specific
- Needs BaseWidgetComponent lifecycle
- Has property groups and variants
- Examples: Probably none - all widgets should use embeddables!
Option C: Both (Embeddable + Widget Wrapper)
- Embeddable in ui-core (pure component)
- Widget wrapper in libs-widgets (adds editor logic)
- Example: button (ui-button + button-widget) β THIS IS CORRECT!
Phase 2: Consolidation Rules
Rule 1: UI Components β ui-core
Move to ui-core (keep as embeddables):
- β breadcrumb
- β chip
- β chip-list
- β clipboard
- β context-menu
- β editable-slug
- β icon/icons
- β input (ui-input)
- β module-dock-slot
- β simple-tabs
- β ux-tabs
Delete from libs-widgets/widgets: Duplicate implementations
Rule 2: Form Components β ui-forms
Move to ui-forms (keep as embeddables):
- β checkbox
- β select (ux-select)
Delete from libs-widgets/widgets: Duplicate implementations
Rule 3: Widgets β Use Embeddables
Refactor widgets to use embeddables:
// β BEFORE: Widget implements everything
@Component({
selector: 'lib-icon-widget',
template: `
<i class="material-icons">{{ icon }}</i>
`
})
export class IconWidgetComponent { }
// β
AFTER: Widget uses embeddable
@Component({
selector: 'lib-icon-widget',
template: `
<ui-icon [icon]="config().icon" [customStyles]="customStyles()"></ui-icon>
`
})
export class IconWidgetComponent extends BaseWidgetComponent { }
Phase 3: Implementation Plan
Step 1: Audit (Which implementation to keep?)
For each duplicate:
- Compare implementations (ui-core vs widgets)
- Choose most robust/feature-complete
- Document decision
Step 2: Migrate (Move logic to embeddables)
- Keep embeddable in ui-core/ui-forms
- Refactor widget to use embeddable
- Add widget-specific logic (properties, variants)
- Test thoroughly
Step 3: Delete (Remove duplicates)
- Delete duplicate from widgets/
- Update imports across codebase
- Update barrel exports
- Verify no broken references
Step 4: Document (Prevent future duplication)
- Update AGENTS.md with clear rules
- Add linting rules (if possible)
- Document architecture decisions
π― Specific Consolidation Examples
Example 1: Icon Component
Current State β
libs-widgets/widgets/src/lib/components/icon-widget/
βββ icon-widget.component.ts (widget implementation)
βββ icon-widget-property-groups.ts
βββ index.ts
libs-ui-core/ui-core/src/lib/components/icon/
βββ icon.component.ts (embeddable implementation)
βββ index.ts
Desired State β
libs-ui-core/ui-core/src/lib/components/icon/
βββ icon.component.ts (embeddable - pure UI)
βββ index.ts
libs-widgets/widgets/src/lib/components/icon-widget/
βββ icon-widget.component.ts (widget - uses <ui-icon>)
βββ icon-widget-property-groups.ts
βββ index.ts
Implementation
// icon-widget.component.ts
import { UiIconComponent } from '@libs-ui-core/ui-core';
@Component({
selector: 'lib-icon-widget',
imports: [UiIconComponent],
template: `
<ui-icon
[icon]="config().icon"
[size]="config().size"
[color]="config().color"
[customStyles]="customStyles()"
></ui-icon>
`
})
export class IconWidgetComponent extends BaseWidgetComponent {
config = computed(() => ({...}));
customStyles = computed(() => ({...}));
}
Example 2: Input Component
Current State β
libs-widgets/widgets/src/lib/components/input-widget/
βββ input-widget.component.ts (full implementation)
libs-ui-core/ui-core/src/lib/components/input/
βββ ui-input.component.ts (full implementation)
Desired State β
libs-ui-core/ui-core/src/lib/components/input/
βββ ui-input.component.ts (embeddable - pure input)
libs-widgets/widgets/src/lib/components/input-widget/
βββ input-widget.component.ts (widget - uses <ui-input>)
Example 3: Card Component
Current State β
libs-widgets/widgets/src/lib/components/card-widget/
βββ card-widget.component.ts (full implementation)
libs-ui-core/ui-core/src/lib/components/card/
βββ card.component.ts (full implementation)
βββ card-header.component.ts
βββ card-content.component.ts
βββ card-footer.component.ts
Desired State β
libs-ui-core/ui-core/src/lib/components/card/
βββ card.component.ts (embeddable - pure card UI)
βββ card-header.component.ts
βββ card-content.component.ts
βββ card-footer.component.ts
libs-widgets/widgets/src/lib/components/card-widget/
βββ card-widget.component.ts (widget - uses <ui-card>)
CardWidget should use <ui-card> embeddable!
π₯ Impact of Consolidation
Before β
- 14+ duplicate components
- Inconsistent implementations
- Changes need multiple updates
- Larger bundle size
- Confusion about which to use
After β
- ONE source of truth per component
- Consistent implementations
- Change once, applies everywhere
- Smaller bundle size
- Clear architecture (embeddable vs widget)
π Estimated Effort
| Phase | Components | Effort | Impact |
|---|---|---|---|
| Audit | 14 duplicates | 1 hour | Understand current state |
| Migrate High Priority | 5 components | 3-4 hours | Button, Card, Input, Icon, Checkbox |
| Migrate Medium Priority | 5 components | 2-3 hours | Tabs, Chip, Select, Context Menu |
| Migrate Low Priority | 4 components | 1-2 hours | Breadcrumb, Clipboard, Editable Slug, Module Dock |
| Testing & Cleanup | All | 2 hours | Verify, delete duplicates, update docs |
| TOTAL | 14 duplicates | 9-12 hours | Clean architecture |
π― Recommended Approach
Option 1: Aggressive Consolidation (Recommended β)
Timeline: 2-3 days
Risk: Medium
Reward: Clean architecture
Steps:
- Audit all 14 duplicates (1 hour)
- Keep embeddables in ui-core/ui-forms as source of truth
- Refactor widgets to use embeddables (like ButtonWidget does)
- Delete duplicates from widgets/
- Test thoroughly
- Document architecture
Result: Clear separation, no duplication, smaller bundle
Option 2: Gradual Consolidation
Timeline: 1-2 weeks
Risk: Low
Reward: Medium
Steps:
- Mark duplicates with deprecation warnings
- Create migration guide for each
- Gradually migrate over time
- Delete when all usages updated
Result: Safer, but slower
Option 3: Live with Duplication (NOT Recommended β)
Timeline: 0 (no action)
Risk: None
Reward: None
Consequence: Technical debt grows, bundle size increases, maintenance harder
π‘ My Strong Recommendation
Do Option 1: Aggressive Consolidation NOW
Why?
- You're in active development - no backward compatibility needed
- Patterns are clear - ButtonWidget shows the way
- Momentum is high - we just fixed all sizing issues
- Foundation is solid - unified property system ready
- Technical debt is young - easier to fix now than later
Plus, you said: "condensce the similar or same widgets" - you WANT this done!
π Proposed Consolidation Order
Priority 1: Most Impactful (Start Here!)
- card-widget β Use
<ui-card>embeddable - input-widget β Use
<ui-input>embeddable - checkbox-widget β Use
<ui-checkbox>embeddable from ui-forms - select-widget β Use
<ux-select>embeddable from ui-forms
Why: High usage, clear embeddable pattern, immediate benefit
Priority 2: Medium Impact
- icon-widget β Use
<ui-icon>embeddable - simple-tabs β Use
<simple-tabs>embeddable (or consolidate into ux-tabs) - ux-tabs β Keep embeddable, remove widget duplicate
- chip-widget β Use
<ui-chip>embeddable - context-menu β Keep embeddable in ui-core, delete from widgets
Priority 3: Lower Impact
- breadcrumb β Likely keep in ui-core only (not typically a widget)
- clipboard β Likely keep in ui-core only (utility component)
- editable-slug β Keep in ui-core only (specialized input)
- module-dock-slot β Keep in ui-core only (layout component)
π Consolidation Checklist
For EACH duplicate:
Step 1: Audit
- Which version is more feature-complete?
- Which is more recently updated?
- Which follows our patterns better?
- Are there any breaking changes?
Step 2: Choose Source of Truth
- Keep embeddable in ui-core/ui-forms
- Mark as source of truth
- Document decision
Step 3: Refactor Widget (if needed)
- Import embeddable
- Use embeddable in template
- Add widget logic (BaseWidgetComponent, properties)
- Pass customStyles to embeddable
Step 4: Delete Duplicate
- Remove duplicate from other library
- Update all imports across codebase
- Update barrel exports
- Verify compilation
Step 5: Test
- Component renders correctly
- Properties panel works
- No visual regressions
- Bundle size reduced
π Expected Outcomes
After consolidation:
Code Quality β
- β DRY principle enforced
- β Clear architecture (embeddable vs widget)
- β Easier maintenance
- β Fewer bugs (one source of truth)
Bundle Size β
- β ~10-15% reduction (estimated)
- β Faster initial load
- β Better code splitting
- β Smaller lazy chunks
Developer Experience β
- β Clear where to add new components
- β Obvious how to create new widgets
- β Easy to find and fix bugs
- β AI-trainable patterns
π₯ The Bottom Line
Current State: π¨ 14 duplicate components
Goal: π― Zero duplication, clear architecture
Effort: 9-12 hours over 2-3 days
Reward: βΎοΈ Clean codebase, easy maintenance, smaller bundle
Recommendation: DO IT NOW while momentum is high!
π― What Do You Want?
Option A: FULL CONSOLIDATION (Aggressive)
β
Fix all 14 duplicates
β
Clean architecture
β° 9-12 hours
Option B: TOP 5 ONLY (Balanced)
β
Fix most impactful (card, input, checkbox, select, icon)
β° 3-4 hours
Option C: DOCUMENT ONLY (Passive)
π Document the issue, fix later
β° 30 minutes
Status: π Analysis complete
Decision: Awaiting your call
Ready: To execute immediately
Let me know which option you prefer! π