87 lines
4.5 KiB
Markdown
87 lines
4.5 KiB
Markdown
# etaf-ui
|
||
|
||
`etaf-ui` is the official ETAF Component catalog. It is a normal optional package above `etaf`; it does not add a second Control or Widget model. Button, Checkbox, Label, Panel, and DataGrid are all ordinary Components with the same View, props, slots, events, and Data contracts.
|
||
|
||
```elisp
|
||
(require 'etaf-ui)
|
||
|
||
(let ((done (etaf-ref nil)))
|
||
(etaf-view
|
||
(panel :title "Account"
|
||
(slot :name 'header
|
||
(button :label "Save" :ref 'save-button
|
||
:on-press (lambda () (message "saved"))))
|
||
(label :text "Preferences")
|
||
(checkbox :checked (etaf-value done) :label "Done"
|
||
:ref 'done-checkbox
|
||
:on-change (lambda (next)
|
||
(setf (etaf-value done) next))))))
|
||
```
|
||
|
||
In `.etaf` files use the short registered tags (`panel`, `label`, `button`,
|
||
`checkbox`, and `data-grid`) for structure. The companion `.el` file owns
|
||
reactive values, Actions, Behaviors, and callbacks; keep the `etaf-view` tree
|
||
made from those same short tags. Canonical `etaf-*` names remain the Elisp
|
||
definition and API names.
|
||
|
||
Button and Checkbox are controlled Components. `etaf-button` accepts `:label`,
|
||
`:on-press`, `:disabled`, `:ref`, and the small presentation set
|
||
`:class`, `:color`, `:bgcolor`, `:border`, `:padding`, `:face`, `:tab-index`,
|
||
and `:aria-label`, plus `:use` for a public Behavior list. An enabled button
|
||
defaults to role `button` and tab index `0`; a disabled button keeps its label
|
||
and disabled styling but has no press handler, Behavior, or tab stop.
|
||
`etaf-checkbox` accepts `:checked`, `:label`,
|
||
`:on-change`, `:disabled`, `:ref`, and the same presentation props. It exposes
|
||
role `checkbox`, a stable `:ref`, and tab index `0` while enabled. Its
|
||
`:on-change` receives the next boolean value; disabled checkboxes have no
|
||
handler or tab stop.
|
||
|
||
Component `:styles` declarations own default appearance. A non-nil
|
||
presentation prop supplied by the caller wins; an omitted or nil prop leaves
|
||
the inherited Theme/default style available. Button has the deliberately small
|
||
`primary`, `secondary`, and `ghost` visual vocabulary; it is a visual variant
|
||
set, not a second widget taxonomy.
|
||
|
||
Enabled buttons and checkboxes expose the same interaction affordances: a hand
|
||
pointer, `mouse-face` hover feedback, a readable `help-echo`, a numeric tab
|
||
stop, and a semantic role. Button presses briefly enter a `pressed` visual
|
||
state. Disabled controls retain their text and disabled appearance but expose
|
||
no callback, pointer activation, or tab stop. The Runtime owns composition of
|
||
an explicit `:on-*` callback with a Behavior callback; the UI package only
|
||
declares the control and its visual state.
|
||
|
||
Spacing is owned by the parent layout, not by Button. Put adjacent controls in
|
||
a `row`/`flex` with an explicit horizontal `:gap`; this keeps each control's
|
||
mouse-face and hit range semantically separate.
|
||
|
||
`etaf-label` accepts `:text`, `:face`, `:class`, `:color`, `:bgcolor`, `:width`,
|
||
`:border`, `:padding`, and `:ref`. `etaf-panel` accepts `:title`, the same
|
||
surface presentation props, and projects the named `header` slot plus the
|
||
default slot.
|
||
|
||
DataGrid accepts column descriptors, a function-valued `:row-key`, and the
|
||
optional `:loading-label`, `:error-label`, `:empty-label`, `:selected-key`, or
|
||
function-valued `:row-selected-p`. When `:on-row-press` is supplied, every
|
||
row is an interactive button: `:row-ref` is required, must return a non-nil
|
||
stable Host reference for each row, and the row receives role `button` and
|
||
tab index `0`. `:on-row-press` receives the row. Without `:on-row-press`, rows
|
||
have no callback or tab stop. `:row-key` remains a required non-nil stable
|
||
scalar identity for retained rows. DataGrid retains one action closure per
|
||
row key, so selection or data Range updates do not recreate handlers for
|
||
unchanged rows.
|
||
|
||
`etaf-pagination` is a controlled Data Component. It accepts a Data controller
|
||
plus stable `:previous-ref` and `:next-ref` values, renders readable `‹`/`›`
|
||
controls and a `Page N / M` summary, and disables the boundary action while a
|
||
page is loading or already at the first/last page. It owns no page state and
|
||
uses the same Button interaction contract.
|
||
|
||
Keyboard focus uses ETAF's public runtime ports: call
|
||
`(etaf-focus-next runtime)` to move through visible Hosts with a numeric
|
||
non-negative `:tab-index`, and dispatch through
|
||
`(etaf-dispatch-event runtime ref 'press)` when an action must be invoked by
|
||
code. Disabled controls and non-interactive DataGrid rows are omitted from
|
||
that tab order.
|
||
|
||
Run `make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs` from this directory.
|