@lion/ui 0.15.1 → 0.15.2

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.
Files changed (109) hide show
  1. package/components/dialog/test/lion-dialog.integration.test.js +170 -0
  2. package/components/input-amount-dropdown/src/localizeNamespaceLoader.js +53 -0
  3. package/components/input-amount-dropdown/translations/bg.js +5 -0
  4. package/components/input-amount-dropdown/translations/cs.js +5 -0
  5. package/components/input-amount-dropdown/translations/de.js +5 -0
  6. package/components/input-amount-dropdown/translations/es.js +5 -0
  7. package/components/input-amount-dropdown/translations/fr.js +5 -0
  8. package/components/input-amount-dropdown/translations/hu.js +5 -0
  9. package/components/input-amount-dropdown/translations/id.js +5 -0
  10. package/components/input-amount-dropdown/translations/it.js +5 -0
  11. package/components/input-amount-dropdown/translations/nl.js +5 -0
  12. package/components/input-amount-dropdown/translations/pl.js +5 -0
  13. package/components/input-amount-dropdown/translations/ro.js +5 -0
  14. package/components/input-amount-dropdown/translations/ru.js +5 -0
  15. package/components/input-amount-dropdown/translations/sk.js +5 -0
  16. package/components/input-amount-dropdown/translations/uk.js +5 -0
  17. package/components/input-amount-dropdown/translations/zh.js +5 -0
  18. package/components/overlays/src/OverlayController.js +34 -7
  19. package/components/overlays/test/OverlayMixin.test.js +2 -2
  20. package/components/overlays/test-suites/OverlayMixin.suite.js +57 -0
  21. package/custom-elements.json +10 -0
  22. package/dist-types/components/dialog/test/lion-dialog.integration.test.d.ts +3 -0
  23. package/dist-types/components/dialog/test/lion-dialog.integration.test.d.ts.map +1 -0
  24. package/dist-types/components/input-amount-dropdown/src/localizeNamespaceLoader.d.ts +1 -1
  25. package/dist-types/components/input-amount-dropdown/src/localizeNamespaceLoader.d.ts.map +1 -1
  26. package/dist-types/components/input-amount-dropdown/translations/bg.d.ts +7 -0
  27. package/dist-types/components/input-amount-dropdown/translations/bg.d.ts.map +1 -0
  28. package/dist-types/components/input-amount-dropdown/translations/cs.d.ts +7 -0
  29. package/dist-types/components/input-amount-dropdown/translations/cs.d.ts.map +1 -0
  30. package/dist-types/components/input-amount-dropdown/translations/de.d.ts +7 -0
  31. package/dist-types/components/input-amount-dropdown/translations/de.d.ts.map +1 -0
  32. package/dist-types/components/input-amount-dropdown/translations/es.d.ts +7 -0
  33. package/dist-types/components/input-amount-dropdown/translations/es.d.ts.map +1 -0
  34. package/dist-types/components/input-amount-dropdown/translations/fr.d.ts +7 -0
  35. package/dist-types/components/input-amount-dropdown/translations/fr.d.ts.map +1 -0
  36. package/dist-types/components/input-amount-dropdown/translations/hu.d.ts +7 -0
  37. package/dist-types/components/input-amount-dropdown/translations/hu.d.ts.map +1 -0
  38. package/dist-types/components/input-amount-dropdown/translations/id.d.ts +7 -0
  39. package/dist-types/components/input-amount-dropdown/translations/id.d.ts.map +1 -0
  40. package/dist-types/components/input-amount-dropdown/translations/it.d.ts +7 -0
  41. package/dist-types/components/input-amount-dropdown/translations/it.d.ts.map +1 -0
  42. package/dist-types/components/input-amount-dropdown/translations/nl.d.ts +7 -0
  43. package/dist-types/components/input-amount-dropdown/translations/nl.d.ts.map +1 -0
  44. package/dist-types/components/input-amount-dropdown/translations/pl.d.ts +7 -0
  45. package/dist-types/components/input-amount-dropdown/translations/pl.d.ts.map +1 -0
  46. package/dist-types/components/input-amount-dropdown/translations/ro.d.ts +7 -0
  47. package/dist-types/components/input-amount-dropdown/translations/ro.d.ts.map +1 -0
  48. package/dist-types/components/input-amount-dropdown/translations/ru.d.ts +7 -0
  49. package/dist-types/components/input-amount-dropdown/translations/ru.d.ts.map +1 -0
  50. package/dist-types/components/input-amount-dropdown/translations/sk.d.ts +7 -0
  51. package/dist-types/components/input-amount-dropdown/translations/sk.d.ts.map +1 -0
  52. package/dist-types/components/input-amount-dropdown/translations/uk.d.ts +7 -0
  53. package/dist-types/components/input-amount-dropdown/translations/uk.d.ts.map +1 -0
  54. package/dist-types/components/input-amount-dropdown/translations/zh.d.ts +7 -0
  55. package/dist-types/components/input-amount-dropdown/translations/zh.d.ts.map +1 -0
  56. package/dist-types/components/overlays/src/OverlayController.d.ts +13 -4
  57. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  58. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
  59. package/dist-types/tsconfig.tsbuildinfo +1 -1
  60. package/docs/components/checkbox-group/overview.md +2 -2
  61. package/docs/components/collapsible/overview.md +1 -1
  62. package/docs/components/combobox/overview.md +1 -1
  63. package/docs/components/combobox/use-cases.md +1 -1
  64. package/docs/components/dialog/overview.md +1 -1
  65. package/docs/components/dialog/use-cases.md +2 -2
  66. package/docs/components/fieldset/overview.md +5 -5
  67. package/docs/components/form/overview.md +3 -3
  68. package/docs/components/form/use-cases.md +2 -2
  69. package/docs/components/icon/use-cases.md +1 -1
  70. package/docs/components/input/overview.md +1 -1
  71. package/docs/components/input-amount/overview.md +3 -3
  72. package/docs/components/input-date/overview.md +3 -3
  73. package/docs/components/input-datepicker/overview.md +5 -5
  74. package/docs/components/input-email/overview.md +2 -2
  75. package/docs/components/input-file/overview.md +1 -1
  76. package/docs/components/input-iban/overview.md +2 -2
  77. package/docs/components/input-range/overview.md +2 -2
  78. package/docs/components/input-stepper/overview.md +1 -1
  79. package/docs/components/input-tel/overview.md +1 -1
  80. package/docs/components/input-tel/use-cases.md +6 -6
  81. package/docs/components/input-tel-dropdown/overview.md +1 -1
  82. package/docs/components/listbox/use-cases.md +1 -1
  83. package/docs/components/radio-group/overview.md +3 -3
  84. package/docs/components/select/use-cases.md +1 -1
  85. package/docs/components/select-rich/use-cases.md +2 -2
  86. package/docs/components/tabs/examples.md +1 -1
  87. package/docs/fundamentals/index.md +4 -4
  88. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  89. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  90. package/docs/fundamentals/rationales/accessibility.md +1 -1
  91. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  92. package/docs/fundamentals/systems/core/overview.md +1 -1
  93. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  94. package/docs/fundamentals/systems/form/model-value.md +1 -1
  95. package/docs/fundamentals/systems/form/overview.md +28 -28
  96. package/docs/fundamentals/systems/form/validate.md +2 -2
  97. package/docs/fundamentals/systems/localize/overview.md +4 -4
  98. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  99. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  100. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  101. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  102. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  103. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  104. package/docs/guides/how-to/create-a-form.md +4 -4
  105. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  106. package/docs/guides/index.md +8 -8
  107. package/docs/guides/principles/index.md +5 -5
  108. package/docs/guides/principles/styling.md +1 -1
  109. package/package.json +1 -1
@@ -0,0 +1,170 @@
1
+ /* eslint-disable lit-a11y/no-autofocus */
2
+ import { expect, fixture as _fixture, html, waitUntil } from '@open-wc/testing';
3
+ import { sendKeys } from '@web/test-runner-commands';
4
+
5
+ import '@lion/ui/define/lion-button.js';
6
+ import '@lion/ui/define/lion-combobox.js';
7
+ import '@lion/ui/define/lion-select-rich.js';
8
+ import '@lion/ui/define/lion-option.js';
9
+ import '@lion/ui/define/lion-dialog.js';
10
+ import '@lion/ui/define/lion-tooltip.js';
11
+
12
+ import { mimicUserTyping } from '@lion/ui/combobox-test-helpers.js';
13
+ import sinon from 'sinon';
14
+
15
+ /**
16
+ * @typedef {import('../src/LionDialog.js').LionDialog} LionDialog
17
+ * @typedef {import('lit').TemplateResult} TemplateResult
18
+ */
19
+ const fixture = /** @type {(arg: TemplateResult) => Promise<LionDialog>} */ (_fixture);
20
+
21
+ const dropDownEntries = ['Apple', 'Banana'];
22
+
23
+ describe('lion-dialog', () => {
24
+ describe('lion-combobox integration', () => {
25
+ it('should close lion-combobox dropdown on Escape and should not close the parent lion-dialog', async () => {
26
+ const el = await fixture(html`
27
+ <lion-dialog has-close-button>
28
+ <lion-button slot="invoker">Open Dialog</lion-button>
29
+ <div slot="header">Combobox example</div>
30
+ <div slot="content">
31
+ <lion-combobox name="combo" label="Select a fruit">
32
+ ${dropDownEntries.map(
33
+ (/** @type { string } */ entry) =>
34
+ html` <lion-option .choiceValue="${entry}">${entry}</lion-option>`,
35
+ )}
36
+ </lion-combobox>
37
+ </div>
38
+ </lion-dialog>
39
+ `);
40
+ const dialogInvoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
41
+ dialogInvoker.click();
42
+ const combobox = /** @type {HTMLElement} */ el.querySelector('lion-combobox');
43
+ const isComboboxRendered = () => !!combobox?.shadowRoot?.childNodes.length;
44
+ await waitUntil(isComboboxRendered);
45
+ // @ts-ignore
46
+ await mimicUserTyping(combobox, 'a');
47
+ const firstOption = /** @type { HTMLElement | undefined } */ (
48
+ el.querySelectorAll('lion-option')?.[0]
49
+ );
50
+ // @ts-ignore
51
+ const isComboboxFirstOptionInDropdownVisible = () => firstOption?.checkVisibility();
52
+ await waitUntil(isComboboxFirstOptionInDropdownVisible);
53
+ const comboboxDialog = combobox?.shadowRoot?.querySelector('dialog');
54
+ // Note, do not remove `console.log` down below. There is a bug in test engine.
55
+ // Referring dialog.close from the test environement fixes the bug
56
+ console.log(sinon.spy(comboboxDialog?.close));
57
+ const comboboxInput = combobox?.querySelector('input');
58
+ comboboxInput?.focus();
59
+ const dropdownDialog = combobox?.shadowRoot?.querySelector('dialog');
60
+ // @ts-ignore
61
+ const dropdownDialogCloseSpy = sinon.spy(dropdownDialog, 'close');
62
+ await sendKeys({
63
+ press: 'Escape',
64
+ });
65
+ // @ts-ignore
66
+ const isDialogVisible = () => el?.shadowRoot?.querySelector('dialog')?.checkVisibility();
67
+ await waitUntil(() => dropdownDialogCloseSpy.called);
68
+ expect(isDialogVisible()).to.equal(true);
69
+ });
70
+ });
71
+
72
+ describe('lion-select-rich integration', () => {
73
+ it('should close lion-select-rich dropdown on Escape and should not close the parent lion-dialog', async () => {
74
+ const el = await fixture(html`
75
+ <lion-dialog has-close-button>
76
+ <lion-button slot="invoker">Open Dialog</lion-button>
77
+ <div slot="header">Select rich example</div>
78
+ <div slot="content">
79
+ <lion-select-rich label="Select a fruit">
80
+ ${dropDownEntries.map(
81
+ (/** @type { string } */ entry) =>
82
+ html` <lion-option .choiceValue="${entry}">${entry}</lion-option>`,
83
+ )}
84
+ </lion-select-rich>
85
+ </div>
86
+ </lion-dialog>
87
+ `);
88
+ const dialogInvoker = /** @type {HTMLElement} */ (el.querySelector('[slot="invoker"]'));
89
+ dialogInvoker.click();
90
+ const selectRichInvoker = /** @type {HTMLElement} */ (
91
+ el.querySelector('lion-select-invoker')
92
+ );
93
+ const isSelectRichInvokerRendered = () => !!selectRichInvoker?.shadowRoot?.childNodes.length;
94
+ await waitUntil(isSelectRichInvokerRendered);
95
+ const selectRich = el?.querySelector('lion-select-rich');
96
+ const selectRichDialog = selectRich?.shadowRoot?.querySelector('dialog');
97
+ // Note, do not remove `console.log` down below. There is a bug in test engine.
98
+ // Referring dialog.close from the test environement fixes the bug
99
+ console.log(selectRichDialog?.close);
100
+
101
+ selectRichInvoker?.click();
102
+ const dropdownDialog = el
103
+ ?.querySelector('lion-select-rich')
104
+ ?.shadowRoot?.querySelector('dialog');
105
+ // @ts-ignore
106
+ const dropdownDialogCloseSpy = sinon.spy(dropdownDialog, 'close');
107
+ const isDropdownVisible = () =>
108
+ el
109
+ ?.querySelector('lion-select-rich')
110
+ ?.shadowRoot?.querySelector('dialog')
111
+ // @ts-ignore
112
+ ?.checkVisibility();
113
+ await waitUntil(isDropdownVisible);
114
+ const lionOptions = /** @type {HTMLElement} */ (el.querySelector('lion-options'));
115
+ lionOptions?.focus();
116
+ await sendKeys({
117
+ press: 'Escape',
118
+ });
119
+ // @ts-ignore
120
+ const isDialogVisible = () => el?.shadowRoot?.querySelector('dialog')?.checkVisibility();
121
+ await waitUntil(() => dropdownDialogCloseSpy.called);
122
+ expect(isDialogVisible()).to.equal(true);
123
+ });
124
+ });
125
+
126
+ describe('lion-tooltip integration', () => {
127
+ it('should close lion-tooltip on first Escape and should close the parent lion-dialog on the second Escape', async () => {
128
+ const el = await fixture(html`
129
+ <lion-dialog has-close-button>
130
+ <lion-button slot="invoker" class="dialog-invoker">Open Dialog</lion-button>
131
+ <div slot="header">Tooltip example</div>
132
+ <div slot="content">
133
+ <lion-tooltip has-arrow>
134
+ <button slot="invoker" class="demo-tooltip-invoker">Focus on me</button>
135
+ <div slot="content">This is a tooltip</div>
136
+ </lion-tooltip>
137
+ </div>
138
+ </lion-dialog>
139
+ `);
140
+
141
+ await el.updateComplete;
142
+ const dialogInvoker = /** @type {HTMLElement} */ (el.querySelector('.dialog-invoker'));
143
+ dialogInvoker.click();
144
+ const tooltip = /** @type {HTMLElement} */ el.querySelector('lion-tooltip');
145
+ const isTooltipRendered = () => !!tooltip?.shadowRoot?.childNodes.length;
146
+ await waitUntil(isTooltipRendered);
147
+ const tooltipButton = /** @type {HTMLElement} */ (el.querySelector('.demo-tooltip-invoker'));
148
+ tooltipButton?.focus();
149
+ const getTooltipContent = () =>
150
+ el
151
+ .querySelector('lion-tooltip')
152
+ ?.shadowRoot?.querySelector('#overlay-content-node-wrapper');
153
+ // @ts-ignore
154
+ const isTooltipContentVisible = () => getTooltipContent()?.checkVisibility();
155
+ await waitUntil(isTooltipContentVisible);
156
+ await sendKeys({
157
+ press: 'Escape',
158
+ });
159
+ // @ts-ignore
160
+ const isDialogVisible = () => el?.shadowRoot?.querySelector('dialog')?.checkVisibility();
161
+ expect(isTooltipContentVisible()).to.equal(false);
162
+ expect(isDialogVisible()).to.equal(true);
163
+ await sendKeys({
164
+ press: 'Escape',
165
+ });
166
+ expect(isTooltipContentVisible()).to.equal(false);
167
+ expect(isDialogVisible()).to.equal(false);
168
+ });
169
+ });
170
+ });
@@ -1,6 +1,59 @@
1
1
  /* eslint-disable import/no-extraneous-dependencies */
2
2
  export const localizeNamespaceLoader = /** @param {string} locale */ locale => {
3
3
  switch (locale) {
4
+ case 'bg-BG':
5
+ case 'bg':
6
+ return import('@lion/ui/input-amount-dropdown-translations/bg.js');
7
+ case 'cs-CZ':
8
+ case 'cs':
9
+ return import('@lion/ui/input-amount-dropdown-translations/cs.js');
10
+ case 'de-DE':
11
+ case 'de':
12
+ return import('@lion/ui/input-amount-dropdown-translations/de.js');
13
+ case 'en-AU':
14
+ case 'en-GB':
15
+ case 'en-US':
16
+ case 'en-PH':
17
+ case 'en':
18
+ return import('@lion/ui/input-amount-dropdown-translations/en.js');
19
+ case 'es-ES':
20
+ case 'es':
21
+ return import('@lion/ui/input-amount-dropdown-translations/es.js');
22
+ case 'fr-FR':
23
+ case 'fr-BE':
24
+ case 'fr':
25
+ return import('@lion/ui/input-amount-dropdown-translations/fr.js');
26
+ case 'hu-HU':
27
+ case 'hu':
28
+ return import('@lion/ui/input-amount-dropdown-translations/hu.js');
29
+ case 'id-ID':
30
+ case 'id':
31
+ return import('@lion/ui/input-amount-dropdown-translations/id.js');
32
+ case 'it-IT':
33
+ case 'it':
34
+ return import('@lion/ui/input-amount-dropdown-translations/it.js');
35
+ case 'nl-BE':
36
+ case 'nl-NL':
37
+ case 'nl':
38
+ return import('@lion/ui/input-amount-dropdown-translations/nl.js');
39
+ case 'pl-PL':
40
+ case 'pl':
41
+ return import('@lion/ui/input-amount-dropdown-translations/pl.js');
42
+ case 'ro-RO':
43
+ case 'ro':
44
+ return import('@lion/ui/input-amount-dropdown-translations/ro.js');
45
+ case 'ru-RU':
46
+ case 'ru':
47
+ return import('@lion/ui/input-amount-dropdown-translations/ru.js');
48
+ case 'sk-SK':
49
+ case 'sk':
50
+ return import('@lion/ui/input-amount-dropdown-translations/sk.js');
51
+ case 'uk-UA':
52
+ case 'uk':
53
+ return import('@lion/ui/input-amount-dropdown-translations/uk.js');
54
+ case 'zh-CN':
55
+ case 'zh':
56
+ return import('@lion/ui/input-amount-dropdown-translations/zh.js');
4
57
  default:
5
58
  return import('@lion/ui/input-amount-dropdown-translations/en.js');
6
59
  }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Всички валути',
3
+ selectCurrency: 'Избор на валута',
4
+ suggestedCurrencies: 'Предпочитани валути',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Všechny měny',
3
+ selectCurrency: 'Vybrat měnu',
4
+ suggestedCurrencies: 'Preferované měny',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Alle Währungen',
3
+ selectCurrency: 'Währung auswählen',
4
+ suggestedCurrencies: 'Bevorzugte Währungen',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Todas las divisas',
3
+ selectCurrency: 'Seleccione divisa',
4
+ suggestedCurrencies: 'Divisas preferidas',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Toutes les devises',
3
+ selectCurrency: 'Sélectionner une devise',
4
+ suggestedCurrencies: 'Devises préférées',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Minden pénznem',
3
+ selectCurrency: 'Pénznem kiválasztása',
4
+ suggestedCurrencies: 'Előnyben részesített pénznemek',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Semua mata uang',
3
+ selectCurrency: 'Pilih mata uang',
4
+ suggestedCurrencies: 'Mata uang pilihan',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Tutte le valute',
3
+ selectCurrency: 'Seleziona valuta',
4
+ suggestedCurrencies: 'Valute preferite',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: "Alle valuta's",
3
+ selectCurrency: 'Selecteer valuta',
4
+ suggestedCurrencies: "Voorkeurs valuta's",
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Wszystkie waluty',
3
+ selectCurrency: 'Wybierz walutę',
4
+ suggestedCurrencies: 'Preferowane waluty',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Toate valutele',
3
+ selectCurrency: 'Selectare valută',
4
+ suggestedCurrencies: 'Valute preferate',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Все валюты',
3
+ selectCurrency: 'Выбрать валюту',
4
+ suggestedCurrencies: 'Предпочтительные валюты',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Všetky meny',
3
+ selectCurrency: 'Zvoliť menu',
4
+ suggestedCurrencies: 'Uprednostňované meny',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: 'Усі валюти',
3
+ selectCurrency: 'Вибрати валюту',
4
+ suggestedCurrencies: 'Обрані валюти',
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ allCurrencies: '所有货币',
3
+ selectCurrency: '选择货币',
4
+ suggestedCurrencies: '首选货币',
5
+ };
@@ -197,15 +197,24 @@ export class OverlayController extends EventTarget {
197
197
  this._contentId = `overlay-content--${Math.random().toString(36).slice(2, 10)}`;
198
198
  /** @private */
199
199
  this.__originalAttrs = new Map();
200
+ /** @private */
201
+ this.__escKeyHandler = this.__escKeyHandler.bind(this);
200
202
  this.updateConfig(config);
201
203
  /** @private */
202
204
  this.__hasActiveTrapsKeyboardFocus = false;
203
205
  /** @private */
204
206
  this.__hasActiveBackdrop = true;
205
207
  /** @private */
206
- this.__escKeyHandler = this.__escKeyHandler.bind(this);
207
- /** @private */
208
208
  this.__cancelHandler = this.__cancelHandler.bind(this);
209
+ /**
210
+ * The property is used to skip `__escKeyHandler` handler for overlays that have been closed
211
+ * by `__escKeyHandlerCalled` previously.
212
+ * `__escKeyHandlerCalled` is set to `false` right before overlay show up
213
+ * `__escKeyHandlerCalled` is set to `true` when `__escKeyHandler` is called at least one time
214
+ * after each 'show' phase
215
+ * @private
216
+ */
217
+ this.__escKeyHandlerCalled = false;
209
218
  }
210
219
 
211
220
  /**
@@ -1211,13 +1220,21 @@ export class OverlayController extends EventTarget {
1211
1220
  * @returns {void}
1212
1221
  */
1213
1222
  __escKeyHandler(event) {
1214
- if (event.key !== 'Escape' || childDialogsClosedInEventLoopWeakmap.has(event)) return;
1223
+ if (
1224
+ event.key !== 'Escape' ||
1225
+ childDialogsClosedInEventLoopWeakmap.has(event) ||
1226
+ (!this.isShown && this.__escKeyHandlerCalled)
1227
+ ) {
1228
+ return;
1229
+ }
1215
1230
 
1216
1231
  const hasPressedInside =
1217
1232
  event.composedPath().includes(this.contentNode) ||
1233
+ (this.invokerNode && event.composedPath().includes(this.invokerNode)) ||
1218
1234
  deepContains(this.contentNode, /** @type {HTMLElement|ShadowRoot} */ (event.target));
1219
1235
 
1220
1236
  if (hasPressedInside) {
1237
+ this.__escKeyHandlerCalled = true;
1221
1238
  this.hide();
1222
1239
  // We could do event.stopPropagation() here, but we don't want to hide info for
1223
1240
  // the outside world about user interactions. Instead, we store the event in a WeakMap
@@ -1245,12 +1262,21 @@ export class OverlayController extends EventTarget {
1245
1262
  * @protected
1246
1263
  */
1247
1264
  _handleHidesOnEsc({ phase }) {
1248
- if (phase === 'show') {
1265
+ if (phase === 'init') {
1266
+ // we remove previously added (if any) event listener to guarantee
1267
+ // there is only one Escape handler added here.
1268
+ // Note `init` phase triggered on every `updateConfig` call and that
1269
+ // could happen multiple times during the component life cycle
1270
+ this.contentNode.removeEventListener('keyup', this.__escKeyHandler);
1249
1271
  this.contentNode.addEventListener('keyup', this.__escKeyHandler);
1250
1272
  if (this.invokerNode) {
1251
1273
  this.invokerNode.addEventListener('keyup', this.__escKeyHandler);
1252
1274
  }
1253
- } else if (phase === 'hide' || phase === 'teardown') {
1275
+ }
1276
+ if (phase === 'show') {
1277
+ this.__escKeyHandlerCalled = false;
1278
+ }
1279
+ if (phase === 'teardown') {
1254
1280
  this.contentNode.removeEventListener('keyup', this.__escKeyHandler);
1255
1281
  if (this.invokerNode) {
1256
1282
  this.invokerNode.removeEventListener('keyup', this.__escKeyHandler);
@@ -1263,9 +1289,10 @@ export class OverlayController extends EventTarget {
1263
1289
  * @protected
1264
1290
  */
1265
1291
  _handleHidesOnOutsideEsc({ phase }) {
1266
- if (phase === 'show') {
1292
+ if (phase === 'init') {
1293
+ document.removeEventListener('keyup', this.#outsideEscKeyHandler);
1267
1294
  document.addEventListener('keyup', this.#outsideEscKeyHandler);
1268
- } else if (phase === 'hide' || phase === 'teardown') {
1295
+ } else if (phase === 'teardown') {
1269
1296
  document.removeEventListener('keyup', this.#outsideEscKeyHandler);
1270
1297
  }
1271
1298
  }
@@ -7,9 +7,9 @@ const tagString = defineCE(
7
7
  class extends OverlayMixin(LitElement) {
8
8
  render() {
9
9
  return html`
10
- <button slot="invoker">invoker button</button>
10
+ <slot name="invoker"></slot>
11
11
  <div id="overlay-content-node-wrapper">
12
- <div slot="content">content of the overlay</div>
12
+ <slot name="content"></slot>
13
13
  </div>
14
14
  `;
15
15
  }
@@ -111,6 +111,63 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
111
111
  expect(el.opened).to.be.false;
112
112
  });
113
113
 
114
+ /**
115
+ * In case OverlayMixin has a handler for Escape which sets `opened` to `false`,
116
+ * make sure it does not conflict with the Escape handler in OverlayController.
117
+ * */
118
+ it('syncs opened between overlayController and OverlayMixin on Escape', async () => {
119
+ const config = { hidesOnEsc: true };
120
+ const el = /** @type {OverlayEl} */ (
121
+ await fixture(html`
122
+ <${tag} id="main-dialog" .config="${config}">
123
+ <div slot="content" id="mainContent">
124
+ open nested overlay:
125
+ <${tag} id="sub-dialog" .config="${config}">
126
+ <div slot="content" id="nestedContent">
127
+ <input id="nestedContentInput">
128
+ </div>
129
+ <button slot="invoker" id="nestedInvoker">nested invoker button</button>
130
+ </${tag}>
131
+ </div>
132
+ <button slot="invoker" id="mainInvoker">invoker button</button>
133
+ </${tag}>
134
+ `)
135
+ );
136
+ await el.updateComplete;
137
+ const subDialog = /** @type {OverlayEl} */ (el.querySelector('#sub-dialog'));
138
+ const nestedContentInput = /** @type {OverlayEl} */ (el.querySelector('#nestedContentInput'));
139
+
140
+ // Note, OverlayController has Escape key listener added to "#nestedContent".
141
+ // And the sub-dialog adds the Escape key listener to "#nestedContentInput" which is a child evelement of "#nestedContent"
142
+ // In this case when "#nestedContentInput" is focused and Escape is pressed, the listener of "#nestedContentInput"
143
+ // is always called before the listener set for "#nestedContent" inside OverlayController.
144
+ // This way we check the scenario when OverlayController's `hide()` is called first from
145
+ // The OverlayMixin and it does not prevent OverlayController `hidesOnEsc` handler from being called
146
+ nestedContentInput?.addEventListener('keyup', (/** @type {* & KeyboardEvent} */ event) => {
147
+ if (event.key === 'Escape') {
148
+ subDialog.opened = false;
149
+ }
150
+ });
151
+
152
+ el.opened = true;
153
+ await el.updateComplete;
154
+ await el._overlayCtrl._showComplete;
155
+ expect(el.opened).to.be.true;
156
+ expect(el._overlayCtrl.isShown).to.be.true;
157
+
158
+ subDialog.opened = true;
159
+ await subDialog.updateComplete;
160
+ await subDialog._overlayCtrl._showComplete;
161
+ expect(subDialog.opened).to.be.true;
162
+ expect(subDialog._overlayCtrl.isShown).to.be.true;
163
+
164
+ await mimicEscapePress(nestedContentInput);
165
+ expect(subDialog.opened).to.be.false;
166
+ expect(subDialog._overlayCtrl.isShown).to.be.false;
167
+ expect(el.opened).to.be.true;
168
+ expect(el._overlayCtrl.isShown).to.be.true;
169
+ });
170
+
114
171
  // TODO: put this tests in OverlayController.test.js instead?
115
172
  it('does not change the body size when opened', async () => {
116
173
  const parentNode = document.createElement('div');
@@ -123690,6 +123690,16 @@
123690
123690
  },
123691
123691
  "privacy": "private"
123692
123692
  },
123693
+ {
123694
+ "kind": "field",
123695
+ "name": "__escKeyHandlerCalled",
123696
+ "type": {
123697
+ "text": "boolean"
123698
+ },
123699
+ "description": "The property is used to skip `__escKeyHandler` handler for overlays that have been closed\nby `__escKeyHandlerCalled` previously.\n`__escKeyHandlerCalled` is set to `false` right before overlay show up\n`__escKeyHandlerCalled` is set to `true` when `__escKeyHandler` is called at least one time\nafter each 'show' phase",
123700
+ "privacy": "private",
123701
+ "default": "false"
123702
+ },
123693
123703
  {
123694
123704
  "kind": "field",
123695
123705
  "name": "__eventListeners",
@@ -0,0 +1,3 @@
1
+ export type LionDialog = import('../src/LionDialog.js').LionDialog;
2
+ export type TemplateResult = import('lit').TemplateResult;
3
+ //# sourceMappingURL=lion-dialog.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lion-dialog.integration.test.d.ts","sourceRoot":"","sources":["../../../../components/dialog/test/lion-dialog.integration.test.js"],"names":[],"mappings":"yBAea,OAAO,sBAAsB,EAAE,UAAU;6BACzC,OAAO,KAAK,EAAE,cAAc"}
@@ -1,2 +1,2 @@
1
- export function localizeNamespaceLoader(locale: string): Promise<typeof import("../translations/en.js")>;
1
+ export function localizeNamespaceLoader(locale: string): Promise<typeof import("../translations/bg.js")>;
2
2
  //# sourceMappingURL=localizeNamespaceLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"localizeNamespaceLoader.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/src/localizeNamespaceLoader.js"],"names":[],"mappings":"AACO,gDAA4C,MAAM,mDAKxD"}
1
+ {"version":3,"file":"localizeNamespaceLoader.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/src/localizeNamespaceLoader.js"],"names":[],"mappings":"AACO,gDAA4C,MAAM,mDA0DxD"}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=bg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bg.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/bg.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=cs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cs.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/cs.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=de.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"de.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/de.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=es.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/es.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=fr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/fr.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=hu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hu.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/hu.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/id.js"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ declare namespace _default {
2
+ const allCurrencies: string;
3
+ const selectCurrency: string;
4
+ const suggestedCurrencies: string;
5
+ }
6
+ export default _default;
7
+ //# sourceMappingURL=it.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"it.d.ts","sourceRoot":"","sources":["../../../../components/input-amount-dropdown/translations/it.js"],"names":[],"mappings":""}