From 2b2b8978d8c973ed3a17eb6ea01ad4085b60a2e1 Mon Sep 17 00:00:00 2001 From: Hugo Nijhuis Date: Fri, 9 Jan 2026 17:23:47 +0100 Subject: [PATCH] Remove internal package import from todo example Replace direct internal/element usage with public ui package components to ensure examples only use the public API: - Add ui.RawCheckbox for plain checkbox without label wrapper - Add ui.Span for span elements with text content - Add View.TextDecoration modifier for strikethrough styling - Update todo example to use these public components Co-Authored-By: Claude Opus 4.5 --- examples/todo/main.go | 22 ++++++---------------- ui/input.go | 21 ++++++++++++++++++++- ui/modifiers.go | 5 +++++ ui/text.go | 7 +++++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/examples/todo/main.go b/examples/todo/main.go index 46806bd..91bba00 100644 --- a/examples/todo/main.go +++ b/examples/todo/main.go @@ -6,7 +6,6 @@ import ( "fmt" "syscall/js" - "git.flowmade.one/flowmade-one/iris/internal/element" "git.flowmade.one/flowmade-one/iris/reactive" "git.flowmade.one/flowmade-one/iris/ui" ) @@ -142,28 +141,19 @@ func todoItem(todo Todo, todos *reactive.Signal[[]Todo]) ui.View { row.Display("flex").Gap("12px").Padding("8px 0").Width("100%").AlignItems("center") row.BorderBottom("1px solid #eee") - // Completed checkbox - checkbox := element.NewElement("input") - checkbox.Attr("type", "checkbox") - if todo.Completed { - checkbox.Set("checked", true) - } - checkbox.On("change", func() { - isChecked := checkbox.Get("checked").Bool() + // Completed checkbox using public ui.RawCheckbox + checkbox := ui.RawCheckbox(todo.Completed, func(isChecked bool) { toggleTodo(todos, todo.ID, isChecked) }) - checkboxView := ui.NewViewFromElement(checkbox) // Todo text with strikethrough if completed textView := ui.NewView() textView.Display("flex").Width("100%") - text := element.NewElement("span") - text.Set("textContent", todo.Text) + text := ui.Span(todo.Text) if todo.Completed { - text.Get("style").Call("setProperty", "text-decoration", "line-through") - text.Get("style").Call("setProperty", "color", "#999") + text.TextDecoration("line-through").Color("#999") } - textView.Child(ui.NewViewFromElement(text)) + textView.Child(text) // Delete button deleteBtn := ui.Button(func() { @@ -171,7 +161,7 @@ func todoItem(todo Todo, todos *reactive.Signal[[]Todo]) ui.View { }, ui.TextFromString("X")) deleteBtn.Padding("4px 8px") - row.Child(checkboxView) + row.Child(checkbox) row.Child(textView) row.Child(deleteBtn) diff --git a/ui/input.go b/ui/input.go index 0410301..f82a362 100644 --- a/ui/input.go +++ b/ui/input.go @@ -205,4 +205,23 @@ func NumberInput(value *reactive.Signal[float64], placeholder string) View { }) return View{input} -} \ No newline at end of file +} +// RawCheckbox creates a plain checkbox input without a label wrapper. +// The onChange callback is called with the new checked state when the user clicks. +func RawCheckbox(checked bool, onChange func(bool)) View { + checkbox := element.NewElement("input") + checkbox.Attr("type", "checkbox") + + // Set initial state + if checked { + checkbox.Set("checked", true) + } + + // Call onChange when user clicks + checkbox.On("change", func() { + newValue := checkbox.Get("checked").Bool() + onChange(newValue) + }) + + return View{checkbox} +} diff --git a/ui/modifiers.go b/ui/modifiers.go index 0b4bcdd..0ae4b14 100644 --- a/ui/modifiers.go +++ b/ui/modifiers.go @@ -170,3 +170,8 @@ func (v View) PointerEvents(value string) View { v.e.PointerEvents(value) return v } + +func (v View) TextDecoration(value string) View { + v.e.Get("style").Call("setProperty", "text-decoration", value) + return v +} diff --git a/ui/text.go b/ui/text.go index e5a5590..ea6fd6b 100644 --- a/ui/text.go +++ b/ui/text.go @@ -21,3 +21,10 @@ func TextFromFunction(fn func() string) View { return View{textNode} } + +// Span creates a span element with the given text content. +func Span(text string) View { + v := View{element.NewElement("span")} + v.e.Set("textContent", text) + return v +}