@zeyos/zx 2.3.0 → 4.0.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 (150) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/DESIGN-SYSTEM.md +96 -0
  3. package/README.md +29 -39
  4. package/dist/types/components/account-menu/account-menu.d.ts +144 -0
  5. package/dist/types/components/app-sidebar/app-sidebar.d.ts +243 -0
  6. package/dist/types/components/avatar/avatar.d.ts +100 -0
  7. package/dist/types/components/card/card.d.ts +128 -0
  8. package/dist/types/components/chart/chart.d.ts +322 -0
  9. package/dist/types/components/date-picker/month-picker.d.ts +6 -0
  10. package/dist/types/components/dialog/dialog.d.ts +9 -0
  11. package/dist/types/components/dock/dock.d.ts +495 -0
  12. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  13. package/dist/types/components/field/field.d.ts +14 -0
  14. package/dist/types/components/field-upload/field-upload.d.ts +37 -4
  15. package/dist/types/components/form/form.d.ts +25 -3
  16. package/dist/types/components/grid/grid.d.ts +172 -0
  17. package/dist/types/components/launcher/launcher.d.ts +359 -0
  18. package/dist/types/components/layout/layout.d.ts +4 -4
  19. package/dist/types/components/menu-button/menu-button.d.ts +10 -2
  20. package/dist/types/components/modal/modal.d.ts +25 -0
  21. package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +7 -1
  22. package/dist/types/components/questionnaire/items.d.ts +327 -0
  23. package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
  24. package/dist/types/components/select/select.d.ts +51 -0
  25. package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
  26. package/dist/types/components/sheet/sheet.d.ts +294 -0
  27. package/dist/types/components/split-view/split-view.d.ts +2 -21
  28. package/dist/types/components/table/table.d.ts +223 -15
  29. package/dist/types/components/tooltip/tooltip.d.ts +2 -2
  30. package/dist/types/components/value-list/value-list.d.ts +24 -3
  31. package/dist/types/core/dom.d.ts +122 -0
  32. package/dist/types/core/drag-axis.d.ts +111 -0
  33. package/dist/types/core/position.d.ts +4 -2
  34. package/dist/types/index.d.ts +13 -2
  35. package/dist/types/internal/app-rail.d.ts +265 -0
  36. package/dist/types/zeyos/icons.d.ts +5 -0
  37. package/dist/types/zeyos/index.d.ts +2 -1
  38. package/dist/types/zeyos/launcher.d.ts +147 -0
  39. package/dist/types/zeyos/select.d.ts +39 -0
  40. package/dist/zx-zeyos.esm.js +1870 -133
  41. package/dist/zx-zeyos.esm.min.js +1 -1
  42. package/dist/zx.css +2006 -267
  43. package/dist/zx.esm.js +8987 -2757
  44. package/dist/zx.esm.min.js +3 -3
  45. package/dist/zx.global.js +8987 -2757
  46. package/dist/zx.global.min.js +3 -3
  47. package/dist/zx.min.css +1 -1
  48. package/docs/api.json +4396 -2344
  49. package/docs/llms.md +463 -86
  50. package/docs/llms.txt +32 -19
  51. package/package.json +10 -17
  52. package/src/components/account-menu/account-menu.css +70 -0
  53. package/src/components/account-menu/account-menu.js +208 -0
  54. package/src/components/app-rail/app-rail.css +107 -0
  55. package/src/components/app-sidebar/app-sidebar.css +80 -0
  56. package/src/components/app-sidebar/app-sidebar.js +588 -0
  57. package/src/components/avatar/avatar.css +61 -0
  58. package/src/components/avatar/avatar.js +222 -0
  59. package/src/components/button/button.css +0 -1
  60. package/src/components/card/card.css +149 -0
  61. package/src/components/card/card.js +285 -0
  62. package/src/components/chart/chart.css +61 -0
  63. package/src/components/chart/chart.js +523 -0
  64. package/src/components/date-picker/month-picker.js +9 -0
  65. package/src/components/dialog/dialog.js +11 -4
  66. package/src/components/dock/dock.css +228 -0
  67. package/src/components/dock/dock.js +977 -0
  68. package/src/components/dropdown/dropdown.js +1 -1
  69. package/src/components/field/field.js +2 -0
  70. package/src/components/field-upload/field-upload.js +9 -4
  71. package/src/components/form/form.js +6 -3
  72. package/src/components/grid/grid.css +6 -0
  73. package/src/components/grid/grid.js +220 -0
  74. package/src/components/launcher/launcher.css +210 -0
  75. package/src/components/launcher/launcher.js +765 -0
  76. package/src/components/layout/layout.js +2 -2
  77. package/src/components/menu-button/menu-button.js +27 -2
  78. package/src/components/modal/modal.css +5 -1
  79. package/src/components/modal/modal.js +37 -2
  80. package/src/components/multi-value-editor/multi-value-editor.js +2 -1
  81. package/src/components/questionnaire/items.js +370 -0
  82. package/src/components/questionnaire/questionnaire.css +387 -0
  83. package/src/components/questionnaire/questionnaire.js +1033 -0
  84. package/src/components/select/field-adapter.js +9 -4
  85. package/src/components/select/select.css +144 -11
  86. package/src/components/select/select.js +259 -27
  87. package/src/components/sheet/sheet-stack.js +304 -0
  88. package/src/components/sheet/sheet.css +351 -0
  89. package/src/components/sheet/sheet.js +551 -0
  90. package/src/components/split-view/split-view.js +76 -161
  91. package/src/components/table/table.css +43 -0
  92. package/src/components/table/table.js +531 -52
  93. package/src/components/tooltip/tooltip.js +5 -2
  94. package/src/components/value-list/value-list.js +6 -3
  95. package/src/core/dom.js +322 -0
  96. package/src/core/drag-axis.js +203 -0
  97. package/src/core/position.js +68 -22
  98. package/src/index.js +20 -2
  99. package/src/internal/app-rail.js +718 -0
  100. package/src/zeyos/icons.js +8 -3
  101. package/src/zeyos/index.js +7 -1
  102. package/src/zeyos/launcher.js +338 -0
  103. package/src/zeyos/modules.js +1 -0
  104. package/src/zeyos/select.js +115 -1
  105. package/styles/tokens/dark.css +2 -3
  106. package/styles/tokens/global.css +6 -6
  107. package/styles/tokens/modules.css +1 -0
  108. package/styles/tokens/semantic.css +5 -3
  109. package/styles/tokens/themes.css +1 -1
  110. package/styles/zx.css +11 -1
  111. package/MIGRATION.md +0 -598
  112. package/dist/types/compat/base.d.ts +0 -156
  113. package/dist/types/compat/globals.d.ts +0 -20
  114. package/dist/types/compat/index.d.ts +0 -128
  115. package/dist/types/compat/map/basic.d.ts +0 -175
  116. package/dist/types/compat/map/data.d.ts +0 -102
  117. package/dist/types/compat/map/date-time.d.ts +0 -80
  118. package/dist/types/compat/map/factory.d.ts +0 -9
  119. package/dist/types/compat/map/form.d.ts +0 -98
  120. package/dist/types/compat/map/helpers.d.ts +0 -12
  121. package/dist/types/compat/map/http.d.ts +0 -36
  122. package/dist/types/compat/map/layout.d.ts +0 -106
  123. package/dist/types/compat/map/options.d.ts +0 -80
  124. package/dist/types/compat/map/select.d.ts +0 -95
  125. package/dist/types/compat/map/stubs.d.ts +0 -32
  126. package/dist/types/compat/map/utilities.d.ts +0 -37
  127. package/dist/types/compat-entry.d.ts +0 -5
  128. package/dist/types/components/permission/permission.d.ts +0 -96
  129. package/dist/zx-compat.esm.js +0 -17484
  130. package/dist/zx-compat.esm.min.js +0 -1
  131. package/dist/zx-compat.global.js +0 -23635
  132. package/dist/zx-compat.global.min.js +0 -3
  133. package/src/compat/base.js +0 -291
  134. package/src/compat/globals.js +0 -165
  135. package/src/compat/index.js +0 -84
  136. package/src/compat/map/basic.js +0 -464
  137. package/src/compat/map/data.js +0 -232
  138. package/src/compat/map/date-time.js +0 -177
  139. package/src/compat/map/factory.js +0 -45
  140. package/src/compat/map/form.js +0 -330
  141. package/src/compat/map/helpers.js +0 -46
  142. package/src/compat/map/http.js +0 -117
  143. package/src/compat/map/layout.js +0 -256
  144. package/src/compat/map/options.js +0 -267
  145. package/src/compat/map/select.js +0 -198
  146. package/src/compat/map/stubs.js +0 -26
  147. package/src/compat/map/utilities.js +0 -113
  148. package/src/compat-entry.js +0 -11
  149. package/src/components/permission/permission.css +0 -47
  150. package/src/components/permission/permission.js +0 -201
@@ -9,7 +9,7 @@ const HANDLE_ESCAPE_DISMISS = Symbol('zxDropdownEscapeDismiss');
9
9
  /**
10
10
  * @typedef {Object} DropdownOptions
11
11
  * @property {Node|string|number|{toElement: () => Node|null}|null} [content=null] Panel content.
12
- * @property {'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'} [placement='bottom-start'] Panel placement.
12
+ * @property {'bottom-start'|'bottom-end'|'top-start'|'top-end'|'bottom'|'top'|'right-start'|'right-end'|'left-start'|'left-end'|'right'|'left'} [placement='bottom-start'] Panel placement.
13
13
  * @property {number} [offset=4] Gap between anchor and panel in pixels.
14
14
  * @property {boolean} [matchWidth=false] Whether the panel matches the anchor width.
15
15
  * @property {'click'|'manual'} [openOn='click'] Trigger behavior.
@@ -16,6 +16,8 @@ import { uid } from '../../core/util.js';
16
16
  * @property {'stack'|'inline'} [layout='stack'] Label/control layout.
17
17
  * @property {Record<string, unknown>} [props={}] Adapter-specific control properties.
18
18
  * @property {FieldAdapterFactory} [adapter] Adapter used by the `custom` type.
19
+ * @property {(event: CustomEvent<{value: unknown}>) => void} [onchange] Value change listener.
20
+ * @property {(event: CustomEvent<{message: string}>) => void} [oninvalid] Validation failure listener.
19
21
  */
20
22
 
21
23
  /**
@@ -30,6 +30,11 @@ import { uid } from '../../core/util.js';
30
30
  * @property {boolean} [autoUpload=true] Upload immediately after selection.
31
31
  * @property {boolean} [preview=true] Show a preview for the first selected image.
32
32
  * @property {UploadTransport|null} [http=null] Injected Http-compatible or stub upload transport.
33
+ * @property {(event: CustomEvent<{files: File[]}>) => void} [onselect] File selection listener.
34
+ * @property {(event: CustomEvent<{percent: number}>) => void} [onprogress] Upload progress listener.
35
+ * @property {(event: CustomEvent<{response: unknown}>) => void} [onsuccess] Upload success listener.
36
+ * @property {(event: CustomEvent<{error: Error}>) => void} [onerror] Upload failure listener.
37
+ * @property {(event: CustomEvent<Record<string, never>>) => void} [onabort] Upload abort listener.
33
38
  */
34
39
 
35
40
  /**
@@ -447,25 +452,25 @@ function abortError() {
447
452
  /**
448
453
  * Files selected event.
449
454
  * @event FieldUpload#select
450
- * @type {CustomEvent<{files: File[]}>
455
+ * @type {CustomEvent<{files: File[]}>}
451
456
  */
452
457
 
453
458
  /**
454
459
  * Upload progress event.
455
460
  * @event FieldUpload#progress
456
- * @type {CustomEvent<{percent: number}>
461
+ * @type {CustomEvent<{percent: number}>}
457
462
  */
458
463
 
459
464
  /**
460
465
  * Upload success event.
461
466
  * @event FieldUpload#success
462
- * @type {CustomEvent<{response: unknown}>
467
+ * @type {CustomEvent<{response: unknown}>}
463
468
  */
464
469
 
465
470
  /**
466
471
  * Upload failure event.
467
472
  * @event FieldUpload#error
468
- * @type {CustomEvent<{error: Error}>
473
+ * @type {CustomEvent<{error: Error}>}
469
474
  */
470
475
 
471
476
  /**
@@ -22,6 +22,9 @@ import { coerceFloat, coerceInteger } from '../field/field.js';
22
22
  * @property {Array<Fieldset|import('../fieldset/fieldset.js').FieldsetOptions>} [fieldsets=[]] Initial fieldsets.
23
23
  * @property {FormAction[]} [actions=[]] Form action descriptors.
24
24
  * @property {boolean} [novalidate=true] Native `novalidate` state.
25
+ * @property {(event: CustomEvent<{values: Record<string, unknown>}>) => void} [onsubmit] Submit listener.
26
+ * @property {(event: CustomEvent<{errors: Record<string, string>}>) => void} [oninvalid] Invalid listener.
27
+ * @property {(event: CustomEvent<{id: string, value: unknown}>) => void} [onchange] Field change listener.
25
28
  */
26
29
 
27
30
  /**
@@ -286,17 +289,17 @@ function isEmpty(value) {
286
289
  /**
287
290
  * Successful form submission event.
288
291
  * @event Form#submit
289
- * @type {CustomEvent<{values: Record<string, unknown>}>
292
+ * @type {CustomEvent<{values: Record<string, unknown>}>}
290
293
  */
291
294
 
292
295
  /**
293
296
  * Form validation failure event.
294
297
  * @event Form#invalid
295
- * @type {CustomEvent<{errors: Record<string, string>}>
298
+ * @type {CustomEvent<{errors: Record<string, string>}>}
296
299
  */
297
300
 
298
301
  /**
299
302
  * Delegated field value change event.
300
303
  * @event Form#change
301
- * @type {CustomEvent<{id: string, value: unknown}>
304
+ * @type {CustomEvent<{id: string, value: unknown}>}
302
305
  */
@@ -0,0 +1,6 @@
1
+ /* Data Grid intentionally renders the Table block. Preset-only treatment stays narrowly scoped so
2
+ the lowercase `.zx-grid` layout helper remains a separate, unchanged primitive. */
3
+ .zx-table[data-preset="billing-items"] tr.zx-grid-billing__summary > td {
4
+ background: var(--zx-color-bg-subtle);
5
+ font-weight: 700;
6
+ }
@@ -0,0 +1,220 @@
1
+ import { Table } from '../table/table.js';
2
+
3
+ /** @typedef {Record<string, any>} BillingRow */
4
+ /**
5
+ * @typedef {Object} GridOptions
6
+ * Grid inherits its constructor options and runtime API from `Table`; this record owns the Grid
7
+ * name in generated documentation, where the Table API is shown alongside it.
8
+ */
9
+ /**
10
+ * @typedef {Object} BillingFields
11
+ * @property {string} [id='id'] Row identifier field.
12
+ * @property {string} [parent='parent'] Parent identifier field.
13
+ * @property {string} [item='item'] Line description field.
14
+ * @property {string} [kind='kind'] Line-kind field (`group`/`subtotal` rows are read-only).
15
+ * @property {string} [quantity='quantity'] Quantity field.
16
+ * @property {string} [unit='unit'] Unit field.
17
+ * @property {string} [unitPrice='unitPrice'] Unit-price field.
18
+ * @property {string} [currency='currency'] Currency-code field.
19
+ * @property {string} [total='total'] Line-total field.
20
+ */
21
+ /**
22
+ * @typedef {Object} BillingItemsOptions
23
+ * @property {BillingRow[]} [data=[]] Billing rows.
24
+ * @property {Partial<BillingFields>} [fields={}] Schema field overrides.
25
+ * @property {Array<{value: unknown, label: string}>|Record<string, string>} [units=[]] Unit choices.
26
+ * @property {Array<{value: unknown, label: string}>|Record<string, string>} [currencies=[]] Currency choices.
27
+ * @property {string} [currency='EUR'] Fallback currency.
28
+ * @property {string} [locale] Number/currency locale.
29
+ * @property {number} [decimals=2] Currency fraction digits.
30
+ * @property {Record<string, object>} [columnOverrides={}] Per-canonical-column overrides.
31
+ * @property {(row: BillingRow, changes: Record<string, unknown>) => number|null|undefined} [lineTotal] Optional total calculation; defaults to quantity × unit price.
32
+ * @property {import('../table/table.js').TableColumn[]} [columns] Complete column replacement.
33
+ * @property {(event: CustomEvent<import('../table/table.js').TableEditCommitDetail>) => void} [oneditcommit] Caller edit listener, invoked after total calculation.
34
+ */
35
+
36
+ /**
37
+ * Public data grid. It deliberately inherits Table's DOM/CSS/API instead of forking the data layer.
38
+ * @extends {Table}
39
+ */
40
+ export class Grid extends Table {
41
+ // The lowercase `grid()` layout factory owns `.zx-grid`; the data Grid is a Table specialization.
42
+ static cssName = 'table';
43
+
44
+ /**
45
+ * Creates a generic data grid with the complete inherited Table contract.
46
+ * @param {Element|string|null} target Grid target.
47
+ * @param {GridOptions & import('../table/table.js').TableOptions} [options={}] Grid/Table options.
48
+ */
49
+ constructor(target = null, options = {}) {
50
+ super(target, options);
51
+ }
52
+
53
+ /**
54
+ * Creates an editable hierarchical billing-line grid.
55
+ * @param {Element|string|null} target Grid target.
56
+ * @param {BillingItemsOptions & import('../table/table.js').TableOptions} [options={}] Preset and Table overrides.
57
+ * @returns {Grid}
58
+ */
59
+ static BillingItems(target, options = {}) {
60
+ const grid = new Grid(target, billingItemsConfig(options));
61
+ grid.el.dataset.preset = 'billing-items';
62
+ return grid;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Builds the Table-compatible options behind `Grid.BillingItems()` without touching the DOM.
68
+ * @param {BillingItemsOptions & import('../table/table.js').TableOptions} [options={}] Preset and Table overrides.
69
+ * @returns {import('../table/table.js').TableOptions}
70
+ */
71
+ export function billingItemsConfig(options = {}) {
72
+ const {
73
+ fields: requestedFields = {},
74
+ units = [],
75
+ currencies = [],
76
+ currency = 'EUR',
77
+ locale,
78
+ decimals = 2,
79
+ columnOverrides = {},
80
+ lineTotal = null,
81
+ columns: suppliedColumns,
82
+ oneditcommit,
83
+ rowClass,
84
+ ...tableOptions
85
+ } = options;
86
+ const fields = { ...DEFAULT_FIELDS, ...requestedFields };
87
+ const calculateLineTotal = typeof lineTotal === 'function' ? lineTotal : (row) => {
88
+ const quantity = billingNumber(row?.[fields.quantity]);
89
+ const price = billingNumber(row?.[fields.unitPrice]);
90
+ return quantity !== null && price !== null ? quantity * price : null;
91
+ };
92
+ const columns = Array.isArray(suppliedColumns) ? suppliedColumns.map((column) => ({ ...column }))
93
+ : billingColumns(fields, { units, currencies, currency, locale, decimals, columnOverrides });
94
+ return {
95
+ rowId: fields.id,
96
+ editMode: 'cell',
97
+ hierarchy: { parentId: fields.parent, column: fields.item, expanded: true },
98
+ responsive: 'sm',
99
+ ...tableOptions,
100
+ columns,
101
+ rowClass(row) {
102
+ const own = isBillingLine(row, fields) ? '' : 'zx-grid-billing__summary';
103
+ const supplied = typeof rowClass === 'function' ? rowClass(row) : '';
104
+ return [own, supplied].filter(Boolean).join(' ');
105
+ },
106
+ oneditcommit(event) {
107
+ const { row, changes } = event.detail;
108
+ if (isBillingLine(row, fields)) {
109
+ const next = { ...row, ...changes };
110
+ const calculated = calculateLineTotal(next, changes);
111
+ if (calculated !== undefined && calculated !== null && Number.isFinite(Number(calculated))) {
112
+ changes[fields.total] = Number(calculated);
113
+ }
114
+ }
115
+ oneditcommit?.(event);
116
+ }
117
+ };
118
+ }
119
+
120
+ /** @type {Readonly<BillingFields>} */
121
+ const DEFAULT_FIELDS = Object.freeze({
122
+ id: 'id',
123
+ parent: 'parent',
124
+ item: 'item',
125
+ kind: 'kind',
126
+ quantity: 'quantity',
127
+ unit: 'unit',
128
+ unitPrice: 'unitPrice',
129
+ currency: 'currency',
130
+ total: 'total'
131
+ });
132
+
133
+ /**
134
+ * Returns whether a billing row is an editable line rather than a group/subtotal.
135
+ * @param {BillingRow} row Row.
136
+ * @param {BillingFields} [fields=DEFAULT_FIELDS] Field map.
137
+ * @returns {boolean}
138
+ */
139
+ export function isBillingLine(row, fields = DEFAULT_FIELDS) {
140
+ const kind = String(row?.[fields.kind] ?? 'line').toLowerCase();
141
+ return !['group', 'subtotal', 'header', 'section'].includes(kind);
142
+ }
143
+
144
+ /**
145
+ * Produces the preset columns without mutating overrides.
146
+ * @param {BillingFields} fields Field map.
147
+ * @param {{units: unknown, currencies: unknown, currency: string, locale?: string, decimals: number, columnOverrides: Record<string, object>}} options Formatting/editor options.
148
+ * @returns {import('../table/table.js').TableColumn[]}
149
+ */
150
+ export function billingColumns(fields, { units, currencies, currency, locale, decimals, columnOverrides }) {
151
+ const editableLine = (type) => (row) => isBillingLine(row, fields) ? type : false;
152
+ const rowCurrency = (row) => String(row?.[fields.currency] || currency);
153
+ const rowUnit = (row) => String(row?.[fields.unit] ?? '');
154
+ const columns = {
155
+ item: {
156
+ id: fields.item,
157
+ label: 'Item',
158
+ width: '2fr',
159
+ sortable: true,
160
+ editable: editableLine('text')
161
+ },
162
+ quantity: {
163
+ id: fields.quantity,
164
+ label: 'Quantity',
165
+ width: '1fr',
166
+ type: 'unit',
167
+ locale,
168
+ unit: rowUnit,
169
+ editable: editableLine('number'),
170
+ editorProps: { min: 0, step: 0.01 }
171
+ },
172
+ unit: {
173
+ id: fields.unit,
174
+ label: 'Unit',
175
+ width: '.8fr',
176
+ editable: editableLine(hasChoices(units) ? 'select' : 'text'),
177
+ options: units
178
+ },
179
+ unitPrice: {
180
+ id: fields.unitPrice,
181
+ label: 'Unit price',
182
+ width: '1fr',
183
+ type: 'currency',
184
+ locale,
185
+ decimals,
186
+ currency: rowCurrency,
187
+ editable: editableLine('number'),
188
+ editorProps: { min: 0, step: 0.01 }
189
+ },
190
+ currency: {
191
+ id: fields.currency,
192
+ label: 'Currency',
193
+ width: '.8fr',
194
+ editable: editableLine(hasChoices(currencies) ? 'select' : 'text'),
195
+ options: currencies
196
+ },
197
+ total: {
198
+ id: fields.total,
199
+ label: 'Line total',
200
+ width: '1fr',
201
+ type: 'currency',
202
+ locale,
203
+ decimals,
204
+ currency: rowCurrency
205
+ }
206
+ };
207
+ return Object.entries(columns).map(([key, column]) => ({ ...column, ...(columnOverrides?.[key] ?? {}) }));
208
+ }
209
+
210
+ /** @param {unknown} value @returns {boolean} */
211
+ function hasChoices(value) {
212
+ return Array.isArray(value) ? value.length > 0 : Boolean(value && typeof value === 'object' && Object.keys(value).length);
213
+ }
214
+
215
+ /** Missing billing operands stay missing; explicit numeric zero remains a valid value. @param {unknown} value @returns {number|null} */
216
+ function billingNumber(value) {
217
+ if (value == null || typeof value === 'string' && value.trim() === '') return null;
218
+ const number = Number(value);
219
+ return Number.isFinite(number) ? number : null;
220
+ }
@@ -0,0 +1,210 @@
1
+ .zx-launcher {
2
+ inline-size: min(760px, calc(100vw - (2 * var(--zx-space-4))));
3
+ max-block-size: min(720px, calc(100vh - (2 * var(--zx-space-6))));
4
+ border: 1px solid var(--zx-color-border);
5
+ border-radius: var(--zx-radius-xl);
6
+ background: var(--zx-color-bg-raised);
7
+ box-shadow: var(--zx-overlay-shadow);
8
+ color: var(--zx-color-text);
9
+ padding: 0;
10
+ }
11
+
12
+ .zx-launcher::backdrop {
13
+ background: var(--zx-color-bg-backdrop);
14
+ }
15
+
16
+ .zx-launcher__surface {
17
+ display: grid;
18
+ grid-template-rows: auto auto minmax(0, 1fr) auto;
19
+ max-block-size: inherit;
20
+ }
21
+
22
+ .zx-launcher__search {
23
+ display: grid;
24
+ grid-template-columns: auto minmax(0, 1fr) auto auto;
25
+ align-items: center;
26
+ gap: var(--zx-space-3);
27
+ border-block-end: 1px solid var(--zx-color-border);
28
+ padding: var(--zx-space-3) var(--zx-space-4);
29
+ }
30
+
31
+ .zx-launcher__search[data-shortcut="false"] {
32
+ grid-template-columns: auto minmax(0, 1fr) auto;
33
+ }
34
+
35
+ .zx-launcher__input {
36
+ min-inline-size: 0;
37
+ border: 0;
38
+ outline: 0;
39
+ background: transparent;
40
+ color: inherit;
41
+ font-size: var(--zx-text-lg);
42
+ }
43
+
44
+ .zx-launcher__input:focus-visible {
45
+ box-shadow: inset var(--zx-focus-ring);
46
+ }
47
+
48
+ .zx-launcher__input::-webkit-search-cancel-button { display: none; }
49
+
50
+ .zx-launcher__shortcut,
51
+ .zx-launcher__hints kbd {
52
+ border: 1px solid var(--zx-color-border-control);
53
+ border-radius: var(--zx-radius-sm);
54
+ background: var(--zx-color-bg-muted);
55
+ color: var(--zx-color-text-muted);
56
+ font-family: var(--zx-font-mono);
57
+ font-size: var(--zx-text-xs);
58
+ font-weight: 600;
59
+ line-height: 1.5;
60
+ }
61
+
62
+ .zx-launcher__shortcut {
63
+ padding-inline: var(--zx-space-2);
64
+ white-space: nowrap;
65
+ }
66
+
67
+ .zx-launcher__status {
68
+ margin: 0;
69
+ padding: var(--zx-space-5);
70
+ color: var(--zx-color-text-muted);
71
+ text-align: center;
72
+ }
73
+
74
+ .zx-launcher__status[hidden] { display: none; }
75
+
76
+ .zx-launcher__results {
77
+ min-block-size: 0;
78
+ overflow: auto;
79
+ padding: var(--zx-space-2);
80
+ }
81
+
82
+ .zx-launcher__group-label {
83
+ padding: var(--zx-space-3) var(--zx-space-3) var(--zx-space-1);
84
+ color: var(--zx-color-text-muted);
85
+ font-size: var(--zx-text-xs);
86
+ font-weight: 700;
87
+ letter-spacing: .04em;
88
+ text-transform: uppercase;
89
+ }
90
+
91
+ .zx-launcher__group[data-layout="grid"] {
92
+ display: grid;
93
+ grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
94
+ gap: var(--zx-space-2);
95
+ padding: 0 var(--zx-space-1) var(--zx-space-2);
96
+ }
97
+
98
+ .zx-launcher__group[data-layout="grid"] .zx-launcher__group-label {
99
+ grid-column: 1 / -1;
100
+ padding-inline: var(--zx-space-2);
101
+ }
102
+
103
+ .zx-launcher__option {
104
+ display: flex;
105
+ align-items: center;
106
+ gap: var(--zx-space-3);
107
+ inline-size: 100%;
108
+ min-block-size: calc(var(--zx-control-height) + var(--zx-space-2));
109
+ border: 0;
110
+ border-radius: var(--zx-radius-md);
111
+ background: transparent;
112
+ padding: var(--zx-space-2) var(--zx-space-3);
113
+ color: inherit;
114
+ text-align: start;
115
+ text-decoration: none;
116
+ }
117
+
118
+ .zx-launcher__option[aria-selected="true"],
119
+ .zx-launcher__option:hover {
120
+ background: var(--zx-color-bg-hover);
121
+ }
122
+
123
+ .zx-launcher__option[aria-current="page"] {
124
+ box-shadow: inset 2px 0 var(--zx-color-accent);
125
+ }
126
+
127
+ .zx-launcher__option[data-kind="application"] {
128
+ display: grid;
129
+ grid-template-rows: auto minmax(0, auto);
130
+ justify-items: center;
131
+ align-content: center;
132
+ min-block-size: 92px;
133
+ padding: var(--zx-space-3) var(--zx-space-2);
134
+ text-align: center;
135
+ }
136
+
137
+ .zx-launcher__option[data-kind="application"][aria-current="page"] {
138
+ box-shadow: inset 0 -2px var(--zx-color-accent);
139
+ }
140
+
141
+ .zx-launcher__option[data-kind="application"] .zx-launcher__icon {
142
+ min-block-size: 36px;
143
+ align-items: center;
144
+ }
145
+
146
+ .zx-launcher__option[data-kind="application"] .zx-launcher__copy {
147
+ inline-size: 100%;
148
+ }
149
+
150
+ .zx-launcher__option[data-kind="application"] .zx-launcher__description,
151
+ .zx-launcher__option[data-kind="application"] .zx-launcher__badge {
152
+ display: none;
153
+ }
154
+
155
+ .zx-launcher__option[data-kind="application"] .zx-launcher__label {
156
+ font-size: var(--zx-text-sm);
157
+ }
158
+
159
+ .zx-launcher__option[aria-disabled="true"] {
160
+ color: var(--zx-color-text-muted);
161
+ cursor: not-allowed;
162
+ opacity: .65;
163
+ }
164
+
165
+ .zx-launcher__icon { display: inline-flex; flex: none; }
166
+ .zx-launcher__copy { display: grid; min-inline-size: 0; gap: 2px; }
167
+ .zx-launcher__label { overflow: hidden; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
168
+ .zx-launcher__description { overflow: hidden; color: var(--zx-color-text-muted); font-size: var(--zx-text-sm); text-overflow: ellipsis; white-space: nowrap; }
169
+ .zx-launcher__badge { margin-inline-start: auto; color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); }
170
+
171
+ .zx-launcher__hints {
172
+ display: flex;
173
+ flex-wrap: wrap;
174
+ justify-content: end;
175
+ gap: var(--zx-space-4);
176
+ padding: var(--zx-space-2) var(--zx-space-4);
177
+ border-block-start: 1px solid var(--zx-color-border);
178
+ color: var(--zx-color-text-muted);
179
+ font-size: var(--zx-text-xs);
180
+ }
181
+
182
+ .zx-launcher__hints span {
183
+ display: inline-flex;
184
+ align-items: center;
185
+ gap: var(--zx-space-1);
186
+ }
187
+
188
+ .zx-launcher__hints kbd {
189
+ min-inline-size: 1.5rem;
190
+ padding-inline: 4px;
191
+ text-align: center;
192
+ }
193
+
194
+ @media (max-width: 520px) {
195
+ .zx-launcher__group[data-layout="grid"] {
196
+ grid-template-columns: repeat(3, minmax(0, 1fr));
197
+ }
198
+
199
+ .zx-launcher__shortcut {
200
+ display: none;
201
+ }
202
+
203
+ .zx-launcher__search {
204
+ grid-template-columns: auto minmax(0, 1fr) auto;
205
+ }
206
+
207
+ .zx-launcher__hints {
208
+ justify-content: center;
209
+ }
210
+ }