@zeyos/zx 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +266 -1
  2. package/README.md +7 -3
  3. package/dist/types/components/activity-item/activity-item.d.ts +351 -0
  4. package/dist/types/components/activity-list/activity-list.d.ts +195 -0
  5. package/dist/types/components/app-sidebar/app-sidebar.d.ts +28 -0
  6. package/dist/types/components/button/button.d.ts +8 -0
  7. package/dist/types/components/calendar/calendar-model.d.ts +22 -0
  8. package/dist/types/components/calendar/calendar.d.ts +19 -0
  9. package/dist/types/components/card/card.d.ts +7 -0
  10. package/dist/types/components/card-view/card-view.d.ts +12 -4
  11. package/dist/types/components/card-view/record-card.d.ts +53 -5
  12. package/dist/types/components/code-editor/code-editor.d.ts +160 -0
  13. package/dist/types/components/code-editor/field-adapter.d.ts +5 -0
  14. package/dist/types/components/context-menu/context-menu.d.ts +18 -2
  15. package/dist/types/components/date-picker/date-picker.d.ts +8 -0
  16. package/dist/types/components/date-picker/time-picker.d.ts +7 -0
  17. package/dist/types/components/dialog/dialog.d.ts +29 -0
  18. package/dist/types/components/entity-ref/entity-ref.d.ts +331 -0
  19. package/dist/types/components/file-item/file-item.d.ts +234 -0
  20. package/dist/types/components/file-list/file-list.d.ts +171 -0
  21. package/dist/types/components/filter/filter.d.ts +91 -36
  22. package/dist/types/components/filter-panel/filter-panel.d.ts +449 -0
  23. package/dist/types/components/kanban-view/kanban-card.d.ts +138 -0
  24. package/dist/types/components/kanban-view/kanban-policy.d.ts +268 -0
  25. package/dist/types/components/kanban-view/kanban-view.d.ts +837 -26
  26. package/dist/types/components/launcher/launcher.d.ts +19 -12
  27. package/dist/types/components/list-toolbar/list-toolbar.d.ts +599 -0
  28. package/dist/types/components/menu-button/menu-button.d.ts +4 -37
  29. package/dist/types/components/message/message.d.ts +7 -0
  30. package/dist/types/components/modal/modal.d.ts +48 -0
  31. package/dist/types/components/navigation-bar/navigation-bar.d.ts +105 -21
  32. package/dist/types/components/panel/panel.d.ts +7 -0
  33. package/dist/types/components/search/search.d.ts +7 -0
  34. package/dist/types/components/select/select.d.ts +4 -0
  35. package/dist/types/components/sort-control/sort-control.d.ts +105 -0
  36. package/dist/types/components/stat-tile/stat-tile.d.ts +277 -0
  37. package/dist/types/components/tabbox/tabbox.d.ts +7 -0
  38. package/dist/types/components/table/table.d.ts +144 -0
  39. package/dist/types/components/table-view/table-view.d.ts +11 -5
  40. package/dist/types/components/timebox/timebox.d.ts +7 -0
  41. package/dist/types/components/value-list/value-list.d.ts +8 -0
  42. package/dist/types/components/view/record-view.d.ts +96 -5
  43. package/dist/types/core/component.d.ts +6 -1
  44. package/dist/types/core/icons.d.ts +17 -0
  45. package/dist/types/index.d.ts +13 -1
  46. package/dist/types/internal/app-rail.d.ts +10 -0
  47. package/dist/types/internal/menu-items.d.ts +134 -0
  48. package/dist/zx-zeyos.esm.js +651 -88
  49. package/dist/zx-zeyos.esm.min.js +8 -1
  50. package/dist/zx.css +6266 -3900
  51. package/dist/zx.esm.js +8487 -1805
  52. package/dist/zx.esm.min.js +10 -3
  53. package/dist/zx.global.js +8487 -1805
  54. package/dist/zx.global.min.js +10 -3
  55. package/dist/zx.min.css +1 -1
  56. package/docs/api.json +1811 -247
  57. package/docs/llms.md +345 -40
  58. package/docs/llms.txt +11 -7
  59. package/package.json +1 -2
  60. package/src/components/activity-item/activity-item.css +137 -0
  61. package/src/components/activity-item/activity-item.js +599 -0
  62. package/src/components/activity-list/activity-list.css +64 -0
  63. package/src/components/activity-list/activity-list.js +375 -0
  64. package/src/components/app-rail/app-rail.css +227 -19
  65. package/src/components/app-sidebar/app-sidebar.css +414 -24
  66. package/src/components/app-sidebar/app-sidebar.js +65 -5
  67. package/src/components/button/button.css +8 -0
  68. package/src/components/button/button.js +6 -1
  69. package/src/components/calendar/calendar-model.js +45 -0
  70. package/src/components/calendar/calendar.css +30 -10
  71. package/src/components/calendar/calendar.js +41 -13
  72. package/src/components/card/card.js +12 -1
  73. package/src/components/card-view/card-view.css +212 -9
  74. package/src/components/card-view/card-view.js +32 -16
  75. package/src/components/card-view/record-card.js +98 -21
  76. package/src/components/code-editor/code-editor.css +67 -0
  77. package/src/components/code-editor/code-editor.js +288 -0
  78. package/src/components/code-editor/field-adapter.js +34 -0
  79. package/src/components/context-menu/context-menu.css +80 -3
  80. package/src/components/context-menu/context-menu.js +22 -30
  81. package/src/components/date-picker/date-picker.js +22 -8
  82. package/src/components/date-picker/month-picker.js +3 -3
  83. package/src/components/date-picker/time-picker.js +20 -8
  84. package/src/components/dialog/dialog.js +88 -66
  85. package/src/components/dropdown/dropdown.js +2 -2
  86. package/src/components/entity-ref/entity-ref.css +182 -0
  87. package/src/components/entity-ref/entity-ref.js +496 -0
  88. package/src/components/file-item/file-item.css +88 -0
  89. package/src/components/file-item/file-item.js +371 -0
  90. package/src/components/file-list/file-list.css +51 -0
  91. package/src/components/file-list/file-list.js +320 -0
  92. package/src/components/filter/filter.css +27 -1
  93. package/src/components/filter/filter.js +199 -45
  94. package/src/components/filter-panel/filter-panel.css +104 -0
  95. package/src/components/filter-panel/filter-panel.js +964 -0
  96. package/src/components/kanban-view/kanban-card.js +239 -0
  97. package/src/components/kanban-view/kanban-policy.js +412 -0
  98. package/src/components/kanban-view/kanban-view.css +674 -36
  99. package/src/components/kanban-view/kanban-view.js +1762 -240
  100. package/src/components/launcher/launcher.js +59 -27
  101. package/src/components/list-toolbar/list-toolbar.css +189 -0
  102. package/src/components/list-toolbar/list-toolbar.js +851 -0
  103. package/src/components/menu-button/menu-button.css +80 -3
  104. package/src/components/menu-button/menu-button.js +21 -37
  105. package/src/components/message/message.css +14 -12
  106. package/src/components/message/message.js +13 -2
  107. package/src/components/modal/modal.css +15 -0
  108. package/src/components/modal/modal.js +141 -0
  109. package/src/components/navigation-bar/navigation-bar.css +77 -2
  110. package/src/components/navigation-bar/navigation-bar.js +171 -4
  111. package/src/components/panel/panel.js +13 -2
  112. package/src/components/search/search.js +17 -5
  113. package/src/components/select/field-adapter.js +4 -1
  114. package/src/components/select/select.js +3 -0
  115. package/src/components/sort-control/sort-control.css +17 -0
  116. package/src/components/sort-control/sort-control.js +140 -0
  117. package/src/components/stat-tile/stat-tile.css +213 -0
  118. package/src/components/stat-tile/stat-tile.js +590 -0
  119. package/src/components/tabbox/tabbox.js +12 -1
  120. package/src/components/table/table.css +51 -2
  121. package/src/components/table/table.js +298 -19
  122. package/src/components/table-view/table-view.css +8 -2
  123. package/src/components/table-view/table-view.js +21 -6
  124. package/src/components/tag-picker/tag-picker.css +3 -1
  125. package/src/components/timebox/timebox.js +18 -5
  126. package/src/components/value-list/value-list.js +22 -6
  127. package/src/components/view/record-view.css +5 -0
  128. package/src/components/view/record-view.js +100 -7
  129. package/src/core/component.js +8 -3
  130. package/src/core/icons.js +74 -5
  131. package/src/index.js +33 -3
  132. package/src/internal/app-rail.js +19 -1
  133. package/src/internal/menu-items.js +142 -0
  134. package/styles/print.css +192 -0
  135. package/styles/zx.css +11 -0
  136. package/DESIGN-SYSTEM.md +0 -182
@@ -0,0 +1,142 @@
1
+ import { h, safeHref } from '../core/dom.js';
2
+ import { icon } from '../core/icons.js';
3
+
4
+ /** @typedef {'menuitem'|'menuitemcheckbox'|'menuitemradio'} MenuItemRole */
5
+ /**
6
+ * @typedef {Object} MenuController
7
+ * @property {() => unknown} close Close the owning menu.
8
+ */
9
+ /**
10
+ * @typedef {Object} MenuItem
11
+ * @property {string} label Item label.
12
+ * @property {string} [icon] Kernel icon name.
13
+ * @property {unknown} [value] Value emitted on selection.
14
+ * @property {boolean} [disabled=false] Whether selection is disabled.
15
+ * @property {boolean} [danger=false] Whether the action is dangerous.
16
+ * @property {string} [href] Native-link destination.
17
+ * @property {string} [target] Native-link target.
18
+ * @property {string} [rel] Native-link relationship.
19
+ * @property {string} [description] Supporting text under the label.
20
+ * @property {string|number} [badge] Compact trailing metadata.
21
+ * @property {string} [shortcut] Keyboard shortcut label.
22
+ * @property {string|number|Node} [adornment] Additional trailing content.
23
+ * @property {MenuItemRole} [role='menuitem'] APG role.
24
+ * @property {boolean} [checked=false] Checked state for checkbox/radio roles.
25
+ * @property {(value: unknown, item: MenuItem, controller: MenuController) => void} [onselect]
26
+ * Selection callback.
27
+ */
28
+ /**
29
+ * @typedef {Object} MenuHeading
30
+ * @property {'heading'} type Entry kind.
31
+ * @property {string} label Visible heading.
32
+ */
33
+ /** @typedef {{type: 'separator'}} MenuSeparator */
34
+ /** @typedef {MenuItem|MenuHeading|MenuSeparator|'-'} MenuEntry */
35
+
36
+ export const MENU_ITEM_SELECTOR = [
37
+ '[role="menuitem"]',
38
+ '[role="menuitemcheckbox"]',
39
+ '[role="menuitemradio"]'
40
+ ].join(',');
41
+
42
+ /**
43
+ * Reports whether an entry is an interactive menu action.
44
+ * @param {MenuEntry|unknown} entry Candidate entry.
45
+ * @returns {entry is MenuItem}
46
+ */
47
+ export function isMenuItem(entry) {
48
+ return Boolean(entry && entry !== '-' && typeof entry === 'object'
49
+ && !['heading', 'separator'].includes(String(/** @type {{type?: unknown}} */ (entry).type ?? '')));
50
+ }
51
+
52
+ /**
53
+ * Resolves the only APG roles accepted by the shared action model.
54
+ * @param {MenuItem} item Item definition.
55
+ * @returns {MenuItemRole}
56
+ */
57
+ export function menuItemRole(item) {
58
+ return ['menuitemcheckbox', 'menuitemradio'].includes(String(item.role))
59
+ ? /** @type {MenuItemRole} */ (item.role)
60
+ : 'menuitem';
61
+ }
62
+
63
+ /**
64
+ * Builds one menu's entries with shared structure and link safety.
65
+ * @param {MenuEntry[]} entries Entry definitions.
66
+ * @param {string} block CSS block name, without the `zx-` prefix.
67
+ * @returns {HTMLElement[]}
68
+ */
69
+ export function renderMenuEntries(entries, block) {
70
+ const nodes = [];
71
+ entries.forEach((entry, index) => {
72
+ if (entry === '-' || (entry && typeof entry === 'object' && entry.type === 'separator')) {
73
+ nodes.push(h('div', { class: `zx-${block}__separator`, role: 'separator' }));
74
+ return;
75
+ }
76
+ if (entry && typeof entry === 'object' && entry.type === 'heading') {
77
+ nodes.push(h('div', {
78
+ class: `zx-${block}__heading`,
79
+ role: 'presentation'
80
+ }, String(entry.label ?? '')));
81
+ return;
82
+ }
83
+ if (!isMenuItem(entry)) return;
84
+
85
+ const role = menuItemRole(entry);
86
+ const href = safeHref(entry.href);
87
+ const target = entry.target == null ? null : String(entry.target);
88
+ const rel = entry.rel == null
89
+ ? (target === '_blank' ? 'noopener noreferrer' : null)
90
+ : String(entry.rel);
91
+ const content = [];
92
+ const leading = [];
93
+ if (role !== 'menuitem') {
94
+ leading.push(h('span', {
95
+ class: `zx-${block}__check`,
96
+ 'data-check-kind': role === 'menuitemradio' ? 'radio' : 'checkbox'
97
+ }));
98
+ }
99
+ if (entry.icon) leading.push(icon(entry.icon));
100
+ content.push(h('span', {
101
+ class: `zx-${block}__leading`,
102
+ ariaHidden: 'true'
103
+ }, leading));
104
+ content.push(h('span', { class: `zx-${block}__body` },
105
+ h('span', { class: `zx-${block}__label` }, String(entry.label ?? '')),
106
+ entry.description == null || entry.description === '' ? null : h('span', {
107
+ class: `zx-${block}__description`
108
+ }, String(entry.description))));
109
+
110
+ const meta = [];
111
+ if (entry.badge != null) {
112
+ meta.push(h('span', { class: `zx-${block}__badge` }, String(entry.badge)));
113
+ }
114
+ if (entry.shortcut) {
115
+ meta.push(h('kbd', { class: `zx-${block}__shortcut` }, String(entry.shortcut)));
116
+ }
117
+ if (entry.adornment != null) {
118
+ const adornment = entry.adornment && typeof entry.adornment === 'object'
119
+ && 'nodeType' in entry.adornment
120
+ ? /** @type {Node} */ (entry.adornment)
121
+ : String(entry.adornment);
122
+ meta.push(h('span', { class: `zx-${block}__adornment` }, adornment));
123
+ }
124
+ if (meta.length) content.push(h('span', { class: `zx-${block}__meta` }, meta));
125
+
126
+ const properties = {
127
+ class: `zx-${block}__item`,
128
+ role,
129
+ tabindex: '-1',
130
+ 'data-menu-item': String(index),
131
+ 'data-danger': entry.danger ? 'true' : null,
132
+ ariaDisabled: entry.disabled ? 'true' : null,
133
+ ariaChecked: role === 'menuitem' ? null : String(Boolean(entry.checked))
134
+ };
135
+ if (href) {
136
+ nodes.push(h('a', { ...properties, href, target, rel }, content));
137
+ } else {
138
+ nodes.push(h('button', { ...properties, type: 'button' }, content));
139
+ }
140
+ });
141
+ return nodes;
142
+ }
@@ -0,0 +1,192 @@
1
+ /*
2
+ * Paper.
3
+ *
4
+ * Imported last from `styles/zx.css`, and everything in it lives inside the one `@media print`
5
+ * block below — so on screen this file contributes nothing at all, and on paper it is the last
6
+ * word. Consumers print invoices, delivery notes and reports out of these components, and until
7
+ * this file existed a printed table took its sticky header, its zebra stripes and whatever row
8
+ * the pointer happened to be over along with it.
9
+ *
10
+ * Paper differs from a screen in four ways, and every rule here answers one of them:
11
+ *
12
+ * - There is no viewport, so nothing may stick and nothing may scroll. A sticky header pins
13
+ * itself to the top of a sheet of paper, and a scroller prints exactly one screenful.
14
+ * - There is no pointer and no focus, so hover fills, focus rings and drag affordances are
15
+ * noise that costs toner.
16
+ * - There is no second page for the half of a card that did not fit, so blocks that read as one
17
+ * thing say where they may be cut, and a table repeats its header on every page.
18
+ * - Ink is not free and a fill is not a colour. Backgrounds come off; the one exception is a
19
+ * status badge, whose fill carries meaning its text alone does not.
20
+ *
21
+ * Semantic tokens only, as everywhere else. The borders are the interesting case: the light
22
+ * theme's `--zx-color-border` is a very pale grey that a printer renders as nothing, so the
23
+ * border roles are repointed — once, at the top — to a mix of the text colour, which prints.
24
+ */
25
+ @media print {
26
+ /*
27
+ * Hairlines. `--zx-color-text` rather than a fixed grey so the mix follows the theme it is
28
+ * printed from, and both selectors are single-class so this beats the theme block that sets the
29
+ * same roles on the same element: this file is imported last, and on a tie the last one wins.
30
+ */
31
+ .zx-scope,
32
+ [data-zx-theme] {
33
+ --zx-color-border: color-mix(in srgb, var(--zx-color-text) 45%, transparent);
34
+ --zx-color-border-strong: color-mix(in srgb, var(--zx-color-text) 65%, transparent);
35
+ --zx-color-border-control: color-mix(in srgb, var(--zx-color-text) 45%, transparent);
36
+ --zx-color-overlay-border: color-mix(in srgb, var(--zx-color-text) 45%, transparent);
37
+ --zx-color-overlay-divider: color-mix(in srgb, var(--zx-color-text) 45%, transparent);
38
+ /* The glass rim is a light tint of the page, which on white paper is the paper. */
39
+ --zx-color-glass-border: color-mix(in srgb, var(--zx-color-text) 45%, transparent);
40
+ }
41
+
42
+ /*
43
+ * A fill is a boundary too, and the filled variants drew theirs with one: their border is
44
+ * `transparent` because the surface underneath said where the card ended. With the fill gone
45
+ * they would arrive on paper as loose text, so they take the hairline instead.
46
+ */
47
+ .zx-scope .zx-card[data-variant="filled"],
48
+ .zx-scope .zx-record-card[data-variant="filled"] {
49
+ border-color: var(--zx-color-border);
50
+ }
51
+
52
+ /*
53
+ * Fills off. A badge is excluded by the selector rather than overridden afterwards, because its
54
+ * eleven kind/variant fills would otherwise have to be restated here one by one, and the copy
55
+ * would rot the first time badge.css gained a kind.
56
+ */
57
+ .zx-scope,
58
+ .zx-scope *:not(.zx-badge, .zx-badge *),
59
+ .zx-scope *:not(.zx-badge, .zx-badge *)::before,
60
+ .zx-scope *:not(.zx-badge, .zx-badge *)::after {
61
+ background-color: transparent !important;
62
+ background-image: none !important;
63
+ box-shadow: none !important;
64
+ text-shadow: none !important;
65
+ -webkit-backdrop-filter: none !important;
66
+ backdrop-filter: none !important;
67
+ }
68
+
69
+ /* The exception: a badge's colour is half of what it says, so it is asked for explicitly. */
70
+ .zx-scope .zx-badge {
71
+ -webkit-print-color-adjust: exact;
72
+ print-color-adjust: exact;
73
+ }
74
+
75
+ /*
76
+ * A solid button's label is the colour that reads on its fill — white on the accent. With the
77
+ * fill gone that label is white on white, so the two kinds that have one take the page's text
78
+ * colour and a hairline of their own. Buttons are not hidden: a printed form or an approval
79
+ * sheet is read by someone who needs to see what the screen offered.
80
+ */
81
+ .zx-scope .zx-btn[data-kind="primary"],
82
+ .zx-scope .zx-btn[data-kind="danger"] {
83
+ border-color: var(--zx-color-border);
84
+ color: var(--zx-color-text);
85
+ }
86
+
87
+ /* Nothing sticks to a sheet of paper. Everything below stacks where it was written instead. */
88
+ .zx-scope .zx-table th,
89
+ .zx-scope .zx-table__scroll[data-sticky-header="true"] th,
90
+ .zx-scope .zx-select__group,
91
+ .zx-scope .zx-calendar__agenda-heading,
92
+ .zx-scope .zx-toolbar,
93
+ .zx-scope .zx-list-toolbar {
94
+ position: static;
95
+ }
96
+
97
+ /*
98
+ * Nothing scrolls either: a scroller prints the rows that happen to be inside it and drops the
99
+ * rest, which on an invoice is a silently short invoice.
100
+ */
101
+ .zx-scope .zx-table__scroll,
102
+ .zx-scope .zx-tree,
103
+ .zx-scope .zx-card-view,
104
+ .zx-scope .zx-record-view {
105
+ overflow: visible;
106
+ max-block-size: none;
107
+ }
108
+
109
+ /* No pointer, no focus, no zebra — three states that only ever existed on a screen. */
110
+ .zx-scope .zx-table__scroll[data-zebra="true"] .zx-table__body tr:nth-child(even),
111
+ .zx-scope .zx-table__body tr[data-row]:hover,
112
+ .zx-scope .zx-table__body tr[aria-selected="true"] {
113
+ background: transparent;
114
+ }
115
+
116
+ .zx-scope :focus,
117
+ .zx-scope :focus-visible {
118
+ outline: none;
119
+ box-shadow: none;
120
+ }
121
+
122
+ /* Chrome and overlays: navigation a reader cannot follow, and panels floating over the page. */
123
+ .zx-scope .zx-navigation-bar,
124
+ .zx-scope .zx-app-rail,
125
+ .zx-scope .zx-app-sidebar,
126
+ .zx-modal,
127
+ .zx-dialog,
128
+ .zx-sheet,
129
+ .zx-dropdown,
130
+ .zx-context-menu,
131
+ .zx-tooltip,
132
+ .zx-launcher,
133
+ .zx-message-region,
134
+ [popover]:popover-open {
135
+ display: none !important;
136
+ }
137
+
138
+ ::backdrop {
139
+ display: none;
140
+ }
141
+
142
+ /* A table that runs over a page break reintroduces itself on the next one. */
143
+ .zx-scope .zx-table thead {
144
+ display: table-header-group;
145
+ }
146
+
147
+ .zx-scope .zx-table tfoot {
148
+ display: table-footer-group;
149
+ }
150
+
151
+ /* Things that read as one object are not cut in half if they can be moved whole. */
152
+ .zx-scope .zx-card,
153
+ .zx-scope .zx-record-card,
154
+ .zx-scope .zx-stat-tile,
155
+ .zx-scope .zx-table__body tr {
156
+ break-inside: avoid;
157
+ }
158
+
159
+ /*
160
+ * A link on paper is a dead end unless it says where it goes — in prose. Inside a table cell or
161
+ * on a button the appended URL is not information, it is a wrecked column, so those take it back
162
+ * off. Each of those selectors outranks the one above on specificity rather than on source
163
+ * order, so reordering the list cannot quietly turn one of them back on.
164
+ */
165
+ .zx-scope a[href^="http"]::after {
166
+ content: " (" attr(href) ")";
167
+ font-size: var(--zx-text-sm);
168
+ font-weight: 400;
169
+ word-break: break-all;
170
+ }
171
+
172
+ .zx-scope a[href]:empty::after,
173
+ .zx-scope a[href].zx-icon-btn::after,
174
+ .zx-scope a:has(> .zx-icon:only-child)::after,
175
+ .zx-scope th a[href]::after,
176
+ .zx-scope td a[href]::after,
177
+ .zx-scope button a[href]::after,
178
+ .zx-scope a[href].zx-btn::after,
179
+ .zx-scope .zx-btn a[href]::after,
180
+ .zx-scope .zx-table a[href]::after,
181
+ .zx-scope .zx-badge a[href]::after,
182
+ .zx-scope a[href].zx-badge::after,
183
+ .zx-scope a[href].zx-entity-ref::after,
184
+ .zx-scope .zx-entity-ref a[href]::after,
185
+ .zx-scope .zx-breadcrumb a[href]::after,
186
+ .zx-scope a[href].zx-stat-tile::after,
187
+ .zx-scope .zx-tabbox a[href]::after,
188
+ .zx-scope .zx-tree a[href]::after,
189
+ .zx-scope .zx-file-item a[href]::after {
190
+ content: none;
191
+ }
192
+ }
package/styles/zx.css CHANGED
@@ -18,6 +18,7 @@
18
18
  @import url("../src/components/skeleton/skeleton.css");
19
19
  @import url("../src/components/copy/copy-button.css");
20
20
  @import url("../src/components/copy/copy-input.css");
21
+ @import url("../src/components/code-editor/code-editor.css");
21
22
  @import url("../src/components/toolbar/toolbar.css");
22
23
  @import url("../src/components/toggle/toggle.css");
23
24
  @import url("../src/components/groupbox/groupbox.css");
@@ -31,6 +32,11 @@
31
32
  @import url("../src/components/app-icon/app-icon.css");
32
33
  @import url("../src/components/launcher/launcher.css");
33
34
  @import url("../src/components/avatar/avatar.css");
35
+ @import url("../src/components/entity-ref/entity-ref.css");
36
+ @import url("../src/components/file-item/file-item.css");
37
+ @import url("../src/components/file-list/file-list.css");
38
+ @import url("../src/components/activity-item/activity-item.css");
39
+ @import url("../src/components/activity-list/activity-list.css");
34
40
  @import url("../src/components/account-menu/account-menu.css");
35
41
  @import url("../src/components/app-rail/app-rail.css");
36
42
  @import url("../src/components/app-sidebar/app-sidebar.css");
@@ -60,6 +66,7 @@
60
66
  @import url("../src/components/view/record-view.css");
61
67
  @import url("../src/components/table/table.css");
62
68
  @import url("../src/components/table-view/table-view.css");
69
+ @import url("../src/components/stat-tile/stat-tile.css");
63
70
  @import url("../src/components/card-view/card-view.css");
64
71
  @import url("../src/components/kanban-view/kanban-view.css");
65
72
  @import url("../src/components/grid/grid.css");
@@ -67,7 +74,10 @@
67
74
  @import url("../src/components/tree/tree.css");
68
75
  @import url("../src/components/finder/finder.css");
69
76
  @import url("../src/components/data-filter/data-filter.css");
77
+ @import url("../src/components/filter-panel/filter-panel.css");
78
+ @import url("../src/components/list-toolbar/list-toolbar.css");
70
79
  @import url("../src/components/filter/filter.css");
80
+ @import url("../src/components/sort-control/sort-control.css");
71
81
  @import url("../src/components/pagination/pagination.css");
72
82
  @import url("../src/components/stepper/stepper.css");
73
83
  @import url("../src/components/breadcrumb/breadcrumb.css");
@@ -78,3 +88,4 @@
78
88
  @import url("../src/components/multi-value-editor/multi-value-editor.css");
79
89
  @import url("../src/components/field-upload/field-upload.css");
80
90
  @import url("../src/components/questionnaire/questionnaire.css");
91
+ @import url("./print.css");
package/DESIGN-SYSTEM.md DELETED
@@ -1,182 +0,0 @@
1
- # Xenon Design System
2
-
3
- Xenon is a product-agnostic design system for browser applications; Zx is its dependency-free
4
- JavaScript implementation. It provides shared foundations, accessible components, interaction
5
- patterns, and application layouts without taking ownership of an application's routing or domain
6
- logic.
7
-
8
- ## System boundary
9
-
10
- Xenon has four layers:
11
-
12
- 1. **Foundations** — semantic tokens, typography, spacing, density, themes, icons, motion, i18n,
13
- accessibility rules, and the safe DOM kernel.
14
- 2. **Components** — lifecycle-safe controls and containers with one options/events/destroy model.
15
- 3. **Patterns** — repeatable business interactions such as global launch, account/preferences,
16
- record detail, transaction entry, filtering, and empty/loading/error handling.
17
- 4. **Application layouts** — rails, bars, workspaces, master/detail, dashboards, inboxes, wizards,
18
- and responsive shell geometry.
19
-
20
- This separation keeps foundations, components, patterns, and layouts independently reusable while
21
- preserving a coherent API and visual language.
22
-
23
- Zx has a generated API reference, live examples, bundled local icons, and no runtime dependency.
24
- Its compact `__()` DOM builder and pure append/property/event helpers let established applications
25
- adopt the system without introducing a framework runtime. Domain policy, transport, persistence,
26
- and navigation remain application-owned.
27
-
28
- ## Coverage ledger
29
-
30
- | Front-end capability | Xenon/Zx status | Design-system boundary |
31
- | --- | --- | --- |
32
- | Buttons, inputs, toggles, dates, selects, checklists, tags | Covered by public components | Components preserve native semantics and expose consistent value/event contracts. |
33
- | Forms and fieldsets | Covered, including component-backed field adapters | Use for record editors; keep validation/business rules application-owned. |
34
- | Dialogs, sheets, dropdowns, context menus, tooltips, messages | Covered | Consolidate duplicate menu behavior before building account/launcher surfaces. |
35
- | Tabs, panels, toolbar, breadcrumbs, stepper, split view, dock | Covered | Compose layouts; do not let navigation components own routes. |
36
- | Sorting, selection, dynamic/local filtering, pagination, trees/finder | Covered | `Filter` authors typed nested expressions; `DataFilter` executes simple local predicates. Backend query compilation stays in adapters. |
37
- | Operational calendars and scheduling | Covered | `Calendar` provides agenda/day/week/month/year views, local collision/spanning layout, selection, and configurable optimistic pointer/keyboard edits. The host owns loading, persistence, permissions, recurrence rules, and DAV. |
38
- | Record table, card, and Kanban views | Covered by one shared contract | `TableView`, `CardView`, and `KanbanView` share schema fields, records, sort, selection, field controls, loading, and versioned state. Core remains persistence-neutral; the optional ZeyOS registry coordinates named layouts through an injected server transport. The host still owns permissions, server validation, and rollback. |
39
- | Editable billing/transaction rows | Covered at generic-grid level | `Grid.BillingItems()` composes single-click typed currency/unit editors, flat hierarchy, same-parent row movement, and column visibility over `Table`. Tax, subtotal, posting, rounding, and persistence stay domain code. |
40
- | Global launcher/search | Covered | `Launcher` combines an application grid, current/pinned state, recent records, and abortable grouped sources. The optional ZeyOS adapter maps the complete 29-app shell catalogue while the host retains permissions, icons, and routing. |
41
- | Account/profile/preferences menu | Covered at presentation level | `Avatar` and `AccountMenu` provide identity and action UI. The host supplies permitted actions and owns preferences, authentication, and logout. |
42
- | Persistent app rail / side navigation | Covered | One route-agnostic `AppSidebar` owns expanded, minimized, and horizontal presentations. Only expanded vertical branches render inline; every rail presentation uses flyouts. |
43
- | Charts and analytical summaries | Covered through an adapter | `Chart` is engine-neutral and accessible; `ChartJsAdapter` accepts an injected Chart.js 4 engine. Chart.js is documentation/test tooling only. |
44
- | Local product/module icons | Covered | `AppIcon` is generic; `zeyosAppIcon()` maps every current ZeyOS module/entity identity and accepts an offline glyph override. The optional remote Font Awesome kit is never loaded automatically. |
45
- | Domain entity selectors/cards/links | Covered at generic presentation level | `Card` provides media, native primary links, secondary actions, and metadata; applications own entity routing and policy. |
46
- | Persistent notification/activity center | Missing, lower priority | `Message` covers ephemeral feedback, not read/unread activity history. |
47
-
48
- ## Current ZeyOS delta audit (25 August 2026)
49
-
50
- This is a source audit, not a visual inventory. The comparison uses the current ZeyOS DOM/UI
51
- implementation as evidence: its generic control catalogue is concentrated in
52
- [`4-ui.orig.js`](../zeyos/ext/global.orig/4-ui.orig.js), configurable index-column management in
53
- [`4-pg.orig.js`](../zeyos/ext/global.orig/4-pg.orig.js#L3464), and the multi-view scheduling surface
54
- in [`calendar.orig.js`](../zeyos/ext/mod/calendar.orig.js#L61). Capabilities already represented by
55
- a Zx component or a documented composition are not counted as gaps.
56
-
57
- ### Already closed by Zx core
58
-
59
- | ZeyOS behavior | Source evidence | Xenon/Zx coverage |
60
- | --- | --- | --- |
61
- | Dynamic search/filter authoring and saved filter controls | [`UI.newSearch`](../zeyos/ext/global.orig/4-ui.orig.js#L3378) and [`UI.newContainerFilters`](../zeyos/ext/global.orig/4-ui.orig.js#L7723) | `Filter` supplies a typed/versioned AST editor; `DataFilter` remains the lightweight local-row helper. A compiler and persistence service are intentionally not core. |
62
- | Agenda/day/week/month/year scheduling | [`calendar.orig.js`](../zeyos/ext/mod/calendar.orig.js#L61) | `Calendar` covers timed collisions, spanning lanes, windowed range events, activity year view, selection, now state, and pointer/keyboard move/resize. `zeyosCalendar()` maps expanded appointment rows and Unix seconds without importing recurrence, DAV, routing, or permissions into core. |
63
- | Record table/card collections and reusable view state | [`_newCrdLstTbl`](../zeyos/ext/global.orig/4-ui.orig.js#L4457), [`newCrd`](../zeyos/ext/global.orig/4-ui.orig.js#L4649), and [`newTbl`](../zeyos/ext/global.orig/4-ui.orig.js#L4782) | `TableView`, `CardView`, and the additive `KanbanView` consume the same field descriptors and JSON-safe layout state. `buildZeyosViewConfig()` derives them from the runtime schema; `SavedViewRegistry` adds exact user/workspace/resource scoping and can bridge the existing `userfields` endpoints. Neither imports the client into core. |
64
- | Editable transaction rows and row movement | [`_newTblAddColEdit`](../zeyos/ext/global.orig/4-ui.orig.js#L5613) and [`newTblItems`](../zeyos/ext/global.orig/4-ui.orig.js#L6070) | `Table`/`Grid.BillingItems()` cover typed editing, currencies/units, hierarchy, single-click entry, same-parent drag/keyboard reorder, and show/hide columns. |
65
- | Entity selection, priority, status, and permission choices | [`newSelEntity`](../zeyos/ext/global.orig/4-ui.orig.js#L3296), [`newSelPriority`](../zeyos/ext/global.orig/4-ui.orig.js#L3101), and the surrounding Select family | `Select.entity()`, `.priority()`, `.status()`, and `.permission()` cover the interaction contract; the ZeyOS adapter owns schemas and localized catalogues. |
66
- | Application launcher and module/entity identity | [`newExpLst`](../zeyos/ext/global.orig/4-ui.orig.js#L4355) and entity/module item builders through line 4457 | `Launcher`, `AppIcon`, and the optional ZeyOS adapter cover the full app catalogue, current/pinned state, recent records, grouped abortable search, forks/weblets, and injected routing. |
67
- | Expanded/minimized/horizontal app navigation | Current shell navigation plus the same module identity catalogue | One public `AppSidebar` owns all presentations. The rail renderer is an internal presenter, not a second component; only expanded vertical branches render inline and rail branches use anchored flyouts. |
68
- | Toasts, loading, cards, dialogs, forms, grids, charts, and layout primitives | Multiple `newContainer*`, input, table, and progress families in `4-ui.orig.js` | Covered by existing Zx components and documented composition; these are not delta items merely because the legacy factory names differ. |
69
-
70
- ### Recommended additions to Zx core
71
-
72
- | Priority | Missing reusable contract | Evidence and proposed boundary |
73
- | --- | --- | --- |
74
- | P0 | **EntityRef** | ZeyOS has a large family of linked/static entity presentations with subtitle, owner/group/assignee context, fork, and record actions: [`newLinkEntity*`](../zeyos/ext/global.orig/4-ui.orig.js#L225) and [`newEntityStatic`/`newEntity*`](../zeyos/ext/global.orig/4-ui.orig.js#L8262). A generic `EntityRef` should own icon/title/subtitle/metadata/link/action semantics; ZeyOS routing, permissions, and context menus remain injected. `Card` is too large for dense table/feed rows. |
75
- | P0 | **FileItem / FileList** | Existing-file, temporary-file, waiting/progress, MIME, size, and download rows recur in [`newFile`, `newFileTemp`, and `newFileWait`](../zeyos/ext/global.orig/4-ui.orig.js#L8158). `FieldUpload` owns selection/upload but not durable file presentation. Core should render file identity/state/actions; transport, authorization, preview, and download URLs stay with the host. |
76
- | P0 | **ActivityList / ActivityItem** | [`newFeed`](../zeyos/ext/global.orig/4-ui.orig.js#L8704) combines chronological records, comments, attachments, likes, and incremental updates. Core should own an accessible chronological list, grouping, loading/empty state, and action slots. Posting, reactions, channels, permissions, and persistence remain application code. |
77
- | P1 | **FacetList** | Counted activity/status/tag/entity side filters appear in [`newNavActivityStatus`](../zeyos/ext/global.orig/4-ui.orig.js#L3967), `newNavTag`, and `newNavEntity`. `Filter` is an expression author, not a compact persistent facet navigator. Core should own selection/count/collapse/loading behavior; query mapping stays injected. |
78
- | P1 | **EditorHost** | ZeyOS uses plain/Markdown/contenteditable/iframe editors through [`newEditor`](../zeyos/ext/global.orig/4-ui.orig.js#L1607) and `newFrameEditor`. Like `Chart`, core should provide labels, toolbar/action slots, value/lifecycle, dirty/read-only/error states, and an injected engine adapter. Sanitization and document/media policy must not be implicit core behavior. |
79
- | P1 | **ColorPicker** | The reusable swatch picker is [`newCl`](../zeyos/ext/global.orig/4-ui.orig.js#L3753). A dependency-free accessible swatch/custom-color picker belongs in core and would also serve the Theme Studio. |
80
- | P2 | **Metric / Summary** | [`newSummary`](../zeyos/ext/global.orig/4-ui.orig.js#L7312) repeatedly formats counts, money, timing, size, stock, and relative values. These can currently be composed from Card and format helpers, but a small semantic Metric/DescriptionList pair would remove repeated markup without importing business formulas. |
81
- | P2 | **RecordPreview** | Typed preview builders for appointments, contacts, links, messages, tasks, and tickets start at [`newPreviewForm`](../zeyos/ext/global.orig/4-ui.orig.js#L9589). Core should offer a generic preview anatomy or engine-neutral preview host, not one component per ZeyOS entity. |
82
- | P2 | **Shortcut / Kbd** | Launcher and menus expose shortcuts but Zx has no reusable semantic `<kbd>` treatment. A tiny factory is justified once shortcuts appear outside those components. |
83
-
84
- ### Adapter work, not new core components
85
-
86
- - A **ZeyOS Filter compiler** mapping allowlisted AST field/operator IDs to the server's plural
87
- `filters` query shape, plus a parser for stored legacy filter state. Compilation must use bound/
88
- structured values and never accept raw SQL or URL fragments.
89
- - A shared **ZeyOS field/status/priority catalogue** built from runtime schemas and localization,
90
- feeding `Field`, `Filter`, `Select.status()`, and `Select.priority()` without hard-coding
91
- entity-specific policy in core.
92
- - **EntityRef/FileItem/ActivityList adapters** that resolve routes, icons, permissions, server
93
- payloads, and action menus while leaving their visual/interaction contracts reusable.
94
- - Optional persistence connectors for column visibility/order, sidebar state, saved filters, recent
95
- items, and theme preferences. Core should expose serializable state and events only.
96
-
97
- ### Deliberately application-owned
98
-
99
- Routing/history, authentication/session/logout, authorization, server transport/caching, saved-view
100
- storage, audit policy, transaction tax/discount/subtotal/posting formulas, server reconciliation and undo history,
101
- calendar recurrence/DAV synchronization, rich-text sanitization, and activity actions are not
102
- design-system responsibilities. Moving them into Zx would reproduce ZeyOS application logic inside
103
- the library and make Xenon less reusable.
104
-
105
- ### Launcher contract
106
-
107
- The launcher searches applications, recent records, and grouped remote record types. The generic
108
- component supplies the tile/list layouts, pinned-order ranking, current-route marker, request
109
- cancellation, spatial keyboard movement, visible keyboard hints, native link metadata, and a
110
- cancelable action. The optional ZeyOS adapter accepts all 29 prototype modules plus forks and
111
- weblets, cached or async recent items, grouped legacy search payloads, permission/current state,
112
- and host icon renderers. All state is injected; the adapter reads no shell globals and deliberately
113
- does not become a second router.
114
-
115
- ### Account contract
116
-
117
- A typical account surface includes identity, role-dependent links, language, authentication and
118
- logout, preferences, and About/version content. `AccountMenu` composes `Avatar` with the existing
119
- menu behavior and emits actions without owning routes or session state. The host decides which
120
- actions exist and what each one does.
121
-
122
- ## Table and transaction follow-ups
123
-
124
- The enhanced `Table` now keeps values numeric while formatting per-row locales, currencies, units,
125
- and decimals; numeric types infer `NumberField` editors. Flat `parentId` data is projected into a
126
- cycle-safe ARIA treegrid with local sibling sorting and expand/collapse APIs.
127
-
128
- `Grid.BillingItems()` now packages the conventional description, quantity, unit, unit-price,
129
- currency, line-total, and hierarchy schema while retaining Table's editing contract. Useful
130
- follow-ups, deliberately separate from this generic preset:
131
-
132
- - summary/footer rows and grouped subtotals;
133
- - persistence connectors for versioned view state (column order and visibility are now component capabilities);
134
- - product-specific invoice/transaction presets with tax, discount, rounding, and formula golden tests;
135
- - server persistence, optimistic rejection, and undo owned by the application/controller layer.
136
-
137
- ## Record-view contract
138
-
139
- `RecordView` is the presentation-neutral base for `TableView`, `CardView`, and `KanbanView`.
140
- Stable field IDs allow a runtime ZeyOS schema to drive every presentation, while per-view properties
141
- add table widths, card previews, or board grouping without changing how values, sorting, selection,
142
- and field visibility work. Each view returns a versioned JSON-safe configuration through
143
- `getViewState()`; record data and rendered Nodes are deliberately excluded.
144
-
145
- The optional ZeyOS adapter builds the shared descriptors and server projection, including hidden
146
- title, media, column, and swim-lane fields. It can page any concrete record view through an injected
147
- client. Preference storage remains outside Zx, and Kanban moves are cancelable: local mode updates a
148
- record clone, while external mode waits for the application to supply accepted server state.
149
-
150
- ## Calendar contract
151
-
152
- `Calendar` normalizes arbitrary event records into stable IDs, copied local Dates, optional colour
153
- and location, and per-event edit policies. Agenda, day, week, month, and year are presentations of
154
- the same event set. The interval helpers operate on calendar days rather than fixed 24-hour spans,
155
- so DST does not move a date; timed overlaps get deterministic columns and all-day/multi-day items
156
- get non-overlapping clipped lanes.
157
-
158
- Move and resize proposals are cancelable and keyboard-equivalent. Optimistic mode is the default
159
- and provides a version-guarded `revert()` that cannot overwrite a newer local edit. Controlled mode
160
- emits the same proposal without local mutation. The optional ZeyOS adapter maps expanded
161
- appointment occurrences and Unix seconds while the application retains transport, recurrence/DAV,
162
- permissions, routing, validation, and conflict handling.
163
-
164
- ## Chart-engine candidates
165
-
166
- Chart.js was selected for the first adapter. It is pinned at 4.5.1 as a development dependency for
167
- tests and the documentation asset, but is never imported by Zx runtime source. Applications inject
168
- their chosen engine into the adapter. Published browser artifact sizes below are approximate and
169
- remain useful when choosing a different future adapter.
170
-
171
- | Engine | Current state at audit | Approx. browser cost | Best fit | Main trade-off |
172
- | --- | --- | ---: | --- | --- |
173
- | [Chart.js](https://github.com/chartjs/Chart.js/releases) 4.5.1 | Mature, active, MIT | 209 kB / 71 kB gzip (UMD) | Broad default: bar, line, doughnut, mixed business charts | Larger than focused engines; canvas requires a separate accessible data summary. |
174
- | [Frappe Charts](https://github.com/frappe/charts/releases) 1.6.x | Zero-dependency SVG, ERP-oriented, MIT | 69 kB / 18 kB gzip (UMD) | Lean dashboards with common chart types | GitHub release and npm publication were out of step; ecosystem and extension surface are smaller. |
175
- | [uPlot](https://github.com/leeoniya/uPlot) 1.6.32 | Active, MIT, highly optimized | 51 kB JS + 2 kB CSS / about 23 kB gzip | Dense time-series and operational telemetry | Deliberately narrow; not a general categorical/stacked business-chart toolkit. |
176
- | [Apache ECharts](https://echarts.apache.org/en/changelog.html) 6.1.0 | Very capable, active, Apache-2.0 | 1.12 MB / 369 kB gzip (full build) | Advanced analytical visualization | Too large as Xenon's default; only sensible as an opt-in advanced adapter or custom build. |
177
-
178
- Implemented architecture: `Chart` accepts an injected engine adapter, maps Xenon semantic tokens,
179
- owns loading/empty/error states, and mirrors its data in an accessible table. Chart.js is the broad
180
- default adapter; Frappe Charts remains the lean ERP-oriented alternative, uPlot a specialized
181
- time-series candidate, and ECharts an opt-in advanced adapter. Any additional package still
182
- requires explicit dependency approval.