use-wc 1.0.0-pre.82 → 1.0.0-pre.83
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/custom-elements.json +71 -71
- package/dist/design-system.css +262 -16
- package/dist/docs/use-control-set.md +15 -1
- package/dist/tokens.css +23 -0
- package/package.json +1 -1
- package/vscode.html-custom-data.json +13 -13
package/custom-elements.json
CHANGED
|
@@ -89,76 +89,6 @@
|
|
|
89
89
|
}
|
|
90
90
|
]
|
|
91
91
|
},
|
|
92
|
-
{
|
|
93
|
-
"kind": "javascript-module",
|
|
94
|
-
"path": "src/elements/use-avatar/use-avatar.ts",
|
|
95
|
-
"declarations": [
|
|
96
|
-
{
|
|
97
|
-
"kind": "class",
|
|
98
|
-
"description": "`use-avatar` renders a small, fixed-size, clipped container for a person or entity's\nlikeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a\ngenerated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);\nwhatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,\n`use-avatar` falls back to initials derived from the `name` attribute.\n\n```html\n<use-avatar><img src=\"ada.jpg\" alt=\"\" /></use-avatar>\n<use-avatar name=\"Riley Quinn\"></use-avatar>\n<use-avatar><svg viewBox=\"0 0 32 32\">…</svg></use-avatar>\n```\n\nSize it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —\nfrom a stylesheet, a style attribute, or the design system's theme layer. The element takes no\ncustom properties of its own: it is a query container, so the initials scale from whatever box\nit ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.\n\nThe element clips its content but gives it no shape of its own — that is the theme's, through\nthe affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in\n`theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the\nothers.\n\nThe element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the\ninitials fallback is plain text in the accessibility tree — an avatar is decorative beside a\nname far more often than it is the name itself, so labelling it here would mean announcing\nthat name twice.",
|
|
99
|
-
"name": "UseAvatar",
|
|
100
|
-
"cssParts": [
|
|
101
|
-
{
|
|
102
|
-
"description": "The span that renders the `name` fallback.",
|
|
103
|
-
"name": "initials"
|
|
104
|
-
}
|
|
105
|
-
],
|
|
106
|
-
"slots": [
|
|
107
|
-
{
|
|
108
|
-
"description": "The avatar's content: an `<img>`/`<picture>`, an `<svg>`, or arbitrary markup. Left empty, the `name` attribute's initials are shown instead, as the slot's own fallback. A photo fills the frame and crops; anything else keeps its own size, capped at the frame. Give an `<svg>` a `width`/`height` — without one it defaults to filling the box, and a rounded shape will clip its corners.",
|
|
109
|
-
"name": ""
|
|
110
|
-
}
|
|
111
|
-
],
|
|
112
|
-
"members": [
|
|
113
|
-
{
|
|
114
|
-
"kind": "field",
|
|
115
|
-
"name": "name",
|
|
116
|
-
"type": {
|
|
117
|
-
"text": "string"
|
|
118
|
-
},
|
|
119
|
-
"default": "\"\"",
|
|
120
|
-
"attribute": "name",
|
|
121
|
-
"reflects": true
|
|
122
|
-
}
|
|
123
|
-
],
|
|
124
|
-
"attributes": [
|
|
125
|
-
{
|
|
126
|
-
"description": "The full name, used for the initials fallback (first + last whitespace-separated token, uppercased) when the slot is empty.",
|
|
127
|
-
"name": "name",
|
|
128
|
-
"type": {
|
|
129
|
-
"text": "string"
|
|
130
|
-
},
|
|
131
|
-
"default": "\"\"",
|
|
132
|
-
"fieldName": "name"
|
|
133
|
-
}
|
|
134
|
-
],
|
|
135
|
-
"superclass": {
|
|
136
|
-
"name": "LitElement",
|
|
137
|
-
"package": "lit"
|
|
138
|
-
},
|
|
139
|
-
"tagName": "use-avatar",
|
|
140
|
-
"customElement": true
|
|
141
|
-
}
|
|
142
|
-
],
|
|
143
|
-
"exports": [
|
|
144
|
-
{
|
|
145
|
-
"kind": "js",
|
|
146
|
-
"name": "UseAvatar",
|
|
147
|
-
"declaration": {
|
|
148
|
-
"name": "UseAvatar",
|
|
149
|
-
"module": "src/elements/use-avatar/use-avatar.ts"
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"kind": "custom-element-definition",
|
|
154
|
-
"name": "use-avatar",
|
|
155
|
-
"declaration": {
|
|
156
|
-
"name": "UseAvatar",
|
|
157
|
-
"module": "src/elements/use-avatar/use-avatar.ts"
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
},
|
|
162
92
|
{
|
|
163
93
|
"kind": "javascript-module",
|
|
164
94
|
"path": "src/elements/use-badge/use-badge.ts",
|
|
@@ -302,6 +232,76 @@
|
|
|
302
232
|
}
|
|
303
233
|
]
|
|
304
234
|
},
|
|
235
|
+
{
|
|
236
|
+
"kind": "javascript-module",
|
|
237
|
+
"path": "src/elements/use-avatar/use-avatar.ts",
|
|
238
|
+
"declarations": [
|
|
239
|
+
{
|
|
240
|
+
"kind": "class",
|
|
241
|
+
"description": "`use-avatar` renders a small, fixed-size, clipped container for a person or entity's\nlikeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a\ngenerated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);\nwhatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,\n`use-avatar` falls back to initials derived from the `name` attribute.\n\n```html\n<use-avatar><img src=\"ada.jpg\" alt=\"\" /></use-avatar>\n<use-avatar name=\"Riley Quinn\"></use-avatar>\n<use-avatar><svg viewBox=\"0 0 32 32\">…</svg></use-avatar>\n```\n\nSize it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —\nfrom a stylesheet, a style attribute, or the design system's theme layer. The element takes no\ncustom properties of its own: it is a query container, so the initials scale from whatever box\nit ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.\n\nThe element clips its content but gives it no shape of its own — that is the theme's, through\nthe affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in\n`theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the\nothers.\n\nThe element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the\ninitials fallback is plain text in the accessibility tree — an avatar is decorative beside a\nname far more often than it is the name itself, so labelling it here would mean announcing\nthat name twice.",
|
|
242
|
+
"name": "UseAvatar",
|
|
243
|
+
"cssParts": [
|
|
244
|
+
{
|
|
245
|
+
"description": "The span that renders the `name` fallback.",
|
|
246
|
+
"name": "initials"
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
"slots": [
|
|
250
|
+
{
|
|
251
|
+
"description": "The avatar's content: an `<img>`/`<picture>`, an `<svg>`, or arbitrary markup. Left empty, the `name` attribute's initials are shown instead, as the slot's own fallback. A photo fills the frame and crops; anything else keeps its own size, capped at the frame. Give an `<svg>` a `width`/`height` — without one it defaults to filling the box, and a rounded shape will clip its corners.",
|
|
252
|
+
"name": ""
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
"members": [
|
|
256
|
+
{
|
|
257
|
+
"kind": "field",
|
|
258
|
+
"name": "name",
|
|
259
|
+
"type": {
|
|
260
|
+
"text": "string"
|
|
261
|
+
},
|
|
262
|
+
"default": "\"\"",
|
|
263
|
+
"attribute": "name",
|
|
264
|
+
"reflects": true
|
|
265
|
+
}
|
|
266
|
+
],
|
|
267
|
+
"attributes": [
|
|
268
|
+
{
|
|
269
|
+
"description": "The full name, used for the initials fallback (first + last whitespace-separated token, uppercased) when the slot is empty.",
|
|
270
|
+
"name": "name",
|
|
271
|
+
"type": {
|
|
272
|
+
"text": "string"
|
|
273
|
+
},
|
|
274
|
+
"default": "\"\"",
|
|
275
|
+
"fieldName": "name"
|
|
276
|
+
}
|
|
277
|
+
],
|
|
278
|
+
"superclass": {
|
|
279
|
+
"name": "LitElement",
|
|
280
|
+
"package": "lit"
|
|
281
|
+
},
|
|
282
|
+
"tagName": "use-avatar",
|
|
283
|
+
"customElement": true
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
"exports": [
|
|
287
|
+
{
|
|
288
|
+
"kind": "js",
|
|
289
|
+
"name": "UseAvatar",
|
|
290
|
+
"declaration": {
|
|
291
|
+
"name": "UseAvatar",
|
|
292
|
+
"module": "src/elements/use-avatar/use-avatar.ts"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"kind": "custom-element-definition",
|
|
297
|
+
"name": "use-avatar",
|
|
298
|
+
"declaration": {
|
|
299
|
+
"name": "UseAvatar",
|
|
300
|
+
"module": "src/elements/use-avatar/use-avatar.ts"
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
]
|
|
304
|
+
},
|
|
305
305
|
{
|
|
306
306
|
"kind": "javascript-module",
|
|
307
307
|
"path": "src/elements/use-calendar-base/use-calendar-base.ts",
|
|
@@ -843,7 +843,7 @@
|
|
|
843
843
|
"declarations": [
|
|
844
844
|
{
|
|
845
845
|
"kind": "class",
|
|
846
|
-
"description": "Groups adjacent controls — buttons and text-style inputs alike — into one visual unit: shared\nborders between touching children, rounded corners only on the two outer ends, and a hovered\nor focused child's border lifted above its neighbors so the whole border reads clearly.\n\n`use-control-set` renders no shadow DOM and no template of its own — it exists only as a\ndedicated tag for `theme/control-set.css` to style, the same way `use-layout` is a bare\nprimitive rather than a specific look. A classic split button is a text button followed by an\nicon-only trigger for a `use-menu`:\n\n```html\n<use-control-set>\n <button type=\"button\">Save</button>\n <button type=\"button\" popovertarget=\"save-options\" aria-label=\"More save options\">\n <use-caret></use-caret>\n </button>\n</use-control-set>\n<use-menu id=\"save-options\" aria-label=\"More save options\">\n <button role=\"menuitem\">Save as…</button>\n</use-menu>\n```\n\nA search box with an attached submit button follows the same shape, mixing a text input with a\nbutton:\n\n```html\n<use-control-set>\n <input type=\"search\" placeholder=\"Search\" />\n <button type=\"submit\">Go</button>\n</use-control-set>\n```\n\nA child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a\ncheckbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing\n`.appearance-input` — see `theme/control-set.css` for exactly which selectors read which\nradius/border tokens.\n\nHow the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`\n(default: a negative overlap equal to the child's own border, for a seamless merged line) and\n`--usewc-effect-control-set-border-radius-sequential` (default: `0`, for square touching\ncorners) can both be overridden — a positive gap and a small radius reads as a looser, softer\nset instead of a fused one.",
|
|
846
|
+
"description": "Groups adjacent controls — buttons and text-style inputs alike — into one visual unit: shared\nborders between touching children, rounded corners only on the two outer ends, and a hovered\nor focused child's border lifted above its neighbors so the whole border reads clearly.\n\n`use-control-set` renders no shadow DOM and no template of its own — it exists only as a\ndedicated tag for `theme/control-set.css` to style, the same way `use-layout` is a bare\nprimitive rather than a specific look. A classic split button is a text button followed by an\nicon-only trigger for a `use-menu`:\n\n```html\n<use-control-set>\n <button type=\"button\">Save</button>\n <button type=\"button\" popovertarget=\"save-options\" aria-label=\"More save options\">\n <use-caret></use-caret>\n </button>\n</use-control-set>\n<use-menu id=\"save-options\" aria-label=\"More save options\">\n <button role=\"menuitem\">Save as…</button>\n</use-menu>\n```\n\nA search box with an attached submit button follows the same shape, mixing a text input with a\nbutton:\n\n```html\n<use-control-set>\n <input type=\"search\" placeholder=\"Search\" />\n <button type=\"submit\">Go</button>\n</use-control-set>\n```\n\nA child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a\ncheckbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing\n`.appearance-input` — see `theme/control-set.css` for exactly which selectors read which\nradius/border tokens. A plain `span` renders as a static text cell between controls.\n\nPagination follows the same shape, with `a.appearance-button` links and `aria-current=\"page\"`\nholding the current page in its pressed look:\n\n```html\n<nav aria-label=\"Pagination\">\n <use-control-set>\n <a class=\"appearance-button\" href=\"?page=1\">1</a>\n <a class=\"appearance-button\" href=\"?page=2\" aria-current=\"page\">2</a>\n <span aria-hidden=\"true\">…</span>\n <a class=\"appearance-button\" href=\"?page=10\">10</a>\n </use-control-set>\n</nav>\n```\n\nHow the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`\n(default: a negative overlap equal to the child's own border, for a seamless merged line) and\n`--usewc-effect-control-set-border-radius-sequential` (default: `0`, for square touching\ncorners) can both be overridden — a positive gap and a small radius reads as a looser, softer\nset instead of a fused one.",
|
|
847
847
|
"name": "UseControlSet",
|
|
848
848
|
"slots": [
|
|
849
849
|
{
|
package/dist/design-system.css
CHANGED
|
@@ -370,22 +370,49 @@
|
|
|
370
370
|
text exactly here instead of staying a lighter tint of it. */
|
|
371
371
|
--usewc-local-link-decoration-opacity: 1;
|
|
372
372
|
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
373
375
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
376
|
+
/* `nav.breadcrumb` lays an `ol` of links out as a single wrapping trail. The separator is
|
|
377
|
+
generated content on every item after the first, reading its glyph from
|
|
378
|
+
`--usewc-effect-breadcrumb-separator` with empty alt text (`/ ""`), so assistive tech hears the
|
|
379
|
+
list structure rather than a run of slashes.
|
|
380
|
+
|
|
381
|
+
The current page is marked with `aria-current="page"` on its link. Rather than restyling
|
|
382
|
+
`color` directly, it swaps the link's own source tokens — the same approach `nav.sidebar` takes
|
|
383
|
+
in `link.css` — so every link state resolves to the document's ink instead of link blue. The
|
|
384
|
+
link's underline is already off here, since `link.css` treats every link inside a `nav` as
|
|
385
|
+
chrome. */
|
|
386
|
+
@layer use-theme.breadcrumb {
|
|
387
|
+
nav.breadcrumb > ol {
|
|
388
|
+
display: flex;
|
|
389
|
+
flex-wrap: wrap;
|
|
390
|
+
align-items: center;
|
|
391
|
+
gap: var(--usewc-layout-breadcrumb-gap);
|
|
392
|
+
margin: 0;
|
|
393
|
+
padding: 0;
|
|
394
|
+
list-style: none;
|
|
385
395
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
396
|
+
> li {
|
|
397
|
+
display: inline-flex;
|
|
398
|
+
align-items: center;
|
|
399
|
+
gap: var(--usewc-layout-breadcrumb-gap);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
> li + li::before {
|
|
403
|
+
content: var(--usewc-effect-breadcrumb-separator) / "";
|
|
404
|
+
color: var(--usewc-color-breadcrumb-separator);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
[aria-current="page"] {
|
|
408
|
+
--usewc-color-link-text-static: var(--usewc-color-breadcrumb-current-text);
|
|
409
|
+
--usewc-color-link-text-hover: var(--usewc-color-breadcrumb-current-text);
|
|
410
|
+
--usewc-color-link-text-active: var(--usewc-color-breadcrumb-current-text);
|
|
411
|
+
cursor: default;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
use-theme-escape & {
|
|
415
|
+
all: revert-layer;
|
|
389
416
|
}
|
|
390
417
|
}
|
|
391
418
|
}
|
|
@@ -655,6 +682,21 @@
|
|
|
655
682
|
--usewc-effect-button-box-shadow-active: none;
|
|
656
683
|
}
|
|
657
684
|
|
|
685
|
+
/* A current or pressed button holds its variant's own pressed look at rest and on hover — the
|
|
686
|
+
current page in a pagination `use-control-set`, or a toggle that's on. It comes after the
|
|
687
|
+
variant blocks so it re-points whichever `-active` values they set, rather than the base
|
|
688
|
+
ones. */
|
|
689
|
+
&:is([aria-current]:not([aria-current="false"]), [aria-pressed="true"]) {
|
|
690
|
+
--usewc-color-button-text-static: var(--usewc-color-button-text-active);
|
|
691
|
+
--usewc-color-button-background-static: var(--usewc-color-button-background-active);
|
|
692
|
+
--usewc-color-button-border-static: var(--usewc-color-button-border-active);
|
|
693
|
+
--usewc-color-button-text-hover: var(--usewc-color-button-text-active);
|
|
694
|
+
--usewc-color-button-background-hover: var(--usewc-color-button-background-active);
|
|
695
|
+
--usewc-color-button-border-hover: var(--usewc-color-button-border-active);
|
|
696
|
+
--usewc-effect-button-box-shadow-static: var(--usewc-effect-button-box-shadow-active);
|
|
697
|
+
--usewc-effect-button-box-shadow-hover: var(--usewc-effect-button-box-shadow-active);
|
|
698
|
+
}
|
|
699
|
+
|
|
658
700
|
&.extra-small {
|
|
659
701
|
--usewc-layout-button-padding-block: var(--usewc-layout-button-extra-small-padding-block);
|
|
660
702
|
--usewc-layout-button-padding-inline: var(--usewc-layout-button-extra-small-padding-inline);
|
|
@@ -752,6 +794,25 @@
|
|
|
752
794
|
all: revert-layer;
|
|
753
795
|
}
|
|
754
796
|
}
|
|
797
|
+
|
|
798
|
+
/* A plain `span` is a static text cell rather than a control — pagination's ellipsis, or a
|
|
799
|
+
unit beside an input. It borrows a base button's border, face, and inline padding so the
|
|
800
|
+
strip's outline stays unbroken through it, and stretches to its neighbors' height through
|
|
801
|
+
the container's default `align-items: stretch` instead of needing its own block padding. */
|
|
802
|
+
use-control-set > span:not([class*="appearance-"]) {
|
|
803
|
+
display: inline-flex;
|
|
804
|
+
align-items: center;
|
|
805
|
+
padding-inline: var(--usewc-layout-button-base-padding-inline);
|
|
806
|
+
font-size: var(--usewc-font-button-base-size);
|
|
807
|
+
color: var(--usewc-color-document-text-muted);
|
|
808
|
+
background: var(--usewc-color-button-base-background-static);
|
|
809
|
+
border: var(--usewc-layout-button-border) var(--usewc-effect-button-border-style)
|
|
810
|
+
var(--usewc-color-button-base-border-static);
|
|
811
|
+
|
|
812
|
+
use-theme-escape & {
|
|
813
|
+
all: revert-layer;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
755
816
|
}
|
|
756
817
|
|
|
757
818
|
@layer use-theme.code {
|
|
@@ -873,8 +934,8 @@
|
|
|
873
934
|
mask-position: center;
|
|
874
935
|
}
|
|
875
936
|
|
|
876
|
-
&:is([open], :open) summary:not([class*="appearance-"])::before,
|
|
877
|
-
&:is([open], :open) summary.appearance-button::before {
|
|
937
|
+
&:is([open], :open) > summary:not([class*="appearance-"])::before,
|
|
938
|
+
&:is([open], :open) > summary.appearance-button::before {
|
|
878
939
|
mask-image: var(--usewc-effect-dropdown-trigger-icon-mask-image, none);
|
|
879
940
|
}
|
|
880
941
|
|
|
@@ -896,6 +957,191 @@
|
|
|
896
957
|
}
|
|
897
958
|
}
|
|
898
959
|
|
|
960
|
+
/* `nav.sidebar` turns every link inside it, at any depth, into a padded row with a hover
|
|
961
|
+
background — a nested `a` would be invalid HTML anyway, so matching descendants can't reach
|
|
962
|
+
anything that isn't a nav item. It lives in its own layer after `link.css` and `details.css` so
|
|
963
|
+
its plain selectors outrank both without a specificity fight.
|
|
964
|
+
|
|
965
|
+
Links keep `link.css`'s own state machinery: this swaps the source tokens it reads through
|
|
966
|
+
(`--usewc-color-link-text-static`/`-hover`/`-active`) rather than setting `color` directly, so
|
|
967
|
+
every existing state recolors at once. `aria-current="page"` swaps the same tokens again for the
|
|
968
|
+
current page.
|
|
969
|
+
|
|
970
|
+
A `details` inside the sidebar is a collapsible group: its `summary` renders as the same kind of
|
|
971
|
+
row, keeping `details.css`'s caret. When the summary starts with an icon (`svg` or `.icon`), the
|
|
972
|
+
icon shows at rest and the caret takes its place on hover or keyboard focus — both share
|
|
973
|
+
`--usewc-layout-sidebar-item-icon-size`, so the swap never shifts the label.
|
|
974
|
+
|
|
975
|
+
Everything after the summary hangs off a guide line centered under the summary's icon column,
|
|
976
|
+
drawn once on the group's `::details-content` rather than on each row, so the rows' own rounded
|
|
977
|
+
corners never bend it, and nested rows get just enough inline padding to land their text under
|
|
978
|
+
the summary's text.
|
|
979
|
+
Rows below the top level all share one derived padding, which is why a group nested two deep
|
|
980
|
+
reads its offset from that padding instead of the top-level one.
|
|
981
|
+
|
|
982
|
+
Rows can sit directly in the nav or in `ul`/`ol` lists — lists are recommended, since assistive
|
|
983
|
+
tech announces their item count — and lists lose their bullets and indentation here so both
|
|
984
|
+
shapes render the same. That's also why a top-level group is found as a `details` with no
|
|
985
|
+
`details` ancestor rather than as a direct child of the nav.
|
|
986
|
+
|
|
987
|
+
Headings that are direct children of the nav are group labels. Only direct children count,
|
|
988
|
+
since a sidebar row can hold its own heading inside a nested `use-pattern`. */
|
|
989
|
+
@layer use-theme.sidebar {
|
|
990
|
+
nav.sidebar {
|
|
991
|
+
--usewc-local-sidebar-nested-padding-inline-start: calc(
|
|
992
|
+
var(--usewc-layout-sidebar-item-icon-size) / 2 + var(--usewc-layout-sidebar-item-gap) -
|
|
993
|
+
var(--usewc-layout-sidebar-nested-guide-width) / 2 - var(--usewc-layout-sidebar-nested-guide-gap)
|
|
994
|
+
);
|
|
995
|
+
|
|
996
|
+
:is(a, summary):not([class*="appearance-"]) {
|
|
997
|
+
display: flex;
|
|
998
|
+
align-items: center;
|
|
999
|
+
gap: var(--usewc-layout-sidebar-item-gap);
|
|
1000
|
+
padding: var(--usewc-layout-sidebar-item-padding-block) var(--usewc-layout-sidebar-item-padding-inline);
|
|
1001
|
+
border-radius: var(--usewc-effect-sidebar-item-border-radius);
|
|
1002
|
+
|
|
1003
|
+
&:is(:hover, :focus-visible) {
|
|
1004
|
+
background-color: var(--usewc-color-sidebar-item-background-hover);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
> :is(svg, .icon):first-child {
|
|
1008
|
+
display: inline-flex;
|
|
1009
|
+
align-items: center;
|
|
1010
|
+
justify-content: center;
|
|
1011
|
+
flex: none;
|
|
1012
|
+
inline-size: var(--usewc-layout-sidebar-item-icon-size);
|
|
1013
|
+
block-size: var(--usewc-layout-sidebar-item-icon-size);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
> :only-child:not(svg, .icon) {
|
|
1017
|
+
flex: auto;
|
|
1018
|
+
min-inline-size: 0;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
use-theme-escape & {
|
|
1022
|
+
all: revert-layer;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
a:not([class*="appearance-"]) {
|
|
1027
|
+
--usewc-color-link-text-static: var(--usewc-color-sidebar-item-text-static);
|
|
1028
|
+
--usewc-color-link-text-hover: var(--usewc-color-sidebar-item-text-hover);
|
|
1029
|
+
--usewc-color-link-text-active: var(--usewc-color-sidebar-item-text-active);
|
|
1030
|
+
|
|
1031
|
+
&[aria-current="page"] {
|
|
1032
|
+
--usewc-color-link-text-static: var(--usewc-color-sidebar-item-text-current);
|
|
1033
|
+
--usewc-color-link-text-hover: var(--usewc-color-sidebar-item-text-current);
|
|
1034
|
+
--usewc-color-link-text-active: var(--usewc-color-sidebar-item-text-current);
|
|
1035
|
+
background-color: var(--usewc-color-sidebar-item-background-current);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
summary:not([class*="appearance-"]) {
|
|
1040
|
+
color: var(--usewc-color-sidebar-item-text-static);
|
|
1041
|
+
cursor: pointer;
|
|
1042
|
+
outline-offset: var(--usewc-effect-outline-offset);
|
|
1043
|
+
|
|
1044
|
+
&:hover {
|
|
1045
|
+
color: var(--usewc-color-sidebar-item-text-hover);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
&:active {
|
|
1049
|
+
color: var(--usewc-color-sidebar-item-text-active);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
&:focus-visible {
|
|
1053
|
+
outline: var(--usewc-effect-outline-size) var(--usewc-effect-outline-style) var(--usewc-color-outline);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
&::before {
|
|
1057
|
+
flex: none;
|
|
1058
|
+
inline-size: var(--usewc-layout-sidebar-item-icon-size);
|
|
1059
|
+
block-size: var(--usewc-layout-sidebar-item-icon-size);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
&:has(> :is(svg, .icon):first-child) {
|
|
1063
|
+
&::before {
|
|
1064
|
+
display: none;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
&:is(:hover, :focus-visible) {
|
|
1068
|
+
&::before {
|
|
1069
|
+
display: inline-block;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
> :is(svg, .icon):first-child {
|
|
1073
|
+
display: none;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
use-theme-escape &,
|
|
1079
|
+
use-theme-escape &::before {
|
|
1080
|
+
all: revert-layer;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
:is(ul, ol) {
|
|
1085
|
+
margin: 0;
|
|
1086
|
+
padding: 0;
|
|
1087
|
+
list-style: none;
|
|
1088
|
+
|
|
1089
|
+
use-theme-escape & {
|
|
1090
|
+
all: revert-layer;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
details:has(a[aria-current="page"]) > summary:not([class*="appearance-"]) {
|
|
1095
|
+
color: var(--usewc-color-sidebar-item-text-current);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
details::details-content {
|
|
1099
|
+
padding-inline-start: var(--usewc-layout-sidebar-nested-guide-gap);
|
|
1100
|
+
border-inline-start: var(--usewc-layout-sidebar-nested-guide-width) solid var(--usewc-color-sidebar-nested-guide);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
details:not(details details)::details-content {
|
|
1104
|
+
margin-inline-start: calc(
|
|
1105
|
+
var(--usewc-layout-sidebar-item-padding-inline) + var(--usewc-layout-sidebar-item-icon-size) / 2 -
|
|
1106
|
+
var(--usewc-layout-sidebar-nested-guide-width) / 2
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
details details::details-content {
|
|
1111
|
+
margin-inline-start: calc(
|
|
1112
|
+
var(--usewc-local-sidebar-nested-padding-inline-start) + var(--usewc-layout-sidebar-item-icon-size) / 2 -
|
|
1113
|
+
var(--usewc-layout-sidebar-nested-guide-width) / 2
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
use-theme-escape & details::details-content {
|
|
1118
|
+
all: revert-layer;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
details > a:not([class*="appearance-"]),
|
|
1122
|
+
details > :not(summary) :is(a, summary):not([class*="appearance-"]) {
|
|
1123
|
+
padding-inline-start: var(--usewc-local-sidebar-nested-padding-inline-start);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
> :is(h1, h2, h3, h4, h5, h6) {
|
|
1127
|
+
margin: var(--usewc-layout-sidebar-group-label-spacing) 0 var(--usewc-space-4);
|
|
1128
|
+
padding-inline: var(--usewc-layout-sidebar-item-padding-inline);
|
|
1129
|
+
font-size: var(--usewc-font-sidebar-group-label-size);
|
|
1130
|
+
font-weight: var(--usewc-font-sidebar-group-label-weight);
|
|
1131
|
+
line-height: var(--usewc-layout-sidebar-group-label-line-height);
|
|
1132
|
+
color: var(--usewc-color-sidebar-group-label-text);
|
|
1133
|
+
|
|
1134
|
+
&:first-child {
|
|
1135
|
+
margin-block-start: 0;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
use-theme-escape & {
|
|
1139
|
+
all: revert-layer;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
899
1145
|
@layer use-theme.segment-input {
|
|
900
1146
|
:is(use-datetime-input, use-date-input, use-time-input, use-duration-input):not(.appearance-native) {
|
|
901
1147
|
display: inline-flex;
|
|
@@ -34,7 +34,21 @@ button:
|
|
|
34
34
|
A child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a
|
|
35
35
|
checkbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing
|
|
36
36
|
`.appearance-input` — see `theme/control-set.css` for exactly which selectors read which
|
|
37
|
-
radius/border tokens.
|
|
37
|
+
radius/border tokens. A plain `span` renders as a static text cell between controls.
|
|
38
|
+
|
|
39
|
+
Pagination follows the same shape, with `a.appearance-button` links and `aria-current="page"`
|
|
40
|
+
holding the current page in its pressed look:
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<nav aria-label="Pagination">
|
|
44
|
+
<use-control-set>
|
|
45
|
+
<a class="appearance-button" href="?page=1">1</a>
|
|
46
|
+
<a class="appearance-button" href="?page=2" aria-current="page">2</a>
|
|
47
|
+
<span aria-hidden="true">…</span>
|
|
48
|
+
<a class="appearance-button" href="?page=10">10</a>
|
|
49
|
+
</use-control-set>
|
|
50
|
+
</nav>
|
|
51
|
+
```
|
|
38
52
|
|
|
39
53
|
How the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`
|
|
40
54
|
(default: a negative overlap equal to the child's own border, for a seamless merged line) and
|
package/dist/tokens.css
CHANGED
|
@@ -222,6 +222,29 @@
|
|
|
222
222
|
--usewc-effect-sidebar-item-border-radius: var(--usewc-effect-border-radius-6);
|
|
223
223
|
--usewc-layout-sidebar-item-padding-block: var(--usewc-space-8);
|
|
224
224
|
--usewc-layout-sidebar-item-padding-inline: var(--usewc-space-12);
|
|
225
|
+
--usewc-color-sidebar-item-text-current: var(--usewc-color-brand-primary);
|
|
226
|
+
--usewc-color-sidebar-item-background-current: oklch(from var(--usewc-color-brand-primary) l c h / 0.1);
|
|
227
|
+
/* A leading icon and the group caret share one box, so the caret can stand in for the icon on
|
|
228
|
+
hover without shifting the label, and one indent lines nested text up under either. */
|
|
229
|
+
--usewc-layout-sidebar-item-icon-size: 1em;
|
|
230
|
+
--usewc-layout-sidebar-item-gap: var(--usewc-space-8);
|
|
231
|
+
/* The guide is a tint of the document's own ink rather than a fixed gray, so it stays equally
|
|
232
|
+
faint against either theme's background without a dark-mode override. */
|
|
233
|
+
--usewc-color-sidebar-nested-guide: oklch(from var(--usewc-color-document-text) l c h / 0.15);
|
|
234
|
+
--usewc-layout-sidebar-nested-guide-width: var(--usewc-space-1);
|
|
235
|
+
--usewc-layout-sidebar-nested-guide-gap: var(--usewc-space-4);
|
|
236
|
+
--usewc-color-sidebar-group-label-text: var(--usewc-color-document-text-muted);
|
|
237
|
+
--usewc-font-sidebar-group-label-size: var(--usewc-font-size-12);
|
|
238
|
+
--usewc-font-sidebar-group-label-weight: var(--usewc-font-weight-semibold);
|
|
239
|
+
--usewc-layout-sidebar-group-label-line-height: var(--usewc-line-height-18);
|
|
240
|
+
--usewc-layout-sidebar-group-label-spacing: var(--usewc-space-16);
|
|
241
|
+
/* - Breadcrumb */
|
|
242
|
+
/* The separator is decoration rather than meaning, the same way a link's underline is, so it
|
|
243
|
+
lives under `effect` — `breadcrumb.css` gives it empty alt text so it's never announced. */
|
|
244
|
+
--usewc-effect-breadcrumb-separator: "/";
|
|
245
|
+
--usewc-color-breadcrumb-separator: var(--usewc-color-document-text-muted);
|
|
246
|
+
--usewc-color-breadcrumb-current-text: var(--usewc-color-document-text);
|
|
247
|
+
--usewc-layout-breadcrumb-gap: var(--usewc-space-8);
|
|
225
248
|
|
|
226
249
|
/* Form */
|
|
227
250
|
/* - Color */
|
package/package.json
CHANGED
|
@@ -19,18 +19,6 @@
|
|
|
19
19
|
],
|
|
20
20
|
"references": []
|
|
21
21
|
},
|
|
22
|
-
{
|
|
23
|
-
"name": "use-avatar",
|
|
24
|
-
"description": "`use-avatar` renders a small, fixed-size, clipped container for a person or entity's\nlikeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a\ngenerated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);\nwhatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,\n`use-avatar` falls back to initials derived from the `name` attribute.\n\n```html\n<use-avatar><img src=\"ada.jpg\" alt=\"\" /></use-avatar>\n<use-avatar name=\"Riley Quinn\"></use-avatar>\n<use-avatar><svg viewBox=\"0 0 32 32\">…</svg></use-avatar>\n```\n\nSize it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —\nfrom a stylesheet, a style attribute, or the design system's theme layer. The element takes no\ncustom properties of its own: it is a query container, so the initials scale from whatever box\nit ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.\n\nThe element clips its content but gives it no shape of its own — that is the theme's, through\nthe affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in\n`theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the\nothers.\n\nThe element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the\ninitials fallback is plain text in the accessibility tree — an avatar is decorative beside a\nname far more often than it is the name itself, so labelling it here would mean announcing\nthat name twice.\n---\n\n\n### **Slots:**\n - _default_ - The avatar's content: an `<img>`/`<picture>`, an `<svg>`, or arbitrary markup. Left empty, the `name` attribute's initials are shown instead, as the slot's own fallback. A photo fills the frame and crops; anything else keeps its own size, capped at the frame. Give an `<svg>` a `width`/`height` — without one it defaults to filling the box, and a rounded shape will clip its corners.\n\n### **CSS Parts:**\n - **initials** - The span that renders the `name` fallback.",
|
|
25
|
-
"attributes": [
|
|
26
|
-
{
|
|
27
|
-
"name": "name",
|
|
28
|
-
"description": "The full name, used for the initials fallback (first + last whitespace-separated token, uppercased) when the slot is empty.",
|
|
29
|
-
"values": []
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
"references": []
|
|
33
|
-
},
|
|
34
22
|
{
|
|
35
23
|
"name": "use-badge",
|
|
36
24
|
"description": "`use-badge` renders a small indicator anchored to another element's corner, using\n[CSS anchor positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning)\ninstead of the classic `position: absolute` + negative-offset trick. This lets the badge live\nanywhere in the DOM rather than being a child of the element it decorates. A badge's shape,\ncolor, and positioning ship built in — reading from the design system's tokens when\n`tokens.css` is loaded, and falling back to sensible defaults otherwise — so no theme is\nrequired to get a working, visible badge.\n\nPoint a badge at its target with the `anchortarget` attribute, set to the target's `id`\n(named to avoid colliding with the `anchor` content attribute HTML is gaining natively):\n\n```html\n<button type=\"button\" id=\"inbox\">Inbox</button>\n<use-badge anchortarget=\"inbox\">99+</use-badge>\n```\n\nThe badge and its anchor must live in the same DOM tree — a badge cannot reach an anchor\ninside another component's shadow root, and an anchor's `anchor-name` set inside a shadow\ntree's stylesheet is not visible here. No positioned ancestor or shared containing block is\nrequired: anchor positioning resolves the badge's location straight from the anchor's own\ngeometry, so the badge can sit anywhere else in the DOM tree.\n\nWithout a resolved anchor — `anchortarget` unset, pointing at a missing id, or `anchorElement`\nnever assigned — the badge has no `:state(anchored)` and renders as a plain inline chip in\nnormal document flow, still using the same color/shape styling.\n\nSome components render their host as `display: contents`, which has no box of its own for CSS\nanchor positioning to resolve against. If the anchor computes a non-empty `--usewc-anchor-name`\ncustom property, the badge uses that dashed-ident as its `position-anchor` directly instead of\ngenerating and writing its own onto the anchor — letting a component publish the name of a\nreal, box-generating part of itself (already established for its own purposes) for badges to\ntarget instead of its host, even though that part lives inside the component's own shadow root.\nThis mechanism is shared with `use-menu`/`use-anchored` via `AnchorController`; components\nwithout a `display: contents` host don't need to publish anything.\n\n**Known Firefox limitation:** anchoring across a shadow root boundary this way — the case\n`--usewc-anchor-name` exists for — is mispositioned in Firefox as of this writing. Verified\ndirectly: `anchor()`'s logical `start`/`end` keywords resolve backwards on both axes\nspecifically for a cross-shadow-root anchor reference, in Firefox only — the same anchor()\ncalls resolve correctly for a same-tree anchor in Firefox, and cross-shadow anchoring resolves\ncorrectly in Chromium and Safari. A badge anchored to a plain element (button, input, anything\nthat isn't itself relying on this escape hatch) is unaffected in every engine, including\nFirefox.\n\n## Side effects\n\nThe badge is a sibling of its anchor rather than a child, so **as a side effect, a badge\nmutates its anchor element**: it appends its own id to the anchor's `aria-describedby`\n(preserving any ids already there, the same way `anchor-name` is appended rather than\nreplaced) to keep its content connected to the anchor for assistive technology. This means a\nbadge's content, or its `aria-label` when set, is announced as part of interacting with the\nanchor, e.g. \"Inbox button, 3\". A `dot` badge has no content of its own, so set `aria-label`\ndirectly on `<use-badge>` for a meaningful description (e.g. `aria-label=\"3 unread messages\"`);\nwithout one, the description contributes nothing and the anchor announces as before.\n\nAvoid adding `aria-hidden` to `<use-badge>` if you rely on this: while the description\ncomputation is specified to still read a hidden node when it's the direct target of\n`aria-describedby`, support for that specific case is inconsistent across browsers and screen\nreaders.\n\nSet `options=\"noaria\"` to opt a badge out of this and leave the anchor's `aria-describedby`\nuntouched, e.g. when the anchor already documents the badge's meaning some other way.\n---\n\n\n### **Slots:**\n - _default_ - Badge content, e.g. a count or short label. Ignored when `dot` is set.",
|
|
@@ -63,6 +51,18 @@
|
|
|
63
51
|
],
|
|
64
52
|
"references": []
|
|
65
53
|
},
|
|
54
|
+
{
|
|
55
|
+
"name": "use-avatar",
|
|
56
|
+
"description": "`use-avatar` renders a small, fixed-size, clipped container for a person or entity's\nlikeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a\ngenerated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);\nwhatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,\n`use-avatar` falls back to initials derived from the `name` attribute.\n\n```html\n<use-avatar><img src=\"ada.jpg\" alt=\"\" /></use-avatar>\n<use-avatar name=\"Riley Quinn\"></use-avatar>\n<use-avatar><svg viewBox=\"0 0 32 32\">…</svg></use-avatar>\n```\n\nSize it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —\nfrom a stylesheet, a style attribute, or the design system's theme layer. The element takes no\ncustom properties of its own: it is a query container, so the initials scale from whatever box\nit ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.\n\nThe element clips its content but gives it no shape of its own — that is the theme's, through\nthe affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in\n`theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the\nothers.\n\nThe element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the\ninitials fallback is plain text in the accessibility tree — an avatar is decorative beside a\nname far more often than it is the name itself, so labelling it here would mean announcing\nthat name twice.\n---\n\n\n### **Slots:**\n - _default_ - The avatar's content: an `<img>`/`<picture>`, an `<svg>`, or arbitrary markup. Left empty, the `name` attribute's initials are shown instead, as the slot's own fallback. A photo fills the frame and crops; anything else keeps its own size, capped at the frame. Give an `<svg>` a `width`/`height` — without one it defaults to filling the box, and a rounded shape will clip its corners.\n\n### **CSS Parts:**\n - **initials** - The span that renders the `name` fallback.",
|
|
57
|
+
"attributes": [
|
|
58
|
+
{
|
|
59
|
+
"name": "name",
|
|
60
|
+
"description": "The full name, used for the initials fallback (first + last whitespace-separated token, uppercased) when the slot is empty.",
|
|
61
|
+
"values": []
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"references": []
|
|
65
|
+
},
|
|
66
66
|
{
|
|
67
67
|
"name": "use-calendarday",
|
|
68
68
|
"description": "A helper component for customizing specific days within `use-calendar`.\nContent placed inside this element will replace the default day number display.\n---\n\n\n### **Slots:**\n - **default** - slot for custom day content (replaces the day number)",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
"name": "use-control-set",
|
|
80
|
-
"description": "Groups adjacent controls — buttons and text-style inputs alike — into one visual unit: shared\nborders between touching children, rounded corners only on the two outer ends, and a hovered\nor focused child's border lifted above its neighbors so the whole border reads clearly.\n\n`use-control-set` renders no shadow DOM and no template of its own — it exists only as a\ndedicated tag for `theme/control-set.css` to style, the same way `use-layout` is a bare\nprimitive rather than a specific look. A classic split button is a text button followed by an\nicon-only trigger for a `use-menu`:\n\n```html\n<use-control-set>\n <button type=\"button\">Save</button>\n <button type=\"button\" popovertarget=\"save-options\" aria-label=\"More save options\">\n <use-caret></use-caret>\n </button>\n</use-control-set>\n<use-menu id=\"save-options\" aria-label=\"More save options\">\n <button role=\"menuitem\">Save as…</button>\n</use-menu>\n```\n\nA search box with an attached submit button follows the same shape, mixing a text input with a\nbutton:\n\n```html\n<use-control-set>\n <input type=\"search\" placeholder=\"Search\" />\n <button type=\"submit\">Go</button>\n</use-control-set>\n```\n\nA child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a\ncheckbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing\n`.appearance-input` — see `theme/control-set.css` for exactly which selectors read which\nradius/border tokens.\n\nHow the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`\n(default: a negative overlap equal to the child's own border, for a seamless merged line) and\n`--usewc-effect-control-set-border-radius-sequential` (default: `0`, for square touching\ncorners) can both be overridden — a positive gap and a small radius reads as a looser, softer\nset instead of a fused one.\n---\n\n\n### **Slots:**\n - _default_ - The grouped controls.",
|
|
80
|
+
"description": "Groups adjacent controls — buttons and text-style inputs alike — into one visual unit: shared\nborders between touching children, rounded corners only on the two outer ends, and a hovered\nor focused child's border lifted above its neighbors so the whole border reads clearly.\n\n`use-control-set` renders no shadow DOM and no template of its own — it exists only as a\ndedicated tag for `theme/control-set.css` to style, the same way `use-layout` is a bare\nprimitive rather than a specific look. A classic split button is a text button followed by an\nicon-only trigger for a `use-menu`:\n\n```html\n<use-control-set>\n <button type=\"button\">Save</button>\n <button type=\"button\" popovertarget=\"save-options\" aria-label=\"More save options\">\n <use-caret></use-caret>\n </button>\n</use-control-set>\n<use-menu id=\"save-options\" aria-label=\"More save options\">\n <button role=\"menuitem\">Save as…</button>\n</use-menu>\n```\n\nA search box with an attached submit button follows the same shape, mixing a text input with a\nbutton:\n\n```html\n<use-control-set>\n <input type=\"search\" placeholder=\"Search\" />\n <button type=\"submit\">Go</button>\n</use-control-set>\n```\n\nA child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a\ncheckbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing\n`.appearance-input` — see `theme/control-set.css` for exactly which selectors read which\nradius/border tokens. A plain `span` renders as a static text cell between controls.\n\nPagination follows the same shape, with `a.appearance-button` links and `aria-current=\"page\"`\nholding the current page in its pressed look:\n\n```html\n<nav aria-label=\"Pagination\">\n <use-control-set>\n <a class=\"appearance-button\" href=\"?page=1\">1</a>\n <a class=\"appearance-button\" href=\"?page=2\" aria-current=\"page\">2</a>\n <span aria-hidden=\"true\">…</span>\n <a class=\"appearance-button\" href=\"?page=10\">10</a>\n </use-control-set>\n</nav>\n```\n\nHow the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`\n(default: a negative overlap equal to the child's own border, for a seamless merged line) and\n`--usewc-effect-control-set-border-radius-sequential` (default: `0`, for square touching\ncorners) can both be overridden — a positive gap and a small radius reads as a looser, softer\nset instead of a fused one.\n---\n\n\n### **Slots:**\n - _default_ - The grouped controls.",
|
|
81
81
|
"attributes": [],
|
|
82
82
|
"references": []
|
|
83
83
|
},
|