@zeyos/zx 2.3.0 → 3.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 +87 -0
- package/DESIGN-SYSTEM.md +136 -0
- package/MIGRATION.md +155 -4
- package/README.md +24 -13
- package/dist/types/compat/map/data.d.ts +3 -2
- package/dist/types/components/account-menu/account-menu.d.ts +144 -0
- package/dist/types/components/app-rail/app-rail.d.ts +250 -0
- package/dist/types/components/app-sidebar/app-sidebar.d.ts +169 -0
- package/dist/types/components/avatar/avatar.d.ts +100 -0
- package/dist/types/components/chart/chart.d.ts +321 -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 +300 -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/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 +219 -12
- 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 +114 -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 +12 -2
- package/dist/zx-compat.esm.js +641 -277
- package/dist/zx-compat.esm.min.js +1 -1
- package/dist/zx-compat.global.js +7609 -2236
- package/dist/zx-compat.global.min.js +3 -3
- package/dist/zx-zeyos.esm.js +546 -87
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +1452 -101
- package/dist/zx.esm.js +7952 -2592
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +7952 -2592
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +2276 -337
- package/docs/llms.md +426 -30
- package/docs/llms.txt +21 -9
- package/package.json +4 -2
- package/src/compat/globals.js +3 -1
- package/src/compat/map/data.js +31 -9
- 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-rail/app-rail.js +668 -0
- package/src/components/app-sidebar/app-sidebar.css +68 -0
- package/src/components/app-sidebar/app-sidebar.js +388 -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/chart/chart.css +61 -0
- package/src/components/chart/chart.js +518 -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 +213 -0
- package/src/components/launcher/launcher.css +100 -0
- package/src/components/launcher/launcher.js +557 -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/select.css +0 -1
- 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 +523 -45
- package/src/components/tooltip/tooltip.js +5 -2
- package/src/components/value-list/value-list.js +6 -3
- package/src/core/dom.js +302 -0
- package/src/core/drag-axis.js +203 -0
- package/src/core/position.js +68 -22
- package/src/index.js +19 -2
- package/styles/tokens/dark.css +2 -3
- package/styles/tokens/global.css +5 -5
- package/styles/tokens/semantic.css +5 -3
- package/styles/tokens/themes.css +1 -1
- package/styles/zx.css +10 -1
- package/dist/types/components/permission/permission.d.ts +0 -96
- 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 the dependency-free design system for ZeyOS business applications; Zx is its
|
|
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 {
|
|
@@ -211,8 +211,9 @@ reflection and ElementInternals form association: `<zx-toggle>`, `<zx-check-butt
|
|
|
211
211
|
|
|
212
212
|
Load `zx-compat.global.js` (or import `zx-compat.esm.js`) →
|
|
213
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
|
|
214
|
+
translation, MooTools-style `addEvent`). `gx.compat.installGlobals()` (opt-in) installs its gx
|
|
215
|
+
`__()` parser only when that name is free, plus `_()`, `String.htmlSpecialChars`, and the element
|
|
216
|
+
`store/retrieve` shim. Full namespace listing in
|
|
216
217
|
the "gx compatibility layer" component section below; class map and unsupported legacy APIs in
|
|
217
218
|
`MIGRATION.md`.
|
|
218
219
|
|
|
@@ -418,6 +419,67 @@ Search input with embedded search and clear buttons (`role="search"`).
|
|
|
418
419
|
- **Events** — `input {value}` (debounced), `submit {value}` (Enter or the button), `clear`.
|
|
419
420
|
<!-- /doc -->
|
|
420
421
|
|
|
422
|
+
<!-- doc:launcher -->
|
|
423
|
+
### Launcher — application and record search
|
|
424
|
+
|
|
425
|
+
A native-dialog launcher for applications, recent records, commands, and grouped remote results.
|
|
426
|
+
Zx owns ranking, focus, request cancellation, and presentation; ZeyOS owns the catalogue,
|
|
427
|
+
permissions, recent-history/cache policy, and the route or command ultimately invoked.
|
|
428
|
+
|
|
429
|
+
- **Constructor** — `new Launcher(null, options)` owns a body-level dialog;
|
|
430
|
+
`new Launcher(existingDialog, options)` enhances and later restores an existing `<dialog>`.
|
|
431
|
+
- **Options** — `items`, abortable `sources: [{id, label?, minQuery?, load(query, {signal})}]`,
|
|
432
|
+
`query`, `debounce: 250`, `minQuery: 0`, `maxResults: 100`, `placeholder`, `label`, `emptyText`,
|
|
433
|
+
`loadingText`, and `shortcut: 'mod+k'|false`.
|
|
434
|
+
- **Items** — `{id, label, description?, keywords?, group?, icon?, badge?, value?, href?, target?,
|
|
435
|
+
invoke?, pinned?, disabled?}`. Links stay native so modified and middle clicks work; non-link
|
|
436
|
+
commands may provide an application-owned `invoke` callback.
|
|
437
|
+
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `focus()`, `setQuery()`, `getQuery()`,
|
|
438
|
+
`setItems()`, `setSources()`, `destroy()`.
|
|
439
|
+
- **Events** — cancelable `select {item, value, source, query}`, `query {query}`, `open`, `close`,
|
|
440
|
+
and `error {source, error}`. Preventing `select` suppresses the supplied link or callback.
|
|
441
|
+
- **Ranking** — local results are case/diacritic-insensitive and deterministic: exact label,
|
|
442
|
+
label prefix, word prefix, label substring, identifier substring, then acronym prefix. Pinned
|
|
443
|
+
items retain an explicit order ahead of otherwise equal results. A new async query aborts and
|
|
444
|
+
ignores stale source work.
|
|
445
|
+
- **Keyboard** — Cmd+K on macOS or Ctrl+K elsewhere opens by default; the shortcut is ignored in
|
|
446
|
+
editable controls, composition, and modal contexts. Arrow keys, Home/End, and Enter operate the
|
|
447
|
+
single listbox selection model; Escape closes and restores focus.
|
|
448
|
+
<!-- /doc -->
|
|
449
|
+
|
|
450
|
+
<!-- doc:avatar -->
|
|
451
|
+
### Avatar
|
|
452
|
+
|
|
453
|
+
A fixed-geometry user image with deterministic initials fallback. Image loading or failure never
|
|
454
|
+
changes layout, and the component is decorative by default so adjacent identity text is not
|
|
455
|
+
announced twice.
|
|
456
|
+
|
|
457
|
+
- **Options** — `src`, `name`, `initials`, `label`, `size: 'sm'|'md'|'lg'|<pixels>`,
|
|
458
|
+
`shape: 'circle'|'rounded'|'square'`, `status: 'online'|'away'|'busy'|'offline'|null`, and
|
|
459
|
+
`statusLabel`.
|
|
460
|
+
- **Methods** — `set(values)`, `setStatus(status, label?)`, `hasImage()`, `destroy()`.
|
|
461
|
+
- **Accessibility** — set `label` only when the avatar stands alone. Presence is supplementary
|
|
462
|
+
status, not the account's accessible name; supply `statusLabel` when it conveys information.
|
|
463
|
+
<!-- /doc -->
|
|
464
|
+
|
|
465
|
+
<!-- doc:account-menu -->
|
|
466
|
+
### AccountMenu
|
|
467
|
+
|
|
468
|
+
Composes `Avatar` and `MenuButton` into one account trigger and APG menu. The popup repeats the
|
|
469
|
+
identity before its actions; Zx never decides role visibility, changes preferences, signs a user
|
|
470
|
+
out, or mutates the session.
|
|
471
|
+
|
|
472
|
+
- **Options** — `account: {name, secondary, src?, initials?, status?, statusLabel?}`, `items`,
|
|
473
|
+
`compact: false`, `label`, and any top/bottom/left/right `placement`.
|
|
474
|
+
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `setAccount()`, `setItems()`, `focus()`,
|
|
475
|
+
`getPanel()`, `destroy()`.
|
|
476
|
+
- **Events** — cancelable `select {value, item}`, `open`, and `close`. A canceled selection does
|
|
477
|
+
not run the item's callback and leaves the menu open, so an application can reject or confirm an
|
|
478
|
+
action without rebuilding the account surface.
|
|
479
|
+
- **Accessibility** — compact mode is visually avatar-only but keeps the full account-menu name on
|
|
480
|
+
its single native trigger; MenuButton retains focus return, typeahead, and arrow-key behavior.
|
|
481
|
+
<!-- /doc -->
|
|
482
|
+
|
|
421
483
|
<!-- doc:select -->
|
|
422
484
|
### Select — APG editable combobox
|
|
423
485
|
|
|
@@ -442,7 +504,7 @@ Unifies single-select, local filtering, and async loading.
|
|
|
442
504
|
`Select.permission(target, {groups, value})`, the record-access picker with Private and Public
|
|
443
505
|
pinned above the groups. Its value is the tri-state ZeyOS stores (`false` private, `true` public,
|
|
444
506
|
or a group ID), `groups` takes an array or a loader `(query)=>items`, and the labels come from
|
|
445
|
-
`msg` (`permission.private`, `permission.public`).
|
|
507
|
+
`msg` (`permission.private`, `permission.public`).
|
|
446
508
|
- **Keyboard** (APG combobox) — ArrowDown/Alt+ArrowDown open; arrows navigate and wrap; Home/End;
|
|
447
509
|
Enter selects; Esc closes; Tab closes; printable characters filter (editable) or run a typeahead
|
|
448
510
|
(readonly). `aria-activedescendant` tracks the active option.
|
|
@@ -675,6 +737,102 @@ Structured modal: a header with title and close button, a body, and footer butto
|
|
|
675
737
|
`Dialog.prompt({ title, message, value })` → string|null.
|
|
676
738
|
<!-- /doc -->
|
|
677
739
|
|
|
740
|
+
<!-- doc:sheet -->
|
|
741
|
+
### Sheet
|
|
742
|
+
|
|
743
|
+
Edge-anchored surface — a `Dialog` attached to one side of the viewport instead of floating in the
|
|
744
|
+
middle. One primitive covers both side sheets and mobile drawers, which differ mainly in the edge they take, so
|
|
745
|
+
`side` replaces what would otherwise be two components. Inherits the whole Dialog anatomy: title,
|
|
746
|
+
footer buttons, switchable views, and focus restoration.
|
|
747
|
+
|
|
748
|
+
- **Options** — `side: 'end'` (`'start' | 'end' | 'top' | 'bottom'`, logical), `modal: true`
|
|
749
|
+
(`true | 'trap-focus' | false`), `backdrop: 'dim'` (`'dim' | 'blur' | 'none'`), `size: null`
|
|
750
|
+
(CSS length or px number, applied to whichever axis `side` implies), `closeButton: true`,
|
|
751
|
+
plus everything Dialog takes — `title`, `content`, `buttons`, `closable`, `lightDismiss`
|
|
752
|
+
(defaults to `true` here, unlike Modal), `destroyOnClose`.
|
|
753
|
+
- **Methods** — `open()`, `close(result?)`, `setSide(side)`, `getSide()`, `setSize(size)`,
|
|
754
|
+
`isModal()`, `isDocked()`, `isOpen()`, `getSize()`, `snapTo(target)`, plus Dialog's `setTitle()`, `setContent()`,
|
|
755
|
+
`setButtons()`, `addView()`, `showView()`.
|
|
756
|
+
- **Events** — `open`, `close {result}`, `cancel` (preventable with `event.preventDefault()`),
|
|
757
|
+
`resize {size, ratio}`, `dockchange {docked, dock}`.
|
|
758
|
+
- **Docked** — a sheet has two lives, and it does not choose between them: `Dock.adopt(sheet)`
|
|
759
|
+
makes it a track in that dock's flow instead of an overlay, and the dock then owns its side,
|
|
760
|
+
size, and resizing. A docked sheet is always non-modal, `close()` collapses its track to zero
|
|
761
|
+
rather than sliding away, and Escape and outside-click stop dismissing it — it is part of the
|
|
762
|
+
layout, not something covering it. `Dock.release(sheet)` hands it back. Nothing is rebuilt
|
|
763
|
+
across a handoff: the element moves and reopens in place, so DOM state and listeners survive,
|
|
764
|
+
and no `open`/`close` is emitted for what is only a change of address.
|
|
765
|
+
- **Modality** — `true` delegates focus containment, page inertness, Escape, and the backdrop to
|
|
766
|
+
the browser through `showModal()`. `'trap-focus'` and `false` open with `show()`, so the page
|
|
767
|
+
keeps scrolling and stays interactive; Escape and outside-click are re-implemented, and
|
|
768
|
+
`'trap-focus'` adds `focusTrap()` on top. Only a modal sheet renders a `::backdrop`, so
|
|
769
|
+
`backdrop` is meaningful only when `modal` is `true`.
|
|
770
|
+
- **Resizing and detents** — `resizable` makes the inner edge draggable between `min` and `max`.
|
|
771
|
+
`snap` gives it detents: a number at or below 1 is a fraction of the viewport along the sheet's
|
|
772
|
+
axis, anything larger is pixels, and a string is any CSS length (`'320px'`, `'90%'`). With
|
|
773
|
+
detents a drag settles on the nearest one rather than where it was released, and `snapTo(index)`
|
|
774
|
+
or `snapTo(value)` moves there directly. Dragging below half the smallest allowed size dismisses
|
|
775
|
+
a `closable` sheet, so resize, detent, and swipe-to-dismiss are one gesture whose meaning is
|
|
776
|
+
decided when the pointer settles. `getSize()` reports the current pixel size. A sheet that is
|
|
777
|
+
neither `resizable` nor snapping still has a draggable handle where `handle` shows one — that is
|
|
778
|
+
what makes a drawer dismissible — but the drag may only take size away, never add it, so it
|
|
779
|
+
cannot be grown by dragging when nothing asked for resizing.
|
|
780
|
+
- **Handle** — `handle: 'auto'` shows a grab handle on `top` and `bottom` sheets, which is what
|
|
781
|
+
makes them read as drawers; `true` and `false` force it either way. It exists whenever the sheet
|
|
782
|
+
is `resizable` or has `snap`, visible or not. It is a `separator` with live
|
|
783
|
+
`aria-valuenow`/`aria-valuemin`/`aria-valuemax`: arrow keys along the axis step it by 16px, Shift
|
|
784
|
+
by 64px. A docked sheet hides its handle — the dock's own divider resizes it there.
|
|
785
|
+
- **Custom properties** — `--zx-sheet-size` (written by `size`; the per-side default otherwise)
|
|
786
|
+
and `--zx-sheet-radius` (inner corners of a top/bottom sheet, default `--zx-radius-xl`) are
|
|
787
|
+
internal geometry, not published styling hooks — prefer the options. `--zx-overlay-blur` is a
|
|
788
|
+
tier-2 semantic token and is public: it sets the `'blur'` backdrop's radius, default `8px`.
|
|
789
|
+
- **Motion** — entry and exit both animate, via `@starting-style` and
|
|
790
|
+
`transition-behavior: allow-discrete` on `display`/`overlay`; without them the sheet appears and
|
|
791
|
+
disappears instantly. All of it sits inside `prefers-reduced-motion: no-preference`.
|
|
792
|
+
- **Keyboard and screen readers** — identical to Dialog: the native `<dialog>` supplies the role
|
|
793
|
+
and `aria-labelledby` points at the title. Escape closes when `closable`, focus moves to the
|
|
794
|
+
`[autofocus]` control or the first focusable descendant on open, and returns to the opener on
|
|
795
|
+
close. Tab cycles within the sheet when `modal` is `true` or `'trap-focus'`.
|
|
796
|
+
<!-- /doc -->
|
|
797
|
+
|
|
798
|
+
<!-- doc:sheet-stack -->
|
|
799
|
+
### SheetStack
|
|
800
|
+
|
|
801
|
+
An ordered group of Sheets that reads as one drill-down. Deliberately tiny, because the browser
|
|
802
|
+
already does the hard part: nested dialogs stack in the top layer by open order, so there is no
|
|
803
|
+
z-index bookkeeping, and Escape closes only the topmost, so unwinding one level at a time is
|
|
804
|
+
native. What is left is which sheet sits at which depth, written onto the elements as `data-depth`
|
|
805
|
+
and `--zx-sheet-depth` for CSS to interpret.
|
|
806
|
+
|
|
807
|
+
Owns no element, so it is a controller rather than a `Component` — constructed with options
|
|
808
|
+
alone, `new SheetStack({…})`.
|
|
809
|
+
|
|
810
|
+
- **Options** — `layout: 'stack'` (`'stack' | 'cascade'`), `offset: 24`, `scale: 0.04`, `max: 3`.
|
|
811
|
+
- **Methods** — `push(sheet)`, `pop()`, `popTo(sheet)`, `clear()`, `top()`, `size()`, `sheets()`,
|
|
812
|
+
`has(sheet)`, `on/off/once`, `destroy()`.
|
|
813
|
+
- **Events** — `push {sheet, depth}`, `pop {sheet}`. `pop` fires however a sheet left — popped,
|
|
814
|
+
dismissed with Escape, or closed by its own button.
|
|
815
|
+
- **Layouts** — `stack` slides each covered sheet back toward its own edge, scales it down, and
|
|
816
|
+
takes it out of the tab order; only the top one is usable, which is the drill-down feel.
|
|
817
|
+
`cascade` shifts each covered sheet clear of the ones in front — by their measured size, not a
|
|
818
|
+
guess — so they sit side by side and all stay usable. `cascade` is usually the right one for an
|
|
819
|
+
ERP screen, where the parent record should stay readable while a line item is edited.
|
|
820
|
+
- **Depth** — numbered from the top: the visible sheet is `0`. Past `max` a sheet stops being
|
|
821
|
+
drawn but stays open and in the stack. In a `stack` only the topmost backdrop shades the page;
|
|
822
|
+
one per depth would compound into black. A `cascade` shades nothing — a backdrop paints directly
|
|
823
|
+
beneath its own dialog in the top layer, so the top sheet's would dim exactly the sheets the
|
|
824
|
+
layout exists to keep readable. Pair a cascade with `modal: false` when the page behind it
|
|
825
|
+
should stay live as well.
|
|
826
|
+
- **Ownership** — the stack never owns its sheets. `destroy()` empties it and strips the depth
|
|
827
|
+
styling without closing anything.
|
|
828
|
+
- **Accessibility** — for `stack`, covered sheets are `inert`. The browser does that on its own
|
|
829
|
+
for stacked *modal* dialogs, but a non-modal stack gets nothing, so the attribute is set either
|
|
830
|
+
way. `cascade` deliberately leaves them interactive.
|
|
831
|
+
- **Gotcha** — `close()` on a dialog dispatches its `close` event in a queued task, not
|
|
832
|
+
synchronously. `pop()` therefore removes the sheet from the stack itself rather than waiting for
|
|
833
|
+
the event, so `popTo()` and `clear()` can loop without racing it.
|
|
834
|
+
<!-- /doc -->
|
|
835
|
+
|
|
678
836
|
<!-- doc:dropdown -->
|
|
679
837
|
### Dropdown
|
|
680
838
|
|
|
@@ -682,7 +840,8 @@ Generic anchored popover in the top layer, constructed as `new Dropdown(anchor,
|
|
|
682
840
|
light-dismisses on an outside click or Esc, and mirrors `aria-expanded` onto the anchor.
|
|
683
841
|
|
|
684
842
|
- **Options** — `content`,
|
|
685
|
-
`placement: 'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'
|
|
843
|
+
`placement: 'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'` plus the matching
|
|
844
|
+
`left*` and `right*` placements, `offset: 4`,
|
|
686
845
|
`matchWidth: false`, `openOn: 'click'|'manual'`, `closeOnSelect: false`.
|
|
687
846
|
- **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `setContent()`, `getPanel()`.
|
|
688
847
|
- **Events** — `open`, `close`.
|
|
@@ -695,8 +854,11 @@ A button that opens a `role="menu"`.
|
|
|
695
854
|
|
|
696
855
|
- **Options** — `label`, `icon`, `kind`,
|
|
697
856
|
`items: [{ label, icon?, value?, disabled?, danger?, onselect? } | '-']`, `placement`.
|
|
698
|
-
- **Methods** — `setItems()`, `open()`, `close()`, `setLabel()
|
|
857
|
+
- **Methods** — `setItems()`, `open()`, `close()`, `setLabel()`, `getTrigger()`, `getPanel()`,
|
|
858
|
+
`focusFirst()`, `focusLast()`.
|
|
699
859
|
- **Events** — `select {value, item}`, `open`, `close`.
|
|
860
|
+
- **Cancellation** — `select` is cancelable. Preventing it skips the item's `onselect` callback and
|
|
861
|
+
leaves the menu open, which is the composition seam used by `AccountMenu` and rail flyouts.
|
|
700
862
|
- **Keyboard** — ArrowDown/Enter/Space open and focus the first item; ArrowUp opens and focuses the
|
|
701
863
|
last; arrows cycle; Home/End; typeahead; Enter/Space select; Esc/Tab close.
|
|
702
864
|
<!-- /doc -->
|
|
@@ -734,7 +896,11 @@ parked at the pointer, so it flips near a viewport edge like every other floatin
|
|
|
734
896
|
|
|
735
897
|
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
898
|
|
|
737
|
-
- **Options** — `content` (string, Node, or a function re-evaluated on every open), `placement`
|
|
899
|
+
- **Options** — `content` (string, Node, or a function re-evaluated on every open), `placement`
|
|
900
|
+
(`'top'` default, plus top/bottom/left/right and their start/end variants), `offset` (6), `delay`
|
|
901
|
+
(400), `hideDelay` (80), `maxWidth` (260; a number is pixels, a string is any CSS length),
|
|
902
|
+
`trigger` (`'both'` default, or `'hover'`, `'focus'`, `'manual'` — `manual` installs no listeners
|
|
903
|
+
at all and leaves everything to the methods), `disabled` (false).
|
|
738
904
|
- **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
905
|
- **Events** — `open`, `close`. Both fire only on a real transition, so a `show()` on an open tooltip is silent.
|
|
740
906
|
- **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.
|
|
@@ -759,22 +925,32 @@ Sortable, selectable, sticky-header data table — one component covering both t
|
|
|
759
925
|
horizontally, and multi-select adds a tri-state header checkbox plus Shift+click range select.
|
|
760
926
|
|
|
761
927
|
- **Options** — `columns: [{ id, label, sortable?, width ('120px'|'2fr'|'auto'), align,
|
|
928
|
+
type?: 'text'|'number'|'currency'|'percent'|'unit', locale?, decimals?, currency?, unit?,
|
|
762
929
|
render?: (row,i)=>Node|string, sortValue?, headerTitle? }]`, `data`, `rowId: 'ID'`,
|
|
763
930
|
`sort: { id, dir }`, `sortMode: 'local'|'server'`, `selectable: false|'single'|'multi'`,
|
|
764
|
-
`stickyHeader: true`, `height`, `emptyText`, `rowClass`, `zebra: true
|
|
931
|
+
`stickyHeader: true`, `height`, `emptyText`, `rowClass`, `zebra: true`, and
|
|
932
|
+
`hierarchy: false|{parentId, column?, expanded?}`. Locale, currency, unit, and decimals may be
|
|
933
|
+
row callbacks; values remain numbers in row data while display formatting is locale-aware.
|
|
765
934
|
- **Methods** — `setData()`, `addData()`, `updateRow(id,row)`, `removeRow(id)`, `getRow(id)`,
|
|
766
935
|
`getData()`, `empty()`, `setSort(id,dir)`, `getSelection()`, `setSelection(ids)`,
|
|
767
936
|
`clearSelection()`, `setLoading(bool)` (busy/skeleton state — dims rows, shows an indeterminate
|
|
768
937
|
top bar, sets `aria-busy`, and is cleared by the next `setData`).
|
|
769
938
|
- **Events** — `rowclick {row, id, index, event}`, `rowdblclick`, `sort {id, dir}`,
|
|
770
|
-
`selectionchange {rows, ids}`, `datachange {rows}`.
|
|
939
|
+
`selectionchange {rows, ids}`, `datachange {rows}`, and `rowtoggle {row, id, expanded}`.
|
|
940
|
+
- **Hierarchy** — flat parent references are projected as an ARIA `treegrid`; `getData()` and all
|
|
941
|
+
editing/mutation APIs stay flat and ID-based. Orphans become roots, cycles render once, local
|
|
942
|
+
sort reorders siblings without mixing levels, and growing counts visible rows. Use
|
|
943
|
+
`toggleRow()`, `expandRow()`, `collapseRow()`, `expandAll()`, `collapseAll()`, and
|
|
944
|
+
`getExpanded()`. The native disclosure button works by pointer and keyboard without selecting
|
|
945
|
+
or clicking the row.
|
|
771
946
|
- **Editing** — `editMode: false|'cell'|'row'` (default `false`, and completely inert until set).
|
|
772
947
|
`'cell'` edits one cell, `'row'` opens every editable cell of the row and commits them as a unit.
|
|
773
948
|
Editors are sized into the cell without changing row height, and an editing cell carries
|
|
774
949
|
`data-editing="true"` (`data-invalid="true"` plus an `aria-live` message when a validator rejects).
|
|
775
950
|
- **Editable columns** — extra column keys: `editable: false|true|'text'|'number'|'select'|'date'|
|
|
776
|
-
'checkbox'|'textarea'|((row)=>boolean)` (`true`
|
|
777
|
-
|
|
951
|
+
'checkbox'|'textarea'|((row)=>boolean)` (`true` infers `'number'` for number/currency/percent/unit
|
|
952
|
+
columns and `'text'` otherwise; a function is evaluated per row, so individual rows stay
|
|
953
|
+
read-only), `options` for `'select'` (`[{value,label}]`, a `{value: label}` map
|
|
778
954
|
whose keys are always strings, or `(row)=>items`), `editorProps` (forwarded to the underlying
|
|
779
955
|
NumberField/Select/Datebox/Toggle or to the generated `<input>`/`<textarea>`),
|
|
780
956
|
`editor: (row, api)=>Node` for a fully custom editor (`api` is `{value, commit(value), cancel(),
|
|
@@ -783,6 +959,10 @@ horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
|
|
|
783
959
|
seeds the text of a `'text'`/`'textarea'` editor, `parse` converts every editor's raw output back),
|
|
784
960
|
and `validate: (value,row)=>true|string` (a returned string marks the cell invalid, shows the
|
|
785
961
|
message, and refuses the commit).
|
|
962
|
+
- **Transaction editors** — currency and unit columns reuse `NumberField` and show the resolved
|
|
963
|
+
currency/unit as its suffix unless `editorProps.unit` overrides it. This is a generic typed-grid
|
|
964
|
+
contract: application code remains responsible for tax, discount, subtotal, and accounting
|
|
965
|
+
formula rules.
|
|
786
966
|
- **Editing methods** — `startEdit(rowId, columnId)`, `commitEdit()`, `cancelEdit()`, `isEditing()`,
|
|
787
967
|
`getEditing()` → `{id, columnId}|null`.
|
|
788
968
|
- **Editing events** — `editstart {row, id, column, columnId, value}`;
|
|
@@ -824,6 +1004,53 @@ horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
|
|
|
824
1004
|
A function is re-called on every render, which is what to use when the placeholder holds controls.
|
|
825
1005
|
<!-- /doc -->
|
|
826
1006
|
|
|
1007
|
+
<!-- doc:grid -->
|
|
1008
|
+
### Grid and `Grid.BillingItems()`
|
|
1009
|
+
|
|
1010
|
+
`Grid` is the public extension point for repeatable data-table presets. It subclasses `Table`
|
|
1011
|
+
without forking its implementation, so sorting, selection, hierarchy, responsive stacking,
|
|
1012
|
+
editable cells/rows, loading, events, and teardown keep the Table contract.
|
|
1013
|
+
|
|
1014
|
+
- **Constructor** — `new Grid(target, tableOptions)` accepts the complete `Table` API.
|
|
1015
|
+
- **Preset** — `Grid.BillingItems(target, options)` supplies an editable hierarchical billing
|
|
1016
|
+
schema for item, quantity, unit, unit price, currency, and line total. It returns a `Grid`.
|
|
1017
|
+
- **Billing options** — `data`, `fields` key overrides, `units`, `currencies`, fallback `currency`,
|
|
1018
|
+
`locale`, `decimals`, `columnOverrides`, complete `columns` replacement, `lineTotal(row, changes)`,
|
|
1019
|
+
and `oneditcommit` in addition to ordinary Table options.
|
|
1020
|
+
- **Rows** — default field names are `id`, `parent`, `kind`, `item`, `quantity`, `unit`,
|
|
1021
|
+
`unitPrice`, `currency`, and `total`. `kind: 'group'|'subtotal'|'header'|'section'` is read-only;
|
|
1022
|
+
other rows are editable. Parent references use Table's flat-data treegrid projection.
|
|
1023
|
+
- **Calculation boundary** — the default line total is quantity × unit price. Applications own
|
|
1024
|
+
taxes, discounts, rounding, subtotal/group recalculation, optimistic persistence, and server
|
|
1025
|
+
validation; provide `lineTotal` or cancel `editcommit` when product policy differs.
|
|
1026
|
+
<!-- /doc -->
|
|
1027
|
+
|
|
1028
|
+
<!-- doc:chart -->
|
|
1029
|
+
### Chart and `ChartJsAdapter`
|
|
1030
|
+
|
|
1031
|
+
An accessible, engine-neutral chart host. Zx renders state, canvas, semantic data summary, tokens,
|
|
1032
|
+
and lifecycle; an injected adapter owns the drawing engine. The Zx runtime imports no Chart.js
|
|
1033
|
+
code, so future adapters do not change the public `Chart` API.
|
|
1034
|
+
|
|
1035
|
+
- **Options** — `adapter`, `type: 'bar'`, `data`, engine-specific `chartOptions`, `label`,
|
|
1036
|
+
`description`, `summary: 'hidden'|'visible'`, `loading`, loading/empty/error text, and
|
|
1037
|
+
`aspectRatio: '16 / 9'`.
|
|
1038
|
+
- **Methods** — `setData()`, `setType()`, `update(chartOptions)`, `setAdapter()`, `setLoading()`,
|
|
1039
|
+
`setError()`, `clearError()`, `resize()`, `refreshTheme()`, `getInstance()`, `destroy()`.
|
|
1040
|
+
- **Events** — `ready {instance}`, `update {data, type}`, `select {datasetIndex, index, dataset,
|
|
1041
|
+
label, value, nativeEvent}`, and `error {error}`.
|
|
1042
|
+
- **Adapter contract** — `adapter.create(canvas, {type, data, options, onSelect})` returns
|
|
1043
|
+
`{update(spec), resize(), destroy(), instance?}`. Implementations must destroy engine resources
|
|
1044
|
+
and must not retain the component after teardown.
|
|
1045
|
+
- **`ChartJsAdapter`** — construct it with a Chart.js constructor or namespace:
|
|
1046
|
+
`new ChartJsAdapter(window.Chart)`. The documentation pins Chart.js 4.5.1 as a development-only
|
|
1047
|
+
asset; `package.json` has no runtime dependencies and application builds explicitly choose how
|
|
1048
|
+
the engine is loaded.
|
|
1049
|
+
- **Accessibility** — the canvas always has a name and optional description, while synchronized
|
|
1050
|
+
labels and dataset values live in a semantic table. `summary: 'hidden'` keeps it visually hidden
|
|
1051
|
+
for assistive technology; `'visible'` makes exact values part of the interface.
|
|
1052
|
+
<!-- /doc -->
|
|
1053
|
+
|
|
827
1054
|
<!-- doc:data-filter -->
|
|
828
1055
|
### DataFilter
|
|
829
1056
|
|
|
@@ -927,6 +1154,76 @@ Beyond the built-in field types, these widget types wrap whole components, used
|
|
|
927
1154
|
`toggle` (Toggle).
|
|
928
1155
|
<!-- /doc -->
|
|
929
1156
|
|
|
1157
|
+
<!-- doc:questionnaire -->
|
|
1158
|
+
### Questionnaire
|
|
1159
|
+
|
|
1160
|
+
A guided, one-question-at-a-time flow: onboarding intake, a service-call checklist, an audit form,
|
|
1161
|
+
a feedback survey. The questionnaire owns the ordered items, the active one, the answers,
|
|
1162
|
+
validation, progress and navigation; the page, card, dialog or drawer around it owns closing,
|
|
1163
|
+
persistence and transport.
|
|
1164
|
+
|
|
1165
|
+
The root is a real `<form>` and the choices are native radios and checkboxes carrying the item
|
|
1166
|
+
name, so `new FormData(questionnaire.toElement())` reads the answers, arrow keys inside a choice
|
|
1167
|
+
group are the browser's rather than ours, and the semantics do not depend on JavaScript. Three
|
|
1168
|
+
things separate it from a `Form` with one `Fieldset` per question: it branches, its answer control
|
|
1169
|
+
can be any registered `Field` type, and its validation may be asynchronous.
|
|
1170
|
+
|
|
1171
|
+
- **Options** — `items: [{name, prompt, description?, section?, required?, multiple?, skippable?,
|
|
1172
|
+
choices?, input?, field?, when?, next?, validate?}]`, `answers: {}` and `active: null` (the
|
|
1173
|
+
resume pair), `progress: true`, `review: false`, `advance: 'manual'|'auto'`, `shortcuts: true`,
|
|
1174
|
+
`allowBack: true`.
|
|
1175
|
+
- **Choices** — `[{value, label, description?, icon?, key?, disabled?, exclusive?}]`. `exclusive`
|
|
1176
|
+
is the "None of the above" behaviour: picking it clears the rest of a `multiple` item, and
|
|
1177
|
+
picking anything else clears it.
|
|
1178
|
+
- **Methods** — `setItems()`, `getItems()`, `goTo(name)`, `next()`, `previous()`, `skip()`,
|
|
1179
|
+
`submit()`, `getAnswers()`, `getAnswer(name)`, `setAnswers(values, {silent})`,
|
|
1180
|
+
`setAnswer(name, value, {silent})`, `getActive()`, `getPath()`, `getProgress()`, `getState()`,
|
|
1181
|
+
`toFormData()`, `reset()`, `focus()`, `destroy()`. `next()`, `skip()` and `submit()` return
|
|
1182
|
+
**promises** — `next()` because an item's `validate` may be asynchronous, and `skip()` because
|
|
1183
|
+
skipping the last question submits. Everything else is synchronous.
|
|
1184
|
+
- **Events** — `change {name, value, answers}`, `navigate {from, to, reason}` **preventable**,
|
|
1185
|
+
`skip {name}`, `invalid {name, message}`, `submit {answers, path}` **preventable**,
|
|
1186
|
+
`complete {answers, path}`.
|
|
1187
|
+
- **Branching** — `when(answers)` decides whether an item is asked at all, and `next` (a name, or
|
|
1188
|
+
`(answer, answers) => name`) decides what follows. Conditions **cascade**: each predicate sees
|
|
1189
|
+
only the answers of visible items declared before it, so hiding the VAT question also hides
|
|
1190
|
+
whatever depended on the VAT id. An answer to a conditioned-out question is kept internally —
|
|
1191
|
+
walk back into the branch and it is still there — but is left out of `getAnswers()` and
|
|
1192
|
+
`toFormData()`, so an abandoned branch never submits stale data. A `next` naming a hidden item
|
|
1193
|
+
walks forward from it rather than stranding the reader; naming an item that does not exist
|
|
1194
|
+
throws `RangeError`.
|
|
1195
|
+
- **Path and progress** — `getPath()` is the questionnaire's memory of the route walked, and
|
|
1196
|
+
`previous()` pops it: once a branch has been taken, "previous" is not `index - 1`. `getProgress()`
|
|
1197
|
+
returns `{index, answered, total, percent, section}` where `total` is the path plus the items
|
|
1198
|
+
still reachable — exact for a static flow, an estimate once a function `next` can jump somewhere
|
|
1199
|
+
the forward walk cannot predict.
|
|
1200
|
+
- **Field answers** — `field: {type: 'date'|'number'|'zxselect'|'rating'|'upload'|…}` hands the
|
|
1201
|
+
answer to a `Field`, so any registered field type works, including ones an application registered
|
|
1202
|
+
itself. The `<legend>` already asks the question, so the Field's own label is hidden from sight
|
|
1203
|
+
but kept as the control's accessible name unless the item gives `field.label` explicitly; the
|
|
1204
|
+
Field draws its own highlight, so a failing answer shows one message, not two.
|
|
1205
|
+
- **Validation** — `required` is checked synchronously; an item's `validate(answer, answers)` may
|
|
1206
|
+
return a message, `null`, or a **promise** of either, and a rejection is reported as its message.
|
|
1207
|
+
While the check is pending the root carries `data-state="checking"` and `aria-busy="true"` and
|
|
1208
|
+
the actions are disabled.
|
|
1209
|
+
- **Review** — `review: true` shows a summary of every answer on the path before submitting, each
|
|
1210
|
+
with an Edit that reopens that question; Continue from an edited question comes straight back to
|
|
1211
|
+
the review rather than replaying the tail.
|
|
1212
|
+
- **Semantics** — the item is a `<fieldset>` and the prompt its `<legend>`; the description and the
|
|
1213
|
+
error are associated through `aria-describedby`, the error is a `role="alert"`, and a failing
|
|
1214
|
+
item carries `aria-invalid="true"`. `data-state` on the root is
|
|
1215
|
+
`asking`, `checking`, `review`, or `complete`. Submitting does not replace the content: it sets
|
|
1216
|
+
`data-state="complete"`, hides the actions, and emits `complete`, leaving the thank-you screen to
|
|
1217
|
+
the application.
|
|
1218
|
+
- **Keyboard** — `1`–`9` then `a`–`z` pick the matching answer, assigned in choice order (an
|
|
1219
|
+
explicit `key` is reserved first, so adding one never renumbers the others) and shown as a key
|
|
1220
|
+
cap on each choice; the caps are `aria-hidden`, since a screen-reader user moves through the
|
|
1221
|
+
group with the arrow keys the radios already provide. `Enter` continues, except in a `multiline`
|
|
1222
|
+
input. Shortcuts are suppressed while focus is in a text control. Navigating moves focus to the
|
|
1223
|
+
new question's fieldset, which is what gets the prompt announced; failing validation moves it to
|
|
1224
|
+
the first answer control instead.
|
|
1225
|
+
<!-- /doc -->
|
|
1226
|
+
|
|
930
1227
|
<!-- doc:value-list -->
|
|
931
1228
|
### ValueList
|
|
932
1229
|
|
|
@@ -991,19 +1288,6 @@ yet. Field type: `tagpicker`.
|
|
|
991
1288
|
within the list.
|
|
992
1289
|
<!-- /doc -->
|
|
993
1290
|
|
|
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
1291
|
<!-- doc:groupbox -->
|
|
1008
1292
|
### Groupbox
|
|
1009
1293
|
|
|
@@ -1073,6 +1357,62 @@ markup with no JavaScript.
|
|
|
1073
1357
|
because a CSS custom property cannot be used inside a media query.
|
|
1074
1358
|
<!-- /doc -->
|
|
1075
1359
|
|
|
1360
|
+
<!-- doc:dock -->
|
|
1361
|
+
### Dock
|
|
1362
|
+
|
|
1363
|
+
A stack of collapsible, resizable panes: the docked inspector column of a design tool, and the
|
|
1364
|
+
detail side of a master–detail screen. Give the root a size of its own (a grid area, `block-size:
|
|
1365
|
+
100%`, a flex child) when the panes should fill a shell rather than grow with their content.
|
|
1366
|
+
|
|
1367
|
+
- **Options** — `orientation: 'vertical'`, `content: null`, `panes: []`, `resizable: true`,
|
|
1368
|
+
`collapsible: true`, `lazy: true`, `storageKey: null`.
|
|
1369
|
+
- **Pane** — `{name, title?, content?, tabs?, active?, size?, min?, grow?, collapsed?,
|
|
1370
|
+
collapsible?, side?}`. `content` takes a string, Node, Component, or a factory called on first
|
|
1371
|
+
reveal. A pane with `tabs` renders its strip in place of the title; `content` is then ignored.
|
|
1372
|
+
`side` (`'start' | 'end'`) only applies when the dock has a `content`.
|
|
1373
|
+
- **Tab** — `{name, title, content?}`, same content shapes.
|
|
1374
|
+
- **Methods** — `pane(name)`, `names()`, `add(pane, {index})`, `remove(name)`,
|
|
1375
|
+
`collapse(name)`, `expand(name)`, `toggle(name)`, `isCollapsed(name)`, `reveal(name)`,
|
|
1376
|
+
`setSize(name, size)`, `getSize(name)`, `activate(pane, tab)`, `getActive(pane)`,
|
|
1377
|
+
`state()`, `setState(state)`, `adopt(sheet, options)`, `release(sheet)`.
|
|
1378
|
+
- **Adopting a Sheet** — `adopt(sheet, {name?, side?, index?, size?, min?, dockAt?})` takes over a
|
|
1379
|
+
`Sheet`'s positioning: it becomes a track in the dock rather than an overlay. The dock owns
|
|
1380
|
+
where it sits, its size, and its resizing; the sheet keeps its content, header, footer, events,
|
|
1381
|
+
and its own `open()`/`close()`. `dockAt` names a breakpoint below which the dock hands the sheet
|
|
1382
|
+
back to a free overlay and reclaims the track, re-adopting it above — measured on the **dock's
|
|
1383
|
+
own width**, so a dock inside a split pane behaves correctly where a viewport media query would
|
|
1384
|
+
not. Because a dock is a flex container by construction it is always a valid host, which is why
|
|
1385
|
+
docking needs no arrangement from the application.
|
|
1386
|
+
- **Ownership** — the dock never owns an adopted sheet: `destroy()` releases them rather than
|
|
1387
|
+
destroying them, `remove(name)` on a sheet releases it, and a sheet that destroys itself while
|
|
1388
|
+
adopted drops out of the dock cleanly.
|
|
1389
|
+
- **Events** — `collapse {name}`, `expand {name}`, `resize {name, size}`,
|
|
1390
|
+
`tabchange {pane, tab, previous}`, `reveal {name}`.
|
|
1391
|
+
- **Sizing** — one custom property per pane and one flex rule: a sized pane is
|
|
1392
|
+
`flex: 0 0 var(--zx-pane-size)`, a collapsed one falls to `flex: 0 0 auto` with its body hidden,
|
|
1393
|
+
and exactly one element grows. With a `content` that is always the content; without one it is the
|
|
1394
|
+
pane declaring `grow`, or the last expanded pane. A drag therefore rewrites at most two
|
|
1395
|
+
properties, and collapsing a pane feeds the grower rather than redistributing across the stack.
|
|
1396
|
+
- **Regions** — with `content` the dock is a region rather than a plain stack: panes sit on either
|
|
1397
|
+
`side` of the flexible middle. Nesting one dock inside another dock's pane gives a workbench —
|
|
1398
|
+
a canvas with an inspector column beside it.
|
|
1399
|
+
- **`reveal(name)`** — accepts a pane name or a tab name. Expands whichever pane holds it,
|
|
1400
|
+
activates the tab when the name is a tab's, and scrolls it into view.
|
|
1401
|
+
- **Persistence** — `storageKey` remembers sizes, collapsed panes, and active tabs through
|
|
1402
|
+
`storage()`, which degrades to memory rather than throwing. `state()`/`setState()` expose the
|
|
1403
|
+
same shape for storing it elsewhere; unknown pane names are ignored, so a stored layout survives
|
|
1404
|
+
a release that added or removed panes.
|
|
1405
|
+
- **Keyboard and screen readers** — each pane header is a row, not one big button, so the collapse
|
|
1406
|
+
toggle and the tab strip can coexist; the toggle carries `aria-expanded` and `aria-controls`.
|
|
1407
|
+
Tabs follow the APG tab pattern with one roving tab stop, Left/Right moving between them.
|
|
1408
|
+
Dividers are focusable `separator`s carrying live `aria-valuenow`/`aria-valuemin`/`aria-valuemax`
|
|
1409
|
+
in pixels: Up/Down (or Left/Right when horizontal) resize by 16px, Shift by 64px, and Enter or
|
|
1410
|
+
Space collapses the pane before the divider. A divider with nothing to resize is taken out of the
|
|
1411
|
+
tab order.
|
|
1412
|
+
- **Out of scope** — drag-to-rearrange, tear-off panels, and multi-column docks. All three are
|
|
1413
|
+
additive without changing the API above.
|
|
1414
|
+
<!-- /doc -->
|
|
1415
|
+
|
|
1076
1416
|
<!-- doc:tabbox -->
|
|
1077
1417
|
### Tabbox — APG tabs
|
|
1078
1418
|
|
|
@@ -1178,12 +1518,67 @@ menu on narrow widths.
|
|
|
1178
1518
|
- **Events** — `change {name}`.
|
|
1179
1519
|
<!-- /doc -->
|
|
1180
1520
|
|
|
1521
|
+
<!-- doc:app-sidebar -->
|
|
1522
|
+
### AppSidebar — expanded application navigation
|
|
1523
|
+
|
|
1524
|
+
Persistent vertical application navigation with header, scrollable tree, and sticky footer slots.
|
|
1525
|
+
It is route-agnostic: ZeyOS supplies native `href` values or handles cancelable selections through
|
|
1526
|
+
`PG.go()`. This expanded presentation is the only application-nav component that reveals children
|
|
1527
|
+
inline.
|
|
1528
|
+
|
|
1529
|
+
- **Options** — shared application `items`, `active`, `expanded`, `collapsed`, `side: 'left'|'right'`,
|
|
1530
|
+
`label`, and `header`, `footer`, `railHeader`, `railFooter` content slots.
|
|
1531
|
+
- **Methods** — `setItems()`, `setActive()`, `setExpanded()`, `getExpanded()`, `toggleBranch()`,
|
|
1532
|
+
`expand()`, `collapse()`, `setCollapsed()`, `isCollapsed()`, `getRail()`, `destroy()`.
|
|
1533
|
+
- **Events** — cancelable `select {item, id, value, href, event}`,
|
|
1534
|
+
`branchchange {item, id, expanded, ids}` (`item`, `id`, and `expanded` are null for a bulk
|
|
1535
|
+
`setExpanded()`), and `collapsechange {collapsed}`.
|
|
1536
|
+
- **Minimized state** — collapse composes `AppRail` over the same normalized item tree. Expanded
|
|
1537
|
+
branch IDs survive the round trip but are not rendered inline while minimized.
|
|
1538
|
+
- **Semantics** — persistent navigation uses `<nav>` and nested lists with native links and
|
|
1539
|
+
disclosure buttons, not menu or menubar roles. A parent with children is disclosure-only; give
|
|
1540
|
+
it an explicit Overview child when the parent also needs a destination.
|
|
1541
|
+
<!-- /doc -->
|
|
1542
|
+
|
|
1543
|
+
<!-- doc:app-rail -->
|
|
1544
|
+
### AppRail — minimized application navigation
|
|
1545
|
+
|
|
1546
|
+
The compact form of application navigation for left, right, top, or bottom placement. It can flow
|
|
1547
|
+
vertically or horizontally, but descendants are always anchored flyouts—never inline—and open
|
|
1548
|
+
toward the workspace.
|
|
1549
|
+
|
|
1550
|
+
- **Options** — shared application `items`, `active`, `orientation: 'vertical'|'horizontal'`,
|
|
1551
|
+
`side: 'left'|'right'|'top'|'bottom'`, `label`, `header`, `footer`, `openDelay: 80`, and
|
|
1552
|
+
`closeDelay: 160`.
|
|
1553
|
+
- **Methods** — `setItems()`, `setActive()`, `getItems()`, `openFlyout(id, {focus})`,
|
|
1554
|
+
`closeFlyout()`, `closeAllFlyouts()` (including pending hover/focus timers and descendant
|
|
1555
|
+
branches), `isFlyoutOpen()`, `focus()`, `destroy()`.
|
|
1556
|
+
- **Events** — cancelable `select {item, id, value, href, event}` and
|
|
1557
|
+
`flyoutchange {item, id, open}`.
|
|
1558
|
+
- **Pointer and focus** — hover or focus reveals a child collection without stealing focus. The
|
|
1559
|
+
close delay covers the trigger-to-panel gap; leaving both trigger and panel closes it. Click,
|
|
1560
|
+
Enter, Space, and the inward arrow also open it, so horizontal subnavigation is discoverable and
|
|
1561
|
+
usable without hover. Escape, outside activation, or selection closes it.
|
|
1562
|
+
- **Semantics** — every icon-only destination retains a visible Tooltip and an accessible name.
|
|
1563
|
+
Persistent rail destinations remain native links/buttons in a labelled navigation list; the
|
|
1564
|
+
transient child flyout supplies its own arrow-key focus interaction.
|
|
1565
|
+
<!-- /doc -->
|
|
1566
|
+
|
|
1181
1567
|
<!-- doc:kernel -->
|
|
1182
1568
|
### Core helpers
|
|
1183
1569
|
|
|
1184
1570
|
- **Component** — the base class: `on`/`off`/`once`/`emit`, `listen`, `toElement`, `msg`,
|
|
1185
1571
|
`destroy`, and the static `Component.from(el)`.
|
|
1186
|
-
- **DOM** — `h(tag, props, ...children)`, `h.raw(html)`, `htmlEscape`, `resolveElement`.
|
|
1572
|
+
- **DOM** — `h(tag, props, ...children)`, `h.raw(html)`, `htmlEscape`, `resolveElement`. The current
|
|
1573
|
+
ZeyOS builder is also first-class: `__(tag#id.class, properties, content)` is the migration alias
|
|
1574
|
+
for `compactElement()`. It preserves `D*` data, `S*` style, boolean/built-in property, attribute,
|
|
1575
|
+
and legacy `on*` callback rules while keeping content text-safe. `applyCompactProperties`,
|
|
1576
|
+
`appendContent`, `appendCompact` (parent return), `appendCompactChild` (child return), and
|
|
1577
|
+
`fragment(...children)` are the pure forms.
|
|
1578
|
+
- **Compact events** — `onCompactEvent`, `offCompactEvent`, and `fireCompactEvent` share one
|
|
1579
|
+
newest-first handler registry. Existing `DOM.on/remEvt/fireEvt` methods can delegate to this
|
|
1580
|
+
triad. Zx never installs globals or alters DOM prototypes; the current application owns those
|
|
1581
|
+
temporary seams while `UI.new*` implementations are replaced without rewriting `PG` routing.
|
|
1187
1582
|
- **Icons** — `icon(name, {size, label})` and `icons`; see the Icons section — bundled inline SVG
|
|
1188
1583
|
by default, Font Awesome after an opt-in.
|
|
1189
1584
|
- **Positioning** — `position(anchor, floating, {placement, offset, flip, matchWidth})` →
|
|
@@ -1328,8 +1723,9 @@ never imported by `src/index.js`, and adds nothing to an application that does n
|
|
|
1328
1723
|
|
|
1329
1724
|
- **Loading** — classic: `<script src="/assets/zx-compat.global.js">` → `window.gx`; module:
|
|
1330
1725
|
`import { gx } from '/assets/zx-compat.esm.js'` (or `src/compat/index.js` in-repo).
|
|
1331
|
-
`gx.compat.installGlobals()` additionally installs the
|
|
1332
|
-
`String.htmlSpecialChars`, and the element `store`/`retrieve` shim.
|
|
1726
|
+
`gx.compat.installGlobals()` additionally installs the gx `__()` parser only when that name is
|
|
1727
|
+
free, plus `_()`, `String.htmlSpecialChars`, and the element `store`/`retrieve` shim. It never
|
|
1728
|
+
replaces ZeyOS's compact builder. `gx.install(host)` assigns
|
|
1333
1729
|
the namespace without the optional globals.
|
|
1334
1730
|
- **`gx.zeyos`** — Select/SelectFilter/SelectDyn/SelectPrio, Table, Tabbox, Panel, MasterPanel,
|
|
1335
1731
|
Groupbox, Search, Datebox, DatePicker, MonthPicker, TimePicker, Timebox, Toggle, Msgbox, Popup,
|