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:
1 parent
1575571f3e
commit
134ddc4c42
5 files changed
+429
-624
No files matched your search
+392
-590
File diff suppressed because it is too large.
Load diff
+37
-24
@@ -11,6 +11,35 @@ Demonstrates:
|
|||||||
from ritz.syntax import *
|
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
|
@component
|
||||||
def VerticalTabs():
|
def VerticalTabs():
|
||||||
"""Vertical tabs for settings categories."""
|
"""Vertical tabs for settings categories."""
|
||||||
@@ -20,19 +49,11 @@ def VerticalTabs():
|
|||||||
setting_tab = value
|
setting_tab = value
|
||||||
|
|
||||||
with Div(class_="vertical-tabs"):
|
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 Div(class_="vertical-tab-menu"):
|
||||||
with Button(class_='vertical-tab active' if setting_tab == 0 else 'vertical-tab',
|
yield VTab(label="⚙️ General", active=setting_tab == 0, onclick=lambda: set_setting(0))
|
||||||
onclick=lambda: set_setting(0)):
|
yield VTab(label="🔒 Privacy", active=setting_tab == 1, onclick=lambda: set_setting(1))
|
||||||
yield "⚙️ General"
|
yield VTab(label="🚀 Advanced", active=setting_tab == 2, onclick=lambda: set_setting(2))
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
# Vertical tab content
|
# Vertical tab content
|
||||||
with Div(class_="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"):
|
with P(class_="subtitle"):
|
||||||
yield "Beautiful composition with TabMenu and TabPane components"
|
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 Ul(class_="tab-menu"):
|
||||||
with Li(class_='tab active' if tab_index == 0 else 'tab'):
|
yield HTab(label="🏠 Home", active=tab_index == 0, onclick=lambda: set_tab(0))
|
||||||
with Button(onclick=lambda: set_tab(0)):
|
yield HTab(label="👤 Profile", active=tab_index == 1, onclick=lambda: set_tab(1))
|
||||||
yield "🏠 Home"
|
yield HTab(label="⚙️ Settings", active=tab_index == 2, onclick=lambda: set_tab(2))
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
# Tab panes - match/case for clean switching
|
# Tab panes - match/case for clean switching
|
||||||
with Div(class_="tab-content"):
|
with Div(class_="tab-content"):
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -916,11 +916,6 @@ class SignalLLVMIRGenerator:
|
|||||||
else:
|
else:
|
||||||
self.lines.append(f" %{elem_var} = call i32 @render_{component_name}()")
|
self.lines.append(f" %{elem_var} = call i32 @render_{component_name}()")
|
||||||
|
|
||||||
# Append to parent if we have one
|
|
||||||
if self.parent_element_stack:
|
|
||||||
parent_var = self.parent_element_stack[-1]
|
|
||||||
self.lines.append(f" call void @js_append_child(i32 %{parent_var}, i32 %{elem_var})")
|
|
||||||
|
|
||||||
return elem_var
|
return elem_var
|
||||||
|
|
||||||
def _emit_match(self, stmt: dict[str, Any]) -> str | None:
|
def _emit_match(self, stmt: dict[str, Any]) -> str | None:
|
||||||
@@ -1165,11 +1160,6 @@ class SignalLLVMIRGenerator:
|
|||||||
# Pop parent
|
# Pop parent
|
||||||
self.parent_element_stack.pop()
|
self.parent_element_stack.pop()
|
||||||
|
|
||||||
# If we're inside an if/match branch (have a grandparent), append to it
|
|
||||||
if self.parent_element_stack:
|
|
||||||
parent_var = self.parent_element_stack[-1]
|
|
||||||
self.lines.append(f" call void @js_append_child(i32 %{parent_var}, i32 %{elem_var})")
|
|
||||||
|
|
||||||
return elem_var
|
return elem_var
|
||||||
|
|
||||||
def _emit_yield(self, stmt: dict[str, Any]) -> str | None:
|
def _emit_yield(self, stmt: dict[str, Any]) -> str | None:
|
||||||
|
|||||||
Reference in new issue
Block a user