@rcarls/rc-menu-button 0.4.2 → 0.6.0

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 CHANGED
@@ -1,5 +1,64 @@
1
1
  # @rcarls/rc-menu-button
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 30eb232: Add icon-only activation-area sizing and Material icon-button variants. Align menu
8
+ selection and submenu affordances, and keep anchored popups within the viewport
9
+ across native and fallback positioning.
10
+ - 30eb232: Add `--rc-menu-button-touch-target-overlap-inline-start` and
11
+ `-inline-end` for an `icon-only` trigger, zero by default. A theme or
12
+ consumer sets one to let the accessible touch-target inflation on that
13
+ side overlap into whatever sits just outside the host, such as a toolbar's
14
+ own edge padding, instead of also reserving layout space there: the
15
+ visible trigger shifts flush with that edge while the invisible hit
16
+ region keeps its full accessible size. Mirrors `@rcarls/rc-button`'s own
17
+ touch-target overlap tokens.
18
+
19
+ ### Patch Changes
20
+
21
+ - 7382c71: Add a priority-aware action toolbar that moves original controls into an
22
+ overflow menu. Which actions are promoted is a purely declarative computation
23
+ from `max-shown` and each action's `data-priority`/authored `slot`, with no
24
+ runtime measurement of the toolbar's or its children's rendered size: a
25
+ consumer whose promoted count needs to react to available space owns that
26
+ decision and writes the resulting `max-shown` value down. Include controlled
27
+ and uncontrolled open state, keyboard navigation, light dismissal, and a
28
+ non-Popover fallback.
29
+
30
+ Fix `--rc-adaptive-menu-touch-target-overlap-inline-start`/`-end`: the host's
31
+ own `max-inline-size: 100%` self-referenced a shrink-to-fit ancestor's
32
+ already-margin-reduced auto size (an app bar's own trailing group, for
33
+ example), quietly clamping the host back down and canceling the overlap out
34
+ from under it. The cap now grows by the overlap amount so it only ever bounds
35
+ the host's real content.
36
+
37
+ - 57370e4: Align component metadata, aggregate framework typings, development-time native-child
38
+ validation, controlled menu state, package declarations, and public documentation before the
39
+ next release.
40
+ - Updated dependencies [7382c71]
41
+ - Updated dependencies [6683eb9]
42
+ - Updated dependencies [ee7ba6c]
43
+ - Updated dependencies [30eb232]
44
+ - @rcarls/rc-menu@0.6.0
45
+ - @rcarls/rc-common@0.6.0
46
+
47
+ ## 0.5.0
48
+
49
+ ### Minor Changes
50
+
51
+ - d33b92f: Use the native Popover API for the popup panel instead of a `hidden` attribute
52
+ and `z-index`. Removes `--rc-menu-button-popup-z-index`; stacking is now
53
+ governed by top-layer insertion order.
54
+
55
+ ### Patch Changes
56
+
57
+ - Updated dependencies [4ae2ef0]
58
+ - Updated dependencies [689340c]
59
+ - @rcarls/rc-common@0.5.0
60
+ - @rcarls/rc-menu@0.5.0
61
+
3
62
  ## 0.4.2
4
63
 
5
64
  ### Patch Changes
package/README.md CHANGED
@@ -18,8 +18,8 @@ npm install @rcarls/rc-menu-button
18
18
  ## Import
19
19
 
20
20
  ```js
21
- import '@rcarls/rc-menu-button/define'; // side-effect: registers <rc-menu-button>
22
- import { RCMenuButton } from '@rcarls/rc-menu-button'; // named class export
21
+ import '@rcarls/rc-menu-button/define'; // side-effect: registers <rc-menu-button>
22
+ import { RCMenuButton } from '@rcarls/rc-menu-button'; // named class export
23
23
  ```
24
24
 
25
25
  `rc-menu-button` depends on `rc-menu`. Ensure both are installed.
@@ -53,57 +53,62 @@ item.
53
53
 
54
54
  ### Properties / attributes
55
55
 
56
- | Property | Attribute | Type | Default | Description |
57
- |---|---|---|---|---|
58
- | `open` | `open` | `boolean` | `false` | Whether the menu popup is visible. Reflects to attribute. Controlled mode: host writes silently. |
59
- | `defaultOpen` | `default-open` | `boolean` | `false` | Initial open state for uncontrolled mode. Ignored after the first controlled write to `open`. |
60
- | `orientation` | `orientation` | `'horizontal' \| 'vertical' \| undefined` | `undefined` | Arrow-key axis for opening the menu. When unset, inherited from a parent `rc-menubar` or `[role="menubar"]` element. Falls back to `'horizontal'`. |
61
- | `placement` | `placement` | `AnchorPlacement` | `'bottom-start'` | Preferred placement of the popup relative to the trigger. Switches to `'right-start'` under vertical orientation unless explicitly overridden. |
56
+ | Property | Attribute | Type | Default | Description |
57
+ | ------------- | -------------- | ----------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
58
+ | `open` | `open` | `boolean` | `false` | Whether the menu popup is visible. Reflects to attribute. Controlled mode: host writes silently. |
59
+ | `defaultOpen` | `default-open` | `boolean` | `false` | Initial open state for uncontrolled mode. Ignored after the first controlled write to `open`. |
60
+ | `orientation` | `orientation` | `'horizontal' \| 'vertical' \| undefined` | `undefined` | Arrow-key axis for opening the menu. Vertical triggers span their allocated menu-row width. When unset, inherited from a parent `rc-menubar` or `[role="menubar"]` element. Falls back to `'horizontal'`. |
61
+ | `placement` | `placement` | `AnchorPlacement` | `'bottom-start'` | Preferred placement of the popup relative to the trigger. Switches to `'right-start'` under vertical orientation unless explicitly overridden. |
62
+ | | `icon-only` | boolean attribute | absent | Hints that the trigger has no visible label so themes can apply icon-button sizing and activation-area geometry. |
62
63
 
63
64
  ### CSS custom properties
64
65
 
65
- | Property | Default | Description |
66
- |---|---|---|
67
- | `--rc-menu-button-trigger-block-size` | `var(--rc-control-block-size)` | Minimum block size of the trigger |
68
- | `--rc-menu-button-trigger-padding-block` | `var(--rc-control-padding-block)` | Trigger block-axis padding |
69
- | `--rc-menu-button-trigger-padding-inline` | `var(--rc-control-padding-inline)` | Trigger inline-axis padding |
70
- | `--rc-menu-button-trigger-gap` | `var(--rc-item-gap)` | Gap between flex children inside the trigger |
71
- | `--rc-menu-button-trigger-border` | `var(--rc-border)` | Trigger border |
72
- | `--rc-menu-button-trigger-radius` | `var(--rc-control-radius)` | Trigger border radius |
73
- | `--rc-menu-button-trigger-background` | `var(--rc-button-bg)` | Trigger background |
74
- | `--rc-menu-button-trigger-color` | `var(--rc-button-text)` | Trigger text color |
75
- | `--rc-menu-button-trigger-transition` | `none` | Trigger state transition |
76
- | `--rc-menu-button-trigger-hover-background` | `color-mix(in srgb, Highlight 8%, transparent)` | Trigger hover background |
77
- | `--rc-menu-button-trigger-hover-color` | `inherit` | Trigger hover text color |
78
- | `--rc-menu-button-trigger-hover-border-color` | `currentColor` | Trigger hover border color |
79
- | `--rc-menu-button-trigger-open-background` | `color-mix(in srgb, Highlight 12%, transparent)` | Trigger background while the menu is open |
80
- | `--rc-menu-button-trigger-open-color` | `inherit` | Trigger text color while the menu is open |
81
- | `--rc-menu-button-trigger-open-border-color` | `currentColor` | Trigger border color while the menu is open |
82
- | `--rc-menu-button-indicator-size` | `1em` | Inline and block size reserved for the optional indicator |
83
- | `--rc-menu-button-indicator-color` | `currentColor` | Color of the optional indicator |
84
- | `--rc-menu-button-indicator-inset` | Trigger inline padding | Indicator distance from the trigger's inline end |
85
- | `--rc-menu-button-popup-z-index` | `1000` | `z-index` of the popup container |
66
+ | Property | Default | Description |
67
+ | ---------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------- |
68
+ | `--rc-menu-button-trigger-block-size` | `var(--rc-control-block-size)` | Minimum block size of the trigger |
69
+ | `--rc-menu-button-trigger-padding-block` | `var(--rc-control-padding-block)` | Trigger block-axis padding |
70
+ | `--rc-menu-button-trigger-padding-inline` | `var(--rc-control-padding-inline)` | Trigger inline-axis padding |
71
+ | `--rc-menu-button-trigger-gap` | `var(--rc-item-gap)` | Gap between flex children inside the trigger |
72
+ | `--rc-menu-button-trigger-border` | `var(--rc-border)` | Trigger border |
73
+ | `--rc-menu-button-trigger-radius` | `var(--rc-control-radius)` | Trigger border radius |
74
+ | `--rc-menu-button-trigger-background` | `var(--rc-button-bg)` | Trigger background |
75
+ | `--rc-menu-button-trigger-color` | `var(--rc-button-text)` | Trigger text color |
76
+ | `--rc-menu-button-trigger-transition` | `none` | Trigger state transition |
77
+ | `--rc-menu-button-trigger-hover-background` | `color-mix(in srgb, Highlight 8%, transparent)` | Trigger hover background |
78
+ | `--rc-menu-button-trigger-hover-color` | `inherit` | Trigger hover text color |
79
+ | `--rc-menu-button-trigger-hover-border-color` | `currentColor` | Trigger hover border color |
80
+ | `--rc-menu-button-trigger-open-background` | `color-mix(in srgb, Highlight 12%, transparent)` | Trigger background while the menu is open |
81
+ | `--rc-menu-button-trigger-open-color` | `inherit` | Trigger text color while the menu is open |
82
+ | `--rc-menu-button-trigger-open-border-color` | `currentColor` | Trigger border color while the menu is open |
83
+ | `--rc-menu-button-indicator-size` | `1em` | Inline and block size reserved for the optional indicator |
84
+ | `--rc-menu-button-indicator-color` | `currentColor` | Color of the optional indicator |
85
+ | `--rc-menu-button-indicator-inset` | Trigger inline padding | Indicator distance from the trigger's inline end |
86
+ | `--rc-menu-button-icon-size` | Trigger block size | Visible inline size of an `icon-only` trigger |
87
+ | `--rc-menu-button-touch-target-block-size` | `3rem` | Minimum block size of an `icon-only` trigger's activation area |
88
+ | `--rc-menu-button-touch-target-inline-size` | Activation-area block size | Minimum inline size of an `icon-only` trigger's activation area |
89
+ | `--rc-menu-button-touch-target-overlap-inline-start` | `0px` | Allows touch-target inflation to overlap the leading neighbor |
90
+ | `--rc-menu-button-touch-target-overlap-inline-end` | `0px` | Allows touch-target inflation to overlap the trailing neighbor |
86
91
 
87
92
  ### CSS parts
88
93
 
89
- | Part | Element | Description |
90
- |---|---|---|
91
- | `root` | Outer `div` | Root wrapper |
94
+ | Part | Element | Description |
95
+ | ------- | ----------- | ------------------------------------------------------- |
96
+ | `root` | Outer `div` | Root wrapper |
92
97
  | `popup` | Popup `div` | Container that shows/hides around the slotted `rc-menu` |
93
98
 
94
99
  ### Slots
95
100
 
96
- | Slot | Description |
97
- |---|---|
98
- | `trigger` | The button (or other interactive element) that toggles the menu. Receives `aria-haspopup` and `aria-expanded` automatically. |
101
+ | Slot | Description |
102
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
103
+ | `trigger` | The button (or other interactive element) that toggles the menu. Receives `aria-haspopup` and `aria-expanded` automatically. |
99
104
  | `indicator` | Optional author-supplied decorative submenu indicator. Rendered at the trigger's inline end with pointer events passed through to the trigger. |
100
- | *(default)* | The `rc-menu` to show as the popup. |
105
+ | _(default)_ | The `rc-menu` to show as the popup. |
101
106
 
102
107
  ### Events
103
108
 
104
- | Event | Bubbles | Cancelable | Detail | When |
105
- |---|---|---|---|---|
106
- | `rc-menu-button-toggle` | Yes (composed) | No | `{ open: boolean }` | Menu opens or closes |
109
+ | Event | Bubbles | Cancelable | Detail | When |
110
+ | ----------------------- | -------------- | ---------- | ------------------- | -------------------- |
111
+ | `rc-menu-button-toggle` | Yes (composed) | No | `{ open: boolean }` | Menu opens or closes |
107
112
 
108
113
  ### Public methods
109
114
 
@@ -125,25 +130,25 @@ toggleMenu(): void
125
130
  Keyboard handling depends on the resolved `orientation` (horizontal by
126
131
  default, or inherited from a parent menubar).
127
132
 
128
- | Key | Condition | Action |
129
- |---|---|---|
130
- | `ArrowDown` | Horizontal orientation | Open menu, focus first item |
131
- | `ArrowUp` | Horizontal orientation | Open menu, focus last item |
132
- | `ArrowRight` | Vertical orientation | Open menu, focus first item |
133
- | `ArrowLeft` | Vertical orientation | Open menu, focus last item |
134
- | `Enter` / `Space` | Menu closed | Open menu |
135
- | `Enter` / `Space` | Menu open | Activate focused item, close menu |
136
- | `Escape` | Menu open | Close menu, return focus to trigger |
133
+ | Key | Condition | Action |
134
+ | ----------------- | ---------------------- | ----------------------------------- |
135
+ | `ArrowDown` | Horizontal orientation | Open menu, focus first item |
136
+ | `ArrowUp` | Horizontal orientation | Open menu, focus last item |
137
+ | `ArrowRight` | Vertical orientation | Open menu, focus first item |
138
+ | `ArrowLeft` | Vertical orientation | Open menu, focus last item |
139
+ | `Enter` / `Space` | Menu closed | Open menu |
140
+ | `Enter` / `Space` | Menu open | Activate focused item, close menu |
141
+ | `Escape` | Menu open | Close menu, return focus to trigger |
137
142
 
138
143
  ---
139
144
 
140
145
  ## ARIA
141
146
 
142
- | Attribute | Where | Value |
143
- |---|---|---|
144
- | `aria-haspopup="menu"` | Trigger element | Set automatically on slot change |
145
- | `aria-expanded` | Trigger element | `"true"` / `"false"`, kept in sync with `open` |
146
- | `open` | Host element | Reflected boolean attribute when menu is open |
147
+ | Attribute | Where | Value |
148
+ | ---------------------- | --------------- | ---------------------------------------------- |
149
+ | `aria-haspopup="menu"` | Trigger element | Set automatically on slot change |
150
+ | `aria-expanded` | Trigger element | `"true"` / `"false"`, kept in sync with `open` |
151
+ | `open` | Host element | Reflected boolean attribute when menu is open |
147
152
 
148
153
  ---
149
154
 
@@ -35,7 +35,7 @@
35
35
  "name": "*",
36
36
  "declaration": {
37
37
  "name": "*",
38
- "module": "src/rc-menu-button"
38
+ "module": "src/rc-menu-button.js"
39
39
  }
40
40
  }
41
41
  ]
@@ -139,9 +139,27 @@
139
139
  "default": "var(--rc-menu-button-trigger-padding-inline)"
140
140
  },
141
141
  {
142
- "description": "Z-index of the popup overlay",
143
- "name": "--rc-menu-button-popup-z-index",
144
- "default": "1000"
142
+ "description": "Inline size of an `icon-only` trigger's visible box. Square by default (equal to `--rc-menu-button-trigger-block-size`); set narrower or wider to change only the trigger's width, independent of its height.",
143
+ "name": "--rc-menu-button-icon-size"
144
+ },
145
+ {
146
+ "description": "Minimum accessible touch target block size for an `icon-only` trigger. A floor, not a fixed size: has no effect once `--rc-menu-button-trigger-block-size` already meets or exceeds it. Grows the shadow-DOM trigger wrapper (reserving layout space) and the light-DOM hit-slop (the actual larger clickable region) together; the visible trigger itself stays at its own size, centered.",
147
+ "name": "--rc-menu-button-touch-target-block-size",
148
+ "default": "3rem"
149
+ },
150
+ {
151
+ "description": "Minimum accessible touch target inline size for an `icon-only` trigger. Defers to `--rc-menu-button-touch-target-block-size` when unset.",
152
+ "name": "--rc-menu-button-touch-target-inline-size"
153
+ },
154
+ {
155
+ "description": "Zero by default. A theme or consumer sets this on an `icon-only` trigger that sits at a real leading edge (no neighbor on that side) to let its touch-target inflation overlap into whatever sits just outside the host, such as a container's own edge padding, instead of also reserving layout space there.",
156
+ "name": "--rc-menu-button-touch-target-overlap-inline-start",
157
+ "default": "0px"
158
+ },
159
+ {
160
+ "description": "The trailing-edge counterpart to `--rc-menu-button-touch-target-overlap-inline-start`.",
161
+ "name": "--rc-menu-button-touch-target-overlap-inline-end",
162
+ "default": "0px"
145
163
  }
146
164
  ],
147
165
  "cssParts": [
@@ -179,6 +197,33 @@
179
197
  "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true, }",
180
198
  "description": "Enables delegatesFocus so the browser routes focus() on the host element\nto the slotted trigger button."
181
199
  },
200
+ {
201
+ "kind": "field",
202
+ "name": "_styledRoots",
203
+ "privacy": "protected",
204
+ "static": true,
205
+ "readonly": true,
206
+ "default": "new Set<Document | ShadowRoot>()"
207
+ },
208
+ {
209
+ "kind": "method",
210
+ "name": "_ensureBaseStyles",
211
+ "privacy": "protected",
212
+ "static": true,
213
+ "return": {
214
+ "type": {
215
+ "text": "void"
216
+ }
217
+ },
218
+ "parameters": [
219
+ {
220
+ "name": "root",
221
+ "type": {
222
+ "text": "Document | ShadowRoot"
223
+ }
224
+ }
225
+ ]
226
+ },
182
227
  {
183
228
  "kind": "field",
184
229
  "name": "_defaultOpen",
@@ -192,10 +237,17 @@
192
237
  "kind": "field",
193
238
  "name": "_open",
194
239
  "type": {
195
- "text": "boolean"
240
+ "text": "boolean | undefined"
196
241
  },
197
- "privacy": "private",
198
- "default": "false"
242
+ "privacy": "private"
243
+ },
244
+ {
245
+ "kind": "field",
246
+ "name": "_uncontrolledOpen",
247
+ "type": {
248
+ "text": "boolean | undefined"
249
+ },
250
+ "privacy": "private"
199
251
  },
200
252
  {
201
253
  "kind": "field",
@@ -360,7 +412,13 @@
360
412
  "kind": "method",
361
413
  "name": "_dispatchToggle",
362
414
  "privacy": "protected",
363
- "description": "Dispatches the `rc-menu-button-toggle` bubbling composed event with the current open state."
415
+ "parameters": [
416
+ {
417
+ "name": "open",
418
+ "default": "this.open"
419
+ }
420
+ ],
421
+ "description": "Dispatches the `rc-menu-button-toggle` bubbling composed event with the requested open state."
364
422
  },
365
423
  {
366
424
  "kind": "method",
@@ -548,6 +606,10 @@
548
606
  },
549
607
  "default": "'bottom-start'",
550
608
  "fieldName": "placement"
609
+ },
610
+ {
611
+ "description": "Hints that the slotted trigger has no visible label, so themes can size it and its touch target as an icon button (see `--rc-menu-button-icon-size` and `--rc-menu-button-touch-target-*` above). Purely a styling hook; RCMenuButton does not read or derive it — set it whenever the trigger is rendered icon-only.",
612
+ "name": "icon-only"
551
613
  }
552
614
  ],
553
615
  "superclass": {
@@ -1,7 +1,7 @@
1
- import { css as h, LitElement as d, html as b } from "lit";
2
- import { property as l, query as g, state as p } from "lit/decorators.js";
1
+ import { css as p, LitElement as g, html as b } from "lit";
2
+ import { property as l, query as d, state as h } from "lit/decorators.js";
3
3
  import { AnchorController as m, keyNavigation as v, keyInteraction as f } from "@rcarls/rc-common";
4
- const _ = h`
4
+ const y = p`
5
5
  :host {
6
6
  display: inline-block;
7
7
  }
@@ -16,6 +16,7 @@ const _ = h`
16
16
 
17
17
  :host([orientation='vertical']) #root {
18
18
  display: block;
19
+ inline-size: 100%;
19
20
  }
20
21
 
21
22
  #trigger-wrap {
@@ -25,10 +26,73 @@ const _ = h`
25
26
 
26
27
  :host([orientation='vertical']) #trigger-wrap {
27
28
  display: block;
29
+ inline-size: 100%;
30
+ }
31
+
32
+ /*
33
+ * Icon-only triggers (e.g. a toolbar's overflow button) can render
34
+ * visually smaller than the accessible 48dp touch-target minimum,
35
+ * especially at a narrow width. This is a floor, not a fixed size: a
36
+ * trigger already at or above it (the default width, or a labeled
37
+ * trigger) is unaffected. #trigger-wrap reserves the layout space and
38
+ * centers the (possibly smaller) slotted trigger within it; the actual
39
+ * larger hit region comes from the light-DOM hit-slop pseudo-element in
40
+ * rc-menu-button.ts. Mirrors rc-button's own touch-target affordance.
41
+ *
42
+ * Scoped to [icon-only] rather than applied unconditionally: switching
43
+ * #trigger-wrap to a flex/grid container would blockify the slotted
44
+ * trigger's own inline-flex display (its getComputedStyle().display
45
+ * becomes "flex", per the CSS Display spec's flex-item blockification —
46
+ * harmless for layout, since a flex item is sized by its container's
47
+ * flex algorithm regardless of its own inline/block outer type, but an
48
+ * observable change other callers shouldn't have to account for).
49
+ */
50
+ :host([icon-only]) #trigger-wrap {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ min-block-size: var(--rc-menu-button-touch-target-block-size, 3rem);
55
+ min-inline-size: var(
56
+ --rc-menu-button-touch-target-inline-size,
57
+ var(--rc-menu-button-touch-target-block-size, 3rem)
58
+ );
59
+ /*
60
+ * Zero by default. A theme or consumer sets one of these on a trigger
61
+ * that sits at a real edge (no neighbor on that side) to let the
62
+ * touch-target inflation above overlap into whatever sits just outside
63
+ * the host instead of also reserving layout space there. Mirrors
64
+ * rc-button's own --rc-button-touch-target-overlap-inline-* tokens.
65
+ */
66
+ margin-inline-start: calc(-1 * var(--rc-menu-button-touch-target-overlap-inline-start, 0px));
67
+ margin-inline-end: calc(-1 * var(--rc-menu-button-touch-target-overlap-inline-end, 0px));
68
+ }
69
+
70
+ :host([icon-only][orientation='vertical']) #trigger-wrap {
71
+ display: flex;
72
+ }
73
+
74
+ /*
75
+ * Icon-only trigger width: square by default (matches its own block
76
+ * size), or a distinct value for a narrower/wider variant. Padding is
77
+ * cleared since an icon-only trigger centers its (typically single) icon
78
+ * child via the flex alignment above rather than via inline padding.
79
+ */
80
+ :host([icon-only]) slot[name='trigger']::slotted(button),
81
+ :host([icon-only]) slot[name='trigger']::slotted([role='button']) {
82
+ inline-size: var(
83
+ --rc-menu-button-icon-size,
84
+ var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em))
85
+ );
86
+ min-inline-size: var(
87
+ --rc-menu-button-icon-size,
88
+ var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em))
89
+ );
90
+ padding-inline: 0;
28
91
  }
29
92
 
30
93
  slot[name='trigger']::slotted(button),
31
94
  slot[name='trigger']::slotted([role='button']) {
95
+ position: relative;
32
96
  display: inline-flex;
33
97
  align-items: center;
34
98
  justify-content: center;
@@ -110,21 +174,56 @@ const _ = h`
110
174
  }
111
175
 
112
176
  #popup {
113
- z-index: var(--rc-menu-button-popup-z-index, 1000);
114
- }
115
-
116
- #popup[hidden] {
117
- display: none;
177
+ margin: 0;
178
+ padding: 0;
179
+ border: none;
180
+ background: none;
181
+ overflow: visible;
182
+ color: inherit;
118
183
  }
119
184
  `;
120
- var $ = Object.defineProperty, k = Object.getOwnPropertyDescriptor, o = (u, t, e, r) => {
121
- for (var n = r > 1 ? void 0 : r ? k(t, e) : t, s = u.length - 1, c; s >= 0; s--)
122
- (c = u[s]) && (n = (r ? c(t, e, n) : c(n)) || n);
123
- return r && n && $(t, e, n), n;
185
+ var _ = Object.defineProperty, k = Object.getOwnPropertyDescriptor, a = (u, t, e, n) => {
186
+ for (var i = n > 1 ? void 0 : n ? k(t, e) : t, s = u.length - 1, c; s >= 0; s--)
187
+ (c = u[s]) && (i = (n ? c(t, e, i) : c(i)) || i);
188
+ return n && i && _(t, e, i), i;
124
189
  };
125
- const a = class a extends d {
190
+ const x = `
191
+ @layer rc-base {
192
+ /*
193
+ * Expands an icon-only trigger's clickable region beyond its visible box
194
+ * up to the accessible touch-target minimum, the same way rc-button and
195
+ * rc-chip do: an absolutely-positioned, invisible pseudo-element on the
196
+ * actual slotted trigger element (not the host) extends the hit area
197
+ * symmetrically. The trigger already has position: relative from the
198
+ * shadow-scoped ::slotted(button) rule. max(100%, size) keeps this a
199
+ * no-op once the visible trigger already meets or exceeds the touch
200
+ * target, rather than shrinking it.
201
+ */
202
+ rc-menu-button[icon-only] > [slot='trigger']::before {
203
+ content: '';
204
+ position: absolute;
205
+ inset-block: calc(
206
+ (
207
+ var(--rc-menu-button-touch-target-block-size, 3rem) -
208
+ max(100%, var(--rc-menu-button-trigger-block-size, 0px))
209
+ ) / -2
210
+ );
211
+ inset-inline: calc(
212
+ (
213
+ var(
214
+ --rc-menu-button-touch-target-inline-size,
215
+ var(--rc-menu-button-touch-target-block-size, 3rem)
216
+ ) -
217
+ max(100%, var(--rc-menu-button-icon-size, var(--rc-menu-button-trigger-block-size, 0px)))
218
+ ) / -2
219
+ );
220
+ }
221
+ }
222
+ `;
223
+ var r;
224
+ const o = (r = class extends g {
126
225
  constructor() {
127
- super(...arguments), this._defaultOpen = !1, this._open = !1, this._openInitialized = !1, this.placement = "bottom-start", this._anchorCtrl = new m(this, {
226
+ super(...arguments), this._defaultOpen = !1, this._openInitialized = !1, this.placement = "bottom-start", this._anchorCtrl = new m(this, {
128
227
  anchor: () => this._$root ?? null,
129
228
  floating: () => this._$popup ?? null,
130
229
  shadowHost: () => this,
@@ -145,13 +244,20 @@ const a = class a extends d {
145
244
  }
146
245
  };
147
246
  }
247
+ static _ensureBaseStyles(t) {
248
+ if (r._styledRoots.has(t))
249
+ return;
250
+ r._styledRoots.add(t);
251
+ const e = document.createElement("style");
252
+ e.setAttribute("data-rc-light-dom-base", "rc-menu-button"), e.textContent = x, t instanceof Document ? t.head.append(e) : t.append(e);
253
+ }
148
254
  get open() {
149
- return this._open;
255
+ return this._open ?? this._uncontrolledOpen ?? this._defaultOpen;
150
256
  }
151
257
  /** Applies open state in controlled mode without dispatching an event. */
152
258
  set open(t) {
153
- const e = this._open;
154
- t !== void 0 && (this._openInitialized = !0, this._setOpen(t, !1), this.requestUpdate("open", e));
259
+ const e = this.open;
260
+ this._open = t, this._openInitialized = !0, this.requestUpdate("open", e), this._syncTriggerAria();
155
261
  }
156
262
  get defaultOpen() {
157
263
  return this._defaultOpen;
@@ -159,7 +265,7 @@ const a = class a extends d {
159
265
  /** Applies the uncontrolled default before any controlled write occurs. */
160
266
  set defaultOpen(t) {
161
267
  const e = this._defaultOpen;
162
- this._defaultOpen = t, t && !this._openInitialized && this._setOpen(!0, !1), this.requestUpdate("defaultOpen", e);
268
+ this._defaultOpen = t, !this._openInitialized && this._open === void 0 && this._uncontrolledOpen === void 0 && this.requestUpdate("open", e), this.requestUpdate("defaultOpen", e);
163
269
  }
164
270
  /**
165
271
  * Popup placement adjusted for orientation.
@@ -189,7 +295,7 @@ const a = class a extends d {
189
295
  }
190
296
  /** Installs the tabindex mutation observer and the document-level click listener. */
191
297
  connectedCallback() {
192
- super.connectedCallback(), this._tabObserver = new MutationObserver(() => this._syncTriggerTabindex()), this._tabObserver.observe(this, { attributes: !0, attributeFilter: ["tabindex"] }), document.addEventListener("click", this._boundHandleDocumentClick, !0), this.defaultOpen && this._setOpen(!0, !1);
298
+ super.connectedCallback(), r._ensureBaseStyles(this.getRootNode()), this._tabObserver = new MutationObserver(() => this._syncTriggerTabindex()), this._tabObserver.observe(this, { attributes: !0, attributeFilter: ["tabindex"] }), document.addEventListener("click", this._boundHandleDocumentClick, !0), this.requestUpdate("open");
193
299
  }
194
300
  /** Disconnects the tabindex observer and removes the document-level click listener. */
195
301
  disconnectedCallback() {
@@ -201,7 +307,9 @@ const a = class a extends d {
201
307
  * @param focusTarget - which item receives initial focus when the menu opens
202
308
  */
203
309
  openMenu(t = "first") {
204
- this.open || (this._anchorCtrl.setOptions({ placement: this._effectivePlacement }), this._setOpen(!0, !0), this._anchorCtrl.update(), this.updateComplete.then(() => {
310
+ this.open || (this._anchorCtrl.setOptions({ placement: this._effectivePlacement }), this._setOpen(!0, !0), this.updateComplete.then(() => {
311
+ if (!this.open)
312
+ return;
205
313
  const e = this._$menu?.deref();
206
314
  t === "last" ? e?.focusLast() : e?.focusFirst();
207
315
  }));
@@ -212,26 +320,26 @@ const a = class a extends d {
212
320
  * @param returnFocus - when `true`, returns focus to the trigger button after closing
213
321
  */
214
322
  closeMenu(t = !0) {
215
- this.open && (this._setOpen(!1, !0), t && this._$trigger?.deref()?.focus());
323
+ this.open && (this._setOpen(!1, !0), t && !this.open && this._$trigger?.deref()?.focus());
216
324
  }
217
325
  /** Toggles the menu between open and closed. */
218
326
  toggleMenu() {
219
327
  this.open ? this.closeMenu() : this.openMenu();
220
328
  }
221
- /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the current open state. */
222
- _dispatchToggle() {
329
+ /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the requested open state. */
330
+ _dispatchToggle(t = this.open) {
223
331
  this.dispatchEvent(
224
332
  new CustomEvent("rc-menu-button-toggle", {
225
333
  bubbles: !0,
226
334
  composed: !0,
227
- detail: { open: this.open }
335
+ detail: { open: t }
228
336
  })
229
337
  );
230
338
  }
231
339
  /** Caches a weak reference to the first assigned trigger element and syncs its ARIA and tabindex state. */
232
340
  _handleTriggerSlotChange(t) {
233
- const r = t.currentTarget.assignedElements()[0];
234
- r && (this._$trigger = new WeakRef(r), this._syncTriggerAria(), this._syncTriggerTabindex());
341
+ const n = t.currentTarget.assignedElements()[0];
342
+ n && (this._$trigger = new WeakRef(n), this._syncTriggerAria(), this._syncTriggerTabindex());
235
343
  }
236
344
  /** Tracks optional indicator content so the trigger reserves its inline-end space. */
237
345
  _handleIndicatorSlotChange(t) {
@@ -272,8 +380,8 @@ const a = class a extends d {
272
380
  }
273
381
  /** Caches a weak reference to the first assigned `rc-menu` element. */
274
382
  _handleMenuSlotChange(t) {
275
- const n = t.currentTarget.assignedElements().find((s) => s.tagName === "RC-MENU");
276
- n && (this._$menu = new WeakRef(n));
383
+ const i = t.currentTarget.assignedElements().find((s) => s.tagName === "RC-MENU");
384
+ i && (this._$menu = new WeakRef(i));
277
385
  }
278
386
  /** Prevents the default button action and delegates to `toggleMenu`. */
279
387
  _handleTriggerClick(t) {
@@ -293,13 +401,11 @@ const a = class a extends d {
293
401
  }
294
402
  /** Syncs trigger ARIA when `open` changes; updates anchor placement when `placement` or `orientation` change. */
295
403
  updated(t) {
296
- super.updated(t), t.has("open") && this._syncTriggerAria(), (t.has("placement") || t.has("orientation")) && this._anchorCtrl.setOptions({ placement: this._effectivePlacement });
404
+ super.updated(t), t.has("open") && (this._syncTriggerAria(), this._$popup?.isConnected && (this._$popup.togglePopover(this.open), this.open && this._anchorCtrl.update())), (t.has("placement") || t.has("orientation")) && this._anchorCtrl.setOptions({ placement: this._effectivePlacement });
297
405
  }
298
406
  _setOpen(t, e) {
299
- if (this._open === t)
300
- return;
301
- const r = this._open;
302
- this._open = t, this.requestUpdate("open", r), this._syncTriggerAria(), e && this._dispatchToggle();
407
+ const n = this.open;
408
+ n !== t && (this._open === void 0 && (this._uncontrolledOpen = t), this.requestUpdate("open", n), this._syncTriggerAria(), e && this._dispatchToggle(t));
303
409
  }
304
410
  /** Writes `aria-haspopup` and `aria-expanded` to the trigger button to match the current open state. */
305
411
  _syncTriggerAria() {
@@ -332,7 +438,7 @@ const a = class a extends d {
332
438
  <div
333
439
  id="popup"
334
440
  part="popup"
335
- ?hidden=${!this.open}
441
+ popover="manual"
336
442
  @rc-menu-close=${this._handleMenuClose}
337
443
  @rc-menu-activate=${this._handleMenuActivate}
338
444
  >
@@ -341,37 +447,36 @@ const a = class a extends d {
341
447
  </div>
342
448
  `;
343
449
  }
344
- };
345
- a.styles = [_], a.shadowRootOptions = {
346
- ...d.shadowRootOptions,
450
+ }, r.styles = [y], r.shadowRootOptions = {
451
+ ...g.shadowRootOptions,
347
452
  delegatesFocus: !0
348
- };
349
- let i = a;
350
- o([
453
+ }, r._styledRoots = /* @__PURE__ */ new Set(), r);
454
+ a([
351
455
  l({ type: Boolean, reflect: !0 })
352
- ], i.prototype, "open", 1);
353
- o([
456
+ ], o.prototype, "open", 1);
457
+ a([
354
458
  l({ type: Boolean, attribute: "default-open" })
355
- ], i.prototype, "defaultOpen", 1);
356
- o([
459
+ ], o.prototype, "defaultOpen", 1);
460
+ a([
357
461
  l({ type: String, reflect: !0 })
358
- ], i.prototype, "orientation", 2);
359
- o([
462
+ ], o.prototype, "orientation", 2);
463
+ a([
360
464
  l({ reflect: !0 })
361
- ], i.prototype, "placement", 2);
362
- o([
363
- g("#root")
364
- ], i.prototype, "_$root", 2);
365
- o([
366
- g("#popup")
367
- ], i.prototype, "_$popup", 2);
368
- o([
369
- p()
370
- ], i.prototype, "_$trigger", 2);
371
- o([
372
- p()
373
- ], i.prototype, "_$menu", 2);
465
+ ], o.prototype, "placement", 2);
466
+ a([
467
+ d("#root")
468
+ ], o.prototype, "_$root", 2);
469
+ a([
470
+ d("#popup")
471
+ ], o.prototype, "_$popup", 2);
472
+ a([
473
+ h()
474
+ ], o.prototype, "_$trigger", 2);
475
+ a([
476
+ h()
477
+ ], o.prototype, "_$menu", 2);
478
+ let C = o;
374
479
  export {
375
- i as R
480
+ C as R
376
481
  };
377
- //# sourceMappingURL=rc-menu-button-CBUIq3iu.js.map
482
+ //# sourceMappingURL=rc-menu-button-DPs2AT2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-menu-button-DPs2AT2d.js","sources":["../src/rc-menu-button.styles.ts","../src/rc-menu-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menuButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([orientation='vertical']) {\n display: block;\n }\n\n #root {\n display: inline-block;\n }\n\n :host([orientation='vertical']) #root {\n display: block;\n inline-size: 100%;\n }\n\n #trigger-wrap {\n position: relative;\n display: inline-block;\n }\n\n :host([orientation='vertical']) #trigger-wrap {\n display: block;\n inline-size: 100%;\n }\n\n /*\n * Icon-only triggers (e.g. a toolbar's overflow button) can render\n * visually smaller than the accessible 48dp touch-target minimum,\n * especially at a narrow width. This is a floor, not a fixed size: a\n * trigger already at or above it (the default width, or a labeled\n * trigger) is unaffected. #trigger-wrap reserves the layout space and\n * centers the (possibly smaller) slotted trigger within it; the actual\n * larger hit region comes from the light-DOM hit-slop pseudo-element in\n * rc-menu-button.ts. Mirrors rc-button's own touch-target affordance.\n *\n * Scoped to [icon-only] rather than applied unconditionally: switching\n * #trigger-wrap to a flex/grid container would blockify the slotted\n * trigger's own inline-flex display (its getComputedStyle().display\n * becomes \"flex\", per the CSS Display spec's flex-item blockification —\n * harmless for layout, since a flex item is sized by its container's\n * flex algorithm regardless of its own inline/block outer type, but an\n * observable change other callers shouldn't have to account for).\n */\n :host([icon-only]) #trigger-wrap {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-block-size: var(--rc-menu-button-touch-target-block-size, 3rem);\n min-inline-size: var(\n --rc-menu-button-touch-target-inline-size,\n var(--rc-menu-button-touch-target-block-size, 3rem)\n );\n /*\n * Zero by default. A theme or consumer sets one of these on a trigger\n * that sits at a real edge (no neighbor on that side) to let the\n * touch-target inflation above overlap into whatever sits just outside\n * the host instead of also reserving layout space there. Mirrors\n * rc-button's own --rc-button-touch-target-overlap-inline-* tokens.\n */\n margin-inline-start: calc(-1 * var(--rc-menu-button-touch-target-overlap-inline-start, 0px));\n margin-inline-end: calc(-1 * var(--rc-menu-button-touch-target-overlap-inline-end, 0px));\n }\n\n :host([icon-only][orientation='vertical']) #trigger-wrap {\n display: flex;\n }\n\n /*\n * Icon-only trigger width: square by default (matches its own block\n * size), or a distinct value for a narrower/wider variant. Padding is\n * cleared since an icon-only trigger centers its (typically single) icon\n * child via the flex alignment above rather than via inline padding.\n */\n :host([icon-only]) slot[name='trigger']::slotted(button),\n :host([icon-only]) slot[name='trigger']::slotted([role='button']) {\n inline-size: var(\n --rc-menu-button-icon-size,\n var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em))\n );\n min-inline-size: var(\n --rc-menu-button-icon-size,\n var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em))\n );\n padding-inline: 0;\n }\n\n slot[name='trigger']::slotted(button),\n slot[name='trigger']::slotted([role='button']) {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--rc-menu-button-trigger-gap, var(--rc-item-gap, 0.5em));\n min-block-size: var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em));\n padding: var(--rc-menu-button-trigger-padding-block, var(--rc-control-padding-block, 0.25em))\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em));\n appearance: none;\n box-sizing: border-box;\n border: var(--rc-menu-button-trigger-border, var(--rc-border, 1px solid ButtonBorder));\n border-radius: var(--rc-menu-button-trigger-radius, var(--rc-control-radius, 0.125em));\n background: var(--rc-menu-button-trigger-background, var(--rc-button-bg, ButtonFace));\n color: var(--rc-menu-button-trigger-color, var(--rc-button-text, ButtonText));\n font: inherit;\n text-decoration: none;\n cursor: default;\n user-select: none;\n transition: var(--rc-menu-button-trigger-transition);\n }\n\n slot[name='trigger']::slotted(button:hover),\n slot[name='trigger']::slotted([role='button']:hover) {\n border-color: var(--rc-menu-button-trigger-hover-border-color, currentColor);\n background: var(\n --rc-menu-button-trigger-hover-background,\n color-mix(in srgb, Highlight 8%, transparent)\n );\n color: var(--rc-menu-button-trigger-hover-color, inherit);\n }\n\n slot[name='trigger']::slotted(button[aria-expanded='true']),\n slot[name='trigger']::slotted([role='button'][aria-expanded='true']) {\n border-color: var(--rc-menu-button-trigger-open-border-color, currentColor);\n background: var(\n --rc-menu-button-trigger-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n color: var(--rc-menu-button-trigger-open-color, inherit);\n }\n\n :host([orientation='vertical']) slot[name='trigger']::slotted(button),\n :host([orientation='vertical']) slot[name='trigger']::slotted([role='button']) {\n inline-size: 100%;\n text-align: start;\n }\n\n :host([has-indicator]) slot[name='trigger']::slotted(button),\n :host([has-indicator]) slot[name='trigger']::slotted([role='button']) {\n padding-inline-end: calc(\n var(\n --rc-menu-button-indicator-inset,\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em))\n ) +\n var(--rc-menu-button-indicator-size, 1em) +\n var(--rc-menu-button-trigger-gap, var(--rc-item-gap, 0.5em))\n );\n }\n\n slot[name='indicator'] {\n position: absolute;\n inset-block-start: 50%;\n inset-inline-end: var(\n --rc-menu-button-indicator-inset,\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em))\n );\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--rc-menu-button-indicator-size, 1em);\n block-size: var(--rc-menu-button-indicator-size, 1em);\n color: var(--rc-menu-button-indicator-color, currentColor);\n pointer-events: none;\n transform: translateY(-50%);\n }\n\n slot[name='indicator']::slotted(*) {\n inline-size: 100%;\n block-size: 100%;\n }\n\n #popup {\n margin: 0;\n padding: 0;\n border: none;\n background: none;\n overflow: visible;\n color: inherit;\n }\n`;\n\nexport default menuButtonStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport {\n AnchorController,\n keyInteraction,\n keyNavigation,\n type AnchorPlacement,\n type KeyboardNavigationAction,\n} from '@rcarls/rc-common';\nimport type { RCMenu } from '@rcarls/rc-menu';\n\nimport menuButtonStyles from './rc-menu-button.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-menu-button': RCMenuButton;\n }\n}\n\nconst LIGHT_DOM_CSS = `\n@layer rc-base {\n /*\n * Expands an icon-only trigger's clickable region beyond its visible box\n * up to the accessible touch-target minimum, the same way rc-button and\n * rc-chip do: an absolutely-positioned, invisible pseudo-element on the\n * actual slotted trigger element (not the host) extends the hit area\n * symmetrically. The trigger already has position: relative from the\n * shadow-scoped ::slotted(button) rule. max(100%, size) keeps this a\n * no-op once the visible trigger already meets or exceeds the touch\n * target, rather than shrinking it.\n */\n rc-menu-button[icon-only] > [slot='trigger']::before {\n content: '';\n position: absolute;\n inset-block: calc(\n (\n var(--rc-menu-button-touch-target-block-size, 3rem) -\n max(100%, var(--rc-menu-button-trigger-block-size, 0px))\n ) / -2\n );\n inset-inline: calc(\n (\n var(\n --rc-menu-button-touch-target-inline-size,\n var(--rc-menu-button-touch-target-block-size, 3rem)\n ) -\n max(100%, var(--rc-menu-button-icon-size, var(--rc-menu-button-trigger-block-size, 0px)))\n ) / -2\n );\n }\n}\n`;\n\n/** Detail payload for the `rc-menu-button-toggle` event. */\nexport interface RCMenuButtonToggleEvent {\n /** Whether the menu transitioned to open (`true`) or closed (`false`). */\n open: boolean;\n}\n\n/**\n * Trigger button that opens an rc-menu popup, following the WAI-ARIA Menu Button pattern.\n *\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-menu-button rc-menu-button docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/ WAI-ARIA Menu Button pattern}\n *\n * @slot trigger - The button element that triggers the menu\n * @slot indicator - Optional decorative indicator rendered at the trigger's inline end\n * @slot default - The rc-menu element to display as popup\n *\n * @fires rc-menu-button-toggle - Fired when the menu opens or closes\n *\n * @cssprop [--rc-menu-button-trigger-block-size=var(--rc-control-block-size)] - Minimum block size of the trigger\n * @cssprop [--rc-menu-button-trigger-padding-block=var(--rc-control-padding-block)] - Trigger block-axis padding\n * @cssprop [--rc-menu-button-trigger-padding-inline=var(--rc-control-padding-inline)] - Trigger inline-axis padding\n * @cssprop [--rc-menu-button-trigger-gap=var(--rc-item-gap)] - Gap between flex children in the trigger\n * @cssprop [--rc-menu-button-trigger-border=var(--rc-border)] - Trigger border\n * @cssprop [--rc-menu-button-trigger-radius=var(--rc-control-radius)] - Trigger border radius\n * @cssprop [--rc-menu-button-trigger-background=var(--rc-button-bg)] - Trigger background\n * @cssprop [--rc-menu-button-trigger-color=var(--rc-button-text)] - Trigger text color\n * @cssprop [--rc-menu-button-trigger-transition] - CSS transition applied to the trigger\n * @cssprop [--rc-menu-button-trigger-hover-background=color-mix(in srgb, Highlight 8%, transparent)] - Trigger hover background\n * @cssprop [--rc-menu-button-trigger-hover-color=inherit] - Trigger hover text color\n * @cssprop [--rc-menu-button-trigger-hover-border-color=currentColor] - Trigger hover border color\n * @cssprop [--rc-menu-button-trigger-open-background=color-mix(in srgb, Highlight 12%, transparent)] - Trigger background when the menu is open\n * @cssprop [--rc-menu-button-trigger-open-color=inherit] - Trigger text color when the menu is open\n * @cssprop [--rc-menu-button-trigger-open-border-color=currentColor] - Trigger border color when the menu is open\n * @cssprop [--rc-menu-button-indicator-size=1em] - Inline and block size of the slotted indicator\n * @cssprop [--rc-menu-button-indicator-color=currentColor] - Color of the slotted indicator\n * @cssprop [--rc-menu-button-indicator-inset=var(--rc-menu-button-trigger-padding-inline)] - Indicator distance from the trigger's inline end\n * @cssprop [--rc-menu-button-icon-size] - Inline size of an `icon-only` trigger's visible box.\n * Square by default (equal to `--rc-menu-button-trigger-block-size`); set narrower or wider\n * to change only the trigger's width, independent of its height.\n * @cssprop [--rc-menu-button-touch-target-block-size=3rem] - Minimum accessible touch target\n * block size for an `icon-only` trigger. A floor, not a fixed size: has no effect once\n * `--rc-menu-button-trigger-block-size` already meets or exceeds it. Grows the shadow-DOM\n * trigger wrapper (reserving layout space) and the light-DOM hit-slop (the actual larger\n * clickable region) together; the visible trigger itself stays at its own size, centered.\n * @cssprop [--rc-menu-button-touch-target-inline-size] - Minimum accessible touch target inline\n * size for an `icon-only` trigger. Defers to `--rc-menu-button-touch-target-block-size` when\n * unset.\n * @cssprop [--rc-menu-button-touch-target-overlap-inline-start=0px] - Zero by default. A theme\n * or consumer sets this on an `icon-only` trigger that sits at a real leading edge (no\n * neighbor on that side) to let its touch-target inflation overlap into whatever sits just\n * outside the host, such as a container's own edge padding, instead of also reserving layout\n * space there.\n * @cssprop [--rc-menu-button-touch-target-overlap-inline-end=0px] - The trailing-edge\n * counterpart to `--rc-menu-button-touch-target-overlap-inline-start`.\n *\n * @csspart root - The root container element\n * @csspart popup - The popup container element\n *\n * @attr open - Whether the menu popup is visible. Controlled mode: host writes silently.\n * @attr default-open - Initial open state for uncontrolled mode. Ignored after the first\n * controlled write to `open`.\n * @attr orientation - Arrow-key axis for opening the menu. Inherits from a parent\n * `rc-menubar` or `[role=\"menubar\"]` when unset.\n * @attr placement - Preferred placement of the popup relative to the trigger.\n * @attr icon-only - Hints that the slotted trigger has no visible label, so themes can size\n * it and its touch target as an icon button (see `--rc-menu-button-icon-size` and\n * `--rc-menu-button-touch-target-*` above). Purely a styling hook; RCMenuButton does not read\n * or derive it — set it whenever the trigger is rendered icon-only.\n */\nexport class RCMenuButton extends LitElement {\n static styles = [menuButtonStyles];\n\n /**\n * Enables delegatesFocus so the browser routes focus() on the host element\n * to the slotted trigger button.\n */\n static override shadowRootOptions: ShadowRootInit = {\n ...LitElement.shadowRootOptions,\n\n delegatesFocus: true,\n };\n\n protected static readonly _styledRoots = new Set<Document | ShadowRoot>();\n\n protected static _ensureBaseStyles(root: Document | ShadowRoot): void {\n if (RCMenuButton._styledRoots.has(root)) {\n return;\n }\n\n RCMenuButton._styledRoots.add(root);\n\n const style = document.createElement('style');\n\n style.setAttribute('data-rc-light-dom-base', 'rc-menu-button');\n style.textContent = LIGHT_DOM_CSS;\n\n if (root instanceof Document) {\n root.head.append(style);\n } else {\n root.append(style);\n }\n }\n\n private _defaultOpen = false;\n private _open: boolean | undefined;\n private _uncontrolledOpen: boolean | undefined;\n private _openInitialized = false;\n\n /**\n * Whether the menu is currently open.\n *\n * In controlled mode the host owns this value; writing the property applies\n * the state silently without dispatching `rc-menu-button-toggle`.\n */\n @property({ type: Boolean, reflect: true })\n get open(): boolean {\n return this._open ?? this._uncontrolledOpen ?? this._defaultOpen;\n }\n\n /** Applies open state in controlled mode without dispatching an event. */\n set open(value: boolean | undefined) {\n const oldValue = this.open;\n\n this._open = value;\n this._openInitialized = true;\n this.requestUpdate('open', oldValue);\n this._syncTriggerAria();\n }\n\n /**\n * Initial open state for uncontrolled mode.\n *\n * Ignored after the first controlled write; use `open` to update state\n * programmatically after mount.\n */\n @property({ type: Boolean, attribute: 'default-open' })\n get defaultOpen(): boolean {\n return this._defaultOpen;\n }\n\n /** Applies the uncontrolled default before any controlled write occurs. */\n set defaultOpen(value: boolean) {\n const oldValue = this._defaultOpen;\n\n this._defaultOpen = value;\n\n if (\n !this._openInitialized &&\n this._open === undefined &&\n this._uncontrolledOpen === undefined\n ) {\n this.requestUpdate('open', oldValue);\n }\n\n this.requestUpdate('defaultOpen', oldValue);\n }\n\n /**\n * Orientation of this menu button, affects which arrow keys open/close the menu.\n *\n * If not set, inherits from a parent rc-menubar or element with role=\"menubar\".\n */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' | undefined;\n\n /** Preferred placement of the popup relative to the trigger button. */\n @property({ reflect: true })\n placement: AnchorPlacement = 'bottom-start';\n\n /**\n * Popup placement adjusted for orientation.\n *\n * Switches from `bottom-start` to `right-start` when the resolved orientation\n * is `vertical`, so vertical menubars open submenus to the side.\n */\n protected get _effectivePlacement(): AnchorPlacement {\n if (this.placement !== 'bottom-start') {\n return this.placement;\n }\n\n return this._resolvedOrientation === 'vertical' ? 'right-start' : this.placement;\n }\n\n /**\n * Resolved orientation, considering inheritance from parent menubar.\n * Falls back to 'horizontal' if no orientation is set or inherited.\n */\n protected get _resolvedOrientation(): 'horizontal' | 'vertical' {\n if (this.orientation) {\n return this.orientation;\n }\n\n const $menubar = this.closest('rc-menubar, [role=\"menubar\"]');\n\n if ($menubar) {\n const orientation =\n $menubar.getAttribute('orientation') ?? $menubar.getAttribute('aria-orientation');\n\n if (orientation === 'vertical') {\n return 'vertical';\n }\n\n if (orientation === 'horizontal') {\n return 'horizontal';\n }\n }\n\n return 'horizontal';\n }\n\n /** Shadow DOM root container. Serves as the anchor element for `_anchorCtrl`. */\n @query('#root') protected _$root!: HTMLElement;\n\n /** Shadow DOM popup container. Hidden when `open` is `false`. */\n @query('#popup') protected _$popup!: HTMLElement;\n\n /** Weak reference to the slotted trigger button. */\n @state()\n protected _$trigger: WeakRef<HTMLElement> | undefined;\n\n /** Weak reference to the slotted `rc-menu` element. */\n @state()\n protected _$menu: WeakRef<RCMenu> | undefined;\n\n /** Positions the popup relative to the trigger using CSS anchor positioning. */\n protected _anchorCtrl = new AnchorController(this, {\n anchor: () => this._$root ?? null,\n floating: () => this._$popup ?? null,\n shadowHost: () => this,\n placement: 'bottom-start',\n offset: 2,\n });\n\n /** Bound handler for document click (light dismiss). Stored for `removeEventListener` pairing. */\n protected _boundHandleDocumentClick = this._handleDocumentClick.bind(this);\n\n /**\n * Watches the host's own `tabindex` attribute so the trigger button's\n * tabindex can be kept in sync.\n *\n * When a parent (e.g. rc-toolbar) places the\n * host under roving-tabindex management it sets/removes tabindex on the\n * host; we mirror that to the trigger so it doesn't become an independent\n * tab stop. When the host has no tabindex the trigger keeps its natural\n * tabindex=0 for standalone usage.\n */\n protected _tabObserver?: MutationObserver;\n\n /** Installs the tabindex mutation observer and the document-level click listener. */\n override connectedCallback() {\n super.connectedCallback();\n RCMenuButton._ensureBaseStyles(this.getRootNode() as Document | ShadowRoot);\n\n this._tabObserver = new MutationObserver(() => this._syncTriggerTabindex());\n this._tabObserver.observe(this, { attributes: true, attributeFilter: ['tabindex'] });\n\n document.addEventListener('click', this._boundHandleDocumentClick, true);\n\n this.requestUpdate('open');\n }\n\n /** Disconnects the tabindex observer and removes the document-level click listener. */\n override disconnectedCallback() {\n this._tabObserver?.disconnect();\n this._tabObserver = undefined;\n\n super.disconnectedCallback();\n document.removeEventListener('click', this._boundHandleDocumentClick, true);\n }\n\n /**\n * Opens the menu and moves focus into it.\n *\n * @param focusTarget - which item receives initial focus when the menu opens\n */\n openMenu(focusTarget: 'first' | 'last' = 'first') {\n if (this.open) {\n return;\n }\n\n this._anchorCtrl.setOptions({ placement: this._effectivePlacement });\n this._setOpen(true, true);\n\n this.updateComplete.then(() => {\n if (!this.open) {\n return;\n }\n\n const $menu = this._$menu?.deref();\n\n focusTarget === 'last' ? $menu?.focusLast() : $menu?.focusFirst();\n });\n }\n\n /**\n * Closes the menu.\n *\n * @param returnFocus - when `true`, returns focus to the trigger button after closing\n */\n closeMenu(returnFocus = true) {\n if (!this.open) {\n return;\n }\n\n this._setOpen(false, true);\n\n if (returnFocus && !this.open) {\n const $trigger = this._$trigger?.deref();\n\n $trigger?.focus();\n }\n }\n\n /** Toggles the menu between open and closed. */\n toggleMenu() {\n if (this.open) {\n this.closeMenu();\n } else {\n this.openMenu();\n }\n }\n\n /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the requested open state. */\n protected _dispatchToggle(open = this.open) {\n this.dispatchEvent(\n new CustomEvent<RCMenuButtonToggleEvent>('rc-menu-button-toggle', {\n bubbles: true,\n composed: true,\n detail: { open },\n }),\n );\n }\n\n /** Caches a weak reference to the first assigned trigger element and syncs its ARIA and tabindex state. */\n protected _handleTriggerSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $trigger = $slot.assignedElements()[0] as HTMLElement | undefined;\n\n if ($trigger) {\n this._$trigger = new WeakRef($trigger);\n this._syncTriggerAria();\n this._syncTriggerTabindex();\n }\n }\n\n /** Tracks optional indicator content so the trigger reserves its inline-end space. */\n protected _handleIndicatorSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n\n this.toggleAttribute('has-indicator', $slot.assignedElements().length > 0);\n }\n\n /**\n * Mirrors the host's `tabindex` attribute to the trigger button.\n *\n * When a roving-tabindex parent (e.g. rc-toolbar) marks this host inactive\n * with `tabindex=\"-1\"`, the trigger must also be suppressed so it does not\n * become an independent tab stop. When the host is the active item\n * (`tabindex=\"0\"`) or standalone (no tabindex), the trigger retains its\n * natural focusability so that Chrome's delegatesFocus can route sequential\n * Tab navigation through the host to the trigger.\n */\n protected _syncTriggerTabindex() {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger) {\n return;\n }\n\n if (this.getAttribute('tabindex') === '-1') {\n $trigger.setAttribute('tabindex', '-1');\n } else {\n $trigger.removeAttribute('tabindex');\n }\n }\n\n /**\n * Overrides the default focus() so that programmatic focus calls (e.g. from\n * a roving-tabindex parent navigating back to this element via arrow keys)\n * always reach the trigger.\n *\n * Chrome's delegatesFocus will not delegate to a tabindex=\"-1\" element, so\n * when the toolbar marks this host inactive it suppresses the trigger — and\n * the next focusItem() call silently fails. Lifting the suppression here and\n * directly calling trigger.focus() bypasses that restriction.\n */\n override focus(options?: FocusOptions) {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger) {\n super.focus(options);\n\n return;\n }\n\n $trigger.removeAttribute('tabindex');\n $trigger.focus(options);\n }\n\n /** Caches a weak reference to the first assigned `rc-menu` element. */\n protected _handleMenuSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $elements = $slot.assignedElements();\n const $menu = $elements.find(($el) => $el.tagName === 'RC-MENU') as RCMenu | undefined;\n\n if ($menu) {\n this._$menu = new WeakRef($menu);\n }\n }\n\n /**\n * Keyboard navigation handler.\n *\n * Opens or closes the menu in response to arrow/Enter/Escape keys.\n **/\n protected _onNavigate = (action: KeyboardNavigationAction) => {\n switch (action) {\n case 'open-to-first':\n case 'activate':\n this.openMenu();\n break;\n\n case 'open-to-last':\n this.openMenu('last');\n break;\n\n case 'escape':\n this.closeMenu();\n break;\n }\n };\n\n /** Prevents the default button action and delegates to `toggleMenu`. */\n protected _handleTriggerClick(e: MouseEvent) {\n e.preventDefault();\n\n this.toggleMenu();\n }\n\n /** Closes the menu when an `rc-menu-close` event bubbles up from the popup. */\n protected _handleMenuClose() {\n this.closeMenu();\n }\n\n /** Closes the menu when an `rc-menu-activate` event bubbles up from the popup. */\n protected _handleMenuActivate() {\n this.closeMenu();\n }\n\n /** Closes the menu on clicks outside this component (light dismiss). */\n protected _handleDocumentClick(e: MouseEvent) {\n if (!this.open) {\n return;\n }\n\n const path = e.composedPath();\n\n if (path.includes(this)) {\n return;\n }\n\n this.closeMenu(false);\n }\n\n /** Syncs trigger ARIA when `open` changes; updates anchor placement when `placement` or `orientation` change. */\n protected override updated(changedProperties: Map<PropertyKey, unknown>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n this._syncTriggerAria();\n\n // A pending update can flush after the host (and its shadow tree) has\n // already been disconnected — e.g. a framework unmounting this element\n // in the same tick as an `open` change. togglePopover() throws\n // InvalidStateError on a disconnected popover, so guard on connectivity\n // rather than letting that reach the caller.\n if (this._$popup?.isConnected) {\n this._$popup.togglePopover(this.open);\n\n if (this.open) {\n this._anchorCtrl.update();\n }\n }\n }\n\n if (changedProperties.has('placement') || changedProperties.has('orientation')) {\n this._anchorCtrl.setOptions({ placement: this._effectivePlacement });\n }\n }\n\n protected _setOpen(open: boolean, dispatch: boolean): void {\n const oldValue = this.open;\n\n if (oldValue === open) {\n return;\n }\n\n if (this._open === undefined) {\n this._uncontrolledOpen = open;\n }\n\n this.requestUpdate('open', oldValue);\n this._syncTriggerAria();\n\n if (dispatch) {\n this._dispatchToggle(open);\n }\n }\n\n /** Writes `aria-haspopup` and `aria-expanded` to the trigger button to match the current open state. */\n protected _syncTriggerAria(): void {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger?.isConnected) {\n return;\n }\n\n $trigger.setAttribute('aria-haspopup', 'menu');\n $trigger.setAttribute('aria-expanded', String(this.open));\n }\n\n protected override render() {\n return html`\n <div id=\"root\" part=\"root\">\n <div\n id=\"trigger-wrap\"\n ${keyNavigation(this._onNavigate, {\n navigationAxis: this._resolvedOrientation,\n handleNavAxis: false,\n handleOpenAxis: true,\n handleActivate: true,\n handleEscape: this.open,\n })}\n ${keyInteraction()}\n @click=${this._handleTriggerClick}\n >\n <slot name=\"trigger\" @slotchange=${this._handleTriggerSlotChange}></slot>\n <slot\n name=\"indicator\"\n aria-hidden=\"true\"\n @slotchange=${this._handleIndicatorSlotChange}\n ></slot>\n </div>\n\n <div\n id=\"popup\"\n part=\"popup\"\n popover=\"manual\"\n @rc-menu-close=${this._handleMenuClose}\n @rc-menu-activate=${this._handleMenuActivate}\n >\n <slot @slotchange=${this._handleMenuSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCMenuButton;\n"],"names":["menuButtonStyles","css","LIGHT_DOM_CSS","_RCMenuButton","_a","LitElement","AnchorController","action","root","style","value","oldValue","$menubar","orientation","focusTarget","$menu","returnFocus","open","e","$trigger","$slot","options","$el","changedProperties","dispatch","html","keyNavigation","keyInteraction","__decorateClass","property","query","state","RCMenuButton"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import "@rcarls/rc-menu/define";
2
- import { R as t } from "./rc-menu-button-CBUIq3iu.js";
2
+ import { R as t } from "./rc-menu-button-DPs2AT2d.js";
3
3
  customElements.get("rc-menu-button") || customElements.define("rc-menu-button", t);
4
4
  export {
5
5
  t as RCMenuButton
@@ -1,4 +1,4 @@
1
- import { R as e } from "./rc-menu-button-CBUIq3iu.js";
1
+ import { R as e } from "./rc-menu-button-DPs2AT2d.js";
2
2
  export {
3
3
  e as RCMenuButton
4
4
  };
@@ -1 +1 @@
1
- export * from './rc-menu-button';
1
+ export * from './rc-menu-button.js';
@@ -42,7 +42,24 @@ export interface RCMenuButtonToggleEvent {
42
42
  * @cssprop [--rc-menu-button-indicator-size=1em] - Inline and block size of the slotted indicator
43
43
  * @cssprop [--rc-menu-button-indicator-color=currentColor] - Color of the slotted indicator
44
44
  * @cssprop [--rc-menu-button-indicator-inset=var(--rc-menu-button-trigger-padding-inline)] - Indicator distance from the trigger's inline end
45
- * @cssprop [--rc-menu-button-popup-z-index=1000] - Z-index of the popup overlay
45
+ * @cssprop [--rc-menu-button-icon-size] - Inline size of an `icon-only` trigger's visible box.
46
+ * Square by default (equal to `--rc-menu-button-trigger-block-size`); set narrower or wider
47
+ * to change only the trigger's width, independent of its height.
48
+ * @cssprop [--rc-menu-button-touch-target-block-size=3rem] - Minimum accessible touch target
49
+ * block size for an `icon-only` trigger. A floor, not a fixed size: has no effect once
50
+ * `--rc-menu-button-trigger-block-size` already meets or exceeds it. Grows the shadow-DOM
51
+ * trigger wrapper (reserving layout space) and the light-DOM hit-slop (the actual larger
52
+ * clickable region) together; the visible trigger itself stays at its own size, centered.
53
+ * @cssprop [--rc-menu-button-touch-target-inline-size] - Minimum accessible touch target inline
54
+ * size for an `icon-only` trigger. Defers to `--rc-menu-button-touch-target-block-size` when
55
+ * unset.
56
+ * @cssprop [--rc-menu-button-touch-target-overlap-inline-start=0px] - Zero by default. A theme
57
+ * or consumer sets this on an `icon-only` trigger that sits at a real leading edge (no
58
+ * neighbor on that side) to let its touch-target inflation overlap into whatever sits just
59
+ * outside the host, such as a container's own edge padding, instead of also reserving layout
60
+ * space there.
61
+ * @cssprop [--rc-menu-button-touch-target-overlap-inline-end=0px] - The trailing-edge
62
+ * counterpart to `--rc-menu-button-touch-target-overlap-inline-start`.
46
63
  *
47
64
  * @csspart root - The root container element
48
65
  * @csspart popup - The popup container element
@@ -53,6 +70,10 @@ export interface RCMenuButtonToggleEvent {
53
70
  * @attr orientation - Arrow-key axis for opening the menu. Inherits from a parent
54
71
  * `rc-menubar` or `[role="menubar"]` when unset.
55
72
  * @attr placement - Preferred placement of the popup relative to the trigger.
73
+ * @attr icon-only - Hints that the slotted trigger has no visible label, so themes can size
74
+ * it and its touch target as an icon button (see `--rc-menu-button-icon-size` and
75
+ * `--rc-menu-button-touch-target-*` above). Purely a styling hook; RCMenuButton does not read
76
+ * or derive it — set it whenever the trigger is rendered icon-only.
56
77
  */
57
78
  export declare class RCMenuButton extends LitElement {
58
79
  static styles: import('lit').CSSResult[];
@@ -61,8 +82,11 @@ export declare class RCMenuButton extends LitElement {
61
82
  * to the slotted trigger button.
62
83
  */
63
84
  static shadowRootOptions: ShadowRootInit;
85
+ protected static readonly _styledRoots: Set<Document | ShadowRoot>;
86
+ protected static _ensureBaseStyles(root: Document | ShadowRoot): void;
64
87
  private _defaultOpen;
65
88
  private _open;
89
+ private _uncontrolledOpen;
66
90
  private _openInitialized;
67
91
  /**
68
92
  * Whether the menu is currently open.
@@ -143,8 +167,8 @@ export declare class RCMenuButton extends LitElement {
143
167
  closeMenu(returnFocus?: boolean): void;
144
168
  /** Toggles the menu between open and closed. */
145
169
  toggleMenu(): void;
146
- /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the current open state. */
147
- protected _dispatchToggle(): void;
170
+ /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the requested open state. */
171
+ protected _dispatchToggle(open?: boolean): void;
148
172
  /** Caches a weak reference to the first assigned trigger element and syncs its ARIA and tabindex state. */
149
173
  protected _handleTriggerSlotChange(e: Event): void;
150
174
  /** Tracks optional indicator content so the trigger reserves its inline-end space. */
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.2",
6
+ "version": "0.6.0",
7
7
  "description": "Trigger button that opens an rc-menu popup.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -45,12 +45,12 @@
45
45
  "test:browser:firefox": "vitest --run --project=firefox"
46
46
  },
47
47
  "dependencies": {
48
- "@rcarls/rc-common": "0.4.2",
49
- "@rcarls/rc-menu": "0.4.2",
50
- "@types/node": "^25.6.0"
48
+ "@rcarls/rc-common": "0.6.0",
49
+ "@rcarls/rc-menu": "0.6.0"
51
50
  },
52
51
  "devDependencies": {
53
52
  "@custom-elements-manifest/analyzer": "0.11.0",
53
+ "@types/node": "^25.6.0",
54
54
  "@vitest/browser-playwright": "4.1.5",
55
55
  "lit": "^3.0.0",
56
56
  "playwright": "^1.56.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-menu-button-CBUIq3iu.js","sources":["../src/rc-menu-button.styles.ts","../src/rc-menu-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menuButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([orientation='vertical']) {\n display: block;\n }\n\n #root {\n display: inline-block;\n }\n\n :host([orientation='vertical']) #root {\n display: block;\n }\n\n #trigger-wrap {\n position: relative;\n display: inline-block;\n }\n\n :host([orientation='vertical']) #trigger-wrap {\n display: block;\n }\n\n slot[name='trigger']::slotted(button),\n slot[name='trigger']::slotted([role='button']) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--rc-menu-button-trigger-gap, var(--rc-item-gap, 0.5em));\n min-block-size: var(--rc-menu-button-trigger-block-size, var(--rc-control-block-size, 2.25em));\n padding: var(--rc-menu-button-trigger-padding-block, var(--rc-control-padding-block, 0.25em))\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em));\n appearance: none;\n box-sizing: border-box;\n border: var(--rc-menu-button-trigger-border, var(--rc-border, 1px solid ButtonBorder));\n border-radius: var(--rc-menu-button-trigger-radius, var(--rc-control-radius, 0.125em));\n background: var(--rc-menu-button-trigger-background, var(--rc-button-bg, ButtonFace));\n color: var(--rc-menu-button-trigger-color, var(--rc-button-text, ButtonText));\n font: inherit;\n text-decoration: none;\n cursor: default;\n user-select: none;\n transition: var(--rc-menu-button-trigger-transition);\n }\n\n slot[name='trigger']::slotted(button:hover),\n slot[name='trigger']::slotted([role='button']:hover) {\n border-color: var(--rc-menu-button-trigger-hover-border-color, currentColor);\n background: var(\n --rc-menu-button-trigger-hover-background,\n color-mix(in srgb, Highlight 8%, transparent)\n );\n color: var(--rc-menu-button-trigger-hover-color, inherit);\n }\n\n slot[name='trigger']::slotted(button[aria-expanded='true']),\n slot[name='trigger']::slotted([role='button'][aria-expanded='true']) {\n border-color: var(--rc-menu-button-trigger-open-border-color, currentColor);\n background: var(\n --rc-menu-button-trigger-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n color: var(--rc-menu-button-trigger-open-color, inherit);\n }\n\n :host([orientation='vertical']) slot[name='trigger']::slotted(button),\n :host([orientation='vertical']) slot[name='trigger']::slotted([role='button']) {\n inline-size: 100%;\n text-align: start;\n }\n\n :host([has-indicator]) slot[name='trigger']::slotted(button),\n :host([has-indicator]) slot[name='trigger']::slotted([role='button']) {\n padding-inline-end: calc(\n var(\n --rc-menu-button-indicator-inset,\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em))\n ) +\n var(--rc-menu-button-indicator-size, 1em) +\n var(--rc-menu-button-trigger-gap, var(--rc-item-gap, 0.5em))\n );\n }\n\n slot[name='indicator'] {\n position: absolute;\n inset-block-start: 50%;\n inset-inline-end: var(\n --rc-menu-button-indicator-inset,\n var(--rc-menu-button-trigger-padding-inline, var(--rc-control-padding-inline, 0.5em))\n );\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--rc-menu-button-indicator-size, 1em);\n block-size: var(--rc-menu-button-indicator-size, 1em);\n color: var(--rc-menu-button-indicator-color, currentColor);\n pointer-events: none;\n transform: translateY(-50%);\n }\n\n slot[name='indicator']::slotted(*) {\n inline-size: 100%;\n block-size: 100%;\n }\n\n #popup {\n z-index: var(--rc-menu-button-popup-z-index, 1000);\n }\n\n #popup[hidden] {\n display: none;\n }\n`;\n\nexport default menuButtonStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport {\n AnchorController,\n keyInteraction,\n keyNavigation,\n type AnchorPlacement,\n type KeyboardNavigationAction,\n} from '@rcarls/rc-common';\nimport type { RCMenu } from '@rcarls/rc-menu';\n\nimport menuButtonStyles from './rc-menu-button.styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-menu-button': RCMenuButton;\n }\n}\n\n/** Detail payload for the `rc-menu-button-toggle` event. */\nexport interface RCMenuButtonToggleEvent {\n /** Whether the menu transitioned to open (`true`) or closed (`false`). */\n open: boolean;\n}\n\n/**\n * Trigger button that opens an rc-menu popup, following the WAI-ARIA Menu Button pattern.\n *\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-menu-button rc-menu-button docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/ WAI-ARIA Menu Button pattern}\n *\n * @slot trigger - The button element that triggers the menu\n * @slot indicator - Optional decorative indicator rendered at the trigger's inline end\n * @slot default - The rc-menu element to display as popup\n *\n * @fires rc-menu-button-toggle - Fired when the menu opens or closes\n *\n * @cssprop [--rc-menu-button-trigger-block-size=var(--rc-control-block-size)] - Minimum block size of the trigger\n * @cssprop [--rc-menu-button-trigger-padding-block=var(--rc-control-padding-block)] - Trigger block-axis padding\n * @cssprop [--rc-menu-button-trigger-padding-inline=var(--rc-control-padding-inline)] - Trigger inline-axis padding\n * @cssprop [--rc-menu-button-trigger-gap=var(--rc-item-gap)] - Gap between flex children in the trigger\n * @cssprop [--rc-menu-button-trigger-border=var(--rc-border)] - Trigger border\n * @cssprop [--rc-menu-button-trigger-radius=var(--rc-control-radius)] - Trigger border radius\n * @cssprop [--rc-menu-button-trigger-background=var(--rc-button-bg)] - Trigger background\n * @cssprop [--rc-menu-button-trigger-color=var(--rc-button-text)] - Trigger text color\n * @cssprop [--rc-menu-button-trigger-transition] - CSS transition applied to the trigger\n * @cssprop [--rc-menu-button-trigger-hover-background=color-mix(in srgb, Highlight 8%, transparent)] - Trigger hover background\n * @cssprop [--rc-menu-button-trigger-hover-color=inherit] - Trigger hover text color\n * @cssprop [--rc-menu-button-trigger-hover-border-color=currentColor] - Trigger hover border color\n * @cssprop [--rc-menu-button-trigger-open-background=color-mix(in srgb, Highlight 12%, transparent)] - Trigger background when the menu is open\n * @cssprop [--rc-menu-button-trigger-open-color=inherit] - Trigger text color when the menu is open\n * @cssprop [--rc-menu-button-trigger-open-border-color=currentColor] - Trigger border color when the menu is open\n * @cssprop [--rc-menu-button-indicator-size=1em] - Inline and block size of the slotted indicator\n * @cssprop [--rc-menu-button-indicator-color=currentColor] - Color of the slotted indicator\n * @cssprop [--rc-menu-button-indicator-inset=var(--rc-menu-button-trigger-padding-inline)] - Indicator distance from the trigger's inline end\n * @cssprop [--rc-menu-button-popup-z-index=1000] - Z-index of the popup overlay\n *\n * @csspart root - The root container element\n * @csspart popup - The popup container element\n *\n * @attr open - Whether the menu popup is visible. Controlled mode: host writes silently.\n * @attr default-open - Initial open state for uncontrolled mode. Ignored after the first\n * controlled write to `open`.\n * @attr orientation - Arrow-key axis for opening the menu. Inherits from a parent\n * `rc-menubar` or `[role=\"menubar\"]` when unset.\n * @attr placement - Preferred placement of the popup relative to the trigger.\n */\nexport class RCMenuButton extends LitElement {\n static styles = [menuButtonStyles];\n\n /**\n * Enables delegatesFocus so the browser routes focus() on the host element\n * to the slotted trigger button.\n */\n static override shadowRootOptions: ShadowRootInit = {\n ...LitElement.shadowRootOptions,\n\n delegatesFocus: true,\n };\n\n private _defaultOpen = false;\n private _open = false;\n private _openInitialized = false;\n\n /**\n * Whether the menu is currently open.\n *\n * In controlled mode the host owns this value; writing the property applies\n * the state silently without dispatching `rc-menu-button-toggle`.\n */\n @property({ type: Boolean, reflect: true })\n get open(): boolean {\n return this._open;\n }\n\n /** Applies open state in controlled mode without dispatching an event. */\n set open(value: boolean | undefined) {\n const oldValue = this._open;\n\n if (value === undefined) {\n return;\n }\n\n this._openInitialized = true;\n this._setOpen(value, false);\n this.requestUpdate('open', oldValue);\n }\n\n /**\n * Initial open state for uncontrolled mode.\n *\n * Ignored after the first controlled write; use `open` to update state\n * programmatically after mount.\n */\n @property({ type: Boolean, attribute: 'default-open' })\n get defaultOpen(): boolean {\n return this._defaultOpen;\n }\n\n /** Applies the uncontrolled default before any controlled write occurs. */\n set defaultOpen(value: boolean) {\n const oldValue = this._defaultOpen;\n\n this._defaultOpen = value;\n\n if (value && !this._openInitialized) {\n this._setOpen(true, false);\n }\n\n this.requestUpdate('defaultOpen', oldValue);\n }\n\n /**\n * Orientation of this menu button, affects which arrow keys open/close the menu.\n *\n * If not set, inherits from a parent rc-menubar or element with role=\"menubar\".\n */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' | undefined;\n\n /** Preferred placement of the popup relative to the trigger button. */\n @property({ reflect: true })\n placement: AnchorPlacement = 'bottom-start';\n\n /**\n * Popup placement adjusted for orientation.\n *\n * Switches from `bottom-start` to `right-start` when the resolved orientation\n * is `vertical`, so vertical menubars open submenus to the side.\n */\n protected get _effectivePlacement(): AnchorPlacement {\n if (this.placement !== 'bottom-start') {\n return this.placement;\n }\n\n return this._resolvedOrientation === 'vertical' ? 'right-start' : this.placement;\n }\n\n /**\n * Resolved orientation, considering inheritance from parent menubar.\n * Falls back to 'horizontal' if no orientation is set or inherited.\n */\n protected get _resolvedOrientation(): 'horizontal' | 'vertical' {\n if (this.orientation) {\n return this.orientation;\n }\n\n const $menubar = this.closest('rc-menubar, [role=\"menubar\"]');\n\n if ($menubar) {\n const orientation =\n $menubar.getAttribute('orientation') ?? $menubar.getAttribute('aria-orientation');\n\n if (orientation === 'vertical') {\n return 'vertical';\n }\n\n if (orientation === 'horizontal') {\n return 'horizontal';\n }\n }\n\n return 'horizontal';\n }\n\n /** Shadow DOM root container. Serves as the anchor element for `_anchorCtrl`. */\n @query('#root') protected _$root!: HTMLElement;\n\n /** Shadow DOM popup container. Hidden when `open` is `false`. */\n @query('#popup') protected _$popup!: HTMLElement;\n\n /** Weak reference to the slotted trigger button. */\n @state()\n protected _$trigger: WeakRef<HTMLElement> | undefined;\n\n /** Weak reference to the slotted `rc-menu` element. */\n @state()\n protected _$menu: WeakRef<RCMenu> | undefined;\n\n /** Positions the popup relative to the trigger using CSS anchor positioning. */\n protected _anchorCtrl = new AnchorController(this, {\n anchor: () => this._$root ?? null,\n floating: () => this._$popup ?? null,\n shadowHost: () => this,\n placement: 'bottom-start',\n offset: 2,\n });\n\n /** Bound handler for document click (light dismiss). Stored for `removeEventListener` pairing. */\n protected _boundHandleDocumentClick = this._handleDocumentClick.bind(this);\n\n /**\n * Watches the host's own `tabindex` attribute so the trigger button's\n * tabindex can be kept in sync.\n *\n * When a parent (e.g. rc-toolbar) places the\n * host under roving-tabindex management it sets/removes tabindex on the\n * host; we mirror that to the trigger so it doesn't become an independent\n * tab stop. When the host has no tabindex the trigger keeps its natural\n * tabindex=0 for standalone usage.\n */\n protected _tabObserver?: MutationObserver;\n\n /** Installs the tabindex mutation observer and the document-level click listener. */\n override connectedCallback() {\n super.connectedCallback();\n\n this._tabObserver = new MutationObserver(() => this._syncTriggerTabindex());\n this._tabObserver.observe(this, { attributes: true, attributeFilter: ['tabindex'] });\n\n document.addEventListener('click', this._boundHandleDocumentClick, true);\n\n if (this.defaultOpen) {\n this._setOpen(true, false);\n }\n }\n\n /** Disconnects the tabindex observer and removes the document-level click listener. */\n override disconnectedCallback() {\n this._tabObserver?.disconnect();\n this._tabObserver = undefined;\n\n super.disconnectedCallback();\n document.removeEventListener('click', this._boundHandleDocumentClick, true);\n }\n\n /**\n * Opens the menu and moves focus into it.\n *\n * @param focusTarget - which item receives initial focus when the menu opens\n */\n openMenu(focusTarget: 'first' | 'last' = 'first') {\n if (this.open) {\n return;\n }\n\n this._anchorCtrl.setOptions({ placement: this._effectivePlacement });\n this._setOpen(true, true);\n this._anchorCtrl.update();\n\n this.updateComplete.then(() => {\n const $menu = this._$menu?.deref();\n\n focusTarget === 'last' ? $menu?.focusLast() : $menu?.focusFirst();\n });\n }\n\n /**\n * Closes the menu.\n *\n * @param returnFocus - when `true`, returns focus to the trigger button after closing\n */\n closeMenu(returnFocus = true) {\n if (!this.open) {\n return;\n }\n\n this._setOpen(false, true);\n\n if (returnFocus) {\n const $trigger = this._$trigger?.deref();\n\n $trigger?.focus();\n }\n }\n\n /** Toggles the menu between open and closed. */\n toggleMenu() {\n if (this.open) {\n this.closeMenu();\n } else {\n this.openMenu();\n }\n }\n\n /** Dispatches the `rc-menu-button-toggle` bubbling composed event with the current open state. */\n protected _dispatchToggle() {\n this.dispatchEvent(\n new CustomEvent<RCMenuButtonToggleEvent>('rc-menu-button-toggle', {\n bubbles: true,\n composed: true,\n detail: { open: this.open },\n }),\n );\n }\n\n /** Caches a weak reference to the first assigned trigger element and syncs its ARIA and tabindex state. */\n protected _handleTriggerSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $trigger = $slot.assignedElements()[0] as HTMLElement | undefined;\n\n if ($trigger) {\n this._$trigger = new WeakRef($trigger);\n this._syncTriggerAria();\n this._syncTriggerTabindex();\n }\n }\n\n /** Tracks optional indicator content so the trigger reserves its inline-end space. */\n protected _handleIndicatorSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n\n this.toggleAttribute('has-indicator', $slot.assignedElements().length > 0);\n }\n\n /**\n * Mirrors the host's `tabindex` attribute to the trigger button.\n *\n * When a roving-tabindex parent (e.g. rc-toolbar) marks this host inactive\n * with `tabindex=\"-1\"`, the trigger must also be suppressed so it does not\n * become an independent tab stop. When the host is the active item\n * (`tabindex=\"0\"`) or standalone (no tabindex), the trigger retains its\n * natural focusability so that Chrome's delegatesFocus can route sequential\n * Tab navigation through the host to the trigger.\n */\n protected _syncTriggerTabindex() {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger) {\n return;\n }\n\n if (this.getAttribute('tabindex') === '-1') {\n $trigger.setAttribute('tabindex', '-1');\n } else {\n $trigger.removeAttribute('tabindex');\n }\n }\n\n /**\n * Overrides the default focus() so that programmatic focus calls (e.g. from\n * a roving-tabindex parent navigating back to this element via arrow keys)\n * always reach the trigger.\n *\n * Chrome's delegatesFocus will not delegate to a tabindex=\"-1\" element, so\n * when the toolbar marks this host inactive it suppresses the trigger — and\n * the next focusItem() call silently fails. Lifting the suppression here and\n * directly calling trigger.focus() bypasses that restriction.\n */\n override focus(options?: FocusOptions) {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger) {\n super.focus(options);\n\n return;\n }\n\n $trigger.removeAttribute('tabindex');\n $trigger.focus(options);\n }\n\n /** Caches a weak reference to the first assigned `rc-menu` element. */\n protected _handleMenuSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $elements = $slot.assignedElements();\n const $menu = $elements.find(($el) => $el.tagName === 'RC-MENU') as RCMenu | undefined;\n\n if ($menu) {\n this._$menu = new WeakRef($menu);\n }\n }\n\n /**\n * Keyboard navigation handler.\n *\n * Opens or closes the menu in response to arrow/Enter/Escape keys.\n **/\n protected _onNavigate = (action: KeyboardNavigationAction) => {\n switch (action) {\n case 'open-to-first':\n case 'activate':\n this.openMenu();\n break;\n\n case 'open-to-last':\n this.openMenu('last');\n break;\n\n case 'escape':\n this.closeMenu();\n break;\n }\n };\n\n /** Prevents the default button action and delegates to `toggleMenu`. */\n protected _handleTriggerClick(e: MouseEvent) {\n e.preventDefault();\n\n this.toggleMenu();\n }\n\n /** Closes the menu when an `rc-menu-close` event bubbles up from the popup. */\n protected _handleMenuClose() {\n this.closeMenu();\n }\n\n /** Closes the menu when an `rc-menu-activate` event bubbles up from the popup. */\n protected _handleMenuActivate() {\n this.closeMenu();\n }\n\n /** Closes the menu on clicks outside this component (light dismiss). */\n protected _handleDocumentClick(e: MouseEvent) {\n if (!this.open) {\n return;\n }\n\n const path = e.composedPath();\n\n if (path.includes(this)) {\n return;\n }\n\n this.closeMenu(false);\n }\n\n /** Syncs trigger ARIA when `open` changes; updates anchor placement when `placement` or `orientation` change. */\n protected override updated(changedProperties: Map<PropertyKey, unknown>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n this._syncTriggerAria();\n }\n\n if (changedProperties.has('placement') || changedProperties.has('orientation')) {\n this._anchorCtrl.setOptions({ placement: this._effectivePlacement });\n }\n }\n\n protected _setOpen(open: boolean, dispatch: boolean): void {\n if (this._open === open) {\n return;\n }\n\n const oldValue = this._open;\n\n this._open = open;\n\n this.requestUpdate('open', oldValue);\n this._syncTriggerAria();\n\n if (dispatch) {\n this._dispatchToggle();\n }\n }\n\n /** Writes `aria-haspopup` and `aria-expanded` to the trigger button to match the current open state. */\n protected _syncTriggerAria(): void {\n const $trigger = this._$trigger?.deref();\n\n if (!$trigger?.isConnected) {\n return;\n }\n\n $trigger.setAttribute('aria-haspopup', 'menu');\n $trigger.setAttribute('aria-expanded', String(this.open));\n }\n\n protected override render() {\n return html`\n <div id=\"root\" part=\"root\">\n <div\n id=\"trigger-wrap\"\n ${keyNavigation(this._onNavigate, {\n navigationAxis: this._resolvedOrientation,\n handleNavAxis: false,\n handleOpenAxis: true,\n handleActivate: true,\n handleEscape: this.open,\n })}\n ${keyInteraction()}\n @click=${this._handleTriggerClick}\n >\n <slot name=\"trigger\" @slotchange=${this._handleTriggerSlotChange}></slot>\n <slot\n name=\"indicator\"\n aria-hidden=\"true\"\n @slotchange=${this._handleIndicatorSlotChange}\n ></slot>\n </div>\n\n <div\n id=\"popup\"\n part=\"popup\"\n ?hidden=${!this.open}\n @rc-menu-close=${this._handleMenuClose}\n @rc-menu-activate=${this._handleMenuActivate}\n >\n <slot @slotchange=${this._handleMenuSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCMenuButton;\n"],"names":["menuButtonStyles","css","_RCMenuButton","LitElement","AnchorController","action","value","oldValue","$menubar","orientation","focusTarget","$menu","returnFocus","e","$trigger","$slot","options","$el","changedProperties","open","dispatch","html","keyNavigation","keyInteraction","RCMenuButton","__decorateClass","property","query","state"],"mappings":";;;AAEO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACmEzB,MAAMC,IAAN,MAAMA,UAAqBC,EAAW;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAaL,KAAQ,eAAe,IACvB,KAAQ,QAAQ,IAChB,KAAQ,mBAAmB,IA4D3B,KAAA,YAA6B,gBA0D7B,KAAU,cAAc,IAAIC,EAAiB,MAAM;AAAA,MACjD,QAAQ,MAAM,KAAK,UAAU;AAAA,MAC7B,UAAU,MAAM,KAAK,WAAW;AAAA,MAChC,YAAY,MAAM;AAAA,MAClB,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,CACT,GAGD,KAAU,4BAA4B,KAAK,qBAAqB,KAAK,IAAI,GAmLzE,KAAU,cAAc,CAACC,MAAqC;AAC5D,cAAQA,GAAA;AAAA,QACN,KAAK;AAAA,QACL,KAAK;AACH,eAAK,SAAA;AACL;AAAA,QAEF,KAAK;AACH,eAAK,SAAS,MAAM;AACpB;AAAA,QAEF,KAAK;AACH,eAAK,UAAA;AACL;AAAA,MAAA;AAAA,IAEN;AAAA,EAAA;AAAA,EAxTA,IAAI,OAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,KAAKC,GAA4B;AACnC,UAAMC,IAAW,KAAK;AAEtB,IAAID,MAAU,WAId,KAAK,mBAAmB,IACxB,KAAK,SAASA,GAAO,EAAK,GAC1B,KAAK,cAAc,QAAQC,CAAQ;AAAA,EACrC;AAAA,EASA,IAAI,cAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,YAAYD,GAAgB;AAC9B,UAAMC,IAAW,KAAK;AAEtB,SAAK,eAAeD,GAEhBA,KAAS,CAAC,KAAK,oBACjB,KAAK,SAAS,IAAM,EAAK,GAG3B,KAAK,cAAc,eAAeC,CAAQ;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,IAAc,sBAAuC;AACnD,WAAI,KAAK,cAAc,iBACd,KAAK,YAGP,KAAK,yBAAyB,aAAa,gBAAgB,KAAK;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAc,uBAAkD;AAC9D,QAAI,KAAK;AACP,aAAO,KAAK;AAGd,UAAMC,IAAW,KAAK,QAAQ,8BAA8B;AAE5D,QAAIA,GAAU;AACZ,YAAMC,IACJD,EAAS,aAAa,aAAa,KAAKA,EAAS,aAAa,kBAAkB;AAElF,UAAIC,MAAgB;AAClB,eAAO;AAGT,UAAIA,MAAgB;AAClB,eAAO;AAAA,IAEX;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAyCS,oBAAoB;AAC3B,UAAM,kBAAA,GAEN,KAAK,eAAe,IAAI,iBAAiB,MAAM,KAAK,sBAAsB,GAC1E,KAAK,aAAa,QAAQ,MAAM,EAAE,YAAY,IAAM,iBAAiB,CAAC,UAAU,GAAG,GAEnF,SAAS,iBAAiB,SAAS,KAAK,2BAA2B,EAAI,GAEnE,KAAK,eACP,KAAK,SAAS,IAAM,EAAK;AAAA,EAE7B;AAAA;AAAA,EAGS,uBAAuB;AAC9B,SAAK,cAAc,WAAA,GACnB,KAAK,eAAe,QAEpB,MAAM,qBAAA,GACN,SAAS,oBAAoB,SAAS,KAAK,2BAA2B,EAAI;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAASC,IAAgC,SAAS;AAChD,IAAI,KAAK,SAIT,KAAK,YAAY,WAAW,EAAE,WAAW,KAAK,qBAAqB,GACnE,KAAK,SAAS,IAAM,EAAI,GACxB,KAAK,YAAY,OAAA,GAEjB,KAAK,eAAe,KAAK,MAAM;AAC7B,YAAMC,IAAQ,KAAK,QAAQ,MAAA;AAE3B,MAAAD,MAAgB,SAASC,GAAO,UAAA,IAAcA,GAAO,WAAA;AAAA,IACvD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUC,IAAc,IAAM;AAC5B,IAAK,KAAK,SAIV,KAAK,SAAS,IAAO,EAAI,GAErBA,KACe,KAAK,WAAW,MAAA,GAEvB,MAAA;AAAA,EAEd;AAAA;AAAA,EAGA,aAAa;AACX,IAAI,KAAK,OACP,KAAK,UAAA,IAEL,KAAK,SAAA;AAAA,EAET;AAAA;AAAA,EAGU,kBAAkB;AAC1B,SAAK;AAAA,MACH,IAAI,YAAqC,yBAAyB;AAAA,QAChE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,MAAM,KAAK,KAAA;AAAA,MAAK,CAC3B;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA,EAGU,yBAAyBC,GAAU;AAE3C,UAAMC,IADQD,EAAE,cACO,iBAAA,EAAmB,CAAC;AAE3C,IAAIC,MACF,KAAK,YAAY,IAAI,QAAQA,CAAQ,GACrC,KAAK,iBAAA,GACL,KAAK,qBAAA;AAAA,EAET;AAAA;AAAA,EAGU,2BAA2BD,GAAU;AAC7C,UAAME,IAAQF,EAAE;AAEhB,SAAK,gBAAgB,iBAAiBE,EAAM,iBAAA,EAAmB,SAAS,CAAC;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYU,uBAAuB;AAC/B,UAAMD,IAAW,KAAK,WAAW,MAAA;AAEjC,IAAKA,MAID,KAAK,aAAa,UAAU,MAAM,OACpCA,EAAS,aAAa,YAAY,IAAI,IAEtCA,EAAS,gBAAgB,UAAU;AAAA,EAEvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYS,MAAME,GAAwB;AACrC,UAAMF,IAAW,KAAK,WAAW,MAAA;AAEjC,QAAI,CAACA,GAAU;AACb,YAAM,MAAME,CAAO;AAEnB;AAAA,IACF;AAEA,IAAAF,EAAS,gBAAgB,UAAU,GACnCA,EAAS,MAAME,CAAO;AAAA,EACxB;AAAA;AAAA,EAGU,sBAAsBH,GAAU;AAGxC,UAAMF,IAFQE,EAAE,cACQ,iBAAA,EACA,KAAK,CAACI,MAAQA,EAAI,YAAY,SAAS;AAE/D,IAAIN,MACF,KAAK,SAAS,IAAI,QAAQA,CAAK;AAAA,EAEnC;AAAA;AAAA,EAyBU,oBAAoBE,GAAe;AAC3C,IAAAA,EAAE,eAAA,GAEF,KAAK,WAAA;AAAA,EACP;AAAA;AAAA,EAGU,mBAAmB;AAC3B,SAAK,UAAA;AAAA,EACP;AAAA;AAAA,EAGU,sBAAsB;AAC9B,SAAK,UAAA;AAAA,EACP;AAAA;AAAA,EAGU,qBAAqBA,GAAe;AAO5C,IANI,CAAC,KAAK,QAIGA,EAAE,aAAA,EAEN,SAAS,IAAI,KAItB,KAAK,UAAU,EAAK;AAAA,EACtB;AAAA;AAAA,EAGmB,QAAQK,GAA8C;AACvE,UAAM,QAAQA,CAAiB,GAE3BA,EAAkB,IAAI,MAAM,KAC9B,KAAK,iBAAA,IAGHA,EAAkB,IAAI,WAAW,KAAKA,EAAkB,IAAI,aAAa,MAC3E,KAAK,YAAY,WAAW,EAAE,WAAW,KAAK,qBAAqB;AAAA,EAEvE;AAAA,EAEU,SAASC,GAAeC,GAAyB;AACzD,QAAI,KAAK,UAAUD;AACjB;AAGF,UAAMZ,IAAW,KAAK;AAEtB,SAAK,QAAQY,GAEb,KAAK,cAAc,QAAQZ,CAAQ,GACnC,KAAK,iBAAA,GAEDa,KACF,KAAK,gBAAA;AAAA,EAET;AAAA;AAAA,EAGU,mBAAyB;AACjC,UAAMN,IAAW,KAAK,WAAW,MAAA;AAEjC,IAAKA,GAAU,gBAIfA,EAAS,aAAa,iBAAiB,MAAM,GAC7CA,EAAS,aAAa,iBAAiB,OAAO,KAAK,IAAI,CAAC;AAAA,EAC1D;AAAA,EAEmB,SAAS;AAC1B,WAAOO;AAAA;AAAA;AAAA;AAAA,YAICC,EAAc,KAAK,aAAa;AAAA,MAChC,gBAAgB,KAAK;AAAA,MACrB,eAAe;AAAA,MACf,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,cAAc,KAAK;AAAA,IAAA,CACpB,CAAC;AAAA,YACAC,GAAgB;AAAA,mBACT,KAAK,mBAAmB;AAAA;AAAA,6CAEE,KAAK,wBAAwB;AAAA;AAAA;AAAA;AAAA,0BAIhD,KAAK,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOrC,CAAC,KAAK,IAAI;AAAA,2BACH,KAAK,gBAAgB;AAAA,8BAClB,KAAK,mBAAmB;AAAA;AAAA,8BAExB,KAAK,qBAAqB;AAAA;AAAA;AAAA;AAAA,EAItD;AACF;AA9bErB,EAAO,SAAS,CAACF,CAAgB,GAMjCE,EAAgB,oBAAoC;AAAA,EAClD,GAAGC,EAAW;AAAA,EAEd,gBAAgB;AAAA;AAVb,IAAMqB,IAANtB;AAwBDuB,EAAA;AAAA,EADHC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAvB/BF,EAwBP,WAAA,QAAA,CAAA;AAwBAC,EAAA;AAAA,EADHC,EAAS,EAAE,MAAM,SAAS,WAAW,gBAAgB;AAAA,GA/C3CF,EAgDP,WAAA,eAAA,CAAA;AAuBJC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAtE9BF,EAuEX,WAAA,eAAA,CAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,SAAS,GAAA,CAAM;AAAA,GA1EhBF,EA2EX,WAAA,aAAA,CAAA;AA4C0BC,EAAA;AAAA,EAAzBE,EAAM,OAAO;AAAA,GAvHHH,EAuHe,WAAA,UAAA,CAAA;AAGCC,EAAA;AAAA,EAA1BE,EAAM,QAAQ;AAAA,GA1HJH,EA0HgB,WAAA,WAAA,CAAA;AAIjBC,EAAA;AAAA,EADTG,EAAA;AAAM,GA7HIJ,EA8HD,WAAA,aAAA,CAAA;AAIAC,EAAA;AAAA,EADTG,EAAA;AAAM,GAjIIJ,EAkID,WAAA,UAAA,CAAA;"}