@adia-ai/web-components 0.7.4 → 0.7.6
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/CHANGELOG.md +30 -0
- package/components/action-list/action-list.a2ui.json +2 -2
- package/components/action-list/action-list.yaml +2 -2
- package/components/badge/badge.yaml +1 -0
- package/components/block/block.class.js +20 -4
- package/components/block/block.css +18 -13
- package/components/button/button.a2ui.json +1 -2
- package/components/button/button.css +44 -10
- package/components/button/button.yaml +1 -0
- package/components/card/card.yaml +1 -0
- package/components/chart/chart.a2ui.json +1 -2
- package/components/chart/chart.d.ts +1 -1
- package/components/chart/chart.yaml +1 -0
- package/components/check/check.a2ui.json +0 -3
- package/components/check/check.yaml +0 -2
- package/components/combobox/combobox.a2ui.json +1 -2
- package/components/combobox/combobox.yaml +1 -0
- package/components/command/command.a2ui.json +0 -3
- package/components/command/command.class.js +19 -1
- package/components/command/command.yaml +0 -2
- package/components/context-menu/context-menu.class.js +1 -0
- package/components/description-list/description-list.a2ui.json +1 -2
- package/components/description-list/description-list.d.ts +1 -1
- package/components/description-list/description-list.yaml +1 -0
- package/components/field/field.class.js +1 -0
- package/components/fields/fields.class.js +1 -0
- package/components/grid/grid.yaml +2 -0
- package/components/input/input.a2ui.json +2 -14
- package/components/input/input.yaml +2 -0
- package/components/integration-card/integration-card.class.js +1 -0
- package/components/list/list.class.js +1 -0
- package/components/list/list.yaml +1 -0
- package/components/menu/menu.class.js +1 -0
- package/components/menu/menu.css +14 -2
- package/components/pipeline-status/pipeline-status.yaml +1 -0
- package/components/radio/radio.a2ui.json +0 -3
- package/components/radio/radio.yaml +0 -2
- package/components/rating/rating.yaml +1 -0
- package/components/search/search.a2ui.json +1 -8
- package/components/search/search.yaml +1 -5
- package/components/select/select.a2ui.json +1 -2
- package/components/select/select.class.js +46 -1
- package/components/select/select.test.js +33 -0
- package/components/select/select.yaml +2 -0
- package/components/slider/slider.a2ui.json +0 -3
- package/components/slider/slider.yaml +0 -2
- package/components/swatch/swatch.class.js +1 -0
- package/components/table/table.a2ui.json +2 -4
- package/components/table/table.d.ts +2 -2
- package/components/table/table.yaml +2 -0
- package/components/tabs/tabs.yaml +1 -0
- package/components/tag/tag.yaml +1 -0
- package/components/toggle-group/toggle-group.yaml +1 -0
- package/components/toolbar/toolbar.class.js +1 -0
- package/components/tree/tree.a2ui.json +2 -2
- package/components/tree/tree.yaml +2 -2
- package/dist/host.min.css +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +28 -28
- package/index.css +11 -17
- package/package.json +1 -1
- package/styles/api/sizing.css +18 -6
- package/styles/api/text.css +9 -2
- package/styles/foundation/space.css +33 -0
- package/styles/host.css +20 -22
- package/styles/index.css +14 -17
- package/styles/verse.css +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.7.6] — 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`[padding]` / `[margin]` named scale (`xs`–`xl`) — complete + parametric.** Previously the named padding/margin vocabulary was only `sm`/`md`/`lg` (literal `--a-space-4`/`6`/`8`). Now the full `xs`–`xl` set, each `calc(--a-space-N × --a-{padding,margin}-k)` — mirroring the `[gap]` scale's `value × --a-*-k` form. New `@property --a-padding-k` / `--a-margin-k` knobs (`<number>`, init 1, inherits — a root/provider-level control, subtree-inert like `--a-gap-k`/`--a-density`) retune all named padding/margin at once, per-dimension. `sm`/`md`/`lg` keep their prior values (16/24/32px @k=1) — **behavior-neutral**; `xs` (8px) + `xl` (40px) are new. Integer rungs (`[padding="4"]`) stay literal space-rungs (k-independent). Composes on `--a-density`. Verified: 8/16/24/32/40 @k=1; root `--a-padding-k:2` → md 48 / xl 80; `--a-margin-k` independent of padding. Files: `styles/foundation/space.css`, `styles/api/sizing.css`.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`styles/host.css` is now foundation-only (tokens + resets + page-frame); `styles/index.css` becomes the primitives barrel.** Previously `host.css` bundled the full library (tokens + all 120 component styles + resets, via `index.css`) plus the page-frame. Now: `host.css` = `tokens.css` + `resets.css` + `:where(html)` page-frame only; `styles/index.css` = `components.css` wrapped in `layer(components)` (the primitives barrel). Pages link both in order. The package-root `index.css` (`@adia-ai/web-components/css`) imports both and preserves the existing full-stack published entry — no change for consumers using the package entry. All 119 component dev shells and `site/index.html` updated. **Migration for `host.css`-only consumers:** add `<link rel="stylesheet" href="@adia-ai/web-components/styles/index.css" />` after the `host.css` link.
|
|
12
|
+
- **`<block-ui>` padding/margin unified with the global `[padding]`/`[margin]` scale — now parametric (behavior change).** `block-ui` carried its own literal padding/margin scale (`none`/`xs`/`sm`/`md`/`lg`/`xl` = `0`/`--a-space-1/2/4/6/10` = 0/4/8/16/24/40px, k-independent), duplicated across `block.css` (static `:scope[padding=…]` rules) and `block.class.js` `_SPACE` (the `@bp` responsive path), and diverging from the global `[padding]`/`[margin]` attribute API — `<block-ui padding="md">` rendered 16px while `[padding="md"]` is 24px (same vocabulary, different sizes). Both paths now reference the parametric `--a-{padding,margin}-{xs..xl}` tokens (`foundation/space.css`), so the two grammars AGREE (the same "one named scale" principle as the `[gap]` unification), `block-ui` tracks the `--a-padding-k`/`--a-margin-k` knobs, and the scale is no longer duplicated. **Behavior change** — `block-ui` spacing grows at `xs`/`sm`/`md`/`lg`: `xs` 4→8, `sm` 8→16, **`md` (the default) 16→24**, `lg` 24→32px; `xl` (40) + `none` (0) unchanged. Verified by computed-style probe (8/16/24/32/40 @k=1, default 24, `--a-padding-k:2` → md 48, `@bp` responsive + margins all correct, 0 console errors) + dev-shell visual QA. Files: `components/block/block.css`, `components/block/block.class.js`. **Migration:** a `<block-ui>` that relied on the prior tighter spacing should step the named value one rung down (`md`→`sm`, `lg`→`md`, …) or use the integer rungs (`padding="4"` = literal 16px, k-independent).
|
|
13
|
+
- **CDN bundles rebuilt** — `dist/host.min.css`, `dist/web-components.min.css`, and `dist/web-components.min.js` regenerated so the barrel split + `<block-ui>` + parametric `[padding]`/`[margin]` + `[verse]` re-scaling reach `@adia-ai/web-components@0.7` CDN consumers.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **`[verse]` register now scales icon + caret sizes down with its type + controls.** The compact `[verse]` register (`styles/verse.css`) shifted inset, gap, radius, control-size (`--a-size`), and every type role down — but left `--a-icon-size` (16px @md) and `--a-caret-size` (14px @md) at their regular-register values. So in a verse context a `<select-ui>` caret (an `<icon-ui>` reading `--a-icon-size`) stayed 16×16 against verse's 12px text in a 43px-tall control, and form-element chrome icons read full size — visually oversized. Added a one-tier-down icon/caret scale to `[verse]`, mirroring how it already re-implements `--a-size`: base `[verse]` = 14/12px (= regular-`sm`), `[verse][size="lg"]` = 16/14px (= regular-`md`), `[verse][size="sm"]` = 12/10px. The explicit `[size]` tier rules are **required** because the global `[size]` icon/caret rules live in the `utilities` layer, which verse's `context` layer shadows (same reason `--a-size` needs them). Covers both `<icon-ui>`-based carets (select / combobox, via `--a-icon-size`) and CSS-drawn carets (calendar-grid / calendar-picker / nav-group / pane, via `--a-caret-size`). Verified by computed-style + render-box probe: verse(md) caret 16→14px, verse-`sm` 14→12px, verse-`lg` 20→16px; regular register unchanged. File: `styles/verse.css`.
|
|
18
|
+
- **`<command-ui>` now parses `.map()`/`repeat()`-rendered `<option>`/`<optgroup>` palette items (5th sighting of the `display:contents` wrapper trap).** `#parseOptions()` walked `this.children` directly, so options rendered via `.map()` arrived nested in the template engine's `display:contents`/`role="presentation"` wrapper span and were missed — leaving an empty palette ("No results found.") when the consumer interpolated its option list. New `#logicalOptionChildren()` walks direct children and pierces wrapper spans, mirroring `select-ui#logicalOptionChildren` (FB-98). Eight other `for (const x of this.children)` loops across 8 components (context-menu, field, fields, integration-card, list, menu, swatch, toolbar) were audited and marked `// wrapper-trap-ok` — all read component-stamped or single-literal children that are never consumer-interpolated. `audit:wrapper-trap:strict` added to `check:dogfood-audits:strict`; the audit now reports 0 un-allowlisted loops. File: `components/command/command.class.js`.
|
|
19
|
+
- **`<select-ui>` now parses `.map()`/`repeat()`-rendered `<option>` children (FB-98).** `#parseOptions()` walked `this.children` and matched only `tagName === 'OPTION'`/`'OPTGROUP'`, so interpolated options — each nested in the template engine's `display:contents`/`role="presentation"` wrapper span (`core/template.js` Array branch) — were invisible, leaving the popover empty ("No options"); static-literal options worked (direct children, no wrapper). New `#logicalOptionChildren()` collects `<option>`/`<optgroup>` direct OR nested inside the wrapper spans (skipping component-stamped `[slot]` children), and a re-entrancy-guarded `MutationObserver` re-parses options that arrive after `connected()` (the template's `update()` pass) so the empty-state clears. The same `display:contents` wrapper trap fixed for `menu-ui#show()` (FB-92) and `tree-item-ui#stamp()` (FB-96), now in the third component; mirrors tree's `#logicalSlotChildren`. Static-literal selects + the FB-36 `<option selected>` initial-value path are unchanged. +2 regression tests. File: `components/select/select.class.js`. (Tokens Studio / color-app FB-98)
|
|
20
|
+
- **`<menu-ui>` — a closed declarative menu no longer takes layout space (FB-97).** The closed-state hide rule (`menu.css`) used a child combinator (`:scope > menu-item-ui`), so `.map()`/`repeat()`-rendered items — nested in the template engine's `display:contents`/`role="presentation"` wrapper span — escaped it on the initial (never-opened) render and laid out in flow, ballooning a compact menu to its widest item's width (a 388px file menu displaced a centered toolbar tab-row until a tab became un-clickable). Added wrapper-piercing descendant selectors (`:scope > [role="presentation"] menu-item-ui`, + `menu-divider-ui`); safe vs. the open state since `#show()` appendChild's the bare items into `[data-menu-popover]` (never the wrappers). Verified: a closed `.map()` menu collapses 388px → trigger width (~41px), items `display:none`, neighbour un-displaced; open still renders all items. The CSS instance of the FB-92/96/98 `display:contents` wrapper trap; makes the FB-92/95 "render menu items declaratively" guidance safe for compact menus. File: `components/menu/menu.css`. (Tokens Studio / color-app FB-97)
|
|
21
|
+
- **`button.yaml` `aria-label` prop marked `dynamic: true` — clears dogfood drift.** `aria-label` is a native ARIA attribute managed via `setAttribute` in `connected()` and deliberately kept out of `static properties` (would clobber native `ariaLabel` reflection via `installProps`). The `static-properties-vs-yaml` dogfood audit flagged the yaml declaration as a drift; `dynamic: true` is the established opt-out (same pattern as the `text` prop). `button.a2ui.json` regenerated (`aria-label` → `DynamicString $ref`); dogfood advisory count: 43 → 42.
|
|
22
|
+
- **`<button-ui>` trailing slot kbd-pill now tracks the button's label color on every variant.** A `<kbd-ui slot="trailing">` pill rendered `kbd-ui`'s dark default even on a primary (white-label) button. `kbd-ui` styles its own `color`/`background`/`border` inside `@scope (kbd-ui)`, which wins over the button's `[slot="trailing"]` rule by **scope proximity** (closer scope root) — so setting `color` (even `inherit`) on the slot is inert. Fix: the button overrides `kbd-ui`'s own *tokens* — `[slot="trailing"] { --kbd-fg: currentColor; --kbd-bg / --kbd-border: color-mix(in oklab, currentColor …, transparent) }`. `kbd-ui` declares those tokens at `:where(:scope)` (specificity 0,0,0), so the button's `[slot]` decls (0,1,0) win on **specificity — which the cascade resolves before proximity** — and the pill (text + translucent fill + border) tracks the label: white on primary/colored fills, dark on outline/ghost. Verified on a fresh serve (kbd computed `color` == button label across variants). File: `components/button/button.css`.
|
|
23
|
+
|
|
24
|
+
## [0.7.5] — 2026-06-02
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **`<button-ui>` colored buttons — unreadable solid text + outline rendering as a solid pill.** Two bugs in the `[color]` × `variant` matrix, both verified on the live render (`scripts/qa/button-color-probe.mjs`: WCAG contrast + fill-transparency probe). (1) **Solid** `color="danger|info|success"` set `--button-fg: var(--a-X-fg)`, which resolves to `--a-X-text-strong` — *family-colored* text, ~1:1 contrast on the same-hue fill (near-invisible). Now `--a-chrome-light` (white) like `variant="primary"` → danger 4.75:1, info 4.27:1, success 4.02:1. `warning` keeps dark `--a-warning-fg` (its `--a-warning-bg` fill is light amber). Documented anti-pattern `feedback_text_on_accent_disc` (light text on filled accent surfaces). (2) **Outline/ghost + color** rendered as a solid pill — the `[color]` rule's solid `--button-bg` won source-order over `[variant="outline"]` (the demo's `variant="outline" color="success"` "Approve" button, `button.examples.html:50`). Added combined `[variant][color]` selectors (specificity 0,3,0 > the 0,2,0 `[color]` rule) restoring a transparent fill + colored text (`--a-X-text`) + colored border (`--a-X-border` for outline). **(3) The actual override mechanism.** Fixes (1)+(2) set `--button-fg` correctly, yet the rendered text stayed the fill hue: the global `[color]` presentational utility (`api/text.css`, `utilities` layer) sets `color: var(--a-fg)` and wins over the button's `components`-layer `color: var(--button-fg)` by **layer order** (utilities > components), regardless of specificity. `button-ui` re-purposes `color=` as a semantic *fill* (the `variant="danger"`→`color="danger"` migration, button.css:180) and is the only filled control that does, and is not among the color honorings (`cascade-component-attr-sweep.mjs`) — so it is now excluded from the text-color utility: `[color]:not(:where(button-ui))` (specificity-neutral via `:where()`; a plain `[color="info"]` element still resolves to info text). Verified on a *fresh* serve against the real demo buttons — the persistent dev server caches the `host.css` `@import` chain and masked the fix on edit. Files: `components/button/button.css`, `styles/api/text.css`.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- **CDN bundles rebuilt** — `dist/host.min.css` + `dist/web-components.min.css` regenerated so the button-color fix above reaches `@adia-ai/web-components@0.7` CDN consumers (the bundles were stale since the fix landed on `main` pre-cut, ahead of the cut's `build:bundles`).
|
|
32
|
+
|
|
3
33
|
## [0.7.4] — 2026-06-02
|
|
4
34
|
|
|
5
35
|
### Added
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"Button"
|
|
67
67
|
],
|
|
68
68
|
"slots": {
|
|
69
|
-
"default
|
|
70
|
-
"description": "
|
|
69
|
+
"default": {
|
|
70
|
+
"description": "Holds the list's `<action-item-ui>` children (the action items)."
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"states": [
|
|
@@ -28,8 +28,8 @@ events:
|
|
|
28
28
|
type: object
|
|
29
29
|
description: The triggering list-item element.
|
|
30
30
|
slots:
|
|
31
|
-
default
|
|
32
|
-
description: "
|
|
31
|
+
default:
|
|
32
|
+
description: "Holds the list's `<action-item-ui>` children (the action items)."
|
|
33
33
|
states:
|
|
34
34
|
- name: idle
|
|
35
35
|
description: Default, ready for interaction.
|
|
@@ -19,13 +19,29 @@
|
|
|
19
19
|
* Properties:
|
|
20
20
|
* padding — none | xs | sm | md | lg | xl (default 'md')
|
|
21
21
|
* margin — none | xs | sm | md | lg | xl (default 'none')
|
|
22
|
+
*
|
|
23
|
+
* Values resolve to the parametric --a-{padding,margin}-{xs..xl} scale
|
|
24
|
+
* (foundation/space.css), unified with the global [padding]/[margin] attribute
|
|
25
|
+
* API: md = 24px @k=1, tracks --a-{padding,margin}-k. The `@bp` responsive
|
|
26
|
+
* path below emits the same tokens as the static block.css rules.
|
|
22
27
|
*/
|
|
23
28
|
|
|
24
29
|
import { UIElement } from '../../core/element.js';
|
|
25
30
|
import { parseResponsive, breakpoint } from '../../core/responsive.js';
|
|
26
31
|
|
|
27
|
-
const
|
|
28
|
-
|
|
32
|
+
const _NAMED = new Set(['xs', 'sm', 'md', 'lg', 'xl']);
|
|
33
|
+
/** Resolve a (responsive-parsed) padding/margin value to CSS for dimension
|
|
34
|
+
* `dim` ('padding' | 'margin'). Named rungs map to the parametric
|
|
35
|
+
* --a-{dim}-{xs..xl} scale (foundation/space.css) so this responsive JS path
|
|
36
|
+
* AGREES with the static block.css rules + the global [padding]/[margin]
|
|
37
|
+
* attribute API; bare integers stay literal --a-space-N rungs; 'none' → 0. */
|
|
38
|
+
function _spaceToCss(v, dim) {
|
|
39
|
+
if (v == null || v === '') return '';
|
|
40
|
+
if (v === 'none') return '0';
|
|
41
|
+
if (_NAMED.has(v)) return `var(--a-${dim}-${v})`;
|
|
42
|
+
if (/^\d+$/.test(v)) return `var(--a-space-${v})`;
|
|
43
|
+
return v;
|
|
44
|
+
}
|
|
29
45
|
|
|
30
46
|
export class UIBlock extends UIElement {
|
|
31
47
|
static properties = {
|
|
@@ -42,13 +58,13 @@ export class UIBlock extends UIElement {
|
|
|
42
58
|
const bp = anyR ? breakpoint.value : '';
|
|
43
59
|
|
|
44
60
|
if (padding?.includes('@')) {
|
|
45
|
-
this.style.setProperty('--block-padding', _spaceToCss(parseResponsive(padding, bp)));
|
|
61
|
+
this.style.setProperty('--block-padding', _spaceToCss(parseResponsive(padding, bp), 'padding'));
|
|
46
62
|
} else {
|
|
47
63
|
this.style.removeProperty('--block-padding');
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
if (margin?.includes('@')) {
|
|
51
|
-
this.style.setProperty('--block-margin', _spaceToCss(parseResponsive(margin, bp)));
|
|
67
|
+
this.style.setProperty('--block-margin', _spaceToCss(parseResponsive(margin, bp), 'margin'));
|
|
52
68
|
} else {
|
|
53
69
|
this.style.removeProperty('--block-margin');
|
|
54
70
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@scope (block-ui) {
|
|
2
2
|
:where(:scope) {
|
|
3
|
-
--block-padding: var(--a-
|
|
3
|
+
--block-padding: var(--a-padding-md);
|
|
4
4
|
--block-margin: 0;
|
|
5
5
|
}
|
|
6
6
|
|
|
@@ -11,19 +11,24 @@
|
|
|
11
11
|
margin: var(--block-margin);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/* ── Padding variants
|
|
14
|
+
/* ── Padding variants — the parametric --a-padding-{xs..xl} scale
|
|
15
|
+
(foundation/space.css), unified with the global [padding] attribute API
|
|
16
|
+
(api/sizing.css) so <block-ui padding="md"> == [padding="md"] == 24px @k=1,
|
|
17
|
+
and block-ui now tracks the --a-padding-k knob. Was a literal --a-space-N
|
|
18
|
+
scale (md=16px, k-independent) — see CHANGELOG 0.7.7 behavior change. ── */
|
|
15
19
|
:scope[padding="none"] { --block-padding: 0; }
|
|
16
|
-
:scope[padding="xs"] { --block-padding: var(--a-
|
|
17
|
-
:scope[padding="sm"] { --block-padding: var(--a-
|
|
18
|
-
:scope[padding="md"] { --block-padding: var(--a-
|
|
19
|
-
:scope[padding="lg"] { --block-padding: var(--a-
|
|
20
|
-
:scope[padding="xl"] { --block-padding: var(--a-
|
|
20
|
+
:scope[padding="xs"] { --block-padding: var(--a-padding-xs); }
|
|
21
|
+
:scope[padding="sm"] { --block-padding: var(--a-padding-sm); }
|
|
22
|
+
:scope[padding="md"] { --block-padding: var(--a-padding-md); }
|
|
23
|
+
:scope[padding="lg"] { --block-padding: var(--a-padding-lg); }
|
|
24
|
+
:scope[padding="xl"] { --block-padding: var(--a-padding-xl); }
|
|
21
25
|
|
|
22
|
-
/* ── Margin variants
|
|
26
|
+
/* ── Margin variants — the parametric --a-margin-{xs..xl} scale, unified
|
|
27
|
+
with the global [margin] attribute API (tracks --a-margin-k). ── */
|
|
23
28
|
:scope[margin="none"] { --block-margin: 0; }
|
|
24
|
-
:scope[margin="xs"] { --block-margin: var(--a-
|
|
25
|
-
:scope[margin="sm"] { --block-margin: var(--a-
|
|
26
|
-
:scope[margin="md"] { --block-margin: var(--a-
|
|
27
|
-
:scope[margin="lg"] { --block-margin: var(--a-
|
|
28
|
-
:scope[margin="xl"] { --block-margin: var(--a-
|
|
29
|
+
:scope[margin="xs"] { --block-margin: var(--a-margin-xs); }
|
|
30
|
+
:scope[margin="sm"] { --block-margin: var(--a-margin-sm); }
|
|
31
|
+
:scope[margin="md"] { --block-margin: var(--a-margin-md); }
|
|
32
|
+
:scope[margin="lg"] { --block-margin: var(--a-margin-lg); }
|
|
33
|
+
:scope[margin="xl"] { --block-margin: var(--a-margin-xl); }
|
|
29
34
|
}
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"aria-label": {
|
|
22
22
|
"description": "Accessible label for screen readers. Auto-set from `text` when text is non-empty; meaningful override for icon-only buttons.",
|
|
23
|
-
"
|
|
24
|
-
"default": ""
|
|
23
|
+
"$ref": "common_types.json#/$defs/DynamicString"
|
|
25
24
|
},
|
|
26
25
|
"color": {
|
|
27
26
|
"description": "Semantic intent — composes with [variant]. `<button-ui variant=\"solid\" color=\"danger\">` = filled destructive action; `<button-ui variant=\"outline\" color=\"success\">` = outlined success affordance.",
|
|
@@ -56,7 +56,7 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
56
56
|
--button-border-ghost: transparent;
|
|
57
57
|
--button-border-ghost-hover: transparent;
|
|
58
58
|
--button-bg-danger: var(--a-danger);
|
|
59
|
-
--button-fg-danger: var(--a-
|
|
59
|
+
--button-fg-danger: var(--a-chrome-light); /* white on the saturated fill — see color rules */
|
|
60
60
|
--button-bg-hover-danger: var(--a-danger);
|
|
61
61
|
--button-bg-disabled: var(--a-ui-bg-disabled);
|
|
62
62
|
--button-fg-disabled: var(--a-ui-text-disabled);
|
|
@@ -71,11 +71,12 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
71
71
|
|
|
72
72
|
/* ── Trailing slot ── */
|
|
73
73
|
--button-trailing-font-size: var(--a-ui-sm);
|
|
74
|
-
/* kbd-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
/* kbd-ui styles its color/bg/border inside `@scope (kbd-ui)`, which beats
|
|
75
|
+
this scope by PROXIMITY — so setting `color`/`border` on [slot="trailing"]
|
|
76
|
+
here is inert for a kbd pill. The pill is recolored through kbd's OWN
|
|
77
|
+
tokens (--kbd-fg/-bg/-border) in the rule below instead. The
|
|
78
|
+
--button-trailing-* tokens remain the fallback for non-kbd trailing
|
|
79
|
+
content (badges, plain spans). */
|
|
79
80
|
--button-trailing-border: color-mix(in oklab, currentColor 28%, transparent);
|
|
80
81
|
--button-trailing-radius: var(--a-radius-sm);
|
|
81
82
|
--button-trailing-px: var(--a-space-0-5);
|
|
@@ -142,12 +143,22 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
142
143
|
order: 99;
|
|
143
144
|
margin-inline-start: auto;
|
|
144
145
|
font-size: var(--button-trailing-font-size);
|
|
145
|
-
color:
|
|
146
|
+
color: inherit;
|
|
146
147
|
font-family: inherit;
|
|
147
148
|
border: 1px solid var(--button-trailing-border);
|
|
148
149
|
border-radius: var(--button-trailing-radius);
|
|
149
150
|
padding: 0 var(--button-trailing-px);
|
|
150
151
|
line-height: 1;
|
|
152
|
+
/* Recolor a <kbd-ui slot="trailing"> pill via kbd's OWN tokens so it tracks
|
|
153
|
+
the button label color on every variant (primary white, ghost subtle,
|
|
154
|
+
colored fills). kbd-ui's `:scope { color: var(--kbd-fg) }` wins over the
|
|
155
|
+
`color: inherit` above by scope proximity, but its tokens are declared at
|
|
156
|
+
:where(:scope) (0,0,0) — these (0,1,0) decls win on specificity, which the
|
|
157
|
+
cascade resolves BEFORE proximity. currentColor here is the inherited
|
|
158
|
+
button label color. */
|
|
159
|
+
--kbd-fg: currentColor;
|
|
160
|
+
--kbd-bg: color-mix(in oklab, currentColor 16%, transparent);
|
|
161
|
+
--kbd-border: color-mix(in oklab, currentColor 30%, transparent);
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
/* :scope:active moved outside @scope — see Safari 17.x bug note at top. */
|
|
@@ -186,13 +197,17 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
186
197
|
/* Consume the L3 `-bg` alias, not the L2 `-strong` step. Currently
|
|
187
198
|
resolves identically (both = `-50`), but consuming `-bg` future-
|
|
188
199
|
proofs if the surface-step ever redirects (as -warning-bg did
|
|
189
|
-
in v0.6.36 to fix muddy contrast).
|
|
200
|
+
in v0.6.36 to fix muddy contrast).
|
|
201
|
+
Text is --a-chrome-light (white) on the saturated fill, like primary
|
|
202
|
+
(--button-fg-primary). --a-success-fg is success-COLORED text — near
|
|
203
|
+
invisible on the fill (feedback_text_on_accent_disc). Warning is the
|
|
204
|
+
exception: its --a-warning-bg fill is light, so it keeps dark -fg. */
|
|
190
205
|
--button-bg: var(--a-success-bg);
|
|
191
|
-
--button-fg: var(--a-
|
|
206
|
+
--button-fg: var(--a-chrome-light);
|
|
192
207
|
}
|
|
193
208
|
:scope[color="info"] {
|
|
194
209
|
--button-bg: var(--a-info-bg);
|
|
195
|
-
--button-fg: var(--a-
|
|
210
|
+
--button-fg: var(--a-chrome-light);
|
|
196
211
|
}
|
|
197
212
|
:scope[color="warning"] {
|
|
198
213
|
/* `--a-warning-bg` (bright amber, scheme-independent) not
|
|
@@ -203,6 +218,25 @@ button-ui[color="danger"]:not([disabled]):hover {
|
|
|
203
218
|
--button-fg: var(--a-warning-fg);
|
|
204
219
|
}
|
|
205
220
|
|
|
221
|
+
/* ── Color × non-solid variants ──
|
|
222
|
+
The [color] rules above set a SOLID fill — that's the default rendering
|
|
223
|
+
(bare `color="danger"`). But with variant="outline"/"ghost" the button
|
|
224
|
+
must COMPOSE, not fill. These combined selectors (specificity 0,3,0) beat
|
|
225
|
+
the 0,2,0 [color] rules regardless of source order, restoring a transparent
|
|
226
|
+
fill + colored text (+ colored border for outline). Without them,
|
|
227
|
+
`variant="outline" color="success"` renders as a solid green pill — the
|
|
228
|
+
demo's "Approve" button (button.examples.html:50). --a-X-text is the
|
|
229
|
+
family-colored text designed to read on a neutral page surface; -border is
|
|
230
|
+
the L3 colored border alias. */
|
|
231
|
+
:scope[variant="outline"][color="danger"] { --button-bg: transparent; --button-fg: var(--a-danger-text); --button-border: var(--a-danger-border); }
|
|
232
|
+
:scope[variant="outline"][color="info"] { --button-bg: transparent; --button-fg: var(--a-info-text); --button-border: var(--a-info-border); }
|
|
233
|
+
:scope[variant="outline"][color="success"] { --button-bg: transparent; --button-fg: var(--a-success-text); --button-border: var(--a-success-border); }
|
|
234
|
+
:scope[variant="outline"][color="warning"] { --button-bg: transparent; --button-fg: var(--a-warning-text); --button-border: var(--a-warning-border); }
|
|
235
|
+
:scope[variant="ghost"][color="danger"] { --button-bg: transparent; --button-fg: var(--a-danger-text); }
|
|
236
|
+
:scope[variant="ghost"][color="info"] { --button-bg: transparent; --button-fg: var(--a-info-text); }
|
|
237
|
+
:scope[variant="ghost"][color="success"] { --button-bg: transparent; --button-fg: var(--a-success-text); }
|
|
238
|
+
:scope[variant="ghost"][color="warning"] { --button-bg: transparent; --button-fg: var(--a-warning-text); }
|
|
239
|
+
|
|
206
240
|
/* Hover rules moved outside @scope — see Safari 17.x bug note at
|
|
207
241
|
top of file. */
|
|
208
242
|
|
|
@@ -18,6 +18,7 @@ props:
|
|
|
18
18
|
description: Accessible label for screen readers. Auto-set from `text` when text is non-empty; meaningful override for icon-only buttons.
|
|
19
19
|
type: string
|
|
20
20
|
default: ""
|
|
21
|
+
dynamic: true # native ARIA attr — managed in connected() (setAttribute), deliberately NOT in `static properties` (would clobber native ariaLabel reflection per the installProps memory)
|
|
21
22
|
type:
|
|
22
23
|
description: HTML button type (button, submit, reset)
|
|
23
24
|
type: string
|
|
@@ -16,6 +16,7 @@ props:
|
|
|
16
16
|
rung ("1"…"16").
|
|
17
17
|
type: string
|
|
18
18
|
default: md
|
|
19
|
+
reflect: false # declarative presentational attribute — CSS/author-time read, non-reactive by design
|
|
19
20
|
draggable:
|
|
20
21
|
description: Enables drag handle + cursor:grab. Wires the draggable trait; dispatches drag-end.
|
|
21
22
|
type: boolean
|
|
@@ -55,8 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"data": {
|
|
57
57
|
"description": "JS property (set programmatically — `el.data = [...]`). An array of plain objects; each object's keys are named by the `x` and `y` attributes — e.g. `<chart-ui x=\"month\" y=\"revenue\">` consumes `[{month:'Jan', revenue:3200}, {month:'Feb', revenue:4100}]`. The Chart.js `{labels, datasets}` envelope is NOT chart-ui's API — passing it (or any non-array value) renders an empty chart. May also be supplied declaratively as a JSON-array `data=\"[…]\"` attribute, hydrated once at connect. Custom accessor on the element class, not a reflected attribute.",
|
|
58
|
-
"
|
|
59
|
-
"default": []
|
|
58
|
+
"$ref": "common_types.json#/$defs/DynamicStringList"
|
|
60
59
|
},
|
|
61
60
|
"format": {
|
|
62
61
|
"description": "Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default \"$\"); `percent` multiplies × 100 and adds a % suffix.",
|
|
@@ -23,7 +23,7 @@ export class UIChart extends UIElement {
|
|
|
23
23
|
/** Color scheme */
|
|
24
24
|
color: 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
25
25
|
/** JS property (set programmatically — `el.data = [...]`). An array of plain objects; each object's keys are named by the `x` and `y` attributes — e.g. `<chart-ui x="month" y="revenue">` consumes `[{month:'Jan', revenue:3200}, {month:'Feb', revenue:4100}]`. The Chart.js `{labels, datasets}` envelope is NOT chart-ui's API — passing it (or any non-array value) renders an empty chart. May also be supplied declaratively as a JSON-array `data="[…]"` attribute, hydrated once at connect. Custom accessor on the element class, not a reflected attribute. */
|
|
26
|
-
data:
|
|
26
|
+
data: string;
|
|
27
27
|
/** Number-format mode applied to axis labels + value overlays + donut total + gauge value + treemap value + funnel value + internal tooltip. `abbr` is the legacy 1.2K / 3M format; `decimal` fixes 2 decimals; `currency` prefixes via `--chart-currency-prefix` token (default "$"); `percent` multiplies × 100 and adds a % suffix. */
|
|
28
28
|
format: 'abbr' | 'decimal' | 'currency' | 'percent';
|
|
29
29
|
/** When true, suppress the overlaid average line */
|
|
@@ -93,8 +93,7 @@
|
|
|
93
93
|
},
|
|
94
94
|
"options": {
|
|
95
95
|
"description": "Programmatic option list. Array of {value, label, disabled?, group?} or grouped {label, options:[…]}. Alternative to declarative <option> / <optgroup> children.",
|
|
96
|
-
"
|
|
97
|
-
"default": []
|
|
96
|
+
"$ref": "common_types.json#/$defs/DynamicStringList"
|
|
98
97
|
},
|
|
99
98
|
"placeholder": {
|
|
100
99
|
"description": "Placeholder text in the input when value is empty",
|
|
@@ -140,9 +140,27 @@ export class UICommand extends UIElement {
|
|
|
140
140
|
|
|
141
141
|
// ── Parse declarative <option>/<optgroup> ──
|
|
142
142
|
|
|
143
|
+
// Wrapper-piercing walk for consumer-authored <option>/<optgroup> children.
|
|
144
|
+
// Mirrors select-ui's #logicalOptionChildren (FB-98): .map()/repeat()-rendered
|
|
145
|
+
// options arrive in display:contents/role="presentation" wrapper spans; a plain
|
|
146
|
+
// this.children iteration misses them (FB-98 class, 5th sighting in command-ui).
|
|
147
|
+
#logicalOptionChildren() {
|
|
148
|
+
const out = [];
|
|
149
|
+
const walk = (parent) => {
|
|
150
|
+
for (const ch of parent.children) {
|
|
151
|
+
if (ch.hasAttribute('slot')) continue; // component-stamped — skip
|
|
152
|
+
if (ch.tagName === 'OPTION' || ch.tagName === 'OPTGROUP') { out.push(ch); continue; }
|
|
153
|
+
if (ch.matches('[role="presentation"]') || ch.style?.display === 'contents') { walk(ch); continue; }
|
|
154
|
+
// unknown authored child — ignore (command-ui only uses option/optgroup)
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
walk(this);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
|
|
143
161
|
#parseOptions() {
|
|
144
162
|
const items = [];
|
|
145
|
-
for (const child of this
|
|
163
|
+
for (const child of this.#logicalOptionChildren()) {
|
|
146
164
|
if (child.tagName === 'OPTGROUP') {
|
|
147
165
|
const groupLabel = child.label;
|
|
148
166
|
const group = { label: groupLabel, items: [] };
|
|
@@ -105,6 +105,7 @@ export class UIContextMenu extends UIElement {
|
|
|
105
105
|
return [];
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
// wrapper-trap-ok: detects non-menu-item children as custom content; context-menu items are always static declarative children (right-click actions are not .map()'d)
|
|
108
109
|
for (const child of this.children) {
|
|
109
110
|
const tag = child.tagName.toLowerCase();
|
|
110
111
|
if (tag !== 'menu-item-ui' && tag !== 'menu-divider-ui') return [child];
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"properties": {
|
|
16
16
|
"items": {
|
|
17
17
|
"description": "Optional JSON array of {term, description} — alternative to declarative <dt>/<dd> children",
|
|
18
|
-
"
|
|
19
|
-
"default": []
|
|
18
|
+
"$ref": "common_types.json#/$defs/DynamicStringList"
|
|
20
19
|
},
|
|
21
20
|
"align": {
|
|
22
21
|
"description": "Alignment for inline layout. `start` (default): term and value pack to the term column edge. `between`: term left, value right-aligned with `text-align: end`. `stretch`: value fills the remaining track width (e.g. for a `<slider-ui>` / `<select-ui>` / `<color-picker-ui>` as `<dd>` that should span the full row). Sets `justify-self: stretch` and `width: 100%` on `dd` so block-level form controls inside reach the column edge rather than shrink-wrapping to content.\n",
|
|
@@ -14,7 +14,7 @@ import { UIElement } from '../../core/element.js';
|
|
|
14
14
|
|
|
15
15
|
export class UIDescriptionList extends UIElement {
|
|
16
16
|
/** Optional JSON array of {term, description} — alternative to declarative <dt>/<dd> children */
|
|
17
|
-
items:
|
|
17
|
+
items: string;
|
|
18
18
|
/** Alignment for inline layout. `start` (default): term and value pack to the term column edge. `between`: term left, value right-aligned with `text-align: end`. `stretch`: value fills the remaining track width (e.g. for a `<slider-ui>` / `<select-ui>` / `<color-picker-ui>` as `<dd>` that should span the full row). Sets `justify-self: stretch` and `width: 100%` on `dd` so block-level form controls inside reach the column edge rather than shrink-wrapping to content.
|
|
19
19
|
*/
|
|
20
20
|
align: 'start' | 'between' | 'stretch';
|
|
@@ -30,6 +30,7 @@ props:
|
|
|
30
30
|
description: Optional JSON array of {term, description} — alternative to declarative <dt>/<dd> children
|
|
31
31
|
type: array
|
|
32
32
|
default: []
|
|
33
|
+
dynamic: true # JS-set collection prop with a custom setter — deliberately not in static properties
|
|
33
34
|
layout:
|
|
34
35
|
description: "stacked: term above description. inline: term and description on one row."
|
|
35
36
|
type: string
|
|
@@ -245,6 +245,7 @@ export class UIField extends UIElement {
|
|
|
245
245
|
|
|
246
246
|
/** The default-slot control — first child without a `slot` attribute. */
|
|
247
247
|
#findControl() {
|
|
248
|
+
// wrapper-trap-ok: field control is always a single literal child (one <input>/<textarea>/<select>); interpolating the control via .map() is not a documented field pattern
|
|
248
249
|
for (const ch of this.children) {
|
|
249
250
|
if (!ch.hasAttribute('slot')) return ch;
|
|
250
251
|
}
|
|
@@ -81,6 +81,7 @@ export class UIFields extends UIElement {
|
|
|
81
81
|
|
|
82
82
|
#syncInline() {
|
|
83
83
|
const inline = this.hasAttribute('inline');
|
|
84
|
+
// wrapper-trap-ok: fields-ui children are authored as static field-ui literals within a form group; dynamic .map() field collections use the programmatic API
|
|
84
85
|
for (const child of this.children) {
|
|
85
86
|
if (child.localName !== 'field-ui') continue;
|
|
86
87
|
if (inline) {
|
|
@@ -23,6 +23,7 @@ props:
|
|
|
23
23
|
in a 2-column hero. Sets grid-item alignment, NOT text alignment.
|
|
24
24
|
type: string
|
|
25
25
|
default: stretch
|
|
26
|
+
reflect: false # declarative presentational attribute — CSS/author-time read, non-reactive by design
|
|
26
27
|
columnGap:
|
|
27
28
|
description: Column gap override
|
|
28
29
|
type: string
|
|
@@ -50,6 +51,7 @@ props:
|
|
|
50
51
|
justify-items. Default stretch (items fill their column track).
|
|
51
52
|
type: string
|
|
52
53
|
default: stretch
|
|
54
|
+
reflect: false # declarative presentational attribute — CSS/author-time read, non-reactive by design
|
|
53
55
|
minColumnWidth:
|
|
54
56
|
description: >-
|
|
55
57
|
Minimum track width for columns="auto-fit"/"auto-fill" (any CSS length,
|
|
@@ -40,8 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"autocomplete": {
|
|
42
42
|
"description": "Browser autofill behavior per HTML autocomplete spec. Routed via setAttribute to the host element. Common values: off, on, cc-number, cc-exp, cc-csc, cc-name, email, username, current-password, new-password, one-time-code, given-name, family-name, street-address, postal-code.",
|
|
43
|
-
"
|
|
44
|
-
"default": ""
|
|
43
|
+
"$ref": "common_types.json#/$defs/DynamicString"
|
|
45
44
|
},
|
|
46
45
|
"component": {
|
|
47
46
|
"const": "Input"
|
|
@@ -58,18 +57,7 @@
|
|
|
58
57
|
},
|
|
59
58
|
"inputmode": {
|
|
60
59
|
"description": "Mobile keyboard hint per HTML inputmode spec. Routed via setAttribute to the host element. Values: text, decimal, numeric, tel, search, email, url.",
|
|
61
|
-
"
|
|
62
|
-
"enum": [
|
|
63
|
-
"text",
|
|
64
|
-
"decimal",
|
|
65
|
-
"numeric",
|
|
66
|
-
"tel",
|
|
67
|
-
"search",
|
|
68
|
-
"email",
|
|
69
|
-
"url",
|
|
70
|
-
"none"
|
|
71
|
-
],
|
|
72
|
-
"default": null
|
|
60
|
+
"$ref": "common_types.json#/$defs/DynamicString"
|
|
73
61
|
},
|
|
74
62
|
"label": {
|
|
75
63
|
"description": "Inline label rendered as a leading caption inside the input chrome, between any prefix and the value. Wires aria-labelledby on the editable surface. For stacked label / hint / error compositions, wrap with field-ui.",
|
|
@@ -80,12 +80,14 @@ props:
|
|
|
80
80
|
- email
|
|
81
81
|
- url
|
|
82
82
|
- none
|
|
83
|
+
dynamic: true # native attr — routed via setAttribute to the host, deliberately NOT in static properties (would clobber native reflection)
|
|
83
84
|
autocomplete:
|
|
84
85
|
description: 'Browser autofill behavior per HTML autocomplete spec. Routed via setAttribute to the host element. Common
|
|
85
86
|
values: off, on, cc-number, cc-exp, cc-csc, cc-name, email, username, current-password, new-password, one-time-code,
|
|
86
87
|
given-name, family-name, street-address, postal-code.'
|
|
87
88
|
type: string
|
|
88
89
|
default: ''
|
|
90
|
+
dynamic: true # native attr — routed via setAttribute to the host, deliberately NOT in static properties (would clobber native reflection)
|
|
89
91
|
min:
|
|
90
92
|
description: Minimum numeric value. Applies when `type="number"`. Clamps + drives aria-valuemin + the [-] button's disabled
|
|
91
93
|
state.
|
|
@@ -226,6 +226,7 @@ export class UIIntegrationCard extends UIElement {
|
|
|
226
226
|
#hasConsumerDescription() {
|
|
227
227
|
// Author description = direct child element that is neither one of our
|
|
228
228
|
// stamped data- markers nor an [slot="actions"] / [slot="action"] node.
|
|
229
|
+
// wrapper-trap-ok: detects presence of consumer-provided description; wrapper spans from interpolated content also qualify as "consumer description present" (correct — the content IS there)
|
|
229
230
|
for (const child of this.children) {
|
|
230
231
|
if (child === this.#bodyEl) continue;
|
|
231
232
|
if (child === this.#descEl) continue;
|
|
@@ -174,6 +174,7 @@ export class UIListItem extends UIElement {
|
|
|
174
174
|
// otherwise we'd accidentally remove e.g. a <span slot="icon"> inside a
|
|
175
175
|
// child <card-ui> when list-item-ui has no `icon` prop.
|
|
176
176
|
#ownChild(selector) {
|
|
177
|
+
// wrapper-trap-ok: finds component-stamped children (identified by [data-list-stamped]) — consumer list-item-ui children are never queried here
|
|
177
178
|
for (const ch of this.children) {
|
|
178
179
|
if (ch.matches(selector)) return ch;
|
|
179
180
|
}
|
|
@@ -34,6 +34,7 @@ props:
|
|
|
34
34
|
so content sits at the list-ui edges (canonical edge-to-edge style).
|
|
35
35
|
type: boolean
|
|
36
36
|
default: false
|
|
37
|
+
reflect: false # declarative presentational attribute — CSS/author-time read, non-reactive by design
|
|
37
38
|
selectable:
|
|
38
39
|
description: Enable selection on child listitems (roving tabindex + aria-selected).
|
|
39
40
|
type: boolean
|
|
@@ -290,6 +290,7 @@ export class UIMenuItem extends UIElement {
|
|
|
290
290
|
#wasStamped(el) { return el?.dataset?.menuItemStamped === '1'; }
|
|
291
291
|
|
|
292
292
|
#ownChild(selector) {
|
|
293
|
+
// wrapper-trap-ok: finds component-stamped children (data-menuItemStamped); consumer menu-item-ui children are adopted by #show() using logical children
|
|
293
294
|
for (const ch of this.children) {
|
|
294
295
|
if (ch.matches(selector)) return ch;
|
|
295
296
|
}
|
package/components/menu/menu.css
CHANGED
|
@@ -21,9 +21,21 @@
|
|
|
21
21
|
|
|
22
22
|
/* Items/dividers in Light DOM are hidden unless they've been adopted
|
|
23
23
|
into the popover on open. Popover API also hides the popover itself
|
|
24
|
-
when closed.
|
|
24
|
+
when closed.
|
|
25
|
+
|
|
26
|
+
FB-97: interpolated items (`.map()` / `repeat()`) arrive nested in the
|
|
27
|
+
template engine's `display:contents` / `role="presentation"` wrapper
|
|
28
|
+
span (core/template.js), so the direct-child combinator alone misses
|
|
29
|
+
them on the initial (never-opened) render — a CLOSED declarative menu
|
|
30
|
+
would lay them out in flow and balloon to its widest item's width,
|
|
31
|
+
displacing siblings. The wrapper-piercing descendant selectors hide
|
|
32
|
+
those too. Safe vs. the open state: #show() appendChild's the real
|
|
33
|
+
items (not the wrappers) into [data-menu-popover], so open-state items
|
|
34
|
+
are neither `:scope >` children nor under a `:scope > [role]` wrapper. */
|
|
25
35
|
:scope > menu-item-ui,
|
|
26
|
-
:scope > menu-divider-ui
|
|
36
|
+
:scope > menu-divider-ui,
|
|
37
|
+
:scope > [role="presentation"] menu-item-ui,
|
|
38
|
+
:scope > [role="presentation"] menu-divider-ui {
|
|
27
39
|
display: none;
|
|
28
40
|
}
|
|
29
41
|
}
|