A terminal style form being filled in, field by field.
A settings form drawn the way a terminal app draws one. As upstream
draws it, a focus marker tabs down through a text input, a select, radio
buttons, a checkbox, a switch and a slider, changes each, saves, then
changes them back. Give it fields and it draws your form instead, for
a reader to fill in with keys and clicks.
Options
Give them to Ascii.new/2 as options:, and new ones while it plays
with Ascii.put_options/2 (or a Phoenix player's options): the form
is drawn anew from them. Give only what you mean to change: what a reader
has filled in is in its options already, and giving back older values
would undo keys typed since.
fields- your form, a list of maps, each with atypeand alabel, and its type's own keys. Default[]: upstream's tour."text"- an input holdingtext."select"- one ofchoices, the one at indexchoice."radio"-choicesas radio buttons,choicethe one set."checkbox"-choicesas checkboxes,checkeda boolean for each; with nochoices, one box."switch"-onor off."slider"-valuefrommintomax(0 to 100 by default), in steps ofstep(1; 0 for a hundredth of the range), with itsunitafter it ("%"," ms").
A field with no
typeis a text field; one of a type it does not know is its label alone.buttons- the buttons' names, at the right under the fields. Default["cancel", "save"].focus- the field, or after them the button, in focus, from 0;-1for none. Default0.status- a note at the left of the buttons, such as"saved". Default"".title- the form's name, in its top edge. Default"preferences".cols- the frame's width, 32 to 200; 54 by default.
All but title are for a form of your own: the tour is always 54 by 16.
A form's fields take two rows each, so its frame is
2 * length(fields) + 4 rows. Controls are cut at the right edge, and
buttons that do not fit left out; a focused text field shows the end of
its text, so the caret stays in view. Control characters in its strings
are shown as spaces.
Colours
In one ink, or a gradient, with :ink and :gradient (see
Ascii.Ink); part by part with :parts (see Ascii.Parts),
parts: true taking the colours suggested here:
frame- the border, grey; and the controls' own,frame.input,frame.select(with its arrow) andframe.menu, the tour's open list.title- the form's name in the border.focus- the marker at the focused field or button (or the list's chosen item, or a row's checkbox that keys tick), yellow.label- a field's name;label.focus, the focused one's, yellow.field- what a field holds: its text, the choices' names, on or off.cursor- a text field's caret, yellow.checked,unchecked- radio buttons' and checkboxes' marks, green and grey.bar,knob,track- a switch's and a slider's filled cells, blue; the knob; and the empty cells and the switch's ends, grey.value,unit- a slider's reading.button- a button;button.focus, the focused one, yellow.status- a form's note;status.ok, the tour's saved note, green.key,hint- the keys along the bottom, yellow, and what they do, grey.
Keys and clicks
A form of your own takes keys and clicks with
Ascii.handle_event/2, changing fields and focus, from which the
app reads what was filled in and where the focus is:
- Tab and back tab move the focus round the fields and buttons; up and down move it and stop at the ends; home and end go to the first and last; enter on a field goes on to the next.
- A text field in focus takes printable characters, up to 256, and backspace.
- Space steps a select or radio buttons on, flips a switch, and ticks
the checkbox marked
>. - Left and right step a select or radio buttons, move the checkbox mark, turn a switch off and on, move a slider a step (page up and page down, ten), and move along the buttons.
- Enter or space on a button is the app's: it is ignored, and
focussays which button. - A click takes the focus to the field or button it lands on, and picks the radio button, ticks the checkbox, flips the switch or sets the slider where it lands; on a select already in focus, it steps it on.
The tour takes none. In Phoenix, give the player interactive (and
notify to be told of each key and click); there Tab is the page's, to
move on from the form, so up and down move between fields. In
ExRatatui, Ascii.ExRatatui.handle_event/3; in a terminal,
mix ascii.play form-controls --option 'fields=[{"label": "name"}]' --interactive.
Screen readers
Ascii.describe/1 reads the form, each field's label and value and
where the focus is, as "account: email ada@example.com, plan free,
volume 40%; focus on plan"; past 160 characters it ends ", and N more".
Playing its tour, it gives the piece's name and note.
Example
fields = [
%{type: "text", label: "email", text: "ada@example.com"},
%{type: "radio", label: "plan", choices: ["free", "team"], choice: 1},
%{type: "slider", label: "volume", value: 40, unit: "%"}
]
form = Ascii.new!("form-controls", options: %{title: "account", fields: fields}, parts: true)
{:ok, form} = Ascii.handle_event(form, {:key, "tab"})
{:ok, form} = Ascii.handle_event(form, {:key, "left"})
Enum.at(form.options.fields, 1).choice
#=> 0
Ascii.describe(form)
#=> "account: email ada@example.com, plan free, volume 40%; focus on plan"<Ascii.Phoenix.live_player id="account" piece="form-controls" options={%{title: "account", fields: @fields}} parts interactive notify />Ported from src/pieces/form-controls.ts in bas3line/ascii (MIT).