@zeyos/zx 2.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +138 -0
- package/DESIGN-SYSTEM.md +96 -0
- package/README.md +29 -39
- package/dist/types/components/account-menu/account-menu.d.ts +144 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +243 -0
- package/dist/types/components/avatar/avatar.d.ts +100 -0
- package/dist/types/components/card/card.d.ts +128 -0
- package/dist/types/components/chart/chart.d.ts +322 -0
- package/dist/types/components/date-picker/month-picker.d.ts +6 -0
- package/dist/types/components/dialog/dialog.d.ts +9 -0
- package/dist/types/components/dock/dock.d.ts +495 -0
- package/dist/types/components/dropdown/dropdown.d.ts +2 -2
- package/dist/types/components/field/field.d.ts +14 -0
- package/dist/types/components/field-upload/field-upload.d.ts +37 -4
- package/dist/types/components/form/form.d.ts +25 -3
- package/dist/types/components/grid/grid.d.ts +172 -0
- package/dist/types/components/launcher/launcher.d.ts +359 -0
- package/dist/types/components/layout/layout.d.ts +4 -4
- package/dist/types/components/menu-button/menu-button.d.ts +10 -2
- package/dist/types/components/modal/modal.d.ts +25 -0
- package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +7 -1
- package/dist/types/components/questionnaire/items.d.ts +327 -0
- package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
- package/dist/types/components/select/select.d.ts +51 -0
- package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
- package/dist/types/components/sheet/sheet.d.ts +294 -0
- package/dist/types/components/split-view/split-view.d.ts +2 -21
- package/dist/types/components/table/table.d.ts +223 -15
- package/dist/types/components/tooltip/tooltip.d.ts +2 -2
- package/dist/types/components/value-list/value-list.d.ts +24 -3
- package/dist/types/core/dom.d.ts +122 -0
- package/dist/types/core/drag-axis.d.ts +111 -0
- package/dist/types/core/position.d.ts +4 -2
- package/dist/types/index.d.ts +13 -2
- package/dist/types/internal/app-rail.d.ts +265 -0
- package/dist/types/zeyos/icons.d.ts +5 -0
- package/dist/types/zeyos/index.d.ts +2 -1
- package/dist/types/zeyos/launcher.d.ts +147 -0
- package/dist/types/zeyos/select.d.ts +39 -0
- package/dist/zx-zeyos.esm.js +1870 -133
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +2006 -267
- package/dist/zx.esm.js +8987 -2757
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +8987 -2757
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +4396 -2344
- package/docs/llms.md +463 -86
- package/docs/llms.txt +32 -19
- package/package.json +10 -17
- package/src/components/account-menu/account-menu.css +70 -0
- package/src/components/account-menu/account-menu.js +208 -0
- package/src/components/app-rail/app-rail.css +107 -0
- package/src/components/app-sidebar/app-sidebar.css +80 -0
- package/src/components/app-sidebar/app-sidebar.js +588 -0
- package/src/components/avatar/avatar.css +61 -0
- package/src/components/avatar/avatar.js +222 -0
- package/src/components/button/button.css +0 -1
- package/src/components/card/card.css +149 -0
- package/src/components/card/card.js +285 -0
- package/src/components/chart/chart.css +61 -0
- package/src/components/chart/chart.js +523 -0
- package/src/components/date-picker/month-picker.js +9 -0
- package/src/components/dialog/dialog.js +11 -4
- package/src/components/dock/dock.css +228 -0
- package/src/components/dock/dock.js +977 -0
- package/src/components/dropdown/dropdown.js +1 -1
- package/src/components/field/field.js +2 -0
- package/src/components/field-upload/field-upload.js +9 -4
- package/src/components/form/form.js +6 -3
- package/src/components/grid/grid.css +6 -0
- package/src/components/grid/grid.js +220 -0
- package/src/components/launcher/launcher.css +210 -0
- package/src/components/launcher/launcher.js +765 -0
- package/src/components/layout/layout.js +2 -2
- package/src/components/menu-button/menu-button.js +27 -2
- package/src/components/modal/modal.css +5 -1
- package/src/components/modal/modal.js +37 -2
- package/src/components/multi-value-editor/multi-value-editor.js +2 -1
- package/src/components/questionnaire/items.js +370 -0
- package/src/components/questionnaire/questionnaire.css +387 -0
- package/src/components/questionnaire/questionnaire.js +1033 -0
- package/src/components/select/field-adapter.js +9 -4
- package/src/components/select/select.css +144 -11
- package/src/components/select/select.js +259 -27
- package/src/components/sheet/sheet-stack.js +304 -0
- package/src/components/sheet/sheet.css +351 -0
- package/src/components/sheet/sheet.js +551 -0
- package/src/components/split-view/split-view.js +76 -161
- package/src/components/table/table.css +43 -0
- package/src/components/table/table.js +531 -52
- package/src/components/tooltip/tooltip.js +5 -2
- package/src/components/value-list/value-list.js +6 -3
- package/src/core/dom.js +322 -0
- package/src/core/drag-axis.js +203 -0
- package/src/core/position.js +68 -22
- package/src/index.js +20 -2
- package/src/internal/app-rail.js +718 -0
- package/src/zeyos/icons.js +8 -3
- package/src/zeyos/index.js +7 -1
- package/src/zeyos/launcher.js +338 -0
- package/src/zeyos/modules.js +1 -0
- package/src/zeyos/select.js +115 -1
- package/styles/tokens/dark.css +2 -3
- package/styles/tokens/global.css +6 -6
- package/styles/tokens/modules.css +1 -0
- package/styles/tokens/semantic.css +5 -3
- package/styles/tokens/themes.css +1 -1
- package/styles/zx.css +11 -1
- package/MIGRATION.md +0 -598
- package/dist/types/compat/base.d.ts +0 -156
- package/dist/types/compat/globals.d.ts +0 -20
- package/dist/types/compat/index.d.ts +0 -128
- package/dist/types/compat/map/basic.d.ts +0 -175
- package/dist/types/compat/map/data.d.ts +0 -102
- package/dist/types/compat/map/date-time.d.ts +0 -80
- package/dist/types/compat/map/factory.d.ts +0 -9
- package/dist/types/compat/map/form.d.ts +0 -98
- package/dist/types/compat/map/helpers.d.ts +0 -12
- package/dist/types/compat/map/http.d.ts +0 -36
- package/dist/types/compat/map/layout.d.ts +0 -106
- package/dist/types/compat/map/options.d.ts +0 -80
- package/dist/types/compat/map/select.d.ts +0 -95
- package/dist/types/compat/map/stubs.d.ts +0 -32
- package/dist/types/compat/map/utilities.d.ts +0 -37
- package/dist/types/compat-entry.d.ts +0 -5
- package/dist/types/components/permission/permission.d.ts +0 -96
- package/dist/zx-compat.esm.js +0 -17484
- package/dist/zx-compat.esm.min.js +0 -1
- package/dist/zx-compat.global.js +0 -23635
- package/dist/zx-compat.global.min.js +0 -3
- package/src/compat/base.js +0 -291
- package/src/compat/globals.js +0 -165
- package/src/compat/index.js +0 -84
- package/src/compat/map/basic.js +0 -464
- package/src/compat/map/data.js +0 -232
- package/src/compat/map/date-time.js +0 -177
- package/src/compat/map/factory.js +0 -45
- package/src/compat/map/form.js +0 -330
- package/src/compat/map/helpers.js +0 -46
- package/src/compat/map/http.js +0 -117
- package/src/compat/map/layout.js +0 -256
- package/src/compat/map/options.js +0 -267
- package/src/compat/map/select.js +0 -198
- package/src/compat/map/stubs.js +0 -26
- package/src/compat/map/utilities.js +0 -113
- package/src/compat-entry.js +0 -11
- package/src/components/permission/permission.css +0 -47
- package/src/components/permission/permission.js +0 -201
package/docs/llms.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Zx — agent reference
|
|
1
|
+
# Xenon Design System (Zx) — agent reference
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> Xenon is a dependency-free design system for browser applications; Zx is its product-agnostic
|
|
4
|
+
> vanilla-JavaScript implementation. ES2022 modules, WAI-ARIA-accessible native controls, semantic `--zx-*` design
|
|
5
5
|
> tokens (light/dark + cozy/compact), and lifecycle-safe components. Zero runtime dependencies.
|
|
6
6
|
> This file is the single, complete reference a coding agent needs to build UI with Zx; each
|
|
7
7
|
> component below is wrapped in `<!-- doc:<name> -->` markers so tools can extract a single
|
|
@@ -61,7 +61,7 @@ need not be set). A preset repoints five tier-1 tokens — `--zx-accent-300` …
|
|
|
61
61
|
and the semantic tier takes its own stop per polarity (600/700 on light surfaces, 300/400/500 on
|
|
62
62
|
dark), so one five-line block rethemes light, dark, and auto together. Status colours are not part
|
|
63
63
|
of a preset. Define your own the same way, or build one at `/theme.html` (the theme studio, which
|
|
64
|
-
renders every component live and exports the CSS):
|
|
64
|
+
renders every component family live and exports the CSS):
|
|
65
65
|
|
|
66
66
|
```css
|
|
67
67
|
:root {
|
|
@@ -85,8 +85,8 @@ override that works (global token → then, if needed, a component style).
|
|
|
85
85
|
|
|
86
86
|
For ZeyOS business data use the **dedicated client library** `@zeyos/client`
|
|
87
87
|
(`npm install @zeyos/client`) — a zero-dependency, typed OpenAPI client (accounts,
|
|
88
|
-
transactions/invoices, tickets, 50+ resources), OAuth2/session auth, retries, schema
|
|
89
|
-
introspection.
|
|
88
|
+
transactions/invoices, tickets, 50+ resources), OAuth2/session auth, retries, and schema
|
|
89
|
+
introspection. Zx accepts the client by injection and does not bundle it.
|
|
90
90
|
|
|
91
91
|
```js
|
|
92
92
|
import { createZeyosClient, MemoryTokenStore, normalizeListResult } from '@zeyos/client';
|
|
@@ -207,15 +207,6 @@ reflection and ElementInternals form association: `<zx-toggle>`, `<zx-check-butt
|
|
|
207
207
|
`<zx-checklist>`, `<zx-datebox>`, `<zx-timebox>`, `<zx-search>`, `<zx-groupbox>`, `<zx-tabbox>`,
|
|
208
208
|
`<zx-table>`, `<zx-dialog>`.
|
|
209
209
|
|
|
210
|
-
## gx compatibility
|
|
211
|
-
|
|
212
|
-
Load `zx-compat.global.js` (or import `zx-compat.esm.js`) →
|
|
213
|
-
`window.gx.{core,ui,util,zeyos,bootstrap}` wrapping Zx components (constructor/option/event-name
|
|
214
|
-
translation, MooTools-style `addEvent`). `gx.compat.installGlobals()` (opt-in) installs `__()`,
|
|
215
|
-
`_()`, `String.htmlSpecialChars`, and the element `store/retrieve` shim. Full namespace listing in
|
|
216
|
-
the "gx compatibility layer" component section below; class map and unsupported legacy APIs in
|
|
217
|
-
`MIGRATION.md`.
|
|
218
|
-
|
|
219
210
|
## Conventions (editing component source)
|
|
220
211
|
|
|
221
212
|
Follow `AGENTS.md`. Key rules: never declare instance class fields for state used in `render()`
|
|
@@ -228,14 +219,13 @@ pattern with `:focus-visible` rings and `prefers-reduced-motion` guards.
|
|
|
228
219
|
|
|
229
220
|
```
|
|
230
221
|
src/components/<name>/ component + CSS src/core/ kernel (component, dom, http, i18n, date…)
|
|
231
|
-
src/compat/ gx compat layer styles/ tokens + base.css
|
|
232
222
|
website/ marketing page + docs.html (docs.js) specs/ per-component specs
|
|
233
223
|
website/demos/ per-component demo modules website/layouts/ application layout examples
|
|
234
224
|
tests/ node unit + smoke dist/ built bundles
|
|
235
225
|
|
|
236
226
|
npm run serve # http://127.0.0.1:8321/website/docs.html (no build)
|
|
237
227
|
npm test # node --test tests/unit/*.test.js + node tests/lint-tokens.js
|
|
238
|
-
npm run build # dist/:
|
|
228
|
+
npm run build # dist/: ESM, global, ZeyOS binding, and CSS assets
|
|
239
229
|
node tools/build-module-tokens.js # regenerate styles/tokens/modules.css from src/zeyos/modules.js
|
|
240
230
|
```
|
|
241
231
|
|
|
@@ -418,31 +408,107 @@ Search input with embedded search and clear buttons (`role="search"`).
|
|
|
418
408
|
- **Events** — `input {value}` (debounced), `submit {value}` (Enter or the button), `clear`.
|
|
419
409
|
<!-- /doc -->
|
|
420
410
|
|
|
411
|
+
<!-- doc:launcher -->
|
|
412
|
+
### Launcher — application and record search
|
|
413
|
+
|
|
414
|
+
A native-dialog launcher for applications, recent records, commands, and grouped remote results.
|
|
415
|
+
Zx owns ranking, focus, request cancellation, and presentation; ZeyOS owns the catalogue,
|
|
416
|
+
permissions, recent-history/cache policy, and the route or command ultimately invoked.
|
|
417
|
+
|
|
418
|
+
- **Constructor** — `new Launcher(null, options)` owns a body-level dialog;
|
|
419
|
+
`new Launcher(existingDialog, options)` enhances and later restores an existing `<dialog>`.
|
|
420
|
+
- **Options** — `items`, abortable `sources: [{id, label?, minQuery?, when?, order?, load(query, {signal})}]`,
|
|
421
|
+
`query`, `debounce: 250`, `minQuery: 0`, `maxResults: 100`, `placeholder`, `label`, `emptyText`,
|
|
422
|
+
`loadingText`, `shortcut: 'mod+k'|false`, and visible `hints` labels (or `false`).
|
|
423
|
+
- **Items** — `{id, label, description?, keywords?, group?, icon?, badge?, value?, href?, target?,
|
|
424
|
+
invoke?, pinned?, disabled?, kind?, current?, when?, groupOrder?, itemOrder?}`. `icon` accepts a
|
|
425
|
+
bundled icon name, Node, or factory. Links stay native so modified and middle clicks work;
|
|
426
|
+
non-link commands may provide an application-owned `invoke` callback. Malformed and executable
|
|
427
|
+
URL schemes are stripped; a descriptor with no safe link or callback is disabled.
|
|
428
|
+
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `focus()`, `setQuery()`, `getQuery()`,
|
|
429
|
+
`setItems()`, `setCurrent()`, `setSources()`, `destroy()`.
|
|
430
|
+
- **Events** — cancelable `select {item, value, source, query}`, `query {query}`, `open`, `close`,
|
|
431
|
+
and `error {source, error}`. Preventing `select` suppresses the supplied link or callback.
|
|
432
|
+
- **Ranking** — local results are case/diacritic-insensitive and deterministic: exact label,
|
|
433
|
+
label prefix, word prefix, label substring, identifier substring, then acronym prefix. Pinned
|
|
434
|
+
items retain an explicit order ahead of otherwise equal results. A new async query aborts and
|
|
435
|
+
ignores stale source work.
|
|
436
|
+
- **Keyboard** — Cmd+K on macOS or Ctrl+K elsewhere opens by default; the shortcut is ignored in
|
|
437
|
+
editable controls, composition, and modal contexts. Application tiles use spatial arrow-key
|
|
438
|
+
movement; Up/Down may continue into record groups. Home/End, Page Up/Down, and Enter operate the
|
|
439
|
+
single listbox selection model; Escape closes and restores focus. `aria-current` marks the
|
|
440
|
+
active destination independently from the keyboard's `aria-selected` option.
|
|
441
|
+
- **Optional ZeyOS adapter** — import `zeyosLauncher()` or `buildZeyosLauncherConfig()` from
|
|
442
|
+
`@zeyos/zx/zeyos`. The adapter receives the permitted module/menu catalogue, pins, current
|
|
443
|
+
identifier, recent loader or cache, abortable search, destination resolvers, and application/
|
|
444
|
+
record icon renderers explicitly. It maps the complete shell payload without reading globals or
|
|
445
|
+
taking over application routing.
|
|
446
|
+
<!-- /doc -->
|
|
447
|
+
|
|
448
|
+
<!-- doc:avatar -->
|
|
449
|
+
### Avatar
|
|
450
|
+
|
|
451
|
+
A fixed-geometry user image with deterministic initials fallback. Image loading or failure never
|
|
452
|
+
changes layout, and the component is decorative by default so adjacent identity text is not
|
|
453
|
+
announced twice.
|
|
454
|
+
|
|
455
|
+
- **Options** — `src`, `name`, `initials`, `label`, `size: 'sm'|'md'|'lg'|<pixels>`,
|
|
456
|
+
`shape: 'circle'|'rounded'|'square'`, `status: 'online'|'away'|'busy'|'offline'|null`, and
|
|
457
|
+
`statusLabel`.
|
|
458
|
+
- **Methods** — `set(values)`, `setStatus(status, label?)`, `hasImage()`, `destroy()`.
|
|
459
|
+
- **Accessibility** — set `label` only when the avatar stands alone. Presence is supplementary
|
|
460
|
+
status, not the account's accessible name; supply `statusLabel` when it conveys information.
|
|
461
|
+
<!-- /doc -->
|
|
462
|
+
|
|
463
|
+
<!-- doc:account-menu -->
|
|
464
|
+
### AccountMenu
|
|
465
|
+
|
|
466
|
+
Composes `Avatar` and `MenuButton` into one account trigger and APG menu. The popup repeats the
|
|
467
|
+
identity before its actions; Zx never decides role visibility, changes preferences, signs a user
|
|
468
|
+
out, or mutates the session.
|
|
469
|
+
|
|
470
|
+
- **Options** — `account: {name, secondary, src?, initials?, status?, statusLabel?}`, `items`,
|
|
471
|
+
`compact: false`, `label`, and any top/bottom/left/right `placement`.
|
|
472
|
+
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `setAccount()`, `setItems()`, `focus()`,
|
|
473
|
+
`getPanel()`, `destroy()`.
|
|
474
|
+
- **Events** — cancelable `select {value, item}`, `open`, and `close`. A canceled selection does
|
|
475
|
+
not run the item's callback and leaves the menu open, so an application can reject or confirm an
|
|
476
|
+
action without rebuilding the account surface.
|
|
477
|
+
- **Accessibility** — compact mode is visually avatar-only but keeps the full account-menu name on
|
|
478
|
+
its single native trigger; MenuButton retains focus return, typeahead, and arrow-key behavior.
|
|
479
|
+
<!-- /doc -->
|
|
480
|
+
|
|
421
481
|
<!-- doc:select -->
|
|
422
482
|
### Select — APG editable combobox
|
|
423
483
|
|
|
424
484
|
Unifies single-select, local filtering, and async loading.
|
|
425
485
|
|
|
426
486
|
- **Options** — `items: []`, `fixedItems: []`, `valueKey: 'ID'` (string key or `(item)=>id`),
|
|
427
|
-
`labelKey: 'name'` (string or `(item)=>string`), `renderItem`, `renderValue`,
|
|
428
|
-
`
|
|
429
|
-
`
|
|
487
|
+
`labelKey: 'name'` (string or `(item)=>string`), `renderItem`, `renderValue`,
|
|
488
|
+
`renderValueAdornment`, `renderNone`, `noneLabel`, `actions`, `value`, `disabled`, `placeholder`,
|
|
489
|
+
`clearable: false`, `filter: false | 'local' | async (query)=>items`, `searchKeys`,
|
|
490
|
+
`minQuery: 0`, `debounce: 200`, `listHeight: 280`, `groupKey`.
|
|
430
491
|
- **Getters** — `.value`, `.selected`.
|
|
431
|
-
- **Methods** — `set(id, {silent})`, `setItems()`, `setFixedItems()`, `
|
|
432
|
-
`enable()`/`disable()`, `focus()`.
|
|
433
|
-
- **Events** — `change {value, item}` (`item` is null on clear),
|
|
434
|
-
`loaded {items}`.
|
|
492
|
+
- **Methods** — `set(id, {silent})`, `setItems()`, `setFixedItems()`, `setActions()`, `reset()`,
|
|
493
|
+
`open()`/`close()`, `enable()`/`disable()`, `focus()`.
|
|
494
|
+
- **Events** — `change {value, item}` (`item` is null on clear), preventable
|
|
495
|
+
`action {id, action, query, select}`, `open`, `close`, `query {query}`, `loaded {items}`.
|
|
435
496
|
- **Fixed choices** — `fixedItems` pins entries to the top of the list, separated by a rule (the
|
|
436
497
|
rule is dropped when `groupKey` is on, since a heading already divides them). They belong to the
|
|
437
498
|
control, not to its data: a `filter` function replaces `items` on every query, while the pinned
|
|
438
499
|
entries are narrowed locally against the same query and stay resolvable by `set()`. They survive
|
|
439
500
|
`setItems()` and are shown below `minQuery`. Use them for choices with no row in the source —
|
|
440
501
|
"Unassigned", "Everyone", "Private".
|
|
441
|
-
- **Presets** — `Select.priority(target, opts)
|
|
442
|
-
`Select.
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
`
|
|
502
|
+
- **Presets** — `Select.priority(target, opts)` renders the five-level, five-square ZeyOS priority
|
|
503
|
+
scale; `Select.status(target, opts)` supplies shape- and semantic-color-distinct workflow states
|
|
504
|
+
and accepts replacement `items`; `Select.permission(target, {groups, value})` pins Private and
|
|
505
|
+
Public above record-access groups. Its value is the tri-state ZeyOS stores (`false` private,
|
|
506
|
+
`true` public, or a group ID), and `groups` takes an array or loader `(query)=>items`.
|
|
507
|
+
- **ZeyOS entity preset** — import `zeyosEntitySelect(client, resource, options)` or the DOM-free
|
|
508
|
+
`buildZeyosEntitySelectConfig()` from `@zeyos/zx/zeyos`. It composes the async client binding
|
|
509
|
+
with module-colored icons, subtitle/group readers, a deliberate none row, and an optional
|
|
510
|
+
application-owned create command. The selected value remains the record ID and exact product
|
|
511
|
+
glyphs stay injectable through `renderIcon`.
|
|
446
512
|
- **Keyboard** (APG combobox) — ArrowDown/Alt+ArrowDown open; arrows navigate and wrap; Home/End;
|
|
447
513
|
Enter selects; Esc closes; Tab closes; printable characters filter (editable) or run a typeahead
|
|
448
514
|
(readonly). `aria-activedescendant` tracks the active option.
|
|
@@ -675,6 +741,102 @@ Structured modal: a header with title and close button, a body, and footer butto
|
|
|
675
741
|
`Dialog.prompt({ title, message, value })` → string|null.
|
|
676
742
|
<!-- /doc -->
|
|
677
743
|
|
|
744
|
+
<!-- doc:sheet -->
|
|
745
|
+
### Sheet
|
|
746
|
+
|
|
747
|
+
Edge-anchored surface — a `Dialog` attached to one side of the viewport instead of floating in the
|
|
748
|
+
middle. One primitive covers both side sheets and mobile drawers, which differ mainly in the edge they take, so
|
|
749
|
+
`side` replaces what would otherwise be two components. Inherits the whole Dialog anatomy: title,
|
|
750
|
+
footer buttons, switchable views, and focus restoration.
|
|
751
|
+
|
|
752
|
+
- **Options** — `side: 'end'` (`'start' | 'end' | 'top' | 'bottom'`, logical), `modal: true`
|
|
753
|
+
(`true | 'trap-focus' | false`), `backdrop: 'dim'` (`'dim' | 'blur' | 'none'`), `size: null`
|
|
754
|
+
(CSS length or px number, applied to whichever axis `side` implies), `closeButton: true`,
|
|
755
|
+
plus everything Dialog takes — `title`, `content`, `buttons`, `closable`, `lightDismiss`
|
|
756
|
+
(defaults to `true` here, unlike Modal), `destroyOnClose`.
|
|
757
|
+
- **Methods** — `open()`, `close(result?)`, `setSide(side)`, `getSide()`, `setSize(size)`,
|
|
758
|
+
`isModal()`, `isDocked()`, `isOpen()`, `getSize()`, `snapTo(target)`, plus Dialog's `setTitle()`, `setContent()`,
|
|
759
|
+
`setButtons()`, `addView()`, `showView()`.
|
|
760
|
+
- **Events** — `open`, `close {result}`, `cancel` (preventable with `event.preventDefault()`),
|
|
761
|
+
`resize {size, ratio}`, `dockchange {docked, dock}`.
|
|
762
|
+
- **Docked** — a sheet has two lives, and it does not choose between them: `Dock.adopt(sheet)`
|
|
763
|
+
makes it a track in that dock's flow instead of an overlay, and the dock then owns its side,
|
|
764
|
+
size, and resizing. A docked sheet is always non-modal, `close()` collapses its track to zero
|
|
765
|
+
rather than sliding away, and Escape and outside-click stop dismissing it — it is part of the
|
|
766
|
+
layout, not something covering it. `Dock.release(sheet)` hands it back. Nothing is rebuilt
|
|
767
|
+
across a handoff: the element moves and reopens in place, so DOM state and listeners survive,
|
|
768
|
+
and no `open`/`close` is emitted for what is only a change of address.
|
|
769
|
+
- **Modality** — `true` delegates focus containment, page inertness, Escape, and the backdrop to
|
|
770
|
+
the browser through `showModal()`. `'trap-focus'` and `false` open with `show()`, so the page
|
|
771
|
+
keeps scrolling and stays interactive; Escape and outside-click are re-implemented, and
|
|
772
|
+
`'trap-focus'` adds `focusTrap()` on top. Only a modal sheet renders a `::backdrop`, so
|
|
773
|
+
`backdrop` is meaningful only when `modal` is `true`.
|
|
774
|
+
- **Resizing and detents** — `resizable` makes the inner edge draggable between `min` and `max`.
|
|
775
|
+
`snap` gives it detents: a number at or below 1 is a fraction of the viewport along the sheet's
|
|
776
|
+
axis, anything larger is pixels, and a string is any CSS length (`'320px'`, `'90%'`). With
|
|
777
|
+
detents a drag settles on the nearest one rather than where it was released, and `snapTo(index)`
|
|
778
|
+
or `snapTo(value)` moves there directly. Dragging below half the smallest allowed size dismisses
|
|
779
|
+
a `closable` sheet, so resize, detent, and swipe-to-dismiss are one gesture whose meaning is
|
|
780
|
+
decided when the pointer settles. `getSize()` reports the current pixel size. A sheet that is
|
|
781
|
+
neither `resizable` nor snapping still has a draggable handle where `handle` shows one — that is
|
|
782
|
+
what makes a drawer dismissible — but the drag may only take size away, never add it, so it
|
|
783
|
+
cannot be grown by dragging when nothing asked for resizing.
|
|
784
|
+
- **Handle** — `handle: 'auto'` shows a grab handle on `top` and `bottom` sheets, which is what
|
|
785
|
+
makes them read as drawers; `true` and `false` force it either way. It exists whenever the sheet
|
|
786
|
+
is `resizable` or has `snap`, visible or not. It is a `separator` with live
|
|
787
|
+
`aria-valuenow`/`aria-valuemin`/`aria-valuemax`: arrow keys along the axis step it by 16px, Shift
|
|
788
|
+
by 64px. A docked sheet hides its handle — the dock's own divider resizes it there.
|
|
789
|
+
- **Custom properties** — `--zx-sheet-size` (written by `size`; the per-side default otherwise)
|
|
790
|
+
and `--zx-sheet-radius` (inner corners of a top/bottom sheet, default `--zx-radius-xl`) are
|
|
791
|
+
internal geometry, not published styling hooks — prefer the options. `--zx-overlay-blur` is a
|
|
792
|
+
tier-2 semantic token and is public: it sets the `'blur'` backdrop's radius, default `8px`.
|
|
793
|
+
- **Motion** — entry and exit both animate, via `@starting-style` and
|
|
794
|
+
`transition-behavior: allow-discrete` on `display`/`overlay`; without them the sheet appears and
|
|
795
|
+
disappears instantly. All of it sits inside `prefers-reduced-motion: no-preference`.
|
|
796
|
+
- **Keyboard and screen readers** — identical to Dialog: the native `<dialog>` supplies the role
|
|
797
|
+
and `aria-labelledby` points at the title. Escape closes when `closable`, focus moves to the
|
|
798
|
+
`[autofocus]` control or the first focusable descendant on open, and returns to the opener on
|
|
799
|
+
close. Tab cycles within the sheet when `modal` is `true` or `'trap-focus'`.
|
|
800
|
+
<!-- /doc -->
|
|
801
|
+
|
|
802
|
+
<!-- doc:sheet-stack -->
|
|
803
|
+
### SheetStack
|
|
804
|
+
|
|
805
|
+
An ordered group of Sheets that reads as one drill-down. Deliberately tiny, because the browser
|
|
806
|
+
already does the hard part: nested dialogs stack in the top layer by open order, so there is no
|
|
807
|
+
z-index bookkeeping, and Escape closes only the topmost, so unwinding one level at a time is
|
|
808
|
+
native. What is left is which sheet sits at which depth, written onto the elements as `data-depth`
|
|
809
|
+
and `--zx-sheet-depth` for CSS to interpret.
|
|
810
|
+
|
|
811
|
+
Owns no element, so it is a controller rather than a `Component` — constructed with options
|
|
812
|
+
alone, `new SheetStack({…})`.
|
|
813
|
+
|
|
814
|
+
- **Options** — `layout: 'stack'` (`'stack' | 'cascade'`), `offset: 24`, `scale: 0.04`, `max: 3`.
|
|
815
|
+
- **Methods** — `push(sheet)`, `pop()`, `popTo(sheet)`, `clear()`, `top()`, `size()`, `sheets()`,
|
|
816
|
+
`has(sheet)`, `on/off/once`, `destroy()`.
|
|
817
|
+
- **Events** — `push {sheet, depth}`, `pop {sheet}`. `pop` fires however a sheet left — popped,
|
|
818
|
+
dismissed with Escape, or closed by its own button.
|
|
819
|
+
- **Layouts** — `stack` slides each covered sheet back toward its own edge, scales it down, and
|
|
820
|
+
takes it out of the tab order; only the top one is usable, which is the drill-down feel.
|
|
821
|
+
`cascade` shifts each covered sheet clear of the ones in front — by their measured size, not a
|
|
822
|
+
guess — so they sit side by side and all stay usable. `cascade` is usually the right one for an
|
|
823
|
+
ERP screen, where the parent record should stay readable while a line item is edited.
|
|
824
|
+
- **Depth** — numbered from the top: the visible sheet is `0`. Past `max` a sheet stops being
|
|
825
|
+
drawn but stays open and in the stack. In a `stack` only the topmost backdrop shades the page;
|
|
826
|
+
one per depth would compound into black. A `cascade` shades nothing — a backdrop paints directly
|
|
827
|
+
beneath its own dialog in the top layer, so the top sheet's would dim exactly the sheets the
|
|
828
|
+
layout exists to keep readable. Pair a cascade with `modal: false` when the page behind it
|
|
829
|
+
should stay live as well.
|
|
830
|
+
- **Ownership** — the stack never owns its sheets. `destroy()` empties it and strips the depth
|
|
831
|
+
styling without closing anything.
|
|
832
|
+
- **Accessibility** — for `stack`, covered sheets are `inert`. The browser does that on its own
|
|
833
|
+
for stacked *modal* dialogs, but a non-modal stack gets nothing, so the attribute is set either
|
|
834
|
+
way. `cascade` deliberately leaves them interactive.
|
|
835
|
+
- **Gotcha** — `close()` on a dialog dispatches its `close` event in a queued task, not
|
|
836
|
+
synchronously. `pop()` therefore removes the sheet from the stack itself rather than waiting for
|
|
837
|
+
the event, so `popTo()` and `clear()` can loop without racing it.
|
|
838
|
+
<!-- /doc -->
|
|
839
|
+
|
|
678
840
|
<!-- doc:dropdown -->
|
|
679
841
|
### Dropdown
|
|
680
842
|
|
|
@@ -682,7 +844,8 @@ Generic anchored popover in the top layer, constructed as `new Dropdown(anchor,
|
|
|
682
844
|
light-dismisses on an outside click or Esc, and mirrors `aria-expanded` onto the anchor.
|
|
683
845
|
|
|
684
846
|
- **Options** — `content`,
|
|
685
|
-
`placement: 'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'
|
|
847
|
+
`placement: 'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'` plus the matching
|
|
848
|
+
`left*` and `right*` placements, `offset: 4`,
|
|
686
849
|
`matchWidth: false`, `openOn: 'click'|'manual'`, `closeOnSelect: false`.
|
|
687
850
|
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `setContent()`, `getPanel()`.
|
|
688
851
|
- **Events** — `open`, `close`.
|
|
@@ -695,8 +858,11 @@ A button that opens a `role="menu"`.
|
|
|
695
858
|
|
|
696
859
|
- **Options** — `label`, `icon`, `kind`,
|
|
697
860
|
`items: [{ label, icon?, value?, disabled?, danger?, onselect? } | '-']`, `placement`.
|
|
698
|
-
- **Methods** — `setItems()`, `open()`, `close()`, `setLabel()
|
|
861
|
+
- **Methods** — `setItems()`, `open()`, `close()`, `setLabel()`, `getTrigger()`, `getPanel()`,
|
|
862
|
+
`focusFirst()`, `focusLast()`.
|
|
699
863
|
- **Events** — `select {value, item}`, `open`, `close`.
|
|
864
|
+
- **Cancellation** — `select` is cancelable. Preventing it skips the item's `onselect` callback and
|
|
865
|
+
leaves the menu open, which is the composition seam used by `AccountMenu` and rail flyouts.
|
|
700
866
|
- **Keyboard** — ArrowDown/Enter/Space open and focus the first item; ArrowUp opens and focuses the
|
|
701
867
|
last; arrows cycle; Home/End; typeahead; Enter/Space select; Esc/Tab close.
|
|
702
868
|
<!-- /doc -->
|
|
@@ -734,7 +900,11 @@ parked at the pointer, so it flips near a viewport edge like every other floatin
|
|
|
734
900
|
|
|
735
901
|
A description bubble anchored to another element. The panel is a manual popover positioned by the kernel's `position()`, so it escapes clipping and stacking contexts and flips near a viewport edge; it carries `role="tooltip"` and a generated id, and the anchor gets `aria-describedby` pointing at it only while it is open — closing puts the anchor's original value back, including no value at all. The bubble is never interactive: `pointer-events: none` keeps it from stealing the hover it depends on, and nothing inside it can take focus. Hover opens it after `delay`; keyboard focus opens it immediately, because a keyboard user cannot hover a moment longer; a touch pointer never opens it, since a bubble with no "move away" gesture would simply stick. Only one is ever visible at a time, which falls out of the dismissal rules rather than a registry.
|
|
736
902
|
|
|
737
|
-
- **Options** — `content` (string, Node, or a function re-evaluated on every open), `placement`
|
|
903
|
+
- **Options** — `content` (string, Node, or a function re-evaluated on every open), `placement`
|
|
904
|
+
(`'top'` default, plus top/bottom/left/right and their start/end variants), `offset` (6), `delay`
|
|
905
|
+
(400), `hideDelay` (80), `maxWidth` (260; a number is pixels, a string is any CSS length),
|
|
906
|
+
`trigger` (`'both'` default, or `'hover'`, `'focus'`, `'manual'` — `manual` installs no listeners
|
|
907
|
+
at all and leaves everything to the methods), `disabled` (false).
|
|
738
908
|
- **Methods** — `show()`, `hide()`, `toggle()`, `isOpen()`, `setContent(content)`, `enable()`, `disable()`, `isDisabled()`, `getAnchor()`, `destroy()`. Convenience factories: `tooltip(anchor, contentOrOptions)` takes either a content value or a full option object, and `describe(anchor, text)` is the one-liner replacement for a `title` attribute. Both return the instance.
|
|
739
909
|
- **Events** — `open`, `close`. Both fire only on a real transition, so a `show()` on an open tooltip is silent.
|
|
740
910
|
- **Keyboard** — Focusing the anchor opens the tooltip at once; moving focus away closes it. `Escape` closes it without moving focus, satisfying WCAG 1.4.13. A `pointerdown` anywhere closes it, and focus that arrives with a click does not re-open it.
|
|
@@ -754,27 +924,37 @@ Two panes with a divider the user owns. The layout is a three-track CSS grid dri
|
|
|
754
924
|
<!-- doc:table -->
|
|
755
925
|
### Table
|
|
756
926
|
|
|
757
|
-
Sortable, selectable, sticky-header data table
|
|
758
|
-
|
|
759
|
-
|
|
927
|
+
Sortable, selectable, sticky-header data table. `fr` widths fill the container while px/auto
|
|
928
|
+
widths scroll horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
|
|
929
|
+
range select.
|
|
760
930
|
|
|
761
931
|
- **Options** — `columns: [{ id, label, sortable?, width ('120px'|'2fr'|'auto'), align,
|
|
932
|
+
type?: 'text'|'number'|'currency'|'percent'|'unit', locale?, decimals?, currency?, unit?,
|
|
762
933
|
render?: (row,i)=>Node|string, sortValue?, headerTitle? }]`, `data`, `rowId: 'ID'`,
|
|
763
934
|
`sort: { id, dir }`, `sortMode: 'local'|'server'`, `selectable: false|'single'|'multi'`,
|
|
764
|
-
`stickyHeader: true`, `height`, `emptyText`, `rowClass`, `zebra: true
|
|
935
|
+
`stickyHeader: true`, `height`, `emptyText`, `rowClass`, `zebra: true`, and
|
|
936
|
+
`hierarchy: false|{parentId, column?, expanded?}`. Locale, currency, unit, and decimals may be
|
|
937
|
+
row callbacks; values remain numbers in row data while display formatting is locale-aware.
|
|
765
938
|
- **Methods** — `setData()`, `addData()`, `updateRow(id,row)`, `removeRow(id)`, `getRow(id)`,
|
|
766
939
|
`getData()`, `empty()`, `setSort(id,dir)`, `getSelection()`, `setSelection(ids)`,
|
|
767
940
|
`clearSelection()`, `setLoading(bool)` (busy/skeleton state — dims rows, shows an indeterminate
|
|
768
941
|
top bar, sets `aria-busy`, and is cleared by the next `setData`).
|
|
769
942
|
- **Events** — `rowclick {row, id, index, event}`, `rowdblclick`, `sort {id, dir}`,
|
|
770
|
-
`selectionchange {rows, ids}`, `datachange {rows}`.
|
|
943
|
+
`selectionchange {rows, ids}`, `datachange {rows}`, and `rowtoggle {row, id, expanded}`.
|
|
944
|
+
- **Hierarchy** — flat parent references are projected as an ARIA `treegrid`; `getData()` and all
|
|
945
|
+
editing/mutation APIs stay flat and ID-based. Orphans become roots, cycles render once, local
|
|
946
|
+
sort reorders siblings without mixing levels, and growing counts visible rows. Use
|
|
947
|
+
`toggleRow()`, `expandRow()`, `collapseRow()`, `expandAll()`, `collapseAll()`, and
|
|
948
|
+
`getExpanded()`. The native disclosure button works by pointer and keyboard without selecting
|
|
949
|
+
or clicking the row.
|
|
771
950
|
- **Editing** — `editMode: false|'cell'|'row'` (default `false`, and completely inert until set).
|
|
772
951
|
`'cell'` edits one cell, `'row'` opens every editable cell of the row and commits them as a unit.
|
|
773
952
|
Editors are sized into the cell without changing row height, and an editing cell carries
|
|
774
953
|
`data-editing="true"` (`data-invalid="true"` plus an `aria-live` message when a validator rejects).
|
|
775
954
|
- **Editable columns** — extra column keys: `editable: false|true|'text'|'number'|'select'|'date'|
|
|
776
|
-
'checkbox'|'textarea'|((row)=>boolean)` (`true`
|
|
777
|
-
|
|
955
|
+
'checkbox'|'textarea'|((row)=>boolean)` (`true` infers `'number'` for number/currency/percent/unit
|
|
956
|
+
columns and `'text'` otherwise; a function is evaluated per row, so individual rows stay
|
|
957
|
+
read-only), `options` for `'select'` (`[{value,label}]`, a `{value: label}` map
|
|
778
958
|
whose keys are always strings, or `(row)=>items`), `editorProps` (forwarded to the underlying
|
|
779
959
|
NumberField/Select/Datebox/Toggle or to the generated `<input>`/`<textarea>`),
|
|
780
960
|
`editor: (row, api)=>Node` for a fully custom editor (`api` is `{value, commit(value), cancel(),
|
|
@@ -783,6 +963,10 @@ horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
|
|
|
783
963
|
seeds the text of a `'text'`/`'textarea'` editor, `parse` converts every editor's raw output back),
|
|
784
964
|
and `validate: (value,row)=>true|string` (a returned string marks the cell invalid, shows the
|
|
785
965
|
message, and refuses the commit).
|
|
966
|
+
- **Transaction editors** — currency and unit columns reuse `NumberField` and show the resolved
|
|
967
|
+
currency/unit as its suffix unless `editorProps.unit` overrides it. This is a generic typed-grid
|
|
968
|
+
contract: application code remains responsible for tax, discount, subtotal, and accounting
|
|
969
|
+
formula rules.
|
|
786
970
|
- **Editing methods** — `startEdit(rowId, columnId)`, `commitEdit()`, `cancelEdit()`, `isEditing()`,
|
|
787
971
|
`getEditing()` → `{id, columnId}|null`.
|
|
788
972
|
- **Editing events** — `editstart {row, id, column, columnId, value}`;
|
|
@@ -824,6 +1008,53 @@ horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
|
|
|
824
1008
|
A function is re-called on every render, which is what to use when the placeholder holds controls.
|
|
825
1009
|
<!-- /doc -->
|
|
826
1010
|
|
|
1011
|
+
<!-- doc:grid -->
|
|
1012
|
+
### Grid and `Grid.BillingItems()`
|
|
1013
|
+
|
|
1014
|
+
`Grid` is the public extension point for repeatable data-table presets. It subclasses `Table`
|
|
1015
|
+
without forking its implementation, so sorting, selection, hierarchy, responsive stacking,
|
|
1016
|
+
editable cells/rows, loading, events, and teardown keep the Table contract.
|
|
1017
|
+
|
|
1018
|
+
- **Constructor** — `new Grid(target, tableOptions)` accepts the complete `Table` API.
|
|
1019
|
+
- **Preset** — `Grid.BillingItems(target, options)` supplies an editable hierarchical billing
|
|
1020
|
+
schema for item, quantity, unit, unit price, currency, and line total. It returns a `Grid`.
|
|
1021
|
+
- **Billing options** — `data`, `fields` key overrides, `units`, `currencies`, fallback `currency`,
|
|
1022
|
+
`locale`, `decimals`, `columnOverrides`, complete `columns` replacement, `lineTotal(row, changes)`,
|
|
1023
|
+
and `oneditcommit` in addition to ordinary Table options.
|
|
1024
|
+
- **Rows** — default field names are `id`, `parent`, `kind`, `item`, `quantity`, `unit`,
|
|
1025
|
+
`unitPrice`, `currency`, and `total`. `kind: 'group'|'subtotal'|'header'|'section'` is read-only;
|
|
1026
|
+
other rows are editable. Parent references use Table's flat-data treegrid projection.
|
|
1027
|
+
- **Calculation boundary** — the default line total is quantity × unit price. Applications own
|
|
1028
|
+
taxes, discounts, rounding, subtotal/group recalculation, optimistic persistence, and server
|
|
1029
|
+
validation; provide `lineTotal` or cancel `editcommit` when product policy differs.
|
|
1030
|
+
<!-- /doc -->
|
|
1031
|
+
|
|
1032
|
+
<!-- doc:chart -->
|
|
1033
|
+
### Chart and `ChartJsAdapter`
|
|
1034
|
+
|
|
1035
|
+
An accessible, engine-neutral chart host. Zx renders state, canvas, semantic data summary, tokens,
|
|
1036
|
+
and lifecycle; an injected adapter owns the drawing engine. The Zx runtime imports no Chart.js
|
|
1037
|
+
code, so future adapters do not change the public `Chart` API.
|
|
1038
|
+
|
|
1039
|
+
- **Options** — `adapter`, `type: 'bar'`, `data`, engine-specific `chartOptions`, `label`,
|
|
1040
|
+
`description`, `summary: 'hidden'|'visible'`, `loading`, loading/empty/error text, and
|
|
1041
|
+
`aspectRatio: '16 / 9'`.
|
|
1042
|
+
- **Methods** — `setData()`, `setType()`, `update(chartOptions)`, `setAdapter()`, `setLoading()`,
|
|
1043
|
+
`setError()`, `clearError()`, `resize()`, `refreshTheme()`, `getInstance()`, `destroy()`.
|
|
1044
|
+
- **Events** — `ready {instance}`, `update {data, type}`, `select {datasetIndex, index, dataset,
|
|
1045
|
+
label, value, nativeEvent}`, and `error {error}`.
|
|
1046
|
+
- **Adapter contract** — `adapter.create(canvas, {type, data, options, onSelect})` returns
|
|
1047
|
+
`{update(spec), resize(), destroy(), instance?}`. Implementations must destroy engine resources
|
|
1048
|
+
and must not retain the component after teardown.
|
|
1049
|
+
- **`ChartJsAdapter`** — construct it with a Chart.js constructor or namespace:
|
|
1050
|
+
`new ChartJsAdapter(window.Chart)`. The documentation pins Chart.js 4.5.1 as a development-only
|
|
1051
|
+
asset; `package.json` has no runtime dependencies and application builds explicitly choose how
|
|
1052
|
+
the engine is loaded.
|
|
1053
|
+
- **Accessibility** — the canvas always has a name and optional description, while synchronized
|
|
1054
|
+
labels and dataset values live in a semantic table. `summary: 'hidden'` keeps it visually hidden
|
|
1055
|
+
for assistive technology; `'visible'` makes exact values part of the interface.
|
|
1056
|
+
<!-- /doc -->
|
|
1057
|
+
|
|
827
1058
|
<!-- doc:data-filter -->
|
|
828
1059
|
### DataFilter
|
|
829
1060
|
|
|
@@ -927,6 +1158,76 @@ Beyond the built-in field types, these widget types wrap whole components, used
|
|
|
927
1158
|
`toggle` (Toggle).
|
|
928
1159
|
<!-- /doc -->
|
|
929
1160
|
|
|
1161
|
+
<!-- doc:questionnaire -->
|
|
1162
|
+
### Questionnaire
|
|
1163
|
+
|
|
1164
|
+
A guided, one-question-at-a-time flow: onboarding intake, a service-call checklist, an audit form,
|
|
1165
|
+
a feedback survey. The questionnaire owns the ordered items, the active one, the answers,
|
|
1166
|
+
validation, progress and navigation; the page, card, dialog or drawer around it owns closing,
|
|
1167
|
+
persistence and transport.
|
|
1168
|
+
|
|
1169
|
+
The root is a real `<form>` and the choices are native radios and checkboxes carrying the item
|
|
1170
|
+
name, so `new FormData(questionnaire.toElement())` reads the answers, arrow keys inside a choice
|
|
1171
|
+
group are the browser's rather than ours, and the semantics do not depend on JavaScript. Three
|
|
1172
|
+
things separate it from a `Form` with one `Fieldset` per question: it branches, its answer control
|
|
1173
|
+
can be any registered `Field` type, and its validation may be asynchronous.
|
|
1174
|
+
|
|
1175
|
+
- **Options** — `items: [{name, prompt, description?, section?, required?, multiple?, skippable?,
|
|
1176
|
+
choices?, input?, field?, when?, next?, validate?}]`, `answers: {}` and `active: null` (the
|
|
1177
|
+
resume pair), `progress: true`, `review: false`, `advance: 'manual'|'auto'`, `shortcuts: true`,
|
|
1178
|
+
`allowBack: true`.
|
|
1179
|
+
- **Choices** — `[{value, label, description?, icon?, key?, disabled?, exclusive?}]`. `exclusive`
|
|
1180
|
+
is the "None of the above" behaviour: picking it clears the rest of a `multiple` item, and
|
|
1181
|
+
picking anything else clears it.
|
|
1182
|
+
- **Methods** — `setItems()`, `getItems()`, `goTo(name)`, `next()`, `previous()`, `skip()`,
|
|
1183
|
+
`submit()`, `getAnswers()`, `getAnswer(name)`, `setAnswers(values, {silent})`,
|
|
1184
|
+
`setAnswer(name, value, {silent})`, `getActive()`, `getPath()`, `getProgress()`, `getState()`,
|
|
1185
|
+
`toFormData()`, `reset()`, `focus()`, `destroy()`. `next()`, `skip()` and `submit()` return
|
|
1186
|
+
**promises** — `next()` because an item's `validate` may be asynchronous, and `skip()` because
|
|
1187
|
+
skipping the last question submits. Everything else is synchronous.
|
|
1188
|
+
- **Events** — `change {name, value, answers}`, `navigate {from, to, reason}` **preventable**,
|
|
1189
|
+
`skip {name}`, `invalid {name, message}`, `submit {answers, path}` **preventable**,
|
|
1190
|
+
`complete {answers, path}`.
|
|
1191
|
+
- **Branching** — `when(answers)` decides whether an item is asked at all, and `next` (a name, or
|
|
1192
|
+
`(answer, answers) => name`) decides what follows. Conditions **cascade**: each predicate sees
|
|
1193
|
+
only the answers of visible items declared before it, so hiding the VAT question also hides
|
|
1194
|
+
whatever depended on the VAT id. An answer to a conditioned-out question is kept internally —
|
|
1195
|
+
walk back into the branch and it is still there — but is left out of `getAnswers()` and
|
|
1196
|
+
`toFormData()`, so an abandoned branch never submits stale data. A `next` naming a hidden item
|
|
1197
|
+
walks forward from it rather than stranding the reader; naming an item that does not exist
|
|
1198
|
+
throws `RangeError`.
|
|
1199
|
+
- **Path and progress** — `getPath()` is the questionnaire's memory of the route walked, and
|
|
1200
|
+
`previous()` pops it: once a branch has been taken, "previous" is not `index - 1`. `getProgress()`
|
|
1201
|
+
returns `{index, answered, total, percent, section}` where `total` is the path plus the items
|
|
1202
|
+
still reachable — exact for a static flow, an estimate once a function `next` can jump somewhere
|
|
1203
|
+
the forward walk cannot predict.
|
|
1204
|
+
- **Field answers** — `field: {type: 'date'|'number'|'zxselect'|'rating'|'upload'|…}` hands the
|
|
1205
|
+
answer to a `Field`, so any registered field type works, including ones an application registered
|
|
1206
|
+
itself. The `<legend>` already asks the question, so the Field's own label is hidden from sight
|
|
1207
|
+
but kept as the control's accessible name unless the item gives `field.label` explicitly; the
|
|
1208
|
+
Field draws its own highlight, so a failing answer shows one message, not two.
|
|
1209
|
+
- **Validation** — `required` is checked synchronously; an item's `validate(answer, answers)` may
|
|
1210
|
+
return a message, `null`, or a **promise** of either, and a rejection is reported as its message.
|
|
1211
|
+
While the check is pending the root carries `data-state="checking"` and `aria-busy="true"` and
|
|
1212
|
+
the actions are disabled.
|
|
1213
|
+
- **Review** — `review: true` shows a summary of every answer on the path before submitting, each
|
|
1214
|
+
with an Edit that reopens that question; Continue from an edited question comes straight back to
|
|
1215
|
+
the review rather than replaying the tail.
|
|
1216
|
+
- **Semantics** — the item is a `<fieldset>` and the prompt its `<legend>`; the description and the
|
|
1217
|
+
error are associated through `aria-describedby`, the error is a `role="alert"`, and a failing
|
|
1218
|
+
item carries `aria-invalid="true"`. `data-state` on the root is
|
|
1219
|
+
`asking`, `checking`, `review`, or `complete`. Submitting does not replace the content: it sets
|
|
1220
|
+
`data-state="complete"`, hides the actions, and emits `complete`, leaving the thank-you screen to
|
|
1221
|
+
the application.
|
|
1222
|
+
- **Keyboard** — `1`–`9` then `a`–`z` pick the matching answer, assigned in choice order (an
|
|
1223
|
+
explicit `key` is reserved first, so adding one never renumbers the others) and shown as a key
|
|
1224
|
+
cap on each choice; the caps are `aria-hidden`, since a screen-reader user moves through the
|
|
1225
|
+
group with the arrow keys the radios already provide. `Enter` continues, except in a `multiline`
|
|
1226
|
+
input. Shortcuts are suppressed while focus is in a text control. Navigating moves focus to the
|
|
1227
|
+
new question's fieldset, which is what gets the prompt announced; failing validation moves it to
|
|
1228
|
+
the first answer control instead.
|
|
1229
|
+
<!-- /doc -->
|
|
1230
|
+
|
|
930
1231
|
<!-- doc:value-list -->
|
|
931
1232
|
### ValueList
|
|
932
1233
|
|
|
@@ -991,19 +1292,6 @@ yet. Field type: `tagpicker`.
|
|
|
991
1292
|
within the list.
|
|
992
1293
|
<!-- /doc -->
|
|
993
1294
|
|
|
994
|
-
<!-- doc:permission -->
|
|
995
|
-
### Permission
|
|
996
|
-
|
|
997
|
-
Private / public / group record-permission selector. **Deprecated** — use
|
|
998
|
-
`Select.permission(target, {groups})`, which carries the same tri-state value in one control and
|
|
999
|
-
can query the groups remotely. This class stays for `gx.zeyos.Permission` and is removed in 3.0.
|
|
1000
|
-
|
|
1001
|
-
- **Options** — `value: true|false|groupId`, `groups: []`, `groupsValueKey: 'ID'`,
|
|
1002
|
-
`groupsLabelKey: 'name'`.
|
|
1003
|
-
- **Methods** — `get()` → `'private'|'public'|groupId`, `set(value)`.
|
|
1004
|
-
- **Events** — `change {value}`.
|
|
1005
|
-
<!-- /doc -->
|
|
1006
|
-
|
|
1007
1295
|
<!-- doc:groupbox -->
|
|
1008
1296
|
### Groupbox
|
|
1009
1297
|
|
|
@@ -1014,6 +1302,30 @@ Collapsible titled section built on the native `<details>` element.
|
|
|
1014
1302
|
- **Events** — `open`, `close`.
|
|
1015
1303
|
<!-- /doc -->
|
|
1016
1304
|
|
|
1305
|
+
<!-- doc:card -->
|
|
1306
|
+
### Card
|
|
1307
|
+
|
|
1308
|
+
A semantic content or record surface. Card is intentionally not a Panel preset: it has no
|
|
1309
|
+
disclosure state or application chrome, and composes as one repeated item in a grid or list. A
|
|
1310
|
+
linked Card keeps the root non-interactive and renders a real title anchor as its primary action,
|
|
1311
|
+
so buttons and links in its action, content, and footer regions remain valid sibling controls.
|
|
1312
|
+
|
|
1313
|
+
- **Options** — `title: ''`, `media: null`, `content: null`, `actions: []`, `footer: null`,
|
|
1314
|
+
`link: null|string|{href, target?, rel?, onclick?}`, `variant: 'outlined'|'raised'|'filled'`,
|
|
1315
|
+
`orientation: 'vertical'|'horizontal'`, `headingLevel: 3`.
|
|
1316
|
+
- **Methods** — `setTitle()`, `setMedia()`, `setContent()`, `setActions()`, `setFooter()`,
|
|
1317
|
+
`setLink()`.
|
|
1318
|
+
- **Content** — media, body, and footer accept text, a Node, a Component, or null. Enhanced target
|
|
1319
|
+
children become body content when no explicit content is supplied, and `destroy()` restores the
|
|
1320
|
+
target exactly.
|
|
1321
|
+
- **Interaction** — `link` stretches the native title anchor across the visual surface; secondary
|
|
1322
|
+
controls stay above it and are never nested inside it. A linked card requires a non-empty title.
|
|
1323
|
+
Executable/data URL schemes are rejected. Commands belong in `actions`, and selectable cards
|
|
1324
|
+
should compose a native checkbox or radio.
|
|
1325
|
+
- **Layout** — horizontal media uses the public `--zx-card-media-size` hook and stacks through a
|
|
1326
|
+
container query when the card itself becomes narrow.
|
|
1327
|
+
<!-- /doc -->
|
|
1328
|
+
|
|
1017
1329
|
<!-- doc:panel -->
|
|
1018
1330
|
### Panel / MasterPanel
|
|
1019
1331
|
|
|
@@ -1073,6 +1385,62 @@ markup with no JavaScript.
|
|
|
1073
1385
|
because a CSS custom property cannot be used inside a media query.
|
|
1074
1386
|
<!-- /doc -->
|
|
1075
1387
|
|
|
1388
|
+
<!-- doc:dock -->
|
|
1389
|
+
### Dock
|
|
1390
|
+
|
|
1391
|
+
A stack of collapsible, resizable panes: the docked inspector column of a design tool, and the
|
|
1392
|
+
detail side of a master–detail screen. Give the root a size of its own (a grid area, `block-size:
|
|
1393
|
+
100%`, a flex child) when the panes should fill a shell rather than grow with their content.
|
|
1394
|
+
|
|
1395
|
+
- **Options** — `orientation: 'vertical'`, `content: null`, `panes: []`, `resizable: true`,
|
|
1396
|
+
`collapsible: true`, `lazy: true`, `storageKey: null`.
|
|
1397
|
+
- **Pane** — `{name, title?, content?, tabs?, active?, size?, min?, grow?, collapsed?,
|
|
1398
|
+
collapsible?, side?}`. `content` takes a string, Node, Component, or a factory called on first
|
|
1399
|
+
reveal. A pane with `tabs` renders its strip in place of the title; `content` is then ignored.
|
|
1400
|
+
`side` (`'start' | 'end'`) only applies when the dock has a `content`.
|
|
1401
|
+
- **Tab** — `{name, title, content?}`, same content shapes.
|
|
1402
|
+
- **Methods** — `pane(name)`, `names()`, `add(pane, {index})`, `remove(name)`,
|
|
1403
|
+
`collapse(name)`, `expand(name)`, `toggle(name)`, `isCollapsed(name)`, `reveal(name)`,
|
|
1404
|
+
`setSize(name, size)`, `getSize(name)`, `activate(pane, tab)`, `getActive(pane)`,
|
|
1405
|
+
`state()`, `setState(state)`, `adopt(sheet, options)`, `release(sheet)`.
|
|
1406
|
+
- **Adopting a Sheet** — `adopt(sheet, {name?, side?, index?, size?, min?, dockAt?})` takes over a
|
|
1407
|
+
`Sheet`'s positioning: it becomes a track in the dock rather than an overlay. The dock owns
|
|
1408
|
+
where it sits, its size, and its resizing; the sheet keeps its content, header, footer, events,
|
|
1409
|
+
and its own `open()`/`close()`. `dockAt` names a breakpoint below which the dock hands the sheet
|
|
1410
|
+
back to a free overlay and reclaims the track, re-adopting it above — measured on the **dock's
|
|
1411
|
+
own width**, so a dock inside a split pane behaves correctly where a viewport media query would
|
|
1412
|
+
not. Because a dock is a flex container by construction it is always a valid host, which is why
|
|
1413
|
+
docking needs no arrangement from the application.
|
|
1414
|
+
- **Ownership** — the dock never owns an adopted sheet: `destroy()` releases them rather than
|
|
1415
|
+
destroying them, `remove(name)` on a sheet releases it, and a sheet that destroys itself while
|
|
1416
|
+
adopted drops out of the dock cleanly.
|
|
1417
|
+
- **Events** — `collapse {name}`, `expand {name}`, `resize {name, size}`,
|
|
1418
|
+
`tabchange {pane, tab, previous}`, `reveal {name}`.
|
|
1419
|
+
- **Sizing** — one custom property per pane and one flex rule: a sized pane is
|
|
1420
|
+
`flex: 0 0 var(--zx-pane-size)`, a collapsed one falls to `flex: 0 0 auto` with its body hidden,
|
|
1421
|
+
and exactly one element grows. With a `content` that is always the content; without one it is the
|
|
1422
|
+
pane declaring `grow`, or the last expanded pane. A drag therefore rewrites at most two
|
|
1423
|
+
properties, and collapsing a pane feeds the grower rather than redistributing across the stack.
|
|
1424
|
+
- **Regions** — with `content` the dock is a region rather than a plain stack: panes sit on either
|
|
1425
|
+
`side` of the flexible middle. Nesting one dock inside another dock's pane gives a workbench —
|
|
1426
|
+
a canvas with an inspector column beside it.
|
|
1427
|
+
- **`reveal(name)`** — accepts a pane name or a tab name. Expands whichever pane holds it,
|
|
1428
|
+
activates the tab when the name is a tab's, and scrolls it into view.
|
|
1429
|
+
- **Persistence** — `storageKey` remembers sizes, collapsed panes, and active tabs through
|
|
1430
|
+
`storage()`, which degrades to memory rather than throwing. `state()`/`setState()` expose the
|
|
1431
|
+
same shape for storing it elsewhere; unknown pane names are ignored, so a stored layout survives
|
|
1432
|
+
a release that added or removed panes.
|
|
1433
|
+
- **Keyboard and screen readers** — each pane header is a row, not one big button, so the collapse
|
|
1434
|
+
toggle and the tab strip can coexist; the toggle carries `aria-expanded` and `aria-controls`.
|
|
1435
|
+
Tabs follow the APG tab pattern with one roving tab stop, Left/Right moving between them.
|
|
1436
|
+
Dividers are focusable `separator`s carrying live `aria-valuenow`/`aria-valuemin`/`aria-valuemax`
|
|
1437
|
+
in pixels: Up/Down (or Left/Right when horizontal) resize by 16px, Shift by 64px, and Enter or
|
|
1438
|
+
Space collapses the pane before the divider. A divider with nothing to resize is taken out of the
|
|
1439
|
+
tab order.
|
|
1440
|
+
- **Out of scope** — drag-to-rearrange, tear-off panels, and multi-column docks. All three are
|
|
1441
|
+
additive without changing the API above.
|
|
1442
|
+
<!-- /doc -->
|
|
1443
|
+
|
|
1076
1444
|
<!-- doc:tabbox -->
|
|
1077
1445
|
### Tabbox — APG tabs
|
|
1078
1446
|
|
|
@@ -1178,12 +1546,54 @@ menu on narrow widths.
|
|
|
1178
1546
|
- **Events** — `change {name}`.
|
|
1179
1547
|
<!-- /doc -->
|
|
1180
1548
|
|
|
1549
|
+
<!-- doc:app-sidebar -->
|
|
1550
|
+
### AppSidebar — application navigation in every presentation
|
|
1551
|
+
|
|
1552
|
+
One route-agnostic application-navigation owner with an expanded vertical tree, a minimized
|
|
1553
|
+
vertical rail, and horizontal rail layouts. It mounts exactly one presentation at a time while
|
|
1554
|
+
preserving active and expanded branch state. Only the expanded vertical state reveals descendants
|
|
1555
|
+
inline; every rail state opens descendants toward the workspace in anchored flyouts.
|
|
1556
|
+
|
|
1557
|
+
- **Options** — `items`, `active`, `expanded`, `collapsed`, `collapsible`,
|
|
1558
|
+
`orientation: 'vertical'|'horizontal'`, `side: 'left'|'right'|'top'|'bottom'`, `label`,
|
|
1559
|
+
`header`, `footer`, `railHeader`, `railFooter`, `openDelay: 80`, `closeDelay: 160`, and
|
|
1560
|
+
`renderIcon(item, context)`. Icon values may also be names, nodes, components, or factories.
|
|
1561
|
+
- **Methods** — `setItems()`, `getItems()`, `setActive()`, `setExpanded()`, `getExpanded()`,
|
|
1562
|
+
`toggleBranch()`, `expand()`, `collapse()`, `setCollapsed()`, `isCollapsed()`,
|
|
1563
|
+
`setLayout({orientation, side})`, `openFlyout(id, {focus})`, `closeFlyout()`,
|
|
1564
|
+
`closeAllFlyouts()`, `isFlyoutOpen()`, `focus()`, `destroy()`.
|
|
1565
|
+
- **Events** — cancelable `select {item, id, value, href, event}`,
|
|
1566
|
+
`branchchange {item, id, expanded, ids}`, `collapsechange {collapsed}`, and
|
|
1567
|
+
`flyoutchange {item, id, open}`.
|
|
1568
|
+
- **Presentation state** — horizontal navigation is always effectively minimized and never exposes
|
|
1569
|
+
an expand control. Switching layouts does not erase the saved vertical collapsed preference or
|
|
1570
|
+
expanded branch IDs. `AppSidebar` is the single public application-navigation component; use
|
|
1571
|
+
`collapsed: true` or `orientation: 'horizontal'` for its rail presentations.
|
|
1572
|
+
- **Pointer and focus** — hover or focus reveals rail descendants without stealing focus. Click,
|
|
1573
|
+
Enter, Space, and the arrow toward the workspace also open a flyout; Escape, outside activation,
|
|
1574
|
+
or selection closes it. Expanded navigation supports arrows plus Home/End across visible rows.
|
|
1575
|
+
- **Semantics** — persistent navigation uses `<nav>` and nested lists with native links and
|
|
1576
|
+
disclosure buttons, not menu or menubar roles. Icon-only destinations retain an accessible name
|
|
1577
|
+
and Tooltip. A parent with children is disclosure-only; add an Overview child when it also needs
|
|
1578
|
+
a destination. Malformed and executable URL schemes are stripped; an item with no remaining
|
|
1579
|
+
link or callback is disabled in every presentation.
|
|
1580
|
+
<!-- /doc -->
|
|
1581
|
+
|
|
1181
1582
|
<!-- doc:kernel -->
|
|
1182
1583
|
### Core helpers
|
|
1183
1584
|
|
|
1184
1585
|
- **Component** — the base class: `on`/`off`/`once`/`emit`, `listen`, `toElement`, `msg`,
|
|
1185
1586
|
`destroy`, and the static `Component.from(el)`.
|
|
1186
|
-
- **DOM** — `h(tag, props, ...children)`, `h.raw(html)`, `htmlEscape`, `resolveElement`.
|
|
1587
|
+
- **DOM** — `h(tag, props, ...children)`, `h.raw(html)`, `htmlEscape`, `resolveElement`. The current
|
|
1588
|
+
ZeyOS builder is also first-class: `__(tag#id.class, properties, content)` is the migration alias
|
|
1589
|
+
for `compactElement()`. It preserves `D*` data, `S*` style, boolean/built-in property, attribute,
|
|
1590
|
+
and legacy `on*` callback rules while keeping content text-safe. `applyCompactProperties`,
|
|
1591
|
+
`appendContent`, `appendCompact` (parent return), `appendCompactChild` (child return), and
|
|
1592
|
+
`fragment(...children)` are the pure forms.
|
|
1593
|
+
- **Compact events** — `onCompactEvent`, `offCompactEvent`, and `fireCompactEvent` share one
|
|
1594
|
+
newest-first handler registry. Existing `DOM.on/remEvt/fireEvt` methods can delegate to this
|
|
1595
|
+
triad. Zx never installs globals or alters DOM prototypes; the current application owns those
|
|
1596
|
+
temporary seams while `UI.new*` implementations are replaced without rewriting `PG` routing.
|
|
1187
1597
|
- **Icons** — `icon(name, {size, label})` and `icons`; see the Icons section — bundled inline SVG
|
|
1188
1598
|
by default, Font Awesome after an opt-in.
|
|
1189
1599
|
- **Positioning** — `position(anchor, floating, {placement, offset, flip, matchWidth})` →
|
|
@@ -1319,39 +1729,6 @@ bug wearing a layout costume, while a tooltip that is always there is noise.
|
|
|
1319
1729
|
`data-lines` plus `--zx-truncate-lines` select the multi-line form.
|
|
1320
1730
|
<!-- /doc -->
|
|
1321
1731
|
|
|
1322
|
-
<!-- doc:gx-compat -->
|
|
1323
|
-
### gx compatibility layer
|
|
1324
|
-
|
|
1325
|
-
Opt-in re-implementation of the legacy MooTools-era `gx` API on top of Zx, so existing ZeyOS
|
|
1326
|
-
screens keep running while their code is modernised file by file. It lives in its own bundle, is
|
|
1327
|
-
never imported by `src/index.js`, and adds nothing to an application that does not load it.
|
|
1328
|
-
|
|
1329
|
-
- **Loading** — classic: `<script src="/assets/zx-compat.global.js">` → `window.gx`; module:
|
|
1330
|
-
`import { gx } from '/assets/zx-compat.esm.js'` (or `src/compat/index.js` in-repo).
|
|
1331
|
-
`gx.compat.installGlobals()` additionally installs the legacy free functions `__()`, `_()`,
|
|
1332
|
-
`String.htmlSpecialChars`, and the element `store`/`retrieve` shim. `gx.install(host)` assigns
|
|
1333
|
-
the namespace without the optional globals.
|
|
1334
|
-
- **`gx.zeyos`** — Select/SelectFilter/SelectDyn/SelectPrio, Table, Tabbox, Panel, MasterPanel,
|
|
1335
|
-
Groupbox, Search, Datebox, DatePicker, MonthPicker, TimePicker, Timebox, Toggle, Msgbox, Popup,
|
|
1336
|
-
Dialog, Dropdown, Checklist, Permission, Client, Request, Factory.
|
|
1337
|
-
- **`gx.bootstrap`** — Form, Fieldset, Field, the Select variants, Checklist, Table, Tabbox,
|
|
1338
|
-
NavigationBar, MenuButton, Message, Popup/PopupAlert/PopupConfirm, CheckButton, DataFilter,
|
|
1339
|
-
ValueList, MultiValueEditor, FieldUpload, Timebox.
|
|
1340
|
-
- **`gx.util`** — `formatNum`, `formatTime`, `getMinutes`, `getNumber`, `printf`, `parseResult`,
|
|
1341
|
-
`Parse`, `isArray`/`isObject`/`isFunction`/`isString`/`isNumber`/`isElement`/`isNode`,
|
|
1342
|
-
`Console`.
|
|
1343
|
-
- **`gx.ui`** — Container, SimpleTable, Timebox, and the inert visual-effect stubs
|
|
1344
|
-
Blend/Collapse/Hud/Toggling/HGroup/Templates. **`gx.core`** — Settings. **`gx.compat`** —
|
|
1345
|
-
installGlobals, installElementStorage, parse, GxWrapper.
|
|
1346
|
-
- **Migrating off it** — legacy classes collapse onto fewer Zx components: all four Select
|
|
1347
|
-
variants → one `Select` with a `filter` option; `gx.ui.Table` + `SimpleTable` → one `Table`;
|
|
1348
|
-
`Msgbox`/`bootstrap.Message` → `Message`; `Popup`/`PopupAlert`/`PopupConfirm` → `Modal`/`Dialog`
|
|
1349
|
-
with Promise-returning statics; `gx.zeyos.Client`/`Request` → `@zeyos/client`. Anything that
|
|
1350
|
-
depended on MooTools prototype extensions is gone. `MIGRATION.md` has the full map and the
|
|
1351
|
-
deliberate behaviour changes; `website/compat.html` runs legacy snippets against Zx as a smoke
|
|
1352
|
-
test.
|
|
1353
|
-
<!-- /doc -->
|
|
1354
|
-
|
|
1355
1732
|
<!-- doc:elements -->
|
|
1356
1733
|
### Custom elements — `defineElements()`
|
|
1357
1734
|
|