// App.el — native-hello root component. // // Demonstrates the el-native widget system: // - Window created from manifest.el // - VStack layout // - Label, Button, TextField // - Click and change event callbacks // - Style token application // // This is the manual API that the el-ui-compiler's native codegen target will // eventually emit. For now it shows exactly what apps (and the compiler) need // to produce. import "../../vessels/el-native/src/main.el" // ── State ───────────────────────────────────────────────────────────────────── // Global state — holds the widget handles so callbacks can reference them. // In a real component system, these would be scoped to the component instance. let g_window: Int = -1 let g_label: Int = -1 let g_input: Int = -1 let g_button: Int = -1 let g_counter: Int = 0 let g_counter_lbl: Int = -1 // ── Callbacks ───────────────────────────────────────────────────────────────── // // Callbacks must be top-level functions with the signature: // fn name(widget: Int, data: String) -> Void // The C bridge resolves them by symbol name via dlsym. fn on_greet_click(widget: Int, data: String) -> Void { let name: String = widget_get_text(g_input) let greeting: String = if str_len(name) > 0 { "Hello, " + name + "!" } else { "Hello, World!" } widget_set_text(g_label, greeting) } fn on_counter_click(widget: Int, data: String) -> Void { let g_counter = g_counter + 1 widget_set_text(g_counter_lbl, "Clicks: " + int_to_str(g_counter)) } fn on_name_change(widget: Int, data: String) -> Void { // Enable the greet button only when there is text in the field. // (data is the current text value) let has_text: Bool = str_len(data) > 0 widget_set_disabled(g_button, !has_text) } // ── App build ───────────────────────────────────────────────────────────────── fn app_build(window: Int) -> Void { // Root vertical stack — full-window content. let root: Int = vstack(0) widget_set_padding_all(root, 24) widget_set_bg_color_hex(root, "#0f172a") widget_set_flex(root, 1) // Title label. let title: Int = label("el-native — native widget demo") style_label_heading(title) widget_add_child(root, title) // Spacer (empty label acts as a gap). let gap1: Int = label("") widget_set_height(gap1, 16) widget_add_child(root, gap1) // Subtitle. let subtitle: Int = label("AppKit controls from el code, no ObjC in the app layer.") style_label_muted(subtitle) widget_add_child(root, subtitle) // Divider gap. let gap2: Int = label("") widget_set_height(gap2, 24) widget_add_child(root, gap2) // Name input row. let input_row: Int = hstack(8) let name_label: Int = label("Name:") style_label_body(name_label) widget_set_width(name_label, 60) let input: Int = text_field("Enter your name…") style_label_body(input) widget_set_flex(input, 1) widget_on_change(input, "on_name_change") let g_input = input // stash handle let greet_btn: Int = button("Greet") style_button_primary(greet_btn) widget_set_disabled(greet_btn, true) // disabled until name is typed widget_on_click(greet_btn, "on_greet_click") let g_button = greet_btn widget_add_child(input_row, name_label) widget_add_child(input_row, input) widget_add_child(input_row, greet_btn) widget_add_child(root, input_row) // Greeting output label. let gap3: Int = label("") widget_set_height(gap3, 12) widget_add_child(root, gap3) let greeting: Int = label("Waiting for name…") style_label_body(greeting) widget_set_color_hex(greeting, "#60a5fa") widget_set_font(greeting, "system", 16, true) let g_label = greeting widget_add_child(root, greeting) // Counter row. let gap4: Int = label("") widget_set_height(gap4, 24) widget_add_child(root, gap4) let counter_row: Int = hstack(12) let counter_lbl: Int = label("Clicks: 0") style_label_body(counter_lbl) let g_counter_lbl = counter_lbl let counter_btn: Int = button("Click me") style_button_primary(counter_btn) widget_on_click(counter_btn, "on_counter_click") widget_add_child(counter_row, counter_lbl) widget_add_child(counter_row, counter_btn) widget_add_child(root, counter_row) // Attach root to window. widget_add_child(window, root) }