@optionfactory/fml 9.0.0-rc14 → 9.0.0-rc15
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/dist/custom-elements.json +26 -0
- package/dist/fml.css +1 -0
- package/dist/fml.css.map +1 -1
- package/dist/fml.iife.js +215 -90
- package/dist/fml.iife.js.map +1 -1
- package/dist/fml.iife.min.js +1 -1
- package/dist/fml.iife.min.js.map +1 -1
- package/dist/ful.css +1 -0
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +36 -6
- package/dist/ful.iife.js +214 -90
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +214 -91
- package/dist/ful.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +10 -0
- package/dist/web-types.json +17 -1
- package/package.json +1 -1
package/dist/fml.iife.js
CHANGED
|
@@ -8533,7 +8533,7 @@ var fml = (function (exports) {
|
|
|
8533
8533
|
|
|
8534
8534
|
const showOncePlaced = (popover, anchored) => {
|
|
8535
8535
|
popover.style.visibility = 'hidden';
|
|
8536
|
-
|
|
8536
|
+
queueMicrotask(() => {
|
|
8537
8537
|
if (popover.matches(':popover-open')) {
|
|
8538
8538
|
place(popover, anchored);
|
|
8539
8539
|
}
|
|
@@ -8672,8 +8672,9 @@ var fml = (function (exports) {
|
|
|
8672
8672
|
* start-aligned, clamped into the viewport; `flip` moves it above the
|
|
8673
8673
|
* anchor where the viewport leaves no room below, as the css
|
|
8674
8674
|
* `position-try-fallbacks` the paired popovers declare. A popover not
|
|
8675
|
-
* already open is shown before
|
|
8676
|
-
* sees is the right one
|
|
8675
|
+
* already open is shown and placed before the call returns, so the first
|
|
8676
|
+
* position anybody sees is the right one and the caller can move the focus
|
|
8677
|
+
* into it on the next line.
|
|
8677
8678
|
*
|
|
8678
8679
|
* @param {HTMLElement} popover the `[popover]` element to show, or an
|
|
8679
8680
|
* already-shown element to place
|
|
@@ -8699,16 +8700,10 @@ var fml = (function (exports) {
|
|
|
8699
8700
|
popover.style.left = `${clamp(box.left, PAD, Math.max(PAD, viewport.clientWidth - here.width - PAD))}px`;
|
|
8700
8701
|
popover.style.top = `${clamp(top, PAD, Math.max(PAD, viewport.clientHeight - here.height - PAD))}px`;
|
|
8701
8702
|
};
|
|
8702
|
-
if (popover.matches(':popover-open')
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
popover.style.visibility = 'hidden';
|
|
8707
|
-
popover.showPopover();
|
|
8708
|
-
requestAnimationFrame(() => {
|
|
8709
|
-
placeShown();
|
|
8710
|
-
popover.style.removeProperty('visibility');
|
|
8711
|
-
});
|
|
8703
|
+
if (typeof popover.showPopover === 'function' && !popover.matches(':popover-open')) {
|
|
8704
|
+
popover.showPopover();
|
|
8705
|
+
}
|
|
8706
|
+
placeShown();
|
|
8712
8707
|
return popover;
|
|
8713
8708
|
}
|
|
8714
8709
|
}
|
|
@@ -9000,6 +8995,11 @@ var fml = (function (exports) {
|
|
|
9000
8995
|
//from the host when it gave one, since it has to set aria-controls before
|
|
9001
8996
|
//this element upgrades
|
|
9002
8997
|
this.#menu.id = this.declared('listbox') || Attributes.uid('ful-listbox');
|
|
8998
|
+
this.#menu.addEventListener('mousedown', (evt) => {
|
|
8999
|
+
if (evt.target.closest('li')) {
|
|
9000
|
+
evt.preventDefault();
|
|
9001
|
+
}
|
|
9002
|
+
});
|
|
9003
9003
|
this.#menu.addEventListener('click', (evt) => {
|
|
9004
9004
|
evt.stopPropagation();
|
|
9005
9005
|
const li = evt.target.closest('li');
|
|
@@ -9007,7 +9007,7 @@ var fml = (function (exports) {
|
|
|
9007
9007
|
this.hide();
|
|
9008
9008
|
return;
|
|
9009
9009
|
}
|
|
9010
|
-
if (li.
|
|
9010
|
+
if (li.matches('[aria-disabled="true"]')) {
|
|
9011
9011
|
return;
|
|
9012
9012
|
}
|
|
9013
9013
|
this.#change(li);
|
|
@@ -9016,8 +9016,8 @@ var fml = (function (exports) {
|
|
|
9016
9016
|
}
|
|
9017
9017
|
#selected() {
|
|
9018
9018
|
return (
|
|
9019
|
-
this.#menu?.querySelector('[selected]:not([aria-disabled])') ??
|
|
9020
|
-
this.#menu?.querySelector('li:not([aria-disabled])') ??
|
|
9019
|
+
this.#menu?.querySelector('[selected]:not([aria-disabled="true"])') ??
|
|
9020
|
+
this.#menu?.querySelector('li:not([aria-disabled="true"])') ??
|
|
9021
9021
|
null
|
|
9022
9022
|
);
|
|
9023
9023
|
}
|
|
@@ -9059,7 +9059,11 @@ var fml = (function (exports) {
|
|
|
9059
9059
|
li.setAttribute('aria-selected', picked ? 'true' : 'false');
|
|
9060
9060
|
//metadata.disabled refuses the entry, metadata.reason saying why
|
|
9061
9061
|
const disabled = !!entry?.metadata?.disabled;
|
|
9062
|
-
|
|
9062
|
+
if (disabled) {
|
|
9063
|
+
li.setAttribute('aria-disabled', 'true');
|
|
9064
|
+
} else {
|
|
9065
|
+
li.removeAttribute('aria-disabled');
|
|
9066
|
+
}
|
|
9063
9067
|
if (disabled && entry.metadata.reason) {
|
|
9064
9068
|
li.setAttribute('title', String(entry.metadata.reason));
|
|
9065
9069
|
} else {
|
|
@@ -9148,7 +9152,7 @@ var fml = (function (exports) {
|
|
|
9148
9152
|
}
|
|
9149
9153
|
#walk(from, forward) {
|
|
9150
9154
|
for (let li = from; li; li = li[`${forward ? 'next' : 'previous'}ElementSibling`]) {
|
|
9151
|
-
if (!li.
|
|
9155
|
+
if (!li.matches('[aria-disabled="true"]')) {
|
|
9152
9156
|
return li;
|
|
9153
9157
|
}
|
|
9154
9158
|
}
|
|
@@ -10592,15 +10596,110 @@ var fml = (function (exports) {
|
|
|
10592
10596
|
}
|
|
10593
10597
|
}
|
|
10594
10598
|
|
|
10599
|
+
/** how long a type-ahead buffer stands before the next character starts a new search */
|
|
10600
|
+
const TYPEAHEAD_WINDOW = 500;
|
|
10601
|
+
|
|
10602
|
+
/**
|
|
10603
|
+
* The keyboard protocol of a menu popover: the focus moving into the menu as it
|
|
10604
|
+
* opens and back to the invoker as it closes, roving focus over the items with
|
|
10605
|
+
* the arrows, Home and End, type-ahead over their text, and Enter and Space
|
|
10606
|
+
* activating the focused one.
|
|
10607
|
+
*
|
|
10608
|
+
* The menu owns what an item is: `items` answers them in the order they are
|
|
10609
|
+
* walked, read on every gesture so a menu that fills itself later needs no
|
|
10610
|
+
* rewiring, and `current` names the one an opening focuses, the first otherwise.
|
|
10611
|
+
*
|
|
10612
|
+
* @param {HTMLElement} invoker the element the menu belongs to, and where the focus goes back
|
|
10613
|
+
* @param {HTMLElement} menu the `[popover]` holding the items
|
|
10614
|
+
* @param {{items: () => HTMLElement[], current?: () => HTMLElement|null|undefined}} conf
|
|
10615
|
+
*/
|
|
10616
|
+
const wireMenuKeys = (invoker, menu, { items, current = () => null }) => {
|
|
10617
|
+
let typed = '';
|
|
10618
|
+
let typedAt = 0;
|
|
10619
|
+
menu.addEventListener('toggle', (/** @type any */ evt) => {
|
|
10620
|
+
if (evt.newState !== 'open') {
|
|
10621
|
+
//give the invoker back the focus the menu had borrowed, without
|
|
10622
|
+
//stealing it from wherever else the close came from
|
|
10623
|
+
if (menu.contains(document.activeElement)) {
|
|
10624
|
+
invoker.focus();
|
|
10625
|
+
}
|
|
10626
|
+
return;
|
|
10627
|
+
}
|
|
10628
|
+
const all = items();
|
|
10629
|
+
(current() ?? all[0])?.focus();
|
|
10630
|
+
});
|
|
10631
|
+
menu.addEventListener('keydown', (evt) => {
|
|
10632
|
+
const target = /** @type HTMLElement */ (evt.target);
|
|
10633
|
+
const all = items();
|
|
10634
|
+
const item = all.find((candidate) => candidate === target || candidate.contains(target));
|
|
10635
|
+
if (!item) {
|
|
10636
|
+
return;
|
|
10637
|
+
}
|
|
10638
|
+
const at = all.indexOf(item);
|
|
10639
|
+
switch (evt.code) {
|
|
10640
|
+
case 'ArrowDown': {
|
|
10641
|
+
evt.preventDefault();
|
|
10642
|
+
all[(at + 1) % all.length]?.focus();
|
|
10643
|
+
return;
|
|
10644
|
+
}
|
|
10645
|
+
case 'ArrowUp': {
|
|
10646
|
+
evt.preventDefault();
|
|
10647
|
+
all[(at - 1 + all.length) % all.length]?.focus();
|
|
10648
|
+
return;
|
|
10649
|
+
}
|
|
10650
|
+
case 'Home': {
|
|
10651
|
+
evt.preventDefault();
|
|
10652
|
+
all[0]?.focus();
|
|
10653
|
+
return;
|
|
10654
|
+
}
|
|
10655
|
+
case 'End': {
|
|
10656
|
+
evt.preventDefault();
|
|
10657
|
+
all[all.length - 1]?.focus();
|
|
10658
|
+
return;
|
|
10659
|
+
}
|
|
10660
|
+
case 'Enter':
|
|
10661
|
+
case 'Space': {
|
|
10662
|
+
evt.preventDefault();
|
|
10663
|
+
item.click();
|
|
10664
|
+
invoker.focus();
|
|
10665
|
+
return;
|
|
10666
|
+
}
|
|
10667
|
+
case 'Escape': {
|
|
10668
|
+
//the platform's close request hides the menu, the focus is placed
|
|
10669
|
+
//on the invoker before the focused item is detached from it
|
|
10670
|
+
invoker.focus();
|
|
10671
|
+
return;
|
|
10672
|
+
}
|
|
10673
|
+
}
|
|
10674
|
+
if (evt.key.length !== 1 || evt.ctrlKey || evt.altKey || evt.metaKey) {
|
|
10675
|
+
return;
|
|
10676
|
+
}
|
|
10677
|
+
const now = Date.now();
|
|
10678
|
+
typed = now - typedAt > TYPEAHEAD_WINDOW ? evt.key : typed + evt.key;
|
|
10679
|
+
typedAt = now;
|
|
10680
|
+
const wanted = typed.toLowerCase();
|
|
10681
|
+
const repeated = [...wanted].every((character) => character === wanted[0]);
|
|
10682
|
+
const search = repeated ? wanted[0] : wanted;
|
|
10683
|
+
const from = repeated ? at + 1 : at;
|
|
10684
|
+
const found = [...all.slice(from), ...all.slice(0, from)].find((candidate) =>
|
|
10685
|
+
(candidate.textContent ?? '').trim().toLowerCase().startsWith(search),
|
|
10686
|
+
);
|
|
10687
|
+
if (found) {
|
|
10688
|
+
evt.preventDefault();
|
|
10689
|
+
found.focus();
|
|
10690
|
+
}
|
|
10691
|
+
});
|
|
10692
|
+
};
|
|
10693
|
+
|
|
10595
10694
|
/**
|
|
10596
10695
|
* An invoker button paired with the `ul[popover][role=menu]` that follows it:
|
|
10597
10696
|
* the chrome behind every filter's operator, sensitivity and boolean value.
|
|
10598
10697
|
*
|
|
10599
10698
|
* It fills the menu from a vocabulary, wires it the first time more than one
|
|
10600
10699
|
* choice survives the whitelist, pins the button to a static glyph when a
|
|
10601
|
-
* single one does,
|
|
10602
|
-
*
|
|
10603
|
-
*
|
|
10700
|
+
* single one does, takes the shared menu keyboard protocol, and keeps the
|
|
10701
|
+
* button's value, glyph and aria-label in step. A pick that changes the value
|
|
10702
|
+
* calls back; the host decides what that means.
|
|
10604
10703
|
*
|
|
10605
10704
|
* The button's `value` attribute is the store, as it is for a native control:
|
|
10606
10705
|
* the menu protocol finds the current item by it, and nothing mirrors it.
|
|
@@ -10758,64 +10857,10 @@ var fml = (function (exports) {
|
|
|
10758
10857
|
return Array.from(this.#menu.querySelectorAll('li > a'), (a) => /** @type HTMLAnchorElement */ (a));
|
|
10759
10858
|
}
|
|
10760
10859
|
#wire() {
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
if (evt.newState !== 'open') {
|
|
10766
|
-
//give the invoker back the focus the menu had borrowed, without
|
|
10767
|
-
//stealing it from wherever else the close came from
|
|
10768
|
-
if (menu.contains(document.activeElement)) {
|
|
10769
|
-
button.focus();
|
|
10770
|
-
}
|
|
10771
|
-
return;
|
|
10772
|
-
}
|
|
10773
|
-
const items = this.#items();
|
|
10774
|
-
(items.find((a) => a.getAttribute('value') === this.value) ?? items[0])?.focus();
|
|
10775
|
-
});
|
|
10776
|
-
menu.addEventListener('keydown', (evt) => {
|
|
10777
|
-
const target = /** @type HTMLElement */ (evt.target);
|
|
10778
|
-
const item = /** @type HTMLAnchorElement | null */ (target.closest('li > a'));
|
|
10779
|
-
if (!item) {
|
|
10780
|
-
return;
|
|
10781
|
-
}
|
|
10782
|
-
const items = this.#items();
|
|
10783
|
-
const at = items.indexOf(item);
|
|
10784
|
-
switch (evt.code) {
|
|
10785
|
-
case 'ArrowDown': {
|
|
10786
|
-
evt.preventDefault();
|
|
10787
|
-
items[(at + 1) % items.length]?.focus();
|
|
10788
|
-
break;
|
|
10789
|
-
}
|
|
10790
|
-
case 'ArrowUp': {
|
|
10791
|
-
evt.preventDefault();
|
|
10792
|
-
items[(at - 1 + items.length) % items.length]?.focus();
|
|
10793
|
-
break;
|
|
10794
|
-
}
|
|
10795
|
-
case 'Home': {
|
|
10796
|
-
evt.preventDefault();
|
|
10797
|
-
items[0]?.focus();
|
|
10798
|
-
break;
|
|
10799
|
-
}
|
|
10800
|
-
case 'End': {
|
|
10801
|
-
evt.preventDefault();
|
|
10802
|
-
items[items.length - 1]?.focus();
|
|
10803
|
-
break;
|
|
10804
|
-
}
|
|
10805
|
-
case 'Enter':
|
|
10806
|
-
case 'Space': {
|
|
10807
|
-
evt.preventDefault();
|
|
10808
|
-
item.click();
|
|
10809
|
-
button.focus();
|
|
10810
|
-
break;
|
|
10811
|
-
}
|
|
10812
|
-
case 'Escape': {
|
|
10813
|
-
//the platform's close request hides the menu, the focus is placed
|
|
10814
|
-
//on the invoker before the focused item is detached from it
|
|
10815
|
-
button.focus();
|
|
10816
|
-
break;
|
|
10817
|
-
}
|
|
10818
|
-
}
|
|
10860
|
+
Anchors.wire(this.#button, this.#menu, { prefix: 'ful-filter-menu', invoke: true, expanded: true });
|
|
10861
|
+
wireMenuKeys(this.#button, this.#menu, {
|
|
10862
|
+
items: () => this.#items(),
|
|
10863
|
+
current: () => this.#items().find((a) => a.getAttribute('value') === this.value),
|
|
10819
10864
|
});
|
|
10820
10865
|
}
|
|
10821
10866
|
}
|
|
@@ -11790,15 +11835,22 @@ var fml = (function (exports) {
|
|
|
11790
11835
|
*
|
|
11791
11836
|
* The body is text or a node: a string is never read as markup, an
|
|
11792
11837
|
* `innerHTML` sink being a thing the library does not carry. Each button is
|
|
11793
|
-
* a `[result, label, className?]` tuple
|
|
11838
|
+
* a `[result, label, className?]` tuple rendered as its answer, or a node
|
|
11839
|
+
* the caller has built itself, which is how a button carries anything a
|
|
11840
|
+
* tuple cannot say and how a footer gets a spacer.
|
|
11794
11841
|
* @param {string} header
|
|
11795
11842
|
* @param {string|Node} body
|
|
11796
|
-
* @param {[string, string, string?][]} [buttons]
|
|
11843
|
+
* @param {([string, string, string?]|Node)[]} [buttons]
|
|
11844
|
+
* @param {{ className?: string }} [options] `className` dresses the dialog,
|
|
11845
|
+
* the way a declared `ful-dialog` is given one to size it
|
|
11797
11846
|
* @returns {Promise<DialogOutcome>}
|
|
11798
11847
|
*/
|
|
11799
|
-
static async ask(header, body, buttons = []) {
|
|
11848
|
+
static async ask(header, body, buttons = [], { className } = {}) {
|
|
11800
11849
|
const dialog = document.createElement('ful-dialog');
|
|
11801
11850
|
dialog.setAttribute('header', header);
|
|
11851
|
+
if (className) {
|
|
11852
|
+
dialog.className = className;
|
|
11853
|
+
}
|
|
11802
11854
|
if (typeof body === 'string') {
|
|
11803
11855
|
dialog.textContent = body;
|
|
11804
11856
|
} else if (body) {
|
|
@@ -11809,12 +11861,17 @@ var fml = (function (exports) {
|
|
|
11809
11861
|
if (buttons.length > 0) {
|
|
11810
11862
|
const choices = document.createElement('template');
|
|
11811
11863
|
choices.setAttribute('slot', 'buttons');
|
|
11812
|
-
for (const
|
|
11864
|
+
for (const choice of buttons) {
|
|
11865
|
+
if (choice instanceof Node) {
|
|
11866
|
+
choices.content.append(choice);
|
|
11867
|
+
continue;
|
|
11868
|
+
}
|
|
11869
|
+
const [result, label, buttonClass] = choice;
|
|
11813
11870
|
const button = document.createElement('button');
|
|
11814
11871
|
button.type = 'button';
|
|
11815
11872
|
button.dataset.result = result;
|
|
11816
|
-
if (
|
|
11817
|
-
button.className =
|
|
11873
|
+
if (buttonClass) {
|
|
11874
|
+
button.className = buttonClass;
|
|
11818
11875
|
}
|
|
11819
11876
|
button.textContent = label;
|
|
11820
11877
|
choices.content.append(button);
|
|
@@ -11836,13 +11893,19 @@ var fml = (function (exports) {
|
|
|
11836
11893
|
* @param {string} header
|
|
11837
11894
|
* @param {string|Node} body
|
|
11838
11895
|
* @param {{ confirm?: string, cancel?: string }} [labels] overriding the localized defaults
|
|
11896
|
+
* @param {{ className?: string }} [options] as `ask` takes them
|
|
11839
11897
|
* @returns {Promise<boolean>}
|
|
11840
11898
|
*/
|
|
11841
|
-
static async confirm(header, body, labels = {}) {
|
|
11842
|
-
const outcome = await Dialog.ask(
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11899
|
+
static async confirm(header, body, labels = {}, options = {}) {
|
|
11900
|
+
const outcome = await Dialog.ask(
|
|
11901
|
+
header,
|
|
11902
|
+
body,
|
|
11903
|
+
[
|
|
11904
|
+
['cancel', labels.cancel ?? Localization.of().t('dialog.cancel')],
|
|
11905
|
+
['confirm', labels.confirm ?? Localization.of().t('dialog.confirm'), 'ful-button'],
|
|
11906
|
+
],
|
|
11907
|
+
options,
|
|
11908
|
+
);
|
|
11846
11909
|
return !outcome.dismissed && outcome.result === 'confirm';
|
|
11847
11910
|
}
|
|
11848
11911
|
}
|
|
@@ -12049,6 +12112,65 @@ var fml = (function (exports) {
|
|
|
12049
12112
|
}
|
|
12050
12113
|
}
|
|
12051
12114
|
|
|
12115
|
+
/**
|
|
12116
|
+
* A menu of commands on the native popover platform: the invoker named by
|
|
12117
|
+
* `for` toggles it and light dismiss and Escape come from the browser, while
|
|
12118
|
+
* the element adds the menu semantics and the keyboard protocol.
|
|
12119
|
+
*
|
|
12120
|
+
* The items are the buttons and links written inside it, kept as they are and
|
|
12121
|
+
* given their menu role and their place in the roving focus. Activation is the
|
|
12122
|
+
* item's own click, which the element only follows by closing.
|
|
12123
|
+
*/
|
|
12124
|
+
class Menu extends ParsedElement {
|
|
12125
|
+
static attributes = ['for'];
|
|
12126
|
+
render() {
|
|
12127
|
+
const named = this.declared('for');
|
|
12128
|
+
const invoker = named ? document.getElementById(named) : null;
|
|
12129
|
+
if (!invoker) {
|
|
12130
|
+
throw new Error(
|
|
12131
|
+
`ful-menu names no invoker: for="${named ?? ''}" must name an element already in the page when the menu upgrades`,
|
|
12132
|
+
);
|
|
12133
|
+
}
|
|
12134
|
+
this.setAttribute('role', 'menu');
|
|
12135
|
+
if (!this.hasAttribute('popover')) {
|
|
12136
|
+
this.setAttribute('popover', '');
|
|
12137
|
+
}
|
|
12138
|
+
invoker.setAttribute('aria-haspopup', 'menu');
|
|
12139
|
+
Anchors.wire(invoker, this, { prefix: 'ful-menu', invoke: true, expanded: true });
|
|
12140
|
+
wireMenuKeys(invoker, this, { items: () => this.items });
|
|
12141
|
+
this.#mark();
|
|
12142
|
+
this.addEventListener('click', (evt) => {
|
|
12143
|
+
const target = /** @type HTMLElement */ (evt.target);
|
|
12144
|
+
if (this.items.some((item) => item === target || item.contains(target))) {
|
|
12145
|
+
this.hidePopover();
|
|
12146
|
+
}
|
|
12147
|
+
});
|
|
12148
|
+
}
|
|
12149
|
+
/**
|
|
12150
|
+
* The commands, in the order the arrows walk them: the menu's own buttons
|
|
12151
|
+
* and links, minus the disabled and hidden ones, which keep their role and
|
|
12152
|
+
* leave the walk.
|
|
12153
|
+
*/
|
|
12154
|
+
get items() {
|
|
12155
|
+
return this.#mark().filter((item) => !item.hasAttribute('disabled') && !item.hasAttribute('hidden'));
|
|
12156
|
+
}
|
|
12157
|
+
/**
|
|
12158
|
+
* Gives every button and link of the menu its item role and takes it out of
|
|
12159
|
+
* the tab order, and answers them. Read on every gesture as well as at the
|
|
12160
|
+
* render, so a menu a page fills or empties later needs no rewiring.
|
|
12161
|
+
*/
|
|
12162
|
+
#mark() {
|
|
12163
|
+
const all = /** @type HTMLElement[] */ ([...this.querySelectorAll(':scope > button, :scope > a[href]')]);
|
|
12164
|
+
for (const item of all) {
|
|
12165
|
+
if (!item.hasAttribute('role')) {
|
|
12166
|
+
item.setAttribute('role', 'menuitem');
|
|
12167
|
+
}
|
|
12168
|
+
item.tabIndex = -1;
|
|
12169
|
+
}
|
|
12170
|
+
return all;
|
|
12171
|
+
}
|
|
12172
|
+
}
|
|
12173
|
+
|
|
12052
12174
|
const SEVERITIES = ['info', 'success', 'warning', 'error'];
|
|
12053
12175
|
|
|
12054
12176
|
//the regions alive in the document: the show-toast listener is wired once and
|
|
@@ -12694,6 +12816,7 @@ var fml = (function (exports) {
|
|
|
12694
12816
|
.defineElement('ful-tooltip', Tooltip)
|
|
12695
12817
|
.defineElement('ful-dialog', Dialog)
|
|
12696
12818
|
.defineElement('ful-drawer', Drawer)
|
|
12819
|
+
.defineElement('ful-menu', Menu)
|
|
12697
12820
|
.defineElement('ful-toasts', Toasts)
|
|
12698
12821
|
.defineElement('ful-tabs', Tabs)
|
|
12699
12822
|
.defineElement('ful-accordion', Accordion)
|
|
@@ -12760,6 +12883,7 @@ var fml = (function (exports) {
|
|
|
12760
12883
|
LocalDate: LocalDate,
|
|
12761
12884
|
LocalDateFilter: LocalDateFilter,
|
|
12762
12885
|
LocalStorage: LocalStorage,
|
|
12886
|
+
Menu: Menu,
|
|
12763
12887
|
NumberFilter: NumberFilter,
|
|
12764
12888
|
Pagination: Pagination,
|
|
12765
12889
|
Plugin: Plugin,
|
|
@@ -12832,6 +12956,7 @@ var fml = (function (exports) {
|
|
|
12832
12956
|
exports.LocalStorage = LocalStorage;
|
|
12833
12957
|
exports.Localization = Localization;
|
|
12834
12958
|
exports.MediaType = MediaType;
|
|
12959
|
+
exports.Menu = Menu;
|
|
12835
12960
|
exports.Nodes = Nodes;
|
|
12836
12961
|
exports.NumberFilter = NumberFilter;
|
|
12837
12962
|
exports.Pagination = Pagination;
|