Overzicht van Ito
Ito is een Lua-bibliotheek die is ontwikkeld voor het bouwen van Terminal User Interfaces (TUI's). De bibliotheek maakt gebruik van WebAssembly om terminal-layouts en tekenfuncties direct op een Canvas te renderen, waardoor het gebruik van HTML, CSS of JavaScript voor de interface overbodig is.
Kernfunctionaliteiten
- Layout en Compositie: Ontwikkelaars kunnen interfaces opbouwen met behulp van
VStack (verticaal) en HStack (horizontaal), ondersteund door modifiers voor padding, spacing en uitlijning.
- Statusbeheer: Door middel van
ito.state() kunnen waarden worden bijgehouden die de weergave dynamisch aanpassen, wat essentieel is voor het creëren van interactieve applicatieflows.
- Input-afhandeling: De bibliotheek biedt fijnmazige controle over focusbeheer, toetsenbordevents en specifieke acties voor tekstvelden, zoals
onsubmit en oncancel.
Beschikbare Componenten
Ito bevat een uitgebreide set aan terminal-widgets, waaronder:
- Tekst & Invoer:
Text, TextField (met ondersteuning voor wachtwoorden).
- Controls:
Button, Checkbox, Toggle, en Slider.
- Complexere Views:
List voor navigatie, Choices voor genummerde opties, en ScrollView voor grotere hoeveelheden content.
- Layout-hulpmiddelen:
Grid, ZStack, en Spacer.
Styling en Beperkingen
De visuele weergave kan worden aangepast met tekstmodifiers (zoals :bold(), :dim() en kleuren via RGB) en borders. De bibliotheek is ontworpen binnen de beperkingen van de browser, wat betekent dat er geen directe toegang is tot het bestandssysteem of raw ANSI output.
Een Terminal UI bouwen met Ito
Snelstart
- Dezelfde Lua: Begin met
require("ito") en return een functie die een view bouwt. Gebruik ito.state(value) voor waarden die veranderen.
- Compositie: Combineer elementen met
VStack, HStack, Text en de controls die beschreven zijn in de documentatie.
- Views en modifiers: Gebruik
:spacing(1), :padding(2), :grow(), :bold() en :dim() om views te rangschikken en te stylen.
- Preview: De preview wordt bijgewerkt tijdens het bewerken. Bij een fout blijft de laatste werkende preview zichtbaar.
Een volledig voorbeeld
local ito = require("ito")
local phase = ito.state("edit")
local name = ito.state("")
local saved = ito.state("")
return function()
if phase.value == "edit" then
return ito.VStack({
ito.Text("NAME YOUR PROJECT"):bold(),
ito.TextField(name):label("Project name"):focused()
:on_submit(function(value)
if value:match("%S") then
saved.value = value
phase.value = "done"
end
end)
:on_cancel(function() name.value = "" end),
ito.Text("Enter to save · Esc to clear"):dim():wrap(),
}):spacing(1):padding(1)
end
return ito.VStack({
ito.Text("Saved: " .. saved.value):bold():wrap(),
ito.Button("Edit again", function() phase.value = "edit" end):focused(),
}):spacing(1):padding(1)
end
De playground beheert ito.open(), het venster, het thema en de event loop. Er moet een functie worden geretourneerd die één view bouwt. Een lokale host gebruikt diezelfde view-functie met ito.Window, roept window:event(event) aan voor terminal-events en rendert opnieuw na input. Gebruik de huidige Ito-build van deze branch voor de gedeelde control-toevoegingen. Open geen andere terminal en implementeer geen blokkerende loop in de playground-code.
Input en status
- Actieve controls: De actieve control ontvangt input.
TextField(state) bewerkt een Lua-buffer en tekent een inline caret. Het is geen onafhankelijke HTML-tekstbox.
- Focus:
:focused() vraagt focus aan wanneer een control verschijnt.
:focused(condition) vraagt focus aan wanneer de conditie waar wordt.
- Stabiele focus blijft behouden tijdens redraws.
- Kliks met de pointer geven focus aan een control.
- Tab en Shift-Tab navigeren tussen controls wanneer de actieve control deze niet consumeert. Op de grens kan de browser de preview verlaten. Alleen het actieve tekstveld toont een caret.
- TextField Events:
TextField:on_submit(fn) handelt Enter af.
:on_cancel(fn) handelt Escape af.
- Beiden ontvangen de huidige string.
:on_change(fn) ontvangt feitelijke tekstwijzigingen.
- Cancel draait een waarde niet automatisch terug. Houd een concept apart van de opgeslagen waarde wanneer bewerkingen bij annuleren moeten worden weggegooid.
- Statusbeheer: Gebruik een status zoals
phase = ito.state("choose") en conditionele views voor flows zoals choose → edit → review → done. Voeg :id(phase.value) toe als elke fase een nieuwe interne view-status moet krijgen. Houd de applicatiestatus boven de geretourneerde functie.
- Toetsenbord:
:on_key(function(event) ... end) handelt toetsen af die door de gefocuste control onbehandeld blijven. Return true bij consumptie, anders false. event.key gebruikt: enter, esc, tab, backtab, up, down, left, right, home, end, backspace, of een karakter. Modifiers zijn ctrl, alt, shift en meta.
- Plakken is één
{ type = "paste", text = "..." } event. Dien geplakte nieuwe regels niet in als Enter; de single-line editor zet deze om in spaties.
- State-objecten:
ito.state(value) leest en schrijft via .value. Lees de status tijdens het bouwen van de view; update deze in acties. Het muteren van een gewone tabel meldt Ito niet. Vervang een statuswaarde of verhoog een revisiestatus voor mutabele collecties.
- Compositie:
ito.view(function(props) ... end) definieert een samengestelde view. Aanroepen naar status en ito.remember(function() ... end) daarbinnen moeten een consistente volgorde behouden. Gebruik unieke :id(key) waarden voor veranderende lijsten. Een false child wordt weggelaten.
Views en controls
| API | Doel |
Text(string) | Terminal tekst. Gebruik tostring voor getallen. Accepteert ook { { text, TextStyle(...) }, ... } spans. |
VStack({ views }), HStack({ views }) | Verticale/horizontale layout; :spacing(1) voegt één cel of rij toe. |
TextField(state) | Single-line bewerking; :label(text), :placeholder(text), :hidden() voor wachtwoorden. |
Button(text, action) | Activering via Enter, Spatie of pointer. action() neemt geen argumenten. |
Checkbox(text, boolState), Toggle(text, boolState) | Booleaanse terminal controls. :description(text) en :on_change(fn). |
Slider(numberState, { min = 0, max = 100, step = 1 }) | Aanpassen via pijltjestoetsen; Home/End springen naar de grenzen. :label(text), :suffix(text), :on_change(fn). |
Progress(fraction) | Een terminal-meter, beperkt tot 0–1. :label(text) is optioneel. |
List(items, function(item, index, active) ... end) | Navigeerbare rijen. :selection(numberState), :on_choose(function(item, index) ... end), :height(rows). |
Choices({ { label = "...", description = "..." }, ... }) | Genummerde keuzes plus een tekstantwoord. :onchoose(fn), :onother(fn). |
ScrollView(view):state(ScrollState()):height(rows) | Een begrensd scrollgebied. Wiel-input gebruikt terminal-coördinaten. |
Grid({ GridRow({ views }), ... }), Group({ views }), ZStack({ views }), Spacer() | Gedeelde terminal-compositie en layout. |
Heading(text), Metric(value) | Gemakkelijke, benadrukte tekst (geen browser-typografie). |
Alle bovenstaande namen behoren tot ito. Button, checkbox, toggle en slider accepteren :disabled(condition). Uitgeschakelde en onzichtbare controls ontvangen geen focus.
Layout en uiterlijk
Gebruik de volgende modifiers: :padding(1), :padding({ horizontal = 2 }), :width(cells), :height(rows), :max_height(rows), :grow(), :share(0.5), :align(ito.Alignment.center), :id(key), en :invisible(condition).
:hidden(condition) verwijdert een view uit de layout; de :hidden() van TextField maskeert daarentegen de tekst. Geef de voorkeur aan flexibele breedtes en Text(...):wrap() voor kleine schermen. De playground staat maximaal 160 kolommen en 120 rijen toe. Gebruik scrolling voor meer.
Tekst ondersteunt: :bold(), :dim(), :italic(), :underline(), :strikethrough(), :reverse(), :foreground(ito.rgb(0xc65036)), en :style(ito.TextStyle({ bold = true })). :background(ito.rgb(...)) vult een view. Een border gebruikt :border(ito.theme().borders.rounded) of .plain; :title(text) labelt deze. Lees het host-thema binnen de view-functie. Padding vóór een border/background is binnen; padding daarna is buiten. :accessibility_label(text) benoemt een control zonder de weergave te wijzigen.
De browser levert toetsenbord-, pointer-, plak- en IME-input. Het voegt geen DOM, netwerk, bestandssysteem of raw ANSI output API's toe. Canvas bevat een tekst-fallback, maar reproduceert niet de toegankelijkheid van individuele native HTML-controls. Lua heeft een geheugenlimiet en een instructiebudget; oneindige loops worden gestopt.
Geldige bewerkingen herstarten de app; ongeldige bewerkingen houden de laatste werkende app bruikbaar. Controleer de toetsenbordnavigatie, submit/cancel-transities en smalle breedtes. Houd herhaalde waarden, zoals prijzen, in één variabele. Verzin geen methoden zoals :class(), :css() of :font_size().
Een Terminal UI bouwen met Ito
Snelstart
- Dezelfde Lua: Begin met
require("ito") en return een functie die een view bouwt. Gebruik ito.state(value) voor waarden die veranderen.
- Compositie: Combineer elementen met
VStack, HStack, Text en de controls die beschreven zijn in de documentatie.
- Views en modifiers: Gebruik
:spacing(1), :padding(2), :grow(), :bold() en :dim() om views te rangschikken en te stylen.
- Preview: De preview wordt bijgewerkt tijdens het bewerken. Bij een fout blijft de laatste werkende preview zichtbaar.
Een volledig voorbeeld
local ito = require("ito")
local phase = ito.state("edit")
local name = ito.state("")
local saved = ito.state("")
return function()
if phase.value == "edit" then
return ito.VStack({
ito.Text("NAME YOUR PROJECT"):bold(),
ito.TextField(name):label("Project name"):focused()
:on_submit(function(value)
if value:match("%S") then
saved.value = value
phase.value = "done"
end
end)
:on_cancel(function() name.value = "" end),
ito.Text("Enter to save · Esc to clear"):dim():wrap(),
}):spacing(1):padding(1)
end
return ito.VStack({
ito.Text("Saved: " .. saved.value):bold():wrap(),
ito.Button("Edit again", function() phase.value = "edit" end):focused(),
}):spacing(1):padding(1)
end
De playground beheert ito.open(), het venster, het thema en de event loop. Er moet een functie worden geretourneerd die één view bouwt. Een lokale host gebruikt diezelfde view-functie met ito.Window, roept window:event(event) aan voor terminal-events en rendert opnieuw na input. Gebruik de huidige Ito-build van deze branch voor de gedeelde control-toevoegingen. Open geen andere terminal en implementeer geen blokkerende loop in de playground-code.
Input en status
- Actieve controls: De actieve control ontvangt input.
TextField(state) bewerkt een Lua-buffer en tekent een inline caret. Het is geen onafhankelijke HTML-tekstbox.
- Focus:
:focused() vraagt focus aan wanneer een control verschijnt.
:focused(condition) vraagt focus aan wanneer de conditie waar wordt.
- Stabiele focus blijft behouden tijdens redraws.
- Kliks met de pointer geven focus aan een control.
- Tab en Shift-Tab navigeren tussen controls wanneer de actieve control deze niet consumeert. Op de grens kan de browser de preview verlaten. Alleen het actieve tekstveld toont een caret.
- TextField Events:
TextField:on_submit(fn) handelt Enter af.
:on_cancel(fn) handelt Escape af.
- Beiden ontvangen de huidige string.
:on_change(fn) ontvangt feitelijke tekstwijzigingen.
- Cancel draait een waarde niet automatisch terug. Houd een concept apart van de opgeslagen waarde wanneer bewerkingen bij annuleren moeten worden weggegooid.
- Statusbeheer: Gebruik een status zoals
phase = ito.state("choose") en conditionele views voor flows zoals choose → edit → review → done. Voeg :id(phase.value) toe als elke fase een nieuwe interne view-status moet krijgen. Houd de applicatiestatus boven de geretourneerde functie.
- Toetsenbord:
:on_key(function(event) ... end) handelt toetsen af die door de gefocuste control onbehandeld blijven. Return true bij consumptie, anders false. event.key gebruikt: enter, esc, tab, backtab, up, down, left, right, home, end, backspace, of een karakter. Modifiers zijn ctrl, alt, shift en meta.
- Plakken is één
{ type = "paste", text = "..." } event. Dien geplakte nieuwe regels niet in als Enter; de single-line editor zet deze om in spaties.
- State-objecten:
ito.state(value) leest en schrijft via .value. Lees de status tijdens het bouwen van de view; update deze in acties. Het muteren van een gewone tabel meldt Ito niet. Vervang een statuswaarde of verhoog een revisiestatus voor mutabele collecties.
- Compositie:
ito.view(function(props) ... end) definieert een samengestelde view. Aanroepen naar status en ito.remember(function() ... end) daarbinnen moeten een consistente volgorde behouden. Gebruik unieke :id(key) waarden voor veranderende lijsten. Een false child wordt weggelaten.
Views en controls
| API | Doel |
Text(string) | Terminal tekst. Gebruik tostring voor getallen. Accepteert ook { { text, TextStyle(...) }, ... } spans. |
VStack({ views }), HStack({ views }) | Verticale/horizontale layout; :spacing(1) voegt één cel of rij toe. |
TextField(state) | Single-line bewerking; :label(text), :placeholder(text), :hidden() voor wachtwoorden. |
Button(text, action) | Activering via Enter, Spatie of pointer. action() neemt geen argumenten. |
Checkbox(text, boolState), Toggle(text, boolState) | Booleaanse terminal controls. :description(text) en :on_change(fn). |
Slider(numberState, { min = 0, max = 100, step = 1 }) | Aanpassen via pijltjestoetsen; Home/End springen naar de grenzen. :label(text), :suffix(text), :on_change(fn). |
Progress(fraction) | Een terminal-meter, beperkt tot 0–1. :label(text) is optioneel. |
List(items, function(item, index, active) ... end) | Navigeerbare rijen. :selection(numberState), :on_choose(function(item, index) ... end), :height(rows). |
Choices({ { label = "...", description = "..." }, ... }) | Genummerde keuzes plus een tekstantwoord. :onchoose(fn), :onother(fn). |
ScrollView(view):state(ScrollState()):height(rows) | Een begrensd scrollgebied. Wiel-input gebruikt terminal-coördinaten. |
Grid({ GridRow({ views }), ... }), Group({ views }), ZStack({ views }), Spacer() | Gedeelde terminal-compositie en layout. |
Heading(text), Metric(value) | Gemakkelijke, benadrukte tekst (geen browser-typografie). |
Alle bovenstaande namen behoren tot ito. Button, checkbox, toggle en slider accepteren :disabled(condition). Uitgeschakelde en onzichtbare controls ontvangen geen focus.
Layout en uiterlijk
Gebruik de volgende modifiers: :padding(1), :padding({ horizontal = 2 }), :width(cells), :height(rows), :max_height(rows), :grow(), :share(0.5), :align(ito.Alignment.center), :id(key), en :invisible(condition).
:hidden(condition) verwijdert een view uit de layout; de :hidden() van TextField maskeert daarentegen de tekst. Geef de voorkeur aan flexibele breedtes en Text(...):wrap() voor kleine schermen. De playground staat maximaal 160 kolommen en 120 rijen toe. Gebruik scrolling voor meer.
Tekst ondersteunt: :bold(), :dim(), :italic(), :underline(), :strikethrough(), :reverse(), :foreground(ito.rgb(0xc65036)), en :style(ito.TextStyle({ bold = true })). :background(ito.rgb(...)) vult een view. Een border gebruikt :border(ito.theme().borders.rounded) of .plain; :title(text) labelt deze. Lees het host-thema binnen de view-functie. Padding vóór een border/background is binnen; padding daarna is buiten. :accessibility_label(text) benoemt een control zonder de weergave te wijzigen.
De browser levert toetsenbord-, pointer-, plak- en IME-input. Het voegt geen DOM, netwerk, bestandssysteem of raw ANSI output API's toe. Canvas bevat een tekst-fallback, maar reproduceert niet de toegankelijkheid van individuele native HTML-controls. Lua heeft een geheugenlimiet en een instructiebudget; oneindige loops worden gestopt.
Geldige bewerkingen herstarten de app; ongeldige bewerkingen houden de laatste werkende app bruikbaar. Controleer de toetsenbordnavigatie, submit/cancel-transities en smalle breedtes. Houd herhaalde waarden, zoals prijzen, in één variabele. Verzin geen methoden zoals :class(), :css() of :font_size().