@aurodesignsystem-dev/auro-formkit 0.0.0-pr1541.3 → 0.0.0-pr1541.5
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/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/api.md +1 -1
- package/components/combobox/demo/customize.min.js +72 -21
- package/components/combobox/demo/getting-started.min.js +72 -21
- package/components/combobox/demo/index.md +1 -0
- package/components/combobox/demo/index.min.js +72 -21
- package/components/combobox/dist/auro-combobox.d.ts +1 -1
- package/components/combobox/dist/index.js +4 -4
- package/components/combobox/dist/registered.js +4 -4
- package/components/counter/demo/customize.min.js +2 -2
- package/components/counter/demo/index.min.js +2 -2
- package/components/counter/dist/index.js +2 -2
- package/components/counter/dist/registered.js +2 -2
- package/components/datepicker/demo/customize.min.js +3 -3
- package/components/datepicker/demo/index.min.js +3 -3
- package/components/datepicker/dist/index.js +3 -3
- package/components/datepicker/dist/registered.js +3 -3
- package/components/dropdown/demo/customize.min.js +1 -1
- package/components/dropdown/demo/getting-started.min.js +1 -1
- package/components/dropdown/demo/index.min.js +1 -1
- package/components/dropdown/dist/index.js +1 -1
- package/components/dropdown/dist/registered.js +1 -1
- package/components/form/demo/customize.min.js +87 -32
- package/components/form/demo/getting-started.min.js +87 -32
- package/components/form/demo/index.min.js +87 -32
- package/components/form/demo/registerDemoDeps.min.js +87 -32
- package/components/input/demo/customize.min.js +1 -1
- package/components/input/demo/getting-started.min.js +1 -1
- package/components/input/demo/index.min.js +1 -1
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/menu/demo/api.md +24 -18
- package/components/menu/demo/css-only.md +1 -1
- package/components/menu/demo/customize.md +83 -83
- package/components/menu/demo/getting-started.md +2 -2
- package/components/menu/demo/index.min.js +68 -17
- package/components/menu/demo/voiceover.md +12 -8
- package/components/menu/dist/auro-menu-utils.d.ts +19 -0
- package/components/menu/dist/auro-menu.d.ts +4 -8
- package/components/menu/dist/auro-menuoption.d.ts +1 -0
- package/components/menu/dist/index.js +68 -17
- package/components/menu/dist/registered.js +68 -17
- package/components/radio/demo/customize.min.js +1 -1
- package/components/radio/demo/getting-started.min.js +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/api.md +2 -2
- package/components/select/demo/customize.md +3 -0
- package/components/select/demo/customize.min.js +75 -20
- package/components/select/demo/getting-started.md +1 -1
- package/components/select/demo/getting-started.min.js +75 -20
- package/components/select/demo/index.md +2 -2
- package/components/select/demo/index.min.js +75 -20
- package/components/select/dist/auro-select.d.ts +6 -2
- package/components/select/dist/index.js +7 -3
- package/components/select/dist/registered.js +7 -3
- package/custom-elements.json +1832 -1783
- package/package.json +1 -1
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
<auro-anchorlink fluid href="#scroll" class="level2 body-xs">Scroll</auro-anchorlink>
|
|
11
11
|
<auro-anchorlink fluid href="#nocheckmark" class="level2 body-xs">No Checkmark</auro-anchorlink>
|
|
12
12
|
<auro-anchorlink fluid href="#dividers" class="level2 body-xs">Dividers</auro-anchorlink>
|
|
13
|
+
<auro-anchorlink fluid href="#nestedMenu" class="level2 body-xs">Nested Menu</auro-anchorlink>
|
|
14
|
+
<auro-anchorlink fluid href="#customBehavior">Behavior</auro-anchorlink>
|
|
13
15
|
<auro-anchorlink fluid href="#static" class="level2 body-xs">Static Options</auro-anchorlink>
|
|
14
16
|
<auro-anchorlink fluid href="#matchWord" class="level2 body-xs">Match Word</auro-anchorlink>
|
|
15
17
|
<auro-anchorlink fluid href="#persistent" class="level2 body-xs">Persistent Option</auro-anchorlink>
|
|
16
18
|
<auro-anchorlink fluid href="#nomatch" class="level2 body-xs">No Match Placeholder</auro-anchorlink>
|
|
17
|
-
<auro-anchorlink fluid href="#nestedMenu" class="level2 body-xs">Nested Menu</auro-anchorlink>
|
|
18
|
-
<auro-anchorlink fluid href="#customBehavior">Behavior</auro-anchorlink>
|
|
19
19
|
<auro-anchorlink fluid href="#disabled" class="level2 body-xs">Disabled Options</auro-anchorlink>
|
|
20
20
|
<auro-anchorlink fluid href="#disabledMenu" class="level2 body-xs">Disabled Menu</auro-anchorlink>
|
|
21
21
|
<auro-anchorlink fluid href="#loading" class="level2 body-xs">Loading</auro-anchorlink>
|
|
@@ -324,6 +324,86 @@
|
|
|
324
324
|
</auro-menu></code></pre>
|
|
325
325
|
<!-- AURO-GENERATED-CONTENT:END -->
|
|
326
326
|
</auro-accordion>
|
|
327
|
+
<auro-header level="3" id="nestedMenu">Nested Menu</auro-header>
|
|
328
|
+
<p>Nest additional <code>auro-menu</code> elements inside the default slot to create sub-menus. Each nested menu maintains its own selection state.</p>
|
|
329
|
+
<div class="exampleWrapper">
|
|
330
|
+
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/nested-menu.html) -->
|
|
331
|
+
<!-- The below content is automatically added from ./../apiExamples/nested-menu.html -->
|
|
332
|
+
<auro-menu id="alpha">
|
|
333
|
+
<auro-menuoption value="stops">Stops</auro-menuoption>
|
|
334
|
+
<auro-menuoption value="price">Price</auro-menuoption>
|
|
335
|
+
<auro-menuoption value="duration">Duration</auro-menuoption>
|
|
336
|
+
<hr>
|
|
337
|
+
<auro-menu id="beta">
|
|
338
|
+
<auro-menuoption value="apples">Apples</auro-menuoption>
|
|
339
|
+
<auro-menuoption value="oranges">Oranges</auro-menuoption>
|
|
340
|
+
<auro-menuoption value="pears">Pears</auro-menuoption>
|
|
341
|
+
<auro-menuoption value="grapes">Grapes</auro-menuoption>
|
|
342
|
+
<auro-menuoption value="kiwi">Kiwi</auro-menuoption>
|
|
343
|
+
<hr>
|
|
344
|
+
<auro-menu id="charlie">
|
|
345
|
+
<auro-menuoption value="person">Person</auro-menuoption>
|
|
346
|
+
<auro-menuoption value="woman">Woman</auro-menuoption>
|
|
347
|
+
<auro-menuoption value="man">Man</auro-menuoption>
|
|
348
|
+
<auro-menuoption value="camera">Camera</auro-menuoption>
|
|
349
|
+
<auro-menuoption value="tv">TV</auro-menuoption>
|
|
350
|
+
</auro-menu>
|
|
351
|
+
</auro-menu>
|
|
352
|
+
<hr>
|
|
353
|
+
<auro-menuoption value="departure">Departure</auro-menuoption>
|
|
354
|
+
<auro-menuoption value="arrival">Arrival</auro-menuoption>
|
|
355
|
+
<hr>
|
|
356
|
+
<auro-menu id="delta">
|
|
357
|
+
<auro-menuoption value="cars">Cars</auro-menuoption>
|
|
358
|
+
<auro-menuoption value="trucks">Trucks</auro-menuoption>
|
|
359
|
+
<auro-menuoption value="boats">Boats</auro-menuoption>
|
|
360
|
+
<auro-menuoption value="planes">Planes</auro-menuoption>
|
|
361
|
+
<auro-menuoption value="motorcycles">Motorcycles</auro-menuoption>
|
|
362
|
+
</auro-menu>
|
|
363
|
+
</auro-menu>
|
|
364
|
+
<!-- AURO-GENERATED-CONTENT:END -->
|
|
365
|
+
</div>
|
|
366
|
+
<auro-accordion alignRight>
|
|
367
|
+
<span slot="trigger">See code</span>
|
|
368
|
+
<!-- AURO-GENERATED-CONTENT:START (CODE:src=./../apiExamples/nested-menu.html) -->
|
|
369
|
+
<!-- The below code snippet is automatically added from ./../apiExamples/nested-menu.html -->
|
|
370
|
+
<pre class="language-html"><code class="language-html"><auro-menu id="alpha">
|
|
371
|
+
<auro-menuoption value="stops">Stops</auro-menuoption>
|
|
372
|
+
<auro-menuoption value="price">Price</auro-menuoption>
|
|
373
|
+
<auro-menuoption value="duration">Duration</auro-menuoption>
|
|
374
|
+
<hr>
|
|
375
|
+
<auro-menu id="beta">
|
|
376
|
+
<auro-menuoption value="apples">Apples</auro-menuoption>
|
|
377
|
+
<auro-menuoption value="oranges">Oranges</auro-menuoption>
|
|
378
|
+
<auro-menuoption value="pears">Pears</auro-menuoption>
|
|
379
|
+
<auro-menuoption value="grapes">Grapes</auro-menuoption>
|
|
380
|
+
<auro-menuoption value="kiwi">Kiwi</auro-menuoption>
|
|
381
|
+
<hr>
|
|
382
|
+
<auro-menu id="charlie">
|
|
383
|
+
<auro-menuoption value="person">Person</auro-menuoption>
|
|
384
|
+
<auro-menuoption value="woman">Woman</auro-menuoption>
|
|
385
|
+
<auro-menuoption value="man">Man</auro-menuoption>
|
|
386
|
+
<auro-menuoption value="camera">Camera</auro-menuoption>
|
|
387
|
+
<auro-menuoption value="tv">TV</auro-menuoption>
|
|
388
|
+
</auro-menu>
|
|
389
|
+
</auro-menu>
|
|
390
|
+
<hr>
|
|
391
|
+
<auro-menuoption value="departure">Departure</auro-menuoption>
|
|
392
|
+
<auro-menuoption value="arrival">Arrival</auro-menuoption>
|
|
393
|
+
<hr>
|
|
394
|
+
<auro-menu id="delta">
|
|
395
|
+
<auro-menuoption value="cars">Cars</auro-menuoption>
|
|
396
|
+
<auro-menuoption value="trucks">Trucks</auro-menuoption>
|
|
397
|
+
<auro-menuoption value="boats">Boats</auro-menuoption>
|
|
398
|
+
<auro-menuoption value="planes">Planes</auro-menuoption>
|
|
399
|
+
<auro-menuoption value="motorcycles">Motorcycles</auro-menuoption>
|
|
400
|
+
</auro-menu>
|
|
401
|
+
</auro-menu></code></pre>
|
|
402
|
+
<!-- AURO-GENERATED-CONTENT:END -->
|
|
403
|
+
</auro-accordion>
|
|
404
|
+
</section>
|
|
405
|
+
<section>
|
|
406
|
+
<auro-header level="2" id="customBehavior">Behavior</auro-header>
|
|
327
407
|
<auro-header level="3" id="static">Static Options</auro-header>
|
|
328
408
|
<p>Add the <code>static</code> attribute to an <code>auro-menuoption</code> to make it non-interactive — the option renders but is skipped during keyboard navigation and cannot be selected. Useful for section headers or informational rows inside a menu.</p>
|
|
329
409
|
<div class="exampleWrapper">
|
|
@@ -462,86 +542,6 @@
|
|
|
462
542
|
</auro-menu></code></pre>
|
|
463
543
|
<!-- AURO-GENERATED-CONTENT:END -->
|
|
464
544
|
</auro-accordion>
|
|
465
|
-
<auro-header level="3" id="nestedMenu">Nested Menu</auro-header>
|
|
466
|
-
<p>Nest additional <code>auro-menu</code> elements inside the default slot to create sub-menus. Each nested menu maintains its own selection state.</p>
|
|
467
|
-
<div class="exampleWrapper">
|
|
468
|
-
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/nested-menu.html) -->
|
|
469
|
-
<!-- The below content is automatically added from ./../apiExamples/nested-menu.html -->
|
|
470
|
-
<auro-menu id="alpha">
|
|
471
|
-
<auro-menuoption value="stops">Stops</auro-menuoption>
|
|
472
|
-
<auro-menuoption value="price">Price</auro-menuoption>
|
|
473
|
-
<auro-menuoption value="duration">Duration</auro-menuoption>
|
|
474
|
-
<hr>
|
|
475
|
-
<auro-menu id="beta">
|
|
476
|
-
<auro-menuoption value="apples">Apples</auro-menuoption>
|
|
477
|
-
<auro-menuoption value="oranges">Oranges</auro-menuoption>
|
|
478
|
-
<auro-menuoption value="pears">Pears</auro-menuoption>
|
|
479
|
-
<auro-menuoption value="grapes">Grapes</auro-menuoption>
|
|
480
|
-
<auro-menuoption value="kiwi">Kiwi</auro-menuoption>
|
|
481
|
-
<hr>
|
|
482
|
-
<auro-menu id="charlie">
|
|
483
|
-
<auro-menuoption value="person">Person</auro-menuoption>
|
|
484
|
-
<auro-menuoption value="woman">Woman</auro-menuoption>
|
|
485
|
-
<auro-menuoption value="man">Man</auro-menuoption>
|
|
486
|
-
<auro-menuoption value="camera">Camera</auro-menuoption>
|
|
487
|
-
<auro-menuoption value="tv">TV</auro-menuoption>
|
|
488
|
-
</auro-menu>
|
|
489
|
-
</auro-menu>
|
|
490
|
-
<hr>
|
|
491
|
-
<auro-menuoption value="departure">Departure</auro-menuoption>
|
|
492
|
-
<auro-menuoption value="arrival">Arrival</auro-menuoption>
|
|
493
|
-
<hr>
|
|
494
|
-
<auro-menu id="delta">
|
|
495
|
-
<auro-menuoption value="cars">Cars</auro-menuoption>
|
|
496
|
-
<auro-menuoption value="trucks">Trucks</auro-menuoption>
|
|
497
|
-
<auro-menuoption value="boats">Boats</auro-menuoption>
|
|
498
|
-
<auro-menuoption value="planes">Planes</auro-menuoption>
|
|
499
|
-
<auro-menuoption value="motorcycles">Motorcycles</auro-menuoption>
|
|
500
|
-
</auro-menu>
|
|
501
|
-
</auro-menu>
|
|
502
|
-
<!-- AURO-GENERATED-CONTENT:END -->
|
|
503
|
-
</div>
|
|
504
|
-
<auro-accordion alignRight>
|
|
505
|
-
<span slot="trigger">See code</span>
|
|
506
|
-
<!-- AURO-GENERATED-CONTENT:START (CODE:src=./../apiExamples/nested-menu.html) -->
|
|
507
|
-
<!-- The below code snippet is automatically added from ./../apiExamples/nested-menu.html -->
|
|
508
|
-
<pre class="language-html"><code class="language-html"><auro-menu id="alpha">
|
|
509
|
-
<auro-menuoption value="stops">Stops</auro-menuoption>
|
|
510
|
-
<auro-menuoption value="price">Price</auro-menuoption>
|
|
511
|
-
<auro-menuoption value="duration">Duration</auro-menuoption>
|
|
512
|
-
<hr>
|
|
513
|
-
<auro-menu id="beta">
|
|
514
|
-
<auro-menuoption value="apples">Apples</auro-menuoption>
|
|
515
|
-
<auro-menuoption value="oranges">Oranges</auro-menuoption>
|
|
516
|
-
<auro-menuoption value="pears">Pears</auro-menuoption>
|
|
517
|
-
<auro-menuoption value="grapes">Grapes</auro-menuoption>
|
|
518
|
-
<auro-menuoption value="kiwi">Kiwi</auro-menuoption>
|
|
519
|
-
<hr>
|
|
520
|
-
<auro-menu id="charlie">
|
|
521
|
-
<auro-menuoption value="person">Person</auro-menuoption>
|
|
522
|
-
<auro-menuoption value="woman">Woman</auro-menuoption>
|
|
523
|
-
<auro-menuoption value="man">Man</auro-menuoption>
|
|
524
|
-
<auro-menuoption value="camera">Camera</auro-menuoption>
|
|
525
|
-
<auro-menuoption value="tv">TV</auro-menuoption>
|
|
526
|
-
</auro-menu>
|
|
527
|
-
</auro-menu>
|
|
528
|
-
<hr>
|
|
529
|
-
<auro-menuoption value="departure">Departure</auro-menuoption>
|
|
530
|
-
<auro-menuoption value="arrival">Arrival</auro-menuoption>
|
|
531
|
-
<hr>
|
|
532
|
-
<auro-menu id="delta">
|
|
533
|
-
<auro-menuoption value="cars">Cars</auro-menuoption>
|
|
534
|
-
<auro-menuoption value="trucks">Trucks</auro-menuoption>
|
|
535
|
-
<auro-menuoption value="boats">Boats</auro-menuoption>
|
|
536
|
-
<auro-menuoption value="planes">Planes</auro-menuoption>
|
|
537
|
-
<auro-menuoption value="motorcycles">Motorcycles</auro-menuoption>
|
|
538
|
-
</auro-menu>
|
|
539
|
-
</auro-menu></code></pre>
|
|
540
|
-
<!-- AURO-GENERATED-CONTENT:END -->
|
|
541
|
-
</auro-accordion>
|
|
542
|
-
</section>
|
|
543
|
-
<section>
|
|
544
|
-
<auro-header level="2" id="customBehavior">Behavior</auro-header>
|
|
545
545
|
<auro-header level="3" id="disabled">Disabled Options</auro-header>
|
|
546
546
|
<p>Use the <code>disabled</code> attribute on <code>auro-menuoption</code> to prevent interaction with specific options.</p>
|
|
547
547
|
<div class="exampleWrapper">
|
|
@@ -810,7 +810,7 @@
|
|
|
810
810
|
<!-- AURO-GENERATED-CONTENT:END -->
|
|
811
811
|
</auro-accordion>
|
|
812
812
|
<auro-header level="3" id="presetValue">Preset Value</auro-header>
|
|
813
|
-
<p>Use the <code>value</code> attribute on <code>auro-menu</code> to set the selected option when the menu renders.</p>
|
|
813
|
+
<p>Use the <code>value</code> attribute on <code>auro-menu</code> to set the selected option when the menu renders. The value must match a selectable option; if it matches an option marked <code>disabled</code> or <code>static</code>, no option is selected and <code>auroMenu-selectValueFailure</code> is dispatched.</p>
|
|
814
814
|
<div class="exampleWrapper">
|
|
815
815
|
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/preset-value.html) -->
|
|
816
816
|
<!-- The below content is automatically added from ./../apiExamples/preset-value.html -->
|
|
@@ -296,7 +296,7 @@ Ensure your `tsconfig.json` uses `"moduleResolution": "bundler"` so TypeScript c
|
|
|
296
296
|
<auro-header level="2" id="stateManagement">State Management</auro-header>
|
|
297
297
|
<p>The following properties reflect the current state of the menu and can be accessed via JavaScript.</p>
|
|
298
298
|
<auro-header level="3" id="value">value</auro-header>
|
|
299
|
-
<p>Gets or sets the selected value. In multi-select mode, this is a JSON stringified array of selected option values (e.g., <code>'["stops","duration"]'</code>).</p>
|
|
299
|
+
<p>Gets or sets the selected value. In multi-select mode, this is a JSON stringified array of selected option values (e.g., <code>'["stops","duration"]'</code>). If the value matches an option marked <code>disabled</code> or <code>static</code>, the selection is cleared (<code>optionSelected</code> becomes <code>undefined</code>) and <code>auroMenu-selectValueFailure</code> is dispatched. <code>hidden</code> options remain selectable by value.</p>
|
|
300
300
|
<auro-header level="3" id="optionSelected">optionSelected</auro-header>
|
|
301
301
|
<p>Returns the currently selected <code><auro-menuoption></code> element, or <code>undefined</code> if no option is selected. When <code>multiSelect</code> is enabled, returns an array of selected elements.</p>
|
|
302
302
|
<auro-header level="3" id="optionActive">optionActive</auro-header>
|
|
@@ -391,7 +391,7 @@ Ensure your `tsconfig.json` uses `"moduleResolution": "bundler"` so TypeScript c
|
|
|
391
391
|
<li><code>auroMenu-activatedOption</code> — the active (highlighted) option changed via keyboard or hover.</li>
|
|
392
392
|
<li><code>auroMenu-optionsChange</code> — the set of available options was updated (e.g., after a slot change).</li>
|
|
393
393
|
<li><code>auroMenu-selectValueReset</code> — the menu's <code>value</code> was reset via <code>reset()</code>.</li>
|
|
394
|
-
<li><code>auroMenu-selectValueFailure</code> — a
|
|
394
|
+
<li><code>auroMenu-selectValueFailure</code> — a value selection (via <code>selectByValue()</code>, the <code>value</code> attribute, or setting the <code>value</code> property) found no matching selectable option. This includes values that match an option marked <code>disabled</code> or <code>static</code>, which are never selectable.</li>
|
|
395
395
|
</ul>
|
|
396
396
|
<div class="exampleWrapper">
|
|
397
397
|
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/events.html) -->
|
|
@@ -221,6 +221,18 @@ class AuroLibraryRuntimeUtils {
|
|
|
221
221
|
// See LICENSE in the project root for license information.
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Serializes a multi-select value array back into the String `value` property.
|
|
226
|
+
* An empty (or missing) array collapses to `undefined` so an emptied selection
|
|
227
|
+
* clears `value` rather than reflecting a `"[]"` attribute.
|
|
228
|
+
* @private
|
|
229
|
+
* @param {Array<string>|undefined} values - The selected values.
|
|
230
|
+
* @returns {string|undefined} JSON string of the values, or undefined when empty.
|
|
231
|
+
*/
|
|
232
|
+
function serializeMultiSelectValue(values) {
|
|
233
|
+
return values && values.length > 0 ? JSON.stringify(values) : undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
224
236
|
/**
|
|
225
237
|
* Validates if an option can be interacted with.
|
|
226
238
|
* @private
|
|
@@ -233,6 +245,20 @@ function isOptionInteractive(option) {
|
|
|
233
245
|
!option.hasAttribute('static');
|
|
234
246
|
}
|
|
235
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Validates if an option may be selected by matching a programmatic value.
|
|
250
|
+
* Unlike `isOptionInteractive`, `hidden` is allowed: the combobox toggles
|
|
251
|
+
* `hidden` as its type-ahead filter, so a filtered-out option is still a
|
|
252
|
+
* valid programmatic selection. Only disabled and static options — which are
|
|
253
|
+
* never selectable — are rejected.
|
|
254
|
+
* @param {HTMLElement} option - The option to check.
|
|
255
|
+
* @returns {boolean} True if option can be selected by value.
|
|
256
|
+
*/
|
|
257
|
+
function isSelectableByValue(option) {
|
|
258
|
+
return !option.hasAttribute('disabled') &&
|
|
259
|
+
!option.hasAttribute('static');
|
|
260
|
+
}
|
|
261
|
+
|
|
236
262
|
/**
|
|
237
263
|
* Helper method to dispatch custom events.
|
|
238
264
|
* @param {HTMLElement} element - Element to dispatch event from.
|
|
@@ -415,22 +441,26 @@ class AuroMenu extends AuroElement {
|
|
|
415
441
|
|
|
416
442
|
/**
|
|
417
443
|
* Specifies the current active menuOption.
|
|
444
|
+
* @readonly
|
|
418
445
|
*/
|
|
419
446
|
optionActive: {
|
|
420
447
|
type: Object,
|
|
421
|
-
attribute:
|
|
448
|
+
attribute: false
|
|
422
449
|
},
|
|
423
450
|
|
|
424
451
|
/**
|
|
425
452
|
* The currently selected menu option(s). In single-select mode this is a single `HTMLElement` (or `undefined` when nothing is selected). In multi-select mode this is an array of `HTMLElement`s.
|
|
453
|
+
* @readonly
|
|
426
454
|
*/
|
|
427
455
|
optionSelected: {
|
|
428
456
|
// Allow HTMLElement, HTMLElement[] arrays and undefined
|
|
429
|
-
type: Object
|
|
457
|
+
type: Object,
|
|
458
|
+
attribute: false
|
|
430
459
|
},
|
|
431
460
|
|
|
432
461
|
/**
|
|
433
462
|
* The value of the selected option. In multi-select mode, this is a JSON stringified array of selected option values.
|
|
463
|
+
* Options marked `disabled` or `static` are not selectable by value; `hidden` options remain selectable. In single-select mode, if the value matches a non-selectable option the selection is cleared (`optionSelected` becomes `undefined`) and `auroMenu-selectValueFailure` is dispatched. In multi-select mode, non-selectable entries are dropped from the value and the remaining selectable entries are selected; `auroMenu-selectValueFailure` is dispatched only when none of the entries match a selectable option.
|
|
434
464
|
*/
|
|
435
465
|
value: {
|
|
436
466
|
type: String,
|
|
@@ -554,7 +584,7 @@ class AuroMenu extends AuroElement {
|
|
|
554
584
|
}
|
|
555
585
|
|
|
556
586
|
/**
|
|
557
|
-
* Selects options by value.
|
|
587
|
+
* Selects options by value. Options marked `disabled` or `static` are not selectable; `hidden` options remain selectable. In single-select mode, if the value matches a non-selectable option the selection is cleared and `auroMenu-selectValueFailure` is dispatched. In multi-select mode, non-selectable entries are dropped and the remaining selectable entries are selected; `auroMenu-selectValueFailure` is dispatched only when none of the entries match a selectable option. Passing `undefined`, `null`, an empty string, or an empty array clears the selection without dispatching a failure.
|
|
558
588
|
* @param {string|string[]|undefined|null} value - The value(s) to select.
|
|
559
589
|
* @public
|
|
560
590
|
*/
|
|
@@ -639,6 +669,11 @@ class AuroMenu extends AuroElement {
|
|
|
639
669
|
this.initItems();
|
|
640
670
|
}
|
|
641
671
|
|
|
672
|
+
// Set when reconciliation reassigns `value` below. That reassignment schedules a
|
|
673
|
+
// second updated() cycle, so the `event`-attribute dispatch is deferred to that
|
|
674
|
+
// cycle to avoid firing option custom events twice on the same selection.
|
|
675
|
+
let valueReconciled = false;
|
|
676
|
+
|
|
642
677
|
// Handle null/undefined/empty case — empty/whitespace strings clear selection
|
|
643
678
|
// consistently with selectByValue(''), and avoid downstream `.includes('')` matches.
|
|
644
679
|
if (this.value === undefined || this.value === null || (typeof this.value === 'string' && this.value.trim() === '')) {
|
|
@@ -651,11 +686,31 @@ class AuroMenu extends AuroElement {
|
|
|
651
686
|
// Defensive default: `formattedValue` can be undefined for unexpected value types,
|
|
652
687
|
// and calling `.includes` on undefined would throw during reconciliation.
|
|
653
688
|
const valueArray = this.formattedValue || [];
|
|
654
|
-
const matchingOptions = this.items ? this.items.filter((item) => valueArray.includes(item.value)) : [];
|
|
689
|
+
const matchingOptions = this.items ? this.items.filter((item) => isSelectableByValue(item) && valueArray.includes(item.value)) : [];
|
|
655
690
|
newSelected = matchingOptions.length > 0 ? matchingOptions : undefined;
|
|
691
|
+
|
|
692
|
+
// Reconcile `value` with the selectable set. Drop only entries whose option is
|
|
693
|
+
// loaded but non-selectable (disabled/static) — leaving them would desync `value`
|
|
694
|
+
// from `optionSelected`, and the toggle handlers rebuild `value` from `formattedValue`,
|
|
695
|
+
// so the rejected entry would resurface on the next select/deselect. Entries with no
|
|
696
|
+
// matching item yet are preserved so async preselection still works once options render.
|
|
697
|
+
const rejectedValues = this.items
|
|
698
|
+
? this.items.filter((item) => !isSelectableByValue(item) && valueArray.includes(item.value)).map((item) => item.value)
|
|
699
|
+
: [];
|
|
700
|
+
if (rejectedValues.length > 0) {
|
|
701
|
+
const reconciled = valueArray.filter((val) => !rejectedValues.includes(val));
|
|
702
|
+
this.value = serializeMultiSelectValue(reconciled);
|
|
703
|
+
valueReconciled = true;
|
|
704
|
+
}
|
|
656
705
|
} else {
|
|
657
|
-
// In single-select mode, this.value should be a string
|
|
658
|
-
|
|
706
|
+
// In single-select mode, this.value should be a string. Reject
|
|
707
|
+
// disabled/static options so a programmatic value pointing at a
|
|
708
|
+
// non-selectable option falls through to the no-match path below
|
|
709
|
+
// (dispatching auroMenu-selectValueFailure) instead of pinning it.
|
|
710
|
+
// `hidden` is intentionally NOT excluded: the combobox toggles
|
|
711
|
+
// `hidden` as its type-ahead filter, so a filtered-out option is
|
|
712
|
+
// still a valid programmatic selection.
|
|
713
|
+
const matchingOption = this.items ? this.items.find((item) => isSelectableByValue(item) && item.value === this.value) : undefined;
|
|
659
714
|
|
|
660
715
|
if (matchingOption) {
|
|
661
716
|
newSelected = matchingOption;
|
|
@@ -697,8 +752,9 @@ class AuroMenu extends AuroElement {
|
|
|
697
752
|
]
|
|
698
753
|
]));
|
|
699
754
|
|
|
700
|
-
// Notify of changes
|
|
701
|
-
|
|
755
|
+
// Notify of changes. Skip when reconciliation just reassigned `value`: the
|
|
756
|
+
// follow-on update cycle re-runs this branch and fires the events exactly once.
|
|
757
|
+
if (this.optionSelected !== undefined && !valueReconciled) {
|
|
702
758
|
const selected = Array.isArray(this.optionSelected) ? this.optionSelected : [this.optionSelected];
|
|
703
759
|
selected.forEach((opt) => {
|
|
704
760
|
if (opt.hasAttribute('event')) {
|
|
@@ -911,7 +967,7 @@ class AuroMenu extends AuroElement {
|
|
|
911
967
|
const currentSelected = this.optionSelected || [];
|
|
912
968
|
|
|
913
969
|
if (!currentValue.includes(option.value)) {
|
|
914
|
-
this.value =
|
|
970
|
+
this.value = serializeMultiSelectValue([
|
|
915
971
|
...currentValue,
|
|
916
972
|
option.value
|
|
917
973
|
]);
|
|
@@ -937,15 +993,9 @@ class AuroMenu extends AuroElement {
|
|
|
937
993
|
*/
|
|
938
994
|
handleDeselectState(option) {
|
|
939
995
|
if (this.multiSelect) {
|
|
940
|
-
// Remove this option from array
|
|
996
|
+
// Remove this option from array; an empty result collapses `value` to undefined.
|
|
941
997
|
const newFormattedValue = (this.formattedValue || []).filter((val) => val !== option.value);
|
|
942
|
-
|
|
943
|
-
// If array is empty after removal, set back to undefined
|
|
944
|
-
if (newFormattedValue && newFormattedValue.length === 0) {
|
|
945
|
-
this.value = undefined;
|
|
946
|
-
} else {
|
|
947
|
-
this.value = JSON.stringify(newFormattedValue);
|
|
948
|
-
}
|
|
998
|
+
this.value = serializeMultiSelectValue(newFormattedValue);
|
|
949
999
|
|
|
950
1000
|
this.optionSelected = this.optionSelected.filter((val) => val !== option);
|
|
951
1001
|
if (this.optionSelected.length === 0) {
|
|
@@ -1459,6 +1509,7 @@ let menuOptionIdCounter = 0;
|
|
|
1459
1509
|
* The `auro-menuoption` element provides users a way to define a menu option.
|
|
1460
1510
|
* @customElement auro-menuoption
|
|
1461
1511
|
*
|
|
1512
|
+
* @attr {Boolean} static - When present, marks the option as non-interactive — it renders but is skipped during keyboard navigation and cannot be selected. Useful for section headers, informational rows inside a menu, or attaching event listeners.
|
|
1462
1513
|
* @slot default - The default slot for the menu option text.
|
|
1463
1514
|
*
|
|
1464
1515
|
* @event auroMenuOption-mouseover - Notifies that this option has been hovered over.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<auro-header level="1" id="overview">Menu - VoiceOver Behavior</auro-header>
|
|
2
2
|
<p>This page documents the VoiceOver experience when using the <code><auro-menu></code> component. It covers announcements and interactions for menu navigation and option selection.</p>
|
|
3
|
+
<div class="note"><strong>Note:</strong> In the standard integrations (<code><auro-select></code>, <code><auro-combobox></code>), keyboard focus stays on the parent trigger/input — it does <strong>not</strong> move into the menu. The parent captures keys and drives the menu, and the active option is announced via <code>aria-activedescendant</code> on the trigger rather than by moving DOM focus between options. The focus-on-the-menu behavior described alongside the standalone case below only applies when an author makes <code><auro-menu></code> itself focusable (for example, <code>tabindex="0"</code>).</p>
|
|
3
4
|
<auro-header level="2" id="voiceOverInteractiveAnnouncements">Interactive Announcements</auro-header>
|
|
4
5
|
<auro-header level="3" id="voiceOverMenuContainer">Menu Container</auro-header>
|
|
5
|
-
<p>When
|
|
6
|
+
<p>When the listbox is exposed — the parent's dropdown opens, or a standalone focusable menu receives focus — VoiceOver announces:</p>
|
|
6
7
|
<ol>
|
|
7
8
|
<li><strong>Role:</strong> <em>"list box"</em> — set on the root <code><auro-menu></code>; nested menus use <code>role="group"</code> with <code>aria-label="submenu"</code>.</li>
|
|
8
9
|
<li><strong>Item count:</strong> The number of visible options (e.g., <em>"5 items"</em>)</li>
|
|
@@ -20,17 +21,20 @@
|
|
|
20
21
|
</ol>
|
|
21
22
|
<div class="note"><strong>Note:</strong> <code><auro-menuoption></code> is not directly focusable — <code>tabindex="-1"</code> keeps it out of the tab order. In a select or combobox context, focus stays on the parent trigger and the active option is pointed at via <code>aria-activedescendant</code> (using <code>ariaActiveDescendantElement</code> to cross the shadow-root boundary).</div>
|
|
22
23
|
<auro-header level="3" id="voiceOverSelection">Selection</auro-header>
|
|
23
|
-
<p>
|
|
24
|
+
<p>In a select or combobox context, the parent captures Enter (and Tab) on its trigger/input and commits the active option through the menu; the menu itself does not receive the key. When the selection is committed:</p>
|
|
24
25
|
<ul>
|
|
25
26
|
<li>VoiceOver announces the option label followed by <em>"selected"</em></li>
|
|
26
27
|
<li>In multi-select mode, previously selected options remain selected and their state is preserved</li>
|
|
27
|
-
</ul>
|
|
28
|
+
</ul>
|
|
29
|
+
<p>A standalone focusable menu (see the note at the top of this page) handles Enter and Tab on its own host, producing the same selection announcement.</p>
|
|
28
30
|
<auro-header level="2" id="voiceOverWorkflow">Navigation Workflow</auro-header>
|
|
31
|
+
<p>In the standard select/combobox integrations, focus remains on the parent trigger/input throughout — the menu is a visually presented listbox the parent points into, not a place focus travels to:</p>
|
|
29
32
|
<ol>
|
|
30
|
-
<li><strong>
|
|
31
|
-
<li><strong>Navigate options:</strong>
|
|
32
|
-
<li><strong>Select an option:</strong>
|
|
33
|
-
<li><strong>Exit:</strong> Tab
|
|
34
|
-
</ol>
|
|
33
|
+
<li><strong>Open the listbox:</strong> Activating the trigger (or typing in a combobox) exposes the menu; VoiceOver announces the listbox role and item count</li>
|
|
34
|
+
<li><strong>Navigate options:</strong> Arrow Down/Up keys pressed on the trigger move the active option; <code>aria-activedescendant</code> updates and VoiceOver announces each option's label, role, and position</li>
|
|
35
|
+
<li><strong>Select an option:</strong> Enter (captured by the parent) commits the active option; VoiceOver confirms the selection</li>
|
|
36
|
+
<li><strong>Exit:</strong> Escape and Tab are handled by the parent — Escape closes the listbox, and Tab commits the active option before moving focus to the next element in the tab sequence</li>
|
|
37
|
+
</ol>
|
|
38
|
+
<p>A standalone focusable menu follows the same active-option model, except focus is on the menu host and the menu handles Arrow, Enter, and Tab directly. See the menu's key events documentation for the full standalone key table.</p>
|
|
35
39
|
<auro-header level="2" id="voiceOverNestedMenus">Nested Menus</auro-header>
|
|
36
40
|
<p>When a nested <code>auro-menu</code> is encountered, VoiceOver announces a new listbox context. Each nested menu maintains its own option count and position tracking.</p>
|
|
@@ -10,6 +10,15 @@
|
|
|
10
10
|
* or if the value cannot be parsed into an array from a JSON string.
|
|
11
11
|
*/
|
|
12
12
|
export function arrayConverter(value: any): any[] | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Serializes a multi-select value array back into the String `value` property.
|
|
15
|
+
* An empty (or missing) array collapses to `undefined` so an emptied selection
|
|
16
|
+
* clears `value` rather than reflecting a `"[]"` attribute.
|
|
17
|
+
* @private
|
|
18
|
+
* @param {Array<string>|undefined} values - The selected values.
|
|
19
|
+
* @returns {string|undefined} JSON string of the values, or undefined when empty.
|
|
20
|
+
*/
|
|
21
|
+
export function serializeMultiSelectValue(values: Array<string> | undefined): string | undefined;
|
|
13
22
|
/**
|
|
14
23
|
* Compare two arrays for equality.
|
|
15
24
|
* @private
|
|
@@ -25,6 +34,16 @@ export function arraysAreEqual(arr1: any[], arr2: any[]): boolean;
|
|
|
25
34
|
* @returns {boolean} True if option is interactive.
|
|
26
35
|
*/
|
|
27
36
|
export function isOptionInteractive(option: HTMLElement): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Validates if an option may be selected by matching a programmatic value.
|
|
39
|
+
* Unlike `isOptionInteractive`, `hidden` is allowed: the combobox toggles
|
|
40
|
+
* `hidden` as its type-ahead filter, so a filtered-out option is still a
|
|
41
|
+
* valid programmatic selection. Only disabled and static options — which are
|
|
42
|
+
* never selectable — are rejected.
|
|
43
|
+
* @param {HTMLElement} option - The option to check.
|
|
44
|
+
* @returns {boolean} True if option can be selected by value.
|
|
45
|
+
*/
|
|
46
|
+
export function isSelectableByValue(option: HTMLElement): boolean;
|
|
28
47
|
/**
|
|
29
48
|
* Helper method to dispatch custom events.
|
|
30
49
|
* @param {HTMLElement} element - Element to dispatch event from.
|
|
@@ -60,21 +60,17 @@ export class AuroMenu extends AuroElement {
|
|
|
60
60
|
reflect: boolean;
|
|
61
61
|
attribute: string;
|
|
62
62
|
};
|
|
63
|
-
/**
|
|
64
|
-
* Specifies the current active menuOption.
|
|
65
|
-
*/
|
|
66
63
|
optionActive: {
|
|
67
64
|
type: ObjectConstructor;
|
|
68
|
-
attribute:
|
|
65
|
+
attribute: boolean;
|
|
69
66
|
};
|
|
70
|
-
/**
|
|
71
|
-
* The currently selected menu option(s). In single-select mode this is a single `HTMLElement` (or `undefined` when nothing is selected). In multi-select mode this is an array of `HTMLElement`s.
|
|
72
|
-
*/
|
|
73
67
|
optionSelected: {
|
|
74
68
|
type: ObjectConstructor;
|
|
69
|
+
attribute: boolean;
|
|
75
70
|
};
|
|
76
71
|
/**
|
|
77
72
|
* The value of the selected option. In multi-select mode, this is a JSON stringified array of selected option values.
|
|
73
|
+
* Options marked `disabled` or `static` are not selectable by value; `hidden` options remain selectable. In single-select mode, if the value matches a non-selectable option the selection is cleared (`optionSelected` becomes `undefined`) and `auroMenu-selectValueFailure` is dispatched. In multi-select mode, non-selectable entries are dropped from the value and the remaining selectable entries are selected; `auroMenu-selectValueFailure` is dispatched only when none of the entries match a selectable option.
|
|
78
74
|
*/
|
|
79
75
|
value: {
|
|
80
76
|
type: StringConstructor;
|
|
@@ -171,7 +167,7 @@ export class AuroMenu extends AuroElement {
|
|
|
171
167
|
*/
|
|
172
168
|
private get formattedValue();
|
|
173
169
|
/**
|
|
174
|
-
* Selects options by value.
|
|
170
|
+
* Selects options by value. Options marked `disabled` or `static` are not selectable; `hidden` options remain selectable. In single-select mode, if the value matches a non-selectable option the selection is cleared and `auroMenu-selectValueFailure` is dispatched. In multi-select mode, non-selectable entries are dropped and the remaining selectable entries are selected; `auroMenu-selectValueFailure` is dispatched only when none of the entries match a selectable option. Passing `undefined`, `null`, an empty string, or an empty array clears the selection without dispatching a failure.
|
|
175
171
|
* @param {string|string[]|undefined|null} value - The value(s) to select.
|
|
176
172
|
* @public
|
|
177
173
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* The `auro-menuoption` element provides users a way to define a menu option.
|
|
3
3
|
* @customElement auro-menuoption
|
|
4
4
|
*
|
|
5
|
+
* @attr {Boolean} static - When present, marks the option as non-interactive — it renders but is skipped during keyboard navigation and cannot be selected. Useful for section headers, informational rows inside a menu, or attaching event listeners.
|
|
5
6
|
* @slot default - The default slot for the menu option text.
|
|
6
7
|
*
|
|
7
8
|
* @event auroMenuOption-mouseover - Notifies that this option has been hovered over.
|