use-wc 1.0.0-pre.77 → 1.0.0-pre.79

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.
@@ -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",
@@ -837,6 +837,48 @@
837
837
  }
838
838
  ]
839
839
  },
840
+ {
841
+ "kind": "javascript-module",
842
+ "path": "src/elements/use-control-set/use-control-set.ts",
843
+ "declarations": [
844
+ {
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&hellip;</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.",
847
+ "name": "UseControlSet",
848
+ "slots": [
849
+ {
850
+ "description": "The grouped controls.",
851
+ "name": ""
852
+ }
853
+ ],
854
+ "members": [],
855
+ "superclass": {
856
+ "name": "LitElement",
857
+ "package": "lit"
858
+ },
859
+ "tagName": "use-control-set",
860
+ "customElement": true
861
+ }
862
+ ],
863
+ "exports": [
864
+ {
865
+ "kind": "js",
866
+ "name": "UseControlSet",
867
+ "declaration": {
868
+ "name": "UseControlSet",
869
+ "module": "src/elements/use-control-set/use-control-set.ts"
870
+ }
871
+ },
872
+ {
873
+ "kind": "custom-element-definition",
874
+ "name": "use-control-set",
875
+ "declaration": {
876
+ "name": "UseControlSet",
877
+ "module": "src/elements/use-control-set/use-control-set.ts"
878
+ }
879
+ }
880
+ ]
881
+ },
840
882
  {
841
883
  "kind": "javascript-module",
842
884
  "path": "src/elements/use-date-input/use-date-input.ts",
@@ -2440,6 +2482,18 @@
2440
2482
  "type": {
2441
2483
  "text": "string[] | string | null"
2442
2484
  }
2485
+ },
2486
+ {
2487
+ "kind": "method",
2488
+ "name": "claimRovingTabStop",
2489
+ "parameters": [
2490
+ {
2491
+ "name": "cell",
2492
+ "type": {
2493
+ "text": "HTMLElement"
2494
+ }
2495
+ }
2496
+ ]
2443
2497
  }
2444
2498
  ],
2445
2499
  "attributes": [
@@ -322,7 +322,7 @@
322
322
  --usewc-local-link-decoration-line: var(--usewc-effect-link-chrome-text-decoration);
323
323
  }
324
324
 
325
- :is(a:not([class*="appearance-"]), .appearance-a) {
325
+ :where(a:not([class*="appearance-"]), .appearance-a) {
326
326
  &:where(:not(a)) {
327
327
  all: unset;
328
328
  }
@@ -506,6 +506,38 @@
506
506
  }
507
507
  }
508
508
 
509
+ &:not([type="file"]):has(> use-caret:empty, > svg:only-child) {
510
+ /*
511
+ * :empty on use-caret checks for no text nodes at all, not just "no element siblings" —
512
+ * that's what makes it safe to key square sizing off of: a caret with a label
513
+ * (<use-caret>Menu</use-caret>) never matches. svg:only-child has no such guarantee (a text
514
+ * node beside the svg still passes), so icon-only buttons without a use-caret wrapper should
515
+ * carry no other content.
516
+ */
517
+ /* aspect-ratio doesn't reliably resolve here — as a flex item inside use-control-set (or
518
+ any flex/grid ancestor), its hypothetical main size can be computed from content before the
519
+ cross size the ratio needs is definite, leaving width and height mismatched. Computing the
520
+ square's side explicitly, from the same ingredients that already determine a normal
521
+ button's natural height, is a real square by construction — and it keeps this button the
522
+ same height as a text sibling in the same use-control-set, rather than shrinking to 1lh. */
523
+ padding-inline: 0;
524
+ --usewc-layout-button-icon-only-size: calc(
525
+ var(--usewc-layout-button-line-height) +
526
+ (var(--usewc-layout-button-padding-block) + var(--usewc-layout-button-border)) * 2
527
+ );
528
+ inline-size: var(--usewc-layout-button-icon-only-size);
529
+ block-size: var(--usewc-layout-button-icon-only-size);
530
+
531
+ /* The default caret glyph is a 50% tint of currentColor for a caret beside a label — as
532
+ the button's only content, it reads better at full strength, so this overrides the token
533
+ rather than the color directly; it inherits into use-caret's shadow tree from here. */
534
+ --usewc-effect-dropdown-trigger-icon-background-color: currentColor;
535
+
536
+ use-theme-escape & {
537
+ all: revert-layer;
538
+ }
539
+ }
540
+
509
541
  &::file-selector-button {
510
542
  margin-inline-end: var(--usewc-layout-input-gap-inline);
511
543
  }
@@ -652,6 +684,69 @@
652
684
  }
653
685
  }
654
686
 
687
+ /* `use-control-set` groups adjacent controls into one visual unit — buttons, text-style inputs,
688
+ and anything else, custom elements included, that renders its own themed border-radius earlier
689
+ in the cascade. Rather than enumerating every control family (which would leave out any custom
690
+ input component this file doesn't know about) and reading each one's own radius token by name
691
+ (which would leave out any component using a token this file has never heard of), the rule
692
+ below matches every direct child indiscriminately and reads back each one's *already-computed*
693
+ radius with `revert-layer` — the value it would have had from an earlier layer if this layer
694
+ didn't exist. That's the exact radius button.css, input.css, select.css, or a future custom
695
+ element's own theme file already gave it, with no name to keep in sync here.
696
+
697
+ This still needs `[type="file"]` and `.appearance-native` excluded: a file input gets a
698
+ completely different treatment in input.css, and `.appearance-native` is this system's opt-out
699
+ of theming altogether — neither should be squared off as if it were a themed control.
700
+
701
+ This lives in its own layer, imported after `input.css`, `button.css`, and every other control
702
+ family's stylesheet in `theme.css`, specifically so the touching-side overrides below can use a
703
+ plain, ordinary-specificity selector: cascade layers are compared before specificity, so a
704
+ later layer wins over an earlier one regardless of how each rule's own selector weighs in — no
705
+ need to fight any control's own selector list for a specificity win the way an override nested
706
+ inside one of them would. `revert-layer` itself also depends on this layer ordering — it rolls
707
+ back to the *previous* layer's value, so it only reaches button.css/input.css's own radius
708
+ because this file's layer comes after theirs.
709
+
710
+ The container only sets `display` and `isolation` — `isolation: isolate` scopes the hover
711
+ `z-index` below to just this set's own children, so a lifted border can't bleed into stacking
712
+ elsewhere on the page. Touching sides merge by default (`--usewc-layout-control-set-gap` is a
713
+ negative overlap equal to the button border, and `--usewc-effect-control-set-border-radius-sequential`
714
+ is `0`), both themeable — see `tokens/semantic.css` for the defaults. The button border is the
715
+ one hardcoded assumption left: it and the input border round to the same rendered pixel at
716
+ ordinary font sizes even though one is `rem`-based and the other `em`-based, so a single gap
717
+ default reads as seamless for any mix of children without needing a per-child value. */
718
+ @layer use-theme.control-set {
719
+ use-control-set {
720
+ display: inline-flex;
721
+ isolation: isolate;
722
+ }
723
+
724
+ use-control-set > *:not([type="file"], .appearance-native) {
725
+ margin-inline-start: var(--usewc-layout-control-set-gap);
726
+ border-radius: var(--usewc-effect-control-set-border-radius-sequential);
727
+
728
+ /* first-child and last-child both apply to a lone child, restoring its full radius. */
729
+ &:first-child {
730
+ margin-inline-start: 0;
731
+ border-start-start-radius: revert-layer;
732
+ border-end-start-radius: revert-layer;
733
+ }
734
+
735
+ &:last-child {
736
+ border-start-end-radius: revert-layer;
737
+ border-end-end-radius: revert-layer;
738
+ }
739
+
740
+ &:where(:hover, :focus-visible, :focus-within) {
741
+ z-index: 1;
742
+ }
743
+
744
+ use-theme-escape & {
745
+ all: revert-layer;
746
+ }
747
+ }
748
+ }
749
+
655
750
  @layer use-theme.code {
656
751
  code,
657
752
  .appearance-code {
@@ -1429,8 +1524,10 @@
1429
1524
  blue-600/700/800 — `currentColor` alone can't step down like that, so each state is the
1430
1525
  cell's own color with its lightness nudged instead. `link.css`'s own decoration-color rule
1431
1526
  already derives from `--usewc-local-link-text`, so the underline follows every step here for
1432
- free, staying a lighter tint of whichever shade the text itself is in. */
1433
- use-gridcell :is(a:not([class*="appearance-"]), .appearance-a) {
1527
+ free, staying a lighter tint of whichever shade the text itself is in. `.control` is excluded
1528
+ the same as `appearance-*` — it's header chrome with its own complete treatment below, not
1529
+ content that should read as a link. */
1530
+ use-gridcell :is(a:not([class*="appearance-"], .control), .appearance-a) {
1434
1531
  --usewc-color-link-text-static: currentColor;
1435
1532
  --usewc-color-link-text-hover: oklch(
1436
1533
  from currentColor calc(l + var(--usewc-color-grid-cell-link-hover-lightness-shift)) c h
@@ -0,0 +1,49 @@
1
+ # `use-control-set`
2
+
3
+ Groups adjacent controls — buttons and text-style inputs alike — into one visual unit: shared
4
+ borders between touching children, rounded corners only on the two outer ends, and a hovered
5
+ or focused child's border lifted above its neighbors so the whole border reads clearly.
6
+
7
+ `use-control-set` renders no shadow DOM and no template of its own — it exists only as a
8
+ dedicated tag for `theme/control-set.css` to style, the same way `use-layout` is a bare
9
+ primitive rather than a specific look. A classic split button is a text button followed by an
10
+ icon-only trigger for a `use-menu`:
11
+
12
+ ```html
13
+ <use-control-set>
14
+ <button type="button">Save</button>
15
+ <button type="button" popovertarget="save-options" aria-label="More save options">
16
+ <use-caret></use-caret>
17
+ </button>
18
+ </use-control-set>
19
+ <use-menu id="save-options" aria-label="More save options">
20
+ <button role="menuitem">Save as&hellip;</button>
21
+ </use-menu>
22
+ ```
23
+
24
+ A search box with an attached submit button follows the same shape, mixing a text input with a
25
+ button:
26
+
27
+ ```html
28
+ <use-control-set>
29
+ <input type="search" placeholder="Search" />
30
+ <button type="submit">Go</button>
31
+ </use-control-set>
32
+ ```
33
+
34
+ A child is a `<button>`, anything wearing `.appearance-button`, an `<input>` (other than a
35
+ checkbox/radio/range/file), a `<select>`, a `<textarea>`, or anything wearing
36
+ `.appearance-input` — see `theme/control-set.css` for exactly which selectors read which
37
+ radius/border tokens.
38
+
39
+ How the touching sides render is themeable rather than fixed: `--usewc-layout-control-set-gap`
40
+ (default: a negative overlap equal to the child's own border, for a seamless merged line) and
41
+ `--usewc-effect-control-set-border-radius-sequential` (default: `0`, for square touching
42
+ corners) can both be overridden — a positive gap and a small radius reads as a looser, softer
43
+ set instead of a fused one.
44
+
45
+ ## Slots
46
+
47
+ | Name | Description |
48
+ | --- | --- |
49
+ | `` | The grouped controls. |
@@ -40,6 +40,7 @@ generated id. Lazily created so single-select grids without a `name` still group
40
40
  | Name | Signature | Description |
41
41
  | --- | --- | --- |
42
42
  | isRowDisabled | `(row: Element \| null \| undefined)` | - |
43
+ | claimRovingTabStop | `(cell: HTMLElement)` | - |
43
44
 
44
45
  ## Slots
45
46
 
package/dist/tokens.css CHANGED
@@ -553,6 +553,15 @@
553
553
  --usewc-font-button-extra-large-size: var(--usewc-font-size-20);
554
554
  --usewc-layout-button-extra-large-line-height: var(--usewc-line-height-32);
555
555
 
556
+ /* Control set — `use-control-set` (see `theme/control-set.css`), grouping adjacent buttons
557
+ and/or text-style inputs into one visual unit. The gap is a negative overlap equal to the
558
+ button border by default, so touching borders merge into one seamless line; a theme can
559
+ widen it to a real positive gap instead. `-sequential` names the radius the same way
560
+ `grid.css`'s adjacent selected-row band does — the edge a child shares with its neighbor, `0`
561
+ by default (square) but able to take a small nonzero value instead of a hard corner. */
562
+ --usewc-layout-control-set-gap: calc(-1 * var(--usewc-layout-button-border));
563
+ --usewc-effect-control-set-border-radius-sequential: 0;
564
+
556
565
  /* Badge — a rose fill with white text: a warm pink-red that stays clear of the danger red's
557
566
  hue and the primary blue, so a count badge doesn't read as an error or a button. The fill
558
567
  is a fixed shade in both themes (like the primary/danger fills), so no dark-mode override
package/dist/use-wc.d.mts CHANGED
@@ -1654,6 +1654,7 @@ export declare class UseGrid extends LitElement {
1654
1654
  updated(changedProps: Map<string, unknown>): void;
1655
1655
  connectedCallback(): void;
1656
1656
  disconnectedCallback(): void;
1657
+ claimRovingTabStop(cell: HTMLElement): void;
1657
1658
  firstUpdated(): void;
1658
1659
  render(): TemplateResult$1<1>;
1659
1660
  static styles: import("lit").CSSResult;
package/dist/use-wc.mjs CHANGED
@@ -4892,11 +4892,13 @@ let UseGrid = class UseGrid extends LitElement {
4892
4892
  this.#unwatchMutations();
4893
4893
  super.disconnectedCallback();
4894
4894
  }
4895
- #focusGridCell(cell) {
4895
+ claimRovingTabStop(cell) {
4896
4896
  this.#getCellCache().cells.forEach((candidate) => {
4897
- candidate.tabIndex = -1;
4897
+ candidate.tabIndex = candidate === cell ? 0 : -1;
4898
4898
  });
4899
- cell.tabIndex = 0;
4899
+ }
4900
+ #focusGridCell(cell) {
4901
+ this.claimRovingTabStop(cell);
4900
4902
  cell.focus();
4901
4903
  }
4902
4904
  firstUpdated() {
@@ -5225,6 +5227,7 @@ let UseGridCell = class UseGridCell extends UseWidget {
5225
5227
  this.#handleFocusIn = () => {
5226
5228
  this.#initializeAction();
5227
5229
  if (this.#action) {
5230
+ this.closest("use-grid")?.claimRovingTabStop(this);
5228
5231
  this.#action.focus();
5229
5232
  this.tabIndex = -1;
5230
5233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-wc",
3
- "version": "1.0.0-pre.77",
3
+ "version": "1.0.0-pre.79",
4
4
  "private": false,
5
5
  "homepage": "https://usewc.com",
6
6
  "bugs": "https://github.com/dang-rabbits/use-wc/issues",
@@ -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)",
@@ -75,6 +75,12 @@
75
75
  "attributes": [],
76
76
  "references": []
77
77
  },
78
+ {
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&hellip;</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.",
81
+ "attributes": [],
82
+ "references": []
83
+ },
78
84
  {
79
85
  "name": "use-date-input",
80
86
  "description": "Displays a date picker using segmented inputs for year, month, and day.\n\nUses browser locale for formatting and ARIA labels.\n---\n",