@rcarls/rc-menubar 0.6.0 → 0.7.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 +125 -0
- package/README.md +15 -7
- package/dist/custom-elements.json +43 -7
- package/dist/{rc-menubar-DCZFgZvn.js → rc-menubar-BNaVFLs3.js} +56 -124
- package/dist/rc-menubar-BNaVFLs3.js.map +1 -0
- package/dist/rc-menubar-define.js +3 -1
- package/dist/rc-menubar-define.js.map +1 -1
- package/dist/rc-menubar.js +3 -2
- package/dist/types/packages/rc-menubar/src/rc-menubar.d.ts +33 -8
- package/package.json +3 -4
- package/dist/rc-menubar-DCZFgZvn.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,130 @@
|
|
|
1
1
|
# @rcarls/rc-menubar
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 54d9ead: Localize every component's built-in text. Button names, role
|
|
8
|
+
descriptions, announcements, and default labels now resolve per key from
|
|
9
|
+
the element's `messages` property, then from text registered with
|
|
10
|
+
`registerMessages(locale, catalog)` in `@rcarls/rc-common`, then from the
|
|
11
|
+
English defaults. The locale is the element's own `lang`, else
|
|
12
|
+
`<html lang>`; an ancestor's `lang` is ignored, because it usually marks
|
|
13
|
+
content rather than the interface. Components re-render when that locale
|
|
14
|
+
changes or new text is registered. `RcMessageCatalog` types the catalog,
|
|
15
|
+
and each package adds its scope to it.
|
|
16
|
+
|
|
17
|
+
Numbers a component formats as text follow the same locale:
|
|
18
|
+
`rc-progress`'s default percentage and `rc-splitter`'s `aria-valuetext`
|
|
19
|
+
use `Intl.NumberFormat`. `TypeaheadController` matches prefixes with an
|
|
20
|
+
`Intl.Collator`, so case and accents are ignored the way the locale
|
|
21
|
+
ignores them, and takes a `locale` option. `ItemsCollectionController`'s
|
|
22
|
+
`setCreateOption(text, label?)` takes the option's visible text from its
|
|
23
|
+
caller.
|
|
24
|
+
|
|
25
|
+
`rc-transfer-list`'s direction arrows are now decorative: screen readers
|
|
26
|
+
read only the action name, and the arrows turn over in RTL.
|
|
27
|
+
|
|
28
|
+
**Breaking:** chrome-text properties are replaced by `messages`. Migrate:
|
|
29
|
+
|
|
30
|
+
- `rc-search-bar` `clear-label` / `clearLabel` → `messages.clear`
|
|
31
|
+
- `rc-adaptive-menu` `overflow-label` / `overflowLabel` → `messages.overflow`
|
|
32
|
+
- `rc-chip-group` `show-all-label` / `showAllLabel` and `show-less-label` /
|
|
33
|
+
`showLessLabel` → `messages.showAll` and `messages.showLess`
|
|
34
|
+
- `rc-select` and `rc-combobox` `dialog-confirm-label` /
|
|
35
|
+
`dialogConfirmLabel` and `dialog-cancel-label` / `dialogCancelLabel` →
|
|
36
|
+
`messages.done` and `messages.cancel`
|
|
37
|
+
- `rc-editor-toolbar` `label` → `messages.toolbar`
|
|
38
|
+
|
|
39
|
+
Per-instance names stay attributes, but now default to `undefined` and fall
|
|
40
|
+
back to a message: `label` on `rc-adaptive-menu`, `rc-chip-group`,
|
|
41
|
+
`rc-menubar`, and `rc-splitter`; `available-label` and `selected-label`
|
|
42
|
+
on `rc-transfer-list`; `low-label` and `high-label` on `rc-range-slider`.
|
|
43
|
+
Read the resolved name from the rendered `aria-label` instead of the
|
|
44
|
+
property.
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- 5c006de: Ship component CSS minified. Package builds now run the CSS in Lit `css` styles
|
|
49
|
+
and light-DOM structural styles through Lightning CSS, removing comments and
|
|
50
|
+
whitespace while keeping source maps that resolve to each template. Rendered
|
|
51
|
+
styles are unchanged.
|
|
52
|
+
|
|
53
|
+
`@rcarls/rc-common` adds `cssText`, an identity tag that marks a plain CSS
|
|
54
|
+
string for minification. `rc-chip`, `rc-disclosure`, and `rc-accordion` now
|
|
55
|
+
depend on `@rcarls/rc-common` for it.
|
|
56
|
+
|
|
57
|
+
- 51f6403: Arrow keys follow the reading direction everywhere. `keyNavigation` now also
|
|
58
|
+
flips the cross axis in RTL, so a vertical menu opens its submenu with
|
|
59
|
+
ArrowLeft, as the APG describes. A horizontal menubar and segmented button
|
|
60
|
+
advance with ArrowLeft in RTL, Alt+ArrowLeft moves items toward the selected
|
|
61
|
+
list of a transfer list in RTL, and the arrow toward the inline start reaches
|
|
62
|
+
the chips of a multiple select or combobox (ArrowRight in RTL).
|
|
63
|
+
|
|
64
|
+
Add `inlineArrowKeys(flow)` for content that runs along the inline axis, such
|
|
65
|
+
as chips or text.
|
|
66
|
+
|
|
67
|
+
- 253ba66: Correct package dependency declarations and prevent bundled Markdown implementation types from
|
|
68
|
+
leaking into the editor declarations.
|
|
69
|
+
|
|
70
|
+
BREAKING CHANGE: `@rcarls/rc-textarea-adapters` now treats `@rcarls/rc-textarea` as a peer instead
|
|
71
|
+
of installing it as a runtime dependency. Both textarea extension packages require a compatible
|
|
72
|
+
pre-1 `@rcarls/rc-textarea` release; install it alongside either extension package when upgrading.
|
|
73
|
+
|
|
74
|
+
- 11680b6: Expose and navigate the orientation a widget actually renders in. An
|
|
75
|
+
`orientation` attribute names a layout: `horizontal` runs along the inline
|
|
76
|
+
axis and `vertical` along the block axis, so both turn over in vertical
|
|
77
|
+
writing modes, the way a native `<input type="range">` does. Toolbar,
|
|
78
|
+
menubar, and adaptive menu now report the rendered orientation as
|
|
79
|
+
`aria-orientation`, and their arrow keys follow it, so a horizontal toolbar
|
|
80
|
+
in vertical text navigates with ArrowDown.
|
|
81
|
+
|
|
82
|
+
`keyNavigation` treats an explicit `navigationAxis` and role defaults as
|
|
83
|
+
layout orientations and converts them the same way; an explicit
|
|
84
|
+
`aria-orientation` attribute is still used as is. Add `renderedOrientation`
|
|
85
|
+
and a `FlowController` that keeps a host's writing mode and direction current
|
|
86
|
+
for rendering.
|
|
87
|
+
|
|
88
|
+
`rc-toolbar` now reflects `orientation` to its host attribute, and its
|
|
89
|
+
vertical layout is keyed off that attribute rather than `aria-orientation`.
|
|
90
|
+
|
|
91
|
+
- Updated dependencies [e3dfa59]
|
|
92
|
+
- Updated dependencies [50d5610]
|
|
93
|
+
- Updated dependencies [9ee769c]
|
|
94
|
+
- Updated dependencies [1179f24]
|
|
95
|
+
- Updated dependencies [595fe37]
|
|
96
|
+
- Updated dependencies [38cd00c]
|
|
97
|
+
- Updated dependencies [5c006de]
|
|
98
|
+
- Updated dependencies [a6553ff]
|
|
99
|
+
- Updated dependencies [2205478]
|
|
100
|
+
- Updated dependencies [4341311]
|
|
101
|
+
- Updated dependencies [899bb5e]
|
|
102
|
+
- Updated dependencies [25fcfe0]
|
|
103
|
+
- Updated dependencies [51f6403]
|
|
104
|
+
- Updated dependencies [9caca6b]
|
|
105
|
+
- Updated dependencies [b764a3c]
|
|
106
|
+
- Updated dependencies [54d9ead]
|
|
107
|
+
- Updated dependencies [94dc987]
|
|
108
|
+
- Updated dependencies [b9175e9]
|
|
109
|
+
- Updated dependencies [c8b762b]
|
|
110
|
+
- Updated dependencies [55e1e7f]
|
|
111
|
+
- Updated dependencies [f1ca82d]
|
|
112
|
+
- Updated dependencies [b87f27b]
|
|
113
|
+
- Updated dependencies [32ebead]
|
|
114
|
+
- Updated dependencies [bfefedd]
|
|
115
|
+
- Updated dependencies [c130173]
|
|
116
|
+
- Updated dependencies [f0f7511]
|
|
117
|
+
- Updated dependencies [c5b6f15]
|
|
118
|
+
- Updated dependencies [11680b6]
|
|
119
|
+
- Updated dependencies [223d36c]
|
|
120
|
+
- Updated dependencies [7b91a44]
|
|
121
|
+
- Updated dependencies [aa04ead]
|
|
122
|
+
- Updated dependencies [ac65b5b]
|
|
123
|
+
- Updated dependencies [afcfef8]
|
|
124
|
+
- Updated dependencies [11ef1ad]
|
|
125
|
+
- @rcarls/rc-common@0.7.0
|
|
126
|
+
- @rcarls/rc-menu-button@0.7.0
|
|
127
|
+
|
|
3
128
|
## 0.6.0
|
|
4
129
|
|
|
5
130
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -67,10 +67,18 @@ Place `rc-menu-button` elements as direct children. The menubar manages focus an
|
|
|
67
67
|
|
|
68
68
|
### Properties / attributes
|
|
69
69
|
|
|
70
|
-
| Property | Attribute | Type | Default
|
|
71
|
-
| ------------- | ------------- | ---------------------------- |
|
|
72
|
-
| `label` | `label` | `string`
|
|
73
|
-
| `orientation` | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'`
|
|
70
|
+
| Property | Attribute | Type | Default | Description |
|
|
71
|
+
| ------------- | ------------- | ---------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `label` | `label` | `string \| undefined` | `label` message | `aria-label` for the menubar. Required; no visible label is rendered by the component. |
|
|
73
|
+
| `orientation` | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout direction and keyboard navigation axis. Propagated to child `rc-menu-button` elements for arrow-key open direction. |
|
|
74
|
+
|
|
75
|
+
### Localization
|
|
76
|
+
|
|
77
|
+
Built-in text follows the element's own `lang`, else `<html lang>`, and never an
|
|
78
|
+
ancestor's `lang`, which usually marks content. Override it per element with the
|
|
79
|
+
`messages` property, or for every instance with `registerMessages()` from
|
|
80
|
+
`@rcarls/rc-common` under `rc-menubar`. Keys: `label`. See the
|
|
81
|
+
[rc-common Localization section](https://github.com/richardcarls/rc-webcomponents/tree/develop/packages/rc-common#localization).
|
|
74
82
|
|
|
75
83
|
### CSS custom properties
|
|
76
84
|
|
|
@@ -91,7 +99,7 @@ Place `rc-menu-button` elements as direct children. The menubar manages focus an
|
|
|
91
99
|
| `--rc-menubar-item-radius` | `var(--rc-control-radius)` | Child trigger border radius |
|
|
92
100
|
| `--rc-menubar-item-background` | `transparent` | Child trigger background |
|
|
93
101
|
| `--rc-menubar-item-color` | `inherit` | Child trigger text color |
|
|
94
|
-
| `--rc-menubar-item-transition` |
|
|
102
|
+
| `--rc-menubar-item-transition` | Not set | Child trigger state transition |
|
|
95
103
|
| `--rc-menubar-item-hover-background` | `color-mix(in srgb, Highlight 8%, transparent)` | Child trigger hover background |
|
|
96
104
|
| `--rc-menubar-item-hover-color` | `inherit` | Child trigger hover text color |
|
|
97
105
|
| `--rc-menubar-item-hover-border-color` | `transparent` | Child trigger hover border color |
|
|
@@ -138,7 +146,7 @@ $previousItem: HTMLElement | undefined
|
|
|
138
146
|
|
|
139
147
|
---
|
|
140
148
|
|
|
141
|
-
## Keyboard
|
|
149
|
+
## Keyboard behavior
|
|
142
150
|
|
|
143
151
|
Horizontal orientation (default):
|
|
144
152
|
|
|
@@ -159,7 +167,7 @@ For vertical orientation, `ArrowDown`/`ArrowUp` replace `ArrowRight`/`ArrowLeft`
|
|
|
159
167
|
|
|
160
168
|
| Attribute | Where | Value |
|
|
161
169
|
| ------------------ | ------------------ | ------------------------------------------------ |
|
|
162
|
-
| `role="menubar"` | Host element |
|
|
170
|
+
| `role="menubar"` | Host element | `menubar` |
|
|
163
171
|
| `aria-orientation` | Host element | `"horizontal"` or `"vertical"` |
|
|
164
172
|
| `aria-label` | Host element | Value of `label` property |
|
|
165
173
|
| `tabindex="0"` | Active trigger | One trigger tabbable at a time (roving tabindex) |
|
|
@@ -44,9 +44,16 @@
|
|
|
44
44
|
"kind": "javascript-module",
|
|
45
45
|
"path": "src/rc-menubar.ts",
|
|
46
46
|
"declarations": [
|
|
47
|
+
{
|
|
48
|
+
"kind": "variable",
|
|
49
|
+
"name": "DEFAULT_MENUBAR_MESSAGES",
|
|
50
|
+
"type": {
|
|
51
|
+
"text": "Readonly<RCMenubarMessages>"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
47
54
|
{
|
|
48
55
|
"kind": "class",
|
|
49
|
-
"description": "Menubar coordinator for rc-menu-button children with roving tabindex and submenu\nhandoff, following the WAI-ARIA Menubar pattern.\n\nUses roving tabindex rather than aria-activedescendant so trigger buttons\nreceive real focus — required for submenu handoff and screen reader announcements
|
|
56
|
+
"description": "Menubar coordinator for rc-menu-button children with roving tabindex and submenu\nhandoff, following the WAI-ARIA Menubar pattern.\n\nUses roving tabindex rather than aria-activedescendant so trigger buttons\nreceive real focus — required for submenu handoff and screen reader announcements.\n\n\nBuilt-in text (the default menubar name) follows the element's own `lang`, else\n`<html lang>`: per element through `messages`, or for every instance\nthrough `registerMessages()` from `@rcarls/rc-common` under `rc-menubar`.",
|
|
50
57
|
"name": "RCMenubar",
|
|
51
58
|
"cssProperties": [
|
|
52
59
|
{
|
|
@@ -172,14 +179,28 @@
|
|
|
172
179
|
}
|
|
173
180
|
],
|
|
174
181
|
"members": [
|
|
182
|
+
{
|
|
183
|
+
"kind": "field",
|
|
184
|
+
"name": "messages",
|
|
185
|
+
"type": {
|
|
186
|
+
"text": "Partial<RCMenubarMessages> | undefined"
|
|
187
|
+
},
|
|
188
|
+
"description": "Built-in text overrides; unset keys fall back to registered text, then English."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"kind": "field",
|
|
192
|
+
"name": "_messages",
|
|
193
|
+
"privacy": "private",
|
|
194
|
+
"readonly": true,
|
|
195
|
+
"default": "new MessagesController( this, 'rc-menubar', DEFAULT_MENUBAR_MESSAGES, { overrides: () => this.messages, }, )"
|
|
196
|
+
},
|
|
175
197
|
{
|
|
176
198
|
"kind": "field",
|
|
177
199
|
"name": "label",
|
|
178
200
|
"type": {
|
|
179
|
-
"text": "string"
|
|
201
|
+
"text": "string | undefined"
|
|
180
202
|
},
|
|
181
|
-
"
|
|
182
|
-
"description": "Accessible label for the `role=\"menubar\"` element.",
|
|
203
|
+
"description": "Accessible label for the `role=\"menubar\"` element. Defaults to the `label` message.",
|
|
183
204
|
"attribute": "label"
|
|
184
205
|
},
|
|
185
206
|
{
|
|
@@ -233,6 +254,14 @@
|
|
|
233
254
|
"privacy": "protected",
|
|
234
255
|
"description": "Bound click handler, held for `removeEventListener` pairing."
|
|
235
256
|
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "field",
|
|
259
|
+
"name": "_flow",
|
|
260
|
+
"privacy": "protected",
|
|
261
|
+
"readonly": true,
|
|
262
|
+
"default": "new FlowController(this)",
|
|
263
|
+
"description": "Keeps the exposed aria-orientation on the orientation actually rendered."
|
|
264
|
+
},
|
|
236
265
|
{
|
|
237
266
|
"kind": "method",
|
|
238
267
|
"name": "_syncHostAria",
|
|
@@ -463,12 +492,11 @@
|
|
|
463
492
|
],
|
|
464
493
|
"attributes": [
|
|
465
494
|
{
|
|
466
|
-
"description": "Accessible label for the `role=\"menubar\"` element.",
|
|
495
|
+
"description": "Accessible label for the `role=\"menubar\"` element. Defaults to the `label` message.",
|
|
467
496
|
"name": "label",
|
|
468
497
|
"type": {
|
|
469
|
-
"text": "string"
|
|
498
|
+
"text": "string | undefined"
|
|
470
499
|
},
|
|
471
|
-
"default": "'Menu'",
|
|
472
500
|
"fieldName": "label"
|
|
473
501
|
},
|
|
474
502
|
{
|
|
@@ -490,6 +518,14 @@
|
|
|
490
518
|
}
|
|
491
519
|
],
|
|
492
520
|
"exports": [
|
|
521
|
+
{
|
|
522
|
+
"kind": "js",
|
|
523
|
+
"name": "DEFAULT_MENUBAR_MESSAGES",
|
|
524
|
+
"declaration": {
|
|
525
|
+
"name": "DEFAULT_MENUBAR_MESSAGES",
|
|
526
|
+
"module": "src/rc-menubar.ts"
|
|
527
|
+
}
|
|
528
|
+
},
|
|
493
529
|
{
|
|
494
530
|
"kind": "js",
|
|
495
531
|
"name": "RCMenubar",
|
|
@@ -1,108 +1,29 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { property as
|
|
3
|
-
import "@rcarls/rc-common";
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#root {
|
|
10
|
-
display: flex;
|
|
11
|
-
flex-direction: row;
|
|
12
|
-
align-items: stretch;
|
|
13
|
-
gap: var(--rc-menubar-gap, var(--rc-control-gap, 0.25em));
|
|
14
|
-
padding-inline: var(--rc-menubar-padding-inline, var(--rc-control-padding-inline, 0.25em));
|
|
15
|
-
padding-block: var(--rc-menubar-padding-block, var(--rc-control-padding-block, 0.25em));
|
|
16
|
-
border: var(--rc-menubar-border, var(--rc-border, 1px solid ButtonBorder));
|
|
17
|
-
border-radius: var(--rc-menubar-radius, var(--rc-control-radius, 0));
|
|
18
|
-
background: var(--rc-menubar-background, var(--rc-surface, Canvas));
|
|
19
|
-
color: var(--rc-menubar-color, var(--rc-field-text, CanvasText));
|
|
20
|
-
font-family: var(--rc-font-family, inherit);
|
|
21
|
-
font-size: var(--rc-font-size, inherit);
|
|
22
|
-
line-height: var(--rc-line-height, normal);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
:host([orientation='vertical']) #root {
|
|
26
|
-
flex-direction: column;
|
|
27
|
-
align-items: stretch;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#slot-wrap {
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: inherit;
|
|
33
|
-
align-items: stretch;
|
|
34
|
-
gap: inherit;
|
|
35
|
-
min-inline-size: 0;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
::slotted(rc-menu-button) {
|
|
39
|
-
flex: 0 0 auto;
|
|
40
|
-
--rc-menu-button-trigger-block-size: var(--rc-menubar-item-block-size, 2.25em);
|
|
41
|
-
--rc-menu-button-trigger-padding-block: var(--rc-menubar-item-padding-block, 0.25em);
|
|
42
|
-
--rc-menu-button-trigger-padding-inline: var(--rc-menubar-item-padding-inline, 0.75em);
|
|
43
|
-
--rc-menu-button-trigger-gap: var(--rc-menubar-item-gap, var(--rc-item-gap, 0.5em));
|
|
44
|
-
--rc-menu-button-trigger-border: var(--rc-menubar-item-border, 1px solid transparent);
|
|
45
|
-
--rc-menu-button-trigger-radius: var(
|
|
46
|
-
--rc-menubar-item-radius,
|
|
47
|
-
var(--rc-control-radius, 0.125em)
|
|
48
|
-
);
|
|
49
|
-
--rc-menu-button-trigger-background: var(--rc-menubar-item-background, transparent);
|
|
50
|
-
--rc-menu-button-trigger-color: var(--rc-menubar-item-color, inherit);
|
|
51
|
-
--rc-menu-button-trigger-transition: var(--rc-menubar-item-transition);
|
|
52
|
-
--rc-menu-button-trigger-hover-border-color: var(
|
|
53
|
-
--rc-menubar-item-hover-border-color,
|
|
54
|
-
transparent
|
|
55
|
-
);
|
|
56
|
-
--rc-menu-button-trigger-hover-background: var(
|
|
57
|
-
--rc-menubar-item-hover-background,
|
|
58
|
-
color-mix(in srgb, Highlight 8%, transparent)
|
|
59
|
-
);
|
|
60
|
-
--rc-menu-button-trigger-hover-color: var(--rc-menubar-item-hover-color, inherit);
|
|
61
|
-
--rc-menu-button-trigger-open-border-color: var(
|
|
62
|
-
--rc-menubar-item-open-border-color,
|
|
63
|
-
transparent
|
|
64
|
-
);
|
|
65
|
-
--rc-menu-button-trigger-open-background: var(
|
|
66
|
-
--rc-menubar-item-open-background,
|
|
67
|
-
color-mix(in srgb, Highlight 12%, transparent)
|
|
68
|
-
);
|
|
69
|
-
--rc-menu-button-trigger-open-color: var(--rc-menubar-item-open-color, inherit);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
::slotted(rc-menu-button[open]) {
|
|
73
|
-
--rc-menu-button-trigger-background: var(
|
|
74
|
-
--rc-menubar-item-open-background,
|
|
75
|
-
color-mix(in srgb, Highlight 12%, transparent)
|
|
76
|
-
);
|
|
77
|
-
--rc-menu-button-trigger-color: var(--rc-menubar-item-open-color, inherit);
|
|
78
|
-
--rc-menu-button-trigger-hover-background: var(
|
|
79
|
-
--rc-menubar-item-open-background,
|
|
80
|
-
color-mix(in srgb, Highlight 12%, transparent)
|
|
81
|
-
);
|
|
82
|
-
--rc-menu-button-trigger-hover-color: var(--rc-menubar-item-open-color, inherit);
|
|
83
|
-
--rc-menu-button-trigger-hover-border-color: var(
|
|
84
|
-
--rc-menubar-item-open-border-color,
|
|
85
|
-
transparent
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
:host([orientation='vertical']) ::slotted(rc-menu-button) {
|
|
90
|
-
inline-size: 100%;
|
|
91
|
-
}
|
|
92
|
-
`;
|
|
93
|
-
var f = Object.defineProperty, u = (l, t, e, n) => {
|
|
94
|
-
for (var i = void 0, r = l.length - 1, o; r >= 0; r--)
|
|
95
|
-
(o = l[r]) && (i = o(t, e, i) || i);
|
|
96
|
-
return i && f(t, e, i), i;
|
|
1
|
+
import { css as b, LitElement as v, html as p } from "lit";
|
|
2
|
+
import { property as c, state as g } from "lit/decorators.js";
|
|
3
|
+
import { MessagesController as f, FlowController as _, renderedOrientation as h, resolveFlow as $, arrowKeys as k } from "@rcarls/rc-common";
|
|
4
|
+
const y = b`:host{display:inline-block}#root{align-items:stretch;gap:var(--rc-menubar-gap,var(--rc-control-gap,.25em));padding-inline:var(--rc-menubar-padding-inline,var(--rc-control-padding-inline,.25em));padding-block:var(--rc-menubar-padding-block,var(--rc-control-padding-block,.25em));border:var(--rc-menubar-border,var(--rc-border,1px solid ButtonBorder));border-radius:var(--rc-menubar-radius,var(--rc-control-radius,0));background:var(--rc-menubar-background,var(--rc-surface,Canvas));color:var(--rc-menubar-color,var(--rc-field-text,CanvasText));font-family:var(--rc-font-family,inherit);font-size:var(--rc-font-size,inherit);line-height:var(--rc-line-height,normal);flex-direction:row;display:flex}:host([orientation=vertical]) #root{flex-direction:column;align-items:stretch}#slot-wrap{flex-direction:inherit;align-items:stretch;gap:inherit;min-inline-size:0;display:flex}::slotted(rc-menu-button){--rc-menu-button-trigger-block-size:var(--rc-menubar-item-block-size,2.25em);--rc-menu-button-trigger-padding-block:var(--rc-menubar-item-padding-block,.25em);--rc-menu-button-trigger-padding-inline:var(--rc-menubar-item-padding-inline,.75em);--rc-menu-button-trigger-gap:var(--rc-menubar-item-gap,var(--rc-item-gap,.5em));--rc-menu-button-trigger-border:var(--rc-menubar-item-border,1px solid transparent);--rc-menu-button-trigger-radius:var(--rc-menubar-item-radius,var(--rc-control-radius,.125em));--rc-menu-button-trigger-background:var(--rc-menubar-item-background,transparent);--rc-menu-button-trigger-color:var(--rc-menubar-item-color,inherit);--rc-menu-button-trigger-transition:var(--rc-menubar-item-transition);--rc-menu-button-trigger-hover-border-color:var(--rc-menubar-item-hover-border-color,transparent);--rc-menu-button-trigger-hover-background:var(--rc-menubar-item-hover-background,color-mix(in srgb, Highlight 8%, transparent));--rc-menu-button-trigger-hover-color:var(--rc-menubar-item-hover-color,inherit);--rc-menu-button-trigger-open-border-color:var(--rc-menubar-item-open-border-color,transparent);--rc-menu-button-trigger-open-background:var(--rc-menubar-item-open-background,color-mix(in srgb, Highlight 12%, transparent));--rc-menu-button-trigger-open-color:var(--rc-menubar-item-open-color,inherit);flex:none}::slotted(rc-menu-button[open]){--rc-menu-button-trigger-background:var(--rc-menubar-item-open-background,color-mix(in srgb, Highlight 12%, transparent));--rc-menu-button-trigger-color:var(--rc-menubar-item-open-color,inherit);--rc-menu-button-trigger-hover-background:var(--rc-menubar-item-open-background,color-mix(in srgb, Highlight 12%, transparent));--rc-menu-button-trigger-hover-color:var(--rc-menubar-item-open-color,inherit);--rc-menu-button-trigger-hover-border-color:var(--rc-menubar-item-open-border-color,transparent)}:host([orientation=vertical]) ::slotted(rc-menu-button){inline-size:100%}`;
|
|
5
|
+
var M = Object.defineProperty, u = (d, t, e, n) => {
|
|
6
|
+
for (var o = void 0, i = d.length - 1, r; i >= 0; i--)
|
|
7
|
+
(r = d[i]) && (o = r(t, e, o) || o);
|
|
8
|
+
return o && M(t, e, o), o;
|
|
97
9
|
};
|
|
98
|
-
const
|
|
10
|
+
const A = {
|
|
99
11
|
Up: "ArrowUp",
|
|
100
12
|
Down: "ArrowDown",
|
|
101
13
|
Left: "ArrowLeft",
|
|
102
14
|
Right: "ArrowRight"
|
|
103
|
-
},
|
|
15
|
+
}, x = Object.freeze({
|
|
16
|
+
label: "Menu"
|
|
17
|
+
}), l = class l extends v {
|
|
104
18
|
constructor() {
|
|
105
|
-
super(...arguments), this.
|
|
19
|
+
super(...arguments), this._messages = new f(
|
|
20
|
+
this,
|
|
21
|
+
"rc-menubar",
|
|
22
|
+
x,
|
|
23
|
+
{
|
|
24
|
+
overrides: () => this.messages
|
|
25
|
+
}
|
|
26
|
+
), this.orientation = "horizontal", this._$menuButtons = [], this._boundHandleKeydown = this._handleKeydown.bind(this), this._boundHandleClick = this._handleClick.bind(this), this._flow = new _(this);
|
|
106
27
|
}
|
|
107
28
|
/** Syncs host ARIA attributes and registers keyboard and click handlers. */
|
|
108
29
|
connectedCallback() {
|
|
@@ -112,13 +33,17 @@ const $ = {
|
|
|
112
33
|
disconnectedCallback() {
|
|
113
34
|
super.disconnectedCallback(), this.removeEventListener("keydown", this._boundHandleKeydown), this.removeEventListener("click", this._boundHandleClick);
|
|
114
35
|
}
|
|
115
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Syncs host ARIA on every update, since a writing-mode change reaches it
|
|
38
|
+
* through the flow controller rather than a property, and child orientation
|
|
39
|
+
* when `orientation` changes.
|
|
40
|
+
*/
|
|
116
41
|
updated(t) {
|
|
117
|
-
super.updated(t),
|
|
42
|
+
super.updated(t), this._syncHostAria(), t.has("orientation") && this._syncMenuButtonOrientation();
|
|
118
43
|
}
|
|
119
44
|
/** Writes `role`, `aria-label`, and `aria-orientation` to the host element. */
|
|
120
45
|
_syncHostAria() {
|
|
121
|
-
this.setAttribute("role", "menubar"), this.setAttribute("aria-label", this.label), this.setAttribute("aria-orientation", this.orientation);
|
|
46
|
+
this.setAttribute("role", "menubar"), this.setAttribute("aria-label", this.label ?? this._messages.value.label), this.setAttribute("aria-orientation", h(this.orientation, this._flow.flow));
|
|
122
47
|
}
|
|
123
48
|
/** Propagates the current `orientation` value to all slotted `rc-menu-button` children. */
|
|
124
49
|
_syncMenuButtonOrientation() {
|
|
@@ -180,24 +105,24 @@ const $ = {
|
|
|
180
105
|
}
|
|
181
106
|
/** Refreshes the cached `rc-menu-button` list when slotted children change. */
|
|
182
107
|
_handleSlotChange(t) {
|
|
183
|
-
const n = t.currentTarget.assignedElements(),
|
|
184
|
-
this._$menuButtons = n.filter((
|
|
108
|
+
const n = t.currentTarget.assignedElements(), o = this._$menuButtons;
|
|
109
|
+
this._$menuButtons = n.filter((i) => i.tagName === "RC-MENU-BUTTON").map((i) => new WeakRef(i)), queueMicrotask(() => {
|
|
185
110
|
if (!this.isConnected)
|
|
186
111
|
return;
|
|
187
|
-
|
|
188
|
-
const a =
|
|
112
|
+
o.forEach((r) => {
|
|
113
|
+
const a = r.deref();
|
|
189
114
|
if (!a)
|
|
190
115
|
return;
|
|
191
116
|
a.removeAttribute("role");
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
}), this.$menuButtons.forEach((
|
|
195
|
-
|
|
117
|
+
const m = this._$getTrigger(a);
|
|
118
|
+
m?.removeAttribute("tabindex"), m?.removeAttribute("role");
|
|
119
|
+
}), this.$menuButtons.forEach((r) => {
|
|
120
|
+
r.removeAttribute("role"), r.orientation = this.orientation, this._$getTrigger(r)?.setAttribute("role", "menuitem");
|
|
196
121
|
});
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}),
|
|
122
|
+
const i = this.$items;
|
|
123
|
+
i.forEach((r, a) => {
|
|
124
|
+
r.setAttribute("tabindex", a === 0 ? "0" : "-1");
|
|
125
|
+
}), i.length > 0 && !this._$lastFocused && (this._$lastFocused = i[0]);
|
|
201
126
|
});
|
|
202
127
|
}
|
|
203
128
|
/** Tracks which child `rc-menu-button` is currently open. */
|
|
@@ -242,16 +167,19 @@ const $ = {
|
|
|
242
167
|
}
|
|
243
168
|
/** Translates keyboard events to navigation actions and activates keyboard interaction mode. */
|
|
244
169
|
_handleKeydown(t) {
|
|
245
|
-
const e =
|
|
170
|
+
const e = A[t.key] ?? t.key, n = $(this), { next: o, prev: i } = k(
|
|
171
|
+
h(this.orientation, n),
|
|
172
|
+
n
|
|
173
|
+
);
|
|
246
174
|
let r;
|
|
247
|
-
e ===
|
|
175
|
+
e === o ? r = "next" : e === i ? r = "prev" : e === "Home" ? r = "start" : e === "End" ? r = "end" : e === "Escape" ? r = "escape" : e === "Tab" && this.setAttribute("data-interaction-mode", "keyboard"), r && (this._handleNavigate(r), this.setAttribute("data-interaction-mode", "keyboard"), t.stopPropagation(), t.preventDefault());
|
|
248
176
|
}
|
|
249
177
|
/** Clears keyboard interaction mode on pointer click. */
|
|
250
178
|
_handleClick() {
|
|
251
179
|
this.removeAttribute("data-interaction-mode");
|
|
252
180
|
}
|
|
253
181
|
render() {
|
|
254
|
-
return
|
|
182
|
+
return p`
|
|
255
183
|
<div id="root" part="root">
|
|
256
184
|
<div
|
|
257
185
|
id="slot-wrap"
|
|
@@ -264,21 +192,25 @@ const $ = {
|
|
|
264
192
|
`;
|
|
265
193
|
}
|
|
266
194
|
};
|
|
267
|
-
|
|
268
|
-
let s =
|
|
195
|
+
l.styles = [y];
|
|
196
|
+
let s = l;
|
|
197
|
+
u([
|
|
198
|
+
c({ attribute: !1 })
|
|
199
|
+
], s.prototype, "messages");
|
|
269
200
|
u([
|
|
270
|
-
|
|
201
|
+
c({ type: String })
|
|
271
202
|
], s.prototype, "label");
|
|
272
203
|
u([
|
|
273
|
-
|
|
204
|
+
c({ type: String, reflect: !0 })
|
|
274
205
|
], s.prototype, "orientation");
|
|
275
206
|
u([
|
|
276
|
-
|
|
207
|
+
g()
|
|
277
208
|
], s.prototype, "_$activeMenuButton");
|
|
278
209
|
u([
|
|
279
|
-
|
|
210
|
+
g()
|
|
280
211
|
], s.prototype, "_$lastFocused");
|
|
281
212
|
export {
|
|
213
|
+
x as D,
|
|
282
214
|
s as R
|
|
283
215
|
};
|
|
284
|
-
//# sourceMappingURL=rc-menubar-
|
|
216
|
+
//# sourceMappingURL=rc-menubar-BNaVFLs3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-menubar-BNaVFLs3.js","sources":["../src/rc-menubar.styles.ts","../src/rc-menubar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menubarStyles = css`\n :host {\n display: inline-block;\n }\n\n #root {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n gap: var(--rc-menubar-gap, var(--rc-control-gap, 0.25em));\n padding-inline: var(--rc-menubar-padding-inline, var(--rc-control-padding-inline, 0.25em));\n padding-block: var(--rc-menubar-padding-block, var(--rc-control-padding-block, 0.25em));\n border: var(--rc-menubar-border, var(--rc-border, 1px solid ButtonBorder));\n border-radius: var(--rc-menubar-radius, var(--rc-control-radius, 0));\n background: var(--rc-menubar-background, var(--rc-surface, Canvas));\n color: var(--rc-menubar-color, var(--rc-field-text, CanvasText));\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n }\n\n :host([orientation='vertical']) #root {\n flex-direction: column;\n align-items: stretch;\n }\n\n #slot-wrap {\n display: flex;\n flex-direction: inherit;\n align-items: stretch;\n gap: inherit;\n min-inline-size: 0;\n }\n\n ::slotted(rc-menu-button) {\n flex: 0 0 auto;\n --rc-menu-button-trigger-block-size: var(--rc-menubar-item-block-size, 2.25em);\n --rc-menu-button-trigger-padding-block: var(--rc-menubar-item-padding-block, 0.25em);\n --rc-menu-button-trigger-padding-inline: var(--rc-menubar-item-padding-inline, 0.75em);\n --rc-menu-button-trigger-gap: var(--rc-menubar-item-gap, var(--rc-item-gap, 0.5em));\n --rc-menu-button-trigger-border: var(--rc-menubar-item-border, 1px solid transparent);\n --rc-menu-button-trigger-radius: var(\n --rc-menubar-item-radius,\n var(--rc-control-radius, 0.125em)\n );\n --rc-menu-button-trigger-background: var(--rc-menubar-item-background, transparent);\n --rc-menu-button-trigger-color: var(--rc-menubar-item-color, inherit);\n --rc-menu-button-trigger-transition: var(--rc-menubar-item-transition);\n --rc-menu-button-trigger-hover-border-color: var(\n --rc-menubar-item-hover-border-color,\n transparent\n );\n --rc-menu-button-trigger-hover-background: var(\n --rc-menubar-item-hover-background,\n color-mix(in srgb, Highlight 8%, transparent)\n );\n --rc-menu-button-trigger-hover-color: var(--rc-menubar-item-hover-color, inherit);\n --rc-menu-button-trigger-open-border-color: var(\n --rc-menubar-item-open-border-color,\n transparent\n );\n --rc-menu-button-trigger-open-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-open-color: var(--rc-menubar-item-open-color, inherit);\n }\n\n ::slotted(rc-menu-button[open]) {\n --rc-menu-button-trigger-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-color: var(--rc-menubar-item-open-color, inherit);\n --rc-menu-button-trigger-hover-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-hover-color: var(--rc-menubar-item-open-color, inherit);\n --rc-menu-button-trigger-hover-border-color: var(\n --rc-menubar-item-open-border-color,\n transparent\n );\n }\n\n :host([orientation='vertical']) ::slotted(rc-menu-button) {\n inline-size: 100%;\n }\n`;\n\nexport default menubarStyles;\n","import { LitElement, html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport {\n arrowKeys,\n MessagesController,\n FlowController,\n renderedOrientation,\n resolveFlow,\n type KeyboardNavigationAction,\n} from '@rcarls/rc-common';\nimport type { RCMenuButton, RCMenuButtonToggleEvent } from '@rcarls/rc-menu-button';\n\nimport menubarStyles from './rc-menubar.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-menubar': RCMenubar;\n }\n}\n\nconst IE_KEY_ALIASES: Record<string, string> = {\n Up: 'ArrowUp',\n Down: 'ArrowDown',\n Left: 'ArrowLeft',\n Right: 'ArrowRight',\n};\n\n/** Built-in text of `rc-menubar`. */\nexport interface RCMenubarMessages {\n /** Default accessible name of the menubar, when `label` is unset. */\n label: string;\n}\n\nexport const DEFAULT_MENUBAR_MESSAGES: Readonly<RCMenubarMessages> = Object.freeze({\n label: 'Menu',\n});\n\ndeclare module '@rcarls/rc-common' {\n interface RcMessageCatalog {\n 'rc-menubar': RCMenubarMessages;\n }\n}\n\n/**\n * Menubar coordinator for rc-menu-button children with roving tabindex and submenu\n * handoff, following the WAI-ARIA Menubar pattern.\n *\n * Uses roving tabindex rather than aria-activedescendant so trigger buttons\n * receive real focus — required for submenu handoff and screen reader announcements.\n *\n *\n * Built-in text (the default menubar name) follows the element's own `lang`, else\n * `<html lang>`: per element through `messages`, or for every instance\n * through `registerMessages()` from `@rcarls/rc-common` under `rc-menubar`.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-menubar rc-menubar docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menubar/ WAI-ARIA Menubar pattern}\n *\n * @slot default - Takes rc-menu-button elements to display in the menubar\n *\n * @csspart root - The root container element\n *\n * @attr label - Accessible label for the `role=\"menubar\"` element. Defaults to the `label` message.\n * @attr orientation - Layout along the inline (`horizontal`) or block (`vertical`) axis,\n * propagated to child `rc-menu-button` elements. Both turn over in vertical writing\n * modes; `aria-orientation` and the arrow keys follow the orientation actually rendered.\n *\n * @cssprop [--rc-menubar-gap=var(--rc-control-gap)] - Gap between menu buttons\n * @cssprop [--rc-menubar-padding-inline=var(--rc-control-padding-inline)] - Inline-axis padding\n * @cssprop [--rc-menubar-padding-block=var(--rc-control-padding-block)] - Block-axis padding\n * @cssprop [--rc-menubar-border=var(--rc-border)] - Root container border\n * @cssprop [--rc-menubar-radius=var(--rc-control-radius)] - Root container border radius\n * @cssprop [--rc-menubar-background=Canvas] - Root container background\n * @cssprop [--rc-menubar-color=CanvasText] - Root container text color\n * @cssprop [--rc-menubar-item-block-size=2.25em] - Minimum block size for child menu-button triggers\n * @cssprop [--rc-menubar-item-padding-block=0.25em] - Child trigger block-axis padding\n * @cssprop [--rc-menubar-item-padding-inline=0.75em] - Child trigger inline-axis padding\n * @cssprop [--rc-menubar-item-gap=var(--rc-item-gap)] - Gap between flex children inside child triggers\n * @cssprop [--rc-menubar-item-border=1px solid transparent] - Child trigger border\n * @cssprop [--rc-menubar-item-radius=var(--rc-control-radius)] - Child trigger border radius\n * @cssprop [--rc-menubar-item-background=transparent] - Child trigger background\n * @cssprop [--rc-menubar-item-color=inherit] - Child trigger text color\n * @cssprop [--rc-menubar-item-transition] - CSS transition applied to child triggers\n * @cssprop [--rc-menubar-item-hover-background=color-mix(in srgb, Highlight 8%, transparent)] - Child trigger hover background\n * @cssprop [--rc-menubar-item-hover-color=inherit] - Child trigger hover text color\n * @cssprop [--rc-menubar-item-hover-border-color=transparent] - Child trigger hover border color\n * @cssprop [--rc-menubar-item-open-background=color-mix(in srgb, Highlight 12%, transparent)] - Child trigger background when its menu is open\n * @cssprop [--rc-menubar-item-open-color=inherit] - Child trigger text color when its menu is open\n * @cssprop [--rc-menubar-item-open-border-color=transparent] - Child trigger border color when its menu is open\n */\nexport class RCMenubar extends LitElement {\n static styles = [menubarStyles];\n\n /** Built-in text overrides; unset keys fall back to registered text, then English. */\n @property({ attribute: false })\n messages: Partial<RCMenubarMessages> | undefined;\n\n private readonly _messages = new MessagesController(\n this,\n 'rc-menubar',\n DEFAULT_MENUBAR_MESSAGES,\n {\n overrides: () => this.messages,\n },\n );\n\n /** Accessible label for the `role=\"menubar\"` element. Defaults to the `label` message. */\n @property({ type: String })\n label: string | undefined;\n\n /** Orientation of the menubar, controls which arrow keys move between items. */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /** Weak reference to the currently open child `rc-menu-button`. */\n @state()\n protected _$activeMenuButton: WeakRef<RCMenuButton> | undefined;\n\n /** The last trigger element to have received focus, used for roving-tabindex bookkeeping. */\n @state()\n protected _$lastFocused: HTMLElement | undefined;\n\n /** Weak references to all slotted `rc-menu-button` children, in DOM order. */\n protected _$menuButtons: WeakRef<RCMenuButton>[] = [];\n\n /** Bound keydown handler, held for `removeEventListener` pairing. */\n protected _boundHandleKeydown = this._handleKeydown.bind(this);\n\n /** Bound click handler, held for `removeEventListener` pairing. */\n protected _boundHandleClick = this._handleClick.bind(this);\n\n /** Syncs host ARIA attributes and registers keyboard and click handlers. */\n override connectedCallback() {\n super.connectedCallback();\n\n this._syncHostAria();\n\n this.addEventListener('keydown', this._boundHandleKeydown);\n this.addEventListener('click', this._boundHandleClick);\n }\n\n /** Removes keyboard and click handlers. */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n this.removeEventListener('keydown', this._boundHandleKeydown);\n this.removeEventListener('click', this._boundHandleClick);\n }\n\n /** Keeps the exposed aria-orientation on the orientation actually rendered. */\n protected readonly _flow = new FlowController(this);\n\n /**\n * Syncs host ARIA on every update, since a writing-mode change reaches it\n * through the flow controller rather than a property, and child orientation\n * when `orientation` changes.\n */\n protected override updated(changedProperties: Map<PropertyKey, unknown>) {\n super.updated(changedProperties);\n\n this._syncHostAria();\n\n if (changedProperties.has('orientation')) {\n this._syncMenuButtonOrientation();\n }\n }\n\n /** Writes `role`, `aria-label`, and `aria-orientation` to the host element. */\n protected _syncHostAria(): void {\n this.setAttribute('role', 'menubar');\n this.setAttribute('aria-label', this.label ?? this._messages.value.label);\n this.setAttribute('aria-orientation', renderedOrientation(this.orientation, this._flow.flow));\n }\n\n /** Propagates the current `orientation` value to all slotted `rc-menu-button` children. */\n protected _syncMenuButtonOrientation(): void {\n this.$menuButtons.forEach(($menuButton) => {\n $menuButton.orientation = this.orientation;\n });\n }\n\n /** Returns the `[slot=\"trigger\"]` element inside a child `rc-menu-button`. */\n protected _$getTrigger($menuButton: RCMenuButton): HTMLElement | null {\n return $menuButton.querySelector('[slot=\"trigger\"]');\n }\n\n /** All slotted trigger elements in DOM order. */\n get $items(): HTMLElement[] {\n return this._$menuButtons\n .map((ref) => ref.deref())\n .filter(($el): $el is RCMenuButton => $el != null)\n .map(($mb) => this._$getTrigger($mb))\n .filter(($el): $el is HTMLElement => $el != null);\n }\n\n /** All slotted `rc-menu-button` children in DOM order. */\n get $menuButtons(): RCMenuButton[] {\n return this._$menuButtons\n .map((ref) => ref.deref())\n .filter(($el): $el is RCMenuButton => $el != null);\n }\n\n /** First trigger element in the menubar. */\n get $firstItem(): HTMLElement | undefined {\n return this.$items.at(0);\n }\n\n /** Last trigger element in the menubar. */\n get $lastItem(): HTMLElement | undefined {\n return this.$items.at(-1);\n }\n\n /** Trigger after `_$lastFocused`, wrapping around to the first. */\n get $nextItem(): HTMLElement | undefined {\n const index = this._$lastFocused ? this.$items.indexOf(this._$lastFocused) : 0;\n\n return this.$items.at((index + 1) % this.$items.length);\n }\n\n /** Trigger before `_$lastFocused`, wrapping around to the last. */\n get $previousItem(): HTMLElement | undefined {\n const index = this._$lastFocused ? this.$items.indexOf(this._$lastFocused) : 0;\n\n return this.$items.at((index - 1) % this.$items.length);\n }\n\n /** Returns the `rc-menu-button` whose slotted trigger matches `$trigger`. */\n protected _$getMenuButtonForTrigger($trigger: HTMLElement): RCMenuButton | undefined {\n return this.$menuButtons.find(($mb) => this._$getTrigger($mb) === $trigger);\n }\n\n /**\n * Moves focus to a trigger element.\n *\n * @param $item - trigger to focus; no-ops when `null` or `undefined`\n */\n focusItem($item?: HTMLElement | null) {\n if ($item != null) {\n $item.focus();\n }\n }\n\n /** Closes the currently open child menu without returning focus to its trigger. */\n closeActiveMenu() {\n const $activeMenuButton = this._$activeMenuButton?.deref();\n\n if ($activeMenuButton) {\n $activeMenuButton.closeMenu(false);\n\n this._$activeMenuButton = undefined;\n }\n }\n\n /** Updates roving-tabindex state when a trigger element receives focus. */\n protected _handleItemFocus(e: FocusEvent) {\n const $target = e.target as HTMLElement;\n\n if ($target.slot !== 'trigger') {\n return;\n }\n\n this._$lastFocused = $target;\n\n this.$items.forEach(($item) => $item.setAttribute('tabindex', '-1'));\n\n $target.setAttribute('tabindex', '0');\n }\n\n /** Refreshes the cached `rc-menu-button` list when slotted children change. */\n protected _handleSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $elements = $slot.assignedElements();\n\n const prevButtons = this._$menuButtons;\n\n // Cache element references synchronously. Defer all DOM mutations.\n // slotchange fires synchronously inside a framework reactive update pass\n // on second+ mount (shadow DOM already exists), so the handler must be\n // instantaneous to avoid interacting with the reactive system.\n this._$menuButtons = $elements\n .filter(($el): $el is RCMenuButton => $el.tagName === 'RC-MENU-BUTTON')\n .map(($el) => new WeakRef($el));\n\n queueMicrotask(() => {\n if (!this.isConnected) {\n return;\n }\n\n prevButtons.forEach((ref) => {\n const $menuButton = ref.deref();\n\n if (!$menuButton) {\n return;\n }\n\n $menuButton.removeAttribute('role');\n\n const $trigger = this._$getTrigger($menuButton);\n\n $trigger?.removeAttribute('tabindex');\n $trigger?.removeAttribute('role');\n });\n\n this.$menuButtons.forEach(($menuButton) => {\n $menuButton.removeAttribute('role');\n $menuButton.orientation = this.orientation;\n\n const $trigger = this._$getTrigger($menuButton);\n\n $trigger?.setAttribute('role', 'menuitem');\n });\n\n const $items = this.$items;\n\n $items.forEach(($trigger, index) => {\n $trigger.setAttribute('tabindex', index === 0 ? '0' : '-1');\n });\n\n if ($items.length > 0 && !this._$lastFocused) {\n this._$lastFocused = $items[0];\n }\n });\n }\n\n /** Tracks which child `rc-menu-button` is currently open. */\n protected _handleMenuButtonToggle(e: CustomEvent<RCMenuButtonToggleEvent>) {\n const $menuButton = e.target as RCMenuButton;\n\n if (e.detail.open) {\n this._$activeMenuButton = new WeakRef($menuButton);\n } else {\n if (this._$activeMenuButton?.deref() === $menuButton) {\n this._$activeMenuButton = undefined;\n }\n }\n }\n\n /**\n * Routes keyboard navigation actions to item focus and menu open/close changes.\n *\n * When a menu is open, moving to an adjacent item closes the current menu and\n * opens the one attached to the newly focused trigger.\n *\n * @param action - the navigation action produced by the keydown handler\n */\n protected _handleNavigate(action: KeyboardNavigationAction) {\n const $activeMenu = this._$activeMenuButton?.deref();\n const wasMenuOpen = $activeMenu?.open ?? false;\n\n switch (action) {\n case 'next':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$nextItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'prev':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$previousItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'start':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$firstItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'end':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$lastItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'escape':\n this.closeActiveMenu();\n\n break;\n }\n }\n\n /** Opens the menu attached to the last-focused trigger. */\n protected _openCurrentMenu() {\n if (this._$lastFocused) {\n const $menuButton = this._$getMenuButtonForTrigger(this._$lastFocused);\n\n if ($menuButton) {\n $menuButton.openMenu();\n }\n }\n }\n\n /** Translates keyboard events to navigation actions and activates keyboard interaction mode. */\n protected _handleKeydown(e: KeyboardEvent): void {\n const key = IE_KEY_ALIASES[e.key] ?? e.key;\n // The layout orientation turns over in vertical text, and horizontal\n // keys flip in RTL: a horizontal menubar advances with ArrowLeft there.\n const flow = resolveFlow(this);\n const { next: navNext, prev: navPrev } = arrowKeys(\n renderedOrientation(this.orientation, flow),\n flow,\n );\n\n let action: KeyboardNavigationAction | undefined;\n\n if (key === navNext) {\n action = 'next';\n } else if (key === navPrev) {\n action = 'prev';\n } else if (key === 'Home') {\n action = 'start';\n } else if (key === 'End') {\n action = 'end';\n } else if (key === 'Escape') {\n action = 'escape';\n } else if (key === 'Tab') {\n this.setAttribute('data-interaction-mode', 'keyboard');\n }\n\n if (!action) {\n return;\n }\n\n this._handleNavigate(action);\n this.setAttribute('data-interaction-mode', 'keyboard');\n\n e.stopPropagation();\n e.preventDefault();\n }\n\n /** Clears keyboard interaction mode on pointer click. */\n protected _handleClick(): void {\n this.removeAttribute('data-interaction-mode');\n }\n\n protected override render() {\n return html`\n <div id=\"root\" part=\"root\">\n <div\n id=\"slot-wrap\"\n @focusin=${this._handleItemFocus}\n @rc-menu-button-toggle=${this._handleMenuButtonToggle}\n >\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCMenubar;\n"],"names":["menubarStyles","css","IE_KEY_ALIASES","DEFAULT_MENUBAR_MESSAGES","_RCMenubar","LitElement","MessagesController","FlowController","changedProperties","renderedOrientation","$menuButton","ref","$el","$mb","index","$trigger","$item","$activeMenuButton","e","$target","$elements","prevButtons","$items","action","wasMenuOpen","key","flow","resolveFlow","navNext","navPrev","arrowKeys","html","RCMenubar","__decorateClass","property","state"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import "@rcarls/rc-menu-button/define";
|
|
2
|
-
import { R as e } from "./rc-menubar-
|
|
2
|
+
import { R as e } from "./rc-menubar-BNaVFLs3.js";
|
|
3
|
+
import { D as n } from "./rc-menubar-BNaVFLs3.js";
|
|
3
4
|
customElements.get("rc-menubar") || customElements.define("rc-menubar", e);
|
|
4
5
|
export {
|
|
6
|
+
n as DEFAULT_MENUBAR_MESSAGES,
|
|
5
7
|
e as RCMenubar
|
|
6
8
|
};
|
|
7
9
|
//# sourceMappingURL=rc-menubar-define.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rc-menubar-define.js","sources":["../src/define.ts"],"sourcesContent":["import '@rcarls/rc-menu-button/define';\nimport { RCMenubar } from './index.js';\n\ncustomElements.get('rc-menubar') || customElements.define('rc-menubar', RCMenubar);\n\nexport * from './index.js';\n"],"names":["RCMenubar"],"mappings":"
|
|
1
|
+
{"version":3,"file":"rc-menubar-define.js","sources":["../src/define.ts"],"sourcesContent":["import '@rcarls/rc-menu-button/define';\nimport { RCMenubar } from './index.js';\n\ncustomElements.get('rc-menubar') || customElements.define('rc-menubar', RCMenubar);\n\nexport * from './index.js';\n"],"names":["RCMenubar"],"mappings":";;;AAGA,eAAe,IAAI,YAAY,KAAK,eAAe,OAAO,cAAcA,CAAS;"}
|
package/dist/rc-menubar.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
-
import { KeyboardNavigationAction } from '@rcarls/rc-common';
|
|
2
|
+
import { FlowController, KeyboardNavigationAction } from '@rcarls/rc-common';
|
|
3
3
|
import { RCMenuButton, RCMenuButtonToggleEvent } from '@rcarls/rc-menu-button';
|
|
4
4
|
declare global {
|
|
5
5
|
interface HTMLElementTagNameMap {
|
|
6
6
|
'rc-menubar': RCMenubar;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
+
/** Built-in text of `rc-menubar`. */
|
|
10
|
+
export interface RCMenubarMessages {
|
|
11
|
+
/** Default accessible name of the menubar, when `label` is unset. */
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_MENUBAR_MESSAGES: Readonly<RCMenubarMessages>;
|
|
15
|
+
declare module '@rcarls/rc-common' {
|
|
16
|
+
interface RcMessageCatalog {
|
|
17
|
+
'rc-menubar': RCMenubarMessages;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
9
20
|
/**
|
|
10
21
|
* Menubar coordinator for rc-menu-button children with roving tabindex and submenu
|
|
11
22
|
* handoff, following the WAI-ARIA Menubar pattern.
|
|
@@ -14,6 +25,10 @@ declare global {
|
|
|
14
25
|
* receive real focus — required for submenu handoff and screen reader announcements.
|
|
15
26
|
*
|
|
16
27
|
*
|
|
28
|
+
* Built-in text (the default menubar name) follows the element's own `lang`, else
|
|
29
|
+
* `<html lang>`: per element through `messages`, or for every instance
|
|
30
|
+
* through `registerMessages()` from `@rcarls/rc-common` under `rc-menubar`.
|
|
31
|
+
*
|
|
17
32
|
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-menubar rc-menubar docs}
|
|
18
33
|
* @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menubar/ WAI-ARIA Menubar pattern}
|
|
19
34
|
*
|
|
@@ -21,9 +36,10 @@ declare global {
|
|
|
21
36
|
*
|
|
22
37
|
* @csspart root - The root container element
|
|
23
38
|
*
|
|
24
|
-
* @attr label - Accessible label for the `role="menubar"` element.
|
|
25
|
-
* @attr orientation - Layout
|
|
26
|
-
* child `rc-menu-button` elements.
|
|
39
|
+
* @attr label - Accessible label for the `role="menubar"` element. Defaults to the `label` message.
|
|
40
|
+
* @attr orientation - Layout along the inline (`horizontal`) or block (`vertical`) axis,
|
|
41
|
+
* propagated to child `rc-menu-button` elements. Both turn over in vertical writing
|
|
42
|
+
* modes; `aria-orientation` and the arrow keys follow the orientation actually rendered.
|
|
27
43
|
*
|
|
28
44
|
* @cssprop [--rc-menubar-gap=var(--rc-control-gap)] - Gap between menu buttons
|
|
29
45
|
* @cssprop [--rc-menubar-padding-inline=var(--rc-control-padding-inline)] - Inline-axis padding
|
|
@@ -50,8 +66,11 @@ declare global {
|
|
|
50
66
|
*/
|
|
51
67
|
export declare class RCMenubar extends LitElement {
|
|
52
68
|
static styles: import('lit').CSSResult[];
|
|
53
|
-
/**
|
|
54
|
-
|
|
69
|
+
/** Built-in text overrides; unset keys fall back to registered text, then English. */
|
|
70
|
+
messages: Partial<RCMenubarMessages> | undefined;
|
|
71
|
+
private readonly _messages;
|
|
72
|
+
/** Accessible label for the `role="menubar"` element. Defaults to the `label` message. */
|
|
73
|
+
label: string | undefined;
|
|
55
74
|
/** Orientation of the menubar, controls which arrow keys move between items. */
|
|
56
75
|
orientation: 'horizontal' | 'vertical';
|
|
57
76
|
/** Weak reference to the currently open child `rc-menu-button`. */
|
|
@@ -68,7 +87,13 @@ export declare class RCMenubar extends LitElement {
|
|
|
68
87
|
connectedCallback(): void;
|
|
69
88
|
/** Removes keyboard and click handlers. */
|
|
70
89
|
disconnectedCallback(): void;
|
|
71
|
-
/**
|
|
90
|
+
/** Keeps the exposed aria-orientation on the orientation actually rendered. */
|
|
91
|
+
protected readonly _flow: FlowController;
|
|
92
|
+
/**
|
|
93
|
+
* Syncs host ARIA on every update, since a writing-mode change reaches it
|
|
94
|
+
* through the flow controller rather than a property, and child orientation
|
|
95
|
+
* when `orientation` changes.
|
|
96
|
+
*/
|
|
72
97
|
protected updated(changedProperties: Map<PropertyKey, unknown>): void;
|
|
73
98
|
/** Writes `role`, `aria-label`, and `aria-orientation` to the host element. */
|
|
74
99
|
protected _syncHostAria(): void;
|
|
@@ -119,6 +144,6 @@ export declare class RCMenubar extends LitElement {
|
|
|
119
144
|
protected _handleKeydown(e: KeyboardEvent): void;
|
|
120
145
|
/** Clears keyboard interaction mode on pointer click. */
|
|
121
146
|
protected _handleClick(): void;
|
|
122
|
-
protected render(): import('lit').TemplateResult<1>;
|
|
147
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
123
148
|
}
|
|
124
149
|
export default RCMenubar;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.7.0",
|
|
7
7
|
"description": "Menubar coordinator for rc-menu-button children with roving tabindex and submenu handoff.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -45,9 +45,8 @@
|
|
|
45
45
|
"test:browser:firefox": "vitest --run --project=firefox"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@rcarls/rc-common": "0.
|
|
49
|
-
"@rcarls/rc-menu": "0.
|
|
50
|
-
"@rcarls/rc-menu-button": "0.6.0"
|
|
48
|
+
"@rcarls/rc-common": "0.7.0",
|
|
49
|
+
"@rcarls/rc-menu-button": "0.7.0"
|
|
51
50
|
},
|
|
52
51
|
"devDependencies": {
|
|
53
52
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rc-menubar-DCZFgZvn.js","sources":["../src/rc-menubar.styles.ts","../src/rc-menubar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menubarStyles = css`\n :host {\n display: inline-block;\n }\n\n #root {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n gap: var(--rc-menubar-gap, var(--rc-control-gap, 0.25em));\n padding-inline: var(--rc-menubar-padding-inline, var(--rc-control-padding-inline, 0.25em));\n padding-block: var(--rc-menubar-padding-block, var(--rc-control-padding-block, 0.25em));\n border: var(--rc-menubar-border, var(--rc-border, 1px solid ButtonBorder));\n border-radius: var(--rc-menubar-radius, var(--rc-control-radius, 0));\n background: var(--rc-menubar-background, var(--rc-surface, Canvas));\n color: var(--rc-menubar-color, var(--rc-field-text, CanvasText));\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n }\n\n :host([orientation='vertical']) #root {\n flex-direction: column;\n align-items: stretch;\n }\n\n #slot-wrap {\n display: flex;\n flex-direction: inherit;\n align-items: stretch;\n gap: inherit;\n min-inline-size: 0;\n }\n\n ::slotted(rc-menu-button) {\n flex: 0 0 auto;\n --rc-menu-button-trigger-block-size: var(--rc-menubar-item-block-size, 2.25em);\n --rc-menu-button-trigger-padding-block: var(--rc-menubar-item-padding-block, 0.25em);\n --rc-menu-button-trigger-padding-inline: var(--rc-menubar-item-padding-inline, 0.75em);\n --rc-menu-button-trigger-gap: var(--rc-menubar-item-gap, var(--rc-item-gap, 0.5em));\n --rc-menu-button-trigger-border: var(--rc-menubar-item-border, 1px solid transparent);\n --rc-menu-button-trigger-radius: var(\n --rc-menubar-item-radius,\n var(--rc-control-radius, 0.125em)\n );\n --rc-menu-button-trigger-background: var(--rc-menubar-item-background, transparent);\n --rc-menu-button-trigger-color: var(--rc-menubar-item-color, inherit);\n --rc-menu-button-trigger-transition: var(--rc-menubar-item-transition);\n --rc-menu-button-trigger-hover-border-color: var(\n --rc-menubar-item-hover-border-color,\n transparent\n );\n --rc-menu-button-trigger-hover-background: var(\n --rc-menubar-item-hover-background,\n color-mix(in srgb, Highlight 8%, transparent)\n );\n --rc-menu-button-trigger-hover-color: var(--rc-menubar-item-hover-color, inherit);\n --rc-menu-button-trigger-open-border-color: var(\n --rc-menubar-item-open-border-color,\n transparent\n );\n --rc-menu-button-trigger-open-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-open-color: var(--rc-menubar-item-open-color, inherit);\n }\n\n ::slotted(rc-menu-button[open]) {\n --rc-menu-button-trigger-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-color: var(--rc-menubar-item-open-color, inherit);\n --rc-menu-button-trigger-hover-background: var(\n --rc-menubar-item-open-background,\n color-mix(in srgb, Highlight 12%, transparent)\n );\n --rc-menu-button-trigger-hover-color: var(--rc-menubar-item-open-color, inherit);\n --rc-menu-button-trigger-hover-border-color: var(\n --rc-menubar-item-open-border-color,\n transparent\n );\n }\n\n :host([orientation='vertical']) ::slotted(rc-menu-button) {\n inline-size: 100%;\n }\n`;\n\nexport default menubarStyles;\n","import { LitElement, html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { type KeyboardNavigationAction } from '@rcarls/rc-common';\nimport type { RCMenuButton, RCMenuButtonToggleEvent } from '@rcarls/rc-menu-button';\n\nimport menubarStyles from './rc-menubar.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-menubar': RCMenubar;\n }\n}\n\nconst IE_KEY_ALIASES: Record<string, string> = {\n Up: 'ArrowUp',\n Down: 'ArrowDown',\n Left: 'ArrowLeft',\n Right: 'ArrowRight',\n};\n\n/**\n * Menubar coordinator for rc-menu-button children with roving tabindex and submenu\n * handoff, following the WAI-ARIA Menubar pattern.\n *\n * Uses roving tabindex rather than aria-activedescendant so trigger buttons\n * receive real focus — required for submenu handoff and screen reader announcements.\n *\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-menubar rc-menubar docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menubar/ WAI-ARIA Menubar pattern}\n *\n * @slot default - Takes rc-menu-button elements to display in the menubar\n *\n * @csspart root - The root container element\n *\n * @attr label - Accessible label for the `role=\"menubar\"` element.\n * @attr orientation - Layout direction and keyboard navigation axis, propagated to\n * child `rc-menu-button` elements.\n *\n * @cssprop [--rc-menubar-gap=var(--rc-control-gap)] - Gap between menu buttons\n * @cssprop [--rc-menubar-padding-inline=var(--rc-control-padding-inline)] - Inline-axis padding\n * @cssprop [--rc-menubar-padding-block=var(--rc-control-padding-block)] - Block-axis padding\n * @cssprop [--rc-menubar-border=var(--rc-border)] - Root container border\n * @cssprop [--rc-menubar-radius=var(--rc-control-radius)] - Root container border radius\n * @cssprop [--rc-menubar-background=Canvas] - Root container background\n * @cssprop [--rc-menubar-color=CanvasText] - Root container text color\n * @cssprop [--rc-menubar-item-block-size=2.25em] - Minimum block size for child menu-button triggers\n * @cssprop [--rc-menubar-item-padding-block=0.25em] - Child trigger block-axis padding\n * @cssprop [--rc-menubar-item-padding-inline=0.75em] - Child trigger inline-axis padding\n * @cssprop [--rc-menubar-item-gap=var(--rc-item-gap)] - Gap between flex children inside child triggers\n * @cssprop [--rc-menubar-item-border=1px solid transparent] - Child trigger border\n * @cssprop [--rc-menubar-item-radius=var(--rc-control-radius)] - Child trigger border radius\n * @cssprop [--rc-menubar-item-background=transparent] - Child trigger background\n * @cssprop [--rc-menubar-item-color=inherit] - Child trigger text color\n * @cssprop [--rc-menubar-item-transition] - CSS transition applied to child triggers\n * @cssprop [--rc-menubar-item-hover-background=color-mix(in srgb, Highlight 8%, transparent)] - Child trigger hover background\n * @cssprop [--rc-menubar-item-hover-color=inherit] - Child trigger hover text color\n * @cssprop [--rc-menubar-item-hover-border-color=transparent] - Child trigger hover border color\n * @cssprop [--rc-menubar-item-open-background=color-mix(in srgb, Highlight 12%, transparent)] - Child trigger background when its menu is open\n * @cssprop [--rc-menubar-item-open-color=inherit] - Child trigger text color when its menu is open\n * @cssprop [--rc-menubar-item-open-border-color=transparent] - Child trigger border color when its menu is open\n */\nexport class RCMenubar extends LitElement {\n static styles = [menubarStyles];\n\n /** Accessible label for the `role=\"menubar\"` element. */\n @property({ type: String })\n label = 'Menu';\n\n /** Orientation of the menubar, controls which arrow keys move between items. */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /** Weak reference to the currently open child `rc-menu-button`. */\n @state()\n protected _$activeMenuButton: WeakRef<RCMenuButton> | undefined;\n\n /** The last trigger element to have received focus, used for roving-tabindex bookkeeping. */\n @state()\n protected _$lastFocused: HTMLElement | undefined;\n\n /** Weak references to all slotted `rc-menu-button` children, in DOM order. */\n protected _$menuButtons: WeakRef<RCMenuButton>[] = [];\n\n /** Bound keydown handler, held for `removeEventListener` pairing. */\n protected _boundHandleKeydown = this._handleKeydown.bind(this);\n\n /** Bound click handler, held for `removeEventListener` pairing. */\n protected _boundHandleClick = this._handleClick.bind(this);\n\n /** Syncs host ARIA attributes and registers keyboard and click handlers. */\n override connectedCallback() {\n super.connectedCallback();\n\n this._syncHostAria();\n\n this.addEventListener('keydown', this._boundHandleKeydown);\n this.addEventListener('click', this._boundHandleClick);\n }\n\n /** Removes keyboard and click handlers. */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n this.removeEventListener('keydown', this._boundHandleKeydown);\n this.removeEventListener('click', this._boundHandleClick);\n }\n\n /** Syncs host ARIA and child orientation when `label` or `orientation` change. */\n protected override updated(changedProperties: Map<PropertyKey, unknown>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('label') || changedProperties.has('orientation')) {\n this._syncHostAria();\n this._syncMenuButtonOrientation();\n }\n }\n\n /** Writes `role`, `aria-label`, and `aria-orientation` to the host element. */\n protected _syncHostAria(): void {\n this.setAttribute('role', 'menubar');\n this.setAttribute('aria-label', this.label);\n this.setAttribute('aria-orientation', this.orientation);\n }\n\n /** Propagates the current `orientation` value to all slotted `rc-menu-button` children. */\n protected _syncMenuButtonOrientation(): void {\n this.$menuButtons.forEach(($menuButton) => {\n $menuButton.orientation = this.orientation;\n });\n }\n\n /** Returns the `[slot=\"trigger\"]` element inside a child `rc-menu-button`. */\n protected _$getTrigger($menuButton: RCMenuButton): HTMLElement | null {\n return $menuButton.querySelector('[slot=\"trigger\"]');\n }\n\n /** All slotted trigger elements in DOM order. */\n get $items(): HTMLElement[] {\n return this._$menuButtons\n .map((ref) => ref.deref())\n .filter(($el): $el is RCMenuButton => $el != null)\n .map(($mb) => this._$getTrigger($mb))\n .filter(($el): $el is HTMLElement => $el != null);\n }\n\n /** All slotted `rc-menu-button` children in DOM order. */\n get $menuButtons(): RCMenuButton[] {\n return this._$menuButtons\n .map((ref) => ref.deref())\n .filter(($el): $el is RCMenuButton => $el != null);\n }\n\n /** First trigger element in the menubar. */\n get $firstItem(): HTMLElement | undefined {\n return this.$items.at(0);\n }\n\n /** Last trigger element in the menubar. */\n get $lastItem(): HTMLElement | undefined {\n return this.$items.at(-1);\n }\n\n /** Trigger after `_$lastFocused`, wrapping around to the first. */\n get $nextItem(): HTMLElement | undefined {\n const index = this._$lastFocused ? this.$items.indexOf(this._$lastFocused) : 0;\n\n return this.$items.at((index + 1) % this.$items.length);\n }\n\n /** Trigger before `_$lastFocused`, wrapping around to the last. */\n get $previousItem(): HTMLElement | undefined {\n const index = this._$lastFocused ? this.$items.indexOf(this._$lastFocused) : 0;\n\n return this.$items.at((index - 1) % this.$items.length);\n }\n\n /** Returns the `rc-menu-button` whose slotted trigger matches `$trigger`. */\n protected _$getMenuButtonForTrigger($trigger: HTMLElement): RCMenuButton | undefined {\n return this.$menuButtons.find(($mb) => this._$getTrigger($mb) === $trigger);\n }\n\n /**\n * Moves focus to a trigger element.\n *\n * @param $item - trigger to focus; no-ops when `null` or `undefined`\n */\n focusItem($item?: HTMLElement | null) {\n if ($item != null) {\n $item.focus();\n }\n }\n\n /** Closes the currently open child menu without returning focus to its trigger. */\n closeActiveMenu() {\n const $activeMenuButton = this._$activeMenuButton?.deref();\n\n if ($activeMenuButton) {\n $activeMenuButton.closeMenu(false);\n\n this._$activeMenuButton = undefined;\n }\n }\n\n /** Updates roving-tabindex state when a trigger element receives focus. */\n protected _handleItemFocus(e: FocusEvent) {\n const $target = e.target as HTMLElement;\n\n if ($target.slot !== 'trigger') {\n return;\n }\n\n this._$lastFocused = $target;\n\n this.$items.forEach(($item) => $item.setAttribute('tabindex', '-1'));\n\n $target.setAttribute('tabindex', '0');\n }\n\n /** Refreshes the cached `rc-menu-button` list when slotted children change. */\n protected _handleSlotChange(e: Event) {\n const $slot = e.currentTarget as HTMLSlotElement;\n const $elements = $slot.assignedElements();\n\n const prevButtons = this._$menuButtons;\n\n // Cache element references synchronously. Defer all DOM mutations.\n // slotchange fires synchronously inside a framework reactive update pass\n // on second+ mount (shadow DOM already exists), so the handler must be\n // instantaneous to avoid interacting with the reactive system.\n this._$menuButtons = $elements\n .filter(($el): $el is RCMenuButton => $el.tagName === 'RC-MENU-BUTTON')\n .map(($el) => new WeakRef($el));\n\n queueMicrotask(() => {\n if (!this.isConnected) {\n return;\n }\n\n prevButtons.forEach((ref) => {\n const $menuButton = ref.deref();\n\n if (!$menuButton) {\n return;\n }\n\n $menuButton.removeAttribute('role');\n\n const $trigger = this._$getTrigger($menuButton);\n\n $trigger?.removeAttribute('tabindex');\n $trigger?.removeAttribute('role');\n });\n\n this.$menuButtons.forEach(($menuButton) => {\n $menuButton.removeAttribute('role');\n $menuButton.orientation = this.orientation;\n\n const $trigger = this._$getTrigger($menuButton);\n\n $trigger?.setAttribute('role', 'menuitem');\n });\n\n const $items = this.$items;\n\n $items.forEach(($trigger, index) => {\n $trigger.setAttribute('tabindex', index === 0 ? '0' : '-1');\n });\n\n if ($items.length > 0 && !this._$lastFocused) {\n this._$lastFocused = $items[0];\n }\n });\n }\n\n /** Tracks which child `rc-menu-button` is currently open. */\n protected _handleMenuButtonToggle(e: CustomEvent<RCMenuButtonToggleEvent>) {\n const $menuButton = e.target as RCMenuButton;\n\n if (e.detail.open) {\n this._$activeMenuButton = new WeakRef($menuButton);\n } else {\n if (this._$activeMenuButton?.deref() === $menuButton) {\n this._$activeMenuButton = undefined;\n }\n }\n }\n\n /**\n * Routes keyboard navigation actions to item focus and menu open/close changes.\n *\n * When a menu is open, moving to an adjacent item closes the current menu and\n * opens the one attached to the newly focused trigger.\n *\n * @param action - the navigation action produced by the keydown handler\n */\n protected _handleNavigate(action: KeyboardNavigationAction) {\n const $activeMenu = this._$activeMenuButton?.deref();\n const wasMenuOpen = $activeMenu?.open ?? false;\n\n switch (action) {\n case 'next':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$nextItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'prev':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$previousItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'start':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$firstItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'end':\n if (wasMenuOpen) {\n this.closeActiveMenu();\n }\n\n this.focusItem(this.$lastItem);\n\n if (wasMenuOpen) {\n this._openCurrentMenu();\n }\n\n break;\n\n case 'escape':\n this.closeActiveMenu();\n\n break;\n }\n }\n\n /** Opens the menu attached to the last-focused trigger. */\n protected _openCurrentMenu() {\n if (this._$lastFocused) {\n const $menuButton = this._$getMenuButtonForTrigger(this._$lastFocused);\n\n if ($menuButton) {\n $menuButton.openMenu();\n }\n }\n }\n\n /** Translates keyboard events to navigation actions and activates keyboard interaction mode. */\n protected _handleKeydown(e: KeyboardEvent): void {\n const key = IE_KEY_ALIASES[e.key] ?? e.key;\n const navNext = this.orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown';\n const navPrev = this.orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp';\n\n let action: KeyboardNavigationAction | undefined;\n\n if (key === navNext) {\n action = 'next';\n } else if (key === navPrev) {\n action = 'prev';\n } else if (key === 'Home') {\n action = 'start';\n } else if (key === 'End') {\n action = 'end';\n } else if (key === 'Escape') {\n action = 'escape';\n } else if (key === 'Tab') {\n this.setAttribute('data-interaction-mode', 'keyboard');\n }\n\n if (!action) {\n return;\n }\n\n this._handleNavigate(action);\n this.setAttribute('data-interaction-mode', 'keyboard');\n\n e.stopPropagation();\n e.preventDefault();\n }\n\n /** Clears keyboard interaction mode on pointer click. */\n protected _handleClick(): void {\n this.removeAttribute('data-interaction-mode');\n }\n\n protected override render() {\n return html`\n <div id=\"root\" part=\"root\">\n <div\n id=\"slot-wrap\"\n @focusin=${this._handleItemFocus}\n @rc-menu-button-toggle=${this._handleMenuButtonToggle}\n >\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCMenubar;\n"],"names":["menubarStyles","css","IE_KEY_ALIASES","_RCMenubar","LitElement","changedProperties","$menuButton","ref","$el","$mb","index","$trigger","$item","$activeMenuButton","e","$target","$elements","prevButtons","$items","action","wasMenuOpen","key","navNext","navPrev","html","RCMenubar","__decorateClass","property","state"],"mappings":";;;AAEO,MAAMA,IAAgBC;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;;;;;;ACY7B,MAAMC,IAAyC;AAAA,EAC7C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT,GA4CaC,IAAN,MAAMA,UAAkBC,EAAW;AAAA,EAAnC,cAAA;AAAA,UAAA,GAAA,SAAA,GAKL,KAAA,QAAQ,QAIR,KAAA,cAAyC,cAWzC,KAAU,gBAAyC,CAAA,GAGnD,KAAU,sBAAsB,KAAK,eAAe,KAAK,IAAI,GAG7D,KAAU,oBAAoB,KAAK,aAAa,KAAK,IAAI;AAAA,EAAA;AAAA;AAAA,EAGhD,oBAAoB;AAC3B,UAAM,kBAAA,GAEN,KAAK,cAAA,GAEL,KAAK,iBAAiB,WAAW,KAAK,mBAAmB,GACzD,KAAK,iBAAiB,SAAS,KAAK,iBAAiB;AAAA,EACvD;AAAA;AAAA,EAGS,uBAAuB;AAC9B,UAAM,qBAAA,GAEN,KAAK,oBAAoB,WAAW,KAAK,mBAAmB,GAC5D,KAAK,oBAAoB,SAAS,KAAK,iBAAiB;AAAA,EAC1D;AAAA;AAAA,EAGmB,QAAQC,GAA8C;AACvE,UAAM,QAAQA,CAAiB,IAE3BA,EAAkB,IAAI,OAAO,KAAKA,EAAkB,IAAI,aAAa,OACvE,KAAK,cAAA,GACL,KAAK,2BAAA;AAAA,EAET;AAAA;AAAA,EAGU,gBAAsB;AAC9B,SAAK,aAAa,QAAQ,SAAS,GACnC,KAAK,aAAa,cAAc,KAAK,KAAK,GAC1C,KAAK,aAAa,oBAAoB,KAAK,WAAW;AAAA,EACxD;AAAA;AAAA,EAGU,6BAAmC;AAC3C,SAAK,aAAa,QAAQ,CAACC,MAAgB;AACzC,MAAAA,EAAY,cAAc,KAAK;AAAA,IACjC,CAAC;AAAA,EACH;AAAA;AAAA,EAGU,aAAaA,GAA+C;AACpE,WAAOA,EAAY,cAAc,kBAAkB;AAAA,EACrD;AAAA;AAAA,EAGA,IAAI,SAAwB;AAC1B,WAAO,KAAK,cACT,IAAI,CAACC,MAAQA,EAAI,OAAO,EACxB,OAAO,CAACC,MAA6BA,KAAO,IAAI,EAChD,IAAI,CAACC,MAAQ,KAAK,aAAaA,CAAG,CAAC,EACnC,OAAO,CAACD,MAA4BA,KAAO,IAAI;AAAA,EACpD;AAAA;AAAA,EAGA,IAAI,eAA+B;AACjC,WAAO,KAAK,cACT,IAAI,CAACD,MAAQA,EAAI,MAAA,CAAO,EACxB,OAAO,CAACC,MAA6BA,KAAO,IAAI;AAAA,EACrD;AAAA;AAAA,EAGA,IAAI,aAAsC;AACxC,WAAO,KAAK,OAAO,GAAG,CAAC;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,YAAqC;AACvC,WAAO,KAAK,OAAO,GAAG,EAAE;AAAA,EAC1B;AAAA;AAAA,EAGA,IAAI,YAAqC;AACvC,UAAME,IAAQ,KAAK,gBAAgB,KAAK,OAAO,QAAQ,KAAK,aAAa,IAAI;AAE7E,WAAO,KAAK,OAAO,IAAIA,IAAQ,KAAK,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA;AAAA,EAGA,IAAI,gBAAyC;AAC3C,UAAMA,IAAQ,KAAK,gBAAgB,KAAK,OAAO,QAAQ,KAAK,aAAa,IAAI;AAE7E,WAAO,KAAK,OAAO,IAAIA,IAAQ,KAAK,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA;AAAA,EAGU,0BAA0BC,GAAiD;AACnF,WAAO,KAAK,aAAa,KAAK,CAACF,MAAQ,KAAK,aAAaA,CAAG,MAAME,CAAQ;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUC,GAA4B;AACpC,IACEA,GAAM,MAAA;AAAA,EAEV;AAAA;AAAA,EAGA,kBAAkB;AAChB,UAAMC,IAAoB,KAAK,oBAAoB,MAAA;AAEnD,IAAIA,MACFA,EAAkB,UAAU,EAAK,GAEjC,KAAK,qBAAqB;AAAA,EAE9B;AAAA;AAAA,EAGU,iBAAiBC,GAAe;AACxC,UAAMC,IAAUD,EAAE;AAElB,IAAIC,EAAQ,SAAS,cAIrB,KAAK,gBAAgBA,GAErB,KAAK,OAAO,QAAQ,CAACH,MAAUA,EAAM,aAAa,YAAY,IAAI,CAAC,GAEnEG,EAAQ,aAAa,YAAY,GAAG;AAAA,EACtC;AAAA;AAAA,EAGU,kBAAkBD,GAAU;AAEpC,UAAME,IADQF,EAAE,cACQ,iBAAA,GAElBG,IAAc,KAAK;AAMzB,SAAK,gBAAgBD,EAClB,OAAO,CAACR,MAA6BA,EAAI,YAAY,gBAAgB,EACrE,IAAI,CAACA,MAAQ,IAAI,QAAQA,CAAG,CAAC,GAEhC,eAAe,MAAM;AACnB,UAAI,CAAC,KAAK;AACR;AAGF,MAAAS,EAAY,QAAQ,CAACV,MAAQ;AAC3B,cAAMD,IAAcC,EAAI,MAAA;AAExB,YAAI,CAACD;AACH;AAGF,QAAAA,EAAY,gBAAgB,MAAM;AAElC,cAAMK,IAAW,KAAK,aAAaL,CAAW;AAE9C,QAAAK,GAAU,gBAAgB,UAAU,GACpCA,GAAU,gBAAgB,MAAM;AAAA,MAClC,CAAC,GAED,KAAK,aAAa,QAAQ,CAACL,MAAgB;AACzC,QAAAA,EAAY,gBAAgB,MAAM,GAClCA,EAAY,cAAc,KAAK,aAEd,KAAK,aAAaA,CAAW,GAEpC,aAAa,QAAQ,UAAU;AAAA,MAC3C,CAAC;AAED,YAAMY,IAAS,KAAK;AAEpB,MAAAA,EAAO,QAAQ,CAACP,GAAUD,MAAU;AAClC,QAAAC,EAAS,aAAa,YAAYD,MAAU,IAAI,MAAM,IAAI;AAAA,MAC5D,CAAC,GAEGQ,EAAO,SAAS,KAAK,CAAC,KAAK,kBAC7B,KAAK,gBAAgBA,EAAO,CAAC;AAAA,IAEjC,CAAC;AAAA,EACH;AAAA;AAAA,EAGU,wBAAwBJ,GAAyC;AACzE,UAAMR,IAAcQ,EAAE;AAEtB,IAAIA,EAAE,OAAO,OACX,KAAK,qBAAqB,IAAI,QAAQR,CAAW,IAE7C,KAAK,oBAAoB,MAAA,MAAYA,MACvC,KAAK,qBAAqB;AAAA,EAGhC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUU,gBAAgBa,GAAkC;AAE1D,UAAMC,IADc,KAAK,oBAAoB,MAAA,GACZ,QAAQ;AAEzC,YAAQD,GAAA;AAAA,MACN,KAAK;AACH,QAAIC,KACF,KAAK,gBAAA,GAGP,KAAK,UAAU,KAAK,SAAS,GAEzBA,KACF,KAAK,iBAAA;AAGP;AAAA,MAEF,KAAK;AACH,QAAIA,KACF,KAAK,gBAAA,GAGP,KAAK,UAAU,KAAK,aAAa,GAE7BA,KACF,KAAK,iBAAA;AAGP;AAAA,MAEF,KAAK;AACH,QAAIA,KACF,KAAK,gBAAA,GAGP,KAAK,UAAU,KAAK,UAAU,GAE1BA,KACF,KAAK,iBAAA;AAGP;AAAA,MAEF,KAAK;AACH,QAAIA,KACF,KAAK,gBAAA,GAGP,KAAK,UAAU,KAAK,SAAS,GAEzBA,KACF,KAAK,iBAAA;AAGP;AAAA,MAEF,KAAK;AACH,aAAK,gBAAA;AAEL;AAAA,IAAA;AAAA,EAEN;AAAA;AAAA,EAGU,mBAAmB;AAC3B,QAAI,KAAK,eAAe;AACtB,YAAMd,IAAc,KAAK,0BAA0B,KAAK,aAAa;AAErE,MAAIA,KACFA,EAAY,SAAA;AAAA,IAEhB;AAAA,EACF;AAAA;AAAA,EAGU,eAAeQ,GAAwB;AAC/C,UAAMO,IAAMnB,EAAeY,EAAE,GAAG,KAAKA,EAAE,KACjCQ,IAAU,KAAK,gBAAgB,eAAe,eAAe,aAC7DC,IAAU,KAAK,gBAAgB,eAAe,cAAc;AAElE,QAAIJ;AAgBJ,IAdIE,MAAQC,IACVH,IAAS,SACAE,MAAQE,IACjBJ,IAAS,SACAE,MAAQ,SACjBF,IAAS,UACAE,MAAQ,QACjBF,IAAS,QACAE,MAAQ,WACjBF,IAAS,WACAE,MAAQ,SACjB,KAAK,aAAa,yBAAyB,UAAU,GAGlDF,MAIL,KAAK,gBAAgBA,CAAM,GAC3B,KAAK,aAAa,yBAAyB,UAAU,GAErDL,EAAE,gBAAA,GACFA,EAAE,eAAA;AAAA,EACJ;AAAA;AAAA,EAGU,eAAqB;AAC7B,SAAK,gBAAgB,uBAAuB;AAAA,EAC9C;AAAA,EAEmB,SAAS;AAC1B,WAAOU;AAAA;AAAA;AAAA;AAAA,qBAIU,KAAK,gBAAgB;AAAA,mCACP,KAAK,uBAAuB;AAAA;AAAA,8BAEjC,KAAK,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAIlD;AACF;AAvWErB,EAAO,SAAS,CAACH,CAAa;AADzB,IAAMyB,IAANtB;AAKLuB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAJfF,EAKX,WAAA,OAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAR9BF,EASX,WAAA,aAAA;AAIUC,EAAA;AAAA,EADTE,EAAA;AAAM,GAZIH,EAaD,WAAA,oBAAA;AAIAC,EAAA;AAAA,EADTE,EAAA;AAAM,GAhBIH,EAiBD,WAAA,eAAA;"}
|