@jxsuite/ui 0.0.0 → 0.1.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 (105) hide show
  1. package/components/jx-accordion-item.json +281 -0
  2. package/components/jx-accordion.json +33 -0
  3. package/components/jx-action-button.json +261 -33
  4. package/components/jx-action-group.json +123 -0
  5. package/components/jx-button.json +133 -25
  6. package/components/jx-checkbox.json +215 -0
  7. package/components/jx-color-area.json +263 -0
  8. package/components/jx-color-field.json +565 -0
  9. package/components/jx-color-slider.json +216 -0
  10. package/components/jx-combobox.json +544 -0
  11. package/components/jx-dialog.json +416 -0
  12. package/components/jx-divider.json +52 -0
  13. package/components/jx-dot.json +38 -0
  14. package/components/jx-field.json +162 -0
  15. package/components/jx-kbd.json +24 -0
  16. package/components/jx-listbox.json +76 -0
  17. package/components/jx-menu-item.json +5 -12
  18. package/components/jx-menu.json +45 -6
  19. package/components/jx-number-field.json +441 -0
  20. package/components/jx-option.json +350 -0
  21. package/components/jx-popover.json +227 -0
  22. package/components/jx-select.json +637 -0
  23. package/components/jx-spinner.json +129 -0
  24. package/components/jx-split.json +221 -0
  25. package/components/jx-swatch-group.json +107 -0
  26. package/components/jx-swatch.json +262 -0
  27. package/components/jx-switch.json +253 -0
  28. package/components/jx-tab-panel.json +58 -0
  29. package/components/jx-tab.json +296 -0
  30. package/components/jx-tabs.json +124 -0
  31. package/components/jx-textfield.json +639 -0
  32. package/components/jx-toast-host.json +121 -0
  33. package/components/jx-toast.json +255 -0
  34. package/components/jx-toolbar.json +81 -0
  35. package/components/jx-tooltip.json +207 -0
  36. package/components/jx-tree-item.json +325 -0
  37. package/components/jx-tree.json +202 -0
  38. package/icons/list.json +4 -0
  39. package/icons/manifest.json +12 -0
  40. package/package.json +27 -5
  41. package/project.json +164 -153
  42. package/src/behaviors/action-group.ts +255 -0
  43. package/src/behaviors/color-area.ts +303 -0
  44. package/src/behaviors/color-field.ts +465 -0
  45. package/src/behaviors/color-slider.ts +154 -0
  46. package/src/behaviors/combobox.ts +474 -0
  47. package/src/behaviors/dialog.ts +137 -0
  48. package/src/behaviors/listbox.ts +118 -0
  49. package/src/behaviors/menu.ts +80 -48
  50. package/src/behaviors/number-field.ts +161 -0
  51. package/src/behaviors/popover.ts +399 -0
  52. package/src/behaviors/select.ts +154 -0
  53. package/src/behaviors/split.ts +478 -0
  54. package/src/behaviors/swatch-group.ts +297 -0
  55. package/src/behaviors/tabs.ts +319 -0
  56. package/src/behaviors/textfield.ts +164 -0
  57. package/src/behaviors/toast-host.ts +241 -0
  58. package/src/behaviors/toast.ts +261 -0
  59. package/src/behaviors/toolbar.ts +413 -0
  60. package/src/behaviors/tooltip.ts +715 -0
  61. package/src/behaviors/tree.ts +830 -0
  62. package/src/color.ts +433 -0
  63. package/src/documents.ts +91 -1
  64. package/src/index.ts +41 -1
  65. package/src/loaders.ts +47 -0
  66. package/src/testing/anchor-support.ts +28 -0
  67. package/src/testing/popover-shim.ts +39 -6
  68. package/src/theme.ts +30 -6
  69. package/stylebook/jx-accordion-item.json +195 -0
  70. package/stylebook/jx-accordion.json +220 -0
  71. package/stylebook/jx-action-button.json +191 -23
  72. package/stylebook/jx-action-group.json +335 -0
  73. package/stylebook/jx-button.json +129 -26
  74. package/stylebook/jx-checkbox.json +245 -0
  75. package/stylebook/jx-color-area.json +272 -0
  76. package/stylebook/jx-color-field.json +261 -0
  77. package/stylebook/jx-color-slider.json +220 -0
  78. package/stylebook/jx-combobox.json +332 -0
  79. package/stylebook/jx-dialog.json +186 -0
  80. package/stylebook/jx-divider.json +125 -0
  81. package/stylebook/jx-dot.json +92 -0
  82. package/stylebook/jx-field.json +313 -0
  83. package/stylebook/jx-icon.json +4 -0
  84. package/stylebook/jx-kbd.json +90 -0
  85. package/stylebook/jx-listbox.json +337 -0
  86. package/stylebook/jx-menu.json +0 -1
  87. package/stylebook/jx-number-field.json +203 -0
  88. package/stylebook/jx-option.json +285 -0
  89. package/stylebook/jx-popover.json +123 -0
  90. package/stylebook/jx-select.json +407 -0
  91. package/stylebook/jx-spinner.json +111 -0
  92. package/stylebook/jx-split.json +170 -0
  93. package/stylebook/jx-swatch-group.json +175 -0
  94. package/stylebook/jx-swatch.json +249 -0
  95. package/stylebook/jx-switch.json +240 -0
  96. package/stylebook/jx-tab-panel.json +147 -0
  97. package/stylebook/jx-tab.json +201 -0
  98. package/stylebook/jx-tabs.json +278 -0
  99. package/stylebook/jx-textfield.json +309 -0
  100. package/stylebook/jx-toast-host.json +157 -0
  101. package/stylebook/jx-toast.json +266 -0
  102. package/stylebook/jx-toolbar.json +435 -0
  103. package/stylebook/jx-tooltip.json +162 -0
  104. package/stylebook/jx-tree-item.json +258 -0
  105. package/stylebook/jx-tree.json +429 -0
@@ -0,0 +1,544 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxCombobox",
4
+ "tagName": "jx-combobox",
5
+ "observedAttributes": [
6
+ "value",
7
+ "placeholder",
8
+ "label",
9
+ "labelledby",
10
+ "describedby",
11
+ "invalid",
12
+ "disabled",
13
+ "readonly",
14
+ "required",
15
+ "size",
16
+ "name",
17
+ "autocomplete",
18
+ "allows-custom-value",
19
+ "error",
20
+ "help"
21
+ ],
22
+ "$elements": [
23
+ {
24
+ "$ref": "./jx-icon.json"
25
+ },
26
+ {
27
+ "$ref": "./jx-popover.json"
28
+ },
29
+ {
30
+ "$ref": "./jx-option.json"
31
+ },
32
+ {
33
+ "$ref": "./jx-listbox.json"
34
+ }
35
+ ],
36
+ "state": {
37
+ "value": {
38
+ "type": "string",
39
+ "default": "",
40
+ "attribute": "value",
41
+ "description": "The text in the field, which IS the value. A row's label is what it draws and its value is what it commits, and for a combobox those are normally one string: a picker whose rows carry a hidden key is a jx-select. Written by the reader as they type, by a pick, and by the host."
42
+ },
43
+ "options": {
44
+ "type": "array",
45
+ "default": [],
46
+ "description": "The rows to draw, as { value, label?, description?, disabled?, face?, swatch?, line?, weight?, slant?, variant?, transform?, decoration? } — the last eight being jx-option's drawing channels, passed through as they are. THE ELEMENT FILTERS NOTHING: this is the list that will be shown, not a corpus to match against. Every consumer already owns its own matching — a fuzzy ranker that knows about modes and recents, a catalogue fetched from a provider — so a second opinion here would be one more thing for each of them to defeat. A host re-answers it on input. It carries no attribute key, because a list cannot be one. Empty, there is nothing to open: the chevron is not drawn (data-empty) and neither typing nor an arrow shows the panel, so a field whose catalogue has not arrived is a text field until it does."
47
+ },
48
+ "allowsCustomValue": {
49
+ "type": "boolean",
50
+ "default": false,
51
+ "attribute": "allows-custom-value",
52
+ "description": "Whether a value no row holds is kept. Set, the rows are a set of SUGGESTIONS and anything typed stands — which is the reported gap: a model id field whose catalogue is what a provider happens to list, not what the field will accept. Unset, the list is closed and a value no row holds is refused on the COMMIT, putting back the last one that was accepted."
53
+ },
54
+ "label": {
55
+ "type": "string",
56
+ "default": "",
57
+ "attribute": "label",
58
+ "description": "The accessible name, forwarded to the control as aria-label. Required unless labelledby names a visible label. The list takes its own name from it too, so a reader entering the popup hears which field it belongs to."
59
+ },
60
+ "labelledby": {
61
+ "type": "string",
62
+ "default": "",
63
+ "attribute": "labelledby",
64
+ "description": "Forwarded to the inner control as aria-labelledby."
65
+ },
66
+ "describedby": {
67
+ "type": "string",
68
+ "default": "",
69
+ "attribute": "describedby",
70
+ "description": "Forwarded to the inner control as aria-describedby, after the element's own error and help sentences."
71
+ },
72
+ "placeholder": {
73
+ "type": "string",
74
+ "default": "",
75
+ "attribute": "placeholder",
76
+ "description": "Shown while the field is empty. Not a label."
77
+ },
78
+ "name": {
79
+ "type": "string",
80
+ "default": "",
81
+ "attribute": "name",
82
+ "description": "The form field name, forwarded to the control."
83
+ },
84
+ "autocomplete": {
85
+ "type": "string",
86
+ "default": "off",
87
+ "attribute": "autocomplete",
88
+ "description": "The browser's own autofill, forwarded to the control. It defaults to off rather than to nothing, because the UA's own dropdown over a listbox the element is already drawing is two panels answering one question."
89
+ },
90
+ "size": {
91
+ "type": "string",
92
+ "default": "md",
93
+ "attribute": "size",
94
+ "description": "sm, md or lg. The control height is the kit's, so a row of controls lines up."
95
+ },
96
+ "disabled": {
97
+ "type": "boolean",
98
+ "default": false,
99
+ "attribute": "disabled",
100
+ "description": "Cannot be edited, opened or focused."
101
+ },
102
+ "readonly": {
103
+ "type": "boolean",
104
+ "default": false,
105
+ "attribute": "readonly",
106
+ "description": "Can be focused and selected, not edited — and the list never opens, because every row is an edit."
107
+ },
108
+ "required": {
109
+ "type": "boolean",
110
+ "default": false,
111
+ "attribute": "required",
112
+ "description": "Forwarded to the control, for the form it sits in."
113
+ },
114
+ "invalid": {
115
+ "type": "boolean",
116
+ "default": false,
117
+ "attribute": "invalid",
118
+ "description": "The value is refused: the control says aria-invalid and draws in the danger colour."
119
+ },
120
+ "error": {
121
+ "type": "string",
122
+ "default": "",
123
+ "attribute": "error",
124
+ "description": "The sentence explaining a refused value, drawn under the field and announced as it changes. Its region is permanent and empty until there is something to say, so the first refusal is announced rather than only a later one."
125
+ },
126
+ "help": {
127
+ "type": "string",
128
+ "default": "",
129
+ "attribute": "help",
130
+ "description": "A sentence of guidance under the field."
131
+ },
132
+ "open": {
133
+ "type": "boolean",
134
+ "default": false,
135
+ "description": "Whether the list is showing. THIS IS NOT A DOOR: it follows the panel's own toggle event, so a light dismiss and an Escape move it as surely as the chevron does. Writing it opens nothing."
136
+ },
137
+ "activeIndex": {
138
+ "type": "number",
139
+ "default": -1,
140
+ "description": "Which row the caret is on, or -1 for none — and -1 is where a keystroke leaves it, so Enter commits what the READER typed until they arrow onto a row. A list opened by a GESTURE lands on the row the field's value already names: the chevron and Alt+ArrowDown put the caret there, so a catalogue that arrived after the reader typed an id shows it as theirs rather than as a list with nothing chosen. It is kept apart from the rows on purpose: a key moves the highlight without the row list reconciling, and the id it computes is the one string the field and the listbox are both told."
141
+ },
142
+ "committed": {
143
+ "type": "string",
144
+ "default": "",
145
+ "description": "The last value the element accepted, which is what a closed list puts back when it refuses one. Written by the sidecar at mount and on every accepted commit."
146
+ },
147
+ "uid": {
148
+ "type": "string",
149
+ "default": "",
150
+ "description": "This element's own id stem, minted on mount. The panel, the listbox, each row and the two sentences take their ids from it, so a consumer writes none of them and two comboboxes on one surface cannot collide."
151
+ },
152
+ "listId": "${state.uid ? state.uid + '-list' : ''}",
153
+ "panelId": "${state.uid ? state.uid + '-panel' : ''}",
154
+ "activeId": "${state.uid && state.activeIndex >= 0 ? state.uid + '-o' + state.activeIndex : ''}",
155
+ "hasError": {
156
+ "$expression": {
157
+ "operator": "!==",
158
+ "target": {
159
+ "$ref": "#/state/error"
160
+ },
161
+ "value": ""
162
+ }
163
+ },
164
+ "hasHelp": {
165
+ "$expression": {
166
+ "operator": "!==",
167
+ "target": {
168
+ "$ref": "#/state/help"
169
+ },
170
+ "value": ""
171
+ }
172
+ },
173
+ "onMount": {
174
+ "$prototype": "Function",
175
+ "$src": "jx-ui:/behaviors/combobox.ts",
176
+ "$export": "mountCombobox",
177
+ "description": "Mints the id stem and records the value the element starts out holding, so a refused edit has something to be put back to."
178
+ },
179
+ "onInput": {
180
+ "$prototype": "Function",
181
+ "$src": "jx-ui:/behaviors/combobox.ts",
182
+ "$export": "onComboboxInput",
183
+ "description": "Mirrors what the reader types into value, clears the highlight and opens the list — if there is anything to list. The control's own input event goes on to bubble out of the element unchanged, which is how a host knows to re-answer options."
184
+ },
185
+ "onKeydown": {
186
+ "$prototype": "Function",
187
+ "$src": "jx-ui:/behaviors/combobox.ts",
188
+ "$export": "onComboboxKeydown",
189
+ "description": "The editable-combobox keyboard: ArrowDown and ArrowUp open the list and move the caret through it with wrap, Alt+ArrowDown opens without moving and Alt+ArrowUp closes, Enter takes the highlighted row, Tab takes it on the way out, and Escape closes the list and is stopped so it does not also close a dialog around the field. Home and End are left to the text caret."
190
+ },
191
+ "onCommit": {
192
+ "$prototype": "Function",
193
+ "$src": "jx-ui:/behaviors/combobox.ts",
194
+ "$export": "onComboboxCommit",
195
+ "emits": [
196
+ {
197
+ "name": "change",
198
+ "description": "A refused value was put back; e.target is the element. An accepted one lets the control's own change bubble instead, so exactly one change reaches a host per edit."
199
+ }
200
+ ],
201
+ "description": "The commit, on the control's own change. An accepted value stands in the row's spelling; a value a closed list does not hold is put back, the control's change is stopped at the control, and the element says change once for itself."
202
+ },
203
+ "onPick": {
204
+ "$prototype": "Function",
205
+ "$src": "jx-ui:/behaviors/combobox.ts",
206
+ "$export": "onComboboxPick",
207
+ "emits": [
208
+ {
209
+ "name": "input",
210
+ "description": "A row was taken; e.target is the element."
211
+ },
212
+ {
213
+ "name": "change",
214
+ "description": "The edit the pick made is finished; e.target is the element."
215
+ }
216
+ ],
217
+ "description": "A row's own bubbling select: its value into the field, the list closed, the caret back in the control, and one input then change from the element rather than from the row."
218
+ },
219
+ "onToggle": {
220
+ "$prototype": "Function",
221
+ "$src": "jx-ui:/behaviors/combobox.ts",
222
+ "$export": "onComboboxToggle",
223
+ "description": "Mirrors the panel's toggle into open, and drops the highlight when the list closes."
224
+ },
225
+ "onButton": {
226
+ "$prototype": "Function",
227
+ "$src": "jx-ui:/behaviors/combobox.ts",
228
+ "$export": "onComboboxButton",
229
+ "description": "The chevron: shows the list under the field with the caret on the row the field already holds, and puts the text caret in the control — or hides a list that is already showing. Not drawn while there are no rows."
230
+ },
231
+ "onRowsPointerDown": {
232
+ "$prototype": "Function",
233
+ "body": [
234
+ {
235
+ "preventDefault": true
236
+ }
237
+ ],
238
+ "description": "Keeps the caret in the control while the panel's own gutter is pressed. jx-option cancels the press on a row; this is the same cancellation for the space around the rows, so a press that lands between two of them does not blur the field and fire a change for an edit the reader has not finished."
239
+ }
240
+ },
241
+ "onkeydown": {
242
+ "$ref": "#/state/onKeydown"
243
+ },
244
+ "attributes": {
245
+ "data-size": "${state.size}",
246
+ "data-open": "${state.open ? '' : null}",
247
+ "data-empty": "${Array.isArray(state.options) && state.options.length > 0 ? null : ''}",
248
+ "data-invalid": "${state.invalid ? '' : null}",
249
+ "data-disabled": "${state.disabled ? '' : null}"
250
+ },
251
+ "style": {
252
+ "display": "inline-flex",
253
+ "&[hidden]": {
254
+ "display": "none"
255
+ },
256
+ "position": "relative",
257
+ "flexDirection": "column",
258
+ "gap": "var(--jx-space-1)",
259
+ "verticalAlign": "middle",
260
+ "minWidth": "0",
261
+ "--jx-combobox-h": "var(--jx-control-h)",
262
+ "--jx-combobox-pad": "var(--jx-space-3)",
263
+ "&[data-size=\"sm\"]": {
264
+ "--jx-combobox-h": "calc(var(--jx-control-h) - 4px)",
265
+ "--jx-combobox-pad": "var(--jx-space-2)"
266
+ },
267
+ "&[data-size=\"lg\"]": {
268
+ "--jx-combobox-h": "calc(var(--jx-control-h) + 8px)"
269
+ },
270
+ "& [part=\"field\"]": {
271
+ "display": "flex",
272
+ "alignItems": "center",
273
+ "boxSizing": "border-box",
274
+ "width": "100%",
275
+ "minHeight": "var(--jx-combobox-h)",
276
+ "border": "1px solid var(--jx-border-strong)",
277
+ "borderRadius": "var(--jx-radius-sm)",
278
+ "background": "var(--jx-bg-input)",
279
+ "transition": "border-color var(--jx-dur-1) var(--jx-ease-out)",
280
+ ":hover": {
281
+ "borderColor": "var(--jx-fg-muted)"
282
+ },
283
+ ":focus-within": {
284
+ "outline": "var(--jx-focus-ring)",
285
+ "outlineOffset": "-1px"
286
+ }
287
+ },
288
+ "&[data-invalid] [part=\"field\"]": {
289
+ "borderColor": "var(--jx-danger)"
290
+ },
291
+ "&[data-disabled] [part=\"field\"]": {
292
+ "opacity": "0.5"
293
+ },
294
+ "& [part=\"input\"]": {
295
+ "appearance": "none",
296
+ "boxSizing": "border-box",
297
+ "flex": "1 1 auto",
298
+ "minWidth": "0",
299
+ "margin": "0",
300
+ "paddingBlock": "0",
301
+ "paddingInline": "var(--jx-combobox-pad) var(--jx-space-1)",
302
+ "border": "0",
303
+ "background": "none",
304
+ "color": "var(--jx-fg)",
305
+ "font": "inherit",
306
+ "fontFamily": "var(--jx-font-sans)",
307
+ "fontSize": "var(--jx-text-md)",
308
+ "lineHeight": "var(--jx-leading-md)",
309
+ "outline": "none",
310
+ "::placeholder": {
311
+ "color": "var(--jx-fg-muted)"
312
+ },
313
+ ":disabled": {
314
+ "cursor": "default"
315
+ }
316
+ },
317
+ "&[data-size=\"sm\"] [part=\"input\"]": {
318
+ "fontSize": "var(--jx-text-sm)"
319
+ },
320
+ "&[data-size=\"lg\"] [part=\"input\"]": {
321
+ "fontSize": "var(--jx-text-lg)"
322
+ },
323
+ "& [part=\"toggle\"]": {
324
+ "display": "inline-flex",
325
+ "alignItems": "center",
326
+ "justifyContent": "center",
327
+ "boxSizing": "border-box",
328
+ "flex": "0 0 auto",
329
+ "width": "calc(var(--jx-combobox-h) - 2px)",
330
+ "height": "calc(var(--jx-combobox-h) - 2px)",
331
+ "margin": "0",
332
+ "padding": "0",
333
+ "appearance": "none",
334
+ "border": "0",
335
+ "borderRadius": "var(--jx-radius-sm)",
336
+ "background": "transparent",
337
+ "color": "var(--jx-fg-muted)",
338
+ "cursor": "pointer",
339
+ "outline": "none",
340
+ "transition": "rotate var(--jx-dur-1) var(--jx-ease-out)",
341
+ ":hover": {
342
+ "color": "var(--jx-fg)"
343
+ },
344
+ ":focus-visible": {
345
+ "outline": "var(--jx-focus-ring)",
346
+ "outlineOffset": "-1px"
347
+ }
348
+ },
349
+ "&[data-open] [part=\"toggle\"]": {
350
+ "rotate": "180deg"
351
+ },
352
+ "&[data-empty] [part=\"toggle\"]": {
353
+ "display": "none"
354
+ },
355
+ "&[data-empty] [part=\"input\"]": {
356
+ "paddingInlineEnd": "var(--jx-combobox-pad)"
357
+ },
358
+ "& [part=\"list\"]": {
359
+ "--jx-listbox-max-block-size": "min(320px, 50vh)",
360
+ "minWidth": "0"
361
+ },
362
+ "& [part=\"error\"], & [part=\"help\"]": {
363
+ "margin": "0",
364
+ "fontSize": "var(--jx-text-sm)",
365
+ "lineHeight": "var(--jx-leading-sm)",
366
+ "color": "var(--jx-fg-dim)"
367
+ },
368
+ "& [part=\"error\"]": {
369
+ "color": "var(--jx-danger)"
370
+ },
371
+ "& [part=\"error\"]:empty": {
372
+ "position": "absolute"
373
+ },
374
+ "& > [part=\"help-slot\"]": {
375
+ "display": "contents"
376
+ }
377
+ },
378
+ "children": [
379
+ {
380
+ "tagName": "div",
381
+ "attributes": {
382
+ "part": "field",
383
+ "role": "none"
384
+ },
385
+ "children": [
386
+ {
387
+ "tagName": "input",
388
+ "attributes": {
389
+ "part": "input",
390
+ "type": "text",
391
+ "role": "combobox",
392
+ "autocomplete": "${state.autocomplete}",
393
+ "aria-autocomplete": "list",
394
+ "aria-controls": "${state.listId || null}",
395
+ "aria-expanded": "${state.open ? 'true' : 'false'}",
396
+ "aria-activedescendant": "${state.open && state.activeId ? state.activeId : null}",
397
+ "aria-label": "${state.label || null}",
398
+ "aria-labelledby": "${state.labelledby || null}",
399
+ "aria-describedby": "${[state.hasError && state.uid ? state.uid + '-error' : null, state.hasHelp && state.uid ? state.uid + '-help' : null, state.describedby || null].filter(Boolean).join(' ') || null}",
400
+ "aria-invalid": "${state.invalid ? 'true' : null}",
401
+ "placeholder": "${state.placeholder || null}",
402
+ "name": "${state.name || null}",
403
+ "disabled": {
404
+ "$ref": "#/state/disabled"
405
+ },
406
+ "readonly": {
407
+ "$ref": "#/state/readonly"
408
+ },
409
+ "required": {
410
+ "$ref": "#/state/required"
411
+ },
412
+ "value": "${state.value}"
413
+ },
414
+ "value": {
415
+ "$ref": "#/state/value"
416
+ },
417
+ "oninput": {
418
+ "$ref": "#/state/onInput"
419
+ },
420
+ "onchange": {
421
+ "$ref": "#/state/onCommit"
422
+ }
423
+ },
424
+ {
425
+ "tagName": "button",
426
+ "attributes": {
427
+ "part": "toggle",
428
+ "type": "button",
429
+ "tabindex": "-1",
430
+ "aria-label": "Show suggestions",
431
+ "disabled": {
432
+ "$ref": "#/state/disabled"
433
+ }
434
+ },
435
+ "onclick": {
436
+ "$ref": "#/state/onButton"
437
+ },
438
+ "children": [
439
+ {
440
+ "tagName": "jx-icon",
441
+ "$props": {
442
+ "name": "caret-down"
443
+ },
444
+ "attributes": {
445
+ "part": "toggle-icon"
446
+ }
447
+ }
448
+ ]
449
+ }
450
+ ]
451
+ },
452
+ {
453
+ "$description": "match-width, because a list narrower than its field reads as belonging to something else: the panel measures the HOST the sidecar names as its source, so the rows are as wide as the text box plus the chevron beside it.",
454
+ "tagName": "jx-popover",
455
+ "attributes": {
456
+ "part": "popup",
457
+ "match-width": "",
458
+ "id": "${state.panelId || null}"
459
+ },
460
+ "ontoggle": {
461
+ "$ref": "#/state/onToggle"
462
+ },
463
+ "children": [
464
+ {
465
+ "tagName": "jx-listbox",
466
+ "attributes": {
467
+ "part": "list",
468
+ "id": "${state.listId || null}"
469
+ },
470
+ "$props": {
471
+ "label": "${state.label || 'Suggestions'}",
472
+ "active": "${state.activeId}"
473
+ },
474
+ "onselect": {
475
+ "$ref": "#/state/onPick"
476
+ },
477
+ "onpointerdown": {
478
+ "$ref": "#/state/onRowsPointerDown"
479
+ },
480
+ "children": [
481
+ {
482
+ "$prototype": "Array",
483
+ "items": {
484
+ "$ref": "#/state/options"
485
+ },
486
+ "key": {
487
+ "$ref": "$map/item/value"
488
+ },
489
+ "map": {
490
+ "tagName": "jx-option",
491
+ "attributes": {
492
+ "part": "option",
493
+ "id": "${state.uid}-o${$map.index}",
494
+ "value": "${$map.item.value}",
495
+ "label": "${$map.item.label || $map.item.value}",
496
+ "description": "${$map.item.description || ''}",
497
+ "face": "${$map.item.face || ''}",
498
+ "swatch": "${$map.item.swatch || ''}",
499
+ "line": "${$map.item.line || ''}",
500
+ "weight": "${$map.item.weight || ''}",
501
+ "slant": "${$map.item.slant || ''}",
502
+ "variant": "${$map.item.variant || ''}",
503
+ "transform": "${$map.item.transform || ''}",
504
+ "decoration": "${$map.item.decoration || ''}",
505
+ "disabled": "${!!$map.item.disabled}"
506
+ }
507
+ }
508
+ }
509
+ ]
510
+ }
511
+ ]
512
+ },
513
+ {
514
+ "tagName": "p",
515
+ "attributes": {
516
+ "part": "error",
517
+ "id": "${state.uid ? state.uid + '-error' : null}",
518
+ "role": "status",
519
+ "aria-live": "polite"
520
+ },
521
+ "textContent": "${state.error}"
522
+ },
523
+ {
524
+ "tagName": "div",
525
+ "attributes": {
526
+ "role": "none",
527
+ "part": "help-slot"
528
+ },
529
+ "$switch": {
530
+ "$ref": "#/state/hasHelp"
531
+ },
532
+ "cases": {
533
+ "true": {
534
+ "tagName": "p",
535
+ "attributes": {
536
+ "part": "help",
537
+ "id": "${state.uid ? state.uid + '-help' : null}"
538
+ },
539
+ "textContent": "${state.help}"
540
+ }
541
+ }
542
+ }
543
+ ]
544
+ }