@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.
- package/components/jx-accordion-item.json +281 -0
- package/components/jx-accordion.json +33 -0
- package/components/jx-action-button.json +268 -34
- package/components/jx-action-group.json +131 -0
- package/components/jx-button.json +141 -26
- package/components/jx-checkbox.json +222 -0
- package/components/jx-color-area.json +263 -0
- package/components/jx-color-field.json +565 -0
- package/components/jx-color-slider.json +216 -0
- package/components/jx-combobox.json +551 -0
- package/components/jx-dialog.json +416 -0
- package/components/jx-divider.json +52 -0
- package/components/jx-dot.json +38 -0
- package/components/jx-field.json +162 -0
- package/components/jx-kbd.json +24 -0
- package/components/jx-listbox.json +76 -0
- package/components/jx-menu-item.json +6 -13
- package/components/jx-menu.json +45 -6
- package/components/jx-number-field.json +441 -0
- package/components/jx-option.json +350 -0
- package/components/jx-popover.json +227 -0
- package/components/jx-select.json +637 -0
- package/components/jx-spinner.json +129 -0
- package/components/jx-split.json +221 -0
- package/components/jx-swatch-group.json +107 -0
- package/components/jx-swatch.json +262 -0
- package/components/jx-switch.json +331 -0
- package/components/jx-tab-panel.json +58 -0
- package/components/jx-tab.json +296 -0
- package/components/jx-tabs.json +124 -0
- package/components/jx-textfield.json +645 -0
- package/components/jx-toast-host.json +121 -0
- package/components/jx-toast.json +255 -0
- package/components/jx-toolbar.json +81 -0
- package/components/jx-tooltip.json +207 -0
- package/components/jx-tree-item.json +325 -0
- package/components/jx-tree.json +202 -0
- package/icons/list.json +4 -0
- package/icons/manifest.json +12 -0
- package/package.json +27 -5
- package/project.json +164 -153
- package/src/behaviors/action-group.ts +255 -0
- package/src/behaviors/color-area.ts +303 -0
- package/src/behaviors/color-field.ts +465 -0
- package/src/behaviors/color-slider.ts +154 -0
- package/src/behaviors/combobox.ts +474 -0
- package/src/behaviors/dialog.ts +137 -0
- package/src/behaviors/listbox.ts +118 -0
- package/src/behaviors/menu.ts +80 -48
- package/src/behaviors/number-field.ts +161 -0
- package/src/behaviors/popover.ts +399 -0
- package/src/behaviors/select.ts +154 -0
- package/src/behaviors/split.ts +478 -0
- package/src/behaviors/swatch-group.ts +297 -0
- package/src/behaviors/tabs.ts +319 -0
- package/src/behaviors/textfield.ts +164 -0
- package/src/behaviors/toast-host.ts +241 -0
- package/src/behaviors/toast.ts +261 -0
- package/src/behaviors/toolbar.ts +413 -0
- package/src/behaviors/tooltip.ts +719 -0
- package/src/behaviors/tree.ts +830 -0
- package/src/color.ts +433 -0
- package/src/documents.ts +91 -1
- package/src/index.ts +41 -1
- package/src/loaders.ts +47 -0
- package/src/testing/anchor-support.ts +28 -0
- package/src/testing/popover-shim.ts +39 -6
- package/src/theme.ts +30 -6
- package/stylebook/jx-accordion-item.json +195 -0
- package/stylebook/jx-accordion.json +220 -0
- package/stylebook/jx-action-button.json +191 -23
- package/stylebook/jx-action-group.json +335 -0
- package/stylebook/jx-button.json +129 -26
- package/stylebook/jx-checkbox.json +245 -0
- package/stylebook/jx-color-area.json +272 -0
- package/stylebook/jx-color-field.json +261 -0
- package/stylebook/jx-color-slider.json +220 -0
- package/stylebook/jx-combobox.json +332 -0
- package/stylebook/jx-dialog.json +186 -0
- package/stylebook/jx-divider.json +125 -0
- package/stylebook/jx-dot.json +92 -0
- package/stylebook/jx-field.json +313 -0
- package/stylebook/jx-icon.json +4 -0
- package/stylebook/jx-kbd.json +90 -0
- package/stylebook/jx-listbox.json +337 -0
- package/stylebook/jx-menu.json +0 -1
- package/stylebook/jx-number-field.json +203 -0
- package/stylebook/jx-option.json +285 -0
- package/stylebook/jx-popover.json +123 -0
- package/stylebook/jx-select.json +407 -0
- package/stylebook/jx-spinner.json +111 -0
- package/stylebook/jx-split.json +170 -0
- package/stylebook/jx-swatch-group.json +175 -0
- package/stylebook/jx-swatch.json +249 -0
- package/stylebook/jx-switch.json +240 -0
- package/stylebook/jx-tab-panel.json +147 -0
- package/stylebook/jx-tab.json +201 -0
- package/stylebook/jx-tabs.json +278 -0
- package/stylebook/jx-textfield.json +309 -0
- package/stylebook/jx-toast-host.json +157 -0
- package/stylebook/jx-toast.json +266 -0
- package/stylebook/jx-toolbar.json +435 -0
- package/stylebook/jx-tooltip.json +162 -0
- package/stylebook/jx-tree-item.json +258 -0
- package/stylebook/jx-tree.json +429 -0
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"disabled",
|
|
10
10
|
"loading",
|
|
11
11
|
"type",
|
|
12
|
+
"autofocus",
|
|
12
13
|
"label",
|
|
14
|
+
"hint",
|
|
13
15
|
"labelledby",
|
|
14
16
|
"describedby",
|
|
15
17
|
"popovertarget",
|
|
@@ -20,6 +22,12 @@
|
|
|
20
22
|
"$elements": [
|
|
21
23
|
{
|
|
22
24
|
"$ref": "./jx-icon.json"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"$ref": "./jx-spinner.json"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"$ref": "./jx-tooltip.json"
|
|
23
31
|
}
|
|
24
32
|
],
|
|
25
33
|
"state": {
|
|
@@ -41,11 +49,16 @@
|
|
|
41
49
|
"attribute": "quiet",
|
|
42
50
|
"description": "No fill and no border until hovered: a button that sits in a toolbar or beside text."
|
|
43
51
|
},
|
|
52
|
+
"tabindex": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"default": "",
|
|
55
|
+
"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."
|
|
56
|
+
},
|
|
44
57
|
"disabled": {
|
|
45
58
|
"type": "boolean",
|
|
46
59
|
"default": false,
|
|
47
60
|
"attribute": "disabled",
|
|
48
|
-
"description": "Cannot act. Disabled, never absent; a reason belongs in the surrounding text."
|
|
61
|
+
"description": "Cannot act. Disabled, never absent; a reason belongs in the surrounding text or in hint, which a disabled button draws as the control's native title because a disabled control can open no tip."
|
|
49
62
|
},
|
|
50
63
|
"loading": {
|
|
51
64
|
"type": "boolean",
|
|
@@ -59,12 +72,24 @@
|
|
|
59
72
|
"attribute": "type",
|
|
60
73
|
"description": "The native button type: button, submit or reset."
|
|
61
74
|
},
|
|
75
|
+
"autofocus": {
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"default": false,
|
|
78
|
+
"attribute": "autofocus",
|
|
79
|
+
"description": "Takes focus when the surface it is on opens. Forwarded to the inner control, which is the element the platform reads it from: a dialog's showModal() focuses the first focusable descendant unless one claims autofocus."
|
|
80
|
+
},
|
|
62
81
|
"label": {
|
|
63
82
|
"type": "string",
|
|
64
83
|
"default": "",
|
|
65
84
|
"attribute": "label",
|
|
66
85
|
"description": "The accessible name when the visible text is not it, or there is none. Forwarded to the inner control as aria-label."
|
|
67
86
|
},
|
|
87
|
+
"hint": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"default": "",
|
|
90
|
+
"attribute": "hint",
|
|
91
|
+
"description": "A tooltip beside the name, for a button whose visible text is cut short or whose disabled state needs a reason; empty, the usual case, draws nothing. The same shape as jx-action-button's: while the button is ENABLED it is a jx-tooltip child of this element — shown on keyboard focus at once and on hover after the tip's delay, hoverable and dismissible with Escape (SC 1.4.13) — named on the control in aria-describedby so it describes rather than names; while the button is DISABLED it is the control's native title instead, the one affordance a control that receives no focus and no pointer still has. Never both at once."
|
|
92
|
+
},
|
|
68
93
|
"labelledby": {
|
|
69
94
|
"type": "string",
|
|
70
95
|
"default": "",
|
|
@@ -75,7 +100,48 @@
|
|
|
75
100
|
"type": "string",
|
|
76
101
|
"default": "",
|
|
77
102
|
"attribute": "describedby",
|
|
78
|
-
"description": "Forwarded to the inner control as aria-describedby."
|
|
103
|
+
"description": "Forwarded to the inner control as aria-describedby, after the hint's own tip when there is one."
|
|
104
|
+
},
|
|
105
|
+
"uid": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"default": "",
|
|
108
|
+
"description": "This button's own id stem, minted on mount by the tooltip sidecar. The control's id, the tip's id and the three attributes that wire one to the other are all built from it, so a consumer writes none of them. Empty until the mount microtask, which is why every binding that reads it guards on it."
|
|
109
|
+
},
|
|
110
|
+
"hasTip": {
|
|
111
|
+
"$expression": {
|
|
112
|
+
"operator": "&&",
|
|
113
|
+
"target": {
|
|
114
|
+
"operator": "!",
|
|
115
|
+
"target": {
|
|
116
|
+
"operator": "!",
|
|
117
|
+
"target": {
|
|
118
|
+
"$ref": "#/state/hint"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"value": {
|
|
123
|
+
"operator": "&&",
|
|
124
|
+
"target": {
|
|
125
|
+
"operator": "!",
|
|
126
|
+
"target": {
|
|
127
|
+
"$ref": "#/state/disabled"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"value": {
|
|
131
|
+
"operator": "!==",
|
|
132
|
+
"target": {
|
|
133
|
+
"$ref": "#/state/uid"
|
|
134
|
+
},
|
|
135
|
+
"value": ""
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"onMount": {
|
|
141
|
+
"$prototype": "Function",
|
|
142
|
+
"$src": "jx-ui:/behaviors/tooltip.ts",
|
|
143
|
+
"$export": "mintHintId",
|
|
144
|
+
"description": "Mints the id stem the hint's tooltip is wired by. A document cannot: the closed operator set has no counter and no identity."
|
|
79
145
|
},
|
|
80
146
|
"popovertarget": {
|
|
81
147
|
"type": "string",
|
|
@@ -109,6 +175,25 @@
|
|
|
109
175
|
}
|
|
110
176
|
}
|
|
111
177
|
},
|
|
178
|
+
"onSwallow": {
|
|
179
|
+
"$prototype": "Function",
|
|
180
|
+
"body": [
|
|
181
|
+
{
|
|
182
|
+
"if": {
|
|
183
|
+
"$ref": "#/state/loading"
|
|
184
|
+
},
|
|
185
|
+
"then": [
|
|
186
|
+
{
|
|
187
|
+
"stopPropagation": true
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"preventDefault": true
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
"description": "The swallow, on the INNER CONTROL rather than the host: stopPropagation halts an event at the node it is called on and every node after it, not the other listeners on that same node — so a swallow on the host cancels the default and then runs the host's own click listeners anyway, which is the one path a consumer actually uses. Called one node earlier, the click never reaches the host at all."
|
|
196
|
+
},
|
|
112
197
|
"onClick": {
|
|
113
198
|
"$prototype": "Function",
|
|
114
199
|
"body": [
|
|
@@ -126,7 +211,7 @@
|
|
|
126
211
|
]
|
|
127
212
|
}
|
|
128
213
|
],
|
|
129
|
-
"description": "
|
|
214
|
+
"description": "The second half of the swallow, for a click dispatched AT the host: that one never passes the inner control, so this is the only guard that sees it. Its default (a form submission, a popover, a command) is cancelled either way. A disabled button never gets this far, because its inner control is disabled."
|
|
130
215
|
}
|
|
131
216
|
},
|
|
132
217
|
"onclick": {
|
|
@@ -212,18 +297,24 @@
|
|
|
212
297
|
}
|
|
213
298
|
},
|
|
214
299
|
"&[data-size=\"sm\"] > [part=\"control\"]": {
|
|
300
|
+
"$description": "A small button draws 4px under the kit's control height, and the control height is the WCAG 2.2 SC 2.5.8 floor (ui.md §4.3), so the drawn box alone would be a 20px pointer target at the default density. The `::before` is the hit area: an empty pseudo-element that reaches 2px past the drawn box on every side, so what accepts the pointer is exactly `--jx-control-h` square while the picture stays small — jx-tab's close button's technique, and the criterion measures the region that accepts the pointer, not the paint. The inset is -3px and not -2px because an absolutely positioned box is offset from its containing block's PADDING edge, and this control draws a 1px border: the border width comes first, then half of the 4px the box is under. jx-tab's close button is borderless, which is why -4px was exact there, and why the number did not carry over unchanged. In a jx-toolbar (a 4px gap) two extended neighbours abut and neither loses a pixel; jx-action-group's own sheet zeroes the packed axis in a compact group, where the boxes touch and an extension could only steal a strip of the neighbour. Held by target-size.test.ts and the conformance gate, both of which read the border and subtract it.",
|
|
301
|
+
"position": "relative",
|
|
215
302
|
"minHeight": "calc(var(--jx-control-h) - 4px)",
|
|
216
303
|
"padding": "0 var(--jx-space-3)",
|
|
217
|
-
"fontSize": "var(--jx-text-sm)"
|
|
304
|
+
"fontSize": "var(--jx-text-sm)",
|
|
305
|
+
"::before": {
|
|
306
|
+
"content": "\"\"",
|
|
307
|
+
"position": "absolute",
|
|
308
|
+
"inset": "-3px"
|
|
309
|
+
}
|
|
218
310
|
},
|
|
219
311
|
"&[data-size=\"lg\"] > [part=\"control\"]": {
|
|
220
312
|
"minHeight": "calc(var(--jx-control-h) + 8px)",
|
|
221
313
|
"padding": "0 var(--jx-space-5)",
|
|
222
314
|
"fontSize": "var(--jx-text-lg)"
|
|
223
315
|
},
|
|
224
|
-
"& [part=\"icon\"]": {
|
|
225
|
-
"display": "
|
|
226
|
-
"color": "inherit"
|
|
316
|
+
"& > [part=\"control\"] > [part=\"icon\"]": {
|
|
317
|
+
"display": "contents"
|
|
227
318
|
},
|
|
228
319
|
"& [part=\"spinner\"]": {
|
|
229
320
|
"display": "inline-flex",
|
|
@@ -231,13 +322,20 @@
|
|
|
231
322
|
},
|
|
232
323
|
"& [part=\"spinner\"][hidden]": {
|
|
233
324
|
"display": "none"
|
|
325
|
+
},
|
|
326
|
+
"& > [part=\"tooltip\"]": {
|
|
327
|
+
"display": "contents"
|
|
234
328
|
}
|
|
235
329
|
},
|
|
236
330
|
"children": [
|
|
237
331
|
{
|
|
238
332
|
"tagName": "button",
|
|
333
|
+
"onclick": {
|
|
334
|
+
"$ref": "#/state/onSwallow"
|
|
335
|
+
},
|
|
239
336
|
"attributes": {
|
|
240
337
|
"part": "control",
|
|
338
|
+
"id": "${state.uid || null}",
|
|
241
339
|
"type": "${state.type}",
|
|
242
340
|
"disabled": {
|
|
243
341
|
"$ref": "#/state/disabled"
|
|
@@ -245,12 +343,18 @@
|
|
|
245
343
|
"aria-disabled": "${state.loading ? 'true' : null}",
|
|
246
344
|
"aria-busy": "${state.loading ? 'true' : null}",
|
|
247
345
|
"aria-label": "${state.label || null}",
|
|
346
|
+
"title": "${state.disabled && state.hint ? state.hint : null}",
|
|
347
|
+
"interestfor": "${state.hasTip ? state.uid + '-tip' : null}",
|
|
248
348
|
"aria-labelledby": "${state.labelledby || null}",
|
|
249
|
-
"aria-describedby": "${state.describedby || null}",
|
|
349
|
+
"aria-describedby": "${[state.hasTip ? state.uid + '-tip' : null, state.describedby || null].filter(Boolean).join(' ') || null}",
|
|
350
|
+
"tabindex": "${state.tabindex || null}",
|
|
250
351
|
"popovertarget": "${state.popovertarget || null}",
|
|
251
352
|
"popovertargetaction": "${state.popovertargetaction || null}",
|
|
252
353
|
"command": "${state.command || null}",
|
|
253
|
-
"commandfor": "${state.commandfor || null}"
|
|
354
|
+
"commandfor": "${state.commandfor || null}",
|
|
355
|
+
"autofocus": {
|
|
356
|
+
"$ref": "#/state/autofocus"
|
|
357
|
+
}
|
|
254
358
|
},
|
|
255
359
|
"children": [
|
|
256
360
|
{
|
|
@@ -262,8 +366,7 @@
|
|
|
262
366
|
{
|
|
263
367
|
"tagName": "slot",
|
|
264
368
|
"attributes": {
|
|
265
|
-
"name": "icon"
|
|
266
|
-
"part": "icon-slot"
|
|
369
|
+
"name": "icon"
|
|
267
370
|
}
|
|
268
371
|
}
|
|
269
372
|
]
|
|
@@ -275,36 +378,48 @@
|
|
|
275
378
|
},
|
|
276
379
|
"children": [
|
|
277
380
|
{
|
|
278
|
-
"tagName": "slot"
|
|
279
|
-
"attributes": {
|
|
280
|
-
"part": "label-slot"
|
|
281
|
-
}
|
|
381
|
+
"tagName": "slot"
|
|
282
382
|
}
|
|
283
383
|
]
|
|
284
384
|
},
|
|
285
385
|
{
|
|
286
|
-
"tagName": "
|
|
386
|
+
"tagName": "jx-spinner",
|
|
287
387
|
"attributes": {
|
|
288
|
-
"part": "spinner"
|
|
289
|
-
"aria-hidden": "true"
|
|
388
|
+
"part": "spinner"
|
|
290
389
|
},
|
|
291
390
|
"hidden": {
|
|
292
391
|
"$ref": "#/state/notLoading"
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"tagName": "span",
|
|
398
|
+
"attributes": {
|
|
399
|
+
"part": "tooltip"
|
|
400
|
+
},
|
|
401
|
+
"$switch": {
|
|
402
|
+
"$ref": "#/state/hasTip"
|
|
403
|
+
},
|
|
404
|
+
"cases": {
|
|
405
|
+
"true": {
|
|
406
|
+
"tagName": "jx-tooltip",
|
|
407
|
+
"attributes": {
|
|
408
|
+
"part": "tip",
|
|
409
|
+
"id": "${state.uid}-tip",
|
|
410
|
+
"for": "${state.uid}"
|
|
293
411
|
},
|
|
294
412
|
"children": [
|
|
295
413
|
{
|
|
296
|
-
"tagName": "
|
|
297
|
-
"$props": {
|
|
298
|
-
"name": "spinner",
|
|
299
|
-
"weight": "bold"
|
|
300
|
-
},
|
|
414
|
+
"tagName": "span",
|
|
301
415
|
"attributes": {
|
|
302
|
-
"part": "
|
|
303
|
-
}
|
|
416
|
+
"part": "tip-text"
|
|
417
|
+
},
|
|
418
|
+
"textContent": "${state.hint}"
|
|
304
419
|
}
|
|
305
420
|
]
|
|
306
421
|
}
|
|
307
|
-
|
|
422
|
+
}
|
|
308
423
|
}
|
|
309
424
|
]
|
|
310
425
|
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxCheckbox",
|
|
4
|
+
"tagName": "jx-checkbox",
|
|
5
|
+
"observedAttributes": [
|
|
6
|
+
"checked",
|
|
7
|
+
"indeterminate",
|
|
8
|
+
"disabled",
|
|
9
|
+
"label",
|
|
10
|
+
"labelledby",
|
|
11
|
+
"describedby",
|
|
12
|
+
"name",
|
|
13
|
+
"size"
|
|
14
|
+
],
|
|
15
|
+
"state": {
|
|
16
|
+
"checked": {
|
|
17
|
+
"type": "boolean",
|
|
18
|
+
"default": false,
|
|
19
|
+
"attribute": "checked",
|
|
20
|
+
"description": "Whether the box is ticked. Bound to the control BOTH ways, and each binding answers a different question. The PROPERTY is the live state: once the reader clicks, the checkedness dirty flag is set and the content attribute stops controlling the box, so a property binding is the only one that keeps tracking a host write after the first click. The content ATTRIBUTE is the control's DEFAULT checkedness, and it is mirrored because this element is not form-associated (specs/ui.md 3.2): it never hears form.reset(), so without the mirror a reset would move the CONTROL to the authored default and leave the element's state where it was, and the two would disagree silently. With it, a reset is a visible no-op, which is a missing feature rather than a lie."
|
|
21
|
+
},
|
|
22
|
+
"indeterminate": {
|
|
23
|
+
"type": "boolean",
|
|
24
|
+
"default": false,
|
|
25
|
+
"attribute": "indeterminate",
|
|
26
|
+
"description": "The mixed state: neither ticked nor clear, for a box standing over a set that is partly on. HTML gives it no content attribute at all — it exists only as a property — which is the reason this element exists: written into attributes it would parse, validate and silently do nothing. So there is nothing to mirror and no default for a form reset to return to, and a click clears it in the platform."
|
|
27
|
+
},
|
|
28
|
+
"disabled": {
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"default": false,
|
|
31
|
+
"attribute": "disabled",
|
|
32
|
+
"description": "Cannot be ticked or focused. Disabled, never absent."
|
|
33
|
+
},
|
|
34
|
+
"label": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"default": "",
|
|
37
|
+
"attribute": "label",
|
|
38
|
+
"description": "The accessible name, forwarded to the control as aria-label. Leave it empty when the slotted text is on screen: the empty value REMOVES the attribute so the wrapping label's text names the box, rather than naming it twice."
|
|
39
|
+
},
|
|
40
|
+
"labelledby": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"default": "",
|
|
43
|
+
"attribute": "labelledby",
|
|
44
|
+
"description": "Forwarded to the inner control as aria-labelledby, for a visible label the box does not wrap."
|
|
45
|
+
},
|
|
46
|
+
"describedby": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"default": "",
|
|
49
|
+
"attribute": "describedby",
|
|
50
|
+
"description": "Forwarded to the inner control as aria-describedby, for a help or error sentence the row owns."
|
|
51
|
+
},
|
|
52
|
+
"name": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"default": "",
|
|
55
|
+
"attribute": "name",
|
|
56
|
+
"description": "The form field name, forwarded to the control."
|
|
57
|
+
},
|
|
58
|
+
"size": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"default": "md",
|
|
61
|
+
"attribute": "size",
|
|
62
|
+
"description": "sm, md or lg. The row height is the kit's, so a column of controls lines up."
|
|
63
|
+
},
|
|
64
|
+
"tabindex": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"default": "",
|
|
67
|
+
"description": "Forwarded to the inner control as its tabindex, which is what makes a roving caret possible: the focusable node is the input inside, not the host and not the label that wraps it, 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."
|
|
68
|
+
},
|
|
69
|
+
"onChange": {
|
|
70
|
+
"$prototype": "Function",
|
|
71
|
+
"body": [
|
|
72
|
+
{
|
|
73
|
+
"operator": "=",
|
|
74
|
+
"target": {
|
|
75
|
+
"$ref": "#/state/checked"
|
|
76
|
+
},
|
|
77
|
+
"value": {
|
|
78
|
+
"$ref": "event#/target/checked"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"operator": "=",
|
|
83
|
+
"target": {
|
|
84
|
+
"$ref": "#/state/indeterminate"
|
|
85
|
+
},
|
|
86
|
+
"value": {
|
|
87
|
+
"$ref": "event#/target/indeterminate"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"description": "Mirrors both halves of the control's state back. A click on a mixed box clears indeterminate and toggles checked in the platform; reading only checked would let the next flush re-assert mixed over the reader's own tick. The native change and input events bubble from the control as they always do."
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"attributes": {
|
|
95
|
+
"data-size": "${state.size}",
|
|
96
|
+
"data-checked": "${state.checked ? '' : null}",
|
|
97
|
+
"data-indeterminate": "${state.indeterminate ? '' : null}",
|
|
98
|
+
"data-disabled": "${state.disabled ? '' : null}"
|
|
99
|
+
},
|
|
100
|
+
"style": {
|
|
101
|
+
"display": "inline-flex",
|
|
102
|
+
"verticalAlign": "middle",
|
|
103
|
+
"minWidth": "0",
|
|
104
|
+
"&[hidden]": {
|
|
105
|
+
"display": "none"
|
|
106
|
+
},
|
|
107
|
+
"& > [part=\"control\"]": {
|
|
108
|
+
"display": "inline-flex",
|
|
109
|
+
"alignItems": "center",
|
|
110
|
+
"gap": "var(--jx-space-2)",
|
|
111
|
+
"minHeight": "var(--jx-control-h)",
|
|
112
|
+
"minWidth": "0",
|
|
113
|
+
"font": "inherit",
|
|
114
|
+
"fontFamily": "var(--jx-font-sans)",
|
|
115
|
+
"fontSize": "var(--jx-text-md)",
|
|
116
|
+
"lineHeight": "var(--jx-leading-md)",
|
|
117
|
+
"color": "var(--jx-fg)",
|
|
118
|
+
"cursor": "pointer"
|
|
119
|
+
},
|
|
120
|
+
"& [part=\"input\"]": {
|
|
121
|
+
"accentColor": "var(--jx-accent-solid)",
|
|
122
|
+
"flex": "none",
|
|
123
|
+
"width": "var(--jx-icon-size)",
|
|
124
|
+
"height": "var(--jx-icon-size)",
|
|
125
|
+
"margin": "0",
|
|
126
|
+
"cursor": "inherit",
|
|
127
|
+
"outline": "none",
|
|
128
|
+
":focus-visible": {
|
|
129
|
+
"outline": "var(--jx-focus-ring)",
|
|
130
|
+
"outlineOffset": "2px",
|
|
131
|
+
"borderRadius": "var(--jx-radius-xs)"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"& [part=\"label\"]": {
|
|
135
|
+
"minWidth": "0",
|
|
136
|
+
"overflow": "hidden",
|
|
137
|
+
"textOverflow": "ellipsis",
|
|
138
|
+
"whiteSpace": "nowrap"
|
|
139
|
+
},
|
|
140
|
+
"& [part=\"label\"]:empty": {
|
|
141
|
+
"display": "none"
|
|
142
|
+
},
|
|
143
|
+
"&[data-disabled] > [part=\"control\"]": {
|
|
144
|
+
"opacity": "0.5",
|
|
145
|
+
"cursor": "default",
|
|
146
|
+
"color": "var(--jx-fg-dim)"
|
|
147
|
+
},
|
|
148
|
+
"&[data-size=\"sm\"] > [part=\"control\"]": {
|
|
149
|
+
"$description": "The control is the `<label>` wrapping the input, and the label is the pointer target: a click anywhere on it toggles the box. At `sm` it draws 4px under the kit's control height, the WCAG 2.2 SC 2.5.8 floor (ui.md \u00a74.3), so the `::before` extends the hit area 2px beyond the box on every side — jx-tab's close-button technique, the same shape jx-button carries — and the region that accepts the pointer is `--jx-control-h` tall while the row stays 20px. -2px is exact here where jx-button needs -3px: an absolutely positioned box is offset from the PADDING edge, and the label draws no border, so its padding edge is its drawn edge. The label needs `position: relative` here for the pseudo-element to measure against; the input inside is 14px and needs nothing of its own, because the label around it is the target. Held by target-size.test.ts and the conformance gate.",
|
|
150
|
+
"position": "relative",
|
|
151
|
+
"minHeight": "calc(var(--jx-control-h) - 4px)",
|
|
152
|
+
"fontSize": "var(--jx-text-sm)",
|
|
153
|
+
"lineHeight": "var(--jx-leading-sm)",
|
|
154
|
+
"::before": {
|
|
155
|
+
"content": "\"\"",
|
|
156
|
+
"position": "absolute",
|
|
157
|
+
"inset": "-2px"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"&[data-size=\"sm\"] [part=\"input\"]": {
|
|
161
|
+
"width": "calc(var(--jx-icon-size) - 2px)",
|
|
162
|
+
"height": "calc(var(--jx-icon-size) - 2px)"
|
|
163
|
+
},
|
|
164
|
+
"&[data-size=\"lg\"] > [part=\"control\"]": {
|
|
165
|
+
"minHeight": "calc(var(--jx-control-h) + 8px)",
|
|
166
|
+
"fontSize": "var(--jx-text-lg)",
|
|
167
|
+
"lineHeight": "var(--jx-leading-lg)"
|
|
168
|
+
},
|
|
169
|
+
"&[data-size=\"lg\"] [part=\"input\"]": {
|
|
170
|
+
"width": "calc(var(--jx-icon-size) + 2px)",
|
|
171
|
+
"height": "calc(var(--jx-icon-size) + 2px)"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"children": [
|
|
175
|
+
{
|
|
176
|
+
"tagName": "label",
|
|
177
|
+
"attributes": {
|
|
178
|
+
"part": "control"
|
|
179
|
+
},
|
|
180
|
+
"children": [
|
|
181
|
+
{
|
|
182
|
+
"tagName": "input",
|
|
183
|
+
"attributes": {
|
|
184
|
+
"part": "input",
|
|
185
|
+
"type": "checkbox",
|
|
186
|
+
"aria-label": "${state.label || null}",
|
|
187
|
+
"aria-labelledby": "${state.labelledby || null}",
|
|
188
|
+
"aria-describedby": "${state.describedby || null}",
|
|
189
|
+
"tabindex": "${state.tabindex || null}",
|
|
190
|
+
"name": "${state.name || null}",
|
|
191
|
+
"disabled": {
|
|
192
|
+
"$ref": "#/state/disabled"
|
|
193
|
+
},
|
|
194
|
+
"checked": {
|
|
195
|
+
"$ref": "#/state/checked"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"checked": {
|
|
199
|
+
"$ref": "#/state/checked"
|
|
200
|
+
},
|
|
201
|
+
"indeterminate": {
|
|
202
|
+
"$ref": "#/state/indeterminate"
|
|
203
|
+
},
|
|
204
|
+
"onchange": {
|
|
205
|
+
"$ref": "#/state/onChange"
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"tagName": "span",
|
|
210
|
+
"attributes": {
|
|
211
|
+
"part": "label"
|
|
212
|
+
},
|
|
213
|
+
"children": [
|
|
214
|
+
{
|
|
215
|
+
"tagName": "slot"
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|