@zeyos/zx 4.1.1 → 4.3.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 (102) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/DESIGN-SYSTEM.md +33 -3
  3. package/README.md +22 -5
  4. package/dist/types/components/app-icon/app-icon.d.ts +8 -1
  5. package/dist/types/components/aurora/aurora.d.ts +72 -0
  6. package/dist/types/components/calendar/calendar-model.d.ts +202 -0
  7. package/dist/types/components/calendar/calendar.d.ts +517 -0
  8. package/dist/types/components/card-view/card-view.d.ts +303 -0
  9. package/dist/types/components/card-view/record-card.d.ts +242 -0
  10. package/dist/types/components/dialog/dialog.d.ts +6 -1
  11. package/dist/types/components/dropdown/dropdown.d.ts +5 -0
  12. package/dist/types/components/kanban-view/kanban-view.d.ts +572 -0
  13. package/dist/types/components/launcher/launcher.d.ts +5 -0
  14. package/dist/types/components/message/message.d.ts +9 -1
  15. package/dist/types/components/modal/modal.d.ts +44 -7
  16. package/dist/types/components/sheet/sheet.d.ts +22 -12
  17. package/dist/types/components/table/table.d.ts +120 -31
  18. package/dist/types/components/table-view/table-view.d.ts +192 -0
  19. package/dist/types/components/view/record-view.d.ts +464 -0
  20. package/dist/types/core/overlay-host.d.ts +12 -0
  21. package/dist/types/index.d.ts +7 -0
  22. package/dist/types/zeyos/calendar.d.ts +91 -0
  23. package/dist/types/zeyos/icons.d.ts +18 -2
  24. package/dist/types/zeyos/index.d.ts +4 -0
  25. package/dist/types/zeyos/legacy-saved-views.d.ts +66 -0
  26. package/dist/types/zeyos/saved-views.d.ts +331 -0
  27. package/dist/types/zeyos/view.d.ts +305 -0
  28. package/dist/zx-zeyos.esm.js +4742 -1470
  29. package/dist/zx-zeyos.esm.min.js +1 -1
  30. package/dist/zx.css +2536 -471
  31. package/dist/zx.esm.js +5193 -223
  32. package/dist/zx.esm.min.js +3 -3
  33. package/dist/zx.global.js +5193 -223
  34. package/dist/zx.global.min.js +3 -3
  35. package/dist/zx.min.css +1 -1
  36. package/docs/api.json +1729 -182
  37. package/docs/llms.md +236 -32
  38. package/docs/llms.txt +16 -6
  39. package/package.json +1 -1
  40. package/src/components/account-menu/account-menu.css +1 -1
  41. package/src/components/app-icon/app-icon.css +77 -51
  42. package/src/components/app-icon/app-icon.js +28 -4
  43. package/src/components/app-rail/app-rail.css +12 -3
  44. package/src/components/app-sidebar/app-sidebar.css +11 -2
  45. package/src/components/aurora/aurora.css +143 -0
  46. package/src/components/aurora/aurora.js +146 -0
  47. package/src/components/avatar/avatar.css +1 -1
  48. package/src/components/button/button.css +2 -2
  49. package/src/components/calendar/calendar-model.js +402 -0
  50. package/src/components/calendar/calendar.css +609 -0
  51. package/src/components/calendar/calendar.js +1619 -0
  52. package/src/components/card/card.css +2 -2
  53. package/src/components/card-view/card-view.css +389 -0
  54. package/src/components/card-view/card-view.js +527 -0
  55. package/src/components/card-view/record-card.js +392 -0
  56. package/src/components/context-menu/context-menu.css +4 -4
  57. package/src/components/context-menu/context-menu.js +5 -1
  58. package/src/components/date-picker/date-picker.css +31 -12
  59. package/src/components/datebox/date-range-box.css +17 -2
  60. package/src/components/datebox/datebox.css +18 -3
  61. package/src/components/dialog/dialog.css +4 -3
  62. package/src/components/dialog/dialog.js +2 -1
  63. package/src/components/dropdown/dropdown.css +17 -3
  64. package/src/components/dropdown/dropdown.js +7 -2
  65. package/src/components/kanban-view/kanban-view.css +216 -0
  66. package/src/components/kanban-view/kanban-view.js +1228 -0
  67. package/src/components/launcher/launcher.css +24 -9
  68. package/src/components/launcher/launcher.js +9 -2
  69. package/src/components/master-panel/master-panel.css +14 -3
  70. package/src/components/menu-button/menu-button.css +4 -4
  71. package/src/components/message/message.css +13 -21
  72. package/src/components/message/message.js +17 -11
  73. package/src/components/modal/modal.css +19 -5
  74. package/src/components/modal/modal.js +99 -25
  75. package/src/components/navigation-bar/navigation-bar.css +17 -5
  76. package/src/components/panel/panel.css +10 -2
  77. package/src/components/select/select.css +26 -8
  78. package/src/components/sheet/sheet.css +28 -7
  79. package/src/components/sheet/sheet.js +43 -23
  80. package/src/components/table/table.css +83 -5
  81. package/src/components/table/table.js +322 -37
  82. package/src/components/table-view/table-view.css +18 -0
  83. package/src/components/table-view/table-view.js +347 -0
  84. package/src/components/tag-picker/tag-picker.css +18 -4
  85. package/src/components/tooltip/tooltip.css +17 -3
  86. package/src/components/tooltip/tooltip.js +4 -1
  87. package/src/components/view/record-view.css +114 -0
  88. package/src/components/view/record-view.js +770 -0
  89. package/src/core/overlay-host.js +23 -0
  90. package/src/index.js +15 -0
  91. package/src/zeyos/calendar.js +115 -0
  92. package/src/zeyos/icons.js +11 -4
  93. package/src/zeyos/index.js +13 -0
  94. package/src/zeyos/launcher.js +2 -2
  95. package/src/zeyos/legacy-saved-views.js +155 -0
  96. package/src/zeyos/saved-views.js +815 -0
  97. package/src/zeyos/table.js +3 -1
  98. package/src/zeyos/view.js +543 -0
  99. package/styles/icons.css +3 -10
  100. package/styles/tokens/dark.css +4 -0
  101. package/styles/tokens/semantic.css +142 -3
  102. package/styles/zx.css +6 -0
package/docs/llms.md CHANGED
@@ -75,11 +75,24 @@ Keep the 600 stop at 4.5:1 or better against white and the 400 stop at 4.5:1 aga
75
75
 
76
76
  The theme studio treats those stable IDs as complete recipes: selecting a preset also changes its
77
77
  density, neutral tint, radius, control height, base text size, font stack, and material strength.
78
- Its **Material** control is CSS-first (`Flat`, `Glass`, or `Deep glass`); only the deep setting uses
79
- backdrop blur, and components fall back to solid surfaces under reduced-transparency preferences.
78
+ Its **Material** control is CSS-first (`Flat`, `Glass`, or `Deep glass`). Aurora is the independent
79
+ ambient canvas layer; material controls how surfaces respond to that light. The shared recipe
80
+ applies to AppIcons, ordinary controls, persistent chrome, raised cards, and every transient overlay: Dropdown, ContextMenu,
81
+ MenuButton, AccountMenu, AppRail flyouts, Select, TagPicker, date pickers, tooltips, column menus,
82
+ and toasts use `--zx-color-overlay-surface`; Launcher, Modal, Dialog, and overlay Sheets use the
83
+ calmer `--zx-color-overlay-panel`. Both tiers combine a translucent base, responsive specular and
84
+ Aurora tint layers, backdrop filtering, and dedicated state/divider roles; the modal backdrop is a
85
+ separate material token so it does not erase the light the panel should refract. A docked Sheet is
86
+ layout rather than an overlay and becomes opaque, as do dense data surfaces. Glass and Deep glass
87
+ progressively raise translucency, blur, highlights, and elevation; reduced-transparency,
88
+ increased-contrast, forced-colour, and unsupported-filter environments restore solid surfaces.
89
+ Top-layer components remain DOM children of their nearest Zx theme scope, so a theme or material
90
+ set on an application region continues to inherit through its menus, dialogs, tooltips, and toasts.
80
91
 
81
92
  Define a product theme by overriding **semantic** tokens under a `[data-zx-theme="name"]` selector:
82
- `--zx-color-bg-page/surface/raised/control/hover/selected`, `--zx-color-border(-strong/-control)`,
93
+ `--zx-color-bg-page/surface/raised/control/hover/selected`, `--zx-color-glass-chrome/surface`,
94
+ `--zx-color-overlay-surface/panel/backdrop/border/hover/selected/divider/scrim`,
95
+ `--zx-overlay-surface-image/toast-image/panel-image`, `--zx-color-border(-strong/-control)`,
83
96
  `--zx-color-text(-muted/-placeholder)`, `--zx-color-accent(-hover)/on-accent`,
84
97
  `--zx-color-danger/warning/success/info(+ -bg)`, `--zx-focus-ring`, `--zx-control-height/-radius`,
85
98
  `--zx-space-*`, `--zx-radius-*`, `--zx-text-*`. Never use tier-1 palette tokens (`--zx-gray-*`,
@@ -119,8 +132,10 @@ bundles `@zeyos/client`; the application owns client creation, authentication, a
119
132
  ```js
120
133
  import { createZeyosClient } from '@zeyos/client';
121
134
  import {
122
- connect, dataFilterStateToFilters, zeyosForm, zeyosSelect, zeyosTable
135
+ connect, createLegacySavedViewTransport, createSavedViewRegistry,
136
+ dataFilterStateToFilters, legacySavedViewRequest, zeyosForm, zeyosSelect, zeyosTable, zeyosView
123
137
  } from '/assets/zx-zeyos.esm.js';
138
+ import { CardView, TableView } from '/assets/zx.esm.js';
124
139
 
125
140
  const client = createZeyosClient({ platform, auth });
126
141
  const api = connect(client, { locale: 'en-GB' });
@@ -138,6 +153,17 @@ const editor = zeyosForm(client, 'transactions', {
138
153
  });
139
154
  await editor.load(transactionId);
140
155
  await editor.save();
156
+
157
+ const records = zeyosView(client, 'transactions', TableView, {
158
+ fields: ['transactionnum', 'account', 'date', 'netamount', 'status'],
159
+ savedViews: {
160
+ transport: savedViewTransport,
161
+ scope: { userId: currentUserId, workspaceId: currentWorkspaceId }
162
+ }
163
+ });
164
+ await records.ready; // restores a compatible default before the first list request
165
+ await records.load();
166
+ await records.saveView({ name: 'My open invoices', setDefault: true });
141
167
  ```
142
168
 
143
169
  - `connect(client, { onError, locale })` returns `{client, list, get, create, update, reportError}`;
@@ -154,6 +180,21 @@ await editor.save();
154
180
  `{table, load(), setSearch(), setFilters(), loadMore(), count, page, hasMore, destroy()}`. Columns
155
181
  come from schema metadata, sorting uses `sortMode:'server'`, and page zero replaces rows while
156
182
  later pages append them using server `limit`/`offset` and `count`.
183
+ - `buildZeyosViewConfig(client, resource, opts)` resolves one schema to shared `ViewField[]`, a
184
+ complete projection, and view options. `zeyosView(client, resource, CardView|TableView|KanbanView,
185
+ opts)` returns `{view, load(), setSearch(), setFilters(), loadMore(), count, page, hasMore,
186
+ savedViews, ready, restoreDefault(), captureView(), saveView(), applyView(), destroy()}` with
187
+ paging and server sort. Title, preview, group, column, and swim-lane fields stay in the projection
188
+ even when hidden. Without `savedViews`, the host may persist `view.getViewState()` directly.
189
+ - `createSavedViewRegistry(transport, {userId,workspaceId,resource})` coordinates private named
190
+ Table/Card/Kanban configurations as one versioned, atomically replaced document. Entries capture
191
+ component state plus filters/search and an explicit presentation type, never records, selection,
192
+ pages, callbacks, or DOM. Duplicate names, defaults, migration, type mismatch, failed writes, and
193
+ teardown are explicit. `workspaceId:null` addresses ZeyOS's base workspace.
194
+ - `createLegacySavedViewTransport(request)` reuses the authenticated `fields`, `fields_save`, and
195
+ `fields_remove` endpoints through one reserved, namespaced `userfields` record.
196
+ `legacySavedViewRequest(PG.load.bind(PG))` is the optional Promise bridge for a legacy host. The
197
+ scope's `userId` is intentionally not sent to the endpoint; the server session remains authority.
157
198
 
158
199
  Field mapping is schema-driven: entity/FK → async `zxselect`; enum/list → `optionlist` or native
159
200
  `select`; indexed `date` bigint → `date`; other date/time bigints → `datetime`; money/price/numeric
@@ -420,11 +461,13 @@ A native-dialog launcher for applications, recent records, commands, and grouped
420
461
  Zx owns ranking, focus, request cancellation, and presentation; ZeyOS owns the catalogue,
421
462
  permissions, recent-history/cache policy, and the route or command ultimately invoked.
422
463
 
423
- - **Constructor** — `new Launcher(null, options)` owns a body-level dialog;
464
+ - **Constructor** — `new Launcher(null, options)` owns a top-layer dialog in the opener's nearest
465
+ Zx theme scope;
424
466
  `new Launcher(existingDialog, options)` enhances and later restores an existing `<dialog>`.
425
467
  - **Options** — `items`, abortable `sources: [{id, label?, minQuery?, when?, order?, load(query, {signal})}]`,
426
468
  `query`, `debounce: 250`, `minQuery: 0`, `maxResults: 100`, `placeholder`, `label`, `emptyText`,
427
- `loadingText`, `shortcut: 'mod+k'|false`, and visible `hints` labels (or `false`).
469
+ `loadingText`, `shortcut: 'mod+k'|false`, visible `hints` labels (or `false`), and `scope` to
470
+ explicitly select an element whose nearest Zx theme scope owns the launcher.
428
471
  - **Items** — `{id, label, description?, keywords?, group?, icon?, badge?, value?, href?, target?,
429
472
  invoke?, pinned?, disabled?, kind?, current?, when?, groupOrder?, itemOrder?}`. `icon` accepts a
430
473
  bundled icon name, Node, or factory. Links stay native so modified and middle clicks work;
@@ -453,27 +496,34 @@ permissions, recent-history/cache policy, and the route or command ultimately in
453
496
  <!-- doc:app-icon -->
454
497
  ### AppIcon — application identity
455
498
 
456
- A fixed-size, product-agnostic application tile. It keeps glyph geometry stable in launchers,
499
+ A fixed-size, product-agnostic application identity. It keeps glyph geometry stable in launchers,
457
500
  sidebars, entity results, and recent-item rows while identity colour and material remain explicit
458
501
  options rather than application globals.
459
502
 
460
503
  - **Options** — `icon` (bundled name, Node, or lazy renderer), `color`, `size: 36`,
461
- `iconSize: '52%'`, `label`, `badge`, `selected: false`, `glass: false|'subtle'|'strong'`, and
504
+ `iconSize: '52%'`, `label`, `badge`, `selected: false`, `shape: 'tile'|'circle'`,
505
+ `glass: false|'subtle'|'strong'`, and
462
506
  additional `class` names.
463
507
  - **Methods** — `set(partialOptions)` updates the existing root; `destroy()` restores an enhanced
464
508
  target. `appIcon(options)` is the element-returning convenience factory.
465
509
  - **ZeyOS preset** — import `zeyosAppIcon(module, options)` from `@zeyos/zx/zeyos`. Every current
466
510
  ZeyOS application/module has a canonical colour and icon mapping in `src/zeyos/modules.js`;
467
- entity names and aliases resolve through the same catalogue. `moduleChip()` is the compatible
468
- alias. An application may call `useZeyosIcons()` for the existing custom glyph kit or inject an
469
- offline `icon` override; Zx never loads a network asset automatically.
470
- - **Material** — subtle glass is a CSS border/highlight treatment; strong glass progressively adds
471
- `backdrop-filter`. `prefers-reduced-transparency` and browsers without support receive a solid
472
- tile. Glyphs remain white and geometrically centred in either built-in SVG or Font Awesome form;
473
- hover and focus feedback use the same semantic material tokens. The glyph and label semantics do
474
- not depend on the visual treatment.
475
- - **Accessibility** — a non-empty `label` gives the root `role="img"`; otherwise it is decorative.
476
- The badge is visual supplementary status, so include its meaning in `label` when it matters.
511
+ entity names and aliases resolve through the same catalogue. `zeyosAppIcon()` defaults to a
512
+ circular application vessel; `moduleChip()` deliberately keeps a compact tile for entity and
513
+ record identity. An application may call `useZeyosIcons()` for the existing custom glyph kit or
514
+ inject an offline `icon` override; Zx never loads a network asset automatically.
515
+ - **Shape and material** — core `AppIcon` keeps the backward-compatible `tile` default. Application
516
+ launchers and rails use `circle`; entity rows, recent records, badges, and tables use `tile`.
517
+ Subtle glass uses a quiet colour bloom, rim, reflection, and shadow without per-icon backdrop
518
+ blur; strong glass increases those material cues without changing geometry.
519
+ `prefers-reduced-transparency` receives a solid surface. Glyphs remain crisp white and
520
+ geometrically centred in either built-in SVG or Font Awesome form. Enabled interactive hosts
521
+ respond through rim, light, and shadow without translating the icon; decorative and disabled
522
+ identities do not imply clickability.
523
+ - **Accessibility** — on an owned identity surface, a non-empty `label` gives the root
524
+ `role="img"`; otherwise it is decorative. When AppIcon enhances a button or link, it preserves
525
+ that control's native role and uses `label` only as its accessible name. The badge is visual
526
+ supplementary status, so include its meaning in `label` when it matters.
477
527
  <!-- /doc -->
478
528
 
479
529
  <!-- doc:avatar -->
@@ -744,8 +794,10 @@ The shared floating region is fixed to the upper-right logical corner by default
744
794
  messages rather than the page, and uses the translucent glass surface tokens with a solid fallback.
745
795
 
746
796
  - **Statics** — `Message.info/success/warning/error(msg, opts)`,
747
- `Message.show(msg, { kind, timeout=4000, closable })` → `{ close() }`,
748
- `Message.progress(text)` → `{ update(pct, text?), done(), fail(text?) }`.
797
+ `Message.show(msg, { kind, timeout=4000, closable, scope? })` → `{ close() }`,
798
+ `Message.progress(text, {scope?})` → `{ update(pct, text?), done(), fail(text?) }`. `scope` is
799
+ an element or selector whose nearest Zx theme scope owns that floating region; without it the
800
+ focused opener supplies the scope.
749
801
  - **Per-message options** — `kind: 'info'`, `timeout`, `closable: true`, `maxVisible: 5` (extras
750
802
  queue, and hovering pauses dismissal).
751
803
  <!-- /doc -->
@@ -753,11 +805,11 @@ messages rather than the page, and uses the translucent glass surface tokens wit
753
805
  <!-- doc:modal -->
754
806
  ### Modal
755
807
 
756
- Thin overlay on the native `<dialog>` element. The backdrop uses `--zx-color-bg-backdrop`, and
757
- focus returns to the opener on close.
808
+ Thin overlay on the native `<dialog>` element. The surface uses the shared, reading-sized overlay
809
+ panel material; the backdrop uses `--zx-color-overlay-backdrop`, and focus returns to the opener on close.
758
810
 
759
811
  - **Options** — `content`, `width: 'auto'`, `closable: true`, `lightDismiss: false`,
760
- `destroyOnClose: false`.
812
+ `destroyOnClose: false`, `scope: null` (the opener's nearest Zx theme scope by default).
761
813
  - **Methods** — `open()`, `close(result?)`, `setContent()`, `isOpen()`.
762
814
  - **Events** — `open`, `close {result}`, `cancel` (Esc; preventable with `event.preventDefault()`).
763
815
  <!-- /doc -->
@@ -782,13 +834,14 @@ Structured modal: a header with title and close button, a body, and footer butto
782
834
  Edge-anchored surface — a `Dialog` attached to one side of the viewport instead of floating in the
783
835
  middle. One primitive covers both side sheets and mobile drawers, which differ mainly in the edge they take, so
784
836
  `side` replaces what would otherwise be two components. Inherits the whole Dialog anatomy: title,
785
- footer buttons, switchable views, and focus restoration.
837
+ footer buttons, switchable views, focus restoration, and the reading-sized overlay panel material.
838
+ When a Dock adopts it, the Sheet becomes an opaque layout surface instead.
786
839
 
787
840
  - **Options** — `side: 'end'` (`'start' | 'end' | 'top' | 'bottom'`, logical), `modal: true`
788
841
  (`true | 'trap-focus' | false`), `backdrop: 'dim'` (`'dim' | 'blur' | 'none'`), `size: null`
789
842
  (CSS length or px number, applied to whichever axis `side` implies), `closeButton: true`,
790
843
  plus everything Dialog takes — `title`, `content`, `buttons`, `closable`, `lightDismiss`
791
- (defaults to `true` here, unlike Modal), `destroyOnClose`.
844
+ (defaults to `true` here, unlike Modal), `destroyOnClose`, `scope`.
792
845
  - **Methods** — `open()`, `close(result?)`, `setSide(side)`, `getSide()`, `setSize(size)`,
793
846
  `isModal()`, `isDocked()`, `isOpen()`, `getSize()`, `snapTo(target)`, plus Dialog's `setTitle()`, `setContent()`,
794
847
  `setButtons()`, `addView()`, `showView()`.
@@ -802,10 +855,12 @@ footer buttons, switchable views, and focus restoration.
802
855
  across a handoff: the element moves and reopens in place, so DOM state and listeners survive,
803
856
  and no `open`/`close` is emitted for what is only a change of address.
804
857
  - **Modality** — `true` delegates focus containment, page inertness, Escape, and the backdrop to
805
- the browser through `showModal()`. `'trap-focus'` and `false` open with `show()`, so the page
806
- keeps scrolling and stays interactive; Escape and outside-click are re-implemented, and
807
- `'trap-focus'` adds `focusTrap()` on top. Only a modal sheet renders a `::backdrop`, so
808
- `backdrop` is meaningful only when `modal` is `true`.
858
+ the browser through `showModal()`. Floating `'trap-focus'` and `false` sheets use a manual
859
+ Popover top layer, so they stay viewport-anchored even inside a transformed or clipped theme
860
+ scope while the page keeps scrolling and stays interactive. Escape and outside-click are
861
+ re-implemented, and `'trap-focus'` adds `focusTrap()` on top. Their top-layer backdrop is
862
+ explicitly transparent and non-filtering; `backdrop` is meaningful only when `modal` is `true`.
863
+ A docked Sheet remains a native non-modal dialog in its Dock's flow.
809
864
  - **Resizing and detents** — `resizable` makes the inner edge draggable between `min` and `max`.
810
865
  `snap` gives it detents: a number at or below 1 is a fraction of the viewport along the sheet's
811
866
  axis, anything larger is pixels, and a string is any CSS length (`'320px'`, `'90%'`). With
@@ -876,12 +931,14 @@ alone, `new SheetStack({…})`.
876
931
  ### Dropdown
877
932
 
878
933
  Generic anchored popover in the top layer, constructed as `new Dropdown(anchor, options)`. It
879
- light-dismisses on an outside click or Esc, and mirrors `aria-expanded` onto the anchor.
934
+ light-dismisses on an outside click or Esc, mirrors `aria-expanded` onto the anchor, and stays a
935
+ DOM child of the anchor's nearest Zx theme scope while the browser lifts it into the top layer.
880
936
 
881
937
  - **Options** — `content`,
882
938
  `placement: 'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'` plus the matching
883
939
  `left*` and `right*` placements, `offset: 4`,
884
- `matchWidth: false`, `openOn: 'click'|'manual'`, `closeOnSelect: false`.
940
+ `matchWidth: false`, `openOn: 'click'|'manual'`, `closeOnSelect: false`, `scope: null` (the
941
+ anchor's nearest Zx theme scope by default).
885
942
  - **Methods** — `open()`, `close()`, `toggle()`, `isOpen()`, `setContent()`, `getPanel()`.
886
943
  - **Events** — `open`, `close`.
887
944
  <!-- /doc -->
@@ -971,7 +1028,7 @@ range select.
971
1028
  `hierarchy: false|{parentId, column?, expanded?}`. Locale, currency, unit, and decimals may be
972
1029
  row callbacks; values remain numbers in row data while display formatting is locale-aware.
973
1030
  - **Methods** — `setData()`, `addData()`, `updateRow(id,row)`, `removeRow(id)`, `getRow(id)`,
974
- `getData()`, `empty()`, `setSort(id,dir)`, `getSelection()`, `setSelection(ids)`,
1031
+ `getData()`, `empty()`, `setSort(id,dir)`, `getSort()`, `clearSort()`, `getSelection()`, `setSelection(ids)`,
975
1032
  `clearSelection()`, `setLoading(bool)` (busy/skeleton state — dims rows, shows an indeterminate
976
1033
  top bar, sets `aria-busy`, and is cleared by the next `setData`).
977
1034
  - **Events** — `rowclick {row, id, index, event}`, `rowdblclick`, `sort {id, dir}`,
@@ -1051,6 +1108,82 @@ range select.
1051
1108
  - **Column visibility** — `columnVisibility: true` renders a chooser; `hiddenColumns` seeds it.
1052
1109
  `getVisibleColumns()`, `getHiddenColumns()`, `setColumnVisible()`, and `toggleColumn()` preserve
1053
1110
  caller column order and never allow the final visible column to disappear.
1111
+ - **Column order** — `columnReorder: true` adds up/down buttons to the chooser and ArrowUp/
1112
+ ArrowDown support while a column option is focused. `getColumns()`, `setColumns()`,
1113
+ `getColumnOrder()`, `setColumnOrder()`, and `moveColumn()` reconcile stale saved IDs and keep
1114
+ hidden/sorted state attached to stable column IDs. `columnorderchange {order}` fires after a
1115
+ user or non-silent programmatic change.
1116
+ <!-- /doc -->
1117
+
1118
+ <!-- doc:table-view -->
1119
+ ### TableView and the shared RecordView contract
1120
+
1121
+ `TableView` is the record-oriented entry point above the lower-level `Table`. It extends
1122
+ `RecordView` and composes one complete `Table`, so editing, hierarchy, growing, row movement,
1123
+ responsive stacking, loading, and advanced table events remain available through `getTable()`.
1124
+
1125
+ - **Shared fields** — every view accepts `fields: [{id,label,get?,render?,sortValue?,sortable?,
1126
+ visible?,duplicate?,type?,view?}]`. Primitive rendered values become text; an explicit Node is
1127
+ adopted. `field.view.table` carries Table-only column keys without changing CardView or KanbanView.
1128
+ - **Shared options** — `data`, `recordId: 'ID'`, `sort`, `sortMode: 'local'|'server'`,
1129
+ `selectable: false|'single'|'multi'`, `selection`, `fieldOrder`, `hiddenFields`,
1130
+ `fieldControls: true`, and `emptyText`. At least one field remains visible.
1131
+ - **Shared methods** — `setData()`, `addData()`, `updateRecord()`, `removeRecord()`, `getRecord()`,
1132
+ `getData()`, field getters/order/visibility methods, `setSort()`/`getSort()`, selection methods,
1133
+ `setLoading()`, `getViewState()`, and `setViewState()`.
1134
+ - **Portable state** — `{version:1,fieldOrder,hiddenFields,sort}` is JSON-safe configuration only.
1135
+ Records, selection, DOM nodes, rendered values, and callbacks are never serialized. A state from
1136
+ one record view may seed another; unknown fields are ignored and new fields append.
1137
+ - **TableView composition** — `table: {...}` forwards every advanced Table option, while shared
1138
+ fields/data/id/sort/selection/visibility/order win on overlaps. `getTable()` returns the composed
1139
+ instance. Row events become shared `recordclick`/`recorddblclick` details.
1140
+ - **Events** — `recordclick`, `recorddblclick`, `datachange`, `selectionchange`, `sortchange`,
1141
+ `fieldvisibilitychange`, `fieldorderchange`, and `statechange {state,reason}`.
1142
+ <!-- /doc -->
1143
+
1144
+ <!-- doc:card-view -->
1145
+ ### CardView
1146
+
1147
+ A responsive semantic record collection using the same fields, records, sort, selection, and
1148
+ portable state as TableView and KanbanView.
1149
+
1150
+ - **Options** — the shared RecordView options plus `titleField`, `subtitleField`, `preview`,
1151
+ `previewAlt`, `link`, `actions`, `groupBy`, `groupOrder`, `minCardWidth`, `maxColumns`,
1152
+ `variant: 'outlined'|'raised'|'filled'`, `loadingCount`, `headingLevel`, and `label`.
1153
+ - **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`.
1156
+ - **Media and URLs** — `preview` accepts a field ID or callback returning an image URL,
1157
+ `{src,alt,fit}`, Node, or null. Executable/non-image schemes are rejected and image failures show
1158
+ a stable fallback. Title/action links are normalized; `_blank` links receive `noopener`.
1159
+ - **Grouping and layout** — `groupBy` is a field ID or callback; `groupOrder` may deliberately show
1160
+ 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,
1162
+ selection controls, and selected text do not also activate the card. `recordaction` adds the
1163
+ resolved action to the shared event set.
1164
+ <!-- /doc -->
1165
+
1166
+ <!-- doc:kanban-view -->
1167
+ ### KanbanView
1168
+
1169
+ A semantic record board with explicit or data-derived columns, optional swim lanes, shared record
1170
+ cards, advisory work-in-progress limits, and equivalent pointer/programmatic/keyboard movement.
1171
+
1172
+ - **Options** — the shared RecordView options plus `columnBy`, `columns`, `swimlaneBy`,
1173
+ `swimlanes`, card title/subtitle/preview/link/actions, `moveMode: 'local'|'external'`,
1174
+ `columnOrder`, `swimlaneOrder`, collapsed IDs, `showCounts`, `showEmptyColumns`, `variant`, and
1175
+ `label`. Column/lane descriptors use stable `id`, `label`, optional stored `value`, and `accept`;
1176
+ columns may also declare an advisory `limit`.
1177
+ - **Methods** — configure/get/move columns and swim lanes, collapse either axis, and
1178
+ `moveRecord(id,{column?,lane?,index?})`. Board-specific order/collapse joins the common view
1179
+ state; record order, movement history, and selection do not.
1180
+ - **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.
1184
+ - **Keyboard** — focus the move handle; Enter/Space grabs or drops, Escape cancels, Left/Right
1185
+ 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.
1054
1187
  <!-- /doc -->
1055
1188
 
1056
1189
  <!-- doc:grid -->
@@ -1102,6 +1235,53 @@ code, so future adapters do not change the public `Chart` API.
1102
1235
  for assistive technology; `'visible'` makes exact values part of the interface.
1103
1236
  <!-- /doc -->
1104
1237
 
1238
+ <!-- doc:calendar -->
1239
+ ### Calendar
1240
+
1241
+ A dependency-free scheduling surface for operational events. One component owns agenda, day,
1242
+ week, month, and year views; local-time range math; timed collision columns; multi-day lanes;
1243
+ loading and empty states; pointer range selection; and equivalent pointer/keyboard move and resize
1244
+ interactions. Visible ranges use an exclusive `end`, so `dateschange` can be passed directly to a
1245
+ windowed loader.
1246
+
1247
+ - **Options** — `events`, `date`, `view: 'month'`, `views: ['agenda','day','week','month','year']`,
1248
+ `locale`, `weekStart: 1`, `weekNumbers: true`, `workweek: false`, `agendaDays: 14`,
1249
+ `slotDuration: 30`, `slotMinTime: 0`, `slotMaxTime: 1440`, `scrollTime: 480`, `eventLimit: 3`,
1250
+ `selectable: false`, `editable: false`, `eventStartEditable`, `eventDurationEditable`,
1251
+ `optimistic: true`, `nowIndicator: true`, `now`, `disabled`, and `renderEvent(event)`.
1252
+ - **Event input** — generic records default to `{id,title,start,end,allDay,color,location,editable,
1253
+ durationEditable}`. Every field has a string-or-function reader (`eventId`, `eventTitle`,
1254
+ `eventStart`, …); numeric dates use `dateUnit: 'milliseconds'|'seconds'`. Inputs are normalized
1255
+ atomically, duplicate IDs and inverted intervals throw, Dates are copied, text is never parsed as
1256
+ HTML, and suspicious CSS colour strings are ignored.
1257
+ - **Methods** — `getEvents()`, `setEvents()`, `addEvent()`, `updateEvent()`, `removeEvent()`,
1258
+ `getDate()`, `setDate()`, `getView()`, `setView()`, `prev()`, `next()`, `today()`,
1259
+ `setLoading()`, `focusEvent()`, `destroy()`.
1260
+ - **Events** — `dateschange {view,start,end}`, `viewchange {view,oldView}`, `eventclick`,
1261
+ `eventdblclick`, `dateclick {date,allDay,view}`, `select {start,end,allDay,view}`,
1262
+ `new {date,view}`, `moreclick {date,count}`, `eventschange {events}`, and cancelable
1263
+ `eventchange {event,oldEvent,action,delta,jsEvent,revert}`.
1264
+ - **Persistence** — `optimistic: true` updates local events before `eventchange`; call the
1265
+ idempotent, version-guarded `detail.revert()` if persistence fails. With `optimistic: false`, the
1266
+ component stays controlled: it emits the proposal without changing data, and the application
1267
+ applies an accepted response through `updateEvent()` or `setEvents()`. Zx does not send requests.
1268
+ - **View layout** — agenda days keep every event in one vertically stacked content column. Month
1269
+ uses a continuous seven-day grid with full-height day boundaries and event lanes overlaid below
1270
+ the date labels; today is indicated with accent text instead of a decorative edge highlight.
1271
+ - **Pointer editing** — a timed move preserves the point where the event was grabbed and snaps the
1272
+ resulting start to `slotDuration`. The lower grip stretches the event in its original day column,
1273
+ while pointer capture keeps either interaction active if the pointer leaves the event surface.
1274
+ - **Keyboard** — time slots and date grids use arrow-key navigation, Home/End, PageUp/PageDown,
1275
+ Enter/Space activation, and roving focus. On an editable event, Space grabs it, arrows propose a
1276
+ slot/day move (or change the focused resize grip), Space drops, and Escape cancels. Live status
1277
+ text announces the edit and its proposed times.
1278
+ - **ZeyOS binding** — `zeyosCalendar()` maps current appointment occurrence rows (`ID`, `name`,
1279
+ `location`, `color`, `datefrom`, `dateto`, and association text). `calendarEventToZeyosPatch()`
1280
+ returns the base `ID` with Unix-second dates. The current server already expands recurrence into
1281
+ the requested window; recurrence rules, DAV synchronization, permissions, and routes therefore
1282
+ remain in ZeyOS instead of being reimplemented in core.
1283
+ <!-- /doc -->
1284
+
1105
1285
  <!-- doc:data-filter -->
1106
1286
  ### DataFilter
1107
1287
 
@@ -1405,6 +1585,30 @@ so buttons and links in its action, content, and footer regions remain valid sib
1405
1585
  container query when the card itself becomes narrow.
1406
1586
  <!-- /doc -->
1407
1587
 
1588
+ <!-- doc:aurora -->
1589
+ ### Aurora
1590
+
1591
+ A decorative, CSS-driven ambient light field for an existing application surface. Aurora enhances
1592
+ the target in place: it does not wrap, replace, or relocate the surface's content, and it does not
1593
+ own routing, overlays, or interaction. Its gradients sit behind the target's children, so raised
1594
+ Cards and other Liquid Glass surfaces can pick up the underlying colour naturally.
1595
+
1596
+ - **Options** — `preset: 'source'|'confluence'|'horizon'|'diagonal'|'edge'|'curtain'`,
1597
+ `colors: []` (zero to four concrete CSS colours),
1598
+ `intensity: 'subtle'|'balanced'|'vivid'`.
1599
+ - **Methods** — `setPreset(preset)`, `setColors(colors)`, `setIntensity(intensity)`.
1600
+ - **Palette** — an empty list uses semantic accent, info, success, and warning colours. One colour
1601
+ fills all four fields; two alternate; three repeat the second colour in the fourth field; four
1602
+ map directly. Network/image-bearing CSS values and palettes longer than four are rejected.
1603
+ - **Geometry** — Source starts at the leading chrome; Confluence meets from the corners; Horizon
1604
+ forms a shallow top band; Diagonal crosses the surface; Edge preserves a neutral centre; Curtain
1605
+ descends as four elongated fields. All use ordinary CSS gradients without animation.
1606
+ - **Lifecycle** — `destroy()` removes an owned root or restores every original attribute and child
1607
+ of an enhanced target. Content is never rebuilt when a setter changes the effect.
1608
+ - **Accessibility** — the light field is pointer-transparent and purely decorative. Forced-colour
1609
+ and reduced-transparency preferences remove it entirely.
1610
+ <!-- /doc -->
1611
+
1408
1612
  <!-- doc:panel -->
1409
1613
  ### Panel / MasterPanel
1410
1614
 
package/docs/llms.txt CHANGED
@@ -21,21 +21,26 @@ exports and as `window.zx.*`.
21
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
22
 
23
23
  ## Components
24
- - Inputs and identity: `button()`, `buttonGroup()`, `badge()`/`badgeGroup()`, `CheckButton`,
25
- `Toggle`, `Search`, `AppIcon` (+ `zeyosAppIcon()` presets), `Avatar`,
24
+ - Inputs: `button()`, `buttonGroup()`, `badge()`/`badgeGroup()`, `CheckButton`,
25
+ `Toggle`, `Search`,
26
26
  `Select` (APG combobox; `filter: false|'local'|async`; priority, status, permission, and
27
27
  `Select.entity()` presets), `Checklist`, `TagPicker` (icon/color identity), `NumberField`, `Rating`, `Slider`,
28
28
  `copyButton()`/`CopyInput`, `DatePicker`, `MonthPicker`, `TimePicker`,
29
29
  `Datebox`/`DateTimeBox`, `DateRangePicker`/`DateRangeBox`, `Timebox`.
30
30
  - 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
31
  - Data: `Table` (sortable, selectable, sticky header, opt-in inline cell/row editing, row reorder,
32
- column visibility), `Grid` with single-click editing and `Grid.BillingItems()`, engine-neutral
33
- `Chart` with injected `ChartJsAdapter`, backend-neutral nested `Filter`, simple client-side
32
+ column visibility), shared `RecordView` state through `TableView`, `CardView`, and `KanbanView`,
33
+ `Grid` with single-click editing and `Grid.BillingItems()`, engine-neutral
34
+ `Chart` with injected `ChartJsAdapter`, `Calendar` (agenda/day/week/month/year, pointer/keyboard
35
+ drag and resize, `optimistic: true|false`), backend-neutral nested `Filter`, simple client-side
34
36
  `DataFilter`, `Pagination` (+ pure `paginationRange()`), `TreeView` (APG tree),
35
37
  `Finder` (Miller columns).
36
38
  - Forms: `Form`, `Fieldset`, `Questionnaire` (guided one-question-at-a-time flow with branching), `Field` (type registry), `ValueList`, `MultiValueEditor`, `FieldUpload`.
37
39
  - Layout: `stack()`/`grid()`/`aspect()` (spacing, an intrinsically reflowing grid, a fixed-ratio
38
- box), `Groupbox`, `Card` (media/title link/actions/footer), `Panel` (header/footer action
40
+ box), `Groupbox`, `Card` (media/title link/actions/footer), `AppIcon` (generic tile geometry;
41
+ circular `zeyosAppIcon()` application presets and compact `moduleChip()` identities),
42
+ `Aurora` (one- to four-colour ambient
43
+ canvas light; shared material roles govern chrome and overlays), `Avatar`, `Panel` (header/footer action
39
44
  buttons), `MasterPanel`, `Tabbox`
40
45
  (`variant: 'divided'|'bracket'|'line'|'segmented'`), `NavigationBar`, `AppSidebar` (expanded and
41
46
  minimized vertical states plus horizontal rail layouts), `AccountMenu`, `Launcher`,
@@ -47,11 +52,16 @@ exports and as `window.zx.*`.
47
52
  - Helpers: `formatNumber`/`formatCurrency`/`formatPercent`/`formatFileSize`/`formatRelativeTime` (locale-aware, cached `Intl`), `debounce`/`throttle`, `groupBy`/`sortBy`/`uniqueBy`, `escapeRegExp`/`highlightMatch`, `storage()` (namespaced JSON, degrades to memory), `toCsv`/`downloadBlob`/`copyToClipboard`, `truncate()`/`isTruncated()` (line clamp with the full value on hover).
48
53
 
49
54
  ## Theming
50
- Load `zx.css` once; set `data-zx-theme` (`light`|`dark`|`auto`) and `data-zx-density` (`cozy`|`compact`) on any ancestor. Define a product theme by overriding semantic `--zx-color-*` / `--zx-control-*` tokens under `[data-zx-theme="name"]`. The theme studio controls accent, neutral tint, density, font, type size, radius, control height, and CSS-first glass material. Never use tier-1 palette tokens or raw color literals in application CSS.
55
+ Load `zx.css` once; set `data-zx-theme` (`light`|`dark`|`auto`) and `data-zx-density` (`cozy`|`compact`) on any ancestor. Define a product theme by overriding semantic `--zx-color-*` / `--zx-control-*` tokens under `[data-zx-theme="name"]`. The theme studio controls accent, neutral tint, density, font, type size, radius, control height, and CSS-first glass material. Compact menus, pickers, tooltips, column menus, and toasts share responsive compact glass; Launcher, Modal, Dialog, and floating Sheets share a calmer reading panel. Both preserve scoped theme inheritance and refract Aurora/page content; docked Sheets and dense data surfaces remain opaque. Never use tier-1 palette tokens or raw color literals in application CSS.
51
56
 
52
57
  ## Talking to ZeyOS
53
58
  Use the dedicated ZeyOS client library **`@zeyos/client`** (`npm install @zeyos/client`) for ZeyOS business data: `createZeyosClient({ platform, auth })`, typed `client.api.list/get/create/update<Resource>` over the full OpenAPI surface, and `normalizeListResult`. Zx accepts the client by injection and does not bundle it. See the `website/layouts/zeyos-invoices.layout.js` layout for a Zx-components-on-@zeyos/client reference. Zx also ships a minimal `Http`/`zeyosService` for ad-hoc in-app `remotecall`, but `@zeyos/client` is the recommended default.
54
59
 
60
+ The optional `./zeyos` entry maps schemas into all three record views. `SavedViewRegistry` adds
61
+ private named configurations scoped by authenticated user, workspace/fork (including null for the
62
+ base workspace), and resource through an injected atomic transport. The compatibility transport
63
+ reuses ZeyOS `userfields`; records, selection, pages, callbacks, and DOM are never persisted.
64
+
55
65
  ## Installing
56
66
  `npm install @zeyos/zx`. Entry points: `.` (components), `./zeyos` (ZeyOS binding), `./zx.css`
57
67
  (styles), and `./global` (classic script tag). Docs: https://zx.zeyos.com
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeyos/zx",
3
- "version": "4.1.1",
3
+ "version": "4.3.0",
4
4
  "description": "Dependency-free JavaScript implementation of the Xenon Design System.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -60,7 +60,7 @@
60
60
  min-inline-size: 220px;
61
61
  gap: 2px;
62
62
  margin: calc(-1 * var(--zx-space-1)) calc(-1 * var(--zx-space-1)) var(--zx-space-1);
63
- border-block-end: 1px solid var(--zx-color-border);
63
+ border-block-end: 1px solid var(--zx-color-overlay-divider);
64
64
  padding: var(--zx-space-3);
65
65
  }
66
66