use-wc 1.0.0-pre.66 → 1.0.0-pre.67
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 +278 -208
- package/dist/design-system.css +95 -8
- package/dist/docs/use-avatar.md +40 -0
- package/dist/tokens.css +12 -0
- package/dist/use-wc.d.mts +51 -1
- package/dist/use-wc.mjs +58 -1
- package/package.json +1 -1
- package/vscode.css-custom-data.json +4 -0
- package/vscode.html-custom-data.json +18 -6
package/custom-elements.json
CHANGED
|
@@ -89,6 +89,219 @@
|
|
|
89
89
|
}
|
|
90
90
|
]
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
"kind": "javascript-module",
|
|
94
|
+
"path": "src/elements/use-badge/use-badge.ts",
|
|
95
|
+
"declarations": [
|
|
96
|
+
{
|
|
97
|
+
"kind": "class",
|
|
98
|
+
"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.",
|
|
99
|
+
"name": "UseBadge",
|
|
100
|
+
"slots": [
|
|
101
|
+
{
|
|
102
|
+
"description": "Badge content, e.g. a count or short label. Ignored when `dot` is set.",
|
|
103
|
+
"name": ""
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"members": [
|
|
107
|
+
{
|
|
108
|
+
"kind": "field",
|
|
109
|
+
"name": "anchortarget",
|
|
110
|
+
"type": {
|
|
111
|
+
"text": "string | undefined"
|
|
112
|
+
},
|
|
113
|
+
"attribute": "anchortarget",
|
|
114
|
+
"reflects": true
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"kind": "field",
|
|
118
|
+
"name": "dot",
|
|
119
|
+
"type": {
|
|
120
|
+
"text": "boolean"
|
|
121
|
+
},
|
|
122
|
+
"default": "false",
|
|
123
|
+
"attribute": "dot",
|
|
124
|
+
"reflects": true
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"kind": "field",
|
|
128
|
+
"name": "blockalign",
|
|
129
|
+
"type": {
|
|
130
|
+
"text": "\"start\" | \"end\""
|
|
131
|
+
},
|
|
132
|
+
"default": "\"start\"",
|
|
133
|
+
"attribute": "blockalign",
|
|
134
|
+
"reflects": true
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"kind": "field",
|
|
138
|
+
"name": "inlinealign",
|
|
139
|
+
"type": {
|
|
140
|
+
"text": "\"start\" | \"end\""
|
|
141
|
+
},
|
|
142
|
+
"default": "\"end\"",
|
|
143
|
+
"attribute": "inlinealign",
|
|
144
|
+
"reflects": true
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"kind": "field",
|
|
148
|
+
"name": "options",
|
|
149
|
+
"type": {
|
|
150
|
+
"text": "string"
|
|
151
|
+
},
|
|
152
|
+
"default": "\"\"",
|
|
153
|
+
"attribute": "options",
|
|
154
|
+
"reflects": true
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"kind": "field",
|
|
158
|
+
"name": "anchorElement",
|
|
159
|
+
"description": "The element this badge is anchored to. Reading returns whatever element was last resolved,\neither from the `anchortarget` id or set here directly. Setting it anchors to that element\ninstead of resolving `anchortarget`, for cases where the target has no id to reference."
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
"attributes": [
|
|
163
|
+
{
|
|
164
|
+
"description": "Id of the element to anchor to, resolved in the badge's own tree.",
|
|
165
|
+
"name": "anchortarget",
|
|
166
|
+
"type": {
|
|
167
|
+
"text": "string | undefined"
|
|
168
|
+
},
|
|
169
|
+
"fieldName": "anchortarget"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"description": "Renders as a fixed-size dot instead of the slotted content.",
|
|
173
|
+
"name": "dot",
|
|
174
|
+
"type": {
|
|
175
|
+
"text": "boolean"
|
|
176
|
+
},
|
|
177
|
+
"default": "false",
|
|
178
|
+
"fieldName": "dot"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"description": "`\"start\" | \"end\"`: Aligns the badge along the block axis relative to its anchor.",
|
|
182
|
+
"name": "blockalign",
|
|
183
|
+
"type": {
|
|
184
|
+
"text": "\"start\" | \"end\""
|
|
185
|
+
},
|
|
186
|
+
"default": "\"start\"",
|
|
187
|
+
"fieldName": "blockalign"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"description": "`\"start\" | \"end\"`: Aligns the badge along the inline axis relative to its anchor.",
|
|
191
|
+
"name": "inlinealign",
|
|
192
|
+
"type": {
|
|
193
|
+
"text": "\"start\" | \"end\""
|
|
194
|
+
},
|
|
195
|
+
"default": "\"end\"",
|
|
196
|
+
"fieldName": "inlinealign"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"description": "Space-separated feature flags. `noaria` opts out of the automatic `aria-describedby` wiring described above.",
|
|
200
|
+
"name": "options",
|
|
201
|
+
"type": {
|
|
202
|
+
"text": "string"
|
|
203
|
+
},
|
|
204
|
+
"default": "\"\"",
|
|
205
|
+
"fieldName": "options"
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
"superclass": {
|
|
209
|
+
"name": "LitElement",
|
|
210
|
+
"package": "lit"
|
|
211
|
+
},
|
|
212
|
+
"tagName": "use-badge",
|
|
213
|
+
"customElement": true
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"exports": [
|
|
217
|
+
{
|
|
218
|
+
"kind": "js",
|
|
219
|
+
"name": "UseBadge",
|
|
220
|
+
"declaration": {
|
|
221
|
+
"name": "UseBadge",
|
|
222
|
+
"module": "src/elements/use-badge/use-badge.ts"
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"kind": "custom-element-definition",
|
|
227
|
+
"name": "use-badge",
|
|
228
|
+
"declaration": {
|
|
229
|
+
"name": "UseBadge",
|
|
230
|
+
"module": "src/elements/use-badge/use-badge.ts"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
]
|
|
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
|
+
},
|
|
92
305
|
{
|
|
93
306
|
"kind": "javascript-module",
|
|
94
307
|
"path": "src/elements/use-calendar-base/use-calendar-base.ts",
|
|
@@ -494,149 +707,6 @@
|
|
|
494
707
|
}
|
|
495
708
|
]
|
|
496
709
|
},
|
|
497
|
-
{
|
|
498
|
-
"kind": "javascript-module",
|
|
499
|
-
"path": "src/elements/use-badge/use-badge.ts",
|
|
500
|
-
"declarations": [
|
|
501
|
-
{
|
|
502
|
-
"kind": "class",
|
|
503
|
-
"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.",
|
|
504
|
-
"name": "UseBadge",
|
|
505
|
-
"slots": [
|
|
506
|
-
{
|
|
507
|
-
"description": "Badge content, e.g. a count or short label. Ignored when `dot` is set.",
|
|
508
|
-
"name": ""
|
|
509
|
-
}
|
|
510
|
-
],
|
|
511
|
-
"members": [
|
|
512
|
-
{
|
|
513
|
-
"kind": "field",
|
|
514
|
-
"name": "anchortarget",
|
|
515
|
-
"type": {
|
|
516
|
-
"text": "string | undefined"
|
|
517
|
-
},
|
|
518
|
-
"attribute": "anchortarget",
|
|
519
|
-
"reflects": true
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
"kind": "field",
|
|
523
|
-
"name": "dot",
|
|
524
|
-
"type": {
|
|
525
|
-
"text": "boolean"
|
|
526
|
-
},
|
|
527
|
-
"default": "false",
|
|
528
|
-
"attribute": "dot",
|
|
529
|
-
"reflects": true
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
"kind": "field",
|
|
533
|
-
"name": "blockalign",
|
|
534
|
-
"type": {
|
|
535
|
-
"text": "\"start\" | \"end\""
|
|
536
|
-
},
|
|
537
|
-
"default": "\"start\"",
|
|
538
|
-
"attribute": "blockalign",
|
|
539
|
-
"reflects": true
|
|
540
|
-
},
|
|
541
|
-
{
|
|
542
|
-
"kind": "field",
|
|
543
|
-
"name": "inlinealign",
|
|
544
|
-
"type": {
|
|
545
|
-
"text": "\"start\" | \"end\""
|
|
546
|
-
},
|
|
547
|
-
"default": "\"end\"",
|
|
548
|
-
"attribute": "inlinealign",
|
|
549
|
-
"reflects": true
|
|
550
|
-
},
|
|
551
|
-
{
|
|
552
|
-
"kind": "field",
|
|
553
|
-
"name": "options",
|
|
554
|
-
"type": {
|
|
555
|
-
"text": "string"
|
|
556
|
-
},
|
|
557
|
-
"default": "\"\"",
|
|
558
|
-
"attribute": "options",
|
|
559
|
-
"reflects": true
|
|
560
|
-
},
|
|
561
|
-
{
|
|
562
|
-
"kind": "field",
|
|
563
|
-
"name": "anchorElement",
|
|
564
|
-
"description": "The element this badge is anchored to. Reading returns whatever element was last resolved,\neither from the `anchortarget` id or set here directly. Setting it anchors to that element\ninstead of resolving `anchortarget`, for cases where the target has no id to reference."
|
|
565
|
-
}
|
|
566
|
-
],
|
|
567
|
-
"attributes": [
|
|
568
|
-
{
|
|
569
|
-
"description": "Id of the element to anchor to, resolved in the badge's own tree.",
|
|
570
|
-
"name": "anchortarget",
|
|
571
|
-
"type": {
|
|
572
|
-
"text": "string | undefined"
|
|
573
|
-
},
|
|
574
|
-
"fieldName": "anchortarget"
|
|
575
|
-
},
|
|
576
|
-
{
|
|
577
|
-
"description": "Renders as a fixed-size dot instead of the slotted content.",
|
|
578
|
-
"name": "dot",
|
|
579
|
-
"type": {
|
|
580
|
-
"text": "boolean"
|
|
581
|
-
},
|
|
582
|
-
"default": "false",
|
|
583
|
-
"fieldName": "dot"
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
"description": "`\"start\" | \"end\"`: Aligns the badge along the block axis relative to its anchor.",
|
|
587
|
-
"name": "blockalign",
|
|
588
|
-
"type": {
|
|
589
|
-
"text": "\"start\" | \"end\""
|
|
590
|
-
},
|
|
591
|
-
"default": "\"start\"",
|
|
592
|
-
"fieldName": "blockalign"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
"description": "`\"start\" | \"end\"`: Aligns the badge along the inline axis relative to its anchor.",
|
|
596
|
-
"name": "inlinealign",
|
|
597
|
-
"type": {
|
|
598
|
-
"text": "\"start\" | \"end\""
|
|
599
|
-
},
|
|
600
|
-
"default": "\"end\"",
|
|
601
|
-
"fieldName": "inlinealign"
|
|
602
|
-
},
|
|
603
|
-
{
|
|
604
|
-
"description": "Space-separated feature flags. `noaria` opts out of the automatic `aria-describedby` wiring described above.",
|
|
605
|
-
"name": "options",
|
|
606
|
-
"type": {
|
|
607
|
-
"text": "string"
|
|
608
|
-
},
|
|
609
|
-
"default": "\"\"",
|
|
610
|
-
"fieldName": "options"
|
|
611
|
-
}
|
|
612
|
-
],
|
|
613
|
-
"superclass": {
|
|
614
|
-
"name": "LitElement",
|
|
615
|
-
"package": "lit"
|
|
616
|
-
},
|
|
617
|
-
"tagName": "use-badge",
|
|
618
|
-
"customElement": true
|
|
619
|
-
}
|
|
620
|
-
],
|
|
621
|
-
"exports": [
|
|
622
|
-
{
|
|
623
|
-
"kind": "js",
|
|
624
|
-
"name": "UseBadge",
|
|
625
|
-
"declaration": {
|
|
626
|
-
"name": "UseBadge",
|
|
627
|
-
"module": "src/elements/use-badge/use-badge.ts"
|
|
628
|
-
}
|
|
629
|
-
},
|
|
630
|
-
{
|
|
631
|
-
"kind": "custom-element-definition",
|
|
632
|
-
"name": "use-badge",
|
|
633
|
-
"declaration": {
|
|
634
|
-
"name": "UseBadge",
|
|
635
|
-
"module": "src/elements/use-badge/use-badge.ts"
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
]
|
|
639
|
-
},
|
|
640
710
|
{
|
|
641
711
|
"kind": "javascript-module",
|
|
642
712
|
"path": "src/elements/use-calendarday/use-calendarday.ts",
|
|
@@ -702,71 +772,6 @@
|
|
|
702
772
|
}
|
|
703
773
|
]
|
|
704
774
|
},
|
|
705
|
-
{
|
|
706
|
-
"kind": "javascript-module",
|
|
707
|
-
"path": "src/elements/use-caret/use-caret.ts",
|
|
708
|
-
"declarations": [
|
|
709
|
-
{
|
|
710
|
-
"kind": "class",
|
|
711
|
-
"description": "`use-caret` supplies the caret icon and label layout for a consumer who wants to own the\ninvoking button itself. It renders inside a plain `<button>`\nthat carries the native `popovertarget` attribute, pointing at a `use-menu`:\n\n```html\n<button id=\"thing\" popovertarget=\"thing-menu\">\n <use-caret>Menu</use-caret>\n</button>\n<use-menu id=\"thing-menu\" aria-label=\"Menu\">\n <button role=\"menuitem\">First thing</button>\n</use-menu>\n```\n\n`use-menu` finds this button on its own via `popovertarget` and anchors to it — no\n`anchortarget` needed here; that's only for a menu with more than one invoker. See `use-menu`'s\nown docs for that case.\n\nThe button is entirely the consumer's own element — their classes, their content, their event\nhandlers. `use-caret` contributes no interactivity of its own: no internal button, no focus\ntarget, no state. It only renders the label and caret glyph, so consumers get a consistent\nvisual trigger without giving up control of the button.\n\nThe caret direction is derived rather than configured: a trigger nested inside a `use-menu`\nis understood to open a submenu and renders pointing sideways; a top-level trigger renders\npointing down.\n\nSwapping in a different caret **per instance** is a slot: put your own element in the `icon`\nslot and it replaces `part(icon-default)` entirely for that trigger.\n\nSwapping the default caret **for every trigger in the app** doesn't need touching this\ncomponent's `render()` at all — style `::part(icon-default)` from an outside stylesheet, the\nsame way any shadow DOM part is themed:\n\n```css\nuse-caret::part(icon-default) {\n mask-image: url(\"/icons/my-caret.svg\");\n}\n```\n\n(When the design system's `theme.css` is loaded, this is already wired to a token —\n`--usewc-effect-dropdown-trigger-icon-mask-image` — so redefining that custom property has\nthe same effect without writing a `::part()` rule at all.)\n\n`::part()` only reaches CSS-expressible changes (a mask, a background, a transform). For\nanything else — different markup, an icon font, logic beyond a mask — set the static `icon`\nand `nestedIcon` hooks. Every `<use-caret>` in the page picks them up; consumers keep writing\nthe same tag, no new element to register or remember to use instead. `icon` supplies a\ntop-level trigger's glyph, `nestedIcon` a submenu trigger's — set whichever apply; an unset one\nkeeps the built-in ▼/▶ for that case. Set them once, as early as possible (an app's entry\npoint, before any triggers connect) — Lit calls `render()` fresh on every update, so an\nalready-connected instance only reflects the change once something causes it to re-render:\n\n```ts\n// A bare string or TemplateResult is used as-is, on every trigger of that kind:\nUseCaret.icon = \"▾\";\nUseCaret.nestedIcon = \"▸\";\n\n// A function is called on every render instead:\nUseCaret.nestedIcon = (html) => html`<my-icon name=\"chevron-right\"></my-icon>`;\n```\n\nThe function form is called with the component's own `html` tag as its (optional) first\nargument rather than requiring the caller to import one — a page can end up with more than one\ncopy of `lit-html` in its module graph, and a `TemplateResult` built from a *different* copy\nthan the one this component renders with can silently fail to render. Taking `html` in as a\nparameter sidesteps that: whatever's returned is guaranteed to come from the same `lit-html`\nthis component already uses. A bare string skips the concern entirely.\n\nOnly need to change the icon on **some** triggers, not every one in the app? Extend the\nclass, override `render()` normally, and register the subclass under a different tag name so\nit coexists with the built-in element instead of replacing it everywhere:\n\n```ts\nclass MyCaret extends UseCaret {\n override render() {\n return html`<slot></slot><slot name=\"icon\"><my-icon name=\"chevron\"></my-icon></slot>`;\n }\n}\ncustomElements.define(\"my-caret\", MyCaret);\n```",
|
|
712
|
-
"name": "UseCaret",
|
|
713
|
-
"slots": [
|
|
714
|
-
{
|
|
715
|
-
"description": "Trigger label content.",
|
|
716
|
-
"name": "default"
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
"description": "Replaces the default caret glyph.",
|
|
720
|
-
"name": "icon"
|
|
721
|
-
}
|
|
722
|
-
],
|
|
723
|
-
"members": [
|
|
724
|
-
{
|
|
725
|
-
"kind": "field",
|
|
726
|
-
"name": "icon",
|
|
727
|
-
"type": {
|
|
728
|
-
"text": "((html: HtmlTag) => TemplateResult | string) | TemplateResult | string | undefined"
|
|
729
|
-
},
|
|
730
|
-
"static": true,
|
|
731
|
-
"description": "Global override for a top-level trigger's caret. When set, every non-nested `<use-caret>` in\nthe page renders this inside `part(icon-default)` instead of the built-in ▼ character. A\nplain string or `TemplateResult` is used as-is; the function form is called with the\ncomponent's own `html` tag, so a returned template is guaranteed to come from the same\n`lit-html` instance this component renders with. Unset (the default) keeps the built-in ▼."
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
"kind": "field",
|
|
735
|
-
"name": "nestedIcon",
|
|
736
|
-
"type": {
|
|
737
|
-
"text": "((html: HtmlTag) => TemplateResult | string) | TemplateResult | string | undefined"
|
|
738
|
-
},
|
|
739
|
-
"static": true,
|
|
740
|
-
"description": "Global override for a submenu trigger's caret — the counterpart to icon for a\n`<use-caret>` nested inside a `use-menu`. Unset (the default) keeps the built-in ▶."
|
|
741
|
-
}
|
|
742
|
-
],
|
|
743
|
-
"superclass": {
|
|
744
|
-
"name": "LitElement",
|
|
745
|
-
"package": "lit"
|
|
746
|
-
},
|
|
747
|
-
"tagName": "use-caret",
|
|
748
|
-
"customElement": true
|
|
749
|
-
}
|
|
750
|
-
],
|
|
751
|
-
"exports": [
|
|
752
|
-
{
|
|
753
|
-
"kind": "js",
|
|
754
|
-
"name": "UseCaret",
|
|
755
|
-
"declaration": {
|
|
756
|
-
"name": "UseCaret",
|
|
757
|
-
"module": "src/elements/use-caret/use-caret.ts"
|
|
758
|
-
}
|
|
759
|
-
},
|
|
760
|
-
{
|
|
761
|
-
"kind": "custom-element-definition",
|
|
762
|
-
"name": "use-caret",
|
|
763
|
-
"declaration": {
|
|
764
|
-
"name": "UseCaret",
|
|
765
|
-
"module": "src/elements/use-caret/use-caret.ts"
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
]
|
|
769
|
-
},
|
|
770
775
|
{
|
|
771
776
|
"kind": "javascript-module",
|
|
772
777
|
"path": "src/elements/use-date-input/use-date-input.ts",
|
|
@@ -893,6 +898,71 @@
|
|
|
893
898
|
}
|
|
894
899
|
]
|
|
895
900
|
},
|
|
901
|
+
{
|
|
902
|
+
"kind": "javascript-module",
|
|
903
|
+
"path": "src/elements/use-caret/use-caret.ts",
|
|
904
|
+
"declarations": [
|
|
905
|
+
{
|
|
906
|
+
"kind": "class",
|
|
907
|
+
"description": "`use-caret` supplies the caret icon and label layout for a consumer who wants to own the\ninvoking button itself. It renders inside a plain `<button>`\nthat carries the native `popovertarget` attribute, pointing at a `use-menu`:\n\n```html\n<button id=\"thing\" popovertarget=\"thing-menu\">\n <use-caret>Menu</use-caret>\n</button>\n<use-menu id=\"thing-menu\" aria-label=\"Menu\">\n <button role=\"menuitem\">First thing</button>\n</use-menu>\n```\n\n`use-menu` finds this button on its own via `popovertarget` and anchors to it — no\n`anchortarget` needed here; that's only for a menu with more than one invoker. See `use-menu`'s\nown docs for that case.\n\nThe button is entirely the consumer's own element — their classes, their content, their event\nhandlers. `use-caret` contributes no interactivity of its own: no internal button, no focus\ntarget, no state. It only renders the label and caret glyph, so consumers get a consistent\nvisual trigger without giving up control of the button.\n\nThe caret direction is derived rather than configured: a trigger nested inside a `use-menu`\nis understood to open a submenu and renders pointing sideways; a top-level trigger renders\npointing down.\n\nSwapping in a different caret **per instance** is a slot: put your own element in the `icon`\nslot and it replaces `part(icon-default)` entirely for that trigger.\n\nSwapping the default caret **for every trigger in the app** doesn't need touching this\ncomponent's `render()` at all — style `::part(icon-default)` from an outside stylesheet, the\nsame way any shadow DOM part is themed:\n\n```css\nuse-caret::part(icon-default) {\n mask-image: url(\"/icons/my-caret.svg\");\n}\n```\n\n(When the design system's `theme.css` is loaded, this is already wired to a token —\n`--usewc-effect-dropdown-trigger-icon-mask-image` — so redefining that custom property has\nthe same effect without writing a `::part()` rule at all.)\n\n`::part()` only reaches CSS-expressible changes (a mask, a background, a transform). For\nanything else — different markup, an icon font, logic beyond a mask — set the static `icon`\nand `nestedIcon` hooks. Every `<use-caret>` in the page picks them up; consumers keep writing\nthe same tag, no new element to register or remember to use instead. `icon` supplies a\ntop-level trigger's glyph, `nestedIcon` a submenu trigger's — set whichever apply; an unset one\nkeeps the built-in ▼/▶ for that case. Set them once, as early as possible (an app's entry\npoint, before any triggers connect) — Lit calls `render()` fresh on every update, so an\nalready-connected instance only reflects the change once something causes it to re-render:\n\n```ts\n// A bare string or TemplateResult is used as-is, on every trigger of that kind:\nUseCaret.icon = \"▾\";\nUseCaret.nestedIcon = \"▸\";\n\n// A function is called on every render instead:\nUseCaret.nestedIcon = (html) => html`<my-icon name=\"chevron-right\"></my-icon>`;\n```\n\nThe function form is called with the component's own `html` tag as its (optional) first\nargument rather than requiring the caller to import one — a page can end up with more than one\ncopy of `lit-html` in its module graph, and a `TemplateResult` built from a *different* copy\nthan the one this component renders with can silently fail to render. Taking `html` in as a\nparameter sidesteps that: whatever's returned is guaranteed to come from the same `lit-html`\nthis component already uses. A bare string skips the concern entirely.\n\nOnly need to change the icon on **some** triggers, not every one in the app? Extend the\nclass, override `render()` normally, and register the subclass under a different tag name so\nit coexists with the built-in element instead of replacing it everywhere:\n\n```ts\nclass MyCaret extends UseCaret {\n override render() {\n return html`<slot></slot><slot name=\"icon\"><my-icon name=\"chevron\"></my-icon></slot>`;\n }\n}\ncustomElements.define(\"my-caret\", MyCaret);\n```",
|
|
908
|
+
"name": "UseCaret",
|
|
909
|
+
"slots": [
|
|
910
|
+
{
|
|
911
|
+
"description": "Trigger label content.",
|
|
912
|
+
"name": "default"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
"description": "Replaces the default caret glyph.",
|
|
916
|
+
"name": "icon"
|
|
917
|
+
}
|
|
918
|
+
],
|
|
919
|
+
"members": [
|
|
920
|
+
{
|
|
921
|
+
"kind": "field",
|
|
922
|
+
"name": "icon",
|
|
923
|
+
"type": {
|
|
924
|
+
"text": "((html: HtmlTag) => TemplateResult | string) | TemplateResult | string | undefined"
|
|
925
|
+
},
|
|
926
|
+
"static": true,
|
|
927
|
+
"description": "Global override for a top-level trigger's caret. When set, every non-nested `<use-caret>` in\nthe page renders this inside `part(icon-default)` instead of the built-in ▼ character. A\nplain string or `TemplateResult` is used as-is; the function form is called with the\ncomponent's own `html` tag, so a returned template is guaranteed to come from the same\n`lit-html` instance this component renders with. Unset (the default) keeps the built-in ▼."
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
"kind": "field",
|
|
931
|
+
"name": "nestedIcon",
|
|
932
|
+
"type": {
|
|
933
|
+
"text": "((html: HtmlTag) => TemplateResult | string) | TemplateResult | string | undefined"
|
|
934
|
+
},
|
|
935
|
+
"static": true,
|
|
936
|
+
"description": "Global override for a submenu trigger's caret — the counterpart to icon for a\n`<use-caret>` nested inside a `use-menu`. Unset (the default) keeps the built-in ▶."
|
|
937
|
+
}
|
|
938
|
+
],
|
|
939
|
+
"superclass": {
|
|
940
|
+
"name": "LitElement",
|
|
941
|
+
"package": "lit"
|
|
942
|
+
},
|
|
943
|
+
"tagName": "use-caret",
|
|
944
|
+
"customElement": true
|
|
945
|
+
}
|
|
946
|
+
],
|
|
947
|
+
"exports": [
|
|
948
|
+
{
|
|
949
|
+
"kind": "js",
|
|
950
|
+
"name": "UseCaret",
|
|
951
|
+
"declaration": {
|
|
952
|
+
"name": "UseCaret",
|
|
953
|
+
"module": "src/elements/use-caret/use-caret.ts"
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
"kind": "custom-element-definition",
|
|
958
|
+
"name": "use-caret",
|
|
959
|
+
"declaration": {
|
|
960
|
+
"name": "UseCaret",
|
|
961
|
+
"module": "src/elements/use-caret/use-caret.ts"
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
]
|
|
965
|
+
},
|
|
896
966
|
{
|
|
897
967
|
"kind": "javascript-module",
|
|
898
968
|
"path": "src/elements/use-date-picker/use-date-picker.ts",
|
package/dist/design-system.css
CHANGED
|
@@ -1309,6 +1309,57 @@
|
|
|
1309
1309
|
}
|
|
1310
1310
|
}
|
|
1311
1311
|
|
|
1312
|
+
/* Avatar — `use-avatar.ts` ships literal fallback styles (a `currentColor` tint background,
|
|
1313
|
+
medium weight, a full-round shape, and the `corner-shape` a squircle needs) so an unthemed
|
|
1314
|
+
avatar renders on its own; this layer swaps them for the design system's tokens. An outer rule
|
|
1315
|
+
targeting the tag beats the element's own `:host` rules, so matching `use-avatar` directly is
|
|
1316
|
+
enough.
|
|
1317
|
+
|
|
1318
|
+
The element itself references no `--usewc-` token — those belong to the theme, which reaches
|
|
1319
|
+
the component through its tag and its affordance classes (`.circle`, `.square`, `.squircle`)
|
|
1320
|
+
rather than through a custom-property contract. Size is plain `inline-size`/`aspect-ratio` set
|
|
1321
|
+
from outside; the element is a query container, so its initials scale from whatever box it is
|
|
1322
|
+
given. */
|
|
1323
|
+
@layer use-theme.avatar {
|
|
1324
|
+
use-avatar {
|
|
1325
|
+
background: var(--usewc-color-avatar-background);
|
|
1326
|
+
color: var(--usewc-color-avatar-text);
|
|
1327
|
+
font-weight: var(--usewc-font-avatar-weight);
|
|
1328
|
+
border-radius: var(--usewc-effect-avatar-border-radius);
|
|
1329
|
+
|
|
1330
|
+
use-theme-escape & {
|
|
1331
|
+
all: revert-layer;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
use-avatar.circle {
|
|
1336
|
+
border-radius: var(--usewc-effect-avatar-border-radius);
|
|
1337
|
+
|
|
1338
|
+
use-theme-escape & {
|
|
1339
|
+
all: revert-layer;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
use-avatar.square {
|
|
1344
|
+
border-radius: var(--usewc-effect-avatar-border-radius-square);
|
|
1345
|
+
|
|
1346
|
+
use-theme-escape & {
|
|
1347
|
+
all: revert-layer;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/* A superellipse — rounder than a rounded rectangle, flatter than a circle. Degrades to the
|
|
1352
|
+
plain radius wherever `corner-shape` isn't supported. */
|
|
1353
|
+
use-avatar.squircle {
|
|
1354
|
+
border-radius: var(--usewc-effect-avatar-border-radius-squircle);
|
|
1355
|
+
corner-shape: squircle;
|
|
1356
|
+
|
|
1357
|
+
use-theme-escape & {
|
|
1358
|
+
all: revert-layer;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1312
1363
|
/* Grid — `.table` is the default treatment a bare `use-grid` gets (bordered surface, a muted
|
|
1313
1364
|
header, rounded per-row hover/selected bands, roomy cells); `.chips` and `.list` opt out of it
|
|
1314
1365
|
into their own layouts. `use-gridhead`/`use-gridbody`/`use-gridcell` all render into light DOM,
|
|
@@ -2320,12 +2371,38 @@
|
|
|
2320
2371
|
}
|
|
2321
2372
|
}
|
|
2322
2373
|
|
|
2323
|
-
|
|
2374
|
+
/* A header's leading likeness is a `use-avatar` or a `<figure>` — no `img.avatar` convention,
|
|
2375
|
+
since a bare `<img>` in a header is as likely to be a logo as a face, and a class would have
|
|
2376
|
+
to be remembered where the element already says it. Both are squared to the variant's avatar
|
|
2377
|
+
size; a `<figure>` centres whatever it holds, the same way the message rail does. */
|
|
2378
|
+
:where(use-layout.page, use-layout.prose, use-layout.message, use-layout.card) > header > :is(use-avatar, figure) {
|
|
2324
2379
|
flex: none;
|
|
2325
2380
|
inline-size: var(--usewc-layout-region-avatar-size);
|
|
2326
2381
|
block-size: var(--usewc-layout-region-avatar-size);
|
|
2327
2382
|
border-radius: var(--usewc-effect-surface-avatar-border-radius);
|
|
2328
2383
|
overflow: hidden;
|
|
2384
|
+
|
|
2385
|
+
use-theme-escape & {
|
|
2386
|
+
all: revert-layer;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
:where(use-layout.page, use-layout.prose, use-layout.message, use-layout.card) > header > figure {
|
|
2391
|
+
display: flex;
|
|
2392
|
+
align-items: center;
|
|
2393
|
+
justify-content: center;
|
|
2394
|
+
margin-inline: 0;
|
|
2395
|
+
font-size: calc(var(--usewc-layout-region-avatar-size) * 0.4);
|
|
2396
|
+
line-height: 1;
|
|
2397
|
+
|
|
2398
|
+
use-theme-escape & {
|
|
2399
|
+
all: revert-layer;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
:where(use-layout.page, use-layout.prose, use-layout.message, use-layout.card) > header > figure > img {
|
|
2404
|
+
inline-size: 100%;
|
|
2405
|
+
block-size: 100%;
|
|
2329
2406
|
object-fit: cover;
|
|
2330
2407
|
|
|
2331
2408
|
use-theme-escape & {
|
|
@@ -2436,19 +2513,27 @@
|
|
|
2436
2513
|
}
|
|
2437
2514
|
}
|
|
2438
2515
|
|
|
2439
|
-
/* The rail is a fixed square
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2516
|
+
/* The rail is a fixed square holding the likeness. `use-avatar` is the element for it — it
|
|
2517
|
+
brings its own initials fallback and shape — and a bare `<figure>` works too, for a date
|
|
2518
|
+
badge or an icon that isn't a person. A `<figure>` centres whatever it's given rather than
|
|
2519
|
+
assuming an `<img>`; a photo inside one fills the square and crops. */
|
|
2520
|
+
:where(use-layout.message) > :is(use-avatar, figure) {
|
|
2444
2521
|
grid-column: 1;
|
|
2445
2522
|
grid-row: 1 / -1;
|
|
2446
|
-
align-items: center;
|
|
2447
|
-
justify-content: center;
|
|
2448
2523
|
inline-size: var(--usewc-layout-message-rail);
|
|
2449
2524
|
block-size: var(--usewc-layout-message-rail);
|
|
2450
2525
|
overflow: hidden;
|
|
2451
2526
|
border-radius: var(--usewc-effect-surface-avatar-border-radius);
|
|
2527
|
+
|
|
2528
|
+
use-theme-escape & {
|
|
2529
|
+
all: revert-layer;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
:where(use-layout.message) > figure {
|
|
2534
|
+
display: flex;
|
|
2535
|
+
align-items: center;
|
|
2536
|
+
justify-content: center;
|
|
2452
2537
|
font-size: calc(var(--usewc-layout-message-rail) * 0.4);
|
|
2453
2538
|
line-height: 1;
|
|
2454
2539
|
|
|
@@ -2458,7 +2543,9 @@
|
|
|
2458
2543
|
}
|
|
2459
2544
|
|
|
2460
2545
|
:where(use-layout.message) > figure > img {
|
|
2546
|
+
inline-size: 100%;
|
|
2461
2547
|
block-size: 100%;
|
|
2548
|
+
object-fit: cover;
|
|
2462
2549
|
|
|
2463
2550
|
use-theme-escape & {
|
|
2464
2551
|
all: revert-layer;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# `use-avatar`
|
|
2
|
+
|
|
3
|
+
`use-avatar` renders a small, fixed-size, clipped container for a person or entity's
|
|
4
|
+
likeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a
|
|
5
|
+
generated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);
|
|
6
|
+
whatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,
|
|
7
|
+
`use-avatar` falls back to initials derived from the `name` attribute.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<use-avatar><img src="ada.jpg" alt="" /></use-avatar>
|
|
11
|
+
<use-avatar name="Riley Quinn"></use-avatar>
|
|
12
|
+
<use-avatar><svg viewBox="0 0 32 32">…</svg></use-avatar>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Size it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —
|
|
16
|
+
from a stylesheet, a style attribute, or the design system's theme layer. The element takes no
|
|
17
|
+
custom properties of its own: it is a query container, so the initials scale from whatever box
|
|
18
|
+
it ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.
|
|
19
|
+
|
|
20
|
+
The element clips its content but gives it no shape of its own — that is the theme's, through
|
|
21
|
+
the affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in
|
|
22
|
+
`theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the
|
|
23
|
+
others.
|
|
24
|
+
|
|
25
|
+
The element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the
|
|
26
|
+
initials fallback is plain text in the accessibility tree — an avatar is decorative beside a
|
|
27
|
+
name far more often than it is the name itself, so labelling it here would mean announcing
|
|
28
|
+
that name twice.
|
|
29
|
+
|
|
30
|
+
## Attributes
|
|
31
|
+
|
|
32
|
+
| Name | Type | Default | Description |
|
|
33
|
+
| --- | --- | --- | --- |
|
|
34
|
+
| name | `string` | `""` | The full name, used for the initials fallback (first + last whitespace-separated token, uppercased) when the slot is empty. |
|
|
35
|
+
|
|
36
|
+
## Slots
|
|
37
|
+
|
|
38
|
+
| Name | Description |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `` | 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. |
|
package/dist/tokens.css
CHANGED
|
@@ -547,6 +547,16 @@
|
|
|
547
547
|
--usewc-font-badge-weight: var(--usewc-font-weight-medium);
|
|
548
548
|
--usewc-effect-badge-border-radius: var(--usewc-effect-border-radius-pill);
|
|
549
549
|
|
|
550
|
+
/* Avatar — `use-avatar`'s initials fallback and shape (see `theme/avatar.css`). Size and
|
|
551
|
+
aspect ratio are plain `inline-size`/`aspect-ratio`, set wherever the avatar is placed, so
|
|
552
|
+
there is no token for them — the element is a query container and scales itself. */
|
|
553
|
+
--usewc-color-avatar-background: var(--usewc-color-gray-100);
|
|
554
|
+
--usewc-color-avatar-text: var(--usewc-color-gray-600);
|
|
555
|
+
--usewc-font-avatar-weight: var(--usewc-font-weight-medium);
|
|
556
|
+
--usewc-effect-avatar-border-radius: var(--usewc-effect-border-radius-full);
|
|
557
|
+
--usewc-effect-avatar-border-radius-square: var(--usewc-effect-border-radius-6);
|
|
558
|
+
--usewc-effect-avatar-border-radius-squircle: 30%;
|
|
559
|
+
|
|
550
560
|
/* Grid — `.table` is the default treatment a bare `use-grid` gets; `.chips` and `.list`
|
|
551
561
|
(the latter still being defined) opt into their own layouts instead. */
|
|
552
562
|
--usewc-color-grid-border: var(--usewc-color-button-base-border-static);
|
|
@@ -782,6 +792,8 @@
|
|
|
782
792
|
--usewc-color-grid-row-background-selected-hover: oklch(from var(--usewc-color-brand-primary) 0.36 0.06 h);
|
|
783
793
|
--usewc-color-grid-row-background-hover: oklch(from var(--usewc-color-gray-800) l c h / 0.6);
|
|
784
794
|
--usewc-color-grid-header-text: var(--usewc-color-gray-200);
|
|
795
|
+
--usewc-color-avatar-background: var(--usewc-color-gray-800);
|
|
796
|
+
--usewc-color-avatar-text: var(--usewc-color-gray-200);
|
|
785
797
|
}
|
|
786
798
|
}
|
|
787
799
|
|
package/dist/use-wc.d.mts
CHANGED
|
@@ -1554,4 +1554,54 @@ declare global {
|
|
|
1554
1554
|
}
|
|
1555
1555
|
}
|
|
1556
1556
|
//#endregion
|
|
1557
|
-
|
|
1557
|
+
//#region src/elements/use-avatar/use-avatar.d.ts
|
|
1558
|
+
/**
|
|
1559
|
+
* `use-avatar` renders a small, fixed-size, clipped container for a person or entity's
|
|
1560
|
+
* likeness. Slot in an `<img>` (or `<picture>`) for a photo, an inline `<svg>` for a
|
|
1561
|
+
* generated or stylized mark, or arbitrary markup (a `<div>` of initials, a calendar badge);
|
|
1562
|
+
* whatever is slotted is centered and clipped to the avatar's shape. With nothing slotted,
|
|
1563
|
+
* `use-avatar` falls back to initials derived from the `name` attribute.
|
|
1564
|
+
*
|
|
1565
|
+
* ```html
|
|
1566
|
+
* <use-avatar><img src="ada.jpg" alt="" /></use-avatar>
|
|
1567
|
+
* <use-avatar name="Riley Quinn"></use-avatar>
|
|
1568
|
+
* <use-avatar><svg viewBox="0 0 32 32">…</svg></use-avatar>
|
|
1569
|
+
* ```
|
|
1570
|
+
*
|
|
1571
|
+
* Size it with plain CSS — `inline-size` for the size and `aspect-ratio` for the proportions —
|
|
1572
|
+
* from a stylesheet, a style attribute, or the design system's theme layer. The element takes no
|
|
1573
|
+
* custom properties of its own: it is a query container, so the initials scale from whatever box
|
|
1574
|
+
* it ends up with. A non-square `aspect-ratio` suits a wide thumbnail or poster.
|
|
1575
|
+
*
|
|
1576
|
+
* The element clips its content but gives it no shape of its own — that is the theme's, through
|
|
1577
|
+
* the affordance classes it defines: `.circle` (the themed default), `.square`, `.squircle` in
|
|
1578
|
+
* `theme/avatar.css`. A circle only reads right at a `1` ratio, so a wide avatar wants one of the
|
|
1579
|
+
* others.
|
|
1580
|
+
*
|
|
1581
|
+
* The element takes no ARIA role of its own. A slotted `<img>` carries its own `alt`, and the
|
|
1582
|
+
* initials fallback is plain text in the accessibility tree — an avatar is decorative beside a
|
|
1583
|
+
* name far more often than it is the name itself, so labelling it here would mean announcing
|
|
1584
|
+
* that name twice.
|
|
1585
|
+
*
|
|
1586
|
+
* @slot - The avatar's content: an `<img>`/`<picture>`, an `<svg>`, or arbitrary markup. Left
|
|
1587
|
+
* empty, the `name` attribute's initials are shown instead, as the slot's own fallback. A photo
|
|
1588
|
+
* fills the frame and crops; anything else keeps its own size, capped at the frame. Give an
|
|
1589
|
+
* `<svg>` a `width`/`height` — without one it defaults to filling the box, and a rounded shape
|
|
1590
|
+
* will clip its corners.
|
|
1591
|
+
* @attr name - The full name, used for the initials fallback (first + last whitespace-separated
|
|
1592
|
+
* token, uppercased) when the slot is empty.
|
|
1593
|
+
* @csspart initials - The span that renders the `name` fallback.
|
|
1594
|
+
*/
|
|
1595
|
+
declare class UseAvatar extends LitElement {
|
|
1596
|
+
#private;
|
|
1597
|
+
name: string;
|
|
1598
|
+
render(): TemplateResult$1<1>;
|
|
1599
|
+
static styles: import("lit").CSSResult;
|
|
1600
|
+
}
|
|
1601
|
+
declare global {
|
|
1602
|
+
interface HTMLElementTagNameMap {
|
|
1603
|
+
"use-avatar": UseAvatar;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
//#endregion
|
|
1607
|
+
export { UseAnchored, UseAvatar, UseBadge, UseCalendarBase, UseCalendarRenderDay, UseCaret, UseDateInput, UseDatePicker, UseDatetimeInput, UseDurationInput, UseFocusgroup, UseIntlDatetime, UseIntlNumber, UseListboxInput, UseMenu, UseMonthPicker, UseMonthPickerRenderMonth, UseOption, UseScrollarea, UseTimeInput, UseTree, UseTreeitem, UseWeekPicker, UseWidget };
|
package/dist/use-wc.mjs
CHANGED
|
@@ -4553,4 +4553,61 @@ __decorate([property({
|
|
|
4553
4553
|
})], UseBadge.prototype, "options", void 0);
|
|
4554
4554
|
UseBadge = __decorate([customElement("use-badge")], UseBadge);
|
|
4555
4555
|
//#endregion
|
|
4556
|
-
|
|
4556
|
+
//#region src/elements/use-avatar/use-avatar.ts
|
|
4557
|
+
let UseAvatar = class UseAvatar extends LitElement {
|
|
4558
|
+
constructor(..._args) {
|
|
4559
|
+
super(..._args);
|
|
4560
|
+
this.name = "";
|
|
4561
|
+
}
|
|
4562
|
+
get #initials() {
|
|
4563
|
+
const tokens = this.name.trim().split(/\s+/).filter(Boolean);
|
|
4564
|
+
if (tokens.length === 0) return "";
|
|
4565
|
+
return (tokens[0].charAt(0) + (tokens.length > 1 ? tokens[tokens.length - 1].charAt(0) : "")).toUpperCase();
|
|
4566
|
+
}
|
|
4567
|
+
render() {
|
|
4568
|
+
return html`<slot><span part="initials">${this.#initials}</span></slot>`;
|
|
4569
|
+
}
|
|
4570
|
+
static {
|
|
4571
|
+
this.styles = css`
|
|
4572
|
+
:host {
|
|
4573
|
+
container-type: inline-size;
|
|
4574
|
+
display: inline-flex;
|
|
4575
|
+
flex: none;
|
|
4576
|
+
align-items: center;
|
|
4577
|
+
justify-content: center;
|
|
4578
|
+
box-sizing: border-box;
|
|
4579
|
+
inline-size: 2.5rem;
|
|
4580
|
+
block-size: auto;
|
|
4581
|
+
aspect-ratio: 1;
|
|
4582
|
+
overflow: hidden;
|
|
4583
|
+
background: color-mix(in oklab, currentColor 12%, transparent);
|
|
4584
|
+
font-weight: 500;
|
|
4585
|
+
line-height: 1;
|
|
4586
|
+
white-space: nowrap;
|
|
4587
|
+
user-select: none;
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
::slotted(:is(img, picture)) {
|
|
4591
|
+
inline-size: 100%;
|
|
4592
|
+
block-size: 100%;
|
|
4593
|
+
object-fit: cover;
|
|
4594
|
+
}
|
|
4595
|
+
|
|
4596
|
+
::slotted(svg) {
|
|
4597
|
+
max-inline-size: 100%;
|
|
4598
|
+
max-block-size: 100%;
|
|
4599
|
+
}
|
|
4600
|
+
|
|
4601
|
+
[part="initials"] {
|
|
4602
|
+
font-size: 38cqw;
|
|
4603
|
+
}
|
|
4604
|
+
`;
|
|
4605
|
+
}
|
|
4606
|
+
};
|
|
4607
|
+
__decorate([property({
|
|
4608
|
+
type: String,
|
|
4609
|
+
reflect: true
|
|
4610
|
+
})], UseAvatar.prototype, "name", void 0);
|
|
4611
|
+
UseAvatar = __decorate([customElement("use-avatar")], UseAvatar);
|
|
4612
|
+
//#endregion
|
|
4613
|
+
export { UseAnchored, UseAvatar, UseBadge, UseCalendarBase, UseCaret, UseDateInput, UseDatePicker, UseDatetimeInput, UseDurationInput, UseFocusgroup, UseIntlDatetime, UseIntlNumber, UseListboxInput, UseMenu, UseMonthPicker, UseOption, UseScrollarea, UseTimeInput, UseTree, UseTreeitem, UseWeekPicker, UseWidget };
|
package/package.json
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
"version": 1.1,
|
|
4
4
|
"properties": [],
|
|
5
5
|
"pseudoElements": [
|
|
6
|
+
{
|
|
7
|
+
"name": "::part(initials)",
|
|
8
|
+
"description": "The span that renders the `name` fallback."
|
|
9
|
+
},
|
|
6
10
|
{ "name": "::part(header)", "description": "The header container" },
|
|
7
11
|
{ "name": "::part(title)", "description": "The title text" },
|
|
8
12
|
{
|
|
@@ -52,15 +52,21 @@
|
|
|
52
52
|
"references": []
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
|
-
"name": "use-
|
|
56
|
-
"description": "
|
|
57
|
-
"attributes": [
|
|
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
|
+
],
|
|
58
64
|
"references": []
|
|
59
65
|
},
|
|
60
66
|
{
|
|
61
|
-
"name": "use-
|
|
62
|
-
"description": "
|
|
63
|
-
"attributes": [],
|
|
67
|
+
"name": "use-calendarday",
|
|
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)",
|
|
69
|
+
"attributes": [{ "name": "date", "values": [] }],
|
|
64
70
|
"references": []
|
|
65
71
|
},
|
|
66
72
|
{
|
|
@@ -74,6 +80,12 @@
|
|
|
74
80
|
],
|
|
75
81
|
"references": []
|
|
76
82
|
},
|
|
83
|
+
{
|
|
84
|
+
"name": "use-caret",
|
|
85
|
+
"description": "`use-caret` supplies the caret icon and label layout for a consumer who wants to own the\ninvoking button itself. It renders inside a plain `<button>`\nthat carries the native `popovertarget` attribute, pointing at a `use-menu`:\n\n```html\n<button id=\"thing\" popovertarget=\"thing-menu\">\n <use-caret>Menu</use-caret>\n</button>\n<use-menu id=\"thing-menu\" aria-label=\"Menu\">\n <button role=\"menuitem\">First thing</button>\n</use-menu>\n```\n\n`use-menu` finds this button on its own via `popovertarget` and anchors to it — no\n`anchortarget` needed here; that's only for a menu with more than one invoker. See `use-menu`'s\nown docs for that case.\n\nThe button is entirely the consumer's own element — their classes, their content, their event\nhandlers. `use-caret` contributes no interactivity of its own: no internal button, no focus\ntarget, no state. It only renders the label and caret glyph, so consumers get a consistent\nvisual trigger without giving up control of the button.\n\nThe caret direction is derived rather than configured: a trigger nested inside a `use-menu`\nis understood to open a submenu and renders pointing sideways; a top-level trigger renders\npointing down.\n\nSwapping in a different caret **per instance** is a slot: put your own element in the `icon`\nslot and it replaces `part(icon-default)` entirely for that trigger.\n\nSwapping the default caret **for every trigger in the app** doesn't need touching this\ncomponent's `render()` at all — style `::part(icon-default)` from an outside stylesheet, the\nsame way any shadow DOM part is themed:\n\n```css\nuse-caret::part(icon-default) {\n mask-image: url(\"/icons/my-caret.svg\");\n}\n```\n\n(When the design system's `theme.css` is loaded, this is already wired to a token —\n`--usewc-effect-dropdown-trigger-icon-mask-image` — so redefining that custom property has\nthe same effect without writing a `::part()` rule at all.)\n\n`::part()` only reaches CSS-expressible changes (a mask, a background, a transform). For\nanything else — different markup, an icon font, logic beyond a mask — set the static `icon`\nand `nestedIcon` hooks. Every `<use-caret>` in the page picks them up; consumers keep writing\nthe same tag, no new element to register or remember to use instead. `icon` supplies a\ntop-level trigger's glyph, `nestedIcon` a submenu trigger's — set whichever apply; an unset one\nkeeps the built-in ▼/▶ for that case. Set them once, as early as possible (an app's entry\npoint, before any triggers connect) — Lit calls `render()` fresh on every update, so an\nalready-connected instance only reflects the change once something causes it to re-render:\n\n```ts\n// A bare string or TemplateResult is used as-is, on every trigger of that kind:\nUseCaret.icon = \"▾\";\nUseCaret.nestedIcon = \"▸\";\n\n// A function is called on every render instead:\nUseCaret.nestedIcon = (html) => html`<my-icon name=\"chevron-right\"></my-icon>`;\n```\n\nThe function form is called with the component's own `html` tag as its (optional) first\nargument rather than requiring the caller to import one — a page can end up with more than one\ncopy of `lit-html` in its module graph, and a `TemplateResult` built from a *different* copy\nthan the one this component renders with can silently fail to render. Taking `html` in as a\nparameter sidesteps that: whatever's returned is guaranteed to come from the same `lit-html`\nthis component already uses. A bare string skips the concern entirely.\n\nOnly need to change the icon on **some** triggers, not every one in the app? Extend the\nclass, override `render()` normally, and register the subclass under a different tag name so\nit coexists with the built-in element instead of replacing it everywhere:\n\n```ts\nclass MyCaret extends UseCaret {\n override render() {\n return html`<slot></slot><slot name=\"icon\"><my-icon name=\"chevron\"></my-icon></slot>`;\n }\n}\ncustomElements.define(\"my-caret\", MyCaret);\n```\n---\n\n\n### **Slots:**\n - **default** - Trigger label content.\n- **icon** - Replaces the default caret glyph.",
|
|
86
|
+
"attributes": [],
|
|
87
|
+
"references": []
|
|
88
|
+
},
|
|
77
89
|
{
|
|
78
90
|
"name": "use-date-picker",
|
|
79
91
|
"description": "A day-granularity date picker. Value format: YYYY-MM-DD.\n\nCustomize day rendering on an instance:\n```ts\ndatePicker.renderDay = ({ day, date }, html) =>\n date === \"2026-03-17\" ? html`<strong>${day}</strong>` : String(day);\n```\n\nOr override on a subclass to apply it to every instance, falling back to\n`super.renderDay(...)` for dates you don't want to customize:\n```ts\nclass MyDatePicker extends UseDatePicker {\n renderDay(data: { day: number; date: string }, html: LitHtml) {\n if (data.date === \"2026-03-17\") {\n return html`<strong>${data.day}</strong>`;\n }\n return super.renderDay(data, html);\n }\n}\n```\n---\n\n\n### **Events:**\n - **use-change** - Fired on selection with detail `{ value: string }`\n\n### **Methods:**\n - **renderDay(data: _{ day: number; date: string }_, _html: _LitHtml_): _TemplateResult | string_** - See UseCalendarRenderDay. Assigning a new function on an\ninstance (e.g. via `.renderDay=${fn}` in a Lit template) after first\nrender does not schedule a re-render on its own — call `requestUpdate()`\nif needed.\n\nDeclared as a regular method rather than a class field so subclass\noverrides can call `super.renderDay(data, html)` to fall back to the\ndefault (or a parent override's) rendering.\n\n### **Slots:**\n - **header-start** - Content before the title in the header\n- **title** - Title showing the month and year\n- **controls** - Navigation controls (previous, today, next buttons)\n- **header-end** - Content after the controls in the header\n- **date-{YYYY-MM-DD}** - Per-date content that replaces the default day number\n\n### **CSS Parts:**\n - **header** - The header container\n- **title** - The title text\n- **title-month** - The month part of the title\n- **title-literal** - Literal text in the title\n- **title-year** - The year part of the title\n- **controls** - The controls slot container\n- **control** - Individual control button\n- **control-previous** - Previous month button\n- **control-today** - Today button\n- **control-next** - Next month button\n- **grid** - The main calendar grid\n- **grid-header** - The header row with day names\n- **grid-header-cell** - Individual day name header cell\n- **grid-body** - The container for calendar weeks\n- **row** - A row of days\n- **day** - A day cell\n- **day-empty** - An empty day cell (from previous/next month)\n- **day-selected** - A selected day cell\n- **day-today** - The current date cell\n- **day-disabled** - A disabled date cell\n- **title-button** - The clickable button wrapping the month/year title\n- **picker** - The scrollable month/year picker panel (replaces grid when open)\n- **picker-year-section** - Container for one year's label and month grid\n- **picker-year-label** - The year heading inside a year section\n- **picker-months** - The 4-column month grid inside a year section\n- **picker-month** - An individual month button\n- **picker-month-current** - Applied to the currently selected month button",
|