@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,266 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "StylebookToast",
4
+ "tagName": "main",
5
+ "$elements": [
6
+ {
7
+ "$ref": "../components/jx-button.json"
8
+ },
9
+ {
10
+ "$ref": "../components/jx-toast.json"
11
+ }
12
+ ],
13
+ "state": {},
14
+ "style": {
15
+ "fontFamily": "var(--jx-font-sans)",
16
+ "fontSize": "var(--jx-text-md)",
17
+ "color": "var(--jx-fg)",
18
+ "background": "var(--jx-bg)",
19
+ "padding": "var(--jx-space-6)",
20
+ "minHeight": "100vh",
21
+ "& > h1": {
22
+ "fontSize": "var(--jx-text-lg)",
23
+ "fontWeight": "600",
24
+ "margin": "0 0 var(--jx-space-5)"
25
+ },
26
+ "& > h2": {
27
+ "fontSize": "var(--jx-text-md)",
28
+ "fontWeight": "600",
29
+ "margin": "var(--jx-space-6) 0 var(--jx-space-3)"
30
+ },
31
+ "& > p": {
32
+ "color": "var(--jx-fg-dim)",
33
+ "margin": "0 0 var(--jx-space-5)",
34
+ "maxWidth": "60ch"
35
+ },
36
+ "& [role=\"group\"]": {
37
+ "display": "flex",
38
+ "flexDirection": "column",
39
+ "alignItems": "flex-start",
40
+ "gap": "var(--jx-space-3)",
41
+ "margin": "0 0 var(--jx-space-4)"
42
+ }
43
+ },
44
+ "children": [
45
+ {
46
+ "tagName": "h1",
47
+ "textContent": "jx-toast"
48
+ },
49
+ {
50
+ "tagName": "p",
51
+ "textContent": "One outcome, said once: a glyph, a line of text, at most one control that undoes or retries it, and a dismiss button that is always there. A toast never takes the keyboard, and it carries no live region of its own, so the toasts below are drawn and not announced. Put them in a jx-toast-host and the stack speaks for them."
52
+ },
53
+ {
54
+ "tagName": "p",
55
+ "textContent": "Off a host each toast is an ordinary box in the flow, which is what these are. The corner, the stacking and the clock policy of a real stack all belong to the host."
56
+ },
57
+ {
58
+ "tagName": "h2",
59
+ "textContent": "Variants"
60
+ },
61
+ {
62
+ "tagName": "div",
63
+ "attributes": {
64
+ "role": "group",
65
+ "aria-label": "Variants"
66
+ },
67
+ "children": [
68
+ {
69
+ "tagName": "jx-toast",
70
+ "$props": {
71
+ "open": true
72
+ },
73
+ "children": [
74
+ {
75
+ "tagName": "span",
76
+ "textContent": "Draft saved to about.json."
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ "tagName": "jx-toast",
82
+ "$props": {
83
+ "open": true,
84
+ "variant": "positive"
85
+ },
86
+ "children": [
87
+ {
88
+ "tagName": "span",
89
+ "textContent": "Published 14 pages to jxsuite.com."
90
+ }
91
+ ]
92
+ },
93
+ {
94
+ "tagName": "jx-toast",
95
+ "$props": {
96
+ "open": true,
97
+ "variant": "warning"
98
+ },
99
+ "children": [
100
+ {
101
+ "tagName": "span",
102
+ "textContent": "Two images are larger than 2 MB and were not resized."
103
+ }
104
+ ]
105
+ },
106
+ {
107
+ "tagName": "jx-toast",
108
+ "$props": {
109
+ "open": true,
110
+ "variant": "negative"
111
+ },
112
+ "children": [
113
+ {
114
+ "tagName": "span",
115
+ "textContent": "Save failed: the file is open in another program."
116
+ }
117
+ ]
118
+ }
119
+ ]
120
+ },
121
+ {
122
+ "tagName": "h2",
123
+ "textContent": "One recovery control"
124
+ },
125
+ {
126
+ "tagName": "p",
127
+ "textContent": "Anything slotted into action is the one thing a reader may do about the message. Using it closes the toast and reports action, because an answer that has been given is not still being asked. The click is not stopped, so the control's own handler runs first and a host listening above the toast hears it too."
128
+ },
129
+ {
130
+ "tagName": "div",
131
+ "attributes": {
132
+ "role": "group",
133
+ "aria-label": "With an action"
134
+ },
135
+ "children": [
136
+ {
137
+ "tagName": "jx-toast",
138
+ "$props": {
139
+ "open": true,
140
+ "variant": "negative"
141
+ },
142
+ "children": [
143
+ {
144
+ "tagName": "span",
145
+ "textContent": "Could not reach the deploy service."
146
+ },
147
+ {
148
+ "tagName": "jx-button",
149
+ "attributes": {
150
+ "slot": "action"
151
+ },
152
+ "$props": {
153
+ "size": "sm",
154
+ "quiet": true
155
+ },
156
+ "children": [
157
+ {
158
+ "tagName": "span",
159
+ "textContent": "Retry"
160
+ }
161
+ ]
162
+ }
163
+ ]
164
+ },
165
+ {
166
+ "tagName": "jx-toast",
167
+ "$props": {
168
+ "open": true,
169
+ "dismissLabel": "Dismiss notification"
170
+ },
171
+ "children": [
172
+ {
173
+ "tagName": "span",
174
+ "textContent": "Moved 3 files to the trash."
175
+ },
176
+ {
177
+ "tagName": "jx-button",
178
+ "attributes": {
179
+ "slot": "action"
180
+ },
181
+ "$props": {
182
+ "size": "sm",
183
+ "quiet": true
184
+ },
185
+ "children": [
186
+ {
187
+ "tagName": "span",
188
+ "textContent": "Undo"
189
+ }
190
+ ]
191
+ }
192
+ ]
193
+ }
194
+ ]
195
+ },
196
+ {
197
+ "tagName": "h2",
198
+ "textContent": "Sticky, and on a clock"
199
+ },
200
+ {
201
+ "tagName": "p",
202
+ "textContent": "timeout is 0 by default, so a toast stays until it is dismissed. Give it a number of milliseconds and it retires itself, dispatching close with the reason timeout. The clock stops while the pointer is on the toast and while focus is inside it, and resumes with the time that was left, so a control the reader has reached cannot expire under their hand. The second toast below is on a ten second clock and will retire itself."
203
+ },
204
+ {
205
+ "tagName": "div",
206
+ "attributes": {
207
+ "role": "group",
208
+ "aria-label": "Timing"
209
+ },
210
+ "children": [
211
+ {
212
+ "tagName": "jx-toast",
213
+ "$props": {
214
+ "open": true
215
+ },
216
+ "children": [
217
+ {
218
+ "tagName": "span",
219
+ "textContent": "Sticky: this one waits to be dismissed."
220
+ }
221
+ ]
222
+ },
223
+ {
224
+ "tagName": "jx-toast",
225
+ "$props": {
226
+ "open": true,
227
+ "variant": "positive",
228
+ "timeout": 10000
229
+ },
230
+ "children": [
231
+ {
232
+ "tagName": "span",
233
+ "textContent": "On a clock: rest the pointer here and it stops counting."
234
+ }
235
+ ]
236
+ }
237
+ ]
238
+ },
239
+ {
240
+ "tagName": "h2",
241
+ "textContent": "A long message"
242
+ },
243
+ {
244
+ "tagName": "div",
245
+ "attributes": {
246
+ "role": "group",
247
+ "aria-label": "Long message"
248
+ },
249
+ "children": [
250
+ {
251
+ "tagName": "jx-toast",
252
+ "$props": {
253
+ "open": true,
254
+ "variant": "warning"
255
+ },
256
+ "children": [
257
+ {
258
+ "tagName": "span",
259
+ "textContent": "The stylesheet at styles/site.css declares 41 custom properties that no page reads. Nothing was changed, and the build carried on without them."
260
+ }
261
+ ]
262
+ }
263
+ ]
264
+ }
265
+ ]
266
+ }
@@ -0,0 +1,435 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "StylebookToolbar",
4
+ "tagName": "main",
5
+ "$elements": [
6
+ {
7
+ "$ref": "../components/jx-icon.json"
8
+ },
9
+ {
10
+ "$ref": "../components/jx-spinner.json"
11
+ },
12
+ {
13
+ "$ref": "../components/jx-button.json"
14
+ },
15
+ {
16
+ "$ref": "../components/jx-action-button.json"
17
+ },
18
+ {
19
+ "$ref": "../components/jx-action-group.json"
20
+ },
21
+ {
22
+ "$ref": "../components/jx-divider.json"
23
+ },
24
+ {
25
+ "$ref": "../components/jx-textfield.json"
26
+ },
27
+ {
28
+ "$ref": "../components/jx-color-field.json"
29
+ },
30
+ {
31
+ "$ref": "../components/jx-toolbar.json"
32
+ }
33
+ ],
34
+ "state": {
35
+ "filter": "",
36
+ "setFilter": {
37
+ "$prototype": "Function",
38
+ "body": [
39
+ {
40
+ "operator": "=",
41
+ "target": {
42
+ "$ref": "#/state/filter"
43
+ },
44
+ "value": {
45
+ "$ref": "event#/target/value"
46
+ }
47
+ }
48
+ ]
49
+ },
50
+ "fill": "#3b82f6",
51
+ "setFill": {
52
+ "$prototype": "Function",
53
+ "body": [
54
+ {
55
+ "operator": "=",
56
+ "target": {
57
+ "$ref": "#/state/fill"
58
+ },
59
+ "value": {
60
+ "$ref": "event#/target/value"
61
+ }
62
+ }
63
+ ]
64
+ },
65
+ "last": "nothing yet",
66
+ "did": {
67
+ "$prototype": "Function",
68
+ "body": [
69
+ {
70
+ "operator": "=",
71
+ "target": {
72
+ "$ref": "#/state/last"
73
+ },
74
+ "value": {
75
+ "$ref": "event#/currentTarget/dataset/verb"
76
+ }
77
+ }
78
+ ]
79
+ }
80
+ },
81
+ "style": {
82
+ "fontFamily": "var(--jx-font-sans)",
83
+ "fontSize": "var(--jx-text-md)",
84
+ "color": "var(--jx-fg)",
85
+ "background": "var(--jx-bg)",
86
+ "padding": "var(--jx-space-6)",
87
+ "minHeight": "100vh",
88
+ "& > h1": {
89
+ "fontSize": "var(--jx-text-lg)",
90
+ "fontWeight": "600",
91
+ "margin": "0 0 var(--jx-space-5)"
92
+ },
93
+ "& > h2": {
94
+ "fontSize": "var(--jx-text-md)",
95
+ "fontWeight": "600",
96
+ "color": "var(--jx-fg-dim)",
97
+ "margin": "var(--jx-space-5) 0 var(--jx-space-2)"
98
+ },
99
+ "& > p": {
100
+ "color": "var(--jx-fg-dim)",
101
+ "margin": "0 0 var(--jx-space-5)"
102
+ },
103
+ "& > div": {
104
+ "margin": "0 0 var(--jx-space-4)",
105
+ "border": "1px solid var(--jx-border)",
106
+ "borderRadius": "var(--jx-radius-sm)",
107
+ "background": "var(--jx-bg-panel)"
108
+ },
109
+ "& jx-toolbar": {
110
+ "padding": "var(--jx-space-2) var(--jx-space-3)"
111
+ },
112
+ "& [part=\"filter\"]": {
113
+ "width": "180px",
114
+ "flex": "0 0 auto"
115
+ },
116
+ "& [part=\"spacer\"]": {
117
+ "flex": "1"
118
+ },
119
+ "& [part=\"count\"]": {
120
+ "fontSize": "var(--jx-text-sm)",
121
+ "color": "var(--jx-fg-dim)",
122
+ "whiteSpace": "nowrap"
123
+ },
124
+ "& > div[data-vertical]": {
125
+ "width": "max-content"
126
+ }
127
+ },
128
+ "children": [
129
+ {
130
+ "tagName": "h1",
131
+ "textContent": "jx-toolbar"
132
+ },
133
+ {
134
+ "tagName": "p",
135
+ "textContent": "A container of ARBITRARY controls with one tab stop. jx-action-group is a row of action buttons that may be joined into a segmented control; this is the element for a row that also holds a text field, a divider and a plain button, which is what every real toolbar turns out to be. Arrows move between the controls, Home and End reach the ends — and the filter field below keeps those keys for itself while its caret still has text to walk, so you arrow in, type, and arrow out again with the same key. Last verb pressed: ${state.last}."
136
+ },
137
+ {
138
+ "tagName": "h2",
139
+ "textContent": "A mixed row — the shape Studio's grid toolbar has"
140
+ },
141
+ {
142
+ "tagName": "div",
143
+ "children": [
144
+ {
145
+ "tagName": "jx-toolbar",
146
+ "$props": {
147
+ "label": "Grid actions"
148
+ },
149
+ "children": [
150
+ {
151
+ "tagName": "jx-button",
152
+ "$props": {
153
+ "variant": "accent",
154
+ "size": "sm",
155
+ "label": "Save"
156
+ },
157
+ "attributes": {
158
+ "data-verb": "save"
159
+ },
160
+ "onclick": {
161
+ "$ref": "#/state/did"
162
+ },
163
+ "children": [
164
+ {
165
+ "tagName": "span",
166
+ "textContent": "Save"
167
+ }
168
+ ]
169
+ },
170
+ {
171
+ "tagName": "jx-action-button",
172
+ "$props": {
173
+ "size": "sm",
174
+ "label": "Refresh",
175
+ "hint": "Reload from source",
176
+ "icon": "arrows-clockwise"
177
+ },
178
+ "attributes": {
179
+ "data-verb": "refresh"
180
+ },
181
+ "onclick": {
182
+ "$ref": "#/state/did"
183
+ }
184
+ },
185
+ {
186
+ "tagName": "jx-divider",
187
+ "$props": {
188
+ "orientation": "vertical"
189
+ }
190
+ },
191
+ {
192
+ "tagName": "jx-action-button",
193
+ "$props": {
194
+ "size": "sm",
195
+ "label": "Add row",
196
+ "hint": "Add a row",
197
+ "icon": "plus"
198
+ },
199
+ "attributes": {
200
+ "data-verb": "add"
201
+ },
202
+ "onclick": {
203
+ "$ref": "#/state/did"
204
+ }
205
+ },
206
+ {
207
+ "tagName": "jx-action-button",
208
+ "$props": {
209
+ "size": "sm",
210
+ "label": "Delete rows",
211
+ "hint": "Nothing is selected",
212
+ "icon": "trash",
213
+ "disabled": true
214
+ }
215
+ },
216
+ {
217
+ "tagName": "jx-textfield",
218
+ "attributes": {
219
+ "part": "filter"
220
+ },
221
+ "$props": {
222
+ "size": "sm",
223
+ "type": "search",
224
+ "clearable": true,
225
+ "label": "Filter rows",
226
+ "placeholder": "Filter rows",
227
+ "value": {
228
+ "$ref": "#/state/filter"
229
+ }
230
+ },
231
+ "oninput": {
232
+ "$ref": "#/state/setFilter"
233
+ }
234
+ },
235
+ {
236
+ "tagName": "span",
237
+ "attributes": {
238
+ "part": "spacer"
239
+ }
240
+ },
241
+ {
242
+ "tagName": "span",
243
+ "attributes": {
244
+ "part": "count"
245
+ },
246
+ "textContent": "filter: ${state.filter || '—'}"
247
+ }
248
+ ]
249
+ }
250
+ ]
251
+ },
252
+ {
253
+ "tagName": "h2",
254
+ "textContent": "A colour well in the row"
255
+ },
256
+ {
257
+ "tagName": "p",
258
+ "textContent": "A jx-color-field is four controls of its own — the swatch, a text field, the eyedropper and the system's colour well — and in a toolbar it is ONE stop: the swatch. Arrow onto it and Enter opens the picker; the three controls beside it leave the tab order while the field is roved, and take their own stops back anywhere else. Fill: ${state.fill}."
259
+ },
260
+ {
261
+ "tagName": "div",
262
+ "children": [
263
+ {
264
+ "tagName": "jx-toolbar",
265
+ "$props": {
266
+ "label": "Text style"
267
+ },
268
+ "children": [
269
+ {
270
+ "tagName": "jx-action-button",
271
+ "$props": {
272
+ "size": "sm",
273
+ "label": "Bold",
274
+ "hint": "Bold",
275
+ "icon": "text-b",
276
+ "toggles": true
277
+ }
278
+ },
279
+ {
280
+ "tagName": "jx-action-button",
281
+ "$props": {
282
+ "size": "sm",
283
+ "label": "Italic",
284
+ "hint": "Italic",
285
+ "icon": "text-italic",
286
+ "toggles": true
287
+ }
288
+ },
289
+ {
290
+ "tagName": "jx-divider",
291
+ "$props": {
292
+ "orientation": "vertical"
293
+ }
294
+ },
295
+ {
296
+ "tagName": "jx-color-field",
297
+ "$props": {
298
+ "size": "sm",
299
+ "label": "Fill",
300
+ "value": {
301
+ "$ref": "#/state/fill"
302
+ }
303
+ },
304
+ "onchange": {
305
+ "$ref": "#/state/setFill"
306
+ }
307
+ },
308
+ {
309
+ "tagName": "jx-divider",
310
+ "$props": {
311
+ "orientation": "vertical"
312
+ }
313
+ },
314
+ {
315
+ "tagName": "jx-action-button",
316
+ "$props": {
317
+ "size": "sm",
318
+ "label": "Align left",
319
+ "hint": "Align left",
320
+ "icon": "text-align-left"
321
+ }
322
+ }
323
+ ]
324
+ }
325
+ ]
326
+ },
327
+ {
328
+ "tagName": "h2",
329
+ "textContent": "orientation=\"vertical\""
330
+ },
331
+ {
332
+ "tagName": "div",
333
+ "attributes": {
334
+ "data-vertical": ""
335
+ },
336
+ "children": [
337
+ {
338
+ "tagName": "jx-toolbar",
339
+ "$props": {
340
+ "label": "Node actions",
341
+ "orientation": "vertical"
342
+ },
343
+ "children": [
344
+ {
345
+ "tagName": "jx-action-button",
346
+ "$props": {
347
+ "size": "sm",
348
+ "stacked": true,
349
+ "label": "Move up",
350
+ "icon": "arrow-up"
351
+ },
352
+ "attributes": {
353
+ "data-verb": "up"
354
+ },
355
+ "onclick": {
356
+ "$ref": "#/state/did"
357
+ }
358
+ },
359
+ {
360
+ "tagName": "jx-action-button",
361
+ "$props": {
362
+ "size": "sm",
363
+ "stacked": true,
364
+ "label": "Move down",
365
+ "icon": "arrow-down"
366
+ },
367
+ "attributes": {
368
+ "data-verb": "down"
369
+ },
370
+ "onclick": {
371
+ "$ref": "#/state/did"
372
+ }
373
+ },
374
+ {
375
+ "tagName": "jx-action-button",
376
+ "$props": {
377
+ "size": "sm",
378
+ "stacked": true,
379
+ "label": "Duplicate",
380
+ "icon": "copy"
381
+ },
382
+ "attributes": {
383
+ "data-verb": "duplicate"
384
+ },
385
+ "onclick": {
386
+ "$ref": "#/state/did"
387
+ }
388
+ }
389
+ ]
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ "tagName": "h2",
395
+ "textContent": "What a toolbar does NOT rove"
396
+ },
397
+ {
398
+ "tagName": "p",
399
+ "textContent": "A jx-action-group runs a roving caret of its own, so it stands BESIDE a toolbar rather than inside one: two carets over one set of buttons is two writers of the same tabindex, and they do not agree. The group below is its own single tab stop, exactly as it is anywhere else."
400
+ },
401
+ {
402
+ "tagName": "div",
403
+ "children": [
404
+ {
405
+ "tagName": "jx-action-group",
406
+ "$props": {
407
+ "label": "Text style"
408
+ },
409
+ "children": [
410
+ {
411
+ "tagName": "jx-action-button",
412
+ "$props": {
413
+ "label": "Bold",
414
+ "hint": "Bold",
415
+ "icon": "text-b",
416
+ "quiet": false,
417
+ "toggles": true
418
+ }
419
+ },
420
+ {
421
+ "tagName": "jx-action-button",
422
+ "$props": {
423
+ "label": "Italic",
424
+ "hint": "Italic",
425
+ "icon": "text-italic",
426
+ "quiet": false,
427
+ "toggles": true
428
+ }
429
+ }
430
+ ]
431
+ }
432
+ ]
433
+ }
434
+ ]
435
+ }