@visitwonders/assembly 0.10.0 → 0.11.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 (46) hide show
  1. package/README.md +83 -0
  2. package/declarations/form/combobox-field.d.ts +71 -0
  3. package/declarations/form/combobox-field.d.ts.map +1 -0
  4. package/declarations/form/combobox-shared.d.ts +36 -0
  5. package/declarations/form/combobox-shared.d.ts.map +1 -0
  6. package/declarations/form/combobox.d.ts +239 -0
  7. package/declarations/form/combobox.d.ts.map +1 -0
  8. package/declarations/form/index.d.ts +4 -0
  9. package/declarations/form/index.d.ts.map +1 -1
  10. package/declarations/form/multi-combobox-field.d.ts +72 -0
  11. package/declarations/form/multi-combobox-field.d.ts.map +1 -0
  12. package/declarations/form/multi-combobox.d.ts +202 -0
  13. package/declarations/form/multi-combobox.d.ts.map +1 -0
  14. package/declarations/layout/h-stack.d.ts.map +1 -1
  15. package/declarations/layout/stack.d.ts.map +1 -1
  16. package/declarations/layout/v-stack.d.ts.map +1 -1
  17. package/declarations/overlay/popover.d.ts +20 -1
  18. package/declarations/overlay/popover.d.ts.map +1 -1
  19. package/dist/_app_/form/combobox-field.js +1 -0
  20. package/dist/_app_/form/combobox-shared.js +1 -0
  21. package/dist/_app_/form/combobox.js +1 -0
  22. package/dist/_app_/form/multi-combobox-field.js +1 -0
  23. package/dist/_app_/form/multi-combobox.js +1 -0
  24. package/dist/data/{sortable-list-css-211fcfeedc08052ccbac7f51549ce0b1.css → sortable-list-css-03e5d237ea377f7d6056e76cc85b2aaa.css} +8 -4
  25. package/dist/data/sortable-list.js +1 -1
  26. package/dist/form/combobox-field.js +37 -0
  27. package/dist/form/combobox-field.js.map +1 -0
  28. package/dist/form/combobox-shared.js +76 -0
  29. package/dist/form/combobox-shared.js.map +1 -0
  30. package/dist/form/combobox.css +345 -0
  31. package/dist/form/combobox.js +612 -0
  32. package/dist/form/combobox.js.map +1 -0
  33. package/dist/form/{display-field-css-890d9be4b5da61613fd017071f330735.css → display-field-css-502236a2343d47e31e52bdb93a769ca1.css} +2 -2
  34. package/dist/form/display-field.js +1 -1
  35. package/dist/form/index.js +4 -0
  36. package/dist/form/index.js.map +1 -1
  37. package/dist/form/multi-combobox-field.js +36 -0
  38. package/dist/form/multi-combobox-field.js.map +1 -0
  39. package/dist/form/multi-combobox.css +422 -0
  40. package/dist/form/multi-combobox.js +626 -0
  41. package/dist/form/multi-combobox.js.map +1 -0
  42. package/dist/layout/h-stack.js.map +1 -1
  43. package/dist/layout/panel.css +10 -0
  44. package/dist/layout/v-stack.js.map +1 -1
  45. package/dist/overlay/popover.js +19 -1
  46. package/package.json +6 -1
@@ -0,0 +1,36 @@
1
+ import Component from '@glimmer/component';
2
+ import Control from './control.js';
3
+ import MultiComboBox from './multi-combobox.js';
4
+ import { precompileTemplate } from '@ember/template-compilation';
5
+ import { setComponentTemplate } from '@ember/component';
6
+
7
+ class MultiComboBoxField extends Component {
8
+ get isInvalid() {
9
+ return !!this.args.error;
10
+ }
11
+ get isLabelHidden() {
12
+ return this.args.labelVisibility === 'hidden';
13
+ }
14
+ getAriaDescribedBy = controlId => {
15
+ const parts = [];
16
+ if (this.args.helpText) {
17
+ parts.push(`${controlId}-help-text`);
18
+ }
19
+ if (this.args.error) {
20
+ parts.push(`${controlId}-error-message`);
21
+ }
22
+ return parts.length > 0 ? parts.join(' ') : undefined;
23
+ };
24
+ static {
25
+ setComponentTemplate(precompileTemplate("<Control @isInvalid={{this.isInvalid}} @isDisabled={{@isDisabled}} @isRequired={{@isRequired}} @labelInfo={{@labelInfo}} ...attributes as |ctrl|>\n {{#if (has-block \"info\")}}\n <ctrl.Label @isVisuallyHidden={{this.isLabelHidden}}>\n <:default>{{@label}}</:default>\n <:info>{{yield to=\"info\"}}</:info>\n </ctrl.Label>\n {{else}}\n <ctrl.Label @isVisuallyHidden={{this.isLabelHidden}}>\n {{@label}}\n </ctrl.Label>\n {{/if}}\n\n <MultiComboBox @id={{ctrl.id}} @name={{@name}} @items={{@items}} @values={{@values}} @placeholder={{@placeholder}} @noResultsText={{@noResultsText}} @onSearch={{@onSearch}} @searchDebounceMs={{@searchDebounceMs}} @isLoading={{@isLoading}} @onSearchError={{@onSearchError}} @loadingText={{@loadingText}} @isCreatable={{@isCreatable}} @onCreate={{@onCreate}} @createLabel={{@createLabel}} @maxVisibleChips={{@maxVisibleChips}} @isDisabled={{@isDisabled}} @isInvalid={{this.isInvalid}} @isRequired={{@isRequired}} @isClearable={{@isClearable}} @aria-describedby={{this.getAriaDescribedBy ctrl.id}} @onChange={{@onChange}} @onBlur={{@onBlur}} @onFocus={{@onFocus}} @onOpen={{@onOpen}} @onClose={{@onClose}} data-test-multi-combobox-field />\n\n {{#if @helpText}}\n <ctrl.HelpText>{{@helpText}}</ctrl.HelpText>\n {{/if}}\n\n {{#if @error}}\n <ctrl.ErrorMessage>{{@error}}</ctrl.ErrorMessage>\n {{/if}}\n</Control>", {
26
+ strictMode: true,
27
+ scope: () => ({
28
+ Control,
29
+ MultiComboBox
30
+ })
31
+ }), this);
32
+ }
33
+ }
34
+
35
+ export { MultiComboBoxField as default };
36
+ //# sourceMappingURL=multi-combobox-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-combobox-field.js","sources":["../../src/form/multi-combobox-field.gts"],"sourcesContent":["import Component from '@glimmer/component';\n\nimport Control from './control.gts';\nimport MultiComboBox from './multi-combobox.gts';\nimport type { ComboBoxItems, ComboBoxOption } from './combobox-shared.ts';\n\nexport type LabelVisibility = 'visible' | 'hidden';\n\nexport interface MultiComboBoxFieldSignature {\n Element: HTMLDivElement;\n Args: {\n /** Label text (required). */\n label: string;\n\n /** Available options. Flat or pre-grouped. */\n items: ComboBoxItems;\n\n /** Current selected values (controlled). */\n values?: string[];\n\n /** Fires when the selection changes. */\n onChange?: (values: string[], options: ComboBoxOption[]) => void;\n\n /** Async search. */\n onSearch?: (query: string) => Promise<ComboBoxItems>;\n\n /** Debounce for `onSearch` in ms. */\n searchDebounceMs?: number;\n\n /** Force the loading state. */\n isLoading?: boolean;\n\n /** Called when an `onSearch` promise rejects. */\n onSearchError?: (error: unknown) => void;\n\n /** Loading row text. */\n loadingText?: string;\n\n /** Input placeholder when no values selected. */\n placeholder?: string;\n\n /** Empty state text. */\n noResultsText?: string;\n\n /** Allow creating new options from a non-matching query. */\n isCreatable?: boolean;\n\n /** Fires when the user activates the create row. */\n onCreate?: (query: string) => void;\n\n /** Build the create-row label. */\n createLabel?: (query: string) => string;\n\n /** Chips shown before collapsing to \"+N more\". */\n maxVisibleChips?: number;\n\n /** Help text displayed below the control. */\n helpText?: string;\n\n /** Error message (also sets invalid state). */\n error?: string;\n\n /** Field is required. */\n isRequired?: boolean;\n\n /** Field is disabled. */\n isDisabled?: boolean;\n\n /** Show the clear-all button when values are set. */\n isClearable?: boolean;\n\n /** Info tooltip text shown next to the label. */\n labelInfo?: string;\n\n /** Label visibility. */\n labelVisibility?: LabelVisibility;\n\n /** Input name — one hidden input is rendered per selected value. */\n name?: string;\n\n /** Blur event handler. */\n onBlur?: (event: FocusEvent) => void;\n\n /** Focus event handler. */\n onFocus?: (event: FocusEvent) => void;\n\n /** Fires when the dropdown opens. */\n onOpen?: () => void;\n\n /** Fires when the dropdown closes. */\n onClose?: () => void;\n };\n Blocks: {\n /** Rich tooltip content shown next to the label. */\n info: [];\n };\n}\n\nexport default class MultiComboBoxField extends Component<MultiComboBoxFieldSignature> {\n get isInvalid(): boolean {\n return !!this.args.error;\n }\n\n get isLabelHidden(): boolean {\n return this.args.labelVisibility === 'hidden';\n }\n\n getAriaDescribedBy = (controlId: string): string | undefined => {\n const parts: string[] = [];\n if (this.args.helpText) {\n parts.push(`${controlId}-help-text`);\n }\n if (this.args.error) {\n parts.push(`${controlId}-error-message`);\n }\n return parts.length > 0 ? parts.join(' ') : undefined;\n };\n\n <template>\n <Control\n @isInvalid={{this.isInvalid}}\n @isDisabled={{@isDisabled}}\n @isRequired={{@isRequired}}\n @labelInfo={{@labelInfo}}\n ...attributes\n as |ctrl|\n >\n {{#if (has-block \"info\")}}\n <ctrl.Label @isVisuallyHidden={{this.isLabelHidden}}>\n <:default>{{@label}}</:default>\n <:info>{{yield to=\"info\"}}</:info>\n </ctrl.Label>\n {{else}}\n <ctrl.Label @isVisuallyHidden={{this.isLabelHidden}}>\n {{@label}}\n </ctrl.Label>\n {{/if}}\n\n <MultiComboBox\n @id={{ctrl.id}}\n @name={{@name}}\n @items={{@items}}\n @values={{@values}}\n @placeholder={{@placeholder}}\n @noResultsText={{@noResultsText}}\n @onSearch={{@onSearch}}\n @searchDebounceMs={{@searchDebounceMs}}\n @isLoading={{@isLoading}}\n @onSearchError={{@onSearchError}}\n @loadingText={{@loadingText}}\n @isCreatable={{@isCreatable}}\n @onCreate={{@onCreate}}\n @createLabel={{@createLabel}}\n @maxVisibleChips={{@maxVisibleChips}}\n @isDisabled={{@isDisabled}}\n @isInvalid={{this.isInvalid}}\n @isRequired={{@isRequired}}\n @isClearable={{@isClearable}}\n @aria-describedby={{this.getAriaDescribedBy ctrl.id}}\n @onChange={{@onChange}}\n @onBlur={{@onBlur}}\n @onFocus={{@onFocus}}\n @onOpen={{@onOpen}}\n @onClose={{@onClose}}\n data-test-multi-combobox-field\n />\n\n {{#if @helpText}}\n <ctrl.HelpText>{{@helpText}}</ctrl.HelpText>\n {{/if}}\n\n {{#if @error}}\n <ctrl.ErrorMessage>{{@error}}</ctrl.ErrorMessage>\n {{/if}}\n </Control>\n </template>\n}\n"],"names":["MultiComboBoxField","Component","isInvalid","args","error","isLabelHidden","labelVisibility","getAriaDescribedBy","controlId","parts","helpText","push","length","join","undefined","setComponentTemplate","precompileTemplate","strictMode","scope","Control","MultiComboBox"],"mappings":";;;;;;AAkGe,MAAMA,2BAA2BC,SAAA,CAAU;EACxD,IAAIC,SAAAA,GAAqB;AACvB,IAAA,OAAO,CAAC,CAAC,IAAI,CAACC,IAAI,CAACC,KAAK;AAC1B,EAAA;EAEA,IAAIC,aAAAA,GAAyB;AAC3B,IAAA,OAAO,IAAI,CAACF,IAAI,CAACG,eAAe,KAAK,QAAA;AACvC,EAAA;EAEAC,kBAAA,GAAsBC,SAAiB,IAAqB;IAC1D,MAAMC,KAAa,GAAK,EAAE;AAC1B,IAAA,IAAI,IAAI,CAACN,IAAI,CAACO,QAAQ,EAAE;AACtBD,MAAAA,KAAA,CAAME,IAAI,CAAC,CAAA,EAAGH,SAAA,YAAqB,CAAA;AACrC,IAAA;AACA,IAAA,IAAI,IAAI,CAACL,IAAI,CAACC,KAAK,EAAE;AACnBK,MAAAA,KAAA,CAAME,IAAI,CAAC,CAAA,EAAGH,SAAA,gBAAyB,CAAA;AACzC,IAAA;AACA,IAAA,OAAOC,MAAMG,MAAM,GAAG,IAAIH,KAAA,CAAMI,IAAI,CAAC,GAAA,CAAA,GAAOC,SAAA;EAC9C,CAAA;AAEA,EAAA;IAAAC,oBAAA,CAAAC,kBAAA,CAAA,u2CAAA,EAyDA;MAAAC,UAAA,EAAA,IAAA;AAAAC,MAAAA,KAAA,EAAAA,OAAA;QAAAC,OAAA;AAAAC,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;;;;"}
@@ -0,0 +1,422 @@
1
+ /* src/form/multi-combobox.css */
2
+ /* ===================================
3
+ * MultiComboBox Component
4
+ * Multi-select with chips + typeahead
5
+ * =================================== */
6
+
7
+ .multi-combobox_e1a041f66 {
8
+ display: inline-flex;
9
+ width: 100%;
10
+ }
11
+
12
+ /* Visually-hidden aria-live region for screen-reader announcements. */
13
+ .multi-combobox-sr-only_e1a041f66 {
14
+ position: absolute;
15
+ width: 1px;
16
+ height: 1px;
17
+ padding: 0;
18
+ margin: -1px;
19
+ overflow: hidden;
20
+ clip: rect(0, 0, 0, 0);
21
+ white-space: nowrap;
22
+ border: 0;
23
+ }
24
+
25
+ /* ===================================
26
+ * Trigger wrapper — input-like surface that also holds the chips.
27
+ * Fixed height so adding chips doesn't resize the trigger (which
28
+ * would in turn make floating-ui reposition the popover — visible
29
+ * as a "jumping" dropdown on every pick).
30
+ * =================================== */
31
+
32
+ .multi-combobox_e1a041f66 .multi-combobox-trigger_e1a041f66 {
33
+ position: relative;
34
+ display: flex;
35
+ align-items: center;
36
+ width: 100%;
37
+ height: var(--input-height-md);
38
+ border: var(--border-width-1) solid var(--color-border-control);
39
+ border-radius: var(--radius-md);
40
+ background-color: var(--color-bg);
41
+ padding: 0 var(--spacing-1);
42
+ transition:
43
+ border-color var(--transition-fast),
44
+ box-shadow var(--transition-fast);
45
+ }
46
+
47
+ .multi-combobox_e1a041f66 .multi-combobox-trigger_e1a041f66:hover:not([data-disabled="true"]) {
48
+ border-color: var(--color-border-control-hover);
49
+ }
50
+
51
+ .multi-combobox_e1a041f66 .multi-combobox-trigger_e1a041f66:focus-within {
52
+ border-color: var(--color-border-focus);
53
+ box-shadow: var(--focus-ring);
54
+ }
55
+
56
+ /* ===================================
57
+ * Chips row — wraps chips inline with the input.
58
+ * =================================== */
59
+
60
+ .multi-combobox-chips_e1a041f66 {
61
+ flex: 1;
62
+ min-width: 0;
63
+ height: 100%;
64
+ display: flex;
65
+ flex-wrap: nowrap;
66
+ align-items: center;
67
+ gap: 4px;
68
+ padding: 0 var(--spacing-1);
69
+ overflow: hidden;
70
+ }
71
+
72
+ /* ===================================
73
+ * Chip
74
+ * =================================== */
75
+
76
+ .multi-combobox-chip_e1a041f66 {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ gap: 4px;
80
+ max-width: 180px;
81
+ padding: 2px 4px 2px var(--spacing-2);
82
+ background-color: var(--color-bg-neutral-subtle);
83
+ border-radius: var(--radius-md);
84
+ font-size: var(--font-size-13);
85
+ line-height: var(--line-height-tight);
86
+ color: var(--color-text);
87
+ }
88
+
89
+ .multi-combobox-chip-label_e1a041f66 {
90
+ overflow: hidden;
91
+ text-overflow: ellipsis;
92
+ white-space: nowrap;
93
+ }
94
+
95
+ .multi-combobox-chip-remove_e1a041f66 {
96
+ flex-shrink: 0;
97
+ display: inline-flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ width: 18px;
101
+ height: 18px;
102
+ padding: 0;
103
+ border: none;
104
+ background: transparent;
105
+ color: var(--color-text-tertiary);
106
+ cursor: pointer;
107
+ border-radius: var(--radius-sm);
108
+ transition: color var(--transition-fast);
109
+ }
110
+
111
+ .multi-combobox-chip-remove_e1a041f66:hover {
112
+ color: var(--color-text-critical);
113
+ }
114
+
115
+ .multi-combobox-more_e1a041f66 {
116
+ font-size: var(--font-size-13);
117
+ color: var(--color-text-tertiary);
118
+ padding: 0 var(--spacing-1);
119
+ white-space: nowrap;
120
+ }
121
+
122
+ /* ===================================
123
+ * Input
124
+ * =================================== */
125
+
126
+ .multi-combobox-input_e1a041f66 {
127
+ flex: 1;
128
+ min-width: 80px;
129
+ height: var(--spacing-7);
130
+ padding: 0;
131
+ border: none;
132
+ background: transparent;
133
+ font-family: inherit;
134
+ font-size: var(--font-size-md);
135
+ line-height: var(--line-height-tight);
136
+ color: var(--color-text);
137
+ text-overflow: ellipsis;
138
+ }
139
+
140
+ .multi-combobox-input_e1a041f66,
141
+ .multi-combobox-input_e1a041f66:focus,
142
+ .multi-combobox-input_e1a041f66:focus-visible {
143
+ outline: none;
144
+ box-shadow: none;
145
+ }
146
+
147
+ .multi-combobox-input_e1a041f66::placeholder {
148
+ color: var(--color-text-tertiary);
149
+ }
150
+
151
+ .multi-combobox-input_e1a041f66:disabled {
152
+ cursor: not-allowed;
153
+ }
154
+
155
+ /* ===================================
156
+ * Clear + Chevron
157
+ * =================================== */
158
+
159
+ .multi-combobox-clear_e1a041f66,
160
+ .multi-combobox-chevron_e1a041f66 {
161
+ flex-shrink: 0;
162
+ display: inline-flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ width: 24px;
166
+ height: 24px;
167
+ padding: 0;
168
+ margin: 0 2px;
169
+ border: none;
170
+ background: transparent;
171
+ color: var(--color-text-tertiary);
172
+ cursor: pointer;
173
+ border-radius: var(--radius-sm);
174
+ transition: color var(--transition-fast);
175
+ align-self: center;
176
+ }
177
+
178
+ .multi-combobox-clear_e1a041f66:hover,
179
+ .multi-combobox-chevron_e1a041f66:hover:not(:disabled) {
180
+ color: var(--color-text);
181
+ }
182
+
183
+ .multi-combobox-chevron_e1a041f66 {
184
+ margin-right: var(--spacing-1);
185
+ transition:
186
+ transform var(--transition-fast),
187
+ color var(--transition-fast);
188
+ }
189
+
190
+ .multi-combobox_e1a041f66[data-open="true"] .multi-combobox-chevron_e1a041f66 {
191
+ transform: rotate(180deg);
192
+ }
193
+
194
+ .multi-combobox-chevron_e1a041f66:disabled {
195
+ color: var(--color-text-disabled);
196
+ cursor: not-allowed;
197
+ }
198
+
199
+ /* ===================================
200
+ * Invalid state
201
+ * =================================== */
202
+
203
+ .multi-combobox_e1a041f66[data-invalid="true"] .multi-combobox-trigger_e1a041f66 {
204
+ border-color: var(--color-border-critical);
205
+ }
206
+
207
+ .multi-combobox_e1a041f66[data-invalid="true"] .multi-combobox-trigger_e1a041f66:focus-within {
208
+ border-color: var(--color-border-critical);
209
+ box-shadow: var(--focus-ring-critical);
210
+ }
211
+
212
+ /* ===================================
213
+ * Disabled state
214
+ * =================================== */
215
+
216
+ .multi-combobox_e1a041f66[data-disabled="true"] .multi-combobox-trigger_e1a041f66 {
217
+ background-color: var(--color-bg-disabled);
218
+ border-color: var(--color-border-control-disabled);
219
+ cursor: not-allowed;
220
+ }
221
+
222
+ .multi-combobox_e1a041f66[data-disabled="true"] .multi-combobox-input_e1a041f66 {
223
+ color: var(--color-text-disabled);
224
+ }
225
+
226
+ /* ===================================
227
+ * Popover content
228
+ * =================================== */
229
+
230
+ .multi-combobox-popover-content_e1a041f66 {
231
+ min-width: 240px;
232
+ max-height: min(320px, 40vh);
233
+ display: flex;
234
+ flex-direction: column;
235
+ padding: 0;
236
+ overflow: hidden;
237
+ /* Anchor the open-scale animation to the top-left edge (where the
238
+ * popover meets the trigger with @side="bottom" @align="start"),
239
+ * so it appears to emerge from the trigger rather than inflate from
240
+ * its own centre. */
241
+ transform-origin: top left;
242
+ }
243
+
244
+ .multi-combobox-listbox_e1a041f66 {
245
+ flex: 1;
246
+ min-height: 0;
247
+ overflow-y: auto;
248
+ padding: var(--spacing-2) var(--spacing-1);
249
+ /* Keep the active row comfortably away from the scroll edges when
250
+ * keyboard nav brings it into view (scrollIntoView({ block: 'nearest' })). */
251
+ scroll-padding-block: var(--spacing-2);
252
+ }
253
+
254
+ /* ===================================
255
+ * Empty / Loading state
256
+ * =================================== */
257
+
258
+ .multi-combobox-empty_e1a041f66,
259
+ .multi-combobox-loading_e1a041f66 {
260
+ padding: var(--spacing-3);
261
+ text-align: center;
262
+ color: var(--color-text-tertiary);
263
+ font-size: var(--font-size-13);
264
+ }
265
+
266
+ /* ===================================
267
+ * Groups
268
+ * =================================== */
269
+
270
+ .multi-combobox-group_e1a041f66:not(:first-child) {
271
+ border-top: 1px solid var(--color-border-subtle);
272
+ margin-top: var(--spacing-1);
273
+ padding-top: var(--spacing-1);
274
+ }
275
+
276
+ .multi-combobox-group-heading_e1a041f66 {
277
+ padding: var(--spacing-2) var(--spacing-3) var(--spacing-1);
278
+ font-size: var(--font-size-11);
279
+ font-weight: var(--font-weight-medium);
280
+ color: var(--color-text-tertiary);
281
+ text-transform: uppercase;
282
+ letter-spacing: 0.05em;
283
+ }
284
+
285
+ /* ===================================
286
+ * Create row
287
+ * =================================== */
288
+
289
+ .multi-combobox-create_e1a041f66 {
290
+ border-top: 1px solid var(--color-border-subtle);
291
+ margin-top: var(--spacing-1);
292
+ padding-top: var(--spacing-2);
293
+ color: var(--color-text-accent);
294
+ font-weight: var(--font-weight-medium);
295
+ }
296
+
297
+ .multi-combobox-create-icon_e1a041f66 {
298
+ flex-shrink: 0;
299
+ display: inline-flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+ width: 16px;
303
+ height: 16px;
304
+ font-size: var(--font-size-md);
305
+ line-height: 1;
306
+ }
307
+
308
+ /* ===================================
309
+ * Options
310
+ * =================================== */
311
+
312
+ .multi-combobox-option_e1a041f66 {
313
+ display: flex;
314
+ align-items: center;
315
+ justify-content: space-between;
316
+ gap: var(--spacing-2);
317
+ padding: var(--spacing-2) var(--spacing-3);
318
+ border-radius: var(--radius-sm);
319
+ font-size: var(--font-size-13);
320
+ line-height: var(--line-height-tight);
321
+ color: var(--color-text);
322
+ cursor: pointer;
323
+ user-select: none;
324
+ transition: background-color var(--transition-fast);
325
+ }
326
+
327
+ /* When a description is present, the content block becomes two-line;
328
+ * switch alignment so the checkbox aligns with the first line (label),
329
+ * not the visual centre between the two lines. */
330
+ .multi-combobox-option_e1a041f66:has(.multi-combobox-option-description_e1a041f66) {
331
+ align-items: flex-start;
332
+ }
333
+
334
+ .multi-combobox-option_e1a041f66:hover:not([data-disabled="true"]) {
335
+ background-color: var(--color-bg-neutral-subtle);
336
+ }
337
+
338
+ .multi-combobox-option_e1a041f66[data-active="true"]:not([data-disabled="true"]) {
339
+ background-color: var(--color-bg-neutral-subtle);
340
+ }
341
+
342
+ .multi-combobox-option_e1a041f66[data-disabled="true"] {
343
+ color: var(--color-text-disabled);
344
+ cursor: not-allowed;
345
+ }
346
+
347
+ .multi-combobox-option-content_e1a041f66 {
348
+ flex: 1;
349
+ min-width: 0;
350
+ display: flex;
351
+ flex-direction: column;
352
+ gap: 2px;
353
+ }
354
+
355
+ .multi-combobox-option-label_e1a041f66 {
356
+ display: block;
357
+ overflow: hidden;
358
+ text-overflow: ellipsis;
359
+ white-space: nowrap;
360
+ }
361
+
362
+ .multi-combobox-option-description_e1a041f66 {
363
+ display: block;
364
+ font-size: var(--font-size-11);
365
+ font-weight: var(--font-weight-regular);
366
+ color: var(--color-text-tertiary);
367
+ overflow: hidden;
368
+ text-overflow: ellipsis;
369
+ white-space: nowrap;
370
+ }
371
+
372
+ /* ===================================
373
+ * Match highlight
374
+ * =================================== */
375
+
376
+ .multi-combobox-mark_e1a041f66 {
377
+ background: transparent;
378
+ color: inherit;
379
+ font-weight: var(--font-weight-bold);
380
+ padding: 0;
381
+ }
382
+
383
+ /* ===================================
384
+ * Checkbox indicator (trailing, Stripe-style)
385
+ * =================================== */
386
+
387
+ .multi-combobox-checkbox_e1a041f66 {
388
+ flex-shrink: 0;
389
+ position: relative;
390
+ width: 16px;
391
+ height: 16px;
392
+ border: var(--border-width-1) solid var(--color-border-control);
393
+ border-radius: var(--radius-sm);
394
+ background-color: var(--color-bg-surface);
395
+ transition:
396
+ background-color var(--transition-fast),
397
+ border-color var(--transition-fast);
398
+ }
399
+
400
+ /* Align with the first line of content when a description pushes the
401
+ * option to two lines. Without this it would center between lines. */
402
+ .multi-combobox-option_e1a041f66:has(.multi-combobox-option-description_e1a041f66)
403
+ .multi-combobox-checkbox_e1a041f66 {
404
+ margin-top: 2px;
405
+ }
406
+
407
+ .multi-combobox-checkbox_e1a041f66[data-checked="true"] {
408
+ background-color: var(--color-bg-fill-accent);
409
+ border-color: var(--color-bg-fill-accent);
410
+ }
411
+
412
+ .multi-combobox-checkbox_e1a041f66[data-checked="true"]::before {
413
+ content: "";
414
+ position: absolute;
415
+ left: 5px;
416
+ top: 1px;
417
+ width: 4px;
418
+ height: 9px;
419
+ border: solid var(--color-text-on-accent);
420
+ border-width: 0 2px 2px 0;
421
+ transform: rotate(45deg);
422
+ }