@zeyos/zx 4.3.0 → 4.4.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +266 -1
  2. package/README.md +7 -3
  3. package/dist/types/components/activity-item/activity-item.d.ts +351 -0
  4. package/dist/types/components/activity-list/activity-list.d.ts +195 -0
  5. package/dist/types/components/app-sidebar/app-sidebar.d.ts +28 -0
  6. package/dist/types/components/button/button.d.ts +8 -0
  7. package/dist/types/components/calendar/calendar-model.d.ts +22 -0
  8. package/dist/types/components/calendar/calendar.d.ts +19 -0
  9. package/dist/types/components/card/card.d.ts +7 -0
  10. package/dist/types/components/card-view/card-view.d.ts +12 -4
  11. package/dist/types/components/card-view/record-card.d.ts +53 -5
  12. package/dist/types/components/code-editor/code-editor.d.ts +160 -0
  13. package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
  14. package/dist/types/components/context-menu/context-menu.d.ts +18 -2
  15. package/dist/types/components/date-picker/date-picker.d.ts +8 -0
  16. package/dist/types/components/date-picker/time-picker.d.ts +7 -0
  17. package/dist/types/components/dialog/dialog.d.ts +29 -0
  18. package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
  19. package/dist/types/components/file-item/file-item.d.ts +234 -0
  20. package/dist/types/components/file-list/file-list.d.ts +171 -0
  21. package/dist/types/components/filter/filter.d.ts +91 -36
  22. package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
  23. package/dist/types/components/kanban-view/kanban-card.d.ts +138 -0
  24. package/dist/types/components/kanban-view/kanban-policy.d.ts +268 -0
  25. package/dist/types/components/kanban-view/kanban-view.d.ts +837 -26
  26. package/dist/types/components/launcher/launcher.d.ts +19 -12
  27. package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
  28. package/dist/types/components/menu-button/menu-button.d.ts +4 -37
  29. package/dist/types/components/message/message.d.ts +7 -0
  30. package/dist/types/components/modal/modal.d.ts +48 -0
  31. package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
  32. package/dist/types/components/panel/panel.d.ts +7 -0
  33. package/dist/types/components/search/search.d.ts +7 -0
  34. package/dist/types/components/select/select.d.ts +4 -0
  35. package/dist/types/components/sort-control/sort-control.d.ts +105 -0
  36. package/dist/types/components/stat-tile/stat-tile.d.ts +277 -0
  37. package/dist/types/components/tabbox/tabbox.d.ts +7 -0
  38. package/dist/types/components/table/table.d.ts +144 -0
  39. package/dist/types/components/table-view/table-view.d.ts +11 -5
  40. package/dist/types/components/timebox/timebox.d.ts +7 -0
  41. package/dist/types/components/value-list/value-list.d.ts +8 -0
  42. package/dist/types/components/view/record-view.d.ts +96 -5
  43. package/dist/types/core/component.d.ts +6 -1
  44. package/dist/types/core/icons.d.ts +17 -0
  45. package/dist/types/index.d.ts +13 -1
  46. package/dist/types/internal/app-rail.d.ts +10 -0
  47. package/dist/types/internal/menu-items.d.ts +134 -0
  48. package/dist/zx-zeyos.esm.js +651 -88
  49. package/dist/zx-zeyos.esm.min.js +8 -1
  50. package/dist/zx.css +6266 -3900
  51. package/dist/zx.esm.js +8487 -1805
  52. package/dist/zx.esm.min.js +10 -3
  53. package/dist/zx.global.js +8487 -1805
  54. package/dist/zx.global.min.js +10 -3
  55. package/dist/zx.min.css +1 -1
  56. package/docs/api.json +1811 -247
  57. package/docs/llms.md +345 -40
  58. package/docs/llms.txt +11 -7
  59. package/package.json +1 -2
  60. package/src/components/activity-item/activity-item.css +137 -0
  61. package/src/components/activity-item/activity-item.js +599 -0
  62. package/src/components/activity-list/activity-list.css +64 -0
  63. package/src/components/activity-list/activity-list.js +375 -0
  64. package/src/components/app-rail/app-rail.css +227 -19
  65. package/src/components/app-sidebar/app-sidebar.css +414 -24
  66. package/src/components/app-sidebar/app-sidebar.js +65 -5
  67. package/src/components/button/button.css +8 -0
  68. package/src/components/button/button.js +6 -1
  69. package/src/components/calendar/calendar-model.js +45 -0
  70. package/src/components/calendar/calendar.css +30 -10
  71. package/src/components/calendar/calendar.js +41 -13
  72. package/src/components/card/card.js +12 -1
  73. package/src/components/card-view/card-view.css +212 -9
  74. package/src/components/card-view/card-view.js +32 -16
  75. package/src/components/card-view/record-card.js +98 -21
  76. package/src/components/code-editor/code-editor.css +67 -0
  77. package/src/components/code-editor/code-editor.js +288 -0
  78. package/src/components/code-editor/field-adapter.js +34 -0
  79. package/src/components/context-menu/context-menu.css +80 -3
  80. package/src/components/context-menu/context-menu.js +22 -30
  81. package/src/components/date-picker/date-picker.js +22 -8
  82. package/src/components/date-picker/month-picker.js +3 -3
  83. package/src/components/date-picker/time-picker.js +20 -8
  84. package/src/components/dialog/dialog.js +88 -66
  85. package/src/components/dropdown/dropdown.js +2 -2
  86. package/src/components/entity-ref/entity-ref.css +182 -0
  87. package/src/components/entity-ref/entity-ref.js +496 -0
  88. package/src/components/file-item/file-item.css +88 -0
  89. package/src/components/file-item/file-item.js +371 -0
  90. package/src/components/file-list/file-list.css +51 -0
  91. package/src/components/file-list/file-list.js +320 -0
  92. package/src/components/filter/filter.css +27 -1
  93. package/src/components/filter/filter.js +199 -45
  94. package/src/components/filter-panel/filter-panel.css +104 -0
  95. package/src/components/filter-panel/filter-panel.js +964 -0
  96. package/src/components/kanban-view/kanban-card.js +239 -0
  97. package/src/components/kanban-view/kanban-policy.js +412 -0
  98. package/src/components/kanban-view/kanban-view.css +674 -36
  99. package/src/components/kanban-view/kanban-view.js +1762 -240
  100. package/src/components/launcher/launcher.js +59 -27
  101. package/src/components/list-toolbar/list-toolbar.css +189 -0
  102. package/src/components/list-toolbar/list-toolbar.js +851 -0
  103. package/src/components/menu-button/menu-button.css +80 -3
  104. package/src/components/menu-button/menu-button.js +21 -37
  105. package/src/components/message/message.css +14 -12
  106. package/src/components/message/message.js +13 -2
  107. package/src/components/modal/modal.css +15 -0
  108. package/src/components/modal/modal.js +141 -0
  109. package/src/components/navigation-bar/navigation-bar.css +77 -2
  110. package/src/components/navigation-bar/navigation-bar.js +171 -4
  111. package/src/components/panel/panel.js +13 -2
  112. package/src/components/search/search.js +17 -5
  113. package/src/components/select/field-adapter.js +4 -1
  114. package/src/components/select/select.js +3 -0
  115. package/src/components/sort-control/sort-control.css +17 -0
  116. package/src/components/sort-control/sort-control.js +140 -0
  117. package/src/components/stat-tile/stat-tile.css +213 -0
  118. package/src/components/stat-tile/stat-tile.js +590 -0
  119. package/src/components/tabbox/tabbox.js +12 -1
  120. package/src/components/table/table.css +51 -2
  121. package/src/components/table/table.js +298 -19
  122. package/src/components/table-view/table-view.css +8 -2
  123. package/src/components/table-view/table-view.js +21 -6
  124. package/src/components/tag-picker/tag-picker.css +3 -1
  125. package/src/components/timebox/timebox.js +18 -5
  126. package/src/components/value-list/value-list.js +22 -6
  127. package/src/components/view/record-view.css +5 -0
  128. package/src/components/view/record-view.js +100 -7
  129. package/src/core/component.js +8 -3
  130. package/src/core/icons.js +74 -5
  131. package/src/index.js +33 -3
  132. package/src/internal/app-rail.js +19 -1
  133. package/src/internal/menu-items.js +142 -0
  134. package/styles/print.css +192 -0
  135. package/styles/zx.css +11 -0
  136. package/DESIGN-SYSTEM.md +0 -182
package/docs/llms.md CHANGED
@@ -31,6 +31,8 @@ const t = new Table(target, options);
31
31
  (always an object, e.g. `{ value, item }`).
32
32
  - Every `emit` also dispatches a **bubbling, composed** `zx-<type>` `CustomEvent` on `t.el`, so
33
33
  `t.el.addEventListener('zx-change', …)` and event delegation work.
34
+ - Mutation boundaries may opt into honoring cancellation of that mirrored DOM event; Kanban's
35
+ `zx-recordmove` does, so delegated hosts can veto a move without a component reference.
34
36
  - `t.destroy()` aborts all listeners (one AbortController), unregisters the element, and removes an
35
37
  owned root. `Component.from(el)` returns the component for a root element (replaces the legacy
36
38
  `el.retrieve('com')`).
@@ -99,6 +101,13 @@ Define a product theme by overriding **semantic** tokens under a `[data-zx-theme
99
101
  `--zx-green-*`) or raw color literals in application/component CSS. Prefer the least-specific
100
102
  override that works (global token → then, if needed, a component style).
101
103
 
104
+ **Print.** `zx.css` imports `styles/print.css` last. It releases sticky headers and scroll
105
+ containers, drops fills, shadows, zebra striping and focus rings, hides overlays and navigation
106
+ chrome, repeats table headers across pages, keeps cards and rows from breaking, and prints link
107
+ URLs in prose but never inside a table cell or on a button. Status badges keep their colour,
108
+ because there it carries meaning beside the word. An application that pins `data-zx-theme="dark"`
109
+ still prints the dark token set; `auto` resolves to light under `@media print` and is unaffected.
110
+
102
111
  ## Talking to ZeyOS — use `@zeyos/client`
103
112
 
104
113
  For ZeyOS business data use the **dedicated client library** `@zeyos/client`
@@ -253,28 +262,6 @@ reflection and ElementInternals form association: `<zx-toggle>`, `<zx-check-butt
253
262
  `<zx-checklist>`, `<zx-datebox>`, `<zx-timebox>`, `<zx-search>`, `<zx-groupbox>`, `<zx-tabbox>`,
254
263
  `<zx-table>`, `<zx-dialog>`.
255
264
 
256
- ## Conventions (editing component source)
257
-
258
- Follow `AGENTS.md`. Key rules: never declare instance class fields for state used in `render()`
259
- (render runs inside the base constructor before field initializers); route all DOM listeners
260
- through `this.listen()`; no `innerHTML` outside `h.raw()`; express state via ARIA/`data-*`, not
261
- state classes; small glyph buttons use the shared `.zx-icon-btn` utility; follow the named APG
262
- pattern with `:focus-visible` rings and `prefers-reduced-motion` guards.
263
-
264
- ## File map & commands
265
-
266
- ```
267
- src/components/<name>/ component + CSS src/core/ kernel (component, dom, http, i18n, date…)
268
- website/ marketing page + docs.html (docs.js) specs/ per-component specs
269
- website/demos/ per-component demo modules website/layouts/ application layout examples
270
- tests/ node unit + smoke dist/ built bundles
271
-
272
- npm run serve # http://127.0.0.1:8321/website/docs.html (no build)
273
- npm test # node --test tests/unit/*.test.js + node tests/lint-tokens.js
274
- npm run build # dist/: ESM, global, ZeyOS binding, and CSS assets
275
- node tools/build-module-tokens.js # regenerate styles/tokens/modules.css from src/zeyos/modules.js
276
- ```
277
-
278
265
  ---
279
266
 
280
267
  # Components
@@ -291,6 +278,9 @@ accept.
291
278
 
292
279
  - **`button(options)`** → `HTMLButtonElement`. Options: `label`, `icon` (an icon name), `kind:
293
280
  'default'|'primary'|'danger'|'ghost'`, `size: 'md'|'sm'`, `disabled`, `title`, `onclick`.
281
+ - **Shortcut hints** — `shortcut: {label:'N', keys:'N'}` adds a visible key hint, hover text and
282
+ `aria-keyshortcuts`. The host binds the action and owns editing/modality/permission guards;
283
+ a hint never installs a global handler. Dialog and Sheet footer descriptors accept it too.
294
284
  - **`buttonGroup([button(…), …])`** → a container that joins the buttons into one control.
295
285
  <!-- /doc -->
296
286
 
@@ -541,6 +531,106 @@ announced twice.
541
531
  status, not the account's accessible name; supply `statusLabel` when it conveys information.
542
532
  <!-- /doc -->
543
533
 
534
+ <!-- doc:entity-ref -->
535
+ ### EntityRef
536
+
537
+ Dense record identity for table cells, feeds, selectors, and detail metadata. It owns presentation
538
+ and safe native interaction semantics; the application injects routes, permissions, context menus,
539
+ and record mutations.
540
+
541
+ - **Options** — `id`, `title`, `subtitle` (text, Node, or Component), `icon` (name, Node,
542
+ Component, or lazy renderer), `metadata: [{label,value,icon?,showLabel?}]`, `link` (a URL or
543
+ `{href,target?,rel?,download?,onclick?}`), `actions`, `size: 'sm'|'md'|'lg'`, `wrap: false`, and
544
+ `actionsLabel`.
545
+ - **Actions** — an action is a caller-owned Element or
546
+ `{id,label?,icon?,title?,href?,target?,rel?,kind?,disabled?,onselect?}`. Descriptors with `href`
547
+ remain native anchors; others are buttons. Executable destinations are discarded, `_blank`
548
+ gains `noopener`, and an icon-only action requires `title`.
549
+ - **Methods** — `set(values)`, `setMetadata()`, `setActions()`, `setLink()`, `getEntity()`,
550
+ `focus()`, and `destroy()`.
551
+ - **Events** — cancelable `activate {id,entity,href,event}` before a primary-link callback/native
552
+ navigation and `action {id,action,entity,event}` before an action callback/navigation. The
553
+ bubbling `zx-*` mirrors may cancel the same boundary.
554
+ - **Accessibility** — metadata is a definition list; `showLabel:false` clips its label visually
555
+ while keeping it available to assistive technology. Identity links and secondary controls keep
556
+ native keyboard and modifier-click behavior.
557
+ <!-- /doc -->
558
+
559
+ <!-- doc:file-item -->
560
+ ### FileItem
561
+
562
+ A durable or transient file row composed from `EntityRef`, MIME/byte-size metadata, lifecycle
563
+ status, and accessible progress. It never starts a transfer, decides authorization, resolves a
564
+ preview, or persists a file.
565
+
566
+ - **Options** — `id`, `name`, `size` (bytes), `mime`, `subtitle`, `icon: 'file'`, additional
567
+ `metadata`, safe native `link`, `actions`, status (`ready` | `temporary` | `waiting` |
568
+ `uploading` | `processing` | `success` | `error`), `statusLabel`, `progress` (0–100), `indeterminate`,
569
+ `density: 'sm'|'md'|'lg'`, `wrap`, `actionsLabel`, and `locale`.
570
+ - **Methods** — `set(values)`, `setStatus(status,label?)`,
571
+ `setProgress(percent|null,{indeterminate?})`, `getFile()`, `focus()`, and `destroy()`.
572
+ - **Events** — cancelable `activate {id,file,href,event}` and
573
+ `action {id,fileId,action,file,event}`. Cancellation propagates to the composed EntityRef, so it
574
+ suppresses callbacks and navigation rather than merely observing them.
575
+ - **Progress** — determinate work exposes min/max/now and percentage text. Indeterminate work
576
+ omits `aria-valuenow`; status changes are announced separately.
577
+ <!-- /doc -->
578
+
579
+ <!-- doc:file-list -->
580
+ ### FileList
581
+
582
+ An accessible ordered collection of `FileItem` rows with loading and empty presentations.
583
+ Explicit duplicate file IDs are rejected; source order is preserved.
584
+
585
+ - **Options** — `items`, `label: 'Files'`, `loading`, `loadingCount: 3`,
586
+ `loadingText: 'Loading files'`, and `emptyText: 'No files'` (text, Node, or Component).
587
+ - **Methods** — `setItems(items,{silent?})`, `getItems()`, `getItem(id)`,
588
+ `addItem(item,index?,{silent?})`, `updateItem(id,values,{silent?})`,
589
+ `removeItem(id,{silent?})`, `setLoading()`, and `destroy()`.
590
+ - **Events** — cancelable `activate {id,index,file,href,event}` and
591
+ `action {id,fileId,index,action,file,event}`, plus `datachange {items}` after a collection
592
+ mutation. Returned items are defensive snapshots.
593
+ <!-- /doc -->
594
+
595
+ <!-- doc:activity-item -->
596
+ ### ActivityItem
597
+
598
+ One chronological activity entry. It owns actor/avatar anatomy, semantic time, safe content slots,
599
+ attachments, and actions; the application owns posting, reactions, permissions, routing,
600
+ persistence, and sanitization before any rich content becomes a Node.
601
+
602
+ - **Options** — `id`, `actor`, `avatar` (Avatar options or Element), `title`, `content`,
603
+ `timestamp`, `timeLabel`, `metadata`, `attachments`, `actions`, `kind`, and
604
+ `headingLevel: 1..6`. Content slots accept text, Nodes, or Components and never parse HTML.
605
+ - **Actions** — Elements pass through; descriptors accept
606
+ `{id,label?,icon?,href?,target?,rel?,title?,disabled?,kind?,onselect?}`. Unsafe links and unnamed
607
+ icon-only controls are omitted.
608
+ - **Methods** — `setActivity(values)`, `getActivity()`, and `destroy()`.
609
+ - **Events** — cancelable `action {id,action,event}` before a callback or native navigation; its
610
+ bubbling `zx-action` mirror can cancel the same boundary.
611
+ - **Accessibility** — an entry is a native list item containing an article and semantic heading;
612
+ valid timestamps use `<time datetime>`, while display-only labels remain ordinary text.
613
+ <!-- /doc -->
614
+
615
+ <!-- doc:activity-list -->
616
+ ### ActivityList
617
+
618
+ An accessible chronological ordered collection with stable grouping, loading/empty states, and
619
+ incremental host-controlled mutation. It deliberately preserves source order instead of guessing
620
+ whether a feed is newest- or oldest-first.
621
+
622
+ - **Options** — `items`, `groupBy` (property, resolver, or null), `groupLabel`,
623
+ `label: 'Activity'`, `loading`, `loadingCount: 3`, `loadingText`, `emptyText`,
624
+ `groupHeadingLevel`, and `itemHeadingLevel`.
625
+ - **Methods** — `setItems(items,{silent?})`, `getItems()`, `getItem(id)`,
626
+ `appendItems(items,{silent?})`, `prependItems(items,{silent?})`,
627
+ `updateItem(id,values,{silent?})`, `removeItem(id,{silent?})`, `setLoading()`, and `destroy()`.
628
+ - **Events** — `datachange {items}` after mutation. Each child's cancelable `zx-action` bubbles
629
+ naturally through the list for delegated application handling.
630
+ - **Grouping** — groups keep first-seen group order and item source order. The exported pure
631
+ `groupActivityItems()` and `normalizeActivityItems()` helpers do not mutate caller arrays.
632
+ <!-- /doc -->
633
+
544
634
  <!-- doc:account-menu -->
545
635
  ### AccountMenu
546
636
 
@@ -567,6 +657,7 @@ Unifies single-select, local filtering, and async loading.
567
657
  - **Options** — `items: []`, `fixedItems: []`, optional `fixedLabel`, `valueKey: 'ID'` (string key or `(item)=>id`),
568
658
  `labelKey: 'name'` (string or `(item)=>string`), `renderItem`, `renderValue`,
569
659
  `renderValueAdornment`, `renderNone`, `noneLabel`, `actions`, `value`, `disabled`, `placeholder`,
660
+ `label` (accessible combobox name; defaults to the placeholder or "Select"),
570
661
  `clearable: false`, `filter: false | 'local' | async (query)=>items`, `searchKeys`,
571
662
  `minQuery: 0`, `debounce: 200`, `listHeight: 280`, `groupKey`.
572
663
  - **Getters** — `.value`, `.selected`.
@@ -597,6 +688,25 @@ Unifies single-select, local filtering, and async loading.
597
688
  (readonly). `aria-activedescendant` tracks the active option.
598
689
  <!-- /doc -->
599
690
 
691
+ <!-- doc:sort-control -->
692
+ ### SortControl
693
+
694
+ A searchable field selector with an adjacent icon button to reverse the direction. Each field
695
+ appears once. Changing fields preserves direction; toggling direction preserves the field. Built
696
+ from `Select`, with its themed popover and keyboard behavior.
697
+
698
+ - **Options** — `fields: [{id,label}]`, `value: {id,dir:'asc'|'desc'}` (null selects the first field
699
+ ascending), `label: 'Sort by'`, `labels: {asc,desc}` for localized direction text, `disabled`.
700
+ - **Methods** — defensive `getValue()`, `setValue(value,{silent})`, `enable()`, `disable()`,
701
+ `focus()`, `destroy()`. Unknown fields or directions are rejected. An empty catalogue disables
702
+ selection and returns null.
703
+ - **Keyboard** — Tab reaches the direction button and field selector; Space/Enter toggle the
704
+ focused direction button. The field retains Select’s combobox keyboard map. The button’s
705
+ accessible name includes the current direction; its hover title shows current → next direction.
706
+ - **Events** — one `change {value:{id,dir}}` event per changed field or direction. Typed search text does
707
+ not change the sort. The application applies the resulting state to its table, data source or route.
708
+ <!-- /doc -->
709
+
600
710
  <!-- doc:checklist -->
601
711
  ### Checklist
602
712
 
@@ -820,7 +930,7 @@ panel material; the backdrop uses `--zx-color-overlay-backdrop`, and focus retur
820
930
  Structured modal: a header with title and close button, a body, and footer buttons.
821
931
 
822
932
  - **Options** — `title`, `size: 'sm'|'md'|'lg'|number`,
823
- `buttons: [{ label, kind, action: 'close'|'cancel'|fn(dialog), autofocus }]`, `closable: true`.
933
+ `buttons: [{ label, kind, action: 'close'|'cancel'|fn(dialog), autofocus, shortcut }]`, `closable: true`.
824
934
  - **Methods** — `setTitle()`, `setContent()`, `setButtons()`,
825
935
  `addView(key, { content, buttons? })`, `showView(key)`.
826
936
  - **Statics returning Promises** — `Dialog.alert({ title, message })`,
@@ -948,8 +1058,16 @@ DOM child of the anchor's nearest Zx theme scope while the browser lifts it into
948
1058
 
949
1059
  A button that opens a `role="menu"`.
950
1060
 
951
- - **Options** — `label`, `icon`, `kind`,
952
- `items: [{ label, icon?, value?, disabled?, danger?, onselect? } | '-']`, `placement`.
1061
+ - **Options** — `label`, `icon`, `kind`, `placement`, and a shared `items` entry model:
1062
+ - `'-'` or `{type: 'separator'}` draws a separator; `{type: 'heading', label}` draws a visible,
1063
+ non-interactive heading.
1064
+ - Actions keep `label`, `icon`, `value`, `disabled`, `danger`, and `onselect`, and may add
1065
+ `description`, `badge`, `shortcut`, or a text/Node `adornment`.
1066
+ - `href`, `target`, and `rel` render a genuine safe native link, preserving modifier clicks and
1067
+ targets. Executable URL schemes are rejected; `_blank` receives `noopener noreferrer` by
1068
+ default.
1069
+ - `role: 'menuitemcheckbox'|'menuitemradio'` with `checked` exposes an APG checked action. The
1070
+ application owns state changes and calls `setItems()` with the new model.
953
1071
  - **Methods** — `setItems()`, `open()`, `close()`, `setLabel()`, `getTrigger()`, `getPanel()`,
954
1072
  `focusFirst()`, `focusLast()`.
955
1073
  - **Events** — `select {value, item}`, `open`, `close`.
@@ -969,8 +1087,9 @@ parked at the pointer, so it flips near a viewport edge like every other floatin
969
1087
  - **Constructor** — `new ContextMenu(target, options)` where `target` is an element or selector.
970
1088
  Unlike most components the target is not enhanced or replaced; `destroy()` removes only the
971
1089
  anchor the menu created.
972
- - **Options** — `items: []` — the same `{label, icon, value, disabled, danger, onselect}` shape
973
- MenuButton takes, with `'-'` for a separator, **or a function** `(context) => items` called on
1090
+ - **Options** — `items: []` uses the same headings, separators, links, descriptions, trailing
1091
+ metadata, checked roles, and ordinary action shape MenuButton takes, **or a function**
1092
+ `(context) => items` called on
974
1093
  every opening so a row menu can disable the actions that row does not allow; returning an empty
975
1094
  array cancels the opening and leaves the platform menu alone. `selector: null` restricts the
976
1095
  menu to matching descendants and reports the matched element as the context — a table passes
@@ -985,6 +1104,8 @@ parked at the pointer, so it flips near a viewport edge like every other floatin
985
1104
  half most pointer-only context menus miss. Arrows move between items, typing jumps to one by its
986
1105
  first letters, Enter and Space activate, Escape and Tab close — and closing returns focus to
987
1106
  wherever it came from.
1107
+ - **Cancellation** — `select` is cancelable just like MenuButton. Preventing it suppresses the
1108
+ item callback and native navigation and leaves the context menu open.
988
1109
  <!-- /doc -->
989
1110
 
990
1111
  <!-- doc:tooltip -->
@@ -1016,6 +1137,15 @@ Two panes with a divider the user owns. The layout is a three-track CSS grid dri
1016
1137
  <!-- doc:table -->
1017
1138
  ### Table
1018
1139
 
1140
+ **Group and section rows.** `rowKind` names the field (or a callback) that classifies a row, and
1141
+ `rowKinds` maps a kind to `{span, render, class}`. A `span: true` row renders one
1142
+ `<th scope="colgroup">` across every rendered cell — including the selection and reorder columns —
1143
+ and carries no others, which is what a heading row in a billing document actually is. Both
1144
+ default to null, so a table that sets neither renders exactly as before. While any spanning row is
1145
+ present the header sort controls are withheld and `setSort()` is a no-op: sorting a grouped table
1146
+ scatters its positions out of their sections, and silently doing so is worse than not offering it.
1147
+ The stacked presentation renders the heading alone rather than a row of labelled blanks.
1148
+
1019
1149
  Sortable, selectable, sticky-header data table. `fr` widths fill the container while px/auto
1020
1150
  widths scroll horizontally, and multi-select adds a tri-state header checkbox plus Shift+click
1021
1151
  range select.
@@ -1118,6 +1248,12 @@ range select.
1118
1248
  <!-- doc:table-view -->
1119
1249
  ### TableView and the shared RecordView contract
1120
1250
 
1251
+ **`fieldControls` takes an object.** `true` and `false` behave as they always have; a
1252
+ `{label, target}` object names the chooser's trigger and mounts the disclosure into a host
1253
+ element — a list toolbar, say — instead of the view's own. `label` omitted resolves
1254
+ `recordView.fields`. This is what lets a translated application use the chooser at all: the
1255
+ trigger used to be the literal `Fields`, with no way to change it or move it.
1256
+
1121
1257
  `TableView` is the record-oriented entry point above the lower-level `Table`. It extends
1122
1258
  `RecordView` and composes one complete `Table`, so editing, hierarchy, growing, row movement,
1123
1259
  responsive stacking, loading, and advanced table events remain available through `getTable()`.
@@ -1150,15 +1286,27 @@ portable state as TableView and KanbanView.
1150
1286
  - **Options** — the shared RecordView options plus `titleField`, `subtitleField`, `preview`,
1151
1287
  `previewAlt`, `link`, `actions`, `groupBy`, `groupOrder`, `minCardWidth`, `maxColumns`,
1152
1288
  `variant: 'outlined'|'raised'|'filled'`, `loadingCount`, `headingLevel`, and `label`.
1289
+ - **Selection trigger** — `selectionTrigger:'checkbox'` preserves existing selection behavior.
1290
+ With `'card'`, selectable backgrounds toggle on click, Enter or Space, Shift+click selects a range,
1291
+ and the checkbox is omitted. Links, actions and text selection keep their native behavior. Selection
1292
+ remains announced through the card's ARIA description. This option also works in KanbanView.
1153
1293
  - **Cards** — each record is a focusable `<li>` with a native title link, separate secondary
1154
- actions, optional native multi-select checkbox, labelled metadata, and `aria-selected` state.
1155
- Title/subtitle fields are not duplicated in metadata unless their field sets `duplicate:true`.
1294
+ actions, optional native multi-select checkbox, labelled metadata, and a global ARIA selection
1295
+ description that retains valid listitem semantics.
1296
+ CardView uses a dense collection rhythm: titles clamp to two lines, previews stay at
1297
+ thumbnail/avatar scale, and visible fields become compact labelled metadata chips. Title/subtitle
1298
+ fields are not duplicated in metadata unless their field sets `duplicate:true`.
1299
+ - **Shared card slots** — a visible field may set
1300
+ `view.card.slot: 'eyebrow-start'|'eyebrow-end'|'title-prefix'`. These slots create a semantic
1301
+ eyebrow row or put labelled content immediately before (and outside) the title heading/link.
1302
+ Unknown slots remain ordinary metadata; visibility and field order still control rendering.
1156
1303
  - **Media and URLs** — `preview` accepts a field ID or callback returning an image URL,
1157
1304
  `{src,alt,fit}`, Node, or null. Executable/non-image schemes are rejected and image failures show
1158
1305
  a stable fallback. Title/action links are normalized; `_blank` links receive `noopener`.
1159
1306
  - **Grouping and layout** — `groupBy` is a field ID or callback; `groupOrder` may deliberately show
1160
1307
  empty groups. Cards reflow through container queries and may cap columns without viewport logic.
1161
- - **Interaction** — Enter activates a focused card; Space toggles selection. Links, actions,
1308
+ - **Interaction** — By default Enter activates a focused card; Space toggles selection. With
1309
+ `selectionTrigger:'card'`, Enter also toggles selection. Links, actions,
1162
1310
  selection controls, and selected text do not also activate the card. `recordaction` adds the
1163
1311
  resolved action to the shared event set.
1164
1312
  <!-- /doc -->
@@ -1174,16 +1322,29 @@ cards, advisory work-in-progress limits, and equivalent pointer/programmatic/key
1174
1322
  `columnOrder`, `swimlaneOrder`, collapsed IDs, `showCounts`, `showEmptyColumns`, `variant`, and
1175
1323
  `label`. Column/lane descriptors use stable `id`, `label`, optional stored `value`, and `accept`;
1176
1324
  columns may also declare an advisory `limit`.
1325
+ - **Selection trigger** — `selectionTrigger:'card'` provides the same checkbox-free click and
1326
+ keyboard selection as CardView. The default remains `'checkbox'`.
1177
1327
  - **Methods** — configure/get/move columns and swim lanes, collapse either axis, and
1178
1328
  `moveRecord(id,{column?,lane?,index?})`. Board-specific order/collapse joins the common view
1179
- state; record order, movement history, and selection do not.
1329
+ state; record order, movement history, and selection do not. Saved preferences for data-derived
1330
+ axes survive an empty/partial result set and reconcile as later records introduce their IDs.
1331
+ - **Dense board layout** — bounded muted columns use a stable 20rem rail with native horizontal
1332
+ overflow, 48px headings, compact counts, 8–12px card padding, and 8px card gaps. Surface cards
1333
+ use an optional square thumbnail and a two-tier hierarchy from shared card field slots:
1334
+ `eyebrow-start`, `eyebrow-end`, and `title-prefix`. Unslotted metadata stays as quiet inline
1335
+ facts. Titles clamp visually to two lines while retaining their complete accessible text. Move
1336
+ and action controls reveal on hover/focus/selection/grab, and remain visible on touch devices.
1180
1337
  - **Movement boundary** — `recordmove {record,id,from,to,column,swimlane,limitExceeded}` is
1181
- cancelable and fires before a commit/request. `accept` is a hard eligibility gate; WIP is visual
1182
- advice. Local mode clones the moved record and never mutates host data. External mode emits only,
1183
- for server validation and optimistic rollback owned by ZeyOS.
1338
+ cancelable and fires before a commit/request; either the component event or bubbling
1339
+ `zx-recordmove` mirror may veto it. `accept` is a hard eligibility gate; WIP is visual advice.
1340
+ Local mode clones the moved record and never mutates host data, and a manual local move clears an
1341
+ active local sort so saved state matches visible order. External mode emits only, for server
1342
+ validation and optimistic rollback owned by ZeyOS.
1184
1343
  - **Keyboard** — focus the move handle; Enter/Space grabs or drops, Escape cancels, Left/Right
1185
1344
  chooses a column, Up/Down chooses a bucket-relative position, and Alt+Up/Down chooses a swim
1186
- lane. A polite live region announces every target and result. Native drag is an enhancement.
1345
+ lane. A polite live region announces every target, result, and reached/exceeded WIP limit.
1346
+ Collapse keeps focus on its control, including when a programmatic collapse hides the focused
1347
+ card. Native drag is an enhancement.
1187
1348
  <!-- /doc -->
1188
1349
 
1189
1350
  <!-- doc:grid -->
@@ -1256,7 +1417,9 @@ windowed loader.
1256
1417
  HTML, and suspicious CSS colour strings are ignored.
1257
1418
  - **Methods** — `getEvents()`, `setEvents()`, `addEvent()`, `updateEvent()`, `removeEvent()`,
1258
1419
  `getDate()`, `setDate()`, `getView()`, `setView()`, `prev()`, `next()`, `today()`,
1259
- `setLoading()`, `focusEvent()`, `destroy()`.
1420
+ `setLoading()`, `focusEvent()`, `destroy()`. `prev()`/`next()` step one visible period and clamp
1421
+ the day of month into the target month, so a 29th–31st anchor cannot skip a shorter month; the
1422
+ same arithmetic is exported as `calendarPageDate()` and `addCalendarMonths()`.
1260
1423
  - **Events** — `dateschange {view,start,end}`, `viewchange {view,oldView}`, `eventclick`,
1261
1424
  `eventdblclick`, `dateclick {date,allDay,view}`, `select {start,end,allDay,view}`,
1262
1425
  `new {date,view}`, `moreclick {date,count}`, `eventschange {events}`, and cancelable
@@ -1295,6 +1458,46 @@ Declarative client-side filter bar producing a filtered array, commonly wired to
1295
1458
  - **Events** — `filter {rows, state}`.
1296
1459
  <!-- /doc -->
1297
1460
 
1461
+ <!-- doc:filter-panel -->
1462
+ ### FilterPanel — typed filters from server metadata
1463
+
1464
+ The third filter component, and the one a data-driven application reaches for. `DataFilter`
1465
+ filters a client-side row set; `Filter` builds a backend-neutral AST with groups and operators.
1466
+ `FilterPanel` takes the `{key: {type, label, options, min, max}}` map a list endpoint already
1467
+ publishes and gives back a query object — so the shape the server describes is the shape the
1468
+ form renders, with no per-application translation layer in between.
1469
+
1470
+ - **Options** — `fields: Record<string, {type, label?, options?, min?, max?, step?, search?}>`,
1471
+ `order` (display order; omitted uses object order), `value` (the applied filters, drafted
1472
+ from), `mode: 'draft'|'live'`, `serialize: 'seconds'|'ms'|'iso'|(date, edge) => unknown`,
1473
+ `emptyText`, `msg`.
1474
+ - **Types** — `text`, `select`, `date`, `date:range`, `int`, `float`, `number`, and
1475
+ `int:range` / `float:range` / `number:range`. An unrecognised type renders a visible,
1476
+ labelled placeholder naming it and is excluded from the value — never dropped silently.
1477
+ - **Methods** — `getValue()`, `setValue()`, `apply()`, `reset()`, `clear()`.
1478
+ - **Events** — `apply {value}`, `change {value, field}`.
1479
+
1480
+ Five behaviours are deliberate rather than incidental:
1481
+
1482
+ - **A select is multi-valued.** "Open or waiting" is the common request, and single choice turns
1483
+ it into two visits. It composes `Checklist`, which brings its own search past eight options,
1484
+ and the group is named after the filter rather than after the component.
1485
+ - **Each end of a range carries its own accessible name.** One `<label for>` cannot name two
1486
+ inputs, and a group label that names neither is worse than no group label.
1487
+ - **`clear()` commits; `reset()` does not.** Clear is "no filters" and applies immediately —
1488
+ emptying the controls while the list stays filtered is a panel that lies about what is on
1489
+ screen. Reset restores the constructed value without committing, which is a host sheet's
1490
+ Cancel.
1491
+ - **An empty `fields` map is normal.** An instance that configures no filters for a settings
1492
+ section is the ordinary case; the panel renders `emptyText`, never an error.
1493
+ - **`0` is a value.** `''`, `null`, `[]` and `{from: null, to: null}` are not, and only active
1494
+ constraints reach the emitted value.
1495
+
1496
+ `serialize` decides how a date leaves the component, because the answer is a wire-format
1497
+ decision rather than an application one. A range's upper bound takes the **end** of its day, or
1498
+ a one-day range matches nothing.
1499
+ <!-- /doc -->
1500
+
1298
1501
  <!-- doc:filter -->
1299
1502
  ### Filter — dynamic backend-neutral expressions
1300
1503
 
@@ -1310,7 +1513,17 @@ adapter to compile into its own backend query language.
1310
1513
  priority/country/currency/unit/entity, and tags. Compatible operators and their arity come from
1311
1514
  the exported `filterOperators` matrix; applications may explicitly override/add operator IDs.
1312
1515
  - **Options** — `fields`, `value`, `operators`, `allowGroups: true`, `maxDepth: 3`,
1313
- `maxConditions: 50`, `autoApply: false`, `readonly`, `disabled`, `applyLabel`, `clearLabel`.
1516
+ `maxConditions: 50`, `autoApply: false`, `readonly`, `disabled`, `applyLabel`, `clearLabel`,
1517
+ `searchable: false`, `layout: 'standard'|'compact'`, `rootLogic: null|'and'|'or'`,
1518
+ `showApply: true`, `showRootActions: true`.
1519
+ - **Searchable conditions** — opt in to local-search `Select` controls for fields, operators and
1520
+ static single-choice/boolean values. Uncommitted search text never becomes a condition value.
1521
+ Multi-choice, async and custom editors retain their existing contracts. Compact rows keep field,
1522
+ operator, value and removal together, wrapping the value below on narrow containers.
1523
+ - **Embedding** — hide internal Apply and duplicate root Add controls when the parent drawer owns
1524
+ submission. `rootLogic` fixes the authored root logic; incompatible saved expressions remain
1525
+ visible and invalid until corrected, never silently rewritten. Removing the last condition
1526
+ returns keyboard focus to Add filter.
1314
1527
  - **Methods** — `getValue()`, atomic `setValue()`, `addCondition()`, `addGroup()`, `update()`,
1315
1528
  `remove()`, `move()`, `validate()`, `apply()`, `clear()`, `focus()`, `setReadonly()`,
1316
1529
  `enable()`/`disable()`.
@@ -1414,6 +1627,26 @@ Beyond the built-in field types, these widget types wrap whole components, used
1414
1627
  `toggle` (Toggle).
1415
1628
  <!-- /doc -->
1416
1629
 
1630
+ <!-- doc:code-editor -->
1631
+ ### CodeEditor — structured text without an editor dependency
1632
+
1633
+ A textarea that behaves like a source editor, and deliberately not more than that: native undo,
1634
+ native IME, and no syntax engine. It never executes or injects the value, so it is the safe
1635
+ surface for structured text — templates, queries, configuration — while rich HTML authoring
1636
+ stays a separate policy decision.
1637
+
1638
+ - **Options** — `value`, `name`, `language` (shown to the reader and exposed as data),
1639
+ `label`, `placeholder`, `rows` (clamped 2–100), `indent` (inserted by Tab, removed by
1640
+ Shift+Tab), `wrap: 'off'|'soft'|'hard'`, `spellcheck`, `readOnly`, `disabled`,
1641
+ `status` (the line/column readout).
1642
+ - **Methods** — `setValue()`.
1643
+ - **Events** — `input {value}`, `change {value}`.
1644
+
1645
+ Tab indents rather than moving focus, which is what a code surface has to do and what makes it a
1646
+ keyboard trap if nothing else is arranged — Escape then Tab leaves the field. A `code` Form field
1647
+ adapter is registered by `registerFieldAdapters()`.
1648
+ <!-- /doc -->
1649
+
1417
1650
  <!-- doc:questionnaire -->
1418
1651
  ### Questionnaire
1419
1652
 
@@ -1585,6 +1818,34 @@ so buttons and links in its action, content, and footer regions remain valid sib
1585
1818
  container query when the card itself becomes narrow.
1586
1819
  <!-- /doc -->
1587
1820
 
1821
+ <!-- doc:stat-tile -->
1822
+ ### StatTile — `statTile(options)` / `StatTile`
1823
+
1824
+ A labelled number with optional delta, trend and icon: the most-copied snippet in any
1825
+ application UI, and the reason competing template products advertise a card count rather than a
1826
+ component count. `statTile()` is the convenience form of `new StatTile(null, options)` and
1827
+ returns the component, the way `tooltip()` does; call `.toElement()` for the node to place.
1828
+
1829
+ - **Options** — `label`, `value`, `format: 'number'|'currency'|'percent'|'fileSize'|null|fn`,
1830
+ `currency`, `locale`, `delta`, `deltaKind: 'positive'|'negative'|'neutral'`, `deltaFormat`,
1831
+ `deltaLabel`, `trend: number[]`, `icon`, `kind`, `href`, `clickable`, `loading`, `msg`.
1832
+ - **Methods** — `update(options)`, `getAccessibleName()`.
1833
+ - **Events** — `click {event}`.
1834
+
1835
+ - **A delta is never colour alone.** It carries its sign and a direction glyph, and `deltaKind`
1836
+ decides the colour rather than the sign — rising ticket counts are not a success, and a
1837
+ component that assumes "up is good" is wrong for half the metrics in any business.
1838
+ - **The accessible name is label + value + spoken delta** ("up 2 vs. last week"). The visible
1839
+ `+2` row and the sparkline are `aria-hidden`, because a sparkline nobody can read is
1840
+ decoration and saying the delta twice is worse than saying it once.
1841
+ - **The element follows the behaviour** — `href` renders an `<a>`, `onclick` without `href` a
1842
+ `<button>`, neither a `<div>` with `role="group"`. Never a div with a click handler.
1843
+ - **`loading: true` renders a skeleton shaped like the tile**, not a spinner.
1844
+
1845
+ Nothing in it assumes a fixed set of buckets or a fixed label: the content of a dashboard tile
1846
+ is the instance's, not the library's.
1847
+ <!-- /doc -->
1848
+
1588
1849
  <!-- doc:aurora -->
1589
1850
  ### Aurora
1590
1851
 
@@ -1795,6 +2056,37 @@ first and last items.
1795
2056
  `aria-current="page"` and is deliberately not interactive; separators are `aria-hidden`.
1796
2057
  <!-- /doc -->
1797
2058
 
2059
+ <!-- doc:list-toolbar -->
2060
+ ### ListToolbar — the bar above a record view
2061
+
2062
+ Every list carries the same four questions — what am I searching for, which records, which
2063
+ columns, in what shape. The parts have always existed (`Search`, `SortControl`, `badge()`,
2064
+ `button()`); this is the composition, so that every consumer stops assembling it differently and
2065
+ forgetting the same thing.
2066
+
2067
+ - **Options** — `search: {placeholder?, value?, debounce?, clearable?}|false`, `count`,
2068
+ `countText`, `views: Array<string|{id, label?, icon?}>` (string presets `auto|cards|table|list`),
2069
+ `view`, `tools: [{id, label?, icon?, badge?, badgeKind?, pressed?, disabled?, onclick?}]`,
2070
+ `label`, `msg`.
2071
+ - **Methods** — `setCount()`, `setBadge()`, `setPressed()`, `setToolDisabled()`, `setTools()`,
2072
+ `getTool()`, `getToolsElement()`, `addTool()`, `setView()`, `getView()`, `getSearch()`,
2073
+ `setSearch()`, `focusSearch()`, `bind()`, `unbind()`.
2074
+ - **Events** — `search {value}`, `viewchange {view, previous}`, `action {id, pressed, tool}`.
2075
+
2076
+ Three properties are the reason to use this rather than assemble your own:
2077
+
2078
+ - **A tool's badge is part of its accessible name**, not a second thing beside it — a tool
2079
+ showing `2` announces as "Filters (2)". Once filters live behind a panel, a list can show four
2080
+ rows out of twenty with nothing on screen saying why, and the badge is what prevents that.
2081
+ - **The count line is a live region**, and `setCount(null)` clears it. The previous number
2082
+ describes the previous filters; a stale count during a load is worse than none.
2083
+ - **Tool buttons meet the 44 px target** in both densities.
2084
+
2085
+ `bind(view)` is optional sugar for a `TableView` or `CardView`: it feature-detects rather than
2086
+ importing them, adopts the view's shape, and mounts a field chooser built with
2087
+ `fieldControls: {target}` into the toolbar. The toolbar is fully functional without it.
2088
+ <!-- /doc -->
2089
+
1798
2090
  <!-- doc:pagination -->
1799
2091
  ### Pagination
1800
2092
 
@@ -1824,9 +2116,16 @@ treated as one empty page rather than zero pages.
1824
2116
  Application navigation bar: brand, items, and right-aligned actions. Items overflow into a "More"
1825
2117
  menu on narrow widths.
1826
2118
 
1827
- - **Options** — `title`, `items: [{ name, title, badge? }]`, `active`, `actions: []`.
2119
+ - **Options** — `title`, `items: [{ name, title, badge? }]`, `active`, `actions: []`,
2120
+ `overflow: true`, `overflowBelow: '44rem'`, `minVisible: 0`.
1828
2121
  - **Methods** — `setTitle()`, `setItems()`, `setActive()`, `setBadge()`, `setActions()`.
1829
2122
  - **Events** — `change {name}`.
2123
+
2124
+ **Overflow is a default, not a law.** Collapsing every item behind "More" is right for a top app
2125
+ bar and wrong for a phone bottom bar, where the navigation is the point. `overflow: false` keeps
2126
+ every item at every width; `overflowBelow` moves the threshold; `minVisible: n` pins the first `n`
2127
+ items and overflows the rest. At the default the collapse is a container query with no observer
2128
+ installed; any other threshold installs a `ResizeObserver`, which is the cost of asking for one.
1830
2129
  <!-- /doc -->
1831
2130
 
1832
2131
  <!-- doc:app-sidebar -->
@@ -1920,8 +2219,14 @@ built-in names are translated to their Font Awesome counterparts (`x` → `fa-xm
1920
2219
  `fa-magnifying-glass`, `warning` → `fa-triangle-exclamation`, …), so component code never changes.
1921
2220
  Prefixes override: `'fa:user'`, `'fas:user'`/`'regular:user'`/`'duotone:user'`/`'thin:user'`,
1922
2221
  `'kit:zeyos-notes'` (custom kit icons), `'builtin:check'` (force the inline SVG). A literal class
1923
- list — `'fa-sharp fa-solid fa-user'` — is used verbatim. Unknown *built-in* names throw
1924
- `RangeError`; unknown names under Font Awesome are passed through to the kit.
2222
+ list — `'fa-sharp fa-solid fa-user'` — is used verbatim. Unknown names under Font Awesome are
2223
+ passed through to the kit, which resolves them in the browser.
2224
+
2225
+ **An unknown *built-in* name does not throw.** Icon names routinely arrive from a server, and one
2226
+ unconfigured name must not take down the screen it appears on, so it renders an empty `<svg>` of
2227
+ the requested size — layout does not shift — carrying `data-zx-icon-missing="<name>"`, and reports
2228
+ itself once per distinct name through `console.warn`. Pass `icon(name, { strict: true })` for the
2229
+ old `RangeError`, at a call site that can afford to fail: a test, or a build-time check.
1925
2230
 
1926
2231
  Font Awesome elements are sized with `font-size` and occupy 1em; bundled SVGs use width/height
1927
2232
  attributes. Both honour `label` (`null` ⇒ `aria-hidden`, otherwise `role="img"` + `aria-label`).
package/docs/llms.txt CHANGED
@@ -16,9 +16,7 @@ exports and as `window.zx.*`.
16
16
  - [Documentation site](https://zx.zeyos.com/docs.html): getting started, every component with a live demo and its JavaScript source, and the application layouts. Machine index: [llms.txt](https://zx.zeyos.com/llms.txt).
17
17
  - [README](../README.md): what Zx is, quick start (ESM + global script), component index, theming, and browser support.
18
18
  - [API reference](llms.md): per-component constructor options, methods, and events for all public components plus the core helpers.
19
- - [Skill](https://zx.zeyos.com/skills/zx/SKILL.md): task-oriented guide — mental model, recipes, ZeyOS HTTP client, theming, gotchas, commands.
20
19
  - [Changelog](../CHANGELOG.md): what changed in each release, including behaviour changes an upgrade has to account for.
21
- - [Contributor contract](https://github.com/zeyos/zx/blob/main/AGENTS.md): conventions for editing component source (token rules, render-time state, listeners, ARIA/APG).
22
20
 
23
21
  ## Components
24
22
  - Inputs: `button()`, `buttonGroup()`, `badge()`/`badgeGroup()`, `CheckButton`,
@@ -28,16 +26,22 @@ exports and as `window.zx.*`.
28
26
  `copyButton()`/`CopyInput`, `DatePicker`, `MonthPicker`, `TimePicker`,
29
27
  `Datebox`/`DateTimeBox`, `DateRangePicker`/`DateRangeBox`, `Timebox`.
30
28
  - Overlays: `Message` (toasts/inline/progress), `Modal`, `Dialog` (+ `alert`/`confirm`/`prompt` Promises), `Sheet` (edge-anchored Dialog; `side`, `modal: true|'trap-focus'|false`, `backdrop`, `snap` detents, swipe-to-dismiss), `SheetStack` (drill-down; `stack`/`cascade`), `Dropdown`, `MenuButton`, `ContextMenu` (right-click; `selector` for per-row menus), `Tooltip`/`tooltip()`/`describe()`.
31
- - Data: `Table` (sortable, selectable, sticky header, opt-in inline cell/row editing, row reorder,
29
+ - Data: `EntityRef` (dense linked/static identity), `FileItem`/`FileList` (durable and transient
30
+ file presentation), `ActivityItem`/`ActivityList` (chronological entries and grouped feeds),
31
+ `Table` (sortable, selectable, sticky header, opt-in inline cell/row editing, row reorder,
32
32
  column visibility), shared `RecordView` state through `TableView`, `CardView`, and `KanbanView`,
33
33
  `Grid` with single-click editing and `Grid.BillingItems()`, engine-neutral
34
34
  `Chart` with injected `ChartJsAdapter`, `Calendar` (agenda/day/week/month/year, pointer/keyboard
35
35
  drag and resize, `optimistic: true|false`), backend-neutral nested `Filter`, simple client-side
36
- `DataFilter`, `Pagination` (+ pure `paginationRange()`), `TreeView` (APG tree),
37
- `Finder` (Miller columns).
38
- - Forms: `Form`, `Fieldset`, `Questionnaire` (guided one-question-at-a-time flow with branching), `Field` (type registry), `ValueList`, `MultiValueEditor`, `FieldUpload`.
36
+ `DataFilter`, `FilterPanel` (typed filter form built from a server's own field metadata;
37
+ `mode: 'draft'|'live'`, `serialize`), `ListToolbar` (search, live result count, view switch, and
38
+ tools whose badge is part of the accessible name), `Pagination` (+ pure `paginationRange()`),
39
+ `SortControl` (searchable field selector with a direction toggle, one atomic `{id,dir}`),
40
+ `TreeView` (APG tree), `Finder` (Miller columns).
41
+ - Forms: `Form`, `Fieldset`, `Questionnaire` (guided one-question-at-a-time flow with branching), `Field` (type registry), `CodeEditor` (structured text in a native textarea; never executes or injects the value), `ValueList`, `MultiValueEditor`, `FieldUpload`.
39
42
  - Layout: `stack()`/`grid()`/`aspect()` (spacing, an intrinsically reflowing grid, a fixed-ratio
40
- box), `Groupbox`, `Card` (media/title link/actions/footer), `AppIcon` (generic tile geometry;
43
+ box), `Groupbox`, `Card` (media/title link/actions/footer), `StatTile`/`statTile()` (labelled
44
+ metric with optional delta, sparkline, and loading state), `AppIcon` (generic tile geometry;
41
45
  circular `zeyosAppIcon()` application presets and compact `moduleChip()` identities),
42
46
  `Aurora` (one- to four-colour ambient
43
47
  canvas light; shared material roles govern chrome and overlays), `Avatar`, `Panel` (header/footer action
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeyos/zx",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "Dependency-free JavaScript implementation of the Xenon Design System.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -65,7 +65,6 @@
65
65
  "docs/api.json",
66
66
  "CHANGELOG.md",
67
67
  "README.md",
68
- "DESIGN-SYSTEM.md",
69
68
  "LICENSE"
70
69
  ],
71
70
  "engines": {