@rcarls/rc-menubar 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # `@rcarls/rc-menubar`
2
2
 
3
- A WAI-ARIA compliant menubar component implementing the [Menubar pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/). Manages roving tabindex across `rc-menu-button` triggers and cascades menu open/close as the user navigates. Built with [Lit 3](https://lit.dev).
3
+ Menubar coordinator for `rc-menu-button` children with roving tabindex and submenu handoff, following the [WAI-ARIA Menubar pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/).
4
+
5
+ Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-menubar](https://richardcarls.github.io/rc-webcomponents/components/rc-menubar).
6
+
7
+ Manages roving tabindex across `rc-menu-button` triggers and cascades menu open/close as the user navigates. Built with [Lit 3](https://lit.dev).
4
8
 
5
9
  ---
6
10
 
@@ -13,7 +17,7 @@ npm install @rcarls/rc-menubar
13
17
  ## Import
14
18
 
15
19
  ```js
16
- import '@rcarls/rc-menubar'; // side-effect: registers <rc-menubar>
20
+ import '@rcarls/rc-menubar/define'; // side-effect: registers <rc-menubar>
17
21
  import { RCMenubar } from '@rcarls/rc-menubar'; // named class export
18
22
  ```
19
23
 
@@ -72,15 +76,34 @@ Place `rc-menu-button` elements as direct children. The menubar manages focus an
72
76
 
73
77
  | Property | Default | Description |
74
78
  |---|---|---|
75
- | `--rc-menubar-gap` | `0` | Gap between menu buttons |
76
- | `--rc-menubar-padding-inline` | `0` | Horizontal padding on the menubar container |
77
- | `--rc-menubar-padding-block` | `0` | Vertical padding on the menubar container |
79
+ | `--rc-menubar-gap` | `var(--rc-control-gap)` | Gap between menu buttons |
80
+ | `--rc-menubar-padding-inline` | `var(--rc-control-padding-inline)` | Inline padding on the menubar container |
81
+ | `--rc-menubar-padding-block` | `var(--rc-control-padding-block)` | Block padding on the menubar container |
82
+ | `--rc-menubar-border` | `var(--rc-border)` | Menubar container border |
83
+ | `--rc-menubar-radius` | `var(--rc-control-radius)` | Menubar container border radius |
84
+ | `--rc-menubar-background` | `Canvas` | Menubar container background |
85
+ | `--rc-menubar-color` | `CanvasText` | Menubar container text color |
86
+ | `--rc-menubar-item-block-size` | `2.25em` | Minimum block size for child menu-button triggers |
87
+ | `--rc-menubar-item-padding-block` | `0.25em` | Child trigger block-axis padding |
88
+ | `--rc-menubar-item-padding-inline` | `0.75em` | Child trigger inline-axis padding |
89
+ | `--rc-menubar-item-gap` | `var(--rc-item-gap)` | Gap between flex children inside child triggers |
90
+ | `--rc-menubar-item-border` | `1px solid transparent` | Child trigger border |
91
+ | `--rc-menubar-item-radius` | `var(--rc-control-radius)` | Child trigger border radius |
92
+ | `--rc-menubar-item-background` | `transparent` | Child trigger background |
93
+ | `--rc-menubar-item-color` | `inherit` | Child trigger text color |
94
+ | `--rc-menubar-item-transition` | — | Child trigger state transition |
95
+ | `--rc-menubar-item-hover-background` | `color-mix(in srgb, Highlight 8%, transparent)` | Child trigger hover background |
96
+ | `--rc-menubar-item-hover-color` | `inherit` | Child trigger hover text color |
97
+ | `--rc-menubar-item-hover-border-color` | `transparent` | Child trigger hover border color |
98
+ | `--rc-menubar-item-open-background` | `color-mix(in srgb, Highlight 12%, transparent)` | Child trigger background while its menu is open |
99
+ | `--rc-menubar-item-open-color` | `inherit` | Child trigger text color while its menu is open |
100
+ | `--rc-menubar-item-open-border-color` | `transparent` | Child trigger border color while its menu is open |
78
101
 
79
102
  ### CSS parts
80
103
 
81
104
  | Part | Element | Description |
82
105
  |---|---|---|
83
- | `root` | `div[role="menubar"]` | The inner menubar container |
106
+ | `root` | Inner `div` | The visual menubar container |
84
107
 
85
108
  ### Slots
86
109
 
@@ -136,9 +159,9 @@ For vertical orientation, `ArrowDown`/`ArrowUp` replace `ArrowRight`/`ArrowLeft`
136
159
 
137
160
  | Attribute | Where | Value |
138
161
  |---|---|---|
139
- | `role="menubar"` | Root `div` | — |
140
- | `aria-orientation` | Root `div` | `"horizontal"` or `"vertical"` |
141
- | `aria-label` | Root `div` | Value of `label` property |
162
+ | `role="menubar"` | Host element | — |
163
+ | `aria-orientation` | Host element | `"horizontal"` or `"vertical"` |
164
+ | `aria-label` | Host element | Value of `label` property |
142
165
  | `tabindex="0"` | Active trigger | One trigger tabbable at a time (roving tabindex) |
143
166
  | `tabindex="-1"` | All other triggers | Removed from tab order |
144
167
 
@@ -46,7 +46,7 @@
46
46
  "declarations": [
47
47
  {
48
48
  "kind": "class",
49
- "description": "A menubar component containing menu buttons, as defined in WAI-ARIA",
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.",
50
50
  "name": "RCMenubar",
51
51
  "cssProperties": [
52
52
  {
@@ -83,6 +83,80 @@
83
83
  "description": "Root container text color",
84
84
  "name": "--rc-menubar-color",
85
85
  "default": "CanvasText"
86
+ },
87
+ {
88
+ "description": "Minimum block size for child menu-button triggers",
89
+ "name": "--rc-menubar-item-block-size",
90
+ "default": "2.25em"
91
+ },
92
+ {
93
+ "description": "Child trigger block-axis padding",
94
+ "name": "--rc-menubar-item-padding-block",
95
+ "default": "0.25em"
96
+ },
97
+ {
98
+ "description": "Child trigger inline-axis padding",
99
+ "name": "--rc-menubar-item-padding-inline",
100
+ "default": "0.75em"
101
+ },
102
+ {
103
+ "description": "Gap between flex children inside child triggers",
104
+ "name": "--rc-menubar-item-gap",
105
+ "default": "var(--rc-item-gap)"
106
+ },
107
+ {
108
+ "description": "Child trigger border",
109
+ "name": "--rc-menubar-item-border",
110
+ "default": "1px solid transparent"
111
+ },
112
+ {
113
+ "description": "Child trigger border radius",
114
+ "name": "--rc-menubar-item-radius",
115
+ "default": "var(--rc-control-radius)"
116
+ },
117
+ {
118
+ "description": "Child trigger background",
119
+ "name": "--rc-menubar-item-background",
120
+ "default": "transparent"
121
+ },
122
+ {
123
+ "description": "Child trigger text color",
124
+ "name": "--rc-menubar-item-color",
125
+ "default": "inherit"
126
+ },
127
+ {
128
+ "description": "CSS transition applied to child triggers",
129
+ "name": "--rc-menubar-item-transition"
130
+ },
131
+ {
132
+ "description": "Child trigger hover background",
133
+ "name": "--rc-menubar-item-hover-background",
134
+ "default": "color-mix(in srgb, Highlight 8%, transparent)"
135
+ },
136
+ {
137
+ "description": "Child trigger hover text color",
138
+ "name": "--rc-menubar-item-hover-color",
139
+ "default": "inherit"
140
+ },
141
+ {
142
+ "description": "Child trigger hover border color",
143
+ "name": "--rc-menubar-item-hover-border-color",
144
+ "default": "transparent"
145
+ },
146
+ {
147
+ "description": "Child trigger background when its menu is open",
148
+ "name": "--rc-menubar-item-open-background",
149
+ "default": "color-mix(in srgb, Highlight 12%, transparent)"
150
+ },
151
+ {
152
+ "description": "Child trigger text color when its menu is open",
153
+ "name": "--rc-menubar-item-open-color",
154
+ "default": "inherit"
155
+ },
156
+ {
157
+ "description": "Child trigger border color when its menu is open",
158
+ "name": "--rc-menubar-item-open-border-color",
159
+ "default": "transparent"
86
160
  }
87
161
  ],
88
162
  "cssParts": [
@@ -105,7 +179,7 @@
105
179
  "text": "string"
106
180
  },
107
181
  "default": "'Menu'",
108
- "description": "Accessible label for this menubar",
182
+ "description": "Accessible label for the `role=\"menubar\"` element.",
109
183
  "attribute": "label"
110
184
  },
111
185
  {
@@ -115,73 +189,76 @@
115
189
  "text": "'horizontal' | 'vertical'"
116
190
  },
117
191
  "default": "'horizontal'",
118
- "description": "Menubar orientation, for keyboard navigation",
192
+ "description": "Orientation of the menubar, controls which arrow keys move between items.",
119
193
  "attribute": "orientation",
120
194
  "reflects": true
121
195
  },
122
196
  {
123
197
  "kind": "field",
124
- "name": "_activeMenuButton",
198
+ "name": "_$activeMenuButton",
125
199
  "type": {
126
200
  "text": "WeakRef<RCMenuButton> | undefined"
127
201
  },
128
- "privacy": "private",
129
- "description": "Reference to the currently open menu button"
202
+ "privacy": "protected",
203
+ "description": "Weak reference to the currently open child `rc-menu-button`."
130
204
  },
131
205
  {
132
206
  "kind": "field",
133
- "name": "_lastFocused",
207
+ "name": "_$lastFocused",
134
208
  "type": {
135
209
  "text": "HTMLElement | undefined"
136
210
  },
137
- "privacy": "private",
138
- "description": "The last menu button trigger to have focus"
211
+ "privacy": "protected",
212
+ "description": "The last trigger element to have received focus, used for roving-tabindex bookkeeping."
139
213
  },
140
214
  {
141
215
  "kind": "field",
142
- "name": "_menuButtons",
216
+ "name": "_$menuButtons",
143
217
  "type": {
144
218
  "text": "WeakRef<RCMenuButton>[]"
145
219
  },
146
- "privacy": "private",
220
+ "privacy": "protected",
147
221
  "default": "[]",
148
- "description": "Array of menu button elements"
222
+ "description": "Weak references to all slotted `rc-menu-button` children, in DOM order."
149
223
  },
150
224
  {
151
225
  "kind": "field",
152
226
  "name": "_boundHandleKeydown",
153
- "privacy": "private"
227
+ "privacy": "protected",
228
+ "description": "Bound keydown handler, held for `removeEventListener` pairing."
154
229
  },
155
230
  {
156
231
  "kind": "field",
157
232
  "name": "_boundHandleClick",
158
- "privacy": "private"
233
+ "privacy": "protected",
234
+ "description": "Bound click handler, held for `removeEventListener` pairing."
159
235
  },
160
236
  {
161
237
  "kind": "method",
162
238
  "name": "_syncHostAria",
163
- "privacy": "private",
239
+ "privacy": "protected",
164
240
  "return": {
165
241
  "type": {
166
242
  "text": "void"
167
243
  }
168
244
  },
169
- "description": "Keep ARIA semantics on the custom element host for slotted children."
245
+ "description": "Writes `role`, `aria-label`, and `aria-orientation` to the host element."
170
246
  },
171
247
  {
172
248
  "kind": "method",
173
249
  "name": "_syncMenuButtonOrientation",
174
- "privacy": "private",
250
+ "privacy": "protected",
175
251
  "return": {
176
252
  "type": {
177
253
  "text": "void"
178
254
  }
179
- }
255
+ },
256
+ "description": "Propagates the current `orientation` value to all slotted `rc-menu-button` children."
180
257
  },
181
258
  {
182
259
  "kind": "method",
183
- "name": "_getTrigger",
184
- "privacy": "private",
260
+ "name": "_$getTrigger",
261
+ "privacy": "protected",
185
262
  "return": {
186
263
  "type": {
187
264
  "text": "HTMLElement | null"
@@ -189,72 +266,72 @@
189
266
  },
190
267
  "parameters": [
191
268
  {
192
- "name": "menuButton",
269
+ "name": "$menuButton",
193
270
  "type": {
194
271
  "text": "RCMenuButton"
195
272
  }
196
273
  }
197
274
  ],
198
- "description": "Get the trigger element from a menu button"
275
+ "description": "Returns the `[slot=\"trigger\"]` element inside a child `rc-menu-button`."
199
276
  },
200
277
  {
201
278
  "kind": "field",
202
- "name": "items",
279
+ "name": "$items",
203
280
  "type": {
204
281
  "text": "HTMLElement[]"
205
282
  },
206
- "description": "Array of focusable trigger elements",
283
+ "description": "All slotted trigger elements in DOM order.",
207
284
  "readonly": true
208
285
  },
209
286
  {
210
287
  "kind": "field",
211
- "name": "menuButtons",
288
+ "name": "$menuButtons",
212
289
  "type": {
213
290
  "text": "RCMenuButton[]"
214
291
  },
215
- "description": "Array of menu button elements",
292
+ "description": "All slotted `rc-menu-button` children in DOM order.",
216
293
  "readonly": true
217
294
  },
218
295
  {
219
296
  "kind": "field",
220
- "name": "firstItem",
297
+ "name": "$firstItem",
221
298
  "type": {
222
299
  "text": "HTMLElement | undefined"
223
300
  },
224
- "description": "First trigger element",
301
+ "description": "First trigger element in the menubar.",
225
302
  "readonly": true
226
303
  },
227
304
  {
228
305
  "kind": "field",
229
- "name": "lastItem",
306
+ "name": "$lastItem",
230
307
  "type": {
231
308
  "text": "HTMLElement | undefined"
232
309
  },
233
- "description": "Last trigger element",
310
+ "description": "Last trigger element in the menubar.",
234
311
  "readonly": true
235
312
  },
236
313
  {
237
314
  "kind": "field",
238
- "name": "nextItem",
315
+ "name": "$nextItem",
239
316
  "type": {
240
317
  "text": "HTMLElement | undefined"
241
318
  },
242
- "description": "Next trigger element, in tab-order",
319
+ "description": "Trigger after `_$lastFocused`, wrapping around to the first.",
243
320
  "readonly": true
244
321
  },
245
322
  {
246
323
  "kind": "field",
247
- "name": "previousItem",
324
+ "name": "$previousItem",
248
325
  "type": {
249
326
  "text": "HTMLElement | undefined"
250
327
  },
251
- "description": "Previous trigger element, in tab-order",
328
+ "description": "Trigger before `_$lastFocused`, wrapping around to the last.",
252
329
  "readonly": true
253
330
  },
254
331
  {
255
332
  "kind": "method",
256
- "name": "_getMenuButtonForTrigger",
257
- "privacy": "private",
333
+ "name": "_$getMenuButtonForTrigger",
334
+ "privacy": "protected",
258
335
  "return": {
259
336
  "type": {
260
337
  "text": "RCMenuButton | undefined"
@@ -262,13 +339,13 @@
262
339
  },
263
340
  "parameters": [
264
341
  {
265
- "name": "trigger",
342
+ "name": "$trigger",
266
343
  "type": {
267
344
  "text": "HTMLElement"
268
345
  }
269
346
  }
270
347
  ],
271
- "description": "Get the menu button that contains a trigger"
348
+ "description": "Returns the `rc-menu-button` whose slotted trigger matches `$trigger`."
272
349
  },
273
350
  {
274
351
  "kind": "method",
@@ -279,20 +356,21 @@
279
356
  "optional": true,
280
357
  "type": {
281
358
  "text": "HTMLElement | null"
282
- }
359
+ },
360
+ "description": "trigger to focus; no-ops when `null` or `undefined`"
283
361
  }
284
362
  ],
285
- "description": "Set focus to a specific trigger element"
363
+ "description": "Moves focus to a trigger element."
286
364
  },
287
365
  {
288
366
  "kind": "method",
289
367
  "name": "closeActiveMenu",
290
- "description": "Close any open menu"
368
+ "description": "Closes the currently open child menu without returning focus to its trigger."
291
369
  },
292
370
  {
293
371
  "kind": "method",
294
372
  "name": "_handleItemFocus",
295
- "privacy": "private",
373
+ "privacy": "protected",
296
374
  "parameters": [
297
375
  {
298
376
  "name": "e",
@@ -300,12 +378,13 @@
300
378
  "text": "FocusEvent"
301
379
  }
302
380
  }
303
- ]
381
+ ],
382
+ "description": "Updates roving-tabindex state when a trigger element receives focus."
304
383
  },
305
384
  {
306
385
  "kind": "method",
307
386
  "name": "_handleSlotChange",
308
- "privacy": "private",
387
+ "privacy": "protected",
309
388
  "parameters": [
310
389
  {
311
390
  "name": "e",
@@ -313,12 +392,13 @@
313
392
  "text": "Event"
314
393
  }
315
394
  }
316
- ]
395
+ ],
396
+ "description": "Refreshes the cached `rc-menu-button` list when slotted children change."
317
397
  },
318
398
  {
319
399
  "kind": "method",
320
400
  "name": "_handleMenuButtonToggle",
321
- "privacy": "private",
401
+ "privacy": "protected",
322
402
  "parameters": [
323
403
  {
324
404
  "name": "e",
@@ -326,30 +406,34 @@
326
406
  "text": "CustomEvent<RCMenuButtonToggleEvent>"
327
407
  }
328
408
  }
329
- ]
409
+ ],
410
+ "description": "Tracks which child `rc-menu-button` is currently open."
330
411
  },
331
412
  {
332
413
  "kind": "method",
333
414
  "name": "_handleNavigate",
334
- "privacy": "private",
415
+ "privacy": "protected",
335
416
  "parameters": [
336
417
  {
337
418
  "name": "action",
338
419
  "type": {
339
420
  "text": "KeyboardNavigationAction"
340
- }
421
+ },
422
+ "description": "the navigation action produced by the keydown handler"
341
423
  }
342
- ]
424
+ ],
425
+ "description": "Routes keyboard navigation actions to item focus and menu open/close changes.\n\nWhen a menu is open, moving to an adjacent item closes the current menu and\nopens the one attached to the newly focused trigger."
343
426
  },
344
427
  {
345
428
  "kind": "method",
346
429
  "name": "_openCurrentMenu",
347
- "privacy": "private"
430
+ "privacy": "protected",
431
+ "description": "Opens the menu attached to the last-focused trigger."
348
432
  },
349
433
  {
350
434
  "kind": "method",
351
435
  "name": "_handleKeydown",
352
- "privacy": "private",
436
+ "privacy": "protected",
353
437
  "return": {
354
438
  "type": {
355
439
  "text": "void"
@@ -362,35 +446,19 @@
362
446
  "text": "KeyboardEvent"
363
447
  }
364
448
  }
365
- ]
449
+ ],
450
+ "description": "Translates keyboard events to navigation actions and activates keyboard interaction mode."
366
451
  },
367
452
  {
368
453
  "kind": "method",
369
454
  "name": "_handleClick",
370
- "privacy": "private",
455
+ "privacy": "protected",
371
456
  "return": {
372
457
  "type": {
373
458
  "text": "void"
374
459
  }
375
- }
376
- },
377
- {
378
- "kind": "method",
379
- "name": "_normalizeKey",
380
- "privacy": "private",
381
- "return": {
382
- "type": {
383
- "text": "string"
384
- }
385
460
  },
386
- "parameters": [
387
- {
388
- "name": "key",
389
- "type": {
390
- "text": "string"
391
- }
392
- }
393
- ]
461
+ "description": "Clears keyboard interaction mode on pointer click."
394
462
  }
395
463
  ],
396
464
  "attributes": [
@@ -400,7 +468,7 @@
400
468
  "text": "string"
401
469
  },
402
470
  "default": "'Menu'",
403
- "description": "Accessible label for this menubar",
471
+ "description": "Accessible label for the `role=\"menubar\"` element.",
404
472
  "fieldName": "label"
405
473
  },
406
474
  {
@@ -409,7 +477,7 @@
409
477
  "text": "'horizontal' | 'vertical'"
410
478
  },
411
479
  "default": "'horizontal'",
412
- "description": "Menubar orientation, for keyboard navigation",
480
+ "description": "Orientation of the menubar, controls which arrow keys move between items.",
413
481
  "fieldName": "orientation"
414
482
  }
415
483
  ],
@@ -1,5 +1,5 @@
1
1
  import "@rcarls/rc-menu-button/define";
2
- import { R as e } from "./rc-menubar-BWcf6GHO.js";
2
+ import { R as e } from "./rc-menubar-tmPcN84a.js";
3
3
  customElements.get("rc-menubar") || customElements.define("rc-menubar", e);
4
4
  export {
5
5
  e as RCMenubar