@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
@@ -42,12 +42,12 @@ import { uid } from '../../core/util.js';
42
42
  * @property {number} [debounce=250] Source-query delay in milliseconds.
43
43
  * @property {number} [minQuery=0] Global source minimum query length.
44
44
  * @property {number} [maxResults=100] Maximum combined results.
45
- * @property {string} [placeholder='Search applications and records'] Search-field placeholder.
46
- * @property {string} [label='Launcher'] Dialog and field label.
47
- * @property {string} [closeLabel='Close launcher'] Close-button accessible label.
48
- * @property {string} [resultsLabel='Launcher results'] Results-region accessible label.
49
- * @property {string} [emptyText='No results'] Empty-state text.
50
- * @property {string} [loadingText='Searching…'] Loading-state text.
45
+ * @property {string} [placeholder] Search-field placeholder. Omitted resolves `launcher.placeholder`, English `Search applications and records`.
46
+ * @property {string} [label] Dialog and field label. Omitted resolves `launcher.label`, English `Launcher`.
47
+ * @property {string} [closeLabel] Close-button accessible label. Omitted resolves `launcher.close`, English `Close launcher`.
48
+ * @property {string} [resultsLabel] Results-region accessible label. Omitted resolves `launcher.results`, English `Launcher results`.
49
+ * @property {string} [emptyText] Empty-state text. Omitted resolves `launcher.empty`, English `No results`.
50
+ * @property {string} [loadingText] Loading-state text. Omitted resolves `launcher.loading`, English `Searching…`.
51
51
  * @property {'mod+k'|false} [shortcut='mod+k'] Optional global keyboard shortcut.
52
52
  * @property {false|{move?: string, open?: string, close?: string}} [hints] Visible keyboard hints, or false.
53
53
  * @property {Element|string|null} [scope=null] Element whose nearest Zx theme scope owns an internally created launcher; defaults to the opener.
@@ -80,14 +80,20 @@ export class Launcher extends Component {
80
80
  debounce: 250,
81
81
  minQuery: 0,
82
82
  maxResults: 100,
83
- placeholder: 'Search applications and records',
84
- label: 'Launcher',
85
- closeLabel: 'Close launcher',
86
- resultsLabel: 'Launcher results',
87
- emptyText: 'No results',
88
- loadingText: 'Searching…',
83
+ /*
84
+ * The six labels default to null rather than to their English text so that an application
85
+ * which installs a translator and passes no labels still gets a translated launcher. The
86
+ * documented default is what `_message()` falls back to, so an untranslated application
87
+ * renders exactly the same words as before.
88
+ */
89
+ placeholder: null,
90
+ label: null,
91
+ closeLabel: null,
92
+ resultsLabel: null,
93
+ emptyText: null,
94
+ loadingText: null,
89
95
  shortcut: 'mod+k',
90
- hints: { move: 'Move', open: 'Open', close: 'Close' },
96
+ hints: null,
91
97
  scope: null
92
98
  };
93
99
 
@@ -126,6 +132,7 @@ export class Launcher extends Component {
126
132
  this._destroyed = false;
127
133
 
128
134
  const listId = uid('zx-launcher-results');
135
+ const label = String(this.options.label ?? this._message('launcher.label', 'Launcher'));
129
136
  const input = h('input', {
130
137
  ref: 'input',
131
138
  class: 'zx-launcher__input',
@@ -136,15 +143,15 @@ export class Launcher extends Component {
136
143
  ariaAutocomplete: 'list',
137
144
  ariaControls: listId,
138
145
  ariaExpanded: 'false',
139
- ariaLabel: this.options.label,
140
- placeholder: this.options.placeholder,
146
+ ariaLabel: label,
147
+ placeholder: this.options.placeholder ?? this._message('launcher.placeholder', 'Search applications and records'),
141
148
  value: this._query
142
149
  });
143
150
  const close = h('button', {
144
151
  ref: 'close',
145
152
  class: 'zx-icon-btn zx-launcher__close',
146
153
  type: 'button',
147
- ariaLabel: this.options.closeLabel
154
+ ariaLabel: this.options.closeLabel ?? this._message('launcher.close', 'Close launcher')
148
155
  }, icon('x'));
149
156
  const status = h('div', {
150
157
  ref: 'status',
@@ -157,14 +164,18 @@ export class Launcher extends Component {
157
164
  class: 'zx-launcher__results',
158
165
  id: listId,
159
166
  role: 'listbox',
160
- ariaLabel: this.options.resultsLabel
167
+ ariaLabel: this.options.resultsLabel ?? this._message('launcher.results', 'Launcher results')
161
168
  });
162
169
  const shortcut = this.options.shortcut === 'mod+k' ? h('kbd', {
163
170
  class: 'zx-launcher__shortcut',
164
171
  ariaHidden: 'true'
165
172
  }, launcherShortcutLabel()) : null;
166
- const footer = launcherHints(this.options.hints);
167
- dialog.setAttribute('aria-label', String(this.options.label));
173
+ const footer = launcherHints(this.options.hints, {
174
+ move: this._message('launcher.hintMove', 'Move'),
175
+ open: this._message('launcher.hintOpen', 'Open'),
176
+ close: this._message('launcher.hintClose', 'Close')
177
+ });
178
+ dialog.setAttribute('aria-label', label);
168
179
  dialog.replaceChildren(
169
180
  h('div', { class: 'zx-launcher__surface' },
170
181
  h('div', {
@@ -458,9 +469,15 @@ export class Launcher extends Component {
458
469
 
459
470
  /** @returns {void} */
460
471
  _renderStatus() {
461
- if (this._busy) this.refs.status.textContent = String(this.options.loadingText);
462
- else if (this._results.length === 0) this.refs.status.textContent = String(this.options.emptyText);
463
- else this.refs.status.textContent = '';
472
+ if (this._busy) {
473
+ this.refs.status.textContent = String(this.options.loadingText
474
+ ?? this._message('launcher.loading', 'Searching…'));
475
+ } else if (this._results.length === 0) {
476
+ this.refs.status.textContent = String(this.options.emptyText
477
+ ?? this._message('launcher.empty', 'No results'));
478
+ } else {
479
+ this.refs.status.textContent = '';
480
+ }
464
481
  this.refs.status.hidden = !this.refs.status.textContent;
465
482
  }
466
483
 
@@ -566,6 +583,17 @@ export class Launcher extends Component {
566
583
  event.preventDefault();
567
584
  this.open();
568
585
  }
586
+
587
+ /**
588
+ * Resolves a message through the host translator, falling back to the built-in English text.
589
+ * @param {string} key Message key.
590
+ * @param {string} fallback English default.
591
+ * @returns {string}
592
+ */
593
+ _message(key, fallback) {
594
+ const message = this.msg(key);
595
+ return message === key ? fallback : message;
596
+ }
569
597
  }
570
598
 
571
599
  /** @returns {string} */
@@ -575,14 +603,18 @@ function launcherShortcutLabel() {
575
603
  return /mac|iphone|ipad/i.test(platform) ? '⌘ K' : 'Ctrl K';
576
604
  }
577
605
 
578
- /** @param {LauncherOptions['hints']} hints @returns {HTMLElement|null} */
579
- function launcherHints(hints) {
606
+ /**
607
+ * @param {LauncherOptions['hints']} hints Host-supplied hint labels, or false to omit the row.
608
+ * @param {{move: string, open: string, close: string}} defaults Resolved built-in labels.
609
+ * @returns {HTMLElement|null}
610
+ */
611
+ function launcherHints(hints, defaults) {
580
612
  if (hints === false) return null;
581
613
  const labels = hints && typeof hints === 'object' ? hints : {};
582
614
  return h('footer', { class: 'zx-launcher__hints', ariaHidden: 'true' },
583
- h('span', {}, h('kbd', {}, '↑↓←→'), labels.move ?? 'Move'),
584
- h('span', {}, h('kbd', {}, '↵'), labels.open ?? 'Open'),
585
- h('span', {}, h('kbd', {}, 'Esc'), labels.close ?? 'Close'));
615
+ h('span', {}, h('kbd', {}, '↑↓←→'), labels.move ?? defaults.move),
616
+ h('span', {}, h('kbd', {}, '↵'), labels.open ?? defaults.open),
617
+ h('span', {}, h('kbd', {}, 'Esc'), labels.close ?? defaults.close));
586
618
  }
587
619
 
588
620
  /** @param {LauncherItem} item @returns {Node|null} */
@@ -0,0 +1,189 @@
1
+ /*
2
+ * The bar above a record view. It wraps rather than collapsing: `Toolbar` moves what no longer
3
+ * fits into an overflow menu, and the first thing that menu would swallow is the tool whose badge
4
+ * explains why the list is showing four rows out of twenty.
5
+ */
6
+ .zx-list-toolbar {
7
+ /* A size container so the labels answer to the width of the bar rather than of the window: the
8
+ same toolbar sits above a full-page list and inside a narrow master panel. The width it
9
+ cannot derive from its own contents is declared here, as size containment requires. */
10
+ container-type: inline-size;
11
+ inline-size: 100%;
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ align-items: center;
15
+ gap: var(--zx-space-2);
16
+ min-inline-size: 0;
17
+ }
18
+
19
+ /*
20
+ * The search field takes the slack and gives it back first. Its hypothetical width is what decides
21
+ * whether the row fits on one line — flex breaks lines on base sizes, not on shrunk ones — so the
22
+ * field is declared narrow and allowed to grow into whatever the tools leave, up to a width past
23
+ * which a longer text box helps nobody.
24
+ */
25
+ .zx-list-toolbar > .zx-list-toolbar__search {
26
+ flex: 1 1 12rem;
27
+ max-inline-size: 22rem;
28
+ min-inline-size: 0;
29
+ }
30
+
31
+ .zx-list-toolbar > .zx-list-toolbar__search .zx-search__input {
32
+ min-inline-size: 8rem;
33
+ }
34
+
35
+ /*
36
+ * The live count line. It is never hidden and never given `display: none`: a live region has to be
37
+ * in the accessibility tree before its text changes, and an empty inline element in a row that
38
+ * already ends in blank space costs nothing to leave in place.
39
+ */
40
+ .zx-list-toolbar__count {
41
+ flex: 0 1 auto;
42
+ min-inline-size: 0;
43
+ color: var(--zx-color-text-muted);
44
+ font-size: var(--zx-text-sm);
45
+ white-space: nowrap;
46
+ overflow: hidden;
47
+ text-overflow: ellipsis;
48
+ }
49
+
50
+ .zx-list-toolbar__spacer {
51
+ flex: 1 1 auto;
52
+ min-inline-size: 0;
53
+ }
54
+
55
+ .zx-list-toolbar__tools,
56
+ .zx-list-toolbar__views {
57
+ display: flex;
58
+ flex-wrap: wrap;
59
+ align-items: center;
60
+ gap: var(--zx-space-1);
61
+ }
62
+
63
+ .zx-list-toolbar__views {
64
+ gap: 0;
65
+ border: 1px solid var(--zx-color-border-control);
66
+ border-radius: var(--zx-control-radius);
67
+ padding: 2px;
68
+ }
69
+
70
+ /*
71
+ * WCAG 2.5.5 Target Size: 44 px, in both densities. Density tightens a layout; it does not make
72
+ * a finger smaller, so this floor is deliberately not expressed through --zx-control-height
73
+ * (32 px cozy, 28 px compact) the way the rest of the controls in this row are. The chrome is flat
74
+ * until the tool is hovered, focused, or pressed, so a target this size does not read as a slab.
75
+ */
76
+ .zx-list-toolbar__tool {
77
+ position: relative;
78
+ display: inline-flex;
79
+ align-items: center;
80
+ justify-content: center;
81
+ gap: var(--zx-space-2);
82
+ min-block-size: 44px;
83
+ min-inline-size: 44px;
84
+ padding-inline: var(--zx-space-2);
85
+ border: 1px solid transparent;
86
+ border-radius: var(--zx-control-radius);
87
+ background: none;
88
+ color: var(--zx-color-text);
89
+ font-size: var(--zx-control-font-size);
90
+ font-weight: var(--zx-control-font-weight);
91
+ line-height: 1.2;
92
+ cursor: pointer;
93
+ }
94
+
95
+ .zx-list-toolbar__tool:hover:not(:disabled) {
96
+ background: var(--zx-color-bg-hover);
97
+ }
98
+
99
+ .zx-list-toolbar__tool:focus-visible {
100
+ box-shadow: var(--zx-focus-ring);
101
+ }
102
+
103
+ /* A pressed tool is marked three ways — the state in `aria-pressed`, a filled ground, and a
104
+ border where the other states have none — so it never rests on colour alone. */
105
+ .zx-list-toolbar__tool[aria-pressed="true"] {
106
+ border-color: var(--zx-color-border-strong);
107
+ background: var(--zx-color-bg-selected);
108
+ }
109
+
110
+ .zx-list-toolbar__tool:disabled {
111
+ color: var(--zx-color-text-placeholder);
112
+ cursor: default;
113
+ }
114
+
115
+ .zx-list-toolbar__tool-label {
116
+ white-space: nowrap;
117
+ }
118
+
119
+ /* The badge is decoration here: its number is already in the button's accessible name, so it must
120
+ not swallow the click that names it either. */
121
+ .zx-list-toolbar__badge {
122
+ pointer-events: none;
123
+ }
124
+
125
+ .zx-list-toolbar__view {
126
+ position: relative;
127
+ display: inline-flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ gap: var(--zx-space-1);
131
+ min-block-size: 44px;
132
+ min-inline-size: 44px;
133
+ padding-inline: var(--zx-space-2);
134
+ border: 0;
135
+ border-radius: calc(var(--zx-control-radius) - 2px);
136
+ background: none;
137
+ color: var(--zx-color-text-muted);
138
+ font-size: var(--zx-control-font-size);
139
+ font-weight: var(--zx-control-font-weight);
140
+ line-height: 1.2;
141
+ cursor: pointer;
142
+ }
143
+
144
+ .zx-list-toolbar__view:hover {
145
+ color: var(--zx-color-text);
146
+ background: var(--zx-color-bg-hover);
147
+ }
148
+
149
+ .zx-list-toolbar__view:focus-visible {
150
+ box-shadow: var(--zx-focus-ring);
151
+ }
152
+
153
+ .zx-list-toolbar__view[aria-pressed="true"] {
154
+ background: var(--zx-color-bg-selected);
155
+ color: var(--zx-color-text);
156
+ }
157
+
158
+ @media (prefers-reduced-motion: no-preference) {
159
+ .zx-list-toolbar__tool,
160
+ .zx-list-toolbar__view {
161
+ transition: background-color var(--zx-dur-fast) var(--zx-ease),
162
+ color var(--zx-dur-fast) var(--zx-ease),
163
+ border-color var(--zx-dur-fast) var(--zx-ease);
164
+ }
165
+ }
166
+
167
+ /*
168
+ * Below a phone-width bar the labels go and the row becomes: field, count, icons. The targets stay
169
+ * 44 px — a narrow viewport is where that matters most — and the names survive in `aria-label`,
170
+ * which is where a tool's badge already lives.
171
+ *
172
+ * Only a control that has an icon left to stand for it gives up its word: `:has()` keeps a
173
+ * label-only entry — the `auto` shape, which no glyph in the set honestly describes — readable
174
+ * instead of collapsing it into an empty button. The label is clipped rather than removed, so it
175
+ * stays the accessible name of a view button either way.
176
+ */
177
+ @container (max-inline-size: 30rem) {
178
+ .zx-list-toolbar__tool:has(.zx-icon) .zx-list-toolbar__tool-label,
179
+ .zx-list-toolbar__view:has(.zx-icon) .zx-list-toolbar__view-label {
180
+ position: absolute;
181
+ inline-size: 1px;
182
+ block-size: 1px;
183
+ margin: -1px;
184
+ padding: 0;
185
+ overflow: hidden;
186
+ clip-path: inset(50%);
187
+ white-space: nowrap;
188
+ }
189
+ }