@optionfactory/fml 9.0.0-rc26 → 9.0.0-rc27
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/fml.css +1 -1
- package/dist/fml.css.map +1 -1
- package/dist/fml.iife.js +90 -1
- 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 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +6 -0
- package/dist/ful.iife.js +90 -1
- 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 -1
- package/dist/ful.mjs.map +1 -1
- package/dist/web-types.json +1 -1
- package/package.json +1 -1
package/dist/fml.iife.js
CHANGED
|
@@ -14188,15 +14188,25 @@ var fml = (function (exports) {
|
|
|
14188
14188
|
* on the host, bubbling, with detail `{ name: null, section, index, first }`,
|
|
14189
14189
|
* and awaits the answers registered through `AsyncEvents.asyncOn`, so a panel
|
|
14190
14190
|
* can deliver itself asynchronously: see `SectionRequests`.
|
|
14191
|
+
*
|
|
14192
|
+
* The tablist stays on one line. When the tabs do not fit it scrolls sideways,
|
|
14193
|
+
* and a previous and a next button appear at the side that has more tabs,
|
|
14194
|
+
* each bringing the next hidden tab into view. They stay out of the tab order:
|
|
14195
|
+
* the keyboard moves through the tabs with the arrow keys. The active tab is
|
|
14196
|
+
* kept in view when it changes and when the tablist changes width.
|
|
14191
14197
|
*/
|
|
14192
14198
|
class Tabs extends ParsedElement {
|
|
14193
14199
|
static slots = true;
|
|
14194
14200
|
static observed = ['active:number'];
|
|
14195
14201
|
static template = `
|
|
14202
|
+
<button type="button" class="ful-tabs-scroll" data-ref="scroll-start" tabindex="-1" hidden data-tpl-aria-label="#l10n:t('tabs.previous')"><ful-icon name="chevron-left" aria-hidden="true"></ful-icon></button>
|
|
14196
14203
|
<ful-tablist role="tablist">{{{{ slots.tabs }}}}</ful-tablist>
|
|
14204
|
+
<button type="button" class="ful-tabs-scroll" data-ref="scroll-end" tabindex="-1" hidden data-tpl-aria-label="#l10n:t('tabs.next')"><ful-icon name="chevron-right" aria-hidden="true"></ful-icon></button>
|
|
14197
14205
|
{{{{ slots.default }}}}
|
|
14198
14206
|
`;
|
|
14199
14207
|
#tablist;
|
|
14208
|
+
#scrollStart;
|
|
14209
|
+
#scrollEnd;
|
|
14200
14210
|
#tabs = [];
|
|
14201
14211
|
#panels = [];
|
|
14202
14212
|
#requests = new SectionRequests();
|
|
@@ -14211,8 +14221,11 @@ var fml = (function (exports) {
|
|
|
14211
14221
|
render({ slots }) {
|
|
14212
14222
|
const fragment = this.template().withOverlay({ slots }).render();
|
|
14213
14223
|
this.#tablist = fragment.querySelector('ful-tablist');
|
|
14224
|
+
this.#scrollStart = fragment.querySelector('[data-ref="scroll-start"]');
|
|
14225
|
+
this.#scrollEnd = fragment.querySelector('[data-ref="scroll-end"]');
|
|
14226
|
+
const chrome = [this.#tablist, this.#scrollStart, this.#scrollEnd];
|
|
14214
14227
|
const declared = [...this.#tablist.children];
|
|
14215
|
-
this.#panels = [...fragment.children].filter((el) => el
|
|
14228
|
+
this.#panels = [...fragment.children].filter((el) => !chrome.includes(el));
|
|
14216
14229
|
if (declared.length !== this.#panels.length) {
|
|
14217
14230
|
console.warn(
|
|
14218
14231
|
`ful-tabs: ${declared.length} tabs declared for ${this.#panels.length} panels, the surplus is left alone`,
|
|
@@ -14260,8 +14273,75 @@ var fml = (function (exports) {
|
|
|
14260
14273
|
this.active = target;
|
|
14261
14274
|
this.#tabs[target].focus();
|
|
14262
14275
|
});
|
|
14276
|
+
this.#scrollStart.addEventListener('click', () => this.#scrollByOneTab(-1));
|
|
14277
|
+
this.#scrollEnd.addEventListener('click', () => this.#scrollByOneTab(1));
|
|
14278
|
+
this.#tablist.addEventListener('scroll', () => this.#showScrollButtons(), { passive: true });
|
|
14279
|
+
let width = -1;
|
|
14280
|
+
const resizes = new ResizeObserver(() => {
|
|
14281
|
+
this.#showScrollButtons();
|
|
14282
|
+
if (this.#tablist.clientWidth !== width) {
|
|
14283
|
+
width = this.#tablist.clientWidth;
|
|
14284
|
+
this.#bringIntoView(this.#tabs[this.#active], 'auto');
|
|
14285
|
+
}
|
|
14286
|
+
});
|
|
14287
|
+
resizes.observe(this.#tablist);
|
|
14288
|
+
for (const tab of this.#tabs) {
|
|
14289
|
+
resizes.observe(tab);
|
|
14290
|
+
}
|
|
14263
14291
|
this.replaceChildren(fragment);
|
|
14264
14292
|
}
|
|
14293
|
+
/**
|
|
14294
|
+
* Shows each scroll button only when there are tabs beyond its side, and
|
|
14295
|
+
* sizes both to the height of the tablist above its border.
|
|
14296
|
+
* @returns {void}
|
|
14297
|
+
*/
|
|
14298
|
+
#showScrollButtons() {
|
|
14299
|
+
const list = this.#tablist;
|
|
14300
|
+
const overflow = list.scrollWidth - list.clientWidth;
|
|
14301
|
+
this.#scrollStart.hidden = list.scrollLeft <= 1;
|
|
14302
|
+
this.#scrollEnd.hidden = list.scrollLeft >= overflow - 1;
|
|
14303
|
+
this.#scrollStart.style.blockSize = this.#scrollEnd.style.blockSize = `${list.clientHeight}px`;
|
|
14304
|
+
}
|
|
14305
|
+
/**
|
|
14306
|
+
* The part of the tablist that no scroll button covers.
|
|
14307
|
+
* @returns {{ start: number, end: number }}
|
|
14308
|
+
*/
|
|
14309
|
+
#visibleRange() {
|
|
14310
|
+
const view = this.#tablist.getBoundingClientRect();
|
|
14311
|
+
return { start: view.left + this.#scrollStart.offsetWidth, end: view.right - this.#scrollEnd.offsetWidth };
|
|
14312
|
+
}
|
|
14313
|
+
/**
|
|
14314
|
+
* Scrolls the tablist so that the first tab cut by the side the direction
|
|
14315
|
+
* points to is wholly visible.
|
|
14316
|
+
* @param {1 | -1} direction 1 towards the end, -1 towards the start
|
|
14317
|
+
* @returns {void}
|
|
14318
|
+
*/
|
|
14319
|
+
#scrollByOneTab(direction) {
|
|
14320
|
+
const { start, end } = this.#visibleRange();
|
|
14321
|
+
const target =
|
|
14322
|
+
direction > 0
|
|
14323
|
+
? this.#tabs.find((tab) => tab.getBoundingClientRect().right > end + 1)
|
|
14324
|
+
: this.#tabs.findLast((tab) => tab.getBoundingClientRect().left < start - 1);
|
|
14325
|
+
this.#bringIntoView(target, matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth');
|
|
14326
|
+
}
|
|
14327
|
+
/**
|
|
14328
|
+
* Scrolls the tablist, and only the tablist, the least needed to show a tab
|
|
14329
|
+
* wholly.
|
|
14330
|
+
* @param {HTMLElement | undefined} tab
|
|
14331
|
+
* @param {ScrollBehavior} behavior
|
|
14332
|
+
* @returns {void}
|
|
14333
|
+
*/
|
|
14334
|
+
#bringIntoView(tab, behavior) {
|
|
14335
|
+
if (!tab) {
|
|
14336
|
+
return;
|
|
14337
|
+
}
|
|
14338
|
+
const { start, end } = this.#visibleRange();
|
|
14339
|
+
const box = tab.getBoundingClientRect();
|
|
14340
|
+
const delta = box.right > end ? Math.ceil(box.right - end) : box.left < start ? Math.floor(box.left - start) : 0;
|
|
14341
|
+
if (delta !== 0) {
|
|
14342
|
+
this.#tablist.scrollBy({ left: delta, behavior });
|
|
14343
|
+
}
|
|
14344
|
+
}
|
|
14265
14345
|
/**
|
|
14266
14346
|
* The index of the visible panel, reflected to the `active` attribute.
|
|
14267
14347
|
* Writing it clamps the value to the paired tabs, a value that is not a
|
|
@@ -14304,6 +14384,7 @@ var fml = (function (exports) {
|
|
|
14304
14384
|
}
|
|
14305
14385
|
this.#active = index;
|
|
14306
14386
|
this.reflectTo('active', index);
|
|
14387
|
+
this.#bringIntoView(this.#tabs[index], 'auto');
|
|
14307
14388
|
if (this.rendered && index !== previous) {
|
|
14308
14389
|
this.dispatchEvent(new CustomEvent('tabs:change', { detail: { active: index, previous } }));
|
|
14309
14390
|
}
|
|
@@ -14599,6 +14680,8 @@ var fml = (function (exports) {
|
|
|
14599
14680
|
'dialog.discard.cancel': 'Keep editing',
|
|
14600
14681
|
'drawer.close': 'Close',
|
|
14601
14682
|
'spinner.loading': 'Loading…',
|
|
14683
|
+
'tabs.previous': 'Previous tabs',
|
|
14684
|
+
'tabs.next': 'Next tabs',
|
|
14602
14685
|
'toast.region': 'Notifications',
|
|
14603
14686
|
'toast.dismiss': 'Dismiss',
|
|
14604
14687
|
'wizard.progress': 'Progress',
|
|
@@ -14648,6 +14731,8 @@ var fml = (function (exports) {
|
|
|
14648
14731
|
'dialog.discard.cancel': 'Continua a modificare',
|
|
14649
14732
|
'drawer.close': 'Chiudi',
|
|
14650
14733
|
'spinner.loading': 'Caricamento…',
|
|
14734
|
+
'tabs.previous': 'Schede precedenti',
|
|
14735
|
+
'tabs.next': 'Schede successive',
|
|
14651
14736
|
'toast.region': 'Notifiche',
|
|
14652
14737
|
'toast.dismiss': 'Chiudi',
|
|
14653
14738
|
'wizard.progress': 'Avanzamento',
|
|
@@ -14700,6 +14785,8 @@ var fml = (function (exports) {
|
|
|
14700
14785
|
'dialog.discard.cancel': 'Seguir editando',
|
|
14701
14786
|
'drawer.close': 'Cerrar',
|
|
14702
14787
|
'spinner.loading': 'Cargando…',
|
|
14788
|
+
'tabs.previous': 'Pestañas anteriores',
|
|
14789
|
+
'tabs.next': 'Pestañas siguientes',
|
|
14703
14790
|
'toast.region': 'Notificaciones',
|
|
14704
14791
|
'toast.dismiss': 'Cerrar',
|
|
14705
14792
|
'wizard.progress': 'Progreso',
|
|
@@ -14752,6 +14839,8 @@ var fml = (function (exports) {
|
|
|
14752
14839
|
'dialog.discard.cancel': 'Continuer à modifier',
|
|
14753
14840
|
'drawer.close': 'Fermer',
|
|
14754
14841
|
'spinner.loading': 'Chargement…',
|
|
14842
|
+
'tabs.previous': 'Onglets précédents',
|
|
14843
|
+
'tabs.next': 'Onglets suivants',
|
|
14755
14844
|
'toast.region': 'Notifications',
|
|
14756
14845
|
'toast.dismiss': 'Fermer',
|
|
14757
14846
|
'wizard.progress': 'Progression',
|