@lion/ui 0.9.0 → 0.10.0
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/components/combobox/src/LionCombobox.js +6 -2
- package/components/combobox/test/lion-combobox.test.js +58 -3
- package/components/core/test/ScopedElementsMixin.test.js +3 -3
- package/components/dialog/test/lion-dialog.test.js +54 -0
- package/components/dialog/test-helpers/test-router.js +43 -0
- package/components/form-core/src/FormatMixin.js +66 -18
- package/components/form-core/test-suites/FormatMixin.suite.js +107 -8
- package/components/form-core/types/FormatMixinTypes.ts +4 -1
- package/components/form-integrations/test/dialog-integrations.test.js +6 -2
- package/components/form-integrations/test/form-integrations.test.js +2 -2
- package/components/input-amount/src/parsers.js +3 -3
- package/components/input-amount/test/lion-input-amount.test.js +36 -2
- package/components/input-amount/test/parsers.test.js +11 -0
- package/components/input-datepicker/translations/es.js +1 -1
- package/components/input-stepper/src/LionInputStepper.js +70 -42
- package/components/input-stepper/test/lion-input-stepper.test.js +48 -12
- package/components/input-tel-dropdown/src/LionInputTelDropdown.js +7 -6
- package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +50 -0
- package/components/localize/src/number/getDecimalSeparator.js +1 -1
- package/components/localize/src/number/parseNumber.js +9 -6
- package/components/localize/test/number/parseNumber.test.js +11 -0
- package/components/localize/types/LocalizeMixinTypes.ts +3 -3
- package/components/overlays/src/OverlayController.js +4 -5
- package/components/overlays/src/OverlayMixin.js +20 -14
- package/components/overlays/test/OverlayController.test.js +11 -8
- package/components/overlays/test-suites/OverlayMixin.suite.js +184 -9
- package/components/overlays/types/ArrowMixinTypes.ts +11 -2
- package/components/overlays/types/OverlayConfig.ts +15 -13
- package/components/select-rich/src/LionSelectRich.js +3 -1
- package/components/select-rich/test/lion-select-rich.test.js +44 -0
- package/custom-elements.json +1337 -115
- package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
- package/dist-types/components/dialog/test/lion-dialog.test.d.ts.map +1 -1
- package/dist-types/components/dialog/test-helpers/test-router.d.ts +2 -0
- package/dist-types/components/dialog/test-helpers/test-router.d.ts.map +1 -0
- package/dist-types/components/form-core/src/FormatMixin.d.ts +1 -1
- package/dist-types/components/form-core/src/FormatMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/types/FormatMixinTypes.d.ts +3 -2
- package/dist-types/components/form-core/types/FormatMixinTypes.d.ts.map +1 -1
- package/dist-types/components/form-integrations/test/dialog-integrations.test.d.ts.map +1 -1
- package/dist-types/components/input-amount/src/parsers.d.ts +2 -2
- package/dist-types/components/input-amount/src/parsers.d.ts.map +1 -1
- package/dist-types/components/input-amount/test/lion-input-amount.test.d.ts.map +1 -1
- package/dist-types/components/input-stepper/src/LionInputStepper.d.ts +22 -24
- package/dist-types/components/input-stepper/src/LionInputStepper.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/test/LionInputTelDropdown.test.d.ts.map +1 -1
- package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
- package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts +3 -2
- package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts +4 -4
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
- package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts +2 -2
- package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayConfig.d.ts +4 -4
- package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/api-table.md +2 -2
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/api-table.md +1 -0
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/api-table.md +1 -0
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/form/use-cases.md +2 -2
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/api-table.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/api-table.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/api-table.md +1 -1
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/api-table.md +2 -1
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/api-table.md +1 -1
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/api-table.md +1 -1
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/api-table.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/api-table.md +1 -1
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/api-table.md +4 -4
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/api-table.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/api-table.md +1 -1
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/api-table.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/api-table.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/api-table.md +1 -1
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/api-table.md +1 -0
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/switch/api-table.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/textarea/api-table.md +1 -1
- package/docs/components/tooltip/api-table.md +1 -0
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +5 -5
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/rationales/accessibility.md +1 -1
- package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/api-table.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +2 -2
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/create-a-form.md +4 -4
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,8 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
#hasSetup = false;
|
|
28
|
+
|
|
27
29
|
constructor() {
|
|
28
30
|
super();
|
|
29
31
|
/**
|
|
@@ -173,22 +175,23 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
*/
|
|
179
|
-
firstUpdated(changedProperties) {
|
|
180
|
-
super.firstUpdated(changedProperties);
|
|
178
|
+
connectedCallback() {
|
|
179
|
+
super.connectedCallback();
|
|
181
180
|
|
|
182
|
-
this.
|
|
181
|
+
this.updateComplete.then(() => {
|
|
182
|
+
if (this.#hasSetup) return;
|
|
183
|
+
this._setupOverlayCtrl();
|
|
184
|
+
this.#hasSetup = true;
|
|
185
|
+
});
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
async disconnectedCallback() {
|
|
186
189
|
super.disconnectedCallback();
|
|
187
190
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
191
|
+
if (await this._isPermanentlyDisconnected()) {
|
|
192
|
+
this._teardownOverlayCtrl();
|
|
193
|
+
this.#hasSetup = false;
|
|
194
|
+
}
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
/**
|
|
@@ -238,6 +241,8 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
238
241
|
|
|
239
242
|
/** @protected */
|
|
240
243
|
_setupOverlayCtrl() {
|
|
244
|
+
if (this._overlayCtrl) return;
|
|
245
|
+
|
|
241
246
|
/** @type {OverlayController} */
|
|
242
247
|
this._overlayCtrl = this._defineOverlay({
|
|
243
248
|
contentNode: this._overlayContentNode,
|
|
@@ -253,11 +258,12 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
253
258
|
|
|
254
259
|
/** @protected */
|
|
255
260
|
_teardownOverlayCtrl() {
|
|
261
|
+
if (!this._overlayCtrl) return;
|
|
262
|
+
|
|
256
263
|
this._teardownOpenCloseListeners();
|
|
257
264
|
this.__teardownSyncFromOverlayController();
|
|
258
265
|
|
|
259
|
-
/** @type {OverlayController} */
|
|
260
|
-
(this._overlayCtrl).teardown();
|
|
266
|
+
/** @type {OverlayController} */ (this._overlayCtrl).teardown();
|
|
261
267
|
}
|
|
262
268
|
|
|
263
269
|
/**
|
|
@@ -396,9 +402,9 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
396
402
|
* Before we decide to teardown, let's wait to see if we were not just moving nodes around.
|
|
397
403
|
* @return {Promise<boolean>}
|
|
398
404
|
*/
|
|
399
|
-
async
|
|
405
|
+
async _isPermanentlyDisconnected() {
|
|
400
406
|
await this.updateComplete;
|
|
401
|
-
return this.isConnected;
|
|
407
|
+
return !this.isConnected;
|
|
402
408
|
}
|
|
403
409
|
};
|
|
404
410
|
export const OverlayMixin = dedupeMixin(OverlayMixinImplementation);
|
|
@@ -103,12 +103,12 @@ const withLocalTestConfig = () =>
|
|
|
103
103
|
async function createNestedEscControllers(parentContent) {
|
|
104
104
|
const childContent = /** @type {HTMLDivElement} */ (parentContent.querySelector('div[id]'));
|
|
105
105
|
// Assert valid fixure
|
|
106
|
-
const
|
|
107
|
-
(parentContent.id
|
|
108
|
-
parentContent.id
|
|
109
|
-
(childContent.id
|
|
110
|
-
childContent.id
|
|
111
|
-
if (!
|
|
106
|
+
const isValidFixture =
|
|
107
|
+
(parentContent.id.startsWith('parent-overlay--hidesOnEsc') ||
|
|
108
|
+
parentContent.id.startsWith('parent-overlay--hidesOnOutsideEsc')) &&
|
|
109
|
+
(childContent.id.startsWith('child-overlay--hidesOnEsc') ||
|
|
110
|
+
childContent.id.startsWith('child-overlay--hidesOnOutsideEsc'));
|
|
111
|
+
if (!isValidFixture) {
|
|
112
112
|
throw new Error('Provide a valid fixture');
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -117,8 +117,8 @@ async function createNestedEscControllers(parentContent) {
|
|
|
117
117
|
shadowRootParent.appendChild(childContent);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
const parentHasOutsideOnEsc = parentContent.id
|
|
121
|
-
const childHasOutsideOnEsc = childContent.id
|
|
120
|
+
const parentHasOutsideOnEsc = parentContent.id.startsWith('parent-overlay--hidesOnOutsideEsc');
|
|
121
|
+
const childHasOutsideOnEsc = childContent.id.startsWith('child-overlay--hidesOnOutsideEsc');
|
|
122
122
|
|
|
123
123
|
const parentConfig = parentHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
|
|
124
124
|
const childConfig = childHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
|
|
@@ -787,6 +787,9 @@ describe('OverlayController', () => {
|
|
|
787
787
|
|
|
788
788
|
expect(parentOverlay.isShown).to.be.false;
|
|
789
789
|
expect(childOverlay.isShown).to.be.true;
|
|
790
|
+
|
|
791
|
+
await childOverlay.teardown();
|
|
792
|
+
await parentOverlay.teardown();
|
|
790
793
|
});
|
|
791
794
|
|
|
792
795
|
it('on [Escape] press outside overlays: parent stays shown, child hides', async () => {
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
unsafeStatic,
|
|
3
|
+
nextFrame,
|
|
4
|
+
aTimeout,
|
|
5
|
+
defineCE,
|
|
6
|
+
fixture,
|
|
7
|
+
expect,
|
|
8
|
+
html,
|
|
9
|
+
} from '@open-wc/testing';
|
|
4
10
|
import { overlays as overlaysManager, OverlayController } from '@lion/ui/overlays.js';
|
|
5
|
-
|
|
6
|
-
import '@lion/ui/define/lion-dialog.js';
|
|
7
11
|
import { browserDetection } from '@lion/ui/core.js';
|
|
12
|
+
import { cache } from 'lit/directives/cache.js';
|
|
13
|
+
import '@lion/ui/define/lion-dialog.js';
|
|
14
|
+
import { LitElement } from 'lit';
|
|
15
|
+
import sinon from 'sinon';
|
|
8
16
|
|
|
9
17
|
/**
|
|
10
|
-
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
11
18
|
* @typedef {import('../types/OverlayMixinTypes.js').DefineOverlayConfig} DefineOverlayConfig
|
|
12
|
-
* @typedef {import('../types/OverlayMixinTypes.js').OverlayHost} OverlayHost
|
|
13
|
-
* @typedef {import('../types/OverlayMixinTypes.js').OverlayMixin} OverlayMixin
|
|
14
|
-
* @typedef {import('lit').LitElement} LitElement
|
|
15
19
|
* @typedef {LitElement & OverlayHost & {_overlayCtrl:OverlayController}} OverlayEl
|
|
20
|
+
* @typedef {import('../types/OverlayMixinTypes.js').OverlayMixin} OverlayMixin
|
|
21
|
+
* @typedef {import('../types/OverlayMixinTypes.js').OverlayHost} OverlayHost
|
|
22
|
+
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
16
23
|
*/
|
|
17
24
|
|
|
18
25
|
function getGlobalOverlayCtrls() {
|
|
@@ -331,6 +338,173 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
|
|
331
338
|
}).to.not.throw;
|
|
332
339
|
stub.restore();
|
|
333
340
|
});
|
|
341
|
+
|
|
342
|
+
describe('Teardown', () => {
|
|
343
|
+
it('does not teardown when moving dom nodes', async () => {
|
|
344
|
+
const el = /** @type {OverlayEl} */ (
|
|
345
|
+
await fixture(html`
|
|
346
|
+
<${tag}>
|
|
347
|
+
<div slot="content">content</div>
|
|
348
|
+
<button slot="invoker">invoker button</button>
|
|
349
|
+
</${tag}>
|
|
350
|
+
`)
|
|
351
|
+
);
|
|
352
|
+
// @ts-expect-error [allow-protected] in tests
|
|
353
|
+
const teardownSpy = sinon.spy(el, '_teardownOverlayCtrl');
|
|
354
|
+
// @ts-expect-error [allow-protected] in tests
|
|
355
|
+
const spyDisconnected = sinon.spy(el, '_isPermanentlyDisconnected');
|
|
356
|
+
|
|
357
|
+
// move around in dom
|
|
358
|
+
const newParent = document.createElement('div');
|
|
359
|
+
document.body.appendChild(newParent);
|
|
360
|
+
newParent.appendChild(el);
|
|
361
|
+
expect(spyDisconnected.callCount).to.equal(1);
|
|
362
|
+
|
|
363
|
+
const otherParent = document.createElement('div');
|
|
364
|
+
document.body.appendChild(otherParent);
|
|
365
|
+
otherParent.appendChild(el);
|
|
366
|
+
await aTimeout(0);
|
|
367
|
+
|
|
368
|
+
expect(spyDisconnected.callCount).to.equal(2);
|
|
369
|
+
expect(teardownSpy.callCount).to.equal(0);
|
|
370
|
+
|
|
371
|
+
// simulate a permanent disconnect
|
|
372
|
+
otherParent.removeChild(el);
|
|
373
|
+
await aTimeout(0);
|
|
374
|
+
|
|
375
|
+
expect(teardownSpy.callCount).to.equal(1);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('allows to disconnect and reconnect later', async () => {
|
|
379
|
+
const el = /** @type {OverlayEl} */ (
|
|
380
|
+
await fixture(html`
|
|
381
|
+
<${tag}>
|
|
382
|
+
<div slot="content">content</div>
|
|
383
|
+
<button slot="invoker">invoker button</button>
|
|
384
|
+
</${tag}>
|
|
385
|
+
`)
|
|
386
|
+
);
|
|
387
|
+
// @ts-expect-error [allow-protected] in tests
|
|
388
|
+
const teardownSpy = sinon.spy(el, '_teardownOverlayCtrl');
|
|
389
|
+
// @ts-expect-error [allow-protected] in tests
|
|
390
|
+
const spyDisconnected = sinon.spy(el, '_isPermanentlyDisconnected');
|
|
391
|
+
// @ts-expect-error [allow-protected] in tests
|
|
392
|
+
const setupSpy = sinon.spy(el, '_setupOverlayCtrl');
|
|
393
|
+
|
|
394
|
+
// 'permanently' disconnect (although we will reconnect later)
|
|
395
|
+
const offlineParent = document.createElement('div');
|
|
396
|
+
offlineParent.appendChild(el);
|
|
397
|
+
await aTimeout(0);
|
|
398
|
+
|
|
399
|
+
expect(spyDisconnected.callCount).to.equal(1);
|
|
400
|
+
expect(teardownSpy.callCount).to.equal(1);
|
|
401
|
+
|
|
402
|
+
// reconnect
|
|
403
|
+
document.body.appendChild(offlineParent);
|
|
404
|
+
await aTimeout(0);
|
|
405
|
+
|
|
406
|
+
expect(setupSpy.callCount).to.equal(1);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('works with cache directive when reconnected', async () => {
|
|
410
|
+
class CachingContext extends LitElement {
|
|
411
|
+
static properties = {
|
|
412
|
+
switched: { type: Boolean },
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
constructor() {
|
|
416
|
+
super();
|
|
417
|
+
|
|
418
|
+
this.switched = false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
get overlayEl() {
|
|
422
|
+
return this.shadowRoot?.querySelector('#myOverlay');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
render() {
|
|
426
|
+
return html`${cache(
|
|
427
|
+
this.switched
|
|
428
|
+
? html`something else`
|
|
429
|
+
: html`<${tag} id="myOverlay">
|
|
430
|
+
<div slot="content">content b</div>
|
|
431
|
+
<button slot="invoker">invoker button b</button>
|
|
432
|
+
</${tag}>`,
|
|
433
|
+
)}`;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const cachingTagName = defineCE(CachingContext);
|
|
438
|
+
const cachingTag = unsafeStatic(cachingTagName);
|
|
439
|
+
|
|
440
|
+
const el = /** @type {CachingContext} */ (
|
|
441
|
+
await fixture(html`
|
|
442
|
+
<${cachingTag}></${cachingTag}>
|
|
443
|
+
`)
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// @ts-expect-error [allow-protected] in tests
|
|
447
|
+
const teardownSpy = sinon.spy(el.overlayEl, '_teardownOverlayCtrl');
|
|
448
|
+
// @ts-expect-error [allow-protected] in tests
|
|
449
|
+
const spyDisconnected = sinon.spy(el.overlayEl, '_isPermanentlyDisconnected');
|
|
450
|
+
// @ts-expect-error [allow-protected] in tests
|
|
451
|
+
const setupSpy = sinon.spy(el.overlayEl, '_setupOverlayCtrl');
|
|
452
|
+
|
|
453
|
+
el.switched = true;
|
|
454
|
+
// render the new content
|
|
455
|
+
await el.updateComplete;
|
|
456
|
+
// wait for the teardown to complete
|
|
457
|
+
await el.updateComplete;
|
|
458
|
+
|
|
459
|
+
expect(spyDisconnected.callCount).to.equal(1);
|
|
460
|
+
expect(teardownSpy.callCount).to.equal(1);
|
|
461
|
+
expect(setupSpy.callCount).to.equal(0);
|
|
462
|
+
|
|
463
|
+
el.switched = false;
|
|
464
|
+
await el.updateComplete;
|
|
465
|
+
|
|
466
|
+
expect(setupSpy.callCount).to.equal(1);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('correctly removes event listeners when disconnected from dom', async () => {
|
|
470
|
+
const el = /** @type {OverlayEl} */ (
|
|
471
|
+
await fixture(html`
|
|
472
|
+
<${tag}>
|
|
473
|
+
<div slot="content">content</div>
|
|
474
|
+
<button slot="invoker">invoker button</button>
|
|
475
|
+
</${tag}>
|
|
476
|
+
`)
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
const eventRemoveSpy = sinon.spy(el._overlayCtrl, 'removeEventListener');
|
|
480
|
+
el.parentNode?.removeChild(el);
|
|
481
|
+
await el.updateComplete;
|
|
482
|
+
|
|
483
|
+
expect(eventRemoveSpy.callCount).to.equal(0);
|
|
484
|
+
|
|
485
|
+
await el.updateComplete;
|
|
486
|
+
const hasOneInstanceFor = (
|
|
487
|
+
/** @type {string} */ eventName,
|
|
488
|
+
/** @type {any[][]} */ eventsToSearch,
|
|
489
|
+
/** @type {string} */ methodToRemove,
|
|
490
|
+
) =>
|
|
491
|
+
Boolean(
|
|
492
|
+
eventsToSearch.filter(
|
|
493
|
+
([eventToSearch, methodToSearch]) =>
|
|
494
|
+
eventToSearch === eventName && methodToSearch === methodToRemove,
|
|
495
|
+
).length,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
// @ts-expect-error [allow-private] in tests
|
|
499
|
+
expect(hasOneInstanceFor('show', eventRemoveSpy.args, el.__onOverlayCtrlShow)).to.be.true;
|
|
500
|
+
// @ts-expect-error [allow-private] in tests
|
|
501
|
+
expect(hasOneInstanceFor('hide', eventRemoveSpy.args, el.__onOverlayCtrlHide)).to.be.true;
|
|
502
|
+
// @ts-expect-error [allow-private] in tests
|
|
503
|
+
expect(hasOneInstanceFor('before-show', eventRemoveSpy.args, el.__onBeforeShow)).to.be.true;
|
|
504
|
+
// @ts-expect-error [allow-private] in tests
|
|
505
|
+
expect(hasOneInstanceFor('before-hide', eventRemoveSpy.args, el.__onBeforeHide)).to.be.true;
|
|
506
|
+
});
|
|
507
|
+
});
|
|
334
508
|
});
|
|
335
509
|
|
|
336
510
|
describe(`OverlayMixin${suffix} nested`, () => {
|
|
@@ -388,6 +562,7 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
|
|
388
562
|
const moveTarget = /** @type {OverlayEl} */ (await fixture('<div id="target"></div>'));
|
|
389
563
|
moveTarget.appendChild(el);
|
|
390
564
|
await el.updateComplete;
|
|
565
|
+
|
|
391
566
|
expect(getGlobalOverlayCtrls().length).to.equal(1);
|
|
392
567
|
}
|
|
393
568
|
});
|
|
@@ -4,25 +4,34 @@ import { Options as PopperOptions, State } from '@popperjs/core/lib/popper.js';
|
|
|
4
4
|
import { OverlayConfig } from './OverlayConfig.js';
|
|
5
5
|
|
|
6
6
|
export declare class ArrowHost {
|
|
7
|
-
static
|
|
7
|
+
static properties: {
|
|
8
8
|
hasArrow: {
|
|
9
9
|
type: BooleanConstructor;
|
|
10
10
|
reflect: boolean;
|
|
11
11
|
attribute: string;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
+
|
|
14
15
|
hasArrow: boolean;
|
|
16
|
+
|
|
15
17
|
repositionComplete: Promise<void>;
|
|
16
18
|
|
|
17
|
-
static
|
|
19
|
+
static styles: CSSResultArray;
|
|
18
20
|
|
|
19
21
|
render(): TemplateResult;
|
|
22
|
+
|
|
20
23
|
protected _arrowTemplate(): TemplateResult;
|
|
24
|
+
|
|
21
25
|
protected _arrowNodeTemplate(): TemplateResult;
|
|
26
|
+
|
|
22
27
|
protected _defineOverlayConfig(): OverlayConfig;
|
|
28
|
+
|
|
23
29
|
protected _getPopperArrowConfig(popperConfigToExtendFrom: Partial<PopperOptions>): Partial<PopperOptions>;
|
|
30
|
+
|
|
24
31
|
private __setupRepositionCompletePromise(): void;
|
|
32
|
+
|
|
25
33
|
get _arrowNode(): Element | null;
|
|
34
|
+
|
|
26
35
|
private __syncFromPopperState(data: Partial<State>): void;
|
|
27
36
|
}
|
|
28
37
|
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { Options } from '@popperjs/core';
|
|
2
2
|
|
|
3
|
+
export type ViewportPlacement =
|
|
4
|
+
| 'center'
|
|
5
|
+
| 'top-left'
|
|
6
|
+
| 'top'
|
|
7
|
+
| 'top-right'
|
|
8
|
+
| 'right'
|
|
9
|
+
| 'bottom-right'
|
|
10
|
+
| 'bottom'
|
|
11
|
+
| 'bottom-left'
|
|
12
|
+
| 'left';
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export interface ViewportConfig {
|
|
16
|
+
placement: ViewportPlacement;
|
|
17
|
+
}
|
|
3
18
|
export interface OverlayConfig {
|
|
4
19
|
// Positioning
|
|
5
20
|
|
|
@@ -80,17 +95,4 @@ export interface OverlayConfig {
|
|
|
80
95
|
visibilityTriggerFunction?: Function;
|
|
81
96
|
}
|
|
82
97
|
|
|
83
|
-
export type ViewportPlacement =
|
|
84
|
-
| 'center'
|
|
85
|
-
| 'top-left'
|
|
86
|
-
| 'top'
|
|
87
|
-
| 'top-right'
|
|
88
|
-
| 'right'
|
|
89
|
-
| 'bottom-right'
|
|
90
|
-
| 'bottom'
|
|
91
|
-
| 'bottom-left'
|
|
92
|
-
| 'left';
|
|
93
98
|
|
|
94
|
-
export interface ViewportConfig {
|
|
95
|
-
placement: ViewportPlacement;
|
|
96
|
-
}
|
|
@@ -423,6 +423,7 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
423
423
|
*/
|
|
424
424
|
_teardownOverlayCtrl() {
|
|
425
425
|
super._teardownOverlayCtrl();
|
|
426
|
+
|
|
426
427
|
this._overlayCtrl.removeEventListener('show', this.__overlayOnShow);
|
|
427
428
|
this._overlayCtrl.removeEventListener('before-show', this.__overlayBeforeShow);
|
|
428
429
|
this._overlayCtrl.removeEventListener('hide', this.__overlayOnHide);
|
|
@@ -434,11 +435,12 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
434
435
|
* @protected
|
|
435
436
|
*/
|
|
436
437
|
async _alignInvokerWidth() {
|
|
438
|
+
await this.updateComplete;
|
|
439
|
+
|
|
437
440
|
if (!this._overlayCtrl?.content) {
|
|
438
441
|
return;
|
|
439
442
|
}
|
|
440
443
|
|
|
441
|
-
await this.updateComplete;
|
|
442
444
|
const initContentDisplay = this._overlayCtrl.content.style.display;
|
|
443
445
|
const initContentMinWidth = this._overlayCtrl.contentWrapperNode.style.minWidth;
|
|
444
446
|
const initContentWidth = this._overlayCtrl.contentWrapperNode.style.width;
|
|
@@ -7,6 +7,7 @@ import '@lion/ui/define/lion-select-rich.js';
|
|
|
7
7
|
import '@lion/ui/define/lion-listbox.js';
|
|
8
8
|
import '@lion/ui/define/lion-option.js';
|
|
9
9
|
import { LitElement } from 'lit';
|
|
10
|
+
import sinon from 'sinon';
|
|
10
11
|
import {
|
|
11
12
|
fixture as _fixture,
|
|
12
13
|
unsafeStatic,
|
|
@@ -711,6 +712,49 @@ describe('lion-select-rich', () => {
|
|
|
711
712
|
});
|
|
712
713
|
});
|
|
713
714
|
|
|
715
|
+
describe('Teardown', () => {
|
|
716
|
+
it('correctly removes event listeners when disconnected from dom', async () => {
|
|
717
|
+
const el = await fixture(html`
|
|
718
|
+
<lion-select-rich label="age">
|
|
719
|
+
<lion-option .choiceValue=${10}>Item 1</lion-option>
|
|
720
|
+
<lion-option .choiceValue=${20}>Item 2</lion-option>
|
|
721
|
+
</lion-select-rich>
|
|
722
|
+
`);
|
|
723
|
+
|
|
724
|
+
const { _overlayCtrl } = getSelectRichMembers(el);
|
|
725
|
+
const eventRemoveSpy = sinon.spy(_overlayCtrl, 'removeEventListener');
|
|
726
|
+
|
|
727
|
+
el.parentNode?.removeChild(el);
|
|
728
|
+
|
|
729
|
+
expect(eventRemoveSpy.callCount).to.equal(0);
|
|
730
|
+
|
|
731
|
+
await el.updateComplete;
|
|
732
|
+
expect(eventRemoveSpy.callCount).to.equal(0);
|
|
733
|
+
|
|
734
|
+
await el.updateComplete;
|
|
735
|
+
|
|
736
|
+
const hasOneInstanceFor = (
|
|
737
|
+
/** @type {string} */ eventName,
|
|
738
|
+
/** @type {any[][]} */ eventsToSearch,
|
|
739
|
+
/** @type {string} */ methodToRemove,
|
|
740
|
+
) =>
|
|
741
|
+
Boolean(
|
|
742
|
+
eventsToSearch.filter(
|
|
743
|
+
([eventToSearch, methodToSearch]) =>
|
|
744
|
+
eventToSearch === eventName && methodToSearch === methodToRemove,
|
|
745
|
+
).length,
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
// @ts-expect-error [allow-private] in tests
|
|
749
|
+
expect(hasOneInstanceFor('show', eventRemoveSpy.args, el.__overlayOnShow)).to.be.true;
|
|
750
|
+
// @ts-expect-error [allow-private] in tests
|
|
751
|
+
expect(hasOneInstanceFor('before-show', eventRemoveSpy.args, el.__overlayBeforeShow)).to.be
|
|
752
|
+
.true;
|
|
753
|
+
// @ts-expect-error [allow-private] in tests
|
|
754
|
+
expect(hasOneInstanceFor('hide', eventRemoveSpy.args, el.__overlayOnHide)).to.be.true;
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
|
|
714
758
|
describe('Subclassers', () => {
|
|
715
759
|
it('allows to override the type of overlay', async () => {
|
|
716
760
|
const mySelectTagString = defineCE(
|