@jxsuite/ui 0.0.0 → 0.2.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 +268 -34
  4. package/components/jx-action-group.json +131 -0
  5. package/components/jx-button.json +141 -26
  6. package/components/jx-checkbox.json +222 -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 +551 -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 +6 -13
  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 +331 -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 +645 -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 +719 -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,645 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxTextfield",
4
+ "tagName": "jx-textfield",
5
+ "observedAttributes": [
6
+ "value",
7
+ "placeholder",
8
+ "type",
9
+ "label",
10
+ "labelledby",
11
+ "describedby",
12
+ "invalid",
13
+ "disabled",
14
+ "readonly",
15
+ "required",
16
+ "mono",
17
+ "multiline",
18
+ "grows",
19
+ "rows",
20
+ "clearable",
21
+ "size",
22
+ "name",
23
+ "autocomplete",
24
+ "error",
25
+ "help"
26
+ ],
27
+ "$elements": [
28
+ {
29
+ "$ref": "./jx-icon.json"
30
+ }
31
+ ],
32
+ "state": {
33
+ "value": {
34
+ "type": "string",
35
+ "default": "",
36
+ "attribute": "value",
37
+ "description": "The field's text. Written by the reader as they type, and by the host; a write equal to what is there never moves the caret. It is written to the control's value CONTENT attribute as well as its property, which makes the control's default value whatever the field currently says. That is deliberate: the element is not form-associated (specs/ui.md §3.2), so it never hears form.reset(), and a control whose default was the authored one would snap back while the element still said something else — an element and its own control disagreeing in silence. The cost is named rather than hidden: reset() is a no-op on this field until form association lands."
38
+ },
39
+ "placeholder": {
40
+ "type": "string",
41
+ "default": "",
42
+ "attribute": "placeholder",
43
+ "description": "Shown while the field is empty. Not a label."
44
+ },
45
+ "type": {
46
+ "type": "string",
47
+ "default": "text",
48
+ "attribute": "type",
49
+ "description": "The native input type: text, search, email, url, password, number or tel."
50
+ },
51
+ "label": {
52
+ "type": "string",
53
+ "default": "",
54
+ "attribute": "label",
55
+ "description": "The accessible name, forwarded to the control as aria-label. Required unless a visible label points at the control."
56
+ },
57
+ "labelledby": {
58
+ "type": "string",
59
+ "default": "",
60
+ "attribute": "labelledby",
61
+ "description": "Forwarded to the inner control as aria-labelledby."
62
+ },
63
+ "describedby": {
64
+ "type": "string",
65
+ "default": "",
66
+ "attribute": "describedby",
67
+ "description": "Forwarded to the inner control as aria-describedby, after the field's own error and help sentences."
68
+ },
69
+ "invalid": {
70
+ "type": "boolean",
71
+ "default": false,
72
+ "attribute": "invalid",
73
+ "description": "The value is refused: the control says aria-invalid and draws in the danger colour."
74
+ },
75
+ "disabled": {
76
+ "type": "boolean",
77
+ "default": false,
78
+ "attribute": "disabled",
79
+ "description": "Cannot be edited or focused. Clearing is an edit, so a disabled field draws no clear button and Escape empties nothing: a host that switched the control off hears no input or change from it."
80
+ },
81
+ "readonly": {
82
+ "type": "boolean",
83
+ "default": false,
84
+ "attribute": "readonly",
85
+ "description": "Can be focused and selected, not edited. Clearing is an edit, so a read-only field draws no clear button and Escape empties nothing."
86
+ },
87
+ "required": {
88
+ "type": "boolean",
89
+ "default": false,
90
+ "attribute": "required",
91
+ "description": "Forwarded to the control, for the form it sits in."
92
+ },
93
+ "mono": {
94
+ "type": "boolean",
95
+ "default": false,
96
+ "attribute": "mono",
97
+ "description": "Draws the value in the monospace face: a path, a selector, a colour."
98
+ },
99
+ "multiline": {
100
+ "type": "boolean",
101
+ "default": false,
102
+ "attribute": "multiline",
103
+ "description": "A textarea rather than an input."
104
+ },
105
+ "grows": {
106
+ "type": "boolean",
107
+ "default": false,
108
+ "attribute": "grows",
109
+ "description": "A multiline field takes the height of its text instead of scrolling inside a fixed box. field-sizing does the work, so nothing is measured and no handler runs per keystroke. Where the engine does not support it the field keeps the height rows asks for, and a growing field with no rows keeps the three-row box a fixed one gets — opting into growth never makes a field shorter than not opting in."
110
+ },
111
+ "rows": {
112
+ "type": "string",
113
+ "default": "",
114
+ "attribute": "rows",
115
+ "description": "How many lines a multiline field is tall before it grows. Forwarded to the textarea, and it is what a growing field falls back to on an engine without field-sizing."
116
+ },
117
+ "clearable": {
118
+ "type": "boolean",
119
+ "default": false,
120
+ "attribute": "clearable",
121
+ "description": "Draws a button inside the field that empties it, shown only while there is something to clear and the field is neither disabled nor read-only. Escape empties the field on exactly the same terms. Firefox draws no clear affordance of its own for type=search, so this is the field's own rather than the platform's."
122
+ },
123
+ "size": {
124
+ "type": "string",
125
+ "default": "md",
126
+ "attribute": "size",
127
+ "description": "sm, md or lg. The control height is the kit's, so a row of controls lines up."
128
+ },
129
+ "name": {
130
+ "type": "string",
131
+ "default": "",
132
+ "attribute": "name",
133
+ "description": "The form field name, forwarded to the control."
134
+ },
135
+ "autocomplete": {
136
+ "type": "string",
137
+ "default": "",
138
+ "attribute": "autocomplete",
139
+ "description": "The autocomplete purpose, forwarded to the control."
140
+ },
141
+ "tabindex": {
142
+ "type": "string",
143
+ "default": "",
144
+ "description": "Forwarded to the inner control as its tabindex, which is what makes a roving caret possible: the focusable node is the control inside, not the host, so a jx-toolbar moving focus writes this rather than reaching into a child's internals. It is a PROPERTY ONLY (el.tabindex = \"0\") and deliberately not an observed attribute: written as an attribute it would land on the host as well, and a host carrying tabindex is itself focusable, so the one control would become two tab stops. The clear button is NOT given it: it is already tabindex=\"-1\" by construction, so the field is one stop whatever the toolbar writes."
145
+ },
146
+ "error": {
147
+ "type": "string",
148
+ "default": "",
149
+ "attribute": "error",
150
+ "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; the empty region is taken out of flow rather than hidden, so it costs no layout and stays in the accessibility tree."
151
+ },
152
+ "help": {
153
+ "type": "string",
154
+ "default": "",
155
+ "attribute": "help",
156
+ "description": "A sentence of guidance under the field."
157
+ },
158
+ "hasError": {
159
+ "$expression": {
160
+ "operator": "!==",
161
+ "target": {
162
+ "$ref": "#/state/error"
163
+ },
164
+ "value": ""
165
+ }
166
+ },
167
+ "hasHelp": {
168
+ "$expression": {
169
+ "operator": "!==",
170
+ "target": {
171
+ "$ref": "#/state/help"
172
+ },
173
+ "value": ""
174
+ }
175
+ },
176
+ "isEmpty": {
177
+ "$expression": {
178
+ "operator": "===",
179
+ "target": {
180
+ "$ref": "#/state/value"
181
+ },
182
+ "value": ""
183
+ }
184
+ },
185
+ "isLocked": {
186
+ "$expression": {
187
+ "operator": "||",
188
+ "target": {
189
+ "$ref": "#/state/disabled"
190
+ },
191
+ "value": {
192
+ "$ref": "#/state/readonly"
193
+ }
194
+ }
195
+ },
196
+ "showClear": {
197
+ "$expression": {
198
+ "operator": "&&",
199
+ "target": {
200
+ "operator": "&&",
201
+ "target": {
202
+ "$ref": "#/state/clearable"
203
+ },
204
+ "value": {
205
+ "operator": "!",
206
+ "target": {
207
+ "$ref": "#/state/isEmpty"
208
+ }
209
+ }
210
+ },
211
+ "value": {
212
+ "operator": "!",
213
+ "target": {
214
+ "$ref": "#/state/isLocked"
215
+ }
216
+ }
217
+ }
218
+ },
219
+ "uid": {
220
+ "type": "string",
221
+ "default": "",
222
+ "description": "This field's own id stem, minted on mount. The error and help sentences take their ids from it, and the control names those ids in aria-describedby."
223
+ },
224
+ "onMount": {
225
+ "$prototype": "Function",
226
+ "$src": "jx-ui:/behaviors/textfield.ts",
227
+ "$export": "mintFieldId",
228
+ "description": "Mints the field's id stem, so the sentences under it can describe the control rather than only being announced once as they change."
229
+ },
230
+ "onInput": {
231
+ "$prototype": "Function",
232
+ "body": [
233
+ {
234
+ "operator": "=",
235
+ "target": {
236
+ "$ref": "#/state/value"
237
+ },
238
+ "value": {
239
+ "$ref": "event#/target/value"
240
+ }
241
+ }
242
+ ],
243
+ "description": "Mirrors what the reader types into value. The native input and change events bubble from the control as they always do."
244
+ },
245
+ "onClear": {
246
+ "$prototype": "Function",
247
+ "$src": "jx-ui:/behaviors/textfield.ts",
248
+ "$export": "clearField",
249
+ "emits": [
250
+ {
251
+ "name": "input",
252
+ "description": "The value was emptied by the clear button; e.target is the field."
253
+ },
254
+ {
255
+ "name": "change",
256
+ "description": "The edit the clear button made is finished; e.target is the field."
257
+ }
258
+ ],
259
+ "description": "The clear button empties the value, puts focus back on the control the reader was in, and says so with input and then change. Both come from the element rather than from the button, so a host reading e.target.value reads the field."
260
+ },
261
+ "onClearPointerDown": {
262
+ "$prototype": "Function",
263
+ "body": [
264
+ {
265
+ "preventDefault": true
266
+ }
267
+ ],
268
+ "description": "Keeps focus in the control while the clear button is pressed. Without it the press moves focus to the button, the control blurs and fires its own native change carrying the value the reader is about to delete, and the clear then fires a second one: two committed edits, and two undo entries, for one gesture."
269
+ },
270
+ "onKeydown": {
271
+ "$prototype": "Function",
272
+ "body": [
273
+ {
274
+ "$switch": {
275
+ "$ref": "event#/key"
276
+ },
277
+ "cases": {
278
+ "Escape": [
279
+ {
280
+ "if": {
281
+ "$ref": "#/state/showClear"
282
+ },
283
+ "then": [
284
+ {
285
+ "preventDefault": true
286
+ },
287
+ {
288
+ "operator": "=",
289
+ "target": {
290
+ "$ref": "#/state/value"
291
+ },
292
+ "value": ""
293
+ },
294
+ {
295
+ "dispatchEvent": "input",
296
+ "bubbles": true
297
+ },
298
+ {
299
+ "dispatchEvent": "change",
300
+ "bubbles": true
301
+ }
302
+ ]
303
+ }
304
+ ],
305
+ "Enter": [
306
+ {
307
+ "if": {
308
+ "operator": "&&",
309
+ "target": {
310
+ "operator": "===",
311
+ "target": {
312
+ "$ref": "#/state/type"
313
+ },
314
+ "value": "search"
315
+ },
316
+ "value": {
317
+ "operator": "!",
318
+ "target": {
319
+ "$ref": "#/state/multiline"
320
+ }
321
+ }
322
+ },
323
+ "then": [
324
+ {
325
+ "preventDefault": true
326
+ }
327
+ ]
328
+ }
329
+ ]
330
+ }
331
+ }
332
+ ],
333
+ "emits": [
334
+ {
335
+ "name": "input",
336
+ "description": "Escape emptied a clearable field; e.target is the field."
337
+ },
338
+ {
339
+ "name": "change",
340
+ "description": "Escape finished emptying a clearable field; e.target is the field."
341
+ }
342
+ ],
343
+ "description": "Two keys, and nothing else. Escape empties a clearable field that has something in it, and cancels so the key does not also close whatever the field sits in. Enter is cancelled on a single-line search field: a search input inside a form submits it, and a search field is the one kind that never means to — the element owns no form, so the guard lives here rather than at every call site. A textarea never submits on Enter, so a multiline field keeps the key and the reader keeps the newline."
344
+ }
345
+ },
346
+ "onkeydown": {
347
+ "$ref": "#/state/onKeydown"
348
+ },
349
+ "attributes": {
350
+ "data-size": "${state.size}",
351
+ "data-invalid": "${state.invalid ? '' : null}",
352
+ "data-mono": "${state.mono ? '' : null}",
353
+ "data-disabled": "${state.disabled ? '' : null}",
354
+ "data-clearable": "${state.clearable ? '' : null}",
355
+ "data-multiline": "${state.multiline ? '' : null}",
356
+ "data-grows": "${state.grows ? '' : null}",
357
+ "data-rows": "${state.rows || null}"
358
+ },
359
+ "style": {
360
+ "display": "inline-flex",
361
+ "position": "relative",
362
+ "flexDirection": "column",
363
+ "gap": "var(--jx-space-1)",
364
+ "verticalAlign": "middle",
365
+ "minWidth": "0",
366
+ "--jx-textfield-h": "var(--jx-control-h)",
367
+ "--jx-textfield-pad": "var(--jx-space-3)",
368
+ "--jx-textfield-pad-end": "var(--jx-textfield-pad)",
369
+ "&[hidden]": {
370
+ "display": "none"
371
+ },
372
+ "&[data-size=\"sm\"]": {
373
+ "--jx-textfield-h": "calc(var(--jx-control-h) - 4px)",
374
+ "--jx-textfield-pad": "var(--jx-space-2)"
375
+ },
376
+ "&[data-size=\"lg\"]": {
377
+ "--jx-textfield-h": "calc(var(--jx-control-h) + 8px)"
378
+ },
379
+ "&[data-clearable]": {
380
+ "--jx-textfield-pad-end": "var(--jx-textfield-h)"
381
+ },
382
+ "& [part=\"input\"]": {
383
+ "appearance": "none",
384
+ "boxSizing": "border-box",
385
+ "width": "100%",
386
+ "minHeight": "var(--jx-textfield-h)",
387
+ "margin": "0",
388
+ "paddingBlock": "0",
389
+ "paddingInline": "var(--jx-textfield-pad) var(--jx-textfield-pad-end)",
390
+ "border": "1px solid var(--jx-border-strong)",
391
+ "borderRadius": "var(--jx-radius-sm)",
392
+ "background": "var(--jx-bg-input)",
393
+ "color": "var(--jx-fg)",
394
+ "font": "inherit",
395
+ "fontFamily": "var(--jx-font-sans)",
396
+ "fontSize": "var(--jx-text-md)",
397
+ "lineHeight": "var(--jx-leading-md)",
398
+ "outline": "none",
399
+ "transition": "border-color var(--jx-dur-1) var(--jx-ease-out)",
400
+ "::placeholder": {
401
+ "color": "var(--jx-fg-muted)"
402
+ },
403
+ ":hover": {
404
+ "borderColor": "var(--jx-fg-muted)"
405
+ },
406
+ ":focus-visible": {
407
+ "outline": "var(--jx-focus-ring)",
408
+ "outlineOffset": "-1px"
409
+ },
410
+ ":disabled": {
411
+ "opacity": "0.5",
412
+ "cursor": "default"
413
+ }
414
+ },
415
+ "& textarea[part=\"input\"]": {
416
+ "minHeight": "calc(var(--jx-textfield-h) * 3)",
417
+ "paddingBlock": "var(--jx-space-2)",
418
+ "resize": "vertical"
419
+ },
420
+ "&[data-grows] textarea[part=\"input\"]": {
421
+ "fieldSizing": "content",
422
+ "resize": "none"
423
+ },
424
+ "&[data-grows][data-rows] textarea[part=\"input\"]": {
425
+ "minHeight": "0"
426
+ },
427
+ "@supports (field-sizing: content)": {
428
+ "&[data-grows] textarea[part=\"input\"]": {
429
+ "minHeight": "0"
430
+ }
431
+ },
432
+ "&[data-mono] [part=\"input\"]": {
433
+ "fontFamily": "var(--jx-font-mono)"
434
+ },
435
+ "&[data-invalid] [part=\"input\"]": {
436
+ "borderColor": "var(--jx-danger)"
437
+ },
438
+ "&[data-clearable] [part=\"input\"]": {
439
+ "::-webkit-search-cancel-button": {
440
+ "appearance": "none"
441
+ }
442
+ },
443
+ "&[data-size=\"sm\"] [part=\"input\"]": {
444
+ "fontSize": "var(--jx-text-sm)"
445
+ },
446
+ "&[data-size=\"lg\"] [part=\"input\"]": {
447
+ "fontSize": "var(--jx-text-lg)"
448
+ },
449
+ "& [part=\"clear\"]": {
450
+ "$description": "The clear button sits inside the field's border, so it draws 2px under the field's height: 22px in a 24px field, and 18px in an `sm` one. The `::before` is its hit area (WCAG 2.2 SC 2.5.8, ui.md \u00a74.3): an empty pseudo-element inset by half the difference between the drawn box and the kit's control height, which is -1px on a default field and -3px on a small one, so the region that accepts the pointer is `--jx-control-h` square at every size while the glyph and its hover box stay where they were. On a large field the difference is positive and the pseudo-element is an invisible box INSIDE a button that is already over the floor, which changes nothing. jx-tab's close button is the technique; the button is absolutely positioned already, so it is its own containing block. The extension lies over the input it clears, which was true of the drawn button too, and 2px past the field's edge at `sm`, where a neighbour at the kit's 4px gap extends 2px back and the two abut.",
451
+ "position": "absolute",
452
+ "insetBlockStart": "1px",
453
+ "insetInlineEnd": "1px",
454
+ "::before": {
455
+ "content": "\"\"",
456
+ "position": "absolute",
457
+ "inset": "calc((var(--jx-textfield-h) - 2px - var(--jx-control-h)) / 2)"
458
+ },
459
+ "display": "inline-flex",
460
+ "alignItems": "center",
461
+ "justifyContent": "center",
462
+ "boxSizing": "border-box",
463
+ "width": "calc(var(--jx-textfield-h) - 2px)",
464
+ "height": "calc(var(--jx-textfield-h) - 2px)",
465
+ "margin": "0",
466
+ "padding": "0",
467
+ "appearance": "none",
468
+ "border": "0",
469
+ "borderRadius": "var(--jx-radius-sm)",
470
+ "background": "transparent",
471
+ "color": "var(--jx-fg-muted)",
472
+ "cursor": "pointer",
473
+ "outline": "none",
474
+ ":hover": {
475
+ "color": "var(--jx-fg)"
476
+ },
477
+ ":focus-visible": {
478
+ "outline": "var(--jx-focus-ring)",
479
+ "outlineOffset": "-1px"
480
+ }
481
+ },
482
+ "&[data-multiline] [part=\"clear\"]": {
483
+ "insetBlockStart": "calc(var(--jx-space-2) + 1px)"
484
+ },
485
+ "& [part=\"error\"], & [part=\"help\"]": {
486
+ "margin": "0",
487
+ "fontSize": "var(--jx-text-sm)",
488
+ "lineHeight": "var(--jx-leading-sm)",
489
+ "color": "var(--jx-fg-dim)"
490
+ },
491
+ "& [part=\"error\"]": {
492
+ "color": "var(--jx-danger)"
493
+ },
494
+ "& [part=\"error\"]:empty": {
495
+ "position": "absolute"
496
+ },
497
+ "& > [part=\"control-slot\"], & > [part=\"clear-slot\"], & > [part=\"help-slot\"]": {
498
+ "display": "contents"
499
+ }
500
+ },
501
+ "children": [
502
+ {
503
+ "tagName": "div",
504
+ "attributes": {
505
+ "role": "none",
506
+ "part": "control-slot"
507
+ },
508
+ "$switch": {
509
+ "$ref": "#/state/multiline"
510
+ },
511
+ "cases": {
512
+ "false": {
513
+ "tagName": "input",
514
+ "attributes": {
515
+ "part": "input",
516
+ "type": "${state.type}",
517
+ "placeholder": "${state.placeholder || null}",
518
+ "aria-label": "${state.label || null}",
519
+ "aria-labelledby": "${state.labelledby || null}",
520
+ "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}",
521
+ "aria-invalid": "${state.invalid ? 'true' : null}",
522
+ "tabindex": "${state.tabindex || null}",
523
+ "name": "${state.name || null}",
524
+ "autocomplete": "${state.autocomplete || null}",
525
+ "disabled": {
526
+ "$ref": "#/state/disabled"
527
+ },
528
+ "readonly": {
529
+ "$ref": "#/state/readonly"
530
+ },
531
+ "required": {
532
+ "$ref": "#/state/required"
533
+ },
534
+ "value": "${state.value}"
535
+ },
536
+ "value": {
537
+ "$ref": "#/state/value"
538
+ },
539
+ "oninput": {
540
+ "$ref": "#/state/onInput"
541
+ }
542
+ },
543
+ "true": {
544
+ "tagName": "textarea",
545
+ "attributes": {
546
+ "part": "input",
547
+ "placeholder": "${state.placeholder || null}",
548
+ "rows": "${state.rows || null}",
549
+ "aria-label": "${state.label || null}",
550
+ "aria-labelledby": "${state.labelledby || null}",
551
+ "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}",
552
+ "aria-invalid": "${state.invalid ? 'true' : null}",
553
+ "tabindex": "${state.tabindex || null}",
554
+ "name": "${state.name || null}",
555
+ "autocomplete": "${state.autocomplete || null}",
556
+ "disabled": {
557
+ "$ref": "#/state/disabled"
558
+ },
559
+ "readonly": {
560
+ "$ref": "#/state/readonly"
561
+ },
562
+ "required": {
563
+ "$ref": "#/state/required"
564
+ }
565
+ },
566
+ "textContent": "${state.value}",
567
+ "value": {
568
+ "$ref": "#/state/value"
569
+ },
570
+ "oninput": {
571
+ "$ref": "#/state/onInput"
572
+ }
573
+ }
574
+ }
575
+ },
576
+ {
577
+ "tagName": "div",
578
+ "attributes": {
579
+ "role": "none",
580
+ "part": "clear-slot"
581
+ },
582
+ "$switch": {
583
+ "$ref": "#/state/showClear"
584
+ },
585
+ "cases": {
586
+ "true": {
587
+ "tagName": "button",
588
+ "attributes": {
589
+ "part": "clear",
590
+ "type": "button",
591
+ "tabindex": "-1",
592
+ "aria-label": "Clear"
593
+ },
594
+ "onclick": {
595
+ "$ref": "#/state/onClear"
596
+ },
597
+ "onpointerdown": {
598
+ "$ref": "#/state/onClearPointerDown"
599
+ },
600
+ "children": [
601
+ {
602
+ "tagName": "jx-icon",
603
+ "$props": {
604
+ "name": "x"
605
+ },
606
+ "attributes": {
607
+ "part": "clear-icon"
608
+ }
609
+ }
610
+ ]
611
+ }
612
+ }
613
+ },
614
+ {
615
+ "tagName": "p",
616
+ "attributes": {
617
+ "part": "error",
618
+ "id": "${state.uid ? state.uid + '-error' : null}",
619
+ "role": "status",
620
+ "aria-live": "polite"
621
+ },
622
+ "textContent": "${state.error}"
623
+ },
624
+ {
625
+ "tagName": "div",
626
+ "attributes": {
627
+ "role": "none",
628
+ "part": "help-slot"
629
+ },
630
+ "$switch": {
631
+ "$ref": "#/state/hasHelp"
632
+ },
633
+ "cases": {
634
+ "true": {
635
+ "tagName": "p",
636
+ "attributes": {
637
+ "part": "help",
638
+ "id": "${state.uid ? state.uid + '-help' : null}"
639
+ },
640
+ "textContent": "${state.help}"
641
+ }
642
+ }
643
+ }
644
+ ]
645
+ }