@optionfactory/fml 9.0.0-rc24 → 9.0.0-rc25
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 +2 -2
- package/dist/fml.iife.js +90 -21
- 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.d.mts +30 -10
- package/dist/ful.iife.js +90 -21
- 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 +90 -21
- package/dist/ful.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +2 -2
- package/dist/web-types.json +3 -3
- package/package.json +1 -1
package/dist/ful.d.mts
CHANGED
|
@@ -740,7 +740,8 @@ declare class FormLoader {
|
|
|
740
740
|
*
|
|
741
741
|
* Attributes on the host starting with `form-` are forwarded, without the
|
|
742
742
|
* prefix, to the native form. `autocomplete` is copied onto the native form as
|
|
743
|
-
* well and stays on the host, the fields reading it from either
|
|
743
|
+
* well and stays on the host, the fields reading it from either; a
|
|
744
|
+
* `form-autocomplete` has the last word on the native form.
|
|
744
745
|
* `clear-invalid-on-change` clears the custom validity of a field of this form
|
|
745
746
|
* when a `change` event bubbles from it; the field's form is read from its
|
|
746
747
|
* `form` property, or from `internals.form` for a form-associated element
|
|
@@ -3160,11 +3161,15 @@ declare class Drawer extends ParsedElement {
|
|
|
3160
3161
|
close(result?: string): void;
|
|
3161
3162
|
}
|
|
3162
3163
|
/**
|
|
3163
|
-
* A menu of commands on the native popover platform
|
|
3164
|
-
*
|
|
3165
|
-
*
|
|
3164
|
+
* A menu of commands on the native popover platform. The menu is the popover
|
|
3165
|
+
* itself: light dismiss and Escape come from the browser.
|
|
3166
|
+
*
|
|
3167
|
+
* A menu naming an invoker by id through `for` belongs to that element: the
|
|
3168
|
+
* invoker toggles it, and it is anchored to the invoker through
|
|
3166
3169
|
* `Anchors.wire`, placed in script where the platform has no css anchor
|
|
3167
|
-
* positioning.
|
|
3170
|
+
* positioning. A menu without `for` is shared: one menu serves many
|
|
3171
|
+
* invokers, such as the "more" button of every row of a list, and a page
|
|
3172
|
+
* opens it beside the invoker it is for with `showFor(invoker)`.
|
|
3168
3173
|
*
|
|
3169
3174
|
* The items are the buttons and `a[href]` links written as its direct
|
|
3170
3175
|
* children, kept as they are. Activation is the item's own click, which the
|
|
@@ -3174,7 +3179,8 @@ declare class Drawer extends ParsedElement {
|
|
|
3174
3179
|
* The keyboard is the ARIA menu protocol: the focus moves to the
|
|
3175
3180
|
* first item as the menu opens, the arrows, Home and End walk the items,
|
|
3176
3181
|
* typing searches their text, Enter and Space activate the focused one, and
|
|
3177
|
-
* Escape and a close from inside the menu hand the focus back to the invoker
|
|
3182
|
+
* Escape and a close from inside the menu hand the focus back to the invoker
|
|
3183
|
+
* that opened it.
|
|
3178
3184
|
*/
|
|
3179
3185
|
declare class Menu extends ParsedElement {
|
|
3180
3186
|
#private;
|
|
@@ -3182,13 +3188,27 @@ declare class Menu extends ParsedElement {
|
|
|
3182
3188
|
static attributes: string[];
|
|
3183
3189
|
/**
|
|
3184
3190
|
* Gives the menu the `menu` role and an empty `popover` attribute unless
|
|
3185
|
-
* it already has one,
|
|
3186
|
-
*
|
|
3187
|
-
*
|
|
3191
|
+
* it already has one, and marks the items. With `for`, read here once, it
|
|
3192
|
+
* also gives the invoker `aria-haspopup="menu"`, an `aria-expanded` kept
|
|
3193
|
+
* in step, and the toggle of the menu.
|
|
3188
3194
|
* @returns {void}
|
|
3189
|
-
* @throws {Error} when `for` names no element in the document at the render
|
|
3195
|
+
* @throws {Error} when `for` is given and names no element in the document at the render
|
|
3190
3196
|
*/
|
|
3191
3197
|
render(): void;
|
|
3198
|
+
/**
|
|
3199
|
+
* Opens a shared menu, one without `for`, beside `invoker`, or moves it
|
|
3200
|
+
* there when it is open for another one. The menu goes below the invoker,
|
|
3201
|
+
* or above it where there is no room below, and is placed once, as
|
|
3202
|
+
* `Anchors.show` places it. The invoker gets `aria-haspopup="menu"` and an
|
|
3203
|
+
* `aria-expanded` that reads true until the menu closes, and the focus
|
|
3204
|
+
* goes back to it on Escape. A call for the invoker whose press has just
|
|
3205
|
+
* closed the menu does nothing, so a second click on the same button
|
|
3206
|
+
* closes the menu rather than opening it again.
|
|
3207
|
+
* @param {HTMLElement} invoker the element the menu opens for
|
|
3208
|
+
* @returns {void}
|
|
3209
|
+
* @throws {Error} when the menu names its invoker through `for`
|
|
3210
|
+
*/
|
|
3211
|
+
showFor(invoker: HTMLElement): void;
|
|
3192
3212
|
/**
|
|
3193
3213
|
* The commands, in the order the arrows walk them: the menu's direct
|
|
3194
3214
|
* `button` and `a[href]` children, minus those carrying a `disabled` or
|
package/dist/ful.iife.js
CHANGED
|
@@ -1358,7 +1358,8 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
1358
1358
|
*
|
|
1359
1359
|
* Attributes on the host starting with `form-` are forwarded, without the
|
|
1360
1360
|
* prefix, to the native form. `autocomplete` is copied onto the native form as
|
|
1361
|
-
* well and stays on the host, the fields reading it from either
|
|
1361
|
+
* well and stays on the host, the fields reading it from either; a
|
|
1362
|
+
* `form-autocomplete` has the last word on the native form.
|
|
1362
1363
|
* `clear-invalid-on-change` clears the custom validity of a field of this form
|
|
1363
1364
|
* when a `change` event bubbles from it; the field's form is read from its
|
|
1364
1365
|
* `form` property, or from `internals.form` for a form-associated element
|
|
@@ -1393,8 +1394,8 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
1393
1394
|
const form = document.createElement('form');
|
|
1394
1395
|
this.form = form;
|
|
1395
1396
|
form.setAttribute('novalidate', '');
|
|
1396
|
-
index_mjs.Attributes.forward('form-', this, form);
|
|
1397
1397
|
index_mjs.Attributes.set(form, 'autocomplete', this.declared('autocomplete'));
|
|
1398
|
+
index_mjs.Attributes.forward('form-', this, form);
|
|
1398
1399
|
form.replaceChildren(...this.childNodes);
|
|
1399
1400
|
form.addEventListener('submit', async (e) => {
|
|
1400
1401
|
e.preventDefault();
|
|
@@ -5582,7 +5583,9 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
5582
5583
|
* `items` answers the items in the order they are walked, and is called on
|
|
5583
5584
|
* every gesture, so a menu that fills itself later needs no rewiring.
|
|
5584
5585
|
*
|
|
5585
|
-
* @param {HTMLElement} invoker the element the menu belongs to
|
|
5586
|
+
* @param {() => HTMLElement|null} invoker answers the element the menu belongs to
|
|
5587
|
+
* now, where the focus goes back; called on every gesture, so a menu shared
|
|
5588
|
+
* by several invokers hands the focus back to the one that opened it
|
|
5586
5589
|
* @param {HTMLElement} menu the `[popover]` holding the items
|
|
5587
5590
|
* @param {{items: () => HTMLElement[], current?: () => HTMLElement|null|undefined}} conf
|
|
5588
5591
|
* `items` answers the items; `current` answers the item an opening focuses
|
|
@@ -5592,7 +5595,7 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
5592
5595
|
let typedAt = 0;
|
|
5593
5596
|
menu.addEventListener('beforetoggle', (/** @type any */ evt) => {
|
|
5594
5597
|
if (evt.newState === 'closed' && menu.contains(document.activeElement)) {
|
|
5595
|
-
invoker
|
|
5598
|
+
invoker()?.focus();
|
|
5596
5599
|
}
|
|
5597
5600
|
});
|
|
5598
5601
|
menu.addEventListener('toggle', (/** @type any */ evt) => {
|
|
@@ -5636,11 +5639,11 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
5636
5639
|
case 'Space': {
|
|
5637
5640
|
evt.preventDefault();
|
|
5638
5641
|
item.click();
|
|
5639
|
-
invoker
|
|
5642
|
+
invoker()?.focus();
|
|
5640
5643
|
return;
|
|
5641
5644
|
}
|
|
5642
5645
|
case 'Escape': {
|
|
5643
|
-
invoker
|
|
5646
|
+
invoker()?.focus();
|
|
5644
5647
|
return;
|
|
5645
5648
|
}
|
|
5646
5649
|
}
|
|
@@ -5865,7 +5868,7 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
5865
5868
|
}
|
|
5866
5869
|
#wire() {
|
|
5867
5870
|
Anchors.wire(this.#button, this.#menu, { prefix: 'ful-filter-menu', invoke: true, expanded: true });
|
|
5868
|
-
wireMenuKeys(this.#button, this.#menu, {
|
|
5871
|
+
wireMenuKeys(() => this.#button, this.#menu, {
|
|
5869
5872
|
items: () => this.#items(),
|
|
5870
5873
|
current: () => this.#items().find((a) => a.getAttribute('value') === this.value),
|
|
5871
5874
|
});
|
|
@@ -7577,11 +7580,15 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
7577
7580
|
}
|
|
7578
7581
|
|
|
7579
7582
|
/**
|
|
7580
|
-
* A menu of commands on the native popover platform
|
|
7581
|
-
*
|
|
7582
|
-
*
|
|
7583
|
+
* A menu of commands on the native popover platform. The menu is the popover
|
|
7584
|
+
* itself: light dismiss and Escape come from the browser.
|
|
7585
|
+
*
|
|
7586
|
+
* A menu naming an invoker by id through `for` belongs to that element: the
|
|
7587
|
+
* invoker toggles it, and it is anchored to the invoker through
|
|
7583
7588
|
* `Anchors.wire`, placed in script where the platform has no css anchor
|
|
7584
|
-
* positioning.
|
|
7589
|
+
* positioning. A menu without `for` is shared: one menu serves many
|
|
7590
|
+
* invokers, such as the "more" button of every row of a list, and a page
|
|
7591
|
+
* opens it beside the invoker it is for with `showFor(invoker)`.
|
|
7585
7592
|
*
|
|
7586
7593
|
* The items are the buttons and `a[href]` links written as its direct
|
|
7587
7594
|
* children, kept as they are. Activation is the item's own click, which the
|
|
@@ -7591,34 +7598,44 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
7591
7598
|
* The keyboard is the ARIA menu protocol: the focus moves to the
|
|
7592
7599
|
* first item as the menu opens, the arrows, Home and End walk the items,
|
|
7593
7600
|
* typing searches their text, Enter and Space activate the focused one, and
|
|
7594
|
-
* Escape and a close from inside the menu hand the focus back to the invoker
|
|
7601
|
+
* Escape and a close from inside the menu hand the focus back to the invoker
|
|
7602
|
+
* that opened it.
|
|
7595
7603
|
*/
|
|
7596
7604
|
class Menu extends index_mjs.ParsedElement {
|
|
7597
7605
|
/** @type {string[]} */
|
|
7598
7606
|
static attributes = ['for'];
|
|
7607
|
+
/** @type {HTMLElement|null} */
|
|
7608
|
+
#invoker = null;
|
|
7609
|
+
/** @type {HTMLElement|null} */
|
|
7610
|
+
#pressed = null;
|
|
7599
7611
|
/**
|
|
7600
7612
|
* Gives the menu the `menu` role and an empty `popover` attribute unless
|
|
7601
|
-
* it already has one,
|
|
7602
|
-
*
|
|
7603
|
-
*
|
|
7613
|
+
* it already has one, and marks the items. With `for`, read here once, it
|
|
7614
|
+
* also gives the invoker `aria-haspopup="menu"`, an `aria-expanded` kept
|
|
7615
|
+
* in step, and the toggle of the menu.
|
|
7604
7616
|
* @returns {void}
|
|
7605
|
-
* @throws {Error} when `for` names no element in the document at the render
|
|
7617
|
+
* @throws {Error} when `for` is given and names no element in the document at the render
|
|
7606
7618
|
*/
|
|
7607
7619
|
render() {
|
|
7608
7620
|
const named = this.declared('for');
|
|
7609
7621
|
const invoker = named ? document.getElementById(named) : null;
|
|
7610
|
-
if (!invoker) {
|
|
7622
|
+
if (named && !invoker) {
|
|
7611
7623
|
throw new Error(
|
|
7612
|
-
`ful-menu names no invoker: for="${named
|
|
7624
|
+
`ful-menu names no invoker: for="${named}" must name an element already in the page when the menu upgrades`,
|
|
7613
7625
|
);
|
|
7614
7626
|
}
|
|
7615
7627
|
this.setAttribute('role', 'menu');
|
|
7616
7628
|
if (!this.hasAttribute('popover')) {
|
|
7617
7629
|
this.setAttribute('popover', '');
|
|
7618
7630
|
}
|
|
7619
|
-
invoker
|
|
7620
|
-
|
|
7621
|
-
|
|
7631
|
+
if (invoker) {
|
|
7632
|
+
this.#invoker = invoker;
|
|
7633
|
+
invoker.setAttribute('aria-haspopup', 'menu');
|
|
7634
|
+
Anchors.wire(invoker, this, { prefix: 'ful-menu', invoke: true, expanded: true });
|
|
7635
|
+
} else {
|
|
7636
|
+
this.#wireShared();
|
|
7637
|
+
}
|
|
7638
|
+
wireMenuKeys(() => this.#invoker, this, { items: () => this.items });
|
|
7622
7639
|
this.#mark();
|
|
7623
7640
|
this.addEventListener('click', (evt) => {
|
|
7624
7641
|
const target = /** @type HTMLElement */ (evt.target);
|
|
@@ -7627,6 +7644,43 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
7627
7644
|
}
|
|
7628
7645
|
});
|
|
7629
7646
|
}
|
|
7647
|
+
/**
|
|
7648
|
+
* Opens a shared menu, one without `for`, beside `invoker`, or moves it
|
|
7649
|
+
* there when it is open for another one. The menu goes below the invoker,
|
|
7650
|
+
* or above it where there is no room below, and is placed once, as
|
|
7651
|
+
* `Anchors.show` places it. The invoker gets `aria-haspopup="menu"` and an
|
|
7652
|
+
* `aria-expanded` that reads true until the menu closes, and the focus
|
|
7653
|
+
* goes back to it on Escape. A call for the invoker whose press has just
|
|
7654
|
+
* closed the menu does nothing, so a second click on the same button
|
|
7655
|
+
* closes the menu rather than opening it again.
|
|
7656
|
+
* @param {HTMLElement} invoker the element the menu opens for
|
|
7657
|
+
* @returns {void}
|
|
7658
|
+
* @throws {Error} when the menu names its invoker through `for`
|
|
7659
|
+
*/
|
|
7660
|
+
showFor(invoker) {
|
|
7661
|
+
if (this.declared('for')) {
|
|
7662
|
+
throw new Error('ful-menu: showFor serves a menu without for; a menu with for is opened by its invoker');
|
|
7663
|
+
}
|
|
7664
|
+
const pressed = this.#pressed;
|
|
7665
|
+
this.#pressed = null;
|
|
7666
|
+
if (pressed === invoker) {
|
|
7667
|
+
return;
|
|
7668
|
+
}
|
|
7669
|
+
if (this.#invoker && this.#invoker !== invoker) {
|
|
7670
|
+
this.#invoker.setAttribute('aria-expanded', 'false');
|
|
7671
|
+
}
|
|
7672
|
+
this.#invoker = invoker;
|
|
7673
|
+
invoker.setAttribute('aria-haspopup', 'menu');
|
|
7674
|
+
invoker.setAttribute('aria-expanded', 'true');
|
|
7675
|
+
//the previous placement wrote margin: 0 inline, hiding the stylesheet's gap
|
|
7676
|
+
this.style.margin = '';
|
|
7677
|
+
const gap = Number.parseFloat(getComputedStyle(this).marginBlockStart) || 0;
|
|
7678
|
+
const moving = this.matches(':popover-open');
|
|
7679
|
+
Anchors.show(this, invoker, { flip: true, gap });
|
|
7680
|
+
if (moving) {
|
|
7681
|
+
this.items[0]?.focus();
|
|
7682
|
+
}
|
|
7683
|
+
}
|
|
7630
7684
|
/**
|
|
7631
7685
|
* The commands, in the order the arrows walk them: the menu's direct
|
|
7632
7686
|
* `button` and `a[href]` children, minus those carrying a `disabled` or
|
|
@@ -7638,6 +7692,21 @@ var ful = (function (exports, index_mjs, index_mjs$1) {
|
|
|
7638
7692
|
get items() {
|
|
7639
7693
|
return this.#mark().filter((item) => !item.hasAttribute('disabled') && !item.hasAttribute('hidden'));
|
|
7640
7694
|
}
|
|
7695
|
+
#wireShared() {
|
|
7696
|
+
document.addEventListener(
|
|
7697
|
+
'pointerdown',
|
|
7698
|
+
(evt) => {
|
|
7699
|
+
const target = /** @type Node */ (evt.target);
|
|
7700
|
+
this.#pressed = this.matches(':popover-open') && this.#invoker?.contains(target) ? this.#invoker : null;
|
|
7701
|
+
},
|
|
7702
|
+
true,
|
|
7703
|
+
);
|
|
7704
|
+
this.addEventListener('toggle', (/** @type any */ evt) => {
|
|
7705
|
+
if (evt.newState === 'closed') {
|
|
7706
|
+
this.#invoker?.setAttribute('aria-expanded', 'false');
|
|
7707
|
+
}
|
|
7708
|
+
});
|
|
7709
|
+
}
|
|
7641
7710
|
/** @returns {HTMLElement[]} every item, disabled and hidden ones included, once marked */
|
|
7642
7711
|
#mark() {
|
|
7643
7712
|
const all = /** @type HTMLElement[] */ ([...this.querySelectorAll(':scope > button, :scope > a[href]')]);
|