diff --git a/todo/todo-main.go b/todo/todo-main.go index c43fca3..309cb37 100644 --- a/todo/todo-main.go +++ b/todo/todo-main.go @@ -11,17 +11,20 @@ import ( //go:embed style.css var styleCSS []byte +// Initialize client with embedded styles and ctrl-c handling var AppClient *waveapp.Client = waveapp.MakeClient(waveapp.AppOpts{ CloseOnCtrlC: true, GlobalStyles: styleCSS, }) +// Basic domain types with json tags for props type Todo struct { Id int `json:"id"` Text string `json:"text"` Completed bool `json:"completed"` } +// Prop types demonstrate parent->child data flow type TodoListProps struct { Todos []Todo `json:"todos"` OnToggle func(int) `json:"onToggle"` @@ -40,25 +43,25 @@ type InputFieldProps struct { OnEnter func() `json:"onEnter"` } +// Reusable input component showing keyboard event handling var InputField = waveapp.DefineComponent[InputFieldProps](AppClient, "InputField", func(ctx context.Context, props InputFieldProps) any { + // Example of special key handling with VDomFunc keyDown := &vdom.VDomFunc{ - Type: vdom.ObjectType_Func, - Fn: func(event vdom.VDomEvent) { - if props.OnEnter != nil { - props.OnEnter() - } - }, + Type: vdom.ObjectType_Func, + Fn: func(event vdom.VDomEvent) { props.OnEnter() }, StopPropagation: true, PreventDefault: true, - Keys: []string{"Enter", "Cmd:Enter"}, // Handle both Enter and Cmd+Enter + Keys: []string{"Enter", "Cmd:Enter"}, } return vdom.E("input", vdom.Class("todo-input"), + // Basic input element props vdom.P("type", "text"), vdom.P("placeholder", "What needs to be done?"), vdom.P("value", props.Value), + // Event handler accessing target value vdom.P("onChange", func(e vdom.VDomEvent) { props.OnChange(e.TargetValue) }), @@ -67,14 +70,16 @@ var InputField = waveapp.DefineComponent[InputFieldProps](AppClient, "InputField }, ) +// Item component showing conditional classes and event handling var TodoItem = waveapp.DefineComponent(AppClient, "TodoItem", func(ctx context.Context, props TodoItemProps) any { return vdom.E("div", vdom.Class("todo-item"), + // Conditional class example vdom.ClassIf(props.Todo.Completed, "completed"), vdom.E("input", - vdom.P("type", "checkbox"), vdom.Class("todo-checkbox"), + vdom.P("type", "checkbox"), vdom.P("checked", props.Todo.Completed), vdom.P("onChange", props.OnToggle), ), @@ -91,10 +96,12 @@ var TodoItem = waveapp.DefineComponent(AppClient, "TodoItem", }, ) +// List component demonstrating mapping over data var TodoList = waveapp.DefineComponent(AppClient, "TodoList", func(ctx context.Context, props TodoListProps) any { return vdom.E("div", vdom.Class("todo-list"), + // ForEach example with props passing vdom.ForEach(props.Todos, func(todo Todo) any { return TodoItem(TodoItemProps{ Todo: todo, @@ -106,32 +113,32 @@ var TodoList = waveapp.DefineComponent(AppClient, "TodoList", }, ) +// Root component showing state management and composition var App = waveapp.DefineComponent(AppClient, "App", func(ctx context.Context, _ any) any { - // State using hooks + // Multiple state hooks example todos, setTodos := vdom.UseState(ctx, []Todo{ {Id: 1, Text: "Learn VDOM", Completed: false}, {Id: 2, Text: "Build a todo app", Completed: false}, - {Id: 3, Text: "Profit!", Completed: false}, }) - nextId, setNextId := vdom.UseState(ctx, 4) + nextId, setNextId := vdom.UseState(ctx, 3) inputText, setInputText := vdom.UseState(ctx, "") - // Event handlers + // Event handlers modifying multiple pieces of state addTodo := func() { if inputText == "" { return } - newTodo := Todo{ + setTodos(append(todos, Todo{ Id: nextId, Text: inputText, Completed: false, - } + })) setNextId(nextId + 1) - setTodos(append(todos, newTodo)) setInputText("") } + // Immutable state update pattern toggleTodo := func(id int) { newTodos := make([]Todo, len(todos)) copy(newTodos, todos) @@ -144,6 +151,7 @@ var App = waveapp.DefineComponent(AppClient, "App", setTodos(newTodos) } + // Filter pattern for deletion deleteTodo := func(id int) { newTodos := make([]Todo, 0, len(todos)-1) for _, todo := range todos { @@ -160,6 +168,7 @@ var App = waveapp.DefineComponent(AppClient, "App", vdom.Class("todo-header"), vdom.E("h1", nil, "Todo List"), ), + // Component composition with props vdom.E("div", vdom.Class("todo-form"), InputField(InputFieldProps{