@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,129 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxSpinner",
4
+ "tagName": "jx-spinner",
5
+ "observedAttributes": ["value", "label", "size"],
6
+ "$elements": [
7
+ {
8
+ "$ref": "./jx-icon.json"
9
+ }
10
+ ],
11
+ "state": {
12
+ "value": {
13
+ "type": "string",
14
+ "default": "",
15
+ "attribute": "value",
16
+ "description": "How far along, 0 to 100. Empty is the indeterminate state: an ARIA progressbar with no aria-valuenow IS indeterminate, so an empty value writes none of the value attributes and the ring spins instead of filling. A string, never a number, because a numeric state entry turns a removed attribute into 0 and could never say empty. A host that writes a number through the property door anyway is read through #/state/progress, which is the ONE predicate the whole element renders from."
17
+ },
18
+ "label": {
19
+ "type": "string",
20
+ "default": "",
21
+ "attribute": "label",
22
+ "description": "What is being waited for, announced. Empty hides the spinner from assistive technology, which is right whenever the surrounding text already says the app is busy; a bare \"progressbar\" announcement is not."
23
+ },
24
+ "size": {
25
+ "type": "string",
26
+ "default": "md",
27
+ "attribute": "size",
28
+ "description": "sm, md or lg. md matches the kit's icon size, so a spinner swapped in for an icon does not move the row."
29
+ },
30
+ "progress": "${state.value === '' || state.value === null || state.value === undefined ? '' : '' + state.value}",
31
+ "isDeterminate": {
32
+ "$expression": {
33
+ "operator": "!==",
34
+ "target": {
35
+ "$ref": "#/state/progress"
36
+ },
37
+ "value": ""
38
+ }
39
+ },
40
+ "ring": "${state.progress === '' ? 'none' : 'conic-gradient(var(--jx-spin-color) ' + state.progress + '%, var(--jx-spin-track-color) 0)'}"
41
+ },
42
+ "attributes": {
43
+ "role": "progressbar",
44
+ "aria-label": "${state.label || null}",
45
+ "aria-hidden": "${state.label ? null : 'true'}",
46
+ "aria-valuenow": "${state.progress || null}",
47
+ "aria-valuemin": "${state.progress ? '0' : null}",
48
+ "aria-valuemax": "${state.progress ? '100' : null}",
49
+ "data-size": "${state.size}",
50
+ "data-determinate": "${state.progress ? '' : null}"
51
+ },
52
+ "style": {
53
+ "display": "inline-flex",
54
+ "verticalAlign": "middle",
55
+ "flex": "none",
56
+ "--jx-spin-size": "var(--jx-icon-size, 16px)",
57
+ "--jx-spin-track": "2px",
58
+ "--jx-spin-dur": "900ms",
59
+ "--jx-spin-color": "currentColor",
60
+ "--jx-spin-track-color": "var(--jx-border)",
61
+ "&[hidden]": {
62
+ "display": "none"
63
+ },
64
+ "&[data-size=\"sm\"]": {
65
+ "--jx-spin-size": "12px"
66
+ },
67
+ "&[data-size=\"lg\"]": {
68
+ "--jx-spin-size": "20px"
69
+ },
70
+ "& [part=\"glyph\"]": {
71
+ "display": "inline-flex",
72
+ "alignItems": "center",
73
+ "justifyContent": "center",
74
+ "boxSizing": "border-box",
75
+ "width": "var(--jx-spin-size)",
76
+ "height": "var(--jx-spin-size)",
77
+ "borderRadius": "50%",
78
+ "color": "var(--jx-spin-color)",
79
+ "animation": "jx-spin var(--jx-spin-dur) linear infinite"
80
+ },
81
+ "& [part=\"glyph-icon\"]": {
82
+ "--jx-icon-size": "var(--jx-spin-size)"
83
+ },
84
+ "&[data-determinate] [part=\"glyph\"]": {
85
+ "animation": "none",
86
+ "mask": "radial-gradient(farthest-side, transparent calc(100% - var(--jx-spin-track)), black 0)"
87
+ },
88
+ "@(prefers-reduced-motion: reduce)": {
89
+ "--jx-spin-dur": "2400ms"
90
+ },
91
+ "@(forced-colors: active)": {
92
+ "--jx-spin-track": "3px"
93
+ },
94
+ "@keyframes jx-spin": {
95
+ "from": {
96
+ "rotate": "0deg"
97
+ },
98
+ "to": {
99
+ "rotate": "360deg"
100
+ }
101
+ }
102
+ },
103
+ "children": [
104
+ {
105
+ "tagName": "span",
106
+ "attributes": {
107
+ "part": "glyph"
108
+ },
109
+ "style": {
110
+ "background": "${state.ring}"
111
+ },
112
+ "children": [
113
+ {
114
+ "tagName": "jx-icon",
115
+ "attributes": {
116
+ "part": "glyph-icon"
117
+ },
118
+ "hidden": {
119
+ "$ref": "#/state/isDeterminate"
120
+ },
121
+ "$props": {
122
+ "name": "spinner",
123
+ "weight": "bold"
124
+ }
125
+ }
126
+ ]
127
+ }
128
+ ]
129
+ }
@@ -0,0 +1,221 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxSplit",
4
+ "tagName": "jx-split",
5
+ "observedAttributes": [
6
+ "orientation",
7
+ "label",
8
+ "value",
9
+ "min",
10
+ "max",
11
+ "gap",
12
+ "step",
13
+ "large-step",
14
+ "collapse",
15
+ "disabled"
16
+ ],
17
+ "state": {
18
+ "orientation": {
19
+ "type": "string",
20
+ "default": "vertical",
21
+ "attribute": "orientation",
22
+ "description": "vertical or horizontal — the separator's OWN orientation, which is ARIA's meaning and the opposite of the axis it moves on: a vertical splitter is the upright line between two side-by-side panes, dragged left and right. Only \"horizontal\" turns it; every other value, the default included, is the upright one."
23
+ },
24
+ "label": {
25
+ "type": "string",
26
+ "default": "Split",
27
+ "attribute": "label",
28
+ "description": "The accessible name. A separator is in neither the accessibility lint's content-named roles nor its labelled ones, so an unnamed one is invisible to every gate and a reader arriving on it is told they have landed on a separator and nothing more. Name every splitter after the thing it divides."
29
+ },
30
+ "value": {
31
+ "type": "number",
32
+ "default": 0.5,
33
+ "attribute": "value",
34
+ "description": "Where the splitter sits: the LEADING side's share of the box it divides, 0-1. A fraction rather than pixels because a splitter has no size of its own to report, and because the same stored number survives a window resize. It is aria-valuenow, and the element is its own writer during a gesture — a host reads it back off the input and change events."
35
+ },
36
+ "min": {
37
+ "type": "number",
38
+ "default": 0,
39
+ "attribute": "min",
40
+ "description": "The smallest share the leading side may have, and aria-valuemin. A policy about the split, which is why it is a constant a host declares rather than something derived: gap answers the other question, and the two are intersected."
41
+ },
42
+ "max": {
43
+ "type": "number",
44
+ "default": 1,
45
+ "attribute": "max",
46
+ "description": "The largest share, and aria-valuemax."
47
+ },
48
+ "gap": {
49
+ "type": "number",
50
+ "default": 0,
51
+ "attribute": "gap",
52
+ "description": "The smallest EITHER side may be, in pixels of the measured track. Converted into the value's own units at gesture time, so it needs no listener and cannot go stale when the window resizes — which a fractional floor computed from a width by a host always does. A track too narrow for two gaps has no legal position, and the splitter goes to the middle of its crossed bounds."
53
+ },
54
+ "step": {
55
+ "type": "number",
56
+ "default": 0.02,
57
+ "attribute": "step",
58
+ "description": "What one arrow key moves the value by. Two per cent of the track is a nudge a reader can aim with; a value that is not a positive number falls back to it."
59
+ },
60
+ "largeStep": {
61
+ "type": "number",
62
+ "default": 0.1,
63
+ "attribute": "large-step",
64
+ "description": "What Shift+Arrow moves it by — the same coarse gesture jx-number-field and jx-color-slider add, and one the platform has on nothing."
65
+ },
66
+ "collapse": {
67
+ "type": "number",
68
+ "default": -1,
69
+ "attribute": "collapse",
70
+ "description": "The value Enter and a double click move to, and back from. The default is below every legal share, so it clamps to min: collapsing means going to the floor unless a host says otherwise. A splitter whose two sides are both real panes points it wherever its double click has always gone."
71
+ },
72
+ "disabled": {
73
+ "type": "boolean",
74
+ "default": false,
75
+ "attribute": "disabled",
76
+ "description": "Cannot be moved, by pointer or by key, and drops out of the tab order. aria-disabled rather than removal, because a splitter a reader cannot find is a layout they cannot explain."
77
+ },
78
+ "dragging": {
79
+ "type": "boolean",
80
+ "default": false,
81
+ "description": "Whether a pointer gesture is live. Written by the behaviour and mirrored as data-dragging, so the splitter stays lit for the length of a drag that has left it — which is the whole point of the pointer capture."
82
+ },
83
+ "restore": {
84
+ "type": "number",
85
+ "default": -1,
86
+ "description": "Where the collapse toggle returns to, recorded on the way down. Negative until a collapse has recorded one, which is a value no share can be."
87
+ },
88
+ "valueText": "${Math.round(((state.value - state.min) / ((state.max - state.min) || 1)) * 100) + '%'}",
89
+ "onPointerDown": {
90
+ "$prototype": "Function",
91
+ "$src": "jx-ui:/behaviors/split.ts",
92
+ "$export": "onSplitPointerDown",
93
+ "description": "Measures the track once, captures the gesture on the element and takes the focus, so the arrow keys carry on from where the pointer stopped. The value does not jump: the splitter is already the thing under the cursor."
94
+ },
95
+ "onPointerMove": {
96
+ "$prototype": "Function",
97
+ "$src": "jx-ui:/behaviors/split.ts",
98
+ "$export": "onSplitPointerMove",
99
+ "description": "The drag, against the length measured at pointerdown. Nothing moves without a press first, so a hover moves no split.",
100
+ "emits": [
101
+ {
102
+ "name": "input",
103
+ "description": "The splitter is moving under the reader's hand. It comes from the ELEMENT, so e.target.value is where it is — and detail is the modifiers this step was made with, { altKey, ctrlKey, metaKey, shiftKey }, for a host whose own snap needs a way through. The element gives none of them a meaning here; what a breakpoint is, and which key skips it, is the host's to say."
104
+ }
105
+ ]
106
+ },
107
+ "onPointerUp": {
108
+ "$prototype": "Function",
109
+ "$src": "jx-ui:/behaviors/split.ts",
110
+ "$export": "onSplitPointerUp",
111
+ "description": "Ends the gesture and commits once. Bound to pointercancel and lostpointercapture as well as pointerup: a capture lost any other way is still a gesture that is over, and a splitter left in the dragging state would follow the next pointer that crossed it with no button down.",
112
+ "emits": [
113
+ {
114
+ "name": "change",
115
+ "description": "The reader let go; e.target is the element, and detail is the modifiers the release carried. Dispatched even when the last move changed nothing, because the commit is about the gesture ending."
116
+ }
117
+ ]
118
+ },
119
+ "onKeydown": {
120
+ "$prototype": "Function",
121
+ "$src": "jx-ui:/behaviors/split.ts",
122
+ "$export": "onSplitKeydown",
123
+ "description": "The splitter keyboard: the arrows of its own axis with Shift for the larger step, Home and End for the extremes, and Enter for the collapse toggle. A keystroke is a move AND a commit. Every other key reaches the host untouched.",
124
+ "emits": [
125
+ {
126
+ "name": "input",
127
+ "description": "A key moved the splitter; detail is the modifiers it was pressed with. Shift is reported even though the element spent it on the large step: what a host makes of a modifier is the host's business."
128
+ },
129
+ {
130
+ "name": "change",
131
+ "description": "The same key committed it, with the same detail."
132
+ }
133
+ ]
134
+ },
135
+ "onDoubleClick": {
136
+ "$prototype": "Function",
137
+ "$src": "jx-ui:/behaviors/split.ts",
138
+ "$export": "onSplitDoubleClick",
139
+ "description": "Collapses the split, and restores it on the next one. This is the SC 2.5.7 door — a single-pointer alternative to dragging — and it is deliberately the same function Enter runs, so the two cannot drift.",
140
+ "emits": [
141
+ {
142
+ "name": "input",
143
+ "description": "The toggle moved the splitter; detail is the click's modifiers."
144
+ },
145
+ {
146
+ "name": "change",
147
+ "description": "And committed it, with the same detail."
148
+ }
149
+ ]
150
+ }
151
+ },
152
+ "attributes": {
153
+ "role": "separator",
154
+ "tabindex": "${state.disabled ? '-1' : '0'}",
155
+ "aria-label": "${state.label}",
156
+ "aria-orientation": "${state.orientation}",
157
+ "aria-valuenow": "${state.value}",
158
+ "aria-valuemin": "${state.min}",
159
+ "aria-valuemax": "${state.max}",
160
+ "aria-valuetext": "${state.valueText}",
161
+ "aria-disabled": "${state.disabled ? 'true' : null}",
162
+ "orientation": "${state.orientation}",
163
+ "data-dragging": "${state.dragging ? '' : null}"
164
+ },
165
+ "onpointerdown": {
166
+ "$ref": "#/state/onPointerDown"
167
+ },
168
+ "onpointermove": {
169
+ "$ref": "#/state/onPointerMove"
170
+ },
171
+ "onpointerup": {
172
+ "$ref": "#/state/onPointerUp"
173
+ },
174
+ "onpointercancel": {
175
+ "$ref": "#/state/onPointerUp"
176
+ },
177
+ "onlostpointercapture": {
178
+ "$ref": "#/state/onPointerUp"
179
+ },
180
+ "onkeydown": {
181
+ "$ref": "#/state/onKeydown"
182
+ },
183
+ "ondblclick": {
184
+ "$ref": "#/state/onDoubleClick"
185
+ },
186
+ "style": {
187
+ "display": "block",
188
+ "&[hidden]": {
189
+ "display": "none"
190
+ },
191
+ "flex": "none",
192
+ "position": "relative",
193
+ "zIndex": "1",
194
+ "touchAction": "none",
195
+ "background": "var(--jx-border)",
196
+ "cursor": "col-resize",
197
+ "inlineSize": "5px",
198
+ "outline": "none",
199
+ "&[orientation=\"horizontal\"]": {
200
+ "cursor": "row-resize",
201
+ "inlineSize": "auto",
202
+ "blockSize": "5px"
203
+ },
204
+ "&:hover, &[data-dragging]": {
205
+ "background": "var(--jx-accent)",
206
+ "opacity": "0.5"
207
+ },
208
+ "&:focus-visible": {
209
+ "outline": "var(--jx-focus-ring)",
210
+ "outlineOffset": "-2px"
211
+ },
212
+ "&[aria-disabled=\"true\"]": {
213
+ "cursor": "default"
214
+ },
215
+ "&[aria-disabled=\"true\"]:hover": {
216
+ "background": "var(--jx-border)",
217
+ "opacity": "1"
218
+ }
219
+ },
220
+ "children": []
221
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxSwatchGroup",
4
+ "tagName": "jx-swatch-group",
5
+ "observedAttributes": ["value", "label", "columns"],
6
+ "state": {
7
+ "value": {
8
+ "type": "string",
9
+ "default": "",
10
+ "attribute": "value",
11
+ "description": "What the chosen swatch stands for; the empty string when none is. The group is the one writer of its children's checked state and of the roving caret, so a host owns this and nothing else — writing a child's checked directly puts the two into a disagreement only a re-render can settle."
12
+ },
13
+ "label": {
14
+ "type": "string",
15
+ "default": "Colours",
16
+ "attribute": "label",
17
+ "description": "The accessible name of the group. A radiogroup is named by nothing else — it takes no name from its members — and no lint can say so, because a bound role switches the naming rules off. Name every group: \"Theme palette\" and \"Recent colours\" are two different questions and a reader hears only this."
18
+ },
19
+ "columns": {
20
+ "type": "number",
21
+ "default": 0,
22
+ "attribute": "columns",
23
+ "description": "How many swatches to a row, or 0 to let them wrap on their own. A fixed grid is what makes a palette's rows line up when the swatches carry labels of different lengths; zero means unset rather than a grid of no columns, because a numeric prop coerces a removed attribute through the current value's type."
24
+ },
25
+ "applySelection": {
26
+ "$prototype": "Function",
27
+ "$src": "jx-ui:/behaviors/swatch-group.ts",
28
+ "$export": "applySwatchSelection",
29
+ "parameters": ["scope"],
30
+ "description": "Writes the selection onto the swatches and returns it. Idempotent: it runs inside a render effect."
31
+ },
32
+ "sync": "${state.applySelection(state)}",
33
+ "onSelect": {
34
+ "$prototype": "Function",
35
+ "$src": "jx-ui:/behaviors/swatch-group.ts",
36
+ "$export": "onSwatchGroupSelect",
37
+ "emits": [
38
+ {
39
+ "name": "change",
40
+ "description": "The selection moved; detail is what the newly chosen swatch stands for, and e.target.value is the same string."
41
+ }
42
+ ],
43
+ "description": "A swatch was activated: value is written first, then change is dispatched, so a listener reading e.target.value sees the new one. Re-choosing the swatch that is already chosen says nothing."
44
+ },
45
+ "onKeydown": {
46
+ "$prototype": "Function",
47
+ "$src": "jx-ui:/behaviors/swatch-group.ts",
48
+ "$export": "onSwatchGroupKeydown",
49
+ "description": "The radio group's keyboard contract: either arrow pair moves the caret between enabled swatches with wrap, Home and End go to the ends, and the swatch the caret lands on is chosen. Both pairs move, because a palette wraps into rows and Down on a grid means the next one."
50
+ },
51
+ "onReady": {
52
+ "$prototype": "Function",
53
+ "$src": "jx-ui:/behaviors/swatch-group.ts",
54
+ "$export": "onSwatchGroupMount",
55
+ "description": "Gives the group its first sight of itself, syncs the swatches, and watches the set. Not optional: applyAttributes runs before distributeSlots, so no swatch exists when the root's bindings first evaluate."
56
+ },
57
+ "onMount": {
58
+ "$prototype": "Function",
59
+ "body": [
60
+ {
61
+ "dispatchEvent": "jx-ready",
62
+ "bubbles": true
63
+ }
64
+ ],
65
+ "emits": [
66
+ {
67
+ "name": "jx-ready",
68
+ "description": "The group has rendered and taken its slotted swatches, which is how onReady reaches the element itself."
69
+ }
70
+ ],
71
+ "description": "Announces that the group has rendered. Its own onReady listens for it, and a host may too."
72
+ }
73
+ },
74
+ "attributes": {
75
+ "role": "radiogroup",
76
+ "aria-label": "${state.label}",
77
+ "data-selection": "${state.sync}",
78
+ "data-columns": "${state.columns > 0 ? '' : null}"
79
+ },
80
+ "onselect": {
81
+ "$ref": "#/state/onSelect"
82
+ },
83
+ "onkeydown": {
84
+ "$ref": "#/state/onKeydown"
85
+ },
86
+ "onjx-ready": {
87
+ "$ref": "#/state/onReady"
88
+ },
89
+ "style": {
90
+ "display": "flex",
91
+ "&[hidden]": {
92
+ "display": "none"
93
+ },
94
+ "flexWrap": "wrap",
95
+ "alignItems": "center",
96
+ "gap": "var(--jx-space-1)",
97
+ "&[data-columns]": {
98
+ "display": "grid",
99
+ "gridTemplateColumns": "repeat(${state.columns}, minmax(0, 1fr))"
100
+ }
101
+ },
102
+ "children": [
103
+ {
104
+ "tagName": "slot"
105
+ }
106
+ ]
107
+ }