Fix duplicate append bug and componentize tabs

**Bug Fixes:**
- Fixed duplicate js_append_child calls causing DOM element re-insertion
- Elements were being appended twice: once by self-append logic, once by parent loop
- This was breaking CSS transitions on vertical tabs (elements moved in DOM)
- Removed self-append logic from _emit_with() and _emit_yield_component()

**Refactoring:**
- Created reusable HTab and VTab components for horizontal/vertical tabs
- Reduced repetitive tab code from 9 lines per tab to 1 line
- Improved code maintainability and reusability
- WASM bundle size reduced from 5987 bytes to 4690 bytes (22% reduction!)

**Result:**
- CSS transitions now work smoothly on vertical tabs ✓
- All 55 tests passing ✓
- Cleaner, more composable tab components ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Aaron SinclairandClaude committed 2025-11-15 11:39:53 -08:00
1 parent 1575571f3e
commit 134ddc4c42
5 files changed
+429 -624

No files matched your search

+37 -24
View File
@@ -11,6 +11,35 @@ Demonstrates:
from ritz.syntax import *
# ===== Reusable Tab Components =====
@component
def HTab(label, active, onclick):
"""Horizontal tab (Li > Button structure).
Args:
label: String - tab label text
active: Boolean - whether this tab is active
onclick: Function - click handler
"""
with Li(class_='tab active' if active else 'tab'):
with Button(onclick=onclick):
yield label
@component
def VTab(label, active, onclick):
"""Vertical tab button.
Args:
label: String - tab label text
active: Boolean - whether this tab is active
onclick: Function - click handler
"""
with Button(class_='vertical-tab active' if active else 'vertical-tab', onclick=onclick):
yield label
@component
def VerticalTabs():
"""Vertical tabs for settings categories."""
@@ -20,19 +49,11 @@ def VerticalTabs():
setting_tab = value
with Div(class_="vertical-tabs"):
# Vertical tab menu - clean ternary syntax!
# Vertical tab menu - using reusable VTab component!
with Div(class_="vertical-tab-menu"):
with Button(class_='vertical-tab active' if setting_tab == 0 else 'vertical-tab',
onclick=lambda: set_setting(0)):
yield "⚙️ General"
with Button(class_='vertical-tab active' if setting_tab == 1 else 'vertical-tab',
onclick=lambda: set_setting(1)):
yield "🔒 Privacy"
with Button(class_='vertical-tab active' if setting_tab == 2 else 'vertical-tab',
onclick=lambda: set_setting(2)):
yield "🚀 Advanced"
yield VTab(label="⚙️ General", active=setting_tab == 0, onclick=lambda: set_setting(0))
yield VTab(label="🔒 Privacy", active=setting_tab == 1, onclick=lambda: set_setting(1))
yield VTab(label="🚀 Advanced", active=setting_tab == 2, onclick=lambda: set_setting(2))
# Vertical tab content
with Div(class_="vertical-tab-content"):
@@ -85,19 +106,11 @@ def Tabs(orientation=0): # 0 = horizontal, 1 = vertical
with P(class_="subtitle"):
yield "Beautiful composition with TabMenu and TabPane components"
# Tab menu - clean ternary syntax!
# Tab menu - using reusable HTab component!
with Ul(class_="tab-menu"):
with Li(class_='tab active' if tab_index == 0 else 'tab'):
with Button(onclick=lambda: set_tab(0)):
yield "🏠 Home"
with Li(class_='tab active' if tab_index == 1 else 'tab'):
with Button(onclick=lambda: set_tab(1)):
yield "👤 Profile"
with Li(class_='tab active' if tab_index == 2 else 'tab'):
with Button(onclick=lambda: set_tab(2)):
yield "⚙️ Settings"
yield HTab(label="🏠 Home", active=tab_index == 0, onclick=lambda: set_tab(0))
yield HTab(label="👤 Profile", active=tab_index == 1, onclick=lambda: set_tab(1))
yield HTab(label="⚙️ Settings", active=tab_index == 2, onclick=lambda: set_tab(2))
# Tab panes - match/case for clean switching
with Div(class_="tab-content"):