@zeyos/zx 2.2.1 → 3.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 (117) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/DESIGN-SYSTEM.md +136 -0
  3. package/MIGRATION.md +155 -4
  4. package/README.md +51 -14
  5. package/dist/types/compat/map/data.d.ts +3 -2
  6. package/dist/types/components/account-menu/account-menu.d.ts +144 -0
  7. package/dist/types/components/app-rail/app-rail.d.ts +250 -0
  8. package/dist/types/components/app-sidebar/app-sidebar.d.ts +169 -0
  9. package/dist/types/components/avatar/avatar.d.ts +100 -0
  10. package/dist/types/components/chart/chart.d.ts +321 -0
  11. package/dist/types/components/date-picker/month-picker.d.ts +6 -0
  12. package/dist/types/components/dialog/dialog.d.ts +9 -0
  13. package/dist/types/components/dock/dock.d.ts +495 -0
  14. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  15. package/dist/types/components/field/field.d.ts +14 -0
  16. package/dist/types/components/field-upload/field-upload.d.ts +37 -4
  17. package/dist/types/components/form/form.d.ts +25 -3
  18. package/dist/types/components/grid/grid.d.ts +172 -0
  19. package/dist/types/components/launcher/launcher.d.ts +300 -0
  20. package/dist/types/components/layout/layout.d.ts +4 -4
  21. package/dist/types/components/menu-button/menu-button.d.ts +10 -2
  22. package/dist/types/components/modal/modal.d.ts +25 -0
  23. package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +74 -9
  24. package/dist/types/components/questionnaire/items.d.ts +327 -0
  25. package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
  26. package/dist/types/components/select/select.d.ts +36 -1
  27. package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
  28. package/dist/types/components/sheet/sheet.d.ts +294 -0
  29. package/dist/types/components/split-view/split-view.d.ts +2 -21
  30. package/dist/types/components/tabbox/tabbox.d.ts +12 -3
  31. package/dist/types/components/table/table.d.ts +219 -12
  32. package/dist/types/components/tooltip/tooltip.d.ts +2 -2
  33. package/dist/types/components/value-list/value-list.d.ts +24 -3
  34. package/dist/types/core/dom.d.ts +114 -0
  35. package/dist/types/core/drag-axis.d.ts +111 -0
  36. package/dist/types/core/position.d.ts +4 -2
  37. package/dist/types/index.d.ts +12 -2
  38. package/dist/zx-compat.esm.js +943 -311
  39. package/dist/zx-compat.esm.min.js +1 -1
  40. package/dist/zx-compat.global.js +7893 -2252
  41. package/dist/zx-compat.global.min.js +3 -3
  42. package/dist/zx-zeyos.esm.js +826 -114
  43. package/dist/zx-zeyos.esm.min.js +1 -1
  44. package/dist/zx.css +1720 -243
  45. package/dist/zx.esm.js +8227 -2599
  46. package/dist/zx.esm.min.js +3 -3
  47. package/dist/zx.global.js +8227 -2599
  48. package/dist/zx.global.min.js +3 -3
  49. package/dist/zx.min.css +1 -1
  50. package/docs/api.json +2597 -255
  51. package/docs/llms.md +475 -37
  52. package/docs/llms.txt +21 -9
  53. package/package.json +4 -2
  54. package/src/compat/globals.js +3 -1
  55. package/src/compat/map/data.js +31 -9
  56. package/src/components/account-menu/account-menu.css +70 -0
  57. package/src/components/account-menu/account-menu.js +208 -0
  58. package/src/components/app-rail/app-rail.css +107 -0
  59. package/src/components/app-rail/app-rail.js +668 -0
  60. package/src/components/app-sidebar/app-sidebar.css +68 -0
  61. package/src/components/app-sidebar/app-sidebar.js +388 -0
  62. package/src/components/avatar/avatar.css +61 -0
  63. package/src/components/avatar/avatar.js +222 -0
  64. package/src/components/button/button.css +0 -1
  65. package/src/components/chart/chart.css +61 -0
  66. package/src/components/chart/chart.js +518 -0
  67. package/src/components/date-picker/date-range-picker.css +7 -0
  68. package/src/components/date-picker/month-picker.js +9 -0
  69. package/src/components/dialog/dialog.js +11 -4
  70. package/src/components/dock/dock.css +228 -0
  71. package/src/components/dock/dock.js +977 -0
  72. package/src/components/dropdown/dropdown.js +1 -1
  73. package/src/components/field/field.js +2 -0
  74. package/src/components/field-upload/field-upload.js +9 -4
  75. package/src/components/fieldset/fieldset.css +7 -0
  76. package/src/components/form/form.css +7 -0
  77. package/src/components/form/form.js +6 -3
  78. package/src/components/grid/grid.css +6 -0
  79. package/src/components/grid/grid.js +213 -0
  80. package/src/components/launcher/launcher.css +100 -0
  81. package/src/components/launcher/launcher.js +557 -0
  82. package/src/components/layout/layout.js +2 -2
  83. package/src/components/menu-button/menu-button.js +27 -2
  84. package/src/components/modal/modal.css +5 -1
  85. package/src/components/modal/modal.js +37 -2
  86. package/src/components/multi-value-editor/multi-value-editor.css +99 -15
  87. package/src/components/multi-value-editor/multi-value-editor.js +237 -19
  88. package/src/components/navigation-bar/navigation-bar.css +7 -0
  89. package/src/components/questionnaire/items.js +370 -0
  90. package/src/components/questionnaire/questionnaire.css +387 -0
  91. package/src/components/questionnaire/questionnaire.js +1033 -0
  92. package/src/components/search/search.css +10 -2
  93. package/src/components/select/select.css +6 -1
  94. package/src/components/select/select.js +99 -11
  95. package/src/components/sheet/sheet-stack.js +304 -0
  96. package/src/components/sheet/sheet.css +351 -0
  97. package/src/components/sheet/sheet.js +551 -0
  98. package/src/components/split-view/split-view.js +76 -161
  99. package/src/components/stepper/stepper.css +12 -2
  100. package/src/components/tabbox/tabbox.css +13 -3
  101. package/src/components/tabbox/tabbox.js +34 -10
  102. package/src/components/table/table.css +43 -0
  103. package/src/components/table/table.js +523 -45
  104. package/src/components/tooltip/tooltip.js +5 -2
  105. package/src/components/value-list/value-list.js +6 -3
  106. package/src/core/dom.js +302 -0
  107. package/src/core/drag-axis.js +203 -0
  108. package/src/core/position.js +68 -22
  109. package/src/index.js +19 -2
  110. package/styles/tokens/dark.css +15 -13
  111. package/styles/tokens/global.css +17 -5
  112. package/styles/tokens/semantic.css +14 -8
  113. package/styles/tokens/themes.css +72 -0
  114. package/styles/zx.css +11 -1
  115. package/dist/types/components/permission/permission.d.ts +0 -93
  116. package/src/components/permission/permission.css +0 -47
  117. package/src/components/permission/permission.js +0 -198
@@ -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
  /**
@@ -6,6 +6,13 @@
6
6
  border-radius: var(--zx-radius-lg);
7
7
  background: var(--zx-color-bg-surface);
8
8
  container-type: inline-size;
9
+ /* A size container takes no width from its own contents, so in a shrink-to-fit host — a flex
10
+ row, an inline-block, a grid `auto` track — it would collapse to nothing and spill. Only the
11
+ host can size it, so it always fills the host. That covers every host with a width of its
12
+ own; a host that shrink-wraps *its* contents still collapses, because 100% then resolves
13
+ against a containing block this element's own containment zeroed. Dropping containment is the
14
+ only fix for that — see multi-value-editor.css. */
15
+ inline-size: 100%;
9
16
  }
10
17
 
11
18
  .zx-fieldset__legend {
@@ -5,6 +5,13 @@
5
5
  min-inline-size: 0;
6
6
  }
7
7
 
8
+ /* Fieldsets are size containers, and a contained descendant contributes nothing to its ancestors'
9
+ intrinsic width either — so a form in a shrink-to-fit host would shrink-wrap to its action
10
+ buttons and leave the fields spilling out of a sliver. The form fills its host instead. */
11
+ .zx-form {
12
+ inline-size: 100%;
13
+ }
14
+
8
15
  .zx-form__actions {
9
16
  display: flex;
10
17
  flex-wrap: wrap;
@@ -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,213 @@
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 = Number(row?.[fields.quantity]);
89
+ const price = Number(row?.[fields.unitPrice]);
90
+ return Number.isFinite(quantity) && Number.isFinite(price) ? 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
+ }
@@ -0,0 +1,100 @@
1
+ .zx-launcher {
2
+ inline-size: min(680px, 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);
19
+ max-block-size: inherit;
20
+ }
21
+
22
+ .zx-launcher__search {
23
+ display: grid;
24
+ grid-template-columns: auto 1fr 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__input {
32
+ min-inline-size: 0;
33
+ border: 0;
34
+ outline: 0;
35
+ background: transparent;
36
+ color: inherit;
37
+ font-size: var(--zx-text-lg);
38
+ }
39
+
40
+ .zx-launcher__input:focus-visible {
41
+ box-shadow: inset var(--zx-focus-ring);
42
+ }
43
+
44
+ .zx-launcher__input::-webkit-search-cancel-button { display: none; }
45
+
46
+ .zx-launcher__status {
47
+ margin: 0;
48
+ padding: var(--zx-space-5);
49
+ color: var(--zx-color-text-muted);
50
+ text-align: center;
51
+ }
52
+
53
+ .zx-launcher__status[hidden] { display: none; }
54
+
55
+ .zx-launcher__results {
56
+ min-block-size: 0;
57
+ overflow: auto;
58
+ padding: var(--zx-space-2);
59
+ }
60
+
61
+ .zx-launcher__group-label {
62
+ padding: var(--zx-space-3) var(--zx-space-3) var(--zx-space-1);
63
+ color: var(--zx-color-text-muted);
64
+ font-size: var(--zx-text-xs);
65
+ font-weight: 700;
66
+ letter-spacing: .04em;
67
+ text-transform: uppercase;
68
+ }
69
+
70
+ .zx-launcher__option {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: var(--zx-space-3);
74
+ inline-size: 100%;
75
+ min-block-size: calc(var(--zx-control-height) + var(--zx-space-2));
76
+ border: 0;
77
+ border-radius: var(--zx-radius-md);
78
+ background: transparent;
79
+ padding: var(--zx-space-2) var(--zx-space-3);
80
+ color: inherit;
81
+ text-align: start;
82
+ text-decoration: none;
83
+ }
84
+
85
+ .zx-launcher__option[aria-selected="true"],
86
+ .zx-launcher__option:hover {
87
+ background: var(--zx-color-bg-hover);
88
+ }
89
+
90
+ .zx-launcher__option[aria-disabled="true"] {
91
+ color: var(--zx-color-text-muted);
92
+ cursor: not-allowed;
93
+ opacity: .65;
94
+ }
95
+
96
+ .zx-launcher__icon { display: inline-flex; flex: none; }
97
+ .zx-launcher__copy { display: grid; min-inline-size: 0; gap: 2px; }
98
+ .zx-launcher__label { overflow: hidden; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
99
+ .zx-launcher__description { overflow: hidden; color: var(--zx-color-text-muted); font-size: var(--zx-text-sm); text-overflow: ellipsis; white-space: nowrap; }
100
+ .zx-launcher__badge { margin-inline-start: auto; color: var(--zx-color-text-muted); font-size: var(--zx-text-xs); }