@optionfactory/fml 9.0.0-rc4 → 9.0.0-rc5

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/ful.mjs CHANGED
@@ -4850,15 +4850,37 @@ class Tooltip extends ParsedElement {
4850
4850
  }
4851
4851
  }
4852
4852
 
4853
- /** A modal dialog on the native platform, open()/ask() resolving with the closer's data-result. */
4853
+ /**
4854
+ * A modal dialog on the native platform, open()/ask() resolving with the
4855
+ * closer's data-result.
4856
+ *
4857
+ * The header carries a close button, as the drawer's does: Escape dismisses a
4858
+ * modal on its own, but nothing says so, and a dialog whose only exit is a key
4859
+ * you have to know about leaves a pointer with nowhere to go. It answers the way
4860
+ * Escape does, with null.
4861
+ *
4862
+ * `requires-answer` is for the dialog that must be answered: the close button is not
4863
+ * rendered and Escape is refused, so the only way out is a button that carries a
4864
+ * result. It has to be both, a close button withheld while Escape still worked
4865
+ * being decoration rather than a rule.
4866
+ *
4867
+ * The chrome is reachable by class as well as by tag, so a plain `<dialog
4868
+ * class="ful-dialog">` written by a page gets the same look whatever its
4869
+ * structure: the tag form matches a direct child, and `ful-dialog-header`,
4870
+ * `ful-dialog-body` and `ful-dialog-footer` match at any depth, which is what a
4871
+ * dialog whose content is wrapped in a form needs.
4872
+ */
4854
4873
  class Dialog extends ParsedElement {
4855
- static attributes = ['header'];
4874
+ static attributes = ['header', 'requires-answer:presence'];
4856
4875
  static slots = true;
4857
4876
  static template = `
4858
4877
  <dialog data-ref="dialog" class="ful-dialog">
4859
- <header data-tpl-if="header"><h2>{{ header }}</h2></header>
4860
- <div data-ref="body">{{{{ slots.default }}}}</div>
4861
- <footer>
4878
+ <header data-tpl-if="header || !requiresAnswer" class="ful-dialog-header">
4879
+ <h2 data-tpl-if="header">{{ header }}</h2>
4880
+ <button data-tpl-if="!requiresAnswer" type="button" data-ref="close" data-tpl-aria-label="#l10n:t('dialog.close')"><ful-icon name="x-lg" aria-hidden="true"></ful-icon></button>
4881
+ </header>
4882
+ <div data-ref="body" class="ful-dialog-body">{{{{ slots.default }}}}</div>
4883
+ <footer class="ful-dialog-footer">
4862
4884
  <button type="button" data-ref="acknowledge" data-result="acknowledged" data-tpl-if="!slots.buttons" data-tpl-aria-label="#l10n:t('dialog.acknowledge')">{{ #l10n:t('dialog.acknowledge') }}</button>
4863
4885
  {{{{ slots.buttons }}}}
4864
4886
  </footer>
@@ -4869,8 +4891,9 @@ class Dialog extends ParsedElement {
4869
4891
  #requests = new SectionRequests();
4870
4892
  #resolvers = [];
4871
4893
  render({ slots }) {
4894
+ const requiresAnswer = this.declared('requires-answer');
4872
4895
  const fragment = this.template()
4873
- .withOverlay({ slots, header: this.declared('header') ?? '' })
4896
+ .withOverlay({ slots, header: this.declared('header') ?? '', requiresAnswer })
4874
4897
  .render();
4875
4898
  this.#dialog = fragment.querySelector('[data-ref=dialog]');
4876
4899
  this.#body = fragment.querySelector('[data-ref=body]');
@@ -4888,6 +4911,17 @@ class Dialog extends ParsedElement {
4888
4911
  this.#dialog.close(result);
4889
4912
  }
4890
4913
  });
4914
+ //dismissal, not an answer: the waiters are settled with null, as Escape does.
4915
+ //Optional because a subclass overriding the template owns what it renders
4916
+ fragment
4917
+ .querySelector('[data-ref=close]')
4918
+ ?.addEventListener('click', () => this.#dialog.close(''));
4919
+ if (requiresAnswer) {
4920
+ //the platform's own dismissal, refused where the dialog must be
4921
+ //answered: cancel fires for Escape and for a close request the
4922
+ //browser makes on its own, and preventing it leaves the dialog open
4923
+ this.#dialog.addEventListener('cancel', (/** @type any */ e) => e.preventDefault());
4924
+ }
4891
4925
  this.replaceChildren(fragment);
4892
4926
  wireTargets();
4893
4927
  }
@@ -5476,6 +5510,7 @@ var en = {
5476
5510
  'filters.boolean.false': 'No',
5477
5511
  'info.tooltip': 'More information',
5478
5512
  'dialog.acknowledge': 'Got it',
5513
+ 'dialog.close': 'Close',
5479
5514
  'drawer.close': 'Close',
5480
5515
  'spinner.loading': 'Loading…',
5481
5516
  'toast.region': 'Notifications',
@@ -5517,6 +5552,7 @@ var it = {
5517
5552
  'filters.boolean.false': 'No',
5518
5553
  'info.tooltip': 'Maggiori informazioni',
5519
5554
  'dialog.acknowledge': 'Ho capito',
5555
+ 'dialog.close': 'Chiudi',
5520
5556
  'drawer.close': 'Chiudi',
5521
5557
  'spinner.loading': 'Caricamento…',
5522
5558
  'toast.region': 'Notifiche',
@@ -5558,6 +5594,7 @@ var es = {
5558
5594
  'filters.boolean.false': 'No',
5559
5595
  'info.tooltip': 'Más información',
5560
5596
  'dialog.acknowledge': 'Entendido',
5597
+ 'dialog.close': 'Cerrar',
5561
5598
  'drawer.close': 'Cerrar',
5562
5599
  'spinner.loading': 'Cargando…',
5563
5600
  'toast.region': 'Notificaciones',
@@ -5602,6 +5639,7 @@ var fr = {
5602
5639
  'filters.boolean.false': 'Non',
5603
5640
  'info.tooltip': 'Plus d’informations',
5604
5641
  'dialog.acknowledge': 'J’ai compris',
5642
+ 'dialog.close': 'Fermer',
5605
5643
  'drawer.close': 'Fermer',
5606
5644
  'spinner.loading': 'Chargement…',
5607
5645
  'toast.region': 'Notifications',