@lion/ui 0.12.0 → 0.13.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 +26 -8
- package/components/combobox/test/lion-combobox.test.js +206 -57
- package/components/form-core/src/FocusMixin.js +1 -0
- package/components/form-core/src/FormControlMixin.js +23 -18
- package/components/form-core/src/validate/ValidateMixin.js +17 -1
- package/components/form-core/test/FormControlMixin.test.js +68 -0
- package/components/form-core/test-suites/ValidateMixin.suite.js +19 -3
- package/components/overlays/src/OverlayController.js +32 -5
- package/components/overlays/src/OverlayMixin.js +1 -0
- package/components/overlays/src/configurations/withDropdownConfig.js +0 -1
- package/components/overlays/src/configurations/withTooltipConfig.js +0 -1
- package/components/overlays/test/OverlayController.test.js +16 -4
- package/components/overlays/test-suites/OverlayMixin.suite.js +71 -0
- package/custom-elements.json +1144 -327
- package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
- package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/FocusMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/FormControlMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixin.suite.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/src/configurations/withDropdownConfig.d.ts.map +1 -1
- package/dist-types/components/overlays/src/configurations/withTooltipConfig.d.ts.map +1 -1
- package/dist-types/components/overlays/test/OverlayController.test.d.ts.map +1 -1
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/api-table.md +6 -6
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/api-table.md +2 -2
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +90 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/api-table.md +2 -2
- 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 +2 -2
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/api-table.md +2 -2
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/api-table.md +2 -2
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/api-table.md +2 -2
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/api-table.md +2 -2
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/api-table.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/api-table.md +2 -2
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/api-table.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/api-table.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/api-table.md +2 -2
- 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 +2 -2
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/api-table.md +2 -2
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/api-table.md +4 -4
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/api-table.md +2 -2
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/api-table.md +2 -2
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/switch/api-table.md +2 -2
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/textarea/api-table.md +2 -2
- package/docs/fundamentals/index.md +4 -4
- 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 +2 -2
- 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/styling.md +3 -20
- 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 +3 -3
|
@@ -528,8 +528,6 @@ export class OverlayController extends EventTarget {
|
|
|
528
528
|
this.__contentHasBeenInitialized = true;
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
-
this.__wrappingDialogNode?.addEventListener('cancel', this.__cancelHandler);
|
|
532
|
-
|
|
533
531
|
// Reset all positioning styles (local, c.q. Popper) and classes (global)
|
|
534
532
|
this.contentWrapperNode.removeAttribute('style');
|
|
535
533
|
this.contentWrapperNode.removeAttribute('class');
|
|
@@ -618,8 +616,9 @@ export class OverlayController extends EventTarget {
|
|
|
618
616
|
contentWrapperNodeL2: this.contentWrapperNode,
|
|
619
617
|
contentNodeL3: this.contentNode,
|
|
620
618
|
});
|
|
621
|
-
// @ts-
|
|
619
|
+
// @ts-expect-error
|
|
622
620
|
wrappingDialogElement.open = true;
|
|
621
|
+
|
|
623
622
|
if (this.isTooltip) {
|
|
624
623
|
// needed to prevent tooltip getting focus in Safari and Firefox
|
|
625
624
|
wrappingDialogElement.setAttribute('tabindex', '-1');
|
|
@@ -633,6 +632,35 @@ export class OverlayController extends EventTarget {
|
|
|
633
632
|
// computed height of 0...
|
|
634
633
|
this.contentNode.style.position = 'static';
|
|
635
634
|
}
|
|
635
|
+
|
|
636
|
+
// Here we prevent any interference of the native <dialog> element with the keyboard behavior
|
|
637
|
+
// as defined by the OverlayController. This is needed until we can configure `closedby="none"`
|
|
638
|
+
// on the native dialog for all browsers: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog#closedby
|
|
639
|
+
const hasClosedBySupport = HTMLDialogElement && 'closedBy' in HTMLDialogElement.prototype;
|
|
640
|
+
if (hasClosedBySupport) {
|
|
641
|
+
// @ts-expect-error
|
|
642
|
+
wrappingDialogElement.closedBy = 'none';
|
|
643
|
+
} else {
|
|
644
|
+
wrappingDialogElement.addEventListener(
|
|
645
|
+
'keydown',
|
|
646
|
+
(/** @type {* & KeyboardEvent} */ event) => {
|
|
647
|
+
if (event.key === 'Escape') {
|
|
648
|
+
event.preventDefault();
|
|
649
|
+
}
|
|
650
|
+
},
|
|
651
|
+
);
|
|
652
|
+
wrappingDialogElement.addEventListener('keyup', (/** @type {* & KeyboardEvent} */ event) => {
|
|
653
|
+
if (event.key === 'Escape') {
|
|
654
|
+
event.preventDefault();
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
wrappingDialogElement.addEventListener('cancel', event => {
|
|
658
|
+
event.stopPropagation();
|
|
659
|
+
});
|
|
660
|
+
wrappingDialogElement.addEventListener('close', event => {
|
|
661
|
+
event.stopPropagation();
|
|
662
|
+
});
|
|
663
|
+
}
|
|
636
664
|
}
|
|
637
665
|
|
|
638
666
|
/**
|
|
@@ -1188,6 +1216,7 @@ export class OverlayController extends EventTarget {
|
|
|
1188
1216
|
const hasPressedInside =
|
|
1189
1217
|
event.composedPath().includes(this.contentNode) ||
|
|
1190
1218
|
deepContains(this.contentNode, /** @type {HTMLElement|ShadowRoot} */ (event.target));
|
|
1219
|
+
|
|
1191
1220
|
if (hasPressedInside) {
|
|
1192
1221
|
this.hide();
|
|
1193
1222
|
// We could do event.stopPropagation() here, but we don't want to hide info for
|
|
@@ -1384,8 +1413,6 @@ export class OverlayController extends EventTarget {
|
|
|
1384
1413
|
teardown() {
|
|
1385
1414
|
this.__handleOverlayStyles({ phase: 'teardown' });
|
|
1386
1415
|
this._handleFeatures({ phase: 'teardown' });
|
|
1387
|
-
this.__wrappingDialogNode?.removeEventListener('cancel', this.__cancelHandler);
|
|
1388
|
-
|
|
1389
1416
|
if (this.#isRegisteredOnManager()) {
|
|
1390
1417
|
this.manager.remove(this);
|
|
1391
1418
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-new */
|
|
2
2
|
import { OverlayController, overlays } from '@lion/ui/overlays.js';
|
|
3
3
|
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
|
4
|
+
import { sendKeys } from '@web/test-runner-commands';
|
|
4
5
|
import sinon from 'sinon';
|
|
5
6
|
import {
|
|
6
7
|
unsafeStatic,
|
|
@@ -28,12 +29,22 @@ const wrappingDialogNodeStyle = 'display: none; z-index: 9999; padding: 0px;';
|
|
|
28
29
|
/**
|
|
29
30
|
* A small wrapper function that closely mimics an escape press from a user
|
|
30
31
|
* (prevents common mistakes like no bubbling or keydown)
|
|
31
|
-
* @param {
|
|
32
|
+
* @param {HTMLElement|Document} element
|
|
32
33
|
*/
|
|
33
34
|
async function mimicEscapePress(element) {
|
|
34
|
-
element
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// Make sure that the element inside the dialog is focusable (and cleanup after)
|
|
36
|
+
if (element instanceof HTMLElement) {
|
|
37
|
+
const { tabIndex: tabIndexBefore } = element;
|
|
38
|
+
// eslint-disable-next-line no-param-reassign
|
|
39
|
+
element.tabIndex = -1;
|
|
40
|
+
element.focus();
|
|
41
|
+
// eslint-disable-next-line no-param-reassign
|
|
42
|
+
element.tabIndex = tabIndexBefore; // make sure element is focusable
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Send the event
|
|
46
|
+
await sendKeys({ press: 'Escape' });
|
|
47
|
+
// Wait for at least a microtask, so that possible property effects are performed
|
|
37
48
|
await aTimeout(0);
|
|
38
49
|
}
|
|
39
50
|
|
|
@@ -726,6 +737,7 @@ describe('OverlayController', () => {
|
|
|
726
737
|
)
|
|
727
738
|
);
|
|
728
739
|
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
740
|
+
|
|
729
741
|
await mimicEscapePress(childOverlay.contentNode);
|
|
730
742
|
|
|
731
743
|
expect(parentOverlay.isShown).to.be.true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
unsafeStatic,
|
|
3
|
+
fixtureSync,
|
|
3
4
|
nextFrame,
|
|
4
5
|
aTimeout,
|
|
5
6
|
defineCE,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
html,
|
|
9
10
|
} from '@open-wc/testing';
|
|
10
11
|
import { overlays as overlaysManager, OverlayController } from '@lion/ui/overlays.js';
|
|
12
|
+
import { sendKeys } from '@web/test-runner-commands';
|
|
11
13
|
import { browserDetection } from '@lion/ui/core.js';
|
|
12
14
|
import { cache } from 'lit/directives/cache.js';
|
|
13
15
|
import '@lion/ui/define/lion-dialog.js';
|
|
@@ -30,6 +32,28 @@ function resetOverlaysManager() {
|
|
|
30
32
|
overlaysManager.list.forEach(overlayCtrl => overlaysManager.remove(overlayCtrl));
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* A small wrapper function that closely mimics an escape press from a user
|
|
37
|
+
* (prevents common mistakes like no bubbling or keydown)
|
|
38
|
+
* @param {HTMLElement|Document} element
|
|
39
|
+
*/
|
|
40
|
+
async function mimicEscapePress(element) {
|
|
41
|
+
// Make sure that the element inside the dialog is focusable (and cleanup after)
|
|
42
|
+
if (element instanceof HTMLElement) {
|
|
43
|
+
const { tabIndex: tabIndexBefore } = element;
|
|
44
|
+
// eslint-disable-next-line no-param-reassign
|
|
45
|
+
element.tabIndex = -1;
|
|
46
|
+
element.focus();
|
|
47
|
+
// eslint-disable-next-line no-param-reassign
|
|
48
|
+
element.tabIndex = tabIndexBefore; // make sure element is focusable
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Send the event
|
|
52
|
+
await sendKeys({ press: 'Escape' });
|
|
53
|
+
// Wait for at least a microtask, so that possible property effects are performed
|
|
54
|
+
await aTimeout(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
/**
|
|
34
58
|
* @param {{tagString:string, tag: object, suffix?:string}} config
|
|
35
59
|
*/
|
|
@@ -315,6 +339,33 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
|
|
315
339
|
expect(getComputedStyle(el._overlayCtrl.contentWrapperNode).display).not.to.equal('none');
|
|
316
340
|
});
|
|
317
341
|
|
|
342
|
+
it('does not run setup when disconnected', async () => {
|
|
343
|
+
const el = /** @type {OverlayEl} */ (
|
|
344
|
+
fixtureSync(html`
|
|
345
|
+
<${tag}>
|
|
346
|
+
<div slot="content">content</div>
|
|
347
|
+
<button slot="invoker">invoker button</button>
|
|
348
|
+
</${tag}>
|
|
349
|
+
`)
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
const parentOfEl = /** @type {HTMLDivElement} */ (el.parentElement);
|
|
353
|
+
|
|
354
|
+
// @ts-expect-error [allow-protected-in-tests]
|
|
355
|
+
const setupSpy = sinon.spy(el, '_setupOverlayCtrl');
|
|
356
|
+
// In some client apps, this sync disconnect happens...
|
|
357
|
+
parentOfEl.removeChild(el);
|
|
358
|
+
await el.updateComplete;
|
|
359
|
+
expect(setupSpy.callCount).to.equal(0);
|
|
360
|
+
|
|
361
|
+
// Now add el again...
|
|
362
|
+
parentOfEl.appendChild(el);
|
|
363
|
+
await el.updateComplete;
|
|
364
|
+
expect(setupSpy.callCount).to.equal(1);
|
|
365
|
+
|
|
366
|
+
setupSpy.restore();
|
|
367
|
+
});
|
|
368
|
+
|
|
318
369
|
/** Prevent unnecessary reset side effects, such as show animation. See: https://github.com/ing-bank/lion/issues/1075 */
|
|
319
370
|
it('does not call updateConfig on equivalent config change', async () => {
|
|
320
371
|
const el = /** @type {OverlayEl} */ (
|
|
@@ -339,6 +390,26 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
|
|
|
339
390
|
stub.restore();
|
|
340
391
|
});
|
|
341
392
|
|
|
393
|
+
it('should not visually hide when hidesOnEsc / hidesOnOutsideEsc is not configured', async () => {
|
|
394
|
+
const el = /** @type {OverlayEl} */ (
|
|
395
|
+
await fixture(html`
|
|
396
|
+
<${tag} .config="${{ hidesOnEsc: false, hidesOnOutsideEsc: false }}" opened>
|
|
397
|
+
<div slot="content">content of the overlay</div>
|
|
398
|
+
<button slot="invoker">invoker button</button>
|
|
399
|
+
</${tag}>
|
|
400
|
+
`)
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
const dialogEl = /** @type {HTMLDialogElement} */ (el._overlayCtrl.__wrappingDialogNode);
|
|
404
|
+
|
|
405
|
+
// @ts-expect-error [allow-protected-in-tests]
|
|
406
|
+
expect(dialogEl.checkVisibility()).to.be.true;
|
|
407
|
+
// @ts-expect-error [allow-protected-in-tests]
|
|
408
|
+
await mimicEscapePress(el._overlayContentNode);
|
|
409
|
+
// @ts-expect-error [allow-protected-in-tests]
|
|
410
|
+
expect(dialogEl.checkVisibility()).to.be.true;
|
|
411
|
+
});
|
|
412
|
+
|
|
342
413
|
describe('Teardown', () => {
|
|
343
414
|
it('does not teardown when moving dom nodes', async () => {
|
|
344
415
|
const el = /** @type {OverlayEl} */ (
|