@zeyos/zx 5.0.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 (154) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/README.md +2 -1
  3. package/dist/types/components/account-menu/account-menu.d.ts +8 -0
  4. package/dist/types/components/activity-list/activity-list.d.ts +9 -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 +288 -14
  7. package/dist/types/components/calendar/calendar.d.ts +67 -5
  8. package/dist/types/components/card-view/card-view.d.ts +7 -4
  9. package/dist/types/components/card-view/record-card.d.ts +11 -0
  10. package/dist/types/components/context-menu/context-menu.d.ts +6 -2
  11. package/dist/types/components/data-filter/data-filter.d.ts +4 -4
  12. package/dist/types/components/dropdown/dropdown.d.ts +22 -7
  13. package/dist/types/components/field/field.d.ts +30 -0
  14. package/dist/types/components/fieldset/external-adapter.d.ts +83 -0
  15. package/dist/types/components/fieldset/fieldset.d.ts +7 -0
  16. package/dist/types/components/file-list/file-list.d.ts +35 -3
  17. package/dist/types/components/filter/filter.d.ts +127 -3
  18. package/dist/types/components/filter-panel/filter-panel.d.ts +36 -7
  19. package/dist/types/components/launcher/launcher.d.ts +8 -0
  20. package/dist/types/components/list-toolbar/list-toolbar.d.ts +15 -6
  21. package/dist/types/components/menu-button/menu-button.d.ts +6 -0
  22. package/dist/types/components/message/message.d.ts +14 -1
  23. package/dist/types/components/modal/modal.d.ts +30 -0
  24. package/dist/types/components/module-bar/module-bar.d.ts +395 -0
  25. package/dist/types/components/pagination/pagination.d.ts +17 -3
  26. package/dist/types/components/select/select.d.ts +6 -0
  27. package/dist/types/components/sheet/sheet.d.ts +15 -0
  28. package/dist/types/components/table/table.d.ts +265 -17
  29. package/dist/types/components/view/record-view.d.ts +59 -2
  30. package/dist/types/components/view-settings/view-settings.d.ts +879 -0
  31. package/dist/types/components/workspace-switcher/workspace-switcher.d.ts +327 -0
  32. package/dist/types/core/component.d.ts +12 -2
  33. package/dist/types/core/i18n.d.ts +27 -3
  34. package/dist/types/core/keyboard.d.ts +98 -1
  35. package/dist/types/core/messages.d.ts +382 -0
  36. package/dist/types/core/overlay-host.d.ts +28 -1
  37. package/dist/types/core/overlay-stack.d.ts +260 -0
  38. package/dist/types/index.d.ts +5 -2
  39. package/dist/types/internal/app-rail.d.ts +38 -0
  40. package/dist/types/internal/menu-items.d.ts +71 -3
  41. package/dist/types/zeyos/index.d.ts +1 -0
  42. package/dist/types/zeyos/launcher.d.ts +9 -0
  43. package/dist/types/zeyos/module-bar.d.ts +176 -0
  44. package/dist/types/zeyos/query.d.ts +31 -5
  45. package/dist/types/zeyos/table.d.ts +245 -8
  46. package/dist/types/zeyos/view.d.ts +16 -2
  47. package/dist/zx-zeyos.esm.js +4422 -430
  48. package/dist/zx-zeyos.esm.min.js +5 -5
  49. package/dist/zx.css +1417 -134
  50. package/dist/zx.esm.js +6986 -830
  51. package/dist/zx.esm.min.js +8 -8
  52. package/dist/zx.global.js +6986 -830
  53. package/dist/zx.global.min.js +8 -8
  54. package/dist/zx.min.css +1 -1
  55. package/docs/api.json +794 -17
  56. package/docs/llms.md +503 -63
  57. package/docs/llms.txt +6 -2
  58. package/package.json +1 -1
  59. package/src/components/account-menu/account-menu.js +12 -0
  60. package/src/components/activity-list/activity-list.js +27 -1
  61. package/src/components/app-icon/app-icon.css +13 -2
  62. package/src/components/app-icon/app-icon.js +11 -1
  63. package/src/components/app-rail/app-rail.css +19 -0
  64. package/src/components/app-sidebar/app-sidebar.css +204 -3
  65. package/src/components/app-sidebar/app-sidebar.js +646 -40
  66. package/src/components/breadcrumb/breadcrumb.css +1 -1
  67. package/src/components/calendar/calendar.css +1 -1
  68. package/src/components/calendar/calendar.js +26 -52
  69. package/src/components/card/card.css +2 -2
  70. package/src/components/card-view/card-view.css +5 -5
  71. package/src/components/card-view/card-view.js +13 -9
  72. package/src/components/card-view/record-card.js +14 -3
  73. package/src/components/code-editor/code-editor.css +1 -1
  74. package/src/components/code-editor/field-adapter.js +9 -2
  75. package/src/components/context-menu/context-menu.js +8 -2
  76. package/src/components/copy/copy-input.css +1 -1
  77. package/src/components/data-filter/data-filter.js +2 -2
  78. package/src/components/date-picker/time-picker.css +2 -2
  79. package/src/components/dock/dock.css +5 -4
  80. package/src/components/dropdown/dropdown.js +157 -72
  81. package/src/components/field/field.js +33 -3
  82. package/src/components/fieldset/external-adapter.js +363 -0
  83. package/src/components/fieldset/fieldset.js +10 -59
  84. package/src/components/file-list/file-list.js +144 -21
  85. package/src/components/filter/filter.css +86 -2
  86. package/src/components/filter/filter.js +300 -8
  87. package/src/components/filter-panel/filter-panel.js +149 -32
  88. package/src/components/finder/finder.css +1 -1
  89. package/src/components/kanban-view/kanban-view.css +3 -3
  90. package/src/components/kanban-view/kanban-view.js +5 -2
  91. package/src/components/launcher/launcher.css +1 -1
  92. package/src/components/launcher/launcher.js +29 -3
  93. package/src/components/list-toolbar/list-toolbar.js +39 -13
  94. package/src/components/master-panel/master-panel.js +0 -1
  95. package/src/components/menu-button/menu-button.css +63 -0
  96. package/src/components/menu-button/menu-button.js +97 -11
  97. package/src/components/message/message.js +60 -20
  98. package/src/components/modal/modal.css +1 -1
  99. package/src/components/modal/modal.js +66 -13
  100. package/src/components/module-bar/module-bar.css +486 -0
  101. package/src/components/module-bar/module-bar.js +1074 -0
  102. package/src/components/multi-value-editor/multi-value-editor.css +1 -1
  103. package/src/components/number-field/field-adapter.js +2 -1
  104. package/src/components/pagination/pagination.css +5 -5
  105. package/src/components/pagination/pagination.js +20 -4
  106. package/src/components/panel/panel.css +3 -2
  107. package/src/components/questionnaire/questionnaire.css +4 -4
  108. package/src/components/rating/field-adapter.js +2 -1
  109. package/src/components/rating/rating.css +1 -1
  110. package/src/components/search/search.css +4 -1
  111. package/src/components/select/select.js +9 -0
  112. package/src/components/sheet/sheet.css +1 -1
  113. package/src/components/sheet/sheet.js +74 -32
  114. package/src/components/slider/field-adapter.js +6 -1
  115. package/src/components/slider/slider.css +2 -2
  116. package/src/components/split-view/split-view.css +1 -1
  117. package/src/components/stat-tile/stat-tile.css +1 -1
  118. package/src/components/stepper/stepper.css +1 -1
  119. package/src/components/tabbox/tabbox.css +9 -5
  120. package/src/components/table/table.css +86 -11
  121. package/src/components/table/table.js +628 -57
  122. package/src/components/tag-picker/field-adapter.js +2 -1
  123. package/src/components/tooltip/tooltip.js +35 -17
  124. package/src/components/tree/tree.css +1 -1
  125. package/src/components/view/record-view.css +1 -1
  126. package/src/components/view/record-view.js +178 -18
  127. package/src/components/view-settings/view-settings.css +285 -0
  128. package/src/components/view-settings/view-settings.js +1830 -0
  129. package/src/components/workspace-switcher/workspace-switcher.css +188 -0
  130. package/src/components/workspace-switcher/workspace-switcher.js +463 -0
  131. package/src/core/component.js +88 -17
  132. package/src/core/fontawesome.js +5 -1
  133. package/src/core/i18n.js +47 -4
  134. package/src/core/icons.js +12 -2
  135. package/src/core/keyboard.js +206 -11
  136. package/src/core/messages.js +427 -0
  137. package/src/core/overlay-host.js +64 -9
  138. package/src/core/overlay-stack.js +487 -0
  139. package/src/core/position.js +22 -3
  140. package/src/index.js +5 -2
  141. package/src/internal/app-rail.js +134 -53
  142. package/src/internal/menu-items.js +61 -3
  143. package/src/zeyos/form.js +5 -3
  144. package/src/zeyos/index.js +3 -0
  145. package/src/zeyos/launcher.js +8 -3
  146. package/src/zeyos/module-bar.js +181 -0
  147. package/src/zeyos/query.js +44 -13
  148. package/src/zeyos/table.js +220 -80
  149. package/src/zeyos/view.js +43 -93
  150. package/styles/base.css +16 -1
  151. package/styles/print.css +1 -1
  152. package/styles/tokens/dark.css +4 -0
  153. package/styles/tokens/semantic.css +56 -28
  154. package/styles/zx.css +3 -0
package/src/zeyos/view.js CHANGED
@@ -1,8 +1,6 @@
1
- import { buildListQuery } from './query.js';
2
1
  import { connect } from './connect.js';
3
- import { normalizeZeyosListResult } from './select.js';
4
2
  import { createSavedViewRegistry } from './saved-views.js';
5
- import { buildZeyosTableConfig } from './table.js';
3
+ import { buildZeyosTableConfig, createServerPager } from './table.js';
6
4
 
7
5
  /** @typedef {import('../components/view/record-view.js').ViewField} ViewField */
8
6
  /** @typedef {import('../components/view/record-view.js').ViewSort} ViewSort */
@@ -32,7 +30,8 @@ import { buildZeyosTableConfig } from './table.js';
32
30
  * calendar day their stored midnight names in it. Defaults to the runtime's own zone.
33
31
  * @property {Record<string, Partial<ViewField>>} [fieldOverrides] View descriptor overrides.
34
32
  * @property {string|((record:Record<string,unknown>)=>unknown)} [recordId='ID'] Record id accessor.
35
- * @property {number} [pageSize=50] Server page size.
33
+ * @property {number} [pageSize=50] Server page size, a positive integer — the same default and
34
+ * validation as `zeyosTable()`, because both bindings page through one shared loader.
36
35
  * @property {ViewSort|null} [sort=null] Initial server sort.
37
36
  * @property {Record<string, unknown>} [filters] Initial ZeyOS predicates.
38
37
  * @property {string} [search=''] Initial full-text query.
@@ -62,7 +61,10 @@ import { buildZeyosTableConfig } from './table.js';
62
61
  * @typedef {Object} ZeyosViewLoadOptions
63
62
  * @property {string} [search] Replacement full-text query.
64
63
  * @property {Record<string, unknown>} [filters] Replacement predicates.
65
- * @property {number} [page=0] Zero-based page; pages above zero append.
64
+ * @property {number} [page=0] Zero-based page, a non-negative integer; pages above zero append
65
+ * unless `replace` is set.
66
+ * @property {boolean} [replace] Replace the records with this page instead of appending it.
67
+ * @property {number} [pageSize] New page size for this and every later load.
66
68
  */
67
69
 
68
70
  /**
@@ -106,6 +108,7 @@ import { buildZeyosTableConfig } from './table.js';
106
108
  * @property {()=>Promise<ZeyosViewLoadResult>} loadMore Loads the next page when available.
107
109
  * @property {number|null} count Current server count.
108
110
  * @property {number} page Current zero-based page.
111
+ * @property {number} pageSize Current server page size.
109
112
  * @property {boolean} hasMore Whether another page is available.
110
113
  * @property {Record<string,any>|null} savedViews Saved-view registry when configured.
111
114
  * @property {Promise<SavedViewApplyResult|null>} ready Default restoration completed before loads.
@@ -198,7 +201,17 @@ export function zeyosView(client, resource, View, opts = {}) {
198
201
  }
199
202
  }
200
203
  const facade = connect(client);
201
- const pageSize = normalizePageSize(opts.pageSize);
204
+ let pager;
205
+ try {
206
+ pager = createServerPager({
207
+ client, facade, resource, projection: config.projection, target: view,
208
+ pageSize: opts.pageSize, sort: opts.sort ?? null, filters: opts.filters ?? {}, search: opts.search,
209
+ searchFields: opts.searchFields, label: 'ZeyOS view'
210
+ });
211
+ } catch (error) {
212
+ view.destroy();
213
+ throw error;
214
+ }
202
215
  let saved;
203
216
  try {
204
217
  saved = resolveSavedViews(opts.savedViews, View, resource);
@@ -217,50 +230,8 @@ export function zeyosView(client, resource, View, opts = {}) {
217
230
  }
218
231
  }
219
232
  }
220
- let currentSort = opts.sort ?? null;
221
- let currentFilters = copyFilters(opts.filters ?? {});
222
- let currentSearch = String(opts.search ?? '');
223
- let currentPage = 0;
224
- let totalCount = null;
225
- let more = false;
226
- let requestSequence = 0;
227
233
  let destroyed = false;
228
-
229
- const performLoad = async (options = {}) => {
230
- if (destroyed) throw new Error('ZeyOS view binding has been destroyed');
231
- if (Object.prototype.hasOwnProperty.call(options, 'search')) currentSearch = String(options.search ?? '');
232
- if (Object.prototype.hasOwnProperty.call(options, 'filters')) currentFilters = copyFilters(options.filters ?? {});
233
- const page = normalizePage(options.page ?? 0);
234
- const query = buildListQuery({
235
- fields: config.projection,
236
- sort: currentSort,
237
- filters: currentFilters,
238
- search: currentSearch,
239
- searchFields: opts.searchFields,
240
- limit: pageSize,
241
- offset: page * pageSize,
242
- count: true
243
- });
244
- const sequence = ++requestSequence;
245
- view.setLoading(true);
246
- try {
247
- const normalized = normalizeZeyosListResult(client, await facade.list(resource, query));
248
- const count = normalized.count ?? null;
249
- const hasMore = count == null
250
- ? normalized.data.length === pageSize
251
- : page * pageSize + normalized.data.length < count;
252
- if (!destroyed && sequence === requestSequence) {
253
- currentPage = page;
254
- totalCount = count;
255
- more = hasMore;
256
- if (page === 0) view.setData(normalized.data);
257
- else view.addData(normalized.data);
258
- }
259
- return { data: normalized.data, count, page, hasMore, query };
260
- } finally {
261
- if (!destroyed && sequence === requestSequence) view.setLoading(false);
262
- }
263
- };
234
+ const performLoad = pager.load;
264
235
 
265
236
  /** @param {string} idOrName @param {{load?:boolean}} [options={}] @returns {Promise<SavedViewApplyResult>} */
266
237
  const applySaved = async (idOrName, options = {}) => {
@@ -270,15 +241,12 @@ export function zeyosView(client, resource, View, opts = {}) {
270
241
  type: presentation,
271
242
  onQuery: async ({ filters, search }) => {
272
243
  if (destroyed) return;
273
- currentFilters = copyFilters(filters ?? {});
274
- currentSearch = String(search ?? '');
244
+ pager.setQuery({ filters: savedFilters(filters), search });
275
245
  }
276
246
  });
277
247
  if (!result.applied || destroyed) return result;
278
- currentSort = appliedViewSort(view, result.entry);
279
- currentPage = 0;
280
- totalCount = null;
281
- more = false;
248
+ pager.setSort(appliedViewSort(view, result.entry));
249
+ pager.reset();
282
250
  if (options.load !== false) await performLoad({ page: 0 });
283
251
  return result;
284
252
  };
@@ -332,6 +300,8 @@ export function zeyosView(client, resource, View, opts = {}) {
332
300
  };
333
301
 
334
302
  const load = async (options = {}) => {
303
+ // Rejected before saved-view initialization runs, so an invalid call has no side effect.
304
+ pager.check(options);
335
305
  await ensureInitialized({ load: false });
336
306
  return performLoad(options);
337
307
  };
@@ -346,8 +316,8 @@ export function zeyosView(client, resource, View, opts = {}) {
346
316
  name: String(source.name ?? ''),
347
317
  type: presentation,
348
318
  state: view.getViewState(),
349
- filters: copyFilters(currentFilters),
350
- search: currentSearch
319
+ filters: pager.filters,
320
+ search: pager.search
351
321
  };
352
322
  };
353
323
 
@@ -377,8 +347,9 @@ export function zeyosView(client, resource, View, opts = {}) {
377
347
  };
378
348
 
379
349
  const sortHandler = (event) => {
350
+ if (destroyed) return;
380
351
  const id = event.detail?.id;
381
- currentSort = id == null ? null : { id: String(id), dir: event.detail.dir === 'desc' ? 'desc' : 'asc' };
352
+ pager.setSort(id == null ? null : { id: String(id), dir: event.detail.dir === 'desc' ? 'desc' : 'asc' });
382
353
  void load({ page: 0 }).catch(() => { /* connect() already reported the API failure. */ });
383
354
  };
384
355
 
@@ -389,26 +360,12 @@ export function zeyosView(client, resource, View, opts = {}) {
389
360
  setFilters: (filters) => load({ filters, page: 0 }),
390
361
  loadMore: async () => {
391
362
  await ensureInitialized({ load: false });
392
- return more ? performLoad({ page: currentPage + 1 }) : {
393
- data: [],
394
- count: totalCount,
395
- page: currentPage,
396
- hasMore: false,
397
- query: buildListQuery({
398
- fields: config.projection,
399
- sort: currentSort,
400
- filters: currentFilters,
401
- search: currentSearch,
402
- searchFields: opts.searchFields,
403
- limit: pageSize,
404
- offset: currentPage * pageSize,
405
- count: true
406
- })
407
- };
363
+ return pager.loadMore();
408
364
  },
409
- get count() { return totalCount; },
410
- get page() { return currentPage; },
411
- get hasMore() { return more; },
365
+ get count() { return pager.count; },
366
+ get page() { return pager.page; },
367
+ get pageSize() { return pager.pageSize; },
368
+ get hasMore() { return pager.hasMore; },
412
369
  savedViews,
413
370
  ready,
414
371
  restoreDefault,
@@ -418,7 +375,7 @@ export function zeyosView(client, resource, View, opts = {}) {
418
375
  destroy: () => {
419
376
  if (destroyed) return;
420
377
  destroyed = true;
421
- requestSequence += 1;
378
+ pager.destroy();
422
379
  if (typeof view.off === 'function') view.off('sortchange', sortHandler);
423
380
  else view.removeEventListener?.('sortchange', sortHandler);
424
381
  if (saved?.owned) savedViews?.destroy?.();
@@ -456,21 +413,14 @@ function supplementalFieldIds(opts) {
456
413
  return [...new Set(ids)];
457
414
  }
458
415
 
459
- /** @param {unknown} value @returns {number} */
460
- function normalizePageSize(value) {
461
- const number = Number(value ?? 50);
462
- return Number.isFinite(number) ? Math.max(1, Math.floor(number)) : 50;
463
- }
464
-
465
- /** @param {unknown} value @returns {number} */
466
- function normalizePage(value) {
467
- const number = Number(value);
468
- return Number.isFinite(number) ? Math.max(0, Math.floor(number)) : 0;
469
- }
470
-
471
- /** @param {unknown} value @returns {Record<string, unknown>} */
472
- function copyFilters(value) {
473
- return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};
416
+ /**
417
+ * Filters restored from a saved view are persisted data, not a caller's argument: a malformed
418
+ * entry reads as no filters rather than failing the restore.
419
+ * @param {unknown} value Stored filters.
420
+ * @returns {Record<string, unknown>}
421
+ */
422
+ function savedFilters(value) {
423
+ return value && typeof value === 'object' && !Array.isArray(value) ? { .../** @type {Record<string, unknown>} */ (value) } : {};
474
424
  }
475
425
 
476
426
  /**
package/styles/base.css CHANGED
@@ -32,6 +32,20 @@
32
32
  box-shadow: var(--zx-focus-ring);
33
33
  }
34
34
 
35
+ /* Forced colours (Windows high contrast) drop every box-shadow, so the accent ring disappears and
36
+ the outline is the only focus indicator left. Components therefore never set `outline: 0` or
37
+ `outline: none` on a focusable element — they make it transparent (`outline-color:
38
+ transparent`, plus `outline-offset: -2px` where the ring is inset) and this rule paints it in a
39
+ system colour. `tests/lint-tokens.js` rejects outline suppression outside a marked exception.
40
+ `!important` because a component's own, more specific `outline-color: transparent` would
41
+ otherwise survive on an element that opts out with `forced-color-adjust: none` (a current item
42
+ filled with Highlight). Offsets are left to the component, so inset rings stay inset. */
43
+ @media (forced-colors: active) {
44
+ .zx-scope :focus-visible {
45
+ outline: 2px solid Highlight !important;
46
+ }
47
+ }
48
+
35
49
  .zx-scope ::selection {
36
50
  background: var(--zx-color-accent);
37
51
  color: var(--zx-color-on-accent);
@@ -129,7 +143,8 @@
129
143
  }
130
144
 
131
145
  .zx-scope .zx-icon-btn:focus-visible {
132
- outline: 0;
146
+ outline-color: transparent;
147
+ outline-offset: -2px;
133
148
  box-shadow: inset var(--zx-focus-ring);
134
149
  }
135
150
 
package/styles/print.css CHANGED
@@ -115,7 +115,7 @@
115
115
 
116
116
  .zx-scope :focus,
117
117
  .zx-scope :focus-visible {
118
- outline: none;
118
+ outline: none; /* lint: outline-ok — printed pages have no focus to show */
119
119
  box-shadow: none;
120
120
  }
121
121
 
@@ -84,6 +84,9 @@
84
84
  --zx-color-tone-slate-fg: var(--zx-tone-slate-300);
85
85
  --zx-color-ring: var(--zx-color-accent);
86
86
  --zx-focus-ring: 0 0 0 3px color-mix(in srgb, var(--zx-color-ring) 45%, transparent);
87
+ /* The surface contact shadow keeps the light value: on a dark canvas the border, not the shadow,
88
+ separates a resting surface, and a heavier shadow would read as a lifted one. */
89
+ --zx-surface-shadow: var(--zx-shadow-1);
87
90
  --zx-overlay-shadow: 0 12px 36px rgb(0 0 0 / 45%);
88
91
  /* A shadow alone barely reads on a dark canvas, so the lifted item also gets a faint light rim. */
89
92
  --zx-drag-shadow: 0 0 0 1px color-mix(in srgb, var(--zx-gray-0) 7%, transparent), 0 2px 6px -1px rgb(0 0 0 / 40%), 0 14px 32px -6px rgb(0 0 0 / 60%);
@@ -158,6 +161,7 @@
158
161
  --zx-color-tone-slate-fg: var(--zx-tone-slate-300);
159
162
  --zx-color-ring: var(--zx-color-accent);
160
163
  --zx-focus-ring: 0 0 0 3px color-mix(in srgb, var(--zx-color-ring) 45%, transparent);
164
+ --zx-surface-shadow: var(--zx-shadow-1);
161
165
  --zx-overlay-shadow: 0 12px 36px rgb(0 0 0 / 45%);
162
166
  --zx-drag-shadow: 0 0 0 1px color-mix(in srgb, var(--zx-gray-0) 7%, transparent), 0 2px 6px -1px rgb(0 0 0 / 40%), 0 14px 32px -6px rgb(0 0 0 / 60%);
163
167
  --zx-header-bg: var(--zx-gray-900);
@@ -12,6 +12,44 @@
12
12
  * `tokens/themes.css` retheme them. Status colours keep their own ramps on purpose — see the note
13
13
  * in that file.
14
14
  */
15
+ /*
16
+ * Geometry and material settings — every token here is theme-independent, so it is declared on
17
+ * :root ONLY and never restated on a `[data-zx-theme]` block. A custom property declared on a
18
+ * theme element shadows the inherited one, so a nested `[data-zx-theme="light"]` region would
19
+ * otherwise reset an application's own `:root { --zx-control-height: 40px }` back to the default
20
+ * while a dark region kept it. There is one geometry; the theme blocks below carry colours only,
21
+ * and `tests/unit/geometry-tokens.test.js` fails if a non-colour token moves back into one.
22
+ */
23
+ :root {
24
+ --zx-control-height: 30px;
25
+ --zx-control-pad-x: 10px;
26
+ --zx-control-radius: var(--zx-radius-lg);
27
+ --zx-control-font-size: var(--zx-text-md);
28
+ --zx-control-font-weight: 500;
29
+ /* Blur applied behind a backdrop that asked for it. */
30
+ --zx-overlay-blur: 8px;
31
+ /* AppIcon is a dark chromatic lens: colour lives in its rim and low bloom, not a glossy fill.
32
+ Its strengths remain inherited, while each AppIcon mixes them with its own module colour. */
33
+ --zx-app-icon-core-strength: 52%;
34
+ --zx-app-icon-rim-strength: 58%;
35
+ --zx-app-icon-bloom-strength: 64%;
36
+ --zx-app-icon-specular-strength: 72%;
37
+ --zx-app-icon-halo-size: 14px;
38
+ --zx-app-icon-halo-strength: 22%;
39
+ --zx-overlay-specular-strength: 48%;
40
+ --zx-glass-blur: 8px;
41
+ --zx-glass-saturation: 130%;
42
+ --zx-glass-color-strength: 82%;
43
+ /* Material filters are roles, not component recipes. Aurora remains a separate canvas layer. */
44
+ --zx-glass-filter-icon: blur(4px) saturate(118%);
45
+ --zx-glass-filter-control: blur(6px) saturate(116%);
46
+ --zx-glass-filter-raised: blur(8px) saturate(120%);
47
+ --zx-glass-filter-chrome: blur(10px) saturate(122%);
48
+ --zx-glass-filter-overlay: blur(16px) saturate(140%);
49
+ --zx-glass-filter-panel: blur(14px) saturate(132%);
50
+ }
51
+
52
+ /* The light theme — colours only. */
15
53
  :root,
16
54
  [data-zx-theme="light"] {
17
55
  color-scheme: light;
@@ -80,41 +118,30 @@
80
118
  --zx-color-chart-6: var(--zx-tone-green-500);
81
119
  --zx-color-chart-7: var(--zx-tone-violet-500);
82
120
  --zx-color-chart-8: var(--zx-tone-red-500);
83
- --zx-control-height: 30px;
84
- --zx-control-pad-x: 10px;
85
- --zx-control-radius: var(--zx-radius-lg);
86
- --zx-control-font-size: var(--zx-text-md);
87
- --zx-control-font-weight: 500;
121
+ /* Solid identity fills — a module tile, an application icon — carrying the white icon glyph.
122
+ The 500 stops keep that glyph at 3:1 or better and read as the same tone on either theme,
123
+ so, like the chart series, the dark theme keeps this list. */
124
+ --zx-color-tone-blue-solid: var(--zx-tone-blue-500);
125
+ --zx-color-tone-teal-solid: var(--zx-tone-teal-500);
126
+ --zx-color-tone-green-solid: var(--zx-tone-green-500);
127
+ --zx-color-tone-amber-solid: var(--zx-tone-amber-500);
128
+ --zx-color-tone-orange-solid: var(--zx-tone-orange-500);
129
+ --zx-color-tone-red-solid: var(--zx-tone-red-500);
130
+ --zx-color-tone-pink-solid: var(--zx-tone-pink-500);
131
+ --zx-color-tone-violet-solid: var(--zx-tone-violet-500);
132
+ --zx-color-tone-slate-solid: var(--zx-tone-slate-500);
133
+ /* A resting surface one hair off what it sits on — a panel, an outlined card in a lane, a slider
134
+ thumb: a contact shadow only, far below an overlay or a dragged item. */
135
+ --zx-surface-shadow: var(--zx-shadow-1);
88
136
  --zx-overlay-shadow: var(--zx-shadow-3);
89
137
  /* An item being dragged — a lifted card, a row in flight, a drag preview: a tight contact
90
138
  shadow and a wide soft one, clearly higher than a resting card and lower than an overlay. */
91
139
  --zx-drag-shadow: 0 2px 4px -1px color-mix(in srgb, var(--zx-gray-950) 10%, transparent),
92
140
  0 12px 28px -6px color-mix(in srgb, var(--zx-gray-950) 22%, transparent);
93
- /* Blur applied behind a backdrop that asked for it. Theme-independent, so light defines it once. */
94
- --zx-overlay-blur: 8px;
95
141
  --zx-color-glass-border: color-mix(in srgb, var(--zx-gray-0) 24%, transparent);
96
142
  --zx-color-glass-highlight: color-mix(in srgb, var(--zx-gray-0) 24%, transparent);
97
143
  --zx-color-glass-highlight-strong: color-mix(in srgb, var(--zx-gray-0) 38%, transparent);
98
- /* AppIcon is a dark chromatic lens: colour lives in its rim and low bloom, not a glossy fill. */
99
- /* Strengths remain inherited, while each AppIcon mixes them with its own module colour. */
100
- --zx-app-icon-core-strength: 52%;
101
- --zx-app-icon-rim-strength: 58%;
102
- --zx-app-icon-bloom-strength: 64%;
103
- --zx-app-icon-specular-strength: 72%;
104
- --zx-app-icon-halo-size: 14px;
105
- --zx-app-icon-halo-strength: 22%;
106
144
  --zx-color-overlay-backdrop: color-mix(in srgb, var(--zx-gray-950) 28%, transparent);
107
- --zx-overlay-specular-strength: 48%;
108
- --zx-glass-blur: 8px;
109
- --zx-glass-saturation: 130%;
110
- --zx-glass-color-strength: 82%;
111
- /* Material filters are roles, not component recipes. Aurora remains a separate canvas layer. */
112
- --zx-glass-filter-icon: blur(4px) saturate(118%);
113
- --zx-glass-filter-control: blur(6px) saturate(116%);
114
- --zx-glass-filter-raised: blur(8px) saturate(120%);
115
- --zx-glass-filter-chrome: blur(10px) saturate(122%);
116
- --zx-glass-filter-overlay: blur(16px) saturate(140%);
117
- --zx-glass-filter-panel: blur(14px) saturate(132%);
118
145
  --zx-glass-control-shadow: inset 0 1px 0 color-mix(in srgb, var(--zx-gray-0) 18%, transparent), var(--zx-shadow-1);
119
146
  --zx-glass-chrome-shadow: inset 0 1px 0 color-mix(in srgb, var(--zx-gray-0) 16%, transparent), var(--zx-shadow-1);
120
147
  --zx-header-bg: var(--zx-gray-900);
@@ -126,8 +153,9 @@
126
153
  * tone tints — are restated on every theme element, not only on :root. A custom property is
127
154
  * resolved where it is declared and inherited as a finished value, so a dark region on a light
128
155
  * page would otherwise inherit light glass and light overlays. The dark theme, which loads later,
129
- * overrides the ones it derives differently. Geometry and the base palette stay on :root, so an
130
- * application's own overrides there still reach nested regions.
156
+ * overrides the ones it derives differently. Geometry and the base palette stay on :root (the block
157
+ * at the top of this file and tokens/global.css), so an application's own overrides there still
158
+ * reach nested regions.
131
159
  */
132
160
  :root,
133
161
  [data-zx-theme] {
package/styles/zx.css CHANGED
@@ -37,7 +37,9 @@
37
37
  @import url("../src/components/activity-item/activity-item.css");
38
38
  @import url("../src/components/activity-list/activity-list.css");
39
39
  @import url("../src/components/account-menu/account-menu.css");
40
+ @import url("../src/components/workspace-switcher/workspace-switcher.css");
40
41
  @import url("../src/components/app-rail/app-rail.css");
42
+ @import url("../src/components/module-bar/module-bar.css");
41
43
  @import url("../src/components/app-sidebar/app-sidebar.css");
42
44
  @import url("../src/components/message/message.css");
43
45
  @import url("../src/components/modal/modal.css");
@@ -68,6 +70,7 @@
68
70
  @import url("../src/components/stat-tile/stat-tile.css");
69
71
  @import url("../src/components/card-view/card-view.css");
70
72
  @import url("../src/components/kanban-view/kanban-view.css");
73
+ @import url("../src/components/view-settings/view-settings.css");
71
74
  @import url("../src/components/grid/grid.css");
72
75
  @import url("../src/components/chart/chart.css");
73
76
  @import url("../src/components/tree/tree.css");