use-wc 1.0.0-pre.52 → 1.0.0-pre.53

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,6 +89,149 @@
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
+ },
92
235
  {
93
236
  "kind": "javascript-module",
94
237
  "path": "src/elements/use-calendar-base/use-calendar-base.ts",
@@ -494,149 +637,6 @@
494
637
  }
495
638
  ]
496
639
  },
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
640
  {
641
641
  "kind": "javascript-module",
642
642
  "path": "src/elements/use-calendarday/use-calendarday.ts",
@@ -106,8 +106,9 @@
106
106
  `::part()` inside a `:where()`/`:is()` argument list is invalid and silently dropped by the
107
107
  browser, taking the whole alternative down with it. Stands alone instead. */
108
108
  use-listbox-input:not(.appearance-native)::part(listbox) {
109
- border: var(--usewc-layout-input-border) var(--usewc-effect-input-border-style)
110
- var(--usewc-color-input-border-static);
109
+ --usewc-color-input-border: var(--usewc-color-input-border-static);
110
+
111
+ border: var(--usewc-layout-input-border) var(--usewc-effect-input-border-style) var(--usewc-color-input-border);
111
112
  padding: var(--usewc-layout-popover-menu-padding);
112
113
  background: var(--usewc-color-input-background-static);
113
114
  font-family: var(--usewc-font-input-family);
@@ -115,12 +116,39 @@
115
116
  font-weight: var(--usewc-font-weight-normal);
116
117
  color: var(--usewc-color-input-text-static);
117
118
  border-radius: var(--usewc-effect-input-border-radius);
119
+ outline: 0 var(--usewc-effect-outline-style) var(--usewc-color-outline);
120
+ outline-offset: var(--usewc-effect-outline-offset-flush);
121
+ transition: var(--usewc-effect-outline-transition);
118
122
  }
119
123
 
120
124
  use-theme-escape use-listbox-input:not(.appearance-native)::part(listbox) {
121
125
  all: revert-layer;
122
126
  }
123
127
 
128
+ use-listbox-input:not(.appearance-native)::part(listbox):hover {
129
+ --usewc-color-input-border: var(--usewc-color-input-border-hover);
130
+ }
131
+
132
+ use-theme-escape use-listbox-input:not(.appearance-native)::part(listbox):hover {
133
+ all: revert-layer;
134
+ }
135
+
136
+ /* The actually-focused element with `delegatesFocus` is this inner part, not the host —
137
+ Chromium's `:focus-visible` heuristic doesn't reliably propagate to the host through
138
+ delegation, so the ring has to be driven from here or the browser's native default outline
139
+ shows on the part instead. Border flips to the same focus color as the outline (matching the
140
+ shared input pattern above) so the two read as one seamless ring instead of a gray border
141
+ inside a mismatched blue ring. */
142
+ use-listbox-input:not(.appearance-native)::part(listbox):focus-visible {
143
+ --usewc-color-input-border: var(--usewc-color-input-border-focus);
144
+
145
+ outline-width: var(--usewc-effect-outline-size);
146
+ }
147
+
148
+ use-theme-escape use-listbox-input:not(.appearance-native)::part(listbox):focus-visible {
149
+ all: revert-layer;
150
+ }
151
+
124
152
  select:not(.appearance-native) {
125
153
  appearance: none;
126
154
  }
@@ -910,7 +938,7 @@
910
938
  }
911
939
  }
912
940
 
913
- use-listbox-input:is(:hover, :focus) use-option:state(active) {
941
+ use-listbox-input:not(:has(use-option:hover)):focus use-option:state(active) {
914
942
  --usewc-color-popover-menu-item-background: var(--usewc-color-popover-menu-item-background-active);
915
943
  }
916
944
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-wc",
3
- "version": "1.0.0-pre.52",
3
+ "version": "1.0.0-pre.53",
4
4
  "private": false,
5
5
  "homepage": "https://usewc.com",
6
6
  "bugs": "https://github.com/dang-rabbits/use-wc/issues",