# STYLE-004: Property Panel UX Overhaul ## Overview Redesign the property panel to surface the three-level styling system: Variant Picker (easy), Token Overrides (intermediate), and Manual Values (advanced). The goal is progressive disclosure - make the happy path obvious while preserving full control. **Phase:** 8 (Styles Overhaul) **Priority:** HIGH **Effort:** 12-16 hours **Risk:** Medium (significant UI changes) **Dependencies:** STYLE-001, STYLE-002 --- ## Background ### Current State - Property panel shows all CSS properties in a flat list - No progressive disclosure (beginners see same UI as experts) - Style variants exist but aren't prominently featured - Token system exists but requires manual typing ### Target State - Variant picker is front-and-center for styled elements - Token overrides available in collapsible section - Manual controls preserved but de-emphasized - Visual indicators show when elements use system styles vs custom --- ## The Three Levels ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ LEVEL 1: VARIANT PICKER [Default View] │ │ "Just pick Primary, Secondary, Ghost..." │ │ • Single dropdown │ │ • Visual previews │ │ • 80% of users, 80% of the time │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ LEVEL 2: TOKEN OVERRIDES [Expanded] │ │ "Use Primary but change the radius to Large" │ │ • Override specific properties with tokens │ │ • Stay systematic, theme-aware │ │ • Designers building design systems │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ LEVEL 3: MANUAL VALUES [Advanced] │ │ "I need exactly 17px padding and this hex color" │ │ • Full CSS control │ │ • Chrome DevTools-style interface │ │ • "You're on your own" │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Property Panel Redesign ### Default View (Button Example) ``` ┌─────────────────────────────────────────────────────────────────┐ │ BUTTON │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ CONTENT │ │ ├─ Label: [Sign Up ] │ │ └─ Icon: [None ▼] Position: [Left ▼] │ │ │ │ STYLE │ │ ├─ Variant: [Primary ▼] │ │ │ ┌────────────────────────────────┐ │ │ │ │ ● Primary ████████████ │ │ │ │ │ Secondary ████████████ │ │ │ │ │ Outline ░░░░░░░░░░░░ │ │ │ │ │ Ghost ············ │ │ │ │ │ Destructive ████████████ │ │ │ │ │ Link ____________ │ │ │ │ │ ──────────────────────────────│ │ │ │ │ + Create Variant │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ └─ Size: [Medium ▼] (sm / md / lg / xl) │ │ │ │ BEHAVIOR │ │ ├─ Disabled: [ ] │ │ └─ Loading: [ ] │ │ │ │ ▶ Style Overrides │ │ ▶ Layout │ │ ▶ Advanced │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Expanded: Style Overrides (Level 2) ``` │ ▼ Style Overrides │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Override properties while staying on-system │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ Background │ │ [From Variant ▼] ───────────────────────────────────────── │ │ │ ┌────────────────────────────────┐ │ │ │ │ ● From Variant (--primary) │ │ │ │ │ ───────────────────────────── │ │ │ │ │ --primary │ │ │ │ │ --primary-hover │ │ │ │ │ --secondary │ │ │ │ │ --destructive │ │ │ │ │ --muted │ │ │ │ │ --surface │ │ │ │ │ --background │ │ │ │ │ ───────────────────────────── │ │ │ │ │ Custom Value... │ ← Escape hatch │ │ │ └────────────────────────────────┘ │ │ │ │ Text Color │ │ [From Variant ▼] │ │ │ │ Border Color │ │ [--border ▼] ← Overriding variant │ │ ⚠️ Overriding variant default │ │ │ │ Border Radius │ │ [--radius-lg ▼] ← Overriding variant │ │ ⚠️ Overriding variant default │ │ │ │ Padding │ │ [From Variant ▼] │ │ │ │ Shadow │ │ [From Variant ▼] │ │ │ │ [Reset All Overrides] │ │ │ ``` When user selects "Custom Value...": ``` │ Background │ │ [Custom ▼] [#a3f7c2 ] [🎨] │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ ⚠️ Custom value won't update when theme changes │ │ │ │ [Save as Token] [Keep Custom] │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ ``` ### Expanded: Layout (Partially Level 3) ``` │ ▼ Layout │ │ │ │ WIDTH │ │ [Auto ▼] [ ] │ │ │ ● Auto (fit content) │ │ │ Full (100%) │ │ │ Fixed │ │ │ Token → [Select Token ▼] │ │ │ │ HEIGHT │ │ [Auto ▼] [ ] │ │ │ │ ALIGNMENT │ │ ┌─────────────────────────────────────┐ │ │ │ [⬉] [⬆] [⬈] Align Self │ │ │ │ [⬅] [·] [➡] │ │ │ │ [⬋] [⬇] [⬊] │ │ │ └─────────────────────────────────────┘ │ │ │ │ SPACING │ │ Margin: [Token ▼] [--space-md ▼] │ │ Padding: [Variant ▼] │ │ │ ``` ### Expanded: Advanced (Level 3) ``` │ ▼ Advanced │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ ⚠️ Manual values bypass the style system │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ POSITION │ │ Position: [Relative ▼] │ │ ┌─────────────────────────────────────┐ │ │ │ Top: [ ] │ │ │ │ Left: [ ] Right: [ ] │ │ │ │ Bottom: [ ] │ │ │ └─────────────────────────────────────┘ │ │ │ │ BOX MODEL │ │ ┌─────────────────────────────────────┐ │ │ │ Margin │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ Border │ │ │ │ │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ Padding │ │ │ │ │ │ │ │ ┌─────────────┐ │ │ │ │ │ │ │ │ │ Content │ │ │ │ │ │ │ │ │ └─────────────┘ │ │ │ │ │ │ │ └─────────────────────┘ │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ │ │ [Edit Individual Values] │ │ │ │ EFFECTS │ │ Opacity: [1.0 ] ────────○ │ │ Cursor: [Pointer ▼] │ │ Overflow: [Visible ▼] │ │ Z-Index: [ ] │ │ │ │ TRANSFORM │ │ Rotate: [0° ] │ │ Scale: [1 ] │ │ Translate X: [0 ] │ │ Translate Y: [0 ] │ │ │ │ TRANSITIONS │ │ Property: [all ▼] │ │ Duration: [--duration-200 ▼] │ │ Easing: [--ease-out ▼] │ │ │ │ CUSTOM CSS │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ /* Any valid CSS */ │ │ │ │ backdrop-filter: blur(8px); │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ ``` --- ## Visual Indicators ### On-System vs Custom Indicators Show users when elements are "on system" vs have custom values: **In the Property Panel Header:** ``` ┌─────────────────────────────────────────────────────────────────┐ │ BUTTON [Using System ✓] │ ├─────────────────────────────────────────────────────────────────┤ vs. ┌─────────────────────────────────────────────────────────────────┐ │ BUTTON [⚡ 2 Custom Values] │ ├─────────────────────────────────────────────────────────────────┤ ``` **In the Style Section:** ``` │ STYLE │ │ ├─ Variant: [Primary ▼] (2 overrides) │ ^^^^^^^^^^^^^ subtle indicator ``` **On Individual Properties:** ``` │ Border Radius │ │ [--radius-lg ▼] ← Override indicator │ │ ⚠️ Overriding variant │ ``` ### In the Canvas (Optional) Small indicator on selected element showing style status: ``` ┌────────────────────────┐ │ │ │ [ Sign Up ] │ ← Normal (using system) │ │ └────────────────────────┘ ┌────────────────────────┐ │ ⚡ │ ← Has custom values │ [ Sign Up ] │ │ │ └────────────────────────┘ ``` --- ## Implementation ### Phase 1: Panel Structure Refactor (4-5 hrs) **Files to modify:** ``` packages/noodl-editor/src/editor/src/views/panels/propertyeditor/ ├── PropertyEditor.tsx # Main panel refactor ├── sections/ │ ├── ContentSection.tsx # Node-specific content │ ├── StyleSection.tsx # Variant picker + size │ ├── StyleOverridesSection.tsx # Level 2 overrides │ ├── LayoutSection.tsx # Layout controls │ ├── AdvancedSection.tsx # Level 3 manual controls │ └── BehaviorSection.tsx # Disabled, loading, etc. ├── PropertyEditor.module.scss └── index.ts ``` **Section Architecture:** ```typescript interface PropertyPanelSection { id: string; title: string; icon?: IconName; defaultExpanded: boolean; render: (node: NodeModel) => React.ReactNode; isApplicable: (nodeType: string) => boolean; } const sections: PropertyPanelSection[] = [ { id: 'content', title: 'Content', defaultExpanded: true, ... }, { id: 'style', title: 'Style', defaultExpanded: true, ... }, { id: 'behavior', title: 'Behavior', defaultExpanded: true, ... }, { id: 'style-overrides', title: 'Style Overrides', defaultExpanded: false, ... }, { id: 'layout', title: 'Layout', defaultExpanded: false, ... }, { id: 'advanced', title: 'Advanced', defaultExpanded: false, ... }, ]; ``` ### Phase 2: Style Section Components (3-4 hrs) **Files to create:** ``` packages/noodl-core-ui/src/components/propertyeditor/ ├── VariantPicker/ │ ├── VariantPicker.tsx │ ├── VariantPicker.module.scss │ ├── VariantOption.tsx # Single variant option with preview │ └── index.ts ├── SizePicker/ │ ├── SizePicker.tsx # sm/md/lg/xl buttons │ └── SizePicker.module.scss ├── TokenOverrideRow/ │ ├── TokenOverrideRow.tsx # Single property override │ ├── TokenOverrideRow.module.scss │ └── index.ts ``` ### Phase 3: Token Picker Integration (2-3 hrs) Connect TokenPicker (from STYLE-001) to override rows: ```typescript interface TokenOverrideRowProps { property: string; // e.g., 'backgroundColor' label: string; // e.g., 'Background' variantValue: string; // Value from variant currentValue: string | null; // Override value (null = use variant) tokenCategory: TokenCategory; // Filter tokens shown onChange: (value: string | null) => void; } function TokenOverrideRow({ property, label, variantValue, currentValue, tokenCategory, onChange }: TokenOverrideRowProps) { const isOverridden = currentValue !== null; return (