@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,262 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxSwatch",
4
+ "tagName": "jx-swatch",
5
+ "observedAttributes": ["color", "value", "label", "checked", "selected", "disabled", "size"],
6
+ "$elements": [
7
+ {
8
+ "$ref": "./jx-icon.json"
9
+ }
10
+ ],
11
+ "state": {
12
+ "color": {
13
+ "type": "string",
14
+ "default": "",
15
+ "attribute": "color",
16
+ "description": "The colour the chip draws, as any CSS colour the page can resolve. Empty is a legal value and is the NO COLOUR chip: it draws a slashed square rather than nothing, because a blank square in a palette reads as a white swatch and picking it would be picking white."
17
+ },
18
+ "value": {
19
+ "type": "string",
20
+ "default": "",
21
+ "attribute": "value",
22
+ "description": "What the swatch stands for: the detail of the select it dispatches, and what a swatch group compares its own value against. Empty falls back to color, so a palette of literal colours needs no second attribute; set it when the swatch stands for a TOKEN whose colour is only how it looks, which is the case a project's palette is made of."
23
+ },
24
+ "label": {
25
+ "type": "string",
26
+ "default": "",
27
+ "attribute": "label",
28
+ "description": "The swatch's name, and its accessible name: it is written to aria-label, so it wins over anything slotted beside the chip. A COLOUR IS NOT A NAME. Without this the element falls back to the value and then to the colour, which announces \"#3b82f6\" one character at a time — legible, technically a name, and useless. Give every swatch in a palette the word a reader would use for it."
29
+ },
30
+ "checked": {
31
+ "type": "string",
32
+ "default": "",
33
+ "attribute": "checked",
34
+ "description": "Empty for a plain button; true or false for one member of a swatch group, which then carries role=radio and aria-checked on its control and puts role=none on the HOST so the radio is the group's own child rather than a grandchild behind a generic. jx-swatch-group is the single writer of this on its children, exactly as jx-tabs is of a tab's selected, so a host moves the selection by writing the group's value."
35
+ },
36
+ "selected": {
37
+ "type": "boolean",
38
+ "default": false,
39
+ "attribute": "selected",
40
+ "description": "Draws the chosen ring and the tick without announcing anything, for a swatch a host has chosen outside a radio group. It is the drawing alone: checked is what a reader is TOLD, and setting one never sets the other."
41
+ },
42
+ "disabled": {
43
+ "type": "boolean",
44
+ "default": false,
45
+ "attribute": "disabled",
46
+ "description": "Cannot be chosen or focused. Disabled, never absent."
47
+ },
48
+ "size": {
49
+ "type": "string",
50
+ "default": "md",
51
+ "attribute": "size",
52
+ "description": "sm, md or lg. The chip grows; the button's target does not shrink below the kit's control height, so a small swatch is still a target a finger can hit."
53
+ },
54
+ "tabindex": {
55
+ "type": "string",
56
+ "default": "",
57
+ "description": "Forwarded to the inner control as its tabindex, which is what makes a roving caret possible: the focusable node is the button inside, not the host, so a group moving focus writes this rather than reaching into a child's internals. It is a PROPERTY ONLY 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 one control would become two tab stops."
58
+ },
59
+ "inkOf": {
60
+ "$prototype": "Function",
61
+ "$src": "jx-ui:/color.ts",
62
+ "$export": "inkOn",
63
+ "parameters": ["color"],
64
+ "description": "Black or white, whichever can be seen on the swatch's own colour, or the empty string for a colour only the browser can resolve. Pure: it takes the colour and returns a word."
65
+ },
66
+ "ink": "${state.inkOf(state.color)}",
67
+ "token": "${state.value || state.color}",
68
+ "name": "${state.label || state.value || state.color || 'Colour'}",
69
+ "isChecked": {
70
+ "$expression": {
71
+ "operator": "===",
72
+ "target": {
73
+ "$ref": "#/state/checked"
74
+ },
75
+ "value": "true"
76
+ }
77
+ },
78
+ "chosen": {
79
+ "$expression": {
80
+ "operator": "||",
81
+ "target": {
82
+ "$ref": "#/state/isChecked"
83
+ },
84
+ "value": {
85
+ "$ref": "#/state/selected"
86
+ }
87
+ }
88
+ },
89
+ "onClick": {
90
+ "$prototype": "Function",
91
+ "body": [
92
+ {
93
+ "dispatchEvent": "select",
94
+ "detail": {
95
+ "$ref": "#/state/token"
96
+ },
97
+ "bubbles": true
98
+ }
99
+ ],
100
+ "emits": [
101
+ {
102
+ "name": "select",
103
+ "description": "The swatch was activated; detail is what it stands for. A swatch group listens for it and answers with its own change."
104
+ }
105
+ ],
106
+ "description": "Activation says what the swatch stands for and nothing else. It does not write its own checked: inside a group the group owns that, and outside one the host does, and an element that chose itself would disagree with both."
107
+ }
108
+ },
109
+ "onclick": {
110
+ "$ref": "#/state/onClick"
111
+ },
112
+ "attributes": {
113
+ "role": "${state.checked ? 'none' : null}",
114
+ "data-size": "${state.size}",
115
+ "data-chosen": "${state.chosen ? '' : null}",
116
+ "data-empty": "${state.color ? null : ''}",
117
+ "data-disabled": "${state.disabled ? '' : null}"
118
+ },
119
+ "style": {
120
+ "display": "inline-flex",
121
+ "&[hidden]": {
122
+ "display": "none"
123
+ },
124
+ "verticalAlign": "middle",
125
+ "--jx-swatch-size": "20px",
126
+ "--jx-swatch-color": "${state.color || 'transparent'}",
127
+ "--jx-swatch-ink": "${state.ink || 'var(--jx-border-strong)'}",
128
+ "--jx-color-checkerboard": "repeating-conic-gradient(var(--jx-gray-300) 0% 25%, var(--jx-bg-input) 0% 50%) 50% / 8px 8px",
129
+ "&[data-size=\"sm\"]": {
130
+ "--jx-swatch-size": "14px"
131
+ },
132
+ "&[data-size=\"lg\"]": {
133
+ "--jx-swatch-size": "28px"
134
+ },
135
+ "& > [part=\"control\"]": {
136
+ "appearance": "none",
137
+ "font": "inherit",
138
+ "fontFamily": "var(--jx-font-sans)",
139
+ "fontSize": "var(--jx-text-md)",
140
+ "display": "inline-flex",
141
+ "alignItems": "center",
142
+ "gap": "var(--jx-space-2)",
143
+ "minInlineSize": "var(--jx-control-h)",
144
+ "minBlockSize": "var(--jx-control-h)",
145
+ "margin": "0",
146
+ "padding": "var(--jx-space-1)",
147
+ "border": "0",
148
+ "borderRadius": "var(--jx-radius-sm)",
149
+ "background": "transparent",
150
+ "color": "var(--jx-fg)",
151
+ "cursor": "pointer",
152
+ "outline": "none",
153
+ ":hover": {
154
+ "background": "var(--jx-hover-bg)"
155
+ },
156
+ ":focus-visible": {
157
+ "outline": "var(--jx-focus-ring)",
158
+ "outlineOffset": "-2px"
159
+ },
160
+ ":disabled": {
161
+ "opacity": "0.5",
162
+ "cursor": "default"
163
+ }
164
+ },
165
+ "& [part=\"chip\"]": {
166
+ "$description": "The ring is drawn with the ink the element worked out from its own colour rather than with a neutral border token, because a mid-grey boundary disappears against a mid-grey swatch and a control whose edge cannot be seen is a WCAG 1.4.11 failure. The checkerboard behind it is what makes a translucent colour read as translucent instead of as a paler opaque one.",
167
+ "position": "relative",
168
+ "display": "inline-flex",
169
+ "alignItems": "center",
170
+ "justifyContent": "center",
171
+ "flex": "none",
172
+ "inlineSize": "var(--jx-swatch-size)",
173
+ "blockSize": "var(--jx-swatch-size)",
174
+ "borderRadius": "var(--jx-radius-xs)",
175
+ "background": "linear-gradient(var(--jx-swatch-color), var(--jx-swatch-color)), var(--jx-color-checkerboard)",
176
+ "boxShadow": "inset 0 0 0 1px var(--jx-swatch-ink)",
177
+ "color": "var(--jx-swatch-ink)"
178
+ },
179
+ "&[data-empty] [part=\"chip\"]": {
180
+ "background": "linear-gradient(to bottom right, transparent calc(50% - 1px), var(--jx-danger) calc(50% - 1px), var(--jx-danger) calc(50% + 1px), transparent calc(50% + 1px)), var(--jx-bg-input)"
181
+ },
182
+ "&[data-chosen] [part=\"chip\"]": {
183
+ "outline": "2px solid var(--jx-fg)",
184
+ "outlineOffset": "2px"
185
+ },
186
+ "& [part=\"mark\"]": {
187
+ "display": "inline-flex",
188
+ "color": "inherit"
189
+ },
190
+ "& [part=\"label\"]": {
191
+ "minInlineSize": "0",
192
+ "overflow": "hidden",
193
+ "textOverflow": "ellipsis",
194
+ "whiteSpace": "nowrap"
195
+ },
196
+ "& [part=\"label\"]:empty": {
197
+ "display": "none"
198
+ },
199
+ "& [part=\"mark-slot\"]": {
200
+ "display": "contents"
201
+ }
202
+ },
203
+ "children": [
204
+ {
205
+ "tagName": "button",
206
+ "attributes": {
207
+ "part": "control",
208
+ "type": "button",
209
+ "role": "${state.checked ? 'radio' : null}",
210
+ "aria-checked": "${state.checked || null}",
211
+ "aria-label": "${state.name}",
212
+ "tabindex": "${state.tabindex || null}",
213
+ "disabled": {
214
+ "$ref": "#/state/disabled"
215
+ }
216
+ },
217
+ "children": [
218
+ {
219
+ "tagName": "span",
220
+ "attributes": {
221
+ "part": "chip",
222
+ "aria-hidden": "true"
223
+ },
224
+ "children": [
225
+ {
226
+ "tagName": "span",
227
+ "attributes": {
228
+ "part": "mark-slot"
229
+ },
230
+ "$switch": {
231
+ "$ref": "#/state/chosen"
232
+ },
233
+ "cases": {
234
+ "true": {
235
+ "tagName": "jx-icon",
236
+ "$props": {
237
+ "name": "check",
238
+ "weight": "bold"
239
+ },
240
+ "attributes": {
241
+ "part": "mark"
242
+ }
243
+ }
244
+ }
245
+ }
246
+ ]
247
+ },
248
+ {
249
+ "tagName": "span",
250
+ "attributes": {
251
+ "part": "label"
252
+ },
253
+ "children": [
254
+ {
255
+ "tagName": "slot"
256
+ }
257
+ ]
258
+ }
259
+ ]
260
+ }
261
+ ]
262
+ }
@@ -0,0 +1,331 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxSwitch",
4
+ "tagName": "jx-switch",
5
+ "observedAttributes": [
6
+ "checked",
7
+ "disabled",
8
+ "hint",
9
+ "label",
10
+ "labelledby",
11
+ "describedby",
12
+ "name",
13
+ "size"
14
+ ],
15
+ "$elements": [
16
+ {
17
+ "$ref": "./jx-tooltip.json"
18
+ }
19
+ ],
20
+ "state": {
21
+ "checked": {
22
+ "type": "boolean",
23
+ "default": false,
24
+ "attribute": "checked",
25
+ "description": "Whether the setting is on. Bound to the control BOTH ways, and the two halves do different jobs. The PROPERTY is what keeps tracking: once the reader flips the box the checkedness dirty flag is set and the content attribute stops controlling the live state, so an attribute binding alone would look right until the first click and then silently stop. The ATTRIBUTE is written as well so the control's defaultChecked can never disagree with the element's state — the same shape jx-textfield ships for value. The cost is that defaultChecked is also the form-reset default, so until the element is form-associated (specs/ui.md §3.2) form.reset() moves this switch nowhere. That is the deliberate half of the trade: with no form association the element never hears the reset, so a working reset would move the CONTROL to the authored default and leave the element's checked state behind it, and a control that silently disagrees with its own element is worse than a reset that does nothing."
26
+ },
27
+ "disabled": {
28
+ "type": "boolean",
29
+ "default": false,
30
+ "attribute": "disabled",
31
+ "description": "Cannot be flipped or focused. Disabled, never absent, and the hint moves from the tip to the row's title while it is: a disabled control cannot open a tip, and why the setting cannot be changed is exactly what the reader hovers to find out."
32
+ },
33
+ "hint": {
34
+ "type": "string",
35
+ "default": "",
36
+ "attribute": "hint",
37
+ "description": "The tooltip on the row: what turning the setting on does, or why it cannot be changed. The same hybrid jx-button and jx-action-button ship. While the switch is ENABLED it is drawn as 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) — and the control names it in aria-describedby, so it is a description beside the name and never the name itself. While the switch is DISABLED it is the native title of the wrapping label instead, because a disabled control receives no focus and no pointer event and could never open a tip, while the platform still shows a title on hover. Never both at once; empty draws neither. ONE difference from the buttons, and it is the platform's rather than the kit's: the tip is wired by `for` alone and the row declares NO `interestfor`. Interest invokers are supported on `a`, `area` and `button` only — never on a label or an input — so the attribute here would show nothing on Chrome 152 while telling the tooltip sidecar the platform had the pair, which is the one combination that draws no tip on any engine. The sidecar binds the label on every engine instead, and that is what the switch pays for a tooltip: six listeners on the row and two on the tip, always, where a button pays them only where the platform lacks the attribute."
38
+ },
39
+ "label": {
40
+ "type": "string",
41
+ "default": "",
42
+ "attribute": "label",
43
+ "description": "The accessible name, forwarded to the control as aria-label. Leave it empty when the slotted text is on screen: the wrapping label is then the name, and a second one would be read twice."
44
+ },
45
+ "labelledby": {
46
+ "type": "string",
47
+ "default": "",
48
+ "attribute": "labelledby",
49
+ "description": "Forwarded to the inner control as aria-labelledby, for a visible label the element does not own."
50
+ },
51
+ "describedby": {
52
+ "type": "string",
53
+ "default": "",
54
+ "attribute": "describedby",
55
+ "description": "Forwarded to the inner control as aria-describedby, for the help or error sentence on the row."
56
+ },
57
+ "name": {
58
+ "type": "string",
59
+ "default": "",
60
+ "attribute": "name",
61
+ "description": "The form field name, forwarded to the control."
62
+ },
63
+ "size": {
64
+ "type": "string",
65
+ "default": "md",
66
+ "attribute": "size",
67
+ "description": "sm, md or lg. The track scales with it so a row of controls lines up."
68
+ },
69
+ "tabindex": {
70
+ "type": "string",
71
+ "default": "",
72
+ "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."
73
+ },
74
+ "uid": {
75
+ "type": "string",
76
+ "default": "",
77
+ "description": "This row's own id stem, minted on mount by the tooltip sidecar. The label's id, the tip's id and the two attributes that wire one to the other are all built from it, so a consumer writes none of them and two hinted switches on one panel cannot collide. Empty until the mount microtask, which is why every binding that reads it guards on it."
78
+ },
79
+ "hasTip": {
80
+ "$expression": {
81
+ "operator": "&&",
82
+ "target": {
83
+ "operator": "!",
84
+ "target": {
85
+ "operator": "!",
86
+ "target": {
87
+ "$ref": "#/state/hint"
88
+ }
89
+ }
90
+ },
91
+ "value": {
92
+ "operator": "&&",
93
+ "target": {
94
+ "operator": "!",
95
+ "target": {
96
+ "$ref": "#/state/disabled"
97
+ }
98
+ },
99
+ "value": {
100
+ "operator": "!==",
101
+ "target": {
102
+ "$ref": "#/state/uid"
103
+ },
104
+ "value": ""
105
+ }
106
+ }
107
+ }
108
+ },
109
+ "onMount": {
110
+ "$prototype": "Function",
111
+ "$src": "jx-ui:/behaviors/tooltip.ts",
112
+ "$export": "mintHintId",
113
+ "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."
114
+ },
115
+ "onChange": {
116
+ "$prototype": "Function",
117
+ "body": [
118
+ {
119
+ "operator": "=",
120
+ "target": {
121
+ "$ref": "#/state/checked"
122
+ },
123
+ "value": {
124
+ "$ref": "event#/target/checked"
125
+ }
126
+ }
127
+ ],
128
+ "description": "Mirrors the reader's flip into checked. The native change and input events bubble from the control as they always do, so a host reads e.target.checked exactly as it would from a bare input."
129
+ }
130
+ },
131
+ "attributes": {
132
+ "data-size": "${state.size}",
133
+ "data-checked": "${state.checked ? '' : null}",
134
+ "data-disabled": "${state.disabled ? '' : null}"
135
+ },
136
+ "style": {
137
+ "display": "inline-flex",
138
+ "verticalAlign": "middle",
139
+ "&[hidden]": {
140
+ "display": "none"
141
+ },
142
+ "& > [part=\"control\"]": {
143
+ "display": "inline-flex",
144
+ "alignItems": "center",
145
+ "gap": "var(--jx-space-2)",
146
+ "minHeight": "var(--jx-control-h)",
147
+ "fontFamily": "var(--jx-font-sans)",
148
+ "fontSize": "var(--jx-text-md)",
149
+ "lineHeight": "var(--jx-leading-md)",
150
+ "color": "var(--jx-fg)",
151
+ "cursor": "pointer"
152
+ },
153
+ "&[data-disabled] > [part=\"control\"]": {
154
+ "cursor": "default",
155
+ "color": "var(--jx-fg-muted)"
156
+ },
157
+ "& [part=\"input\"]": {
158
+ "appearance": "none",
159
+ "boxSizing": "border-box",
160
+ "position": "relative",
161
+ "flex": "0 0 auto",
162
+ "width": "28px",
163
+ "height": "16px",
164
+ "margin": "0",
165
+ "padding": "0",
166
+ "border": "1px solid var(--jx-switch-track)",
167
+ "borderRadius": "999px",
168
+ "background": "var(--jx-switch-track)",
169
+ "cursor": "inherit",
170
+ "outline": "none",
171
+ "--jx-switch-travel": "12px",
172
+ "transition": "background var(--jx-dur-1) var(--jx-ease-out), border-color var(--jx-dur-1) var(--jx-ease-out)",
173
+ "::before": {
174
+ "content": "\"\"",
175
+ "position": "absolute",
176
+ "insetBlockStart": "1px",
177
+ "insetInlineStart": "1px",
178
+ "width": "12px",
179
+ "height": "12px",
180
+ "borderRadius": "50%",
181
+ "background": "var(--jx-switch-thumb)",
182
+ "transition": "translate var(--jx-dur-1) var(--jx-ease-out)"
183
+ },
184
+ ":checked": {
185
+ "background": "var(--jx-accent-solid)",
186
+ "borderColor": "var(--jx-accent-solid)",
187
+ "::before": {
188
+ "translate": "var(--jx-switch-travel) 0"
189
+ }
190
+ },
191
+ ":focus-visible": {
192
+ "outline": "var(--jx-focus-ring)",
193
+ "outlineOffset": "2px"
194
+ },
195
+ ":disabled": {
196
+ "opacity": "0.5",
197
+ "cursor": "default"
198
+ }
199
+ },
200
+ "&:dir(rtl) [part=\"input\"]:checked::before": {
201
+ "translate": "calc(-1 * var(--jx-switch-travel)) 0"
202
+ },
203
+ "&[data-size=\"sm\"] [part=\"input\"]": {
204
+ "width": "22px",
205
+ "height": "12px",
206
+ "--jx-switch-travel": "10px",
207
+ "::before": {
208
+ "width": "8px",
209
+ "height": "8px"
210
+ }
211
+ },
212
+ "&[data-size=\"lg\"] [part=\"input\"]": {
213
+ "width": "34px",
214
+ "height": "20px",
215
+ "--jx-switch-travel": "14px",
216
+ "::before": {
217
+ "width": "16px",
218
+ "height": "16px"
219
+ }
220
+ },
221
+ "& [part=\"label\"]": {
222
+ "minWidth": "0"
223
+ },
224
+ "& [part=\"label\"]:empty": {
225
+ "display": "none"
226
+ },
227
+ "& > [part=\"tooltip\"]": {
228
+ "display": "contents"
229
+ },
230
+ "@(forced-colors: active)": {
231
+ "& [part=\"input\"]": {
232
+ "forcedColorAdjust": "none",
233
+ "background": "ButtonFace",
234
+ "borderColor": "ButtonText",
235
+ "::before": {
236
+ "background": "ButtonText"
237
+ },
238
+ ":checked": {
239
+ "background": "Highlight",
240
+ "borderColor": "Highlight",
241
+ "::before": {
242
+ "background": "ButtonFace"
243
+ }
244
+ },
245
+ ":disabled": {
246
+ "borderColor": "GrayText",
247
+ "opacity": "1",
248
+ "::before": {
249
+ "background": "GrayText"
250
+ }
251
+ }
252
+ }
253
+ }
254
+ },
255
+ "children": [
256
+ {
257
+ "tagName": "label",
258
+ "attributes": {
259
+ "part": "control",
260
+ "id": "${state.uid || null}",
261
+ "title": "${state.disabled && state.hint ? state.hint : null}"
262
+ },
263
+ "children": [
264
+ {
265
+ "tagName": "input",
266
+ "attributes": {
267
+ "part": "input",
268
+ "type": "checkbox",
269
+ "role": "switch",
270
+ "aria-label": "${state.label || null}",
271
+ "aria-labelledby": "${state.labelledby || null}",
272
+ "aria-describedby": "${[state.hasTip ? state.uid + '-tip' : null, state.describedby || null].filter(Boolean).join(' ') || null}",
273
+ "tabindex": "${state.tabindex || null}",
274
+ "name": "${state.name || null}",
275
+ "disabled": {
276
+ "$ref": "#/state/disabled"
277
+ },
278
+ "checked": {
279
+ "$ref": "#/state/checked"
280
+ }
281
+ },
282
+ "checked": {
283
+ "$ref": "#/state/checked"
284
+ },
285
+ "onchange": {
286
+ "$ref": "#/state/onChange"
287
+ }
288
+ },
289
+ {
290
+ "tagName": "span",
291
+ "attributes": {
292
+ "part": "label"
293
+ },
294
+ "children": [
295
+ {
296
+ "tagName": "slot"
297
+ }
298
+ ]
299
+ }
300
+ ]
301
+ },
302
+ {
303
+ "tagName": "span",
304
+ "attributes": {
305
+ "part": "tooltip"
306
+ },
307
+ "$switch": {
308
+ "$ref": "#/state/hasTip"
309
+ },
310
+ "cases": {
311
+ "true": {
312
+ "tagName": "jx-tooltip",
313
+ "attributes": {
314
+ "part": "tip",
315
+ "id": "${state.uid}-tip",
316
+ "for": "${state.uid}"
317
+ },
318
+ "children": [
319
+ {
320
+ "tagName": "span",
321
+ "attributes": {
322
+ "part": "tip-text"
323
+ },
324
+ "textContent": "${state.hint}"
325
+ }
326
+ ]
327
+ }
328
+ }
329
+ }
330
+ ]
331
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "JxTabPanel",
4
+ "tagName": "jx-tab-panel",
5
+ "observedAttributes": ["active", "labelledby"],
6
+ "state": {
7
+ "active": {
8
+ "type": "boolean",
9
+ "default": false,
10
+ "attribute": "active",
11
+ "description": "Whether this panel is the showing one. Every other panel is hidden, not absent, so the ids its tab names stay resolvable."
12
+ },
13
+ "labelledby": {
14
+ "type": "string",
15
+ "default": "",
16
+ "attribute": "labelledby",
17
+ "description": "The id of the tab that controls this panel, announced as aria-labelledby. Nothing checks the pairing: mint this id and the tab's aria-controls from one key."
18
+ },
19
+ "notActive": {
20
+ "$expression": {
21
+ "operator": "!",
22
+ "target": {
23
+ "$ref": "#/state/active"
24
+ }
25
+ }
26
+ }
27
+ },
28
+ "attributes": {
29
+ "role": "tabpanel",
30
+ "tabindex": "0",
31
+ "aria-labelledby": "${state.labelledby || null}",
32
+ "hidden": {
33
+ "$ref": "#/state/notActive"
34
+ }
35
+ },
36
+ "style": {
37
+ "display": "block",
38
+ "&[hidden]": {
39
+ "display": "none"
40
+ },
41
+ "boxSizing": "border-box",
42
+ "padding": "var(--jx-space-3)",
43
+ "fontFamily": "var(--jx-font-sans)",
44
+ "fontSize": "var(--jx-text-md)",
45
+ "lineHeight": "var(--jx-leading-md)",
46
+ "color": "var(--jx-fg)",
47
+ "outline": "none",
48
+ ":focus-visible": {
49
+ "outline": "var(--jx-focus-ring)",
50
+ "outlineOffset": "-2px"
51
+ }
52
+ },
53
+ "children": [
54
+ {
55
+ "tagName": "slot"
56
+ }
57
+ ]
58
+ }