From 55dc24eecc9a235dd26e1d8257d66050683b8a0e Mon Sep 17 00:00:00 2001 From: enzotar Date: Thu, 26 Feb 2026 15:46:55 -0800 Subject: [PATCH] fix: component prop signal wrapping + import demo - emit_component_decl now wraps props in signal-like accessors - Props use { get value() { return props.X; } } pattern - Missing props default to empty string instead of null - Added examples/import-demo.ds demonstrating 3-component import - Zero console errors when rendering imported Card, Badge, Button --- compiler/ds-codegen/src/js_emitter.rs | 9 +++++++-- examples/import-demo.ds | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 examples/import-demo.ds diff --git a/compiler/ds-codegen/src/js_emitter.rs b/compiler/ds-codegen/src/js_emitter.rs index 35f39eb..cbe820f 100644 --- a/compiler/ds-codegen/src/js_emitter.rs +++ b/compiler/ds-codegen/src/js_emitter.rs @@ -466,9 +466,14 @@ impl JsEmitter { fn emit_component_decl(&mut self, comp: &ComponentDecl, graph: &SignalGraph) { self.emit_line(&format!("function DS_{}(props) {{", comp.name)); self.indent += 1; - // Destructure props into local variables + // Destructure props into local signal-compatible variables + // Props may be raw values or signals — wrap in a signal-like accessor for p in &comp.props { - self.emit_line(&format!("const {} = props.{} !== undefined ? props.{} : null;", p.name, p.name, p.name)); + // Create a signal-like wrapper: if prop is already a signal, use it; otherwise wrap + self.emit_line(&format!( + "const {} = (props.{} !== undefined && props.{} !== null) ? (typeof props.{} === 'object' && 'value' in props.{} ? props.{} : {{ get value() {{ return props.{}; }} }}) : {{ get value() {{ return \"\"; }} }};", + p.name, p.name, p.name, p.name, p.name, p.name, p.name + )); } let root_id = self.emit_view_expr(&comp.body, graph); self.emit_line(&format!("return {};", root_id)); diff --git a/examples/import-demo.ds b/examples/import-demo.ds new file mode 100644 index 0000000..9b0c4d8 --- /dev/null +++ b/examples/import-demo.ds @@ -0,0 +1,20 @@ +-- DreamStack Import Demo +-- Demonstrates component imports from registry + +import { Button } from "../registry/components/button" +import { Card } from "../registry/components/card" +import { Badge } from "../registry/components/badge" + +let count = 0 + +view main = column [ + text "🧩 Component Composition" { variant: "title" } + text "Imported 3 components from registry" { variant: "subtitle" } + + Card { title: "Counter Card" } + Badge { label: "imported", variant: "success" } + Button { label: "Click me", variant: "primary" } + + text "Count: {count}" + button "+1" { click: count += 1, variant: "primary" } +]