From f3b1660e2fcc444bb955c02528ef823505e91bf1 Mon Sep 17 00:00:00 2001 From: Cass Deckard Date: Sun, 1 Mar 2026 21:09:01 -0800 Subject: [PATCH] Add onDone support for TextView, InputField, and Table (Issue #5) - Add OnDone to config.Primitive and config.PageConfig - SetDoneFunc handlers for Enter/Escape on TextView, InputField, Table - ondone-demo.yaml example page; navigation test - Docs: tview-coverage.md, issue-dependencies.md Simple SetDoneFunc-only implementation; relies on tview calling done for Enter/Escape. Escape works via global binding. Table: note that tview does not call SetDoneFunc for Enter when rows are selectable. Made-with: Cursor --- builder/builder.go | 19 +++++ builder/properties.go | 52 +++++++++++- config/types.go | 3 + docs/issue-dependencies.md | 80 +++++++++++++++++++ docs/tview-coverage.md | 63 +++++++++++++++ example/acceptance/navigation_test.go | 1 + .../KeyNavigation_BackToMain.terminal | 4 +- .../KeyNavigation_MainMenu.terminal | 4 +- .../KeyNavigation_OnDoneDemoPage.terminal | 30 +++++++ .../LayoutAtMultipleSizes.terminal | 4 +- .../KeyNavigation_OnDoneDemoPage.terminal | 10 +++ .../KeyNavigation_MainMenu.terminal | 4 +- .../KeyNavigation_OnDoneDemoPage.terminal | 24 ++++++ .../LayoutAtMultipleSizes.terminal | 4 +- example/config/app.yaml | 2 + example/config/main.yaml | 4 + example/config/ondone-demo.yaml | 39 +++++++++ 17 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 docs/issue-dependencies.md create mode 100644 docs/tview-coverage.md create mode 100644 example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal create mode 100644 example/acceptance/testdata/snapshots/40x10/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal create mode 100644 example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal create mode 100644 example/config/ondone-demo.yaml diff --git a/builder/builder.go b/builder/builder.go index 65f9db9..7168260 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" "github.com/cassdeckard/tviewyaml/config" "github.com/cassdeckard/tviewyaml/template" @@ -385,6 +386,24 @@ func (b *Builder) buildTable(table *tview.Table, cfg *config.PageConfig, bc *Bui table.SetBorder(true) table.SetSelectable(true, false) + + if cfg.OnDone != "" { + onDoneExpr := cfg.OnDone + table.SetDoneFunc(func(key tcell.Key) { + if key != tcell.KeyEnter && key != tcell.KeyEscape { + return + } + doneKey := "Enter" + if key == tcell.KeyEscape { + doneKey = "Escape" + } + b.context.SetStateDirect("__doneKey", doneKey) + if cb, err := b.executor.ExecuteCallback(onDoneExpr); err == nil { + cb() + } + }) + } + return table, nil } diff --git a/builder/properties.go b/builder/properties.go index b6d02f7..88bf38c 100644 --- a/builder/properties.go +++ b/builder/properties.go @@ -105,8 +105,24 @@ func (pm *PropertyMapper) applyTextViewProperties(tv *tview.TextView, prim *conf } if prim.Regions { tv.SetRegions(true) - - // Add region navigation handlers + } + if prim.OnDone != "" && pm.executor != nil { + onDoneExpr := prim.OnDone + tv.SetDoneFunc(func(key tcell.Key) { + if key != tcell.KeyEnter && key != tcell.KeyEscape { + return + } + doneKey := "Enter" + if key == tcell.KeyEscape { + doneKey = "Escape" + } + pm.context.SetStateDirect("__doneKey", doneKey) + if cb, err := pm.executor.ExecuteCallback(onDoneExpr); err == nil { + cb() + } + }) + } else if prim.Regions { + // Add region navigation handlers (only when onDone is not set) tv.SetDoneFunc(func(key tcell.Key) { currentSelection := tv.GetHighlights() if key == tcell.KeyEnter { @@ -144,6 +160,22 @@ func (pm *PropertyMapper) applyInputFieldProperties(input *tview.InputField, pri if prim.Text != "" { input.SetText(prim.Text) } + if prim.OnDone != "" && pm.executor != nil { + onDoneExpr := prim.OnDone + input.SetDoneFunc(func(key tcell.Key) { + if key != tcell.KeyEnter && key != tcell.KeyEscape { + return + } + doneKey := "Enter" + if key == tcell.KeyEscape { + doneKey = "Escape" + } + pm.context.SetStateDirect("__doneKey", doneKey) + if cb, err := pm.executor.ExecuteCallback(onDoneExpr); err == nil { + cb() + } + }) + } return nil } @@ -175,6 +207,22 @@ func (pm *PropertyMapper) applyDropDownProperties(dd *tview.DropDown, prim *conf func (pm *PropertyMapper) applyTableProperties(table *tview.Table, prim *config.Primitive) error { // Table borders, fixed rows/columns, and data are all handled in populateTableData + if prim.OnDone != "" && pm.executor != nil { + onDoneExpr := prim.OnDone + table.SetDoneFunc(func(key tcell.Key) { + if key != tcell.KeyEnter && key != tcell.KeyEscape { + return + } + doneKey := "Enter" + if key == tcell.KeyEscape { + doneKey = "Escape" + } + pm.context.SetStateDirect("__doneKey", doneKey) + if cb, err := pm.executor.ExecuteCallback(onDoneExpr); err == nil { + cb() + } + }) + } return nil } diff --git a/config/types.go b/config/types.go index c67dae1..fe09305 100644 --- a/config/types.go +++ b/config/types.go @@ -45,6 +45,7 @@ type PageConfig struct { FormItems []FormItem `yaml:"formItems,omitempty"` OnSubmit string `yaml:"onSubmit,omitempty"` // Template expression for runFormSubmit (e.g. Submit button) OnCancel string `yaml:"onCancel,omitempty"` // Template expression when form is cancelled (Escape); if unset and OnSubmit set, Escape runs OnSubmit + OnDone string `yaml:"onDone,omitempty"` // Template expression when user presses Enter/Escape (e.g. page-level table) TableData *TableData `yaml:"tableData,omitempty"` // TreeView-specific (for page-level type: treeView) OnNodeSelected string `yaml:"onNodeSelected,omitempty"` // Template expression when a node is selected (state: __selectedNodeText) @@ -92,6 +93,8 @@ type Primitive struct { FormItems []FormItem `yaml:"formItems,omitempty"` OnSubmit string `yaml:"onSubmit,omitempty"` // Template expression for runFormSubmit (nested form) OnCancel string `yaml:"onCancel,omitempty"` // Template expression when form is cancelled (Escape); if unset and OnSubmit set, Escape runs OnSubmit + // onDone: Template expression when user presses Enter/Escape (TextView, InputField, Table) + OnDone string `yaml:"onDone,omitempty"` // Table-specific properties OnCellSelected string `yaml:"onCellSelected,omitempty"` // Template expression when a cell is selected (state: __selectedCellText, __selectedRow, __selectedCol) Borders bool `yaml:"borders,omitempty"` // Show borders between cells diff --git a/docs/issue-dependencies.md b/docs/issue-dependencies.md new file mode 100644 index 0000000..caf41b4 --- /dev/null +++ b/docs/issue-dependencies.md @@ -0,0 +1,80 @@ +# Issue Dependencies and Presentation Demo + +```mermaid +flowchart LR + subgraph demo [Presentation Demo Slides] + cover[Cover] + intro[Introduction] + helloworld[HelloWorld] + inputfield[InputField] + form[Form] + textview1[TextView1] + textview2[TextView2] + table[Table] + treeview[TreeView] + flex[Flex] + grid[Grid] + colors[Colors] + endSlide[End] + end + + subgraph core [Core Navigation - Info Bar] + i17["#17 presentation nav model"] + i5["#5 onDone / SetDoneFunc"] + i6["#6 SetHighlightedFunc"] + i16["#16 region count config"] + end + + subgraph textview [TextView Slides] + i7["#7 SetScrollable / SetChangedFunc"] + end + + subgraph tableIssues [Table Slide] + i8["#8 SetSeparator"] + i9["#9 SetSelectable row/col"] + i10["#10 SetExpansion / NotSelectable"] + i11["#11 SetBorderPadding"] + i15["#15 cross-primitive callbacks"] + end + + subgraph tree [TreeView Slide] + i14["#14 SetAlign / SetTopLevel / SetGraphics / SetPrefixes"] + end + + subgraph layout [Layout Slides] + i12["#12 responsive Grid"] + i13["#13 SetInputCapture per primitive"] + end + + subgraph other [Other Features] + i4["#4 maskCharacter"] + i2["#2 Frame"] + i3["#3 Image"] + end + + i17 -->|depends on| i5 + i17 -->|depends on| i6 + i16 -->|enhances| i6 + + i5 -->|enables| textview1 + i5 -->|enables| inputfield + i5 -->|enables| table + i5 -->|enables| textview2 + i6 -->|enables| i17 + i17 -->|enables| cover + i17 -->|enables| intro + i16 -->|enables| textview2 + + i7 -->|enables| textview1 + i8 -->|enables| table + i9 -->|enables| table + i10 -->|enables| table + i11 -->|enables| table + i15 -->|enables| table + + i14 -->|enables| treeview + i12 -->|enables| grid + i13 -->|enables| flex + i13 -->|enables| grid + i4 -->|enables| form +``` diff --git a/docs/tview-coverage.md b/docs/tview-coverage.md new file mode 100644 index 0000000..d59a571 --- /dev/null +++ b/docs/tview-coverage.md @@ -0,0 +1,63 @@ +# tview Component Coverage in tviewyaml + +This table maps [tview](https://pkg.go.dev/github.com/rivo/tview) primitives and features to their implementation status in tviewyaml. Based on the [tview package documentation](https://pkg.go.dev/github.com/rivo/tview). + +| tview Component | Implemented | Page-Level | Nested/Child | Primary Example Config | Notes | +|-----------------|-------------|------------|--------------|------------------------|-------| +| **Box** | Yes | No | Yes | [box.yaml](../example/config/box.yaml) | Basic container; base class for most primitives | +| **Button** | Yes | No | Yes (in Form) | [button.yaml](../example/config/button.yaml) | Via form buttons or standalone in flex/grid | +| **Checkbox** | Yes | No | Yes (Form item) | [checkbox.yaml](../example/config/checkbox.yaml) | Form item type `checkbox` | +| **DropDown** | Yes | No | Yes (Form item) | [dropdown.yaml](../example/config/dropdown.yaml) | Form item type `dropdown` | +| **Flex** | Yes | Yes | Yes | [flex.yaml](../example/config/flex.yaml) | Row/column layout; `direction: row` or default column | +| **Form** | Yes | Yes | Yes | [form.yaml](../example/config/form.yaml) | With InputField, Checkbox, Dropdown, Button, TextArea | +| **Frame** | No | No | No | — | Wrapper with header/footer text; not in factory | +| **Grid** | Yes | Yes | Yes | [grid.yaml](../example/config/grid.yaml) | Row/column sizing via `gridRows`, `gridColumns` | +| **Image** | No | No | No | — | Form.AddImage exists in tview; no YAML support | +| **InputField** | Yes | No | Yes (Form item) | [inputfield.yaml](../example/config/inputfield.yaml) | Form item type `inputfield`; supports placeholder, acceptance; `onDone` for Enter/Escape when standalone | +| **List** | Yes | Yes | Yes | [list.yaml](../example/config/list.yaml) | MainText, secondaryText, shortcut, onSelected | +| **Modal** | Yes | Yes | No | [modal.yaml](../example/config/modal.yaml), [modal-about.yaml](../example/config/modal-about.yaml), [modal-confirm.yaml](../example/config/modal-confirm.yaml), [modal-help.yaml](../example/config/modal-help.yaml) | Page-level `type: modal`; text + buttons | +| **Pages** | Yes | Yes (root) | Yes | [app.yaml](../example/config/app.yaml), [nested-pages.yaml](../example/config/nested-pages.yaml) | Tab-like page switching; `ref` to YAML files | +| **Table** | Yes | Yes | Yes | [table.yaml](../example/config/table.yaml) | Headers, rows, borders, fixed rows/columns; `onDone` for Enter/Escape | +| **TextArea** | Yes | No | Yes (Form item) | [form.yaml](../example/config/form.yaml) | Form item type `textarea`; multi-line input | +| **TextView** | Yes | No | Yes | [textview.yaml](../example/config/textview.yaml) | Dynamic colors, regions, scrollable; `onDone` for Enter/Escape | +| **TreeView** | Yes | Yes | Yes | [treeview.yaml](../example/config/treeview.yaml), [treeview-standalone.yaml](../example/config/treeview-standalone.yaml), [treeview-modes.yaml](../example/config/treeview-modes.yaml) | Nodes with children; selectable modes | + +## Form Item Types + +Form items supported in `formItems`: + +| Form Item Type | tview Primitive | Example | +|----------------|-----------------|---------| +| `inputfield` | InputField | [form.yaml](../example/config/form.yaml), [inputfield.yaml](../example/config/inputfield.yaml) | +| `checkbox` | Checkbox | [form.yaml](../example/config/form.yaml), [checkbox.yaml](../example/config/checkbox.yaml) | +| `dropdown` | DropDown | [form.yaml](../example/config/form.yaml), [dropdown.yaml](../example/config/dropdown.yaml) | +| `textarea` | TextArea | [form.yaml](../example/config/form.yaml) | +| `button` | Button | All form configs | + +## tview Features Not Yet Implemented + +| Feature | tview API | Notes | +|---------|-----------|-------| +| **Frame** | `tview.NewFrame(primitive)` | Header/footer text around a primitive | +| **Image** | `tview.NewImage()`, `Form.AddImage()` | Terminal image display; form image field | +| **PasswordField** | `Form.AddPasswordField()` | Implemented via `passwordMode: true` on inputfield + SetMaskCharacter('*'). **TODO:** Support custom `maskCharacter` (e.g. `•`) with `'*'` as default. | + +## Callback Support: onDone + +TextView, InputField (standalone), and Table support `onDone`—a template expression that runs when the user presses Enter or Escape. State `__doneKey` is set to `"Enter"` or `"Escape"` before the callback runs, enabling template branching. See [ondone-demo.yaml](../example/config/ondone-demo.yaml). + +Note: tview's Table does not call SetDoneFunc for Enter when rows are selectable—Enter is used for selection. Escape still triggers onDone on selectable tables. + +## Additional Example Configs (Feature Demos) + +| Config | Purpose | +|--------|---------| +| [main.yaml](../example/config/main.yaml) | Demo menu (list of all features) | +| [state-binding.yaml](../example/config/state-binding.yaml) | Template state binding, reactive views | +| [dynamic-pages.yaml](../example/config/dynamic-pages.yaml) | Dynamic page add/remove | +| [modal-yaml.yaml](../example/config/modal-yaml.yaml) | Modals opened from YAML actions | +| [nested-pages-example.yaml](../example/config/nested-pages-example.yaml) | Nested Pages + Form | +| [clock.yaml](../example/config/clock.yaml) | Live-updating clock (template refresh) | +| [ondone-demo.yaml](../example/config/ondone-demo.yaml) | TextView, InputField, Table with `onDone` (Enter/Escape callbacks) | +| [about.yaml](../example/config/about.yaml) | Simple TextView page | +| [help.yaml](../example/config/help.yaml) | Modal help overlay | diff --git a/example/acceptance/navigation_test.go b/example/acceptance/navigation_test.go index fe3090b..6254bcc 100644 --- a/example/acceptance/navigation_test.go +++ b/example/acceptance/navigation_test.go @@ -18,6 +18,7 @@ var navPages = []struct { {"u", "", "ButtonPage", "Button Demo", ""}, {"c", "", "CheckboxPage", "Checkbox Demo", ""}, {"i", "", "InputFieldPage", "InputField Demo", ""}, + {"o", "", "OnDoneDemoPage", "TextView - Enter or Escape", ""}, {"f", "", "FormPage", "Form Demo", "Enter"}, // Escape triggers onCancel modal, Enter dismisses {"l", "", "ListPage", "List Demo", ""}, {"t", "", "TablePage", "Table Demo", ""}, diff --git a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_BackToMain.terminal b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_BackToMain.terminal index 05ff4f5..9a7fd47 100644 --- a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_BackToMain.terminal +++ b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_BackToMain.terminal @@ -1,6 +1,6 @@ ╔═══════════════════════════════════Tview Feature Demos - Select a feature to explore══════════════════════════════════╗ -║(i) InputField ║ -║ Text input with validation ║ +║(o) onDone Demo ║ +║ TextView, InputField, Table with Enter/Escape callbacks ║ ║(f) Form ║ ║ Complete form with all input types ║ ║(l) List ║ diff --git a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_MainMenu.terminal b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_MainMenu.terminal index bf29dd0..2c4d077 100644 --- a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_MainMenu.terminal +++ b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_MainMenu.terminal @@ -9,6 +9,8 @@ ║ Checkboxes with state management ║ ║(i) InputField ║ ║ Text input with validation ║ +║(o) onDone Demo ║ +║ TextView, InputField, Table with Enter/Escape callbacks ║ ║(f) Form ║ ║ Complete form with all input types ║ ║(l) List ║ @@ -25,6 +27,4 @@ ║ Compare auto, true, and false selection behaviors ║ ║(d) DropDown ║ ║ Dropdown menu with options ║ -║(m) Modal ║ -║ YAML-configured vs programmatic modals ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal new file mode 100644 index 0000000..81a3ee1 --- /dev/null +++ b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal @@ -0,0 +1,30 @@ +╔═════════════════════════onDone Demo - Click a panel to focus, then Enter or Escape to return═════════════════════════╗ +║╔═════════════════════════════════════════════TextView - Enter or Escape═════════════════════════════════════════════╗║ +║║ This TextView has onDone. ║║ +║║ Press Enter or Escape to return. ║║ +║║ ║║ +║║ ║║ +║║ ║║ +║║ ║║ +║║ ║║ +║╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝║ +║┌────────────────────────────────────────────InputField - Enter or Escape────────────────────────────────────────────┐║ +║│Type:  │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘║ +║┌───────────────────────────────────────────────Table - Enter or Escape──────────────────────────────────────────────┐║ +║│A B │║ +║│1 2  │║ +║│3 4 │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/LayoutAtMultipleSizes.terminal b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/LayoutAtMultipleSizes.terminal index bf29dd0..2c4d077 100644 --- a/example/acceptance/testdata/snapshots/120x30/TestAcceptance/LayoutAtMultipleSizes.terminal +++ b/example/acceptance/testdata/snapshots/120x30/TestAcceptance/LayoutAtMultipleSizes.terminal @@ -9,6 +9,8 @@ ║ Checkboxes with state management ║ ║(i) InputField ║ ║ Text input with validation ║ +║(o) onDone Demo ║ +║ TextView, InputField, Table with Enter/Escape callbacks ║ ║(f) Form ║ ║ Complete form with all input types ║ ║(l) List ║ @@ -25,6 +27,4 @@ ║ Compare auto, true, and false selection behaviors ║ ║(d) DropDown ║ ║ Dropdown menu with options ║ -║(m) Modal ║ -║ YAML-configured vs programmatic modals ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/40x10/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal b/example/acceptance/testdata/snapshots/40x10/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal new file mode 100644 index 0000000..26b1c07 --- /dev/null +++ b/example/acceptance/testdata/snapshots/40x10/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal @@ -0,0 +1,10 @@ +╔lick a panel to focus, then Enter or …╗ +║╔═════TextView - Enter or Escape═════╗║ +║╚════════════════════════════════════╝║ +║┌────InputField - Enter or Escape────┐║ +║│Type:  │║ +║└────────────────────────────────────┘║ +║┌───────Table - Enter or Escape──────┐║ +║│A B │║ +║└────────────────────────────────────┘║ +╚══════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_MainMenu.terminal b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_MainMenu.terminal index def1074..4135455 100644 --- a/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_MainMenu.terminal +++ b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_MainMenu.terminal @@ -9,6 +9,8 @@ ║ Checkboxes with state management ║ ║(i) InputField ║ ║ Text input with validation ║ +║(o) onDone Demo ║ +║ TextView, InputField, Table with Enter/Escape callbacks ║ ║(f) Form ║ ║ Complete form with all input types ║ ║(l) List ║ @@ -19,6 +21,4 @@ ║ Text display with colors and regions ║ ║(r) TreeView ║ ║ Hierarchical tree view ║ -║(e) TreeView (standalone page) ║ -║ Top-level page with type: treeView ║ ╚══════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal new file mode 100644 index 0000000..b7d89a6 --- /dev/null +++ b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/KeyNavigation_OnDoneDemoPage.terminal @@ -0,0 +1,24 @@ +╔═════onDone Demo - Click a panel to focus, then Enter or Escape to return═════╗ +║╔═════════════════════════TextView - Enter or Escape═════════════════════════╗║ +║║ This TextView has onDone. ║║ +║║ Press Enter or Escape to return. ║║ +║║ ║║ +║║ ║║ +║║ ║║ +║╚════════════════════════════════════════════════════════════════════════════╝║ +║┌────────────────────────InputField - Enter or Escape────────────────────────┐║ +║│Type:  │║ +║│ │║ +║│ │║ +║│ │║ +║│ │║ +║└────────────────────────────────────────────────────────────────────────────┘║ +║┌───────────────────────────Table - Enter or Escape──────────────────────────┐║ +║│A B │║ +║│1 2  │║ +║│3 4 │║ +║│ │║ +║│ │║ +║│ │║ +║└────────────────────────────────────────────────────────────────────────────┘║ +╚══════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/acceptance/testdata/snapshots/80x24/TestAcceptance/LayoutAtMultipleSizes.terminal b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/LayoutAtMultipleSizes.terminal index def1074..4135455 100644 --- a/example/acceptance/testdata/snapshots/80x24/TestAcceptance/LayoutAtMultipleSizes.terminal +++ b/example/acceptance/testdata/snapshots/80x24/TestAcceptance/LayoutAtMultipleSizes.terminal @@ -9,6 +9,8 @@ ║ Checkboxes with state management ║ ║(i) InputField ║ ║ Text input with validation ║ +║(o) onDone Demo ║ +║ TextView, InputField, Table with Enter/Escape callbacks ║ ║(f) Form ║ ║ Complete form with all input types ║ ║(l) List ║ @@ -19,6 +21,4 @@ ║ Text display with colors and regions ║ ║(r) TreeView ║ ║ Hierarchical tree view ║ -║(e) TreeView (standalone page) ║ -║ Top-level page with type: treeView ║ ╚══════════════════════════════════════════════════════════════════════════════╝ \ No newline at end of file diff --git a/example/config/app.yaml b/example/config/app.yaml index cf21dcd..9200387 100644 --- a/example/config/app.yaml +++ b/example/config/app.yaml @@ -98,6 +98,8 @@ application: ref: clock.yaml - name: inputfield ref: inputfield.yaml + - name: ondone-demo + ref: ondone-demo.yaml - name: list ref: list.yaml - name: modal diff --git a/example/config/main.yaml b/example/config/main.yaml index 5c7afae..8b39ce8 100644 --- a/example/config/main.yaml +++ b/example/config/main.yaml @@ -23,6 +23,10 @@ listItems: secondaryText: "Text input with validation" shortcut: "i" onSelected: '{{ switchToPage "inputfield" }}' + - mainText: "onDone Demo" + secondaryText: "TextView, InputField, Table with Enter/Escape callbacks" + shortcut: "o" + onSelected: '{{ switchToPage "ondone-demo" }}' - mainText: "Form" secondaryText: "Complete form with all input types" shortcut: "f" diff --git a/example/config/ondone-demo.yaml b/example/config/ondone-demo.yaml new file mode 100644 index 0000000..480a24e --- /dev/null +++ b/example/config/ondone-demo.yaml @@ -0,0 +1,39 @@ +type: flex +direction: row +border: true +title: "onDone Demo - Click a panel to focus, then Enter or Escape to return" +items: + - primitive: + type: textView + border: true + title: "TextView - Enter or Escape" + text: | + This TextView has onDone. + Press Enter or Escape to return. + textAlign: center + onDone: '{{ switchToPage "main" }}' + fixedSize: 0 + proportion: 1 + focus: true + - primitive: + type: inputField + border: true + title: "InputField - Enter or Escape" + label: "Type: " + text: "" + onDone: '{{ switchToPage "main" }}' + fixedSize: 0 + proportion: 1 + focus: true + - primitive: + type: table + border: true + title: "Table - Enter or Escape" + columns: ["A", "B"] + rows: + - ["1", "2"] + - ["3", "4"] + onDone: '{{ switchToPage "main" }}' + fixedSize: 0 + proportion: 1 + focus: true