@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
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxOption",
|
|
4
|
+
"tagName": "jx-option",
|
|
5
|
+
"observedAttributes": [
|
|
6
|
+
"value",
|
|
7
|
+
"label",
|
|
8
|
+
"description",
|
|
9
|
+
"selected",
|
|
10
|
+
"disabled",
|
|
11
|
+
"face",
|
|
12
|
+
"swatch",
|
|
13
|
+
"line",
|
|
14
|
+
"weight",
|
|
15
|
+
"slant",
|
|
16
|
+
"variant",
|
|
17
|
+
"transform",
|
|
18
|
+
"decoration"
|
|
19
|
+
],
|
|
20
|
+
"state": {
|
|
21
|
+
"value": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"default": "",
|
|
24
|
+
"attribute": "value",
|
|
25
|
+
"description": "What the row stands for; the detail of the select event it dispatches. The empty string is a LEGAL value — a row meaning inherit or none — and never absence."
|
|
26
|
+
},
|
|
27
|
+
"label": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"default": "",
|
|
30
|
+
"attribute": "label",
|
|
31
|
+
"description": "The row's words, and its accessible name. There is deliberately no default slot, which is jx-tab's answer to the same question: option takes its name from its contents, so unnamed content in the row would join the name, and a row whose only content was a badge would be announced as the badge."
|
|
32
|
+
},
|
|
33
|
+
"description": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"default": "",
|
|
36
|
+
"attribute": "description",
|
|
37
|
+
"description": "A muted note drawn at the end of the row — a path, a category, a return type. It is TEXT and part of the row's name rather than a slot, exactly as jx-select's row description is, so a reader hears what they can see and the row keeps one accessible name. Absent draws no box."
|
|
38
|
+
},
|
|
39
|
+
"selected": {
|
|
40
|
+
"type": "boolean",
|
|
41
|
+
"default": false,
|
|
42
|
+
"attribute": "selected",
|
|
43
|
+
"description": "Whether this is the row the caret is on. THE LISTBOX IS ITS SINGLE WRITER, exactly as jx-tabs is of every tab's: a consumer moves the highlight by writing the listbox's active id — the same id its owning field already points aria-activedescendant at — and never a row's flag. In this listbox the active descendant and the selection are ONE row, because selection follows the caret; a multi-select listbox, which would need them apart, is not offered."
|
|
44
|
+
},
|
|
45
|
+
"disabled": {
|
|
46
|
+
"type": "boolean",
|
|
47
|
+
"default": false,
|
|
48
|
+
"attribute": "disabled",
|
|
49
|
+
"description": "A row that cannot be picked is disabled, never absent: it stays in the list, stays announced, and dispatches nothing when clicked."
|
|
50
|
+
},
|
|
51
|
+
"face": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"default": "",
|
|
54
|
+
"attribute": "face",
|
|
55
|
+
"description": "The font family the label draws in, for a row that IS its own preview. It reaches the label as a custom property set inline on that span, so seventy rows intern the rules two rows do (spec.md 9.1) — the same channel jx-select's rows carry, under the same token name."
|
|
56
|
+
},
|
|
57
|
+
"swatch": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"default": "",
|
|
60
|
+
"attribute": "swatch",
|
|
61
|
+
"description": "A colour chip drawn before the label, as any CSS colour. Absent by default, so a row that is not about a colour pays no box for one."
|
|
62
|
+
},
|
|
63
|
+
"line": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"default": "",
|
|
66
|
+
"attribute": "line",
|
|
67
|
+
"description": "A border-style keyword drawn as a short rule before the label: solid, dashed, dotted, double. Absent by default."
|
|
68
|
+
},
|
|
69
|
+
"weight": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"default": "",
|
|
72
|
+
"attribute": "weight",
|
|
73
|
+
"description": "The font weight the label draws in, for a row that IS its own preview: 700, bold, lighter. It reaches the label the way face does, as a custom property set inline on that span, so a list of nine weights interns one rule. Absent draws the row's own weight."
|
|
74
|
+
},
|
|
75
|
+
"slant": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"default": "",
|
|
78
|
+
"attribute": "slant",
|
|
79
|
+
"description": "The font style the label draws in: italic or oblique. Named slant rather than style because style is the attribute every element already has. Absent draws upright."
|
|
80
|
+
},
|
|
81
|
+
"variant": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"default": "",
|
|
84
|
+
"attribute": "variant",
|
|
85
|
+
"description": "The font variant the label draws in: small-caps. Absent draws the row's own."
|
|
86
|
+
},
|
|
87
|
+
"transform": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"default": "",
|
|
90
|
+
"attribute": "transform",
|
|
91
|
+
"description": "The text transform the label draws with: uppercase, lowercase, capitalize. The label's WORDS are unchanged, so a reader hears the row's name and sees what choosing it would do. Absent draws the words as written."
|
|
92
|
+
},
|
|
93
|
+
"decoration": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"default": "",
|
|
96
|
+
"attribute": "decoration",
|
|
97
|
+
"description": "The text decoration the label draws with, as any text-decoration value: underline, line-through, underline wavy. Absent draws none."
|
|
98
|
+
},
|
|
99
|
+
"noSwatch": {
|
|
100
|
+
"$expression": {
|
|
101
|
+
"operator": "!",
|
|
102
|
+
"target": {
|
|
103
|
+
"$ref": "#/state/swatch"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"noLine": {
|
|
108
|
+
"$expression": {
|
|
109
|
+
"operator": "!",
|
|
110
|
+
"target": {
|
|
111
|
+
"$ref": "#/state/line"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"noDescription": {
|
|
116
|
+
"$expression": {
|
|
117
|
+
"operator": "!",
|
|
118
|
+
"target": {
|
|
119
|
+
"$ref": "#/state/description"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"onClick": {
|
|
124
|
+
"$prototype": "Function",
|
|
125
|
+
"body": [
|
|
126
|
+
{
|
|
127
|
+
"if": {
|
|
128
|
+
"operator": "!",
|
|
129
|
+
"target": {
|
|
130
|
+
"$ref": "#/state/disabled"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"then": [
|
|
134
|
+
{
|
|
135
|
+
"dispatchEvent": "select",
|
|
136
|
+
"detail": {
|
|
137
|
+
"$ref": "#/state/value"
|
|
138
|
+
},
|
|
139
|
+
"bubbles": true,
|
|
140
|
+
"composed": true
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"emits": [
|
|
146
|
+
{
|
|
147
|
+
"name": "select",
|
|
148
|
+
"description": "The row was picked; detail is its value. It bubbles, so the listbox's owner hears every row through one handler rather than one per row."
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"description": "Activation dispatches select unless the row is disabled. The click is NOT stopped, which is where this differs from jx-menu-item: a menu row can contain another menu row and would activate both, and a listbox row can contain nothing, so stopping the click here would only take the gesture away from the panel's own handler."
|
|
152
|
+
},
|
|
153
|
+
"onPointerDown": {
|
|
154
|
+
"$prototype": "Function",
|
|
155
|
+
"body": [
|
|
156
|
+
{
|
|
157
|
+
"preventDefault": true
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"description": "Keeps the caret where it was while a row is pressed. A listbox row is not focusable, so the press would otherwise move focus to the nearest focusable ancestor — off the field that owns the keyboard, and out of the canvas the slash menu is filtering for — and a combobox would fire a change for a value the reader was in the middle of replacing. The same fix jx-textfield's clear button makes, for the same reason."
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"attributes": {
|
|
164
|
+
"role": "option",
|
|
165
|
+
"aria-selected": "${state.selected ? 'true' : 'false'}",
|
|
166
|
+
"aria-disabled": "${state.disabled ? 'true' : null}"
|
|
167
|
+
},
|
|
168
|
+
"onclick": {
|
|
169
|
+
"$ref": "#/state/onClick"
|
|
170
|
+
},
|
|
171
|
+
"onpointerdown": {
|
|
172
|
+
"$ref": "#/state/onPointerDown"
|
|
173
|
+
},
|
|
174
|
+
"style": {
|
|
175
|
+
"display": "flex",
|
|
176
|
+
"&[hidden]": {
|
|
177
|
+
"display": "none"
|
|
178
|
+
},
|
|
179
|
+
"alignItems": "center",
|
|
180
|
+
"gap": "var(--jx-space-3)",
|
|
181
|
+
"minHeight": "var(--jx-control-h)",
|
|
182
|
+
"padding": "var(--jx-space-1) var(--jx-space-3)",
|
|
183
|
+
"borderRadius": "var(--jx-radius-sm)",
|
|
184
|
+
"color": "var(--jx-fg)",
|
|
185
|
+
"cursor": "pointer",
|
|
186
|
+
"userSelect": "none",
|
|
187
|
+
"scrollMarginBlock": "var(--jx-space-1)",
|
|
188
|
+
":hover": {
|
|
189
|
+
"background": "var(--jx-hover-bg)"
|
|
190
|
+
},
|
|
191
|
+
"&[aria-selected=\"true\"]": {
|
|
192
|
+
"$description": "The highlight is keyed on aria-selected rather than on a second data attribute, so the state a reader hears and the state a reader sees cannot come apart — and :hover is left as its own weaker rule, because the pointer moving over a row is a suggestion and the caret is the answer.",
|
|
193
|
+
"background": "var(--jx-accent-solid)",
|
|
194
|
+
"color": "var(--jx-accent-fg)"
|
|
195
|
+
},
|
|
196
|
+
"&[aria-disabled=\"true\"]": {
|
|
197
|
+
"opacity": "0.45",
|
|
198
|
+
"cursor": "default"
|
|
199
|
+
},
|
|
200
|
+
"& [part=\"swatch\"]": {
|
|
201
|
+
"display": "block",
|
|
202
|
+
"flex": "0 0 auto",
|
|
203
|
+
"inlineSize": "16px",
|
|
204
|
+
"blockSize": "16px",
|
|
205
|
+
"borderRadius": "var(--jx-radius-xs)",
|
|
206
|
+
"background": "var(--jx-row-swatch, transparent)",
|
|
207
|
+
"boxShadow": "inset 0 0 0 1px var(--jx-border)"
|
|
208
|
+
},
|
|
209
|
+
"& [part=\"line\"]": {
|
|
210
|
+
"display": "block",
|
|
211
|
+
"flex": "0 0 auto",
|
|
212
|
+
"inlineSize": "32px",
|
|
213
|
+
"blockSize": "0",
|
|
214
|
+
"borderBlockStart": "2px var(--jx-row-line, none) currentColor"
|
|
215
|
+
},
|
|
216
|
+
"& [part=\"icon\"]": {
|
|
217
|
+
"display": "inline-flex",
|
|
218
|
+
"flex": "0 0 auto",
|
|
219
|
+
"color": "var(--jx-fg-dim)"
|
|
220
|
+
},
|
|
221
|
+
"& [part=\"label\"]": {
|
|
222
|
+
"display": "block",
|
|
223
|
+
"minWidth": "0",
|
|
224
|
+
"overflow": "hidden",
|
|
225
|
+
"textOverflow": "ellipsis",
|
|
226
|
+
"whiteSpace": "nowrap",
|
|
227
|
+
"fontFamily": "var(--jx-row-face, inherit)",
|
|
228
|
+
"fontWeight": "var(--jx-row-weight, inherit)",
|
|
229
|
+
"fontStyle": "var(--jx-row-slant, inherit)",
|
|
230
|
+
"fontVariant": "var(--jx-row-variant, inherit)",
|
|
231
|
+
"textTransform": "var(--jx-row-transform, inherit)",
|
|
232
|
+
"textDecoration": "var(--jx-row-decoration, inherit)"
|
|
233
|
+
},
|
|
234
|
+
"& [part=\"description\"]": {
|
|
235
|
+
"display": "block",
|
|
236
|
+
"minWidth": "0",
|
|
237
|
+
"marginInlineStart": "auto",
|
|
238
|
+
"paddingInlineStart": "var(--jx-space-4)",
|
|
239
|
+
"overflow": "hidden",
|
|
240
|
+
"textOverflow": "ellipsis",
|
|
241
|
+
"whiteSpace": "nowrap",
|
|
242
|
+
"color": "var(--jx-fg-muted)",
|
|
243
|
+
"fontSize": "var(--jx-text-sm)"
|
|
244
|
+
},
|
|
245
|
+
"& [part=\"end\"]": {
|
|
246
|
+
"display": "inline-flex",
|
|
247
|
+
"alignItems": "center",
|
|
248
|
+
"flex": "0 0 auto",
|
|
249
|
+
"paddingInlineStart": "var(--jx-space-3)",
|
|
250
|
+
"color": "var(--jx-fg-muted)",
|
|
251
|
+
"fontSize": "var(--jx-text-sm)"
|
|
252
|
+
},
|
|
253
|
+
"& [part=\"swatch\"][hidden], & [part=\"line\"][hidden], & [part=\"description\"][hidden]": {
|
|
254
|
+
"display": "none"
|
|
255
|
+
},
|
|
256
|
+
"& [part=\"icon\"]:empty, & [part=\"end\"]:empty": {
|
|
257
|
+
"$description": "A slot leaves NO node once its content is distributed (spec.md 16.6), so a container that received nothing is genuinely empty and asking it is how an element finds out (ui.md 3.2). Without this, a row using neither channel still pays two boxes and the one gap between its label and its end becomes three.",
|
|
258
|
+
"display": "none"
|
|
259
|
+
},
|
|
260
|
+
"& [part=\"description\"][hidden] + [part=\"end\"], & [part=\"description\"]:empty + [part=\"end\"]": {
|
|
261
|
+
"$description": "The auto margin that pushes the end of the row to the end of the row lives on the description, which is where it belongs when there is one. With no description there is nothing holding that space open, so it moves here — and a display:none sibling still matches +, which is what makes one rule enough.",
|
|
262
|
+
"marginInlineStart": "auto"
|
|
263
|
+
},
|
|
264
|
+
"&[aria-selected=\"true\"] [part=\"description\"], &[aria-selected=\"true\"] [part=\"end\"], &[aria-selected=\"true\"] [part=\"icon\"]": {
|
|
265
|
+
"$description": "A highlighted row draws on the accent, and a muted grey on an accent fails SC 1.4.3. Every channel takes the row's own ink instead of keeping its own.",
|
|
266
|
+
"color": "inherit"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"children": [
|
|
270
|
+
{
|
|
271
|
+
"tagName": "span",
|
|
272
|
+
"attributes": {
|
|
273
|
+
"part": "swatch",
|
|
274
|
+
"aria-hidden": "true"
|
|
275
|
+
},
|
|
276
|
+
"style": {
|
|
277
|
+
"--jx-row-swatch": "${state.swatch || 'transparent'}"
|
|
278
|
+
},
|
|
279
|
+
"hidden": {
|
|
280
|
+
"$ref": "#/state/noSwatch"
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"tagName": "span",
|
|
285
|
+
"attributes": {
|
|
286
|
+
"part": "line",
|
|
287
|
+
"aria-hidden": "true"
|
|
288
|
+
},
|
|
289
|
+
"style": {
|
|
290
|
+
"--jx-row-line": "${state.line || 'none'}"
|
|
291
|
+
},
|
|
292
|
+
"hidden": {
|
|
293
|
+
"$ref": "#/state/noLine"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"tagName": "span",
|
|
298
|
+
"attributes": {
|
|
299
|
+
"part": "icon"
|
|
300
|
+
},
|
|
301
|
+
"children": [
|
|
302
|
+
{
|
|
303
|
+
"tagName": "slot",
|
|
304
|
+
"attributes": {
|
|
305
|
+
"name": "icon"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"tagName": "span",
|
|
312
|
+
"attributes": {
|
|
313
|
+
"part": "label"
|
|
314
|
+
},
|
|
315
|
+
"style": {
|
|
316
|
+
"--jx-row-face": "${state.face || 'inherit'}",
|
|
317
|
+
"--jx-row-weight": "${state.weight || 'inherit'}",
|
|
318
|
+
"--jx-row-slant": "${state.slant || 'inherit'}",
|
|
319
|
+
"--jx-row-variant": "${state.variant || 'inherit'}",
|
|
320
|
+
"--jx-row-transform": "${state.transform || 'inherit'}",
|
|
321
|
+
"--jx-row-decoration": "${state.decoration || 'inherit'}"
|
|
322
|
+
},
|
|
323
|
+
"textContent": "${state.label}"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"tagName": "span",
|
|
327
|
+
"attributes": {
|
|
328
|
+
"part": "description"
|
|
329
|
+
},
|
|
330
|
+
"hidden": {
|
|
331
|
+
"$ref": "#/state/noDescription"
|
|
332
|
+
},
|
|
333
|
+
"textContent": "${state.description}"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"tagName": "span",
|
|
337
|
+
"attributes": {
|
|
338
|
+
"part": "end"
|
|
339
|
+
},
|
|
340
|
+
"children": [
|
|
341
|
+
{
|
|
342
|
+
"tagName": "slot",
|
|
343
|
+
"attributes": {
|
|
344
|
+
"name": "end"
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
]
|
|
350
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
|
+
"$id": "JxPopover",
|
|
4
|
+
"tagName": "jx-popover",
|
|
5
|
+
"observedAttributes": ["label", "arrow", "match-width", "placement", "x", "y", "floor"],
|
|
6
|
+
"state": {
|
|
7
|
+
"label": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "",
|
|
10
|
+
"attribute": "label",
|
|
11
|
+
"description": "The panel's accessible name. Set, the panel becomes a named role=\"group\"; empty, it carries no role at all. A PANEL HOLDING CONTROLS MUST SET IT: role=\"group\" is in neither the accessibility lint's content-named roles nor its labelled roles, so an unnamed one is invisible to every gate, and a non-modal group of form controls with no role and no name announces no boundary on entry. A panel holding only a jx-menu leaves it empty, because the menu carries its own name."
|
|
12
|
+
},
|
|
13
|
+
"arrow": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"default": false,
|
|
16
|
+
"attribute": "arrow",
|
|
17
|
+
"description": "Draw a pointer at the panel's block-start edge. Decorative and aria-hidden; off by default, because a panel placed by measured coordinates cannot promise the arrow lands on its anchor. THE PANEL ITSELF NEVER SCROLLS: the scroll box is [part=\"content\"], because a scroll container clips whatever hangs outside its padding box and the arrow hangs 5px above it; with overflow on the host the arrow paints nothing at all."
|
|
18
|
+
},
|
|
19
|
+
"matchWidth": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"default": false,
|
|
22
|
+
"attribute": "match-width",
|
|
23
|
+
"description": "Make the panel at least as wide as the element it was opened from, the way a select's list matches its trigger. The width is re-measured on each toggle and never continuously, from whatever the toggle names as its source: a raw <button popovertarget>, a kit button forwarding popovertarget, and openAt(panel, trigger) all measure the trigger."
|
|
24
|
+
},
|
|
25
|
+
"placement": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"default": "block-end span-inline-end",
|
|
28
|
+
"attribute": "placement",
|
|
29
|
+
"description": "Where the panel sits relative to the element it was opened from, as a CSS position-area value: block-end span-inline-end (below, its inline-start edge on the trigger's) by default; block-end span-inline-start for a panel that hangs from a trigger's trailing edge; block-start for one that opens above. It applies only while the panel is ANCHORED, which is whenever it was shown from a source, and only on an engine with CSS anchor positioning: the trigger becomes the popover's implicit anchor the moment it is passed to showPopover({ source }) or names the panel with popovertarget, so no anchor-name is ever written on a consumer's element (specs/ui.md 2, 6). Everywhere else the panel stands at x and y. The value is passed to the property as written and is not validated here, because the platform's own grammar is the contract and a value it refuses computes to none, which is the coordinate placement again."
|
|
30
|
+
},
|
|
31
|
+
"x": {
|
|
32
|
+
"type": "number",
|
|
33
|
+
"default": 0,
|
|
34
|
+
"attribute": "x",
|
|
35
|
+
"description": "Where the panel's inline-start edge sits, in viewport pixels, whenever the panel is NOT anchored: shown with no source, given a floor, or on an engine without CSS anchor positioning. A panel shown from a source is placed by the platform against that source (see placement) and ignores x and y, though an opener may still write them, because they are exactly the fallback the anchored rule stands on."
|
|
36
|
+
},
|
|
37
|
+
"y": {
|
|
38
|
+
"type": "number",
|
|
39
|
+
"default": 0,
|
|
40
|
+
"attribute": "y",
|
|
41
|
+
"description": "Where the panel's block-start edge sits, in viewport pixels, under the same condition as x. The gap between that edge and the anchor is the --jx-popover-offset token, not a prop: a numeric prop with a non-zero default cannot express \"unset\", because removing its attribute coerces through the current value's type and writes 0. Anchored, the same margin is the gap below the trigger."
|
|
42
|
+
},
|
|
43
|
+
"floor": {
|
|
44
|
+
"type": "number",
|
|
45
|
+
"default": 0,
|
|
46
|
+
"attribute": "floor",
|
|
47
|
+
"description": "The lowest edge the panel may reach, in viewport pixels; 0 means the viewport's bottom. A panel opened from a rail that abuts a status bar sets it to the rail's bottom, so a tall panel never runs down over the bar."
|
|
48
|
+
},
|
|
49
|
+
"open": {
|
|
50
|
+
"type": "boolean",
|
|
51
|
+
"default": false,
|
|
52
|
+
"description": "Whether the panel is showing. THIS IS NOT A DOOR: writing el.open = true shows nothing. It follows the platform's toggle event; write it through showPopover() and hidePopover(), or through the openAt() and close() helpers in the behaviours module, not directly."
|
|
53
|
+
},
|
|
54
|
+
"settling": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"default": false,
|
|
57
|
+
"description": "Whether a discrete open or close transition is still running. Mirrored as data-jx-settling, so a host can wait for the panel to come to rest before measuring it."
|
|
58
|
+
},
|
|
59
|
+
"anchorWidth": {
|
|
60
|
+
"type": "number",
|
|
61
|
+
"default": 0,
|
|
62
|
+
"description": "The measured border-box width of the element the panel was opened from, in pixels. Written by the behaviour under matchWidth and read by the panel's own min-width; 0 when nothing has been measured."
|
|
63
|
+
},
|
|
64
|
+
"anchored": {
|
|
65
|
+
"type": "boolean",
|
|
66
|
+
"default": false,
|
|
67
|
+
"description": "Whether the panel is showing from a source the platform knows, and therefore positioned by anchor rather than by x and y. Written by the behaviour on beforetoggle, before the panel is laid out, so the first frame is already in the right place; cleared when it closes. Mirrored as data-anchored, which the anchored rule keys on. Not an attribute, because it is the platform's fact and never a consumer's to set. A panel given a floor is never anchored: a floor is a limit the platform's fallbacks cannot express, so it keeps the coordinate placement the clamp honours."
|
|
68
|
+
},
|
|
69
|
+
"panelWidth": "${state.matchWidth && state.anchorWidth > 0 ? state.anchorWidth + 'px' : '180px'}",
|
|
70
|
+
"noArrow": {
|
|
71
|
+
"$expression": {
|
|
72
|
+
"operator": "===",
|
|
73
|
+
"target": {
|
|
74
|
+
"$ref": "#/state/arrow"
|
|
75
|
+
},
|
|
76
|
+
"value": false
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"onBeforeToggle": {
|
|
80
|
+
"$prototype": "Function",
|
|
81
|
+
"$src": "jx-ui:/behaviors/popover.ts",
|
|
82
|
+
"$export": "onBeforeToggle",
|
|
83
|
+
"description": "Decides anchored before the panel is laid out: an opening toggle whose source the platform names, on a panel with no floor, is anchored; everything else is not. On beforetoggle rather than toggle because toggle is queued after the show and a panel that learned it was anchored one frame late would paint once at its coordinates and then jump."
|
|
84
|
+
},
|
|
85
|
+
"onToggle": {
|
|
86
|
+
"$prototype": "Function",
|
|
87
|
+
"$src": "jx-ui:/behaviors/popover.ts",
|
|
88
|
+
"$export": "onToggle",
|
|
89
|
+
"description": "Mirrors the platform's toggle event into open, raises settling for the transition, measures the anchor under matchWidth, and clamps a freshly shown panel into the viewport when it is not anchored; an anchored panel is placed and flipped by the platform and is left alone."
|
|
90
|
+
},
|
|
91
|
+
"onTransitionEnd": {
|
|
92
|
+
"$prototype": "Function",
|
|
93
|
+
"$src": "jx-ui:/behaviors/popover.ts",
|
|
94
|
+
"$export": "onTransitionEnd",
|
|
95
|
+
"description": "Clears settling when the panel's own transition finishes. A transition on a child is not the panel coming to rest, so only an event whose target is the host counts."
|
|
96
|
+
},
|
|
97
|
+
"onMount": {
|
|
98
|
+
"$prototype": "Function",
|
|
99
|
+
"body": [
|
|
100
|
+
{
|
|
101
|
+
"dispatchEvent": "jx-ready",
|
|
102
|
+
"bubbles": true
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"description": "Announces that the element has rendered and carries its popover attribute, so a host may show it. A panel is always an auto popover: light dismiss, Escape and focus restoration are the platform's."
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"onbeforetoggle": {
|
|
109
|
+
"$ref": "#/state/onBeforeToggle"
|
|
110
|
+
},
|
|
111
|
+
"ontoggle": {
|
|
112
|
+
"$ref": "#/state/onToggle"
|
|
113
|
+
},
|
|
114
|
+
"ontransitionend": {
|
|
115
|
+
"$ref": "#/state/onTransitionEnd"
|
|
116
|
+
},
|
|
117
|
+
"attributes": {
|
|
118
|
+
"popover": "auto",
|
|
119
|
+
"role": "${state.label ? 'group' : null}",
|
|
120
|
+
"aria-label": "${state.label || null}",
|
|
121
|
+
"data-open": "${state.open ? '' : null}",
|
|
122
|
+
"data-jx-settling": "${state.settling ? '' : null}",
|
|
123
|
+
"data-anchored": "${state.anchored ? '' : null}"
|
|
124
|
+
},
|
|
125
|
+
"style": {
|
|
126
|
+
"display": "revert-layer",
|
|
127
|
+
"&[hidden]": {
|
|
128
|
+
"display": "none"
|
|
129
|
+
},
|
|
130
|
+
"position": "fixed",
|
|
131
|
+
"insetInlineStart": "${state.x}px",
|
|
132
|
+
"insetBlockStart": "${state.y}px",
|
|
133
|
+
"insetInlineEnd": "auto",
|
|
134
|
+
"insetBlockEnd": "auto",
|
|
135
|
+
"margin": "0",
|
|
136
|
+
"marginBlockStart": "var(--jx-popover-offset, 4px)",
|
|
137
|
+
"padding": "var(--jx-space-2)",
|
|
138
|
+
"minWidth": "${state.panelWidth}",
|
|
139
|
+
"maxWidth": "min(360px, calc(100vw - 8px))",
|
|
140
|
+
"maxHeight": "calc(100vh - 8px)",
|
|
141
|
+
"overflow": "visible",
|
|
142
|
+
"boxSizing": "border-box",
|
|
143
|
+
"flexDirection": "column",
|
|
144
|
+
"background": "var(--jx-bg-overlay)",
|
|
145
|
+
"color": "var(--jx-fg)",
|
|
146
|
+
"border": "1px solid var(--jx-border-strong)",
|
|
147
|
+
"borderRadius": "var(--jx-radius-md)",
|
|
148
|
+
"boxShadow": "var(--jx-shadow-popover)",
|
|
149
|
+
"fontFamily": "var(--jx-font-sans)",
|
|
150
|
+
"fontSize": "var(--jx-text-md)",
|
|
151
|
+
"lineHeight": "var(--jx-leading-md)",
|
|
152
|
+
"pointerEvents": "auto",
|
|
153
|
+
"outline": "none",
|
|
154
|
+
"opacity": "0",
|
|
155
|
+
"transition": "opacity var(--jx-dur-1) var(--jx-ease-out), display var(--jx-dur-1) allow-discrete, overlay var(--jx-dur-1) allow-discrete",
|
|
156
|
+
":popover-open": {
|
|
157
|
+
"display": "flex",
|
|
158
|
+
"opacity": "1"
|
|
159
|
+
},
|
|
160
|
+
"&[hidden]:popover-open": {
|
|
161
|
+
"display": "none"
|
|
162
|
+
},
|
|
163
|
+
"&:focus-visible": {
|
|
164
|
+
"outline": "var(--jx-focus-ring)"
|
|
165
|
+
},
|
|
166
|
+
"@supports (position-area: block-end)": {
|
|
167
|
+
"$description": "The anchored placement, and the whole of what CSS anchor positioning gives a panel: the platform puts it against its IMPLICIT anchor — the element it was shown from — follows that element through scroll and resize, and flips it to the other side when the first placement would overflow, none of which a measured coordinate can do without a listener per cause. No anchor-name is involved: a popover's invoker is its implicit anchor by the platform's own rule, which is what makes this reachable under ui.md 2 (an element writes no style on a consumer's trigger). The insets are released so x and y stop mattering, and matchWidth becomes anchor-size, which follows the trigger as it resizes where the measured width could not. Outside this block, and on a panel shown from nothing or with a floor, the coordinate placement above is the answer, unchanged.",
|
|
168
|
+
"&[data-anchored]": {
|
|
169
|
+
"insetInlineStart": "auto",
|
|
170
|
+
"insetBlockStart": "auto",
|
|
171
|
+
"positionArea": "${state.placement}",
|
|
172
|
+
"positionTryFallbacks": "flip-block, flip-inline, flip-block flip-inline",
|
|
173
|
+
"minWidth": "${state.matchWidth ? 'anchor-size(width)' : '180px'}"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"@starting-style": {
|
|
177
|
+
"&:popover-open": {
|
|
178
|
+
"opacity": "0"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"& > [part=\"content\"]": {
|
|
182
|
+
"display": "flex",
|
|
183
|
+
"flexDirection": "column",
|
|
184
|
+
"gap": "var(--jx-space-2)",
|
|
185
|
+
"minHeight": "0",
|
|
186
|
+
"overflow": "auto"
|
|
187
|
+
},
|
|
188
|
+
"& > [part=\"arrow\"]": {
|
|
189
|
+
"display": "block",
|
|
190
|
+
"position": "absolute",
|
|
191
|
+
"insetBlockStart": "-5px",
|
|
192
|
+
"insetInlineStart": "var(--jx-space-4)",
|
|
193
|
+
"width": "8px",
|
|
194
|
+
"height": "8px",
|
|
195
|
+
"rotate": "45deg",
|
|
196
|
+
"background": "var(--jx-bg-overlay)",
|
|
197
|
+
"borderTop": "1px solid var(--jx-border-strong)",
|
|
198
|
+
"borderInlineStart": "1px solid var(--jx-border-strong)"
|
|
199
|
+
},
|
|
200
|
+
"& > [part=\"arrow\"][hidden]": {
|
|
201
|
+
"display": "none"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"children": [
|
|
205
|
+
{
|
|
206
|
+
"tagName": "div",
|
|
207
|
+
"attributes": {
|
|
208
|
+
"part": "content"
|
|
209
|
+
},
|
|
210
|
+
"children": [
|
|
211
|
+
{
|
|
212
|
+
"tagName": "slot"
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"tagName": "span",
|
|
218
|
+
"attributes": {
|
|
219
|
+
"part": "arrow",
|
|
220
|
+
"aria-hidden": "true"
|
|
221
|
+
},
|
|
222
|
+
"hidden": {
|
|
223
|
+
"$ref": "#/state/noArrow"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
}
|