@zeyos/zx 4.4.0 → 5.2.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 (252) hide show
  1. package/CHANGELOG.md +447 -0
  2. package/README.md +44 -11
  3. package/dist/types/components/account-menu/account-menu.d.ts +8 -0
  4. package/dist/types/components/activity-list/activity-list.d.ts +31 -1
  5. package/dist/types/components/app-icon/app-icon.d.ts +14 -2
  6. package/dist/types/components/app-sidebar/app-sidebar.d.ts +293 -17
  7. package/dist/types/components/avatar/avatar.d.ts +46 -7
  8. package/dist/types/components/badge/badge.d.ts +21 -1
  9. package/dist/types/components/button/button.d.ts +15 -0
  10. package/dist/types/components/calendar/calendar.d.ts +67 -5
  11. package/dist/types/components/card-view/card-view.d.ts +7 -4
  12. package/dist/types/components/card-view/record-card.d.ts +11 -0
  13. package/dist/types/components/chart/chart.d.ts +10 -0
  14. package/dist/types/components/checklist/checklist.d.ts +9 -0
  15. package/dist/types/components/code-editor/code-editor.d.ts +6 -17
  16. package/dist/types/components/context-menu/context-menu.d.ts +6 -2
  17. package/dist/types/components/data-filter/data-filter.d.ts +4 -4
  18. package/dist/types/components/datebox/date-range-box.d.ts +5 -1
  19. package/dist/types/components/datebox/datebox.d.ts +7 -2
  20. package/dist/types/components/dialog/dialog.d.ts +46 -6
  21. package/dist/types/components/dropdown/dropdown.d.ts +24 -9
  22. package/dist/types/components/entity-ref/entity-ref.d.ts +2 -2
  23. package/dist/types/components/field/field.d.ts +54 -2
  24. package/dist/types/components/fieldset/external-adapter.d.ts +83 -0
  25. package/dist/types/components/fieldset/fieldset.d.ts +26 -1
  26. package/dist/types/components/file-item/file-item.d.ts +34 -6
  27. package/dist/types/components/file-list/file-list.d.ts +35 -3
  28. package/dist/types/components/filter/filter.d.ts +127 -3
  29. package/dist/types/components/filter-panel/filter-panel.d.ts +36 -7
  30. package/dist/types/components/form/form.d.ts +12 -1
  31. package/dist/types/components/kanban-view/kanban-card.d.ts +8 -0
  32. package/dist/types/components/launcher/launcher.d.ts +268 -15
  33. package/dist/types/components/list-toolbar/list-toolbar.d.ts +16 -7
  34. package/dist/types/components/menu-button/menu-button.d.ts +39 -5
  35. package/dist/types/components/message/message.d.ts +132 -17
  36. package/dist/types/components/modal/modal.d.ts +43 -2
  37. package/dist/types/components/module-bar/module-bar.d.ts +395 -0
  38. package/dist/types/components/pagination/pagination.d.ts +17 -3
  39. package/dist/types/components/select/color.d.ts +12 -0
  40. package/dist/types/components/select/glyphs.d.ts +124 -0
  41. package/dist/types/components/select/select.d.ts +17 -3
  42. package/dist/types/components/sheet/sheet.d.ts +15 -0
  43. package/dist/types/components/stat-tile/stat-tile.d.ts +16 -5
  44. package/dist/types/components/tabbox/tabbox.d.ts +9 -0
  45. package/dist/types/components/table/table.d.ts +311 -18
  46. package/dist/types/components/tag-picker/tag-picker.d.ts +21 -4
  47. package/dist/types/components/tree/tree.d.ts +13 -0
  48. package/dist/types/components/view/record-view.d.ts +59 -2
  49. package/dist/types/components/view-settings/view-settings.d.ts +879 -0
  50. package/dist/types/components/workspace-switcher/workspace-switcher.d.ts +327 -0
  51. package/dist/types/core/breakpoint.d.ts +1 -1
  52. package/dist/types/core/component.d.ts +12 -2
  53. package/dist/types/core/i18n.d.ts +27 -3
  54. package/dist/types/core/icons.d.ts +23 -25
  55. package/dist/types/core/keyboard.d.ts +98 -1
  56. package/dist/types/core/messages.d.ts +382 -0
  57. package/dist/types/core/motion.d.ts +59 -0
  58. package/dist/types/core/overlay-host.d.ts +42 -1
  59. package/dist/types/core/overlay-stack.d.ts +260 -0
  60. package/dist/types/index.d.ts +10 -5
  61. package/dist/types/internal/app-rail.d.ts +38 -0
  62. package/dist/types/internal/menu-items.d.ts +71 -3
  63. package/dist/types/zeyos/connect.d.ts +6 -0
  64. package/dist/types/zeyos/form.d.ts +50 -9
  65. package/dist/types/zeyos/index.d.ts +2 -1
  66. package/dist/types/zeyos/launcher.d.ts +9 -0
  67. package/dist/types/zeyos/module-bar.d.ts +176 -0
  68. package/dist/types/zeyos/query.d.ts +110 -5
  69. package/dist/types/zeyos/schema.d.ts +24 -1
  70. package/dist/types/zeyos/table.d.ts +345 -22
  71. package/dist/types/zeyos/view.d.ts +26 -2
  72. package/dist/zx-zeyos.esm.js +6178 -1008
  73. package/dist/zx-zeyos.esm.min.js +53 -5
  74. package/dist/zx.css +2861 -827
  75. package/dist/zx.esm.js +8909 -1480
  76. package/dist/zx.esm.min.js +55 -7
  77. package/dist/zx.global.js +8911 -1482
  78. package/dist/zx.global.min.js +55 -7
  79. package/dist/zx.min.css +1 -1
  80. package/docs/api.json +1079 -117
  81. package/docs/llms.md +956 -154
  82. package/docs/llms.txt +9 -5
  83. package/package.json +1 -1
  84. package/src/components/account-menu/account-menu.css +35 -10
  85. package/src/components/account-menu/account-menu.js +12 -0
  86. package/src/components/activity-item/activity-item.css +1 -1
  87. package/src/components/activity-item/activity-item.js +3 -0
  88. package/src/components/activity-list/activity-list.css +38 -3
  89. package/src/components/activity-list/activity-list.js +61 -1
  90. package/src/components/app-icon/app-icon.css +14 -3
  91. package/src/components/app-icon/app-icon.js +11 -1
  92. package/src/components/app-rail/app-rail.css +59 -79
  93. package/src/components/app-sidebar/app-sidebar.css +304 -168
  94. package/src/components/app-sidebar/app-sidebar.js +667 -46
  95. package/src/components/aurora/aurora.css +5 -3
  96. package/src/components/avatar/avatar.css +32 -7
  97. package/src/components/avatar/avatar.js +72 -8
  98. package/src/components/badge/badge.css +54 -2
  99. package/src/components/badge/badge.js +29 -2
  100. package/src/components/breadcrumb/breadcrumb.css +1 -1
  101. package/src/components/button/button.css +67 -9
  102. package/src/components/button/button.js +38 -0
  103. package/src/components/calendar/calendar.css +47 -47
  104. package/src/components/calendar/calendar.js +26 -52
  105. package/src/components/card/card.css +4 -4
  106. package/src/components/card-view/card-view.css +14 -12
  107. package/src/components/card-view/card-view.js +13 -9
  108. package/src/components/card-view/record-card.js +14 -3
  109. package/src/components/chart/chart.css +4 -1
  110. package/src/components/chart/chart.js +12 -0
  111. package/src/components/check-button/check-button.css +10 -2
  112. package/src/components/checklist/checklist.css +9 -2
  113. package/src/components/checklist/checklist.js +11 -5
  114. package/src/components/checklist/field-adapter.js +3 -1
  115. package/src/components/code-editor/code-editor.css +7 -6
  116. package/src/components/code-editor/code-editor.js +19 -1
  117. package/src/components/code-editor/field-adapter.js +9 -2
  118. package/src/components/context-menu/context-menu.css +9 -4
  119. package/src/components/context-menu/context-menu.js +8 -2
  120. package/src/components/copy/copy-button.css +6 -0
  121. package/src/components/copy/copy-input.css +9 -4
  122. package/src/components/data-filter/data-filter.css +5 -4
  123. package/src/components/data-filter/data-filter.js +2 -2
  124. package/src/components/date-picker/date-picker.css +6 -6
  125. package/src/components/date-picker/date-range-picker.css +3 -3
  126. package/src/components/date-picker/time-picker.css +3 -3
  127. package/src/components/datebox/date-range-box.css +79 -2
  128. package/src/components/datebox/date-range-box.js +13 -2
  129. package/src/components/datebox/datebox.css +79 -2
  130. package/src/components/datebox/datebox.js +13 -2
  131. package/src/components/dialog/dialog.css +26 -0
  132. package/src/components/dialog/dialog.js +99 -17
  133. package/src/components/dock/dock.css +5 -4
  134. package/src/components/dropdown/dropdown.css +1 -1
  135. package/src/components/dropdown/dropdown.js +159 -72
  136. package/src/components/empty-state/empty-state.css +2 -2
  137. package/src/components/entity-ref/entity-ref.css +1 -1
  138. package/src/components/entity-ref/entity-ref.js +1 -1
  139. package/src/components/field/field.css +28 -9
  140. package/src/components/field/field.js +101 -29
  141. package/src/components/field-upload/field-upload.css +1 -1
  142. package/src/components/fieldset/external-adapter.js +363 -0
  143. package/src/components/fieldset/fieldset.css +5 -3
  144. package/src/components/fieldset/fieldset.js +38 -64
  145. package/src/components/file-item/file-item.js +144 -10
  146. package/src/components/file-list/file-list.js +144 -21
  147. package/src/components/filter/filter.css +86 -2
  148. package/src/components/filter/filter.js +307 -11
  149. package/src/components/filter-panel/filter-panel.css +1 -1
  150. package/src/components/filter-panel/filter-panel.js +149 -32
  151. package/src/components/finder/finder.css +16 -14
  152. package/src/components/form/form.css +5 -4
  153. package/src/components/form/form.js +11 -2
  154. package/src/components/grid/grid.css +1 -1
  155. package/src/components/groupbox/groupbox.css +1 -1
  156. package/src/components/kanban-view/kanban-card.js +11 -3
  157. package/src/components/kanban-view/kanban-view.css +42 -18
  158. package/src/components/kanban-view/kanban-view.js +9 -6
  159. package/src/components/launcher/launcher.css +108 -26
  160. package/src/components/launcher/launcher.js +530 -42
  161. package/src/components/list-toolbar/list-toolbar.css +13 -8
  162. package/src/components/list-toolbar/list-toolbar.js +40 -14
  163. package/src/components/master-panel/master-panel.css +2 -0
  164. package/src/components/master-panel/master-panel.js +0 -1
  165. package/src/components/menu-button/menu-button.css +72 -4
  166. package/src/components/menu-button/menu-button.js +160 -18
  167. package/src/components/message/message.css +33 -3
  168. package/src/components/message/message.js +264 -22
  169. package/src/components/modal/modal.css +1 -1
  170. package/src/components/modal/modal.js +83 -15
  171. package/src/components/module-bar/module-bar.css +486 -0
  172. package/src/components/module-bar/module-bar.js +1074 -0
  173. package/src/components/multi-value-editor/multi-value-editor.css +1 -1
  174. package/src/components/navigation-bar/navigation-bar.css +18 -9
  175. package/src/components/number-field/field-adapter.js +3 -1
  176. package/src/components/number-field/number-field.css +70 -0
  177. package/src/components/number-field/number-field.js +2 -0
  178. package/src/components/pagination/pagination.css +13 -11
  179. package/src/components/pagination/pagination.js +20 -4
  180. package/src/components/panel/panel.css +4 -3
  181. package/src/components/questionnaire/questionnaire.css +4 -4
  182. package/src/components/rating/field-adapter.js +2 -1
  183. package/src/components/rating/rating.css +8 -1
  184. package/src/components/search/search.css +4 -1
  185. package/src/components/select/color.js +22 -0
  186. package/src/components/select/field-adapter.js +2 -0
  187. package/src/components/select/glyphs.js +165 -0
  188. package/src/components/select/select.css +138 -45
  189. package/src/components/select/select.js +92 -47
  190. package/src/components/sheet/sheet.css +12 -9
  191. package/src/components/sheet/sheet.js +74 -32
  192. package/src/components/slider/field-adapter.js +6 -1
  193. package/src/components/slider/slider.css +18 -4
  194. package/src/components/slider/slider.js +1 -1
  195. package/src/components/sort-control/sort-control.css +4 -1
  196. package/src/components/split-view/split-view.css +1 -1
  197. package/src/components/stat-tile/stat-tile.css +42 -47
  198. package/src/components/stat-tile/stat-tile.js +17 -6
  199. package/src/components/stepper/stepper.css +1 -1
  200. package/src/components/tabbox/tabbox.css +41 -32
  201. package/src/components/tabbox/tabbox.js +5 -1
  202. package/src/components/table/table.css +187 -37
  203. package/src/components/table/table.js +718 -73
  204. package/src/components/tag-picker/field-adapter.js +2 -1
  205. package/src/components/tag-picker/tag-picker.css +83 -5
  206. package/src/components/tag-picker/tag-picker.js +25 -8
  207. package/src/components/timebox/timebox.css +22 -2
  208. package/src/components/toggle/toggle.css +12 -1
  209. package/src/components/toolbar/toolbar.js +2 -2
  210. package/src/components/tooltip/tooltip.css +4 -0
  211. package/src/components/tooltip/tooltip.js +44 -19
  212. package/src/components/tree/tree.css +26 -17
  213. package/src/components/tree/tree.js +31 -0
  214. package/src/components/value-list/value-list.css +3 -3
  215. package/src/components/view/record-view.css +1 -1
  216. package/src/components/view/record-view.js +178 -18
  217. package/src/components/view-settings/view-settings.css +285 -0
  218. package/src/components/view-settings/view-settings.js +1830 -0
  219. package/src/components/workspace-switcher/workspace-switcher.css +188 -0
  220. package/src/components/workspace-switcher/workspace-switcher.js +463 -0
  221. package/src/core/breakpoint.js +1 -1
  222. package/src/core/component.js +88 -17
  223. package/src/core/fontawesome.js +5 -1
  224. package/src/core/i18n.js +47 -4
  225. package/src/core/icons.js +204 -61
  226. package/src/core/keyboard.js +206 -11
  227. package/src/core/messages.js +427 -0
  228. package/src/core/motion.js +147 -0
  229. package/src/core/overlay-host.js +77 -3
  230. package/src/core/overlay-stack.js +487 -0
  231. package/src/core/position.js +22 -3
  232. package/src/index.js +10 -5
  233. package/src/internal/app-rail.js +135 -55
  234. package/src/internal/menu-items.js +61 -3
  235. package/src/zeyos/connect.js +6 -2
  236. package/src/zeyos/form.js +69 -27
  237. package/src/zeyos/index.js +4 -1
  238. package/src/zeyos/launcher.js +8 -3
  239. package/src/zeyos/module-bar.js +181 -0
  240. package/src/zeyos/query.js +197 -13
  241. package/src/zeyos/schema.js +144 -27
  242. package/src/zeyos/table.js +287 -84
  243. package/src/zeyos/view.js +49 -93
  244. package/styles/base.css +72 -1
  245. package/styles/icons.css +11 -1
  246. package/styles/print.css +1 -1
  247. package/styles/tokens/dark.css +117 -37
  248. package/styles/tokens/global.css +121 -27
  249. package/styles/tokens/semantic.css +140 -43
  250. package/styles/tokens/themes.css +7 -6
  251. package/styles/zx.css +3 -1
  252. package/styles/tokens/density.css +0 -9
package/CHANGELOG.md CHANGED
@@ -8,6 +8,453 @@ and friends remain the complete record.
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## 5.2.0 — 2026-10-29
12
+
13
+ A record collection pattern with a five-way view switch and filter chips, two components to go
14
+ with it, and the sixteen defects a library-wide consistency audit found, fixed.
15
+
16
+ ### Added
17
+
18
+ - **`WorkspaceSwitcher`** — the account or workspace switcher at the head of a module menu: the
19
+ open workspace's tile, name and secondary line with a chevron, opening a menu of the user's
20
+ workspaces as `menuitemradio` rows followed by workspace actions; `compact` shows the tile
21
+ alone. `select` is cancelable, `setActive()`, `setWorkspaces()`, `setCompact()`. The layout
22
+ kit's `suiteNav()` takes a `workspace` option that puts it in place of the brand.
23
+ - **`ViewSettings`** — the content of a "View settings" drawer: search the hidden fields and add
24
+ one with an explicit button, see every field's type glyph, arrange the shown fields by pointer
25
+ or keyboard (announced, auto-scrolling), hide them, choose the grouping, and set a board's
26
+ columns, swim lanes and empty-column rule. `bind(view)` keeps it in step with a record view; a
27
+ `locked` field is offered neither to hide nor to move; the panel's own `fields` act as the
28
+ allow-list when bound.
29
+ - `ListToolbar` view presets `table | list | cards | gallery | board`, with bundled glyphs
30
+ `table`, `image`, `columns`, and `type`, `hash`, `mail`, `link-2`, `circle-chevron-down` for
31
+ field types.
32
+ - `Filter`: fields take an `icon` shown in the searchable picker; choice icons are drawn; a
33
+ many-valued operator on fixed choices uses a `TagPicker`; compact rows show their group's
34
+ and/or as a pill that switches the logic; `withinLast` / `withinNext` take an amount and a unit.
35
+ - A default English message catalogue in core (`defaultMessages`): `msg(key)` resolves the
36
+ instance table, the host translator, the class defaults, then the catalogue, so no raw key
37
+ reaches the screen without a translator. A test keeps it complete against every key in `src/`.
38
+ - `src/core/overlay-stack.js` — one registry of open overlays with the z-order, Escape routing
39
+ to the topmost layer, and the outside-press test along the opener chain; `Modal`, `Sheet`,
40
+ `Dropdown`, `MenuButton`, `ContextMenu`, `Tooltip`, `Message`, `Launcher` and the rail flyouts
41
+ use it.
42
+ - `Table`: the APG grid and treegrid keyboard model — arrows, Home/End, Page keys, Enter to
43
+ activate, Space and Shift+Arrow to select, Ctrl/Cmd+A — on tables that are `selectable`,
44
+ editable, hierarchical, listen for `rowclick`, or set `interactive: true`; focus kept by row id
45
+ across data changes; `label` / `labelledBy` for the grid's name; row controls named by the row's
46
+ first text cell; 24px targets on checkboxes and sort buttons.
47
+ - `RecordView.getFieldControls()` and `mountFieldControls(target)`; `KanbanView` honours
48
+ `fieldControls.target`; `ListToolbar.bind()` mounts the chooser through them.
49
+ - `MenuButton.toggle()`; `Select.get()`; `Field` `readonly` and `setReadonly()`;
50
+ `FilterPanel` `timeZone`; `dataFilterStateToFilters(state, defs, { timeZone })`; the ZeyOS
51
+ bindings' `load({ replace, pageSize })` and `pageSize` getter; `rovingTabindex` `rtl: 'auto'`;
52
+ `--zx-surface-shadow`.
53
+ - `Pagination` and `Search`: the summary and page size sit at the start of the bar, the pager at
54
+ the end; the search input fills a stretched field so the submit glyph stays on its trailing
55
+ edge.
56
+
57
+ ### Changed
58
+
59
+ - Geometry tokens (control sizes, blur, filters) are declared on `:root` only; the theme blocks
60
+ carry colours. A nested light region no longer resets an application's `--zx-control-height`.
61
+ - Every `outline: 0` in the stylesheets became `outline-color: transparent`, and `base.css` draws a
62
+ solid `Highlight` outline on `:focus-visible` under forced colors.
63
+ - The token lint covers `icons.css`, flags tier-1 accent, module and shadow names in component and
64
+ layout CSS, modern colour functions, raw colours in `var()` fallbacks, and outline suppression.
65
+ - A host translator now takes precedence over a class's own `defaults.msg`, which makes `Field`,
66
+ `Form` and `Questionnaire` translatable; a translator that returns the key counts as no answer.
67
+ - `Calendar` message keys are namespaced (`calendar.next`, `calendar.today`, …); the bare keys are
68
+ still honoured for one version.
69
+ - Light dismiss stops at the first overlay that contains the press: a press in the upper of two
70
+ light-dismiss sheets no longer closes the lower one. Anchored popups and toast regions are hosted
71
+ inside the open dialog their anchor sits in.
72
+ - The ZeyOS `zeyosTable` / `zeyosView` bindings share one loader; an invalid page or page size
73
+ throws a `RangeError` and non-object filters a `TypeError` where they used to clamp, and a
74
+ rejected call changes nothing. `Pagination`'s documentation shows the real mapping
75
+ (`offset = (page - 1) * pageSize`, `load({ page: page - 1, replace: true })`).
76
+ - `Field`'s `code` type reports `change` on commit and `input` on every keystroke.
77
+ - `Fieldset.addField()` writes with the caller's options; a component's own `change` listeners
78
+ hear a non-silent `setValues()`.
79
+
80
+ ### Fixed
81
+
82
+ - Menus, dropdowns, context menus, rail flyouts and toasts were inert while a modal `Dialog` or
83
+ `Sheet` was open; a non-modal `Sheet` closed itself when an item was chosen in a menu inside it,
84
+ and Escape closed the sheet while leaving its dropdown open; an Escape another control handled is
85
+ ignored; a `Dropdown` panel is reachable with Tab, and Tab out of a panel holding a `Select` or a
86
+ roving toolbar lands after the trigger.
87
+ - `AccountMenu.toggle()` threw.
88
+ - `Table`, `CardView` and `DataFilter` showed raw message keys without a translator.
89
+ - `Table` rows were not focusable, so `rowclick` and single selection were mouse-only; re-rendering
90
+ a table scrolled the page back to it.
91
+ - `Fieldset.addField()` could not read, write or disable `get()/set()` components.
92
+ - `Field` emitted `change` twice for `slider` and `code`.
93
+ - Focus dropped to `<body>` after moving a field in the record-view chooser and after every
94
+ `FileList.updateItem()`; `ActivityList` had the same fault. The move is announced and Escape
95
+ closes the chooser.
96
+ - `rovingTabindex` took ArrowLeft/Right/Home/End from text fields inside a `Toolbar`, and missed a
97
+ disabled `<fieldset>` around its items.
98
+ - `FilterPanel` and the ZeyOS query conversion used the browser's local midnight for dates; both
99
+ take the instance time zone.
100
+ - `--zx-shadow-1`, a tier-1 token, was used by three components; `MasterPanel` wrote a module
101
+ accent property nothing read.
102
+ - The layout icon pack no longer shadows bundled glyphs.
103
+
104
+ ### Website
105
+
106
+ - **Record collection**, a new screen pattern: one toolbar over the same records as a table, a
107
+ list, cards, a gallery and a board; dynamic filters as editable chips with all/any matching and
108
+ a Filters drawer holding the expression editor, kept in step both ways; a View settings drawer
109
+ bound to the current presentation, with the board's axes resolved so columns and swim lanes
110
+ never share a field; grouping, saved views, a stage facet, bulk actions, a workspace switcher at
111
+ the head of the module strip, and the pager. Keys: 1–5 views, F and V for the drawers, / for
112
+ search, N for a new record, ? for the sheet.
113
+ - The contributor notes gain a library consistency review, repository-only, with the defects above
114
+ and a staged programme for the remaining redundancies and inconsistencies.
115
+
116
+ ## 5.1.0 — 2026-10-22
117
+
118
+ ### Added
119
+
120
+ - **`ModuleBar`** — the module level of an application: one colour-coded tile per module in a
121
+ vertical strip or a horizontal bar. Modules take a theme `tone` or any CSS `color`, and draw as
122
+ `tint` (default), `solid` (the classic identity tile), or `plain`; `labels: 'below'` prints names
123
+ under the tiles, `labels: 'beside'` beside them as a navigation column of its own, and
124
+ `setLabels()` switches between the two; a section of modules is a heading over them, or a rule
125
+ between groups on an icon strip. A module's children open as a flyout menu, or (`menus: 'none'`) are left to a
126
+ panel the application owns, with `setExpanded()`, `aria-expanded`, and `aria-controls`. Modules
127
+ that do not fit, or are not `pinned`, are under an "All modules" catalogue — grouped, filterable,
128
+ arrow-navigable — while the current module stays on the bar. One Tab stop, arrow keys, Home/End,
129
+ and type-ahead; `setBadge()` updates a count in place; `partitionModules()` and
130
+ `resolveModuleColor()` are exported.
131
+ - **`AppSidebar` sections** — `{ section: true, label, actions, children }` is a quiet heading over
132
+ rows at its own level, so one sidebar replaces several stacked ones: one landmark, one keyboard
133
+ sequence, and on a rail a separator.
134
+ - **`AppSidebar` `layout: 'modules'`** — the top level becomes a `ModuleBar` strip beside a panel
135
+ with one module's menu, plus that module's own `header` and `content`. Choosing a module fires a
136
+ cancelable `modulechange`; `setModule()`, `getModule()`, `setBadge()`, `setModuleLabels()`, and
137
+ `moduleBar` presentation options. Three presentations — both menus expanded, the module menu
138
+ collapsed to icons beside the side menu, or both collapsed with every menu as a flyout — and a
139
+ small three-way switch at the foot of the strip to choose between them (`presentations`,
140
+ `presentation`, `getPresentation()`, `setPresentation()`, `togglePresentation()`,
141
+ `presentationchange`).
142
+ - **ZeyOS module bar** — `zeyosModuleItems()`, `buildZeyosModuleBarConfig()`,
143
+ `buildZeyosAppSidebarConfig()`, and `zeyosModuleBar()` build both from the launcher's shell
144
+ state plus each module's menu and badges, in the ZeyOS identity colours.
145
+ - `AccountMenu.setCompact()` switches between the avatar alone and the avatar with name and role.
146
+ - **Menu choices** — a `{type: 'choice', label, value, options, onselect}` entry in `MenuButton`
147
+ and `AccountMenu` items: a setting chosen in place as a small segmented group of
148
+ `menuitemradio` options, the menu staying open. `AppSidebar`'s `presentationChoice()` returns
149
+ its layout switch as one, `presentationGlyph()` draws its pictograms, and
150
+ `presentationSwitch: false` takes the switch off the strip.
151
+ - `--zx-color-tone-{blue,…,slate}-solid`, solid identity fills the white icon glyph reads on in
152
+ both themes, and `AppIcon`'s `tone` option that uses them.
153
+ - A `grid` (`table-cells-large`) icon in the bundled set.
154
+
155
+ ### Fixed
156
+
157
+ - `position()` adds its name to the anchor's `anchor-name` list and removes only its own, so a
158
+ tooltip and a menu on one trigger no longer overwrite each other — a keyboard-opened rail flyout
159
+ appeared at the page origin.
160
+ - `AppRail`: a tile's tooltip stays quiet while its flyout is open, so the first Escape closes the
161
+ flyout, and on a vertical rail ArrowLeft leaves a top-level flyout for its tile.
162
+
163
+ ### Website
164
+
165
+ - Every layout with a navigation column now shares one suite navigation: the Zx mark, the ACME
166
+ modules under their headings, the signed-in user, and the layout's own menu. The account menu
167
+ opens above the account and holds the layout — both menus expanded, the module menu collapsed,
168
+ or both collapsed — and the theme — light, dark, or system — each a three-way choice; Mod+B
169
+ steps through the layouts, and the choice is remembered. Below 1440px the module menu keeps
170
+ its labels off, between 860 and 1180px both menus start collapsed, and below that the navigation
171
+ is a drawer; choosing another module's screen opens that layout, and each layout's menu ends with
172
+ a "More in <module>" section leading to its sibling layouts.
173
+ - The fictional company the layouts share is now called ACME.
174
+
175
+ ## 5.0.0 — 2026-10-09
176
+
177
+ Xenon now has one geometry and a quieter finish. The cozy and compact view modes are gone; in their
178
+ place is a single, slightly tighter default whose spacing, corners, and control height are tokens a
179
+ product sets once. On top of it the visual language was refined against how well-made business
180
+ applications look today: "where you are" is a neutral fill rather than a block of accent colour,
181
+ status colours no longer borrow the brand green, chrome and canvas separate by tone instead of by
182
+ lines, labels are sentence case at medium weights, and icons are outlines.
183
+
184
+ The other half is what building twenty complete screens on the library asked of it. A layout
185
+ gallery of application templates and screen patterns — mail, an issue tracker, a knowledge base, AI
186
+ chat, an agent workspace, invoicing, inventory, workflows, infrastructure, CRM, and the screens
187
+ inside them — every one usable from a phone to a wide screen and clean under an accessibility
188
+ audit. Fixing what those screens found: some forty component defects, status colours that read as
189
+ text, nested dark themes, and focus that never falls to the page. And what they needed: motion as
190
+ a reader's setting, a command palette with pages, toasts that carry their action, busy buttons,
191
+ type-to-confirm, and public status and priority glyphs.
192
+
193
+ ### Breaking
194
+
195
+ - **Form field keys are no longer element ids.** Control ids are generated per Form and Fieldset
196
+ instance (`<idPrefix>-<key>`; `idPrefix` makes them predictable), so a form mounted twice repeats
197
+ no id and a key such as `stage` never collides with `#stage` elsewhere. The key stays the field's
198
+ `name`, the native control's `name`, and its `data-field-id`; radio groups are named after the
199
+ control id. Code that looked a control up by `#<key>` reads `form.getField(key).controlId` (or
200
+ queries `[data-field-id="<key>"]`) instead. An explicit `id` that differs from the key is used as
201
+ given, and the legacy compatibility layer keeps key ids.
202
+ - **Density modes are removed.** `data-zx-density` (`cozy` | `compact`) no longer has any effect,
203
+ `styles/tokens/density.css` no longer ships, and no component carries density-specific rules.
204
+ Migration: drop the attribute. To tighten an application — or one region of it — set
205
+ `--zx-space-unit` and `--zx-control-height` instead, for example
206
+ `:root { --zx-space-unit: 3.5px; --zx-control-height: 28px; }`, which is close to what compact
207
+ used to do without shrinking the type.
208
+ - **`FileItem`'s `density` option is now `identitySize`** (`'sm'|'md'|'lg'`, the size of the
209
+ file's icon and name), and `FileList` items take the same name. The word now means one thing
210
+ nowhere in the library.
211
+
212
+ ### Changed
213
+
214
+ - Every toast pauses while it holds focus as well as hover, resumes when neither applies, and
215
+ returns focus to where it came from if it closes while focused.
216
+ - Sheet slides on `--zx-ease-drawer`; KanbanView's drag preview and grabbed card take
217
+ `--zx-drag-shadow`. A solid primary button's pressed step is darker than its hover step.
218
+ - Launcher `select` and `error` details carry `page`; closing the launcher returns it to its root.
219
+ The status and priority glyph styles are `.zx-status-icon` and `.zx-priority-icon` (Select's
220
+ glyphs keep their old classes as well).
221
+ - **`Select.priority()` reads by height, not hue**: levels are four grey signal bars filled to the
222
+ level in muted ink, and only the highest is coloured — a danger square with "!". It offers "No
223
+ priority" (value null, message `priority.none`) at the head of the list; `clearable: false`
224
+ restores the old list, a required priority field leaves it out, and the legacy compatibility
225
+ select keeps its old list unless it allows empty values. Values and message keys are unchanged.
226
+ - **Quiet NumberField** start-aligns its value with the quiet values around it; both steppers sit
227
+ at the trailing end, shown on hover or focus.
228
+ - **Field `type: 'html'`** draws no input frame; display content keeps a control's height.
229
+ - **Toggle labels** start-align and wrap like text, the track level with the first line; a field
230
+ beside a taller one keeps its label and control at the top of its cell.
231
+ - **FileItem** shows a readable type ("PDF", "Image") instead of the MIME type and picks its icon
232
+ from the MIME type when the icon set has one.
233
+ - **AppSidebar** creates its own root as a `<div>` (the `<nav>` inside is the landmark), so it no
234
+ longer adds an unnamed complementary landmark; `getItems()` leaves out empty `children`.
235
+ - **Table** puts `data-column` on every header and body cell in every mode; **KanbanView**
236
+ assignee faces take Avatar's tint from the name (or a descriptor `tone`); the neutral soft
237
+ **Badge** is a wash of the text colour, visible on raised dark surfaces, and a small dotted
238
+ Badge has 12px text and a 4px gap.
239
+ - **ZeyOS enums read as labels** ("Invoiced", "Partly paid") in generated tables and forms; a
240
+ schema `{value, label}` is used as given. **ZeyOS date-only fields are calendar days** — indexed
241
+ `date`, `duedate`, `birthdate`, `datefrom`/`dateto` outside appointments and events, `datecancel`,
242
+ and `lastbilling` show no time and are stored as midnight in the instance's zone (`timeZone`,
243
+ default the browser's); `lastmodified` and the appointment, event, comment, record, and
244
+ document-version timestamps are date-times.
245
+ - **Spacing derives from one unit.** `--zx-space-1` … `--zx-space-8` are multiples of the new
246
+ `--zx-space-unit` (4px by default, so the steps are unchanged at 4–40px).
247
+ - **Corners are smaller and proportional.** `--zx-radius` is now `4px`, and `-sm`, `-md`, `-lg`,
248
+ and `-xl` are ×0.5, ×0.75, ×1, and ×1.5 of it — 2 / 3 / 4 / 6px, down from 3 / 5 / 7 / 11px — so a
249
+ theme that scales the base keeps every step in proportion. `--zx-control-radius` still follows
250
+ `-lg`. Panels that used `-xl` (Launcher, Sheet, the AppSidebar and AppRail items) use `-lg` or
251
+ `-md`; ValueList chips and record-card metadata chips are no longer pills, and the SortControl
252
+ direction button is a control rather than a circle.
253
+ - **Controls are 30px tall** (`--zx-control-height`, from 32px). `--zx-control-pad-x` stays 10px
254
+ and text sizes are unchanged.
255
+ - **Structured menus are tighter.** AppSidebar rows are one control tall (from control + 8px) with
256
+ 2px between rows, 12px between groups, and a 3px corner. A text-only child starts under its
257
+ parent's label; a child with its own icon steps in 16px, just clear of the guide line, instead
258
+ of a whole icon column. The rail flyouts follow. TreeView indents 12px per level (from
259
+ 18px) with a 4px block padding per row. MenuButton, ContextMenu, Select, TagPicker, Launcher,
260
+ Finder, Checklist, and the Table column menu share one row: 4px × 8px padding, the smallest
261
+ radius, panels at `--zx-radius-lg`, and section labels no taller than an item.
262
+ - **"Current" is neutral, and nothing is docked to an edge.** Where you are — the active
263
+ navigation item (AppSidebar, its rails and flyouts), the open TreeView node, the current Finder
264
+ column entry, the active tab in every Tabbox variant, the pressed ListToolbar view, the current
265
+ Calendar view, Launcher app and Pagination page — is a neutral `--zx-color-bg-current` fill with
266
+ the text colour at weight 600; the edge marker beside the active item is gone. What you have
267
+ *picked* (checked rows, chosen options, a multi-selection) keeps the accent tint. A rail item
268
+ whose flyout holds the active route takes the accent colour. Forced colours still use the
269
+ system's selected pair.
270
+ - **One solid accent per screen.** Solid accent is for the primary button; tab underlines, pressed
271
+ toggles, and decorative icons no longer use it. In dark, the primary button sits on the accent
272
+ 600 step with white text (`--zx-color-accent-solid` / `--zx-color-on-accent-solid`) instead of
273
+ the bright 400 step.
274
+ - **Status green is its own colour.** `--zx-green-*` is a yellow-green status ramp that no longer
275
+ matches the default ZeyOS accent, so a "success" badge or chart segment never reads as branding.
276
+ The brand values moved to `--zx-emerald-*`, which the default accent points at.
277
+ - **Dark theme is layered.** Page, chrome, surface, raised, and overlay steps sit off near-black
278
+ (#1b1b1e → #313136), primary text is about 90% white, and borders are translucent white.
279
+ - **Quieter type.** Decorative upper-case and letter-spaced labels are gone from every component
280
+ (menu and Select groups, Launcher groups, StatTile labels, Calendar weekdays, Table headers, …);
281
+ row and label weights moved from 600 to 500, titles to 600–650, and UI text is set with
282
+ `--zx-tracking-tight` and Inter's `cv11`. Field labels and Fieldset legends are small, medium, and
283
+ muted, so values lead.
284
+ - **Tables** drop the header band (muted medium labels on the surface), divide rows with
285
+ `--zx-color-border-subtle`, and set numbers in tabular figures.
286
+ - **Avatars** fall back to a colour picked from the name (one of eight tones) with no ring, at
287
+ 24 / 32 / 40px, and show one initial below 24px.
288
+ - **StatTile** labels are sentence case, values 24px tabular, the icon is a muted glyph without a
289
+ coloured chip, and tiles in a row line up whether or not they carry a sparkline.
290
+ - **EmptyState** draws its icon in `--zx-color-text-subtle` and its title semibold.
291
+ - **Danger is legible as text.** Light `--zx-color-danger` moves to the 600 step and the dark
292
+ danger tint is lighter, so danger ink keeps 4.5:1 on every surface and on its own tint, as the
293
+ other status colours do (now tested for all four in both themes and every preset).
294
+ - **The dark selected tint is lighter** (13% of the accent instead of 18%), so muted text on a
295
+ checked row or chosen option keeps 4.5:1 under every preset (now tested, light and dark).
296
+ - **Toasts lose their coloured leading-edge bar**; the kind shows in the icon and a tinted border,
297
+ as everywhere else nothing is docked to an edge.
298
+ - **Button key hints** are quieter by colour and weight instead of opacity, which left them below
299
+ 4.5:1 on a solid primary button.
300
+ - **Select.entity** shows an entity without a colour as a neutral tile with a muted glyph; before,
301
+ the glyph was white on the pale accent tint and could not be seen.
302
+ - **Icons are Lucide outlines.** The bundled set renders as strokes in `currentColor` (ISC; a
303
+ 1.75-unit stroke per 24 that never thins below 1px), with every existing name kept. Bundles keep
304
+ the licence notice. A chosen Rating star is drawn solid.
305
+ - **The theme studio's Density section is now Spacing**: a slider for `--zx-space-unit` (3–6px).
306
+ The radius slider sets `--zx-radius` in pixels (0–10px), the standard recipes carry a spacing
307
+ unit instead of a density, Copy CSS exports the unit, and a theme saved by an earlier studio
308
+ still loads.
309
+
310
+ ### Added
311
+
312
+ - **Motion as a setting.** `data-zx-motion="reduced"` on any element stops motion inside it: the
313
+ duration tokens become `0ms` and a base rule stops CSS animations and transitions, while state
314
+ changes still apply; the system preference zeroes the tokens too. `prefersReducedMotion(element)`,
315
+ `watchMotion(element, fn, { signal, immediate })`, and `MOTION_ATTRIBUTE` let script follow it;
316
+ Chart passes `reducedMotion` to its adapter and `ChartJsAdapter` turns animation off under it.
317
+ - `--zx-ease-spring` (a small overshoot) and `--zx-ease-drawer` (a decisive ease-out) beside
318
+ `--zx-ease`, and `--zx-drag-shadow` for an item being dragged.
319
+ - **Launcher pages.** An item with `items` (an array, or a loader `(query, { signal })`) opens a
320
+ nested page: a scope chip in the input, Backspace, ArrowLeft, or × to go back, "⌫ Back" in the
321
+ footer, `open({ page })`, `back()`, `getPage()`, and a `page` event. Items take a `hint` (muted
322
+ text at the end of the row), `shortcut` key caps, and `keys` for `aria-keyshortcuts`.
323
+ - **Message `action`** (`{ label, onclick, kind }`, a small button that runs and closes the toast;
324
+ a toast with an action stays at least 8 seconds) and **`leading`** (a node such as an Avatar in
325
+ place of the kind icon).
326
+ - **`Dialog.confirm({ confirmText })`** — type-to-confirm: a labelled input that has focus, and a
327
+ confirm button and Enter that work only on an exact match.
328
+ - **Busy buttons.** `button({ busy })` and `setButtonBusy(button, busy)` show a spinner in place of
329
+ the icon, set `aria-busy`, and ignore activation while the action runs — but keep the button
330
+ focusable, so focus does not fall to the page as it does from a disabled button.
331
+ - **`statusIcon(status)` and `priorityIcon(level)`**, the glyphs `Select.status()` and
332
+ `Select.priority()` draw, for lists, boards, and filters; decorative unless given a `label`.
333
+ - `idPrefix` on Form and Fieldset; Field `name`, `field.name`, and `field.controlId`.
334
+ - Checklist `hideLabel`; TagPicker `toneKey` (default `'tone'`), colouring a tag the way a Badge
335
+ `tone` does; ActivityList `variant: 'compact'` for cards narrower than 30rem; Table column
336
+ `ariaLabel` for a blank or terse header; FileItem `typeLabel`; `Dialog.prompt` `okLabel` and
337
+ `cancelLabel`.
338
+ - `MenuButton.open({ returnFocus })` (also on `focusFirst()` and `focusLast()`) and
339
+ `Message.disposeRegion(scope)`.
340
+ - ZeyOS: `zeyosTable` passes Table options through (`variant`, `zebra`, `stickyHeader`,
341
+ `responsive`, `growing`, `emptyText`, `rowClass`, `rowKind(s)`, the column chooser, and the Table
342
+ listeners; editing, row reordering, and hierarchy stay out because the binding never persists
343
+ them); `timeZone` and per-field `formats` on `zeyosTable`, `zeyosForm`, `zeyosView`, and
344
+ `resolveFields`; `unixSecondsToCalendarDay()` and `calendarDayToUnixSeconds()`; `zeyosForm`
345
+ `scope` and `notify`.
346
+ - **Colour roles:** `--zx-color-bg-current`, `--zx-color-bg-chrome`, `--zx-color-border-subtle`,
347
+ `--zx-color-text-subtle`, the categorical tones `--zx-color-tone-{blue,teal,green,amber,orange,
348
+ red,pink,violet,slate}-{bg,fg}`, and the chart series `--zx-color-chart-1` … `-8`, whose first
349
+ series is deliberately not the accent. Contrast is tested in both themes and all six presets.
350
+ - **Type tokens:** `--zx-text-3xl` (30px), `--zx-weight-medium`, `--zx-weight-semibold`,
351
+ `--zx-tracking-tight`, `--zx-tracking-title`.
352
+ - **Quiet fields:** inside any `[data-zx-fields="quiet"]` container, native fields and Select,
353
+ TagPicker, Datebox, DateRangeBox, NumberField, and Timebox show their frame only on hover and
354
+ focus — property panels read as data, not as a wall of boxes.
355
+ - `Table` / `TableView` `variant: 'plain'` (no frame, no header band) for tables inside cards;
356
+ `badge({ tone })` with the categorical tones (and `BADGE_TONES`); `Avatar` `tone`, `avatarTone()`
357
+ and `AVATAR_TONES`; `StatTile` `caption`, read with the value.
358
+ - `registerIcons()` accepts outline glyphs as `[viewBox, path, 'stroke']`; `[viewBox, path]` pairs
359
+ still render filled.
360
+ - `Tabbox` `label`, the tab list's accessible name.
361
+
362
+ ### Fixed
363
+
364
+ - A destructive `Dialog.confirm` started focus on the destructive button; it starts on Cancel, the
365
+ least destructive choice (type-to-confirm starts in its input).
366
+ - On a phone, toasts covered the header's controls; they rise from the foot of the screen there.
367
+ - A ghost Button showed no focus ring: its `box-shadow: none` outranked `:focus-visible`.
368
+ - Select's loading spinner never turned (it read an undefined duration token).
369
+ - The Launcher's search row could push its close button off a narrow screen.
370
+ - A `[data-zx-theme="dark"]` region on a light page inherited light glass, overlays, hover and
371
+ current fills, tone tints, and focus ring: colours derived from other theme colours were resolved
372
+ on `:root` only. They are restated on every theme element now; geometry overrides on `:root`
373
+ still reach nested regions.
374
+ - Overlays (Dropdown, Tooltip, MenuButton, ContextMenu, Modal, Dialog, Sheet, Launcher) created before their
375
+ anchor or scope was in the document parked their panel on `<body>`, outside the theme scope; they
376
+ find their host on first open.
377
+ - Choosing a MenuButton item dropped focus to `<body>`; it returns to the trigger. CodeEditor
378
+ trapped the keyboard; Escape then Tab leaves it, as documented.
379
+ - Floating Message regions kept sending toasts into an emptied host and were never removed.
380
+ - Table and Grid number and date editors select their content on entry (typing "6" over "1.00"
381
+ gives 6); sortable headers use the same font as the others; no scrollbar gutter is reserved on a
382
+ table that does not scroll; a blank header has an accessible name. TreeView type-ahead calls
383
+ `preventDefault` and leaves text controls in rows alone.
384
+ - Table's selection checkboxes and row-reorder handles sit in the middle of their cell. They rode a
385
+ few pixels high on the text baseline, and the cell padding pushed them off the centre of their
386
+ control-height column, in a fixed layout past its edge.
387
+ - NumberField, Datebox, and DateRangeBox fill a Field's control column; clear-button padding is
388
+ reserved only when `clearable`, and a disabled Datebox or DateRangeBox shows no clear button.
389
+ Slider end labels stay inside the component. A Checklist inside a Field no longer repeats its
390
+ heading.
391
+ - `colorKey` on `Select.entity()` and TagPicker accepts token references (`var(--zx-…)`). Clicking a
392
+ read-only Select no longer draws the keyboard focus ring; a disabled Select fades like a disabled
393
+ Field; a read-only TagPicker shows only its tags.
394
+ - `collapsible: false` still showed AppSidebar's minimise button. copyButton's status line and
395
+ CopyInput's hidden label were positioned outside their control.
396
+ - A Field whose adapter returns a wrapper (a `custom` field holding a component) named the
397
+ wrapper, which cannot carry a name; its label, description, and validity now reach the first
398
+ unnamed form control inside it, or the adapter's new `labelTarget`.
399
+ - Launcher ran an item's command before closing, so closing put focus back on an element the
400
+ command had just redrawn or moved focus away from; it closes first now.
401
+ - A MenuButton's menu had no accessible name; it is labelled by its trigger, as the APG pattern
402
+ has it. NumberField no longer swallows Mod+Enter (and other chords), so a form or dialog's submit
403
+ shortcut works from a number field. Datebox and DateRangeBox were 2px taller than the text input
404
+ beside them; every control is one control height.
405
+ - A Tooltip placed beside an anchor near the edge of the screen squeezed to a word per line
406
+ instead of moving: it now takes the other side, or goes above or below when neither side fits.
407
+ - A Chart in a narrow card overflowed it (its 220px minimum height became a 587px minimum width
408
+ through the aspect ratio); it grows taller instead. A StatTile delta keeps its figure on one line
409
+ in a narrow tile.
410
+ - `zeyosTable` showed a due date as a date-time whose hour moved with daylight saving, and
411
+ `zeyosForm` edited it as one; `zeyosForm.save()` raised its toast wherever focus was.
412
+ - The AccountMenu trigger rendered as a centred, boxed card because `menu-button.css` loaded after
413
+ `account-menu.css`; it is a flat row again.
414
+ - CodeEditor referenced `--zx-color-bg-subtle`, which never existed.
415
+ - The Marque Gold preset's accent text now reaches 4.5:1 on the light chrome tone.
416
+ - A sortable end-aligned Table column put its header label at the start, away from its figures;
417
+ the label now sits at the end with the sort arrow before it.
418
+ - ActivityItem's heading read the actor and title as one word ("Jonas Weberset…") to assistive
419
+ technology; a space now separates them.
420
+ - Table's Columns chooser, RecordView's Fields chooser, KanbanView's undo and redo, and Filter's
421
+ actions used a `zx-button` class no stylesheet defines, so they rendered as bare browser buttons;
422
+ they are small Zx buttons now (ghost in toolbars, primary for Apply).
423
+
424
+ ### Website
425
+
426
+ - The application layouts moved from the documentation sidebar to a gallery of their own
427
+ (`layouts.html`), with a live thumbnail per layout, a near-full-screen view with its source, and a
428
+ standalone page (`layout.html#<id>`) for opening one in its own tab. Nine complete application
429
+ templates join the eight screen patterns, which are rebuilt on the same application shell.
430
+ - The documentation, gallery, and theme studio share the library's look: navigation on the chrome
431
+ tone, neutral current entries, sentence-case labels, hairline example cards, and code and API
432
+ tables drawn like the refined Table.
433
+ - New in the gallery: an **agent workspace** template — agents with live presence, editor tabs, a
434
+ plan and execution log with hand-offs, approvals as toasts that carry their action, a command
435
+ palette with pages, a bottom panel, and a status bar — and two screen patterns, **agent chat**
436
+ (tool calls, an approval that blocks the run, sources, and the run beside the thread) and
437
+ **system states** (every empty, loading, error, validation, and confirmation state, with a
438
+ switch to go offline). The AI chat template shows its work: tool steps, sources, artifacts with
439
+ versions, regenerate and branch, and `@agent` mentions.
440
+ - Every layout works from a phone to a wide screen: below 1180px the inspector and below 860px
441
+ the navigation become drawers, and on a phone a layout shows its list or its record with a way
442
+ back. All seventeen pass an accessibility audit — named controls and landmarks, text contrast,
443
+ visible focus, heading order — in both themes, wide and narrow.
444
+ - The theme studio has a Motion setting (System or Reduced), kept across the whole site as a
445
+ reader's preference, and a Button states card showing every kind in every state.
446
+ - The site self-hosts Inter as a variable font (SIL OFL), so every weight renders as designed and no
447
+ font request leaves the site.
448
+ - The theme studio offers more to build from. Eleven neutral tints — Neutral, Zinc, Stone, Cool,
449
+ Mist, Sage, Olive, Warm, Taupe, Mauve, and Accent — are picked from swatches of the ramp each
450
+ would produce, and a strength control scales any of them from grey to twice its colour; every
451
+ tint keeps the text roles legible at full strength. The typeface list grows from six system
452
+ stacks to eleven, drawn in their own type, plus a custom stack for a brand font, and the code
453
+ font (`--zx-font-mono`) is a choice of its own.
454
+ - Themes can be saved and loaded as JSON. Export writes a `zx-theme` file — the settings, plus the
455
+ custom properties they produce — to copy or download; Import takes one pasted, dropped, or chosen,
456
+ loads it even when a value is out of range or unknown, and says what it adjusted.
457
+
11
458
  ## 4.4.0 — 2026-09-22
12
459
 
13
460
  A large release in two halves. The first adds capability: a dependency-free code editor, the
package/README.md CHANGED
@@ -80,6 +80,10 @@ namespaced `storage()` view that degrades to memory when the browser refuses wri
80
80
  `toCsv`/`downloadBlob`/`copyToClipboard` for exporting what a table is showing.
81
81
 
82
82
  `icon()` renders the inline SVG glyphs Zx bundles — no webfont, stylesheet, or network request.
83
+ They are outline icons from [Lucide](https://lucide.dev) (ISC licence; the notice ships in
84
+ `src/core/icons.js`): `currentColor` strokes on a 24-unit grid, about 1.2px at the default 16px.
85
+ `registerIcons()` adds more, either filled (`[viewBox, path]`, e.g. Font Awesome paths) or outlined
86
+ (`[viewBox, path, 'stroke']`, e.g. further Lucide icons).
83
87
  Applications that want Font Awesome call `loadFontAwesome({ kit })` once, and every icon in the
84
88
  library follows, including names Zx maps to their Font Awesome counterparts. Names can also pick a
85
89
  renderer themselves: `'fa:user'`, `'duotone:user'`, `'kit:zeyos-notes'`, `'builtin:check'`, or a
@@ -173,7 +177,8 @@ ZeyOS binding — see `src/zeyos/modules.js`.
173
177
  | `MasterPanel` | Full-height application panel with fixed header actions and footer. |
174
178
  | `Tabbox` | APG tabs in four appearances, with lazy content, closing, badges, and disabled states. |
175
179
  | `NavigationBar` | Responsive application navigation with optional tab panels and overflow. |
176
- | `AppSidebar` | Expanded or minimized vertical application navigation plus horizontal rails; descendants are inline only while expanded. |
180
+ | `AppSidebar` | Expanded or minimized vertical application navigation plus horizontal rails; descendants are inline only while expanded. Sections group a tree; `layout: 'modules'` puts a module strip beside one module's menu. |
181
+ | `ModuleBar` | Colour-coded module tiles in a strip or bar: flyout menus, live badges, one Tab stop, and an "All modules" catalogue for what does not fit. |
177
182
  | `Toolbar` | APG toolbar: one tab stop, arrow-key movement, and overflow into a menu. |
178
183
  | `SplitView` | Resizable two-pane split with a keyboard-operable separator. |
179
184
  | `Stepper` | Linear multi-step progress with completed, active, and error states. |
@@ -233,13 +238,13 @@ moduleColor('invoices'); // '#535494'
233
238
  name, identity colour, label, and a stock Font Awesome fallback. The `--zx-module-*` CSS custom
234
239
  properties are generated from that file, so CSS and JavaScript cannot disagree about a colour.
235
240
 
236
- ## Themes and density
241
+ ## Themes
237
242
 
238
243
  Load `zx.css` once. Zx components consume semantic `--zx-*` tokens and inherit their values from
239
- the document. Select a built-in theme and density on any ancestor (normally `<html>`):
244
+ the document. Select a built-in theme on any ancestor (normally `<html>`):
240
245
 
241
246
  ```html
242
- <html data-zx-theme="dark" data-zx-density="compact">
247
+ <html data-zx-theme="dark">
243
248
  ```
244
249
 
245
250
  Top-layer menus, dialogs, tooltips, launchers, and toast regions stay under the nearest Zx theme
@@ -247,10 +252,22 @@ scope in the DOM, so a theme or product-token override on a nested application s
247
252
  to its overlays. Pass the optional `scope` context to Modal, Dialog, Sheet, Launcher, or static
248
253
  Message calls when the opener is not inside the intended scope.
249
254
 
250
- Theme values are `light`, `dark`, and `auto`; density values are `cozy` and `compact`. `auto`
251
- follows the operating-system color preference.
255
+ Theme values are `light`, `dark`, and `auto`. `auto` follows the operating-system color
256
+ preference.
252
257
 
253
- A third attribute picks the **accent**, orthogonally to the other two:
258
+ There is one geometry. Spacing steps are multiples of `--zx-space-unit` (4px:
259
+ 4, 8, 12, 16, 20, 24, 32, 40), radius steps are fractions of `--zx-radius` (4px: 2, 3, 4, 6), and
260
+ controls are `--zx-control-height` (30px) tall. To tighten or loosen an application — or one
261
+ region of it — override those tokens rather than switching a mode:
262
+
263
+ ```css
264
+ :root {
265
+ --zx-space-unit: 3.5px;
266
+ --zx-control-height: 28px;
267
+ }
268
+ ```
269
+
270
+ A second attribute picks the **accent**, orthogonally to the theme:
254
271
 
255
272
  ```html
256
273
  <html data-zx-theme="dark" data-zx-preset="ocean">
@@ -272,6 +289,8 @@ through, so a preset rethemes light, dark, and auto at once:
272
289
 
273
290
  Light surfaces take the 600 and 700 stops, dark ones take 300, 400, and 500 — so keep 600 legible
274
291
  against white and 400 against near-black, and `--zx-color-on-accent` stays correct in both. The
292
+ primary button is the exception on purpose: `--zx-color-accent-solid` is the 600 stop with white
293
+ ink in both themes, so the one solid accent on a screen never turns into a bright slab in dark. The
275
294
  [theme studio](https://zx.zeyos.com/theme.html) renders every component family under a live theme and
276
295
  exports the result.
277
296
 
@@ -292,7 +311,20 @@ Anything beyond the accent is a semantic token override, without reaching into c
292
311
 
293
312
  Prefer semantic tokens such as `--zx-color-*`, `--zx-control-*`, `--zx-space-*`,
294
313
  `--zx-radius-*`, and `--zx-text-*`. Palette tokens are implementation details and should not be
295
- used by application or component CSS.
314
+ used by application or component CSS. A few roles carry most of the visual language:
315
+
316
+ - `--zx-color-bg-chrome` for navigation and inspector columns beside the `--zx-color-bg-surface`
317
+ canvas, and `--zx-color-border-subtle` for dividers inside them — tone separates, lines only
318
+ where tone cannot.
319
+ - `--zx-color-bg-current` (neutral) for where you are, `--zx-color-bg-selected` (accent tint) for
320
+ what you picked.
321
+ - `--zx-color-text-muted` for secondary text and `--zx-color-text-subtle` for icons and meta.
322
+ - `--zx-color-tone-<hue>-bg` / `-fg` (blue, teal, green, amber, orange, red, pink, violet, slate)
323
+ for categorical colour — tags, avatars, icon tiles — and `--zx-color-chart-1` … `-8` for chart
324
+ series. Neither is the accent or a status colour; `success` is a yellow-green of its own.
325
+
326
+ Add `data-zx-fields="quiet"` to a property panel and its native fields show no border or fill until
327
+ hovered or focused.
296
328
 
297
329
  ## Browser support
298
330
 
@@ -311,9 +343,10 @@ npm install
311
343
  npm run serve
312
344
  ```
313
345
 
314
- Open <http://127.0.0.1:8321/website/docs.html> for the documentation — getting started, every
315
- component with a live demo and its JavaScript source, and the application layouts. Also available: <http://127.0.0.1:8321/tests/smoke/smoke.html> for source-module smoke
316
- tests, or build first and open <http://127.0.0.1:8321/tests/smoke/smoke-dist.html> for
346
+ Open <http://127.0.0.1:8321/website/docs.html> for the documentation — getting started, and every
347
+ component with a live demo and its JavaScript source — and
348
+ <http://127.0.0.1:8321/website/layouts.html> for the gallery of application layouts. Also
349
+ available: <http://127.0.0.1:8321/tests/smoke/smoke.html> for source-module smoke tests, or build first and open <http://127.0.0.1:8321/tests/smoke/smoke-dist.html> for
317
350
  classic-script distribution tests.
318
351
 
319
352
  ```sh
@@ -126,6 +126,14 @@ export declare class AccountMenu extends Component<AccountMenuOptions> {
126
126
  isOpen(): boolean;
127
127
  /** Replaces account presentation without touching session state. @param {AccountIdentity} account @returns {this} */
128
128
  setAccount(account: AccountIdentity): this;
129
+ /**
130
+ * Shows the avatar alone or the avatar with the name and secondary line — for a navigation
131
+ * column that narrows to icons and widens again. The trigger keeps its full accessible name
132
+ * either way.
133
+ * @param {boolean} compact
134
+ * @returns {this}
135
+ */
136
+ setCompact(compact: boolean): this;
129
137
  /** Replaces account actions. @param {MenuButtonItem[]} items @returns {this} */
130
138
  setItems(items: MenuButtonItem[]): this;
131
139
  /** Focuses the account trigger. @returns {this} */