@lion/ui 0.8.2 → 0.8.3
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/overlays/src/OverlayController.js +40 -13
- package/components/overlays/test/OverlayController.test.js +233 -30
- package/components/overlays/test-helpers/mimicClick.js +2 -2
- package/custom-elements.json +31 -4
- package/dist-types/components/form-integrations/test/helpers/helpers.d.ts +3 -3
- package/dist-types/components/form-integrations/test/helpers/helpers.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +9 -5
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/overlays/test/OverlayController.test.d.ts +1 -1
- package/dist-types/components/overlays/test/OverlayController.test.d.ts.map +1 -1
- package/dist-types/components/overlays/test-helpers/mimicClick.d.ts +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- 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/icon/use-cases.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.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/overview.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
- 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/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/api-table.md +1 -0
- 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
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { overlays } from './singleton.js';
|
|
2
2
|
import { containFocus } from './utils/contain-focus.js';
|
|
3
|
+
import { deepContains } from './utils/deep-contains.js';
|
|
3
4
|
import { overlayShadowDomStyle } from './overlayShadowDomStyle.js';
|
|
4
5
|
import { _adoptStyleUtils } from './utils/adopt-styles.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
|
-
* @typedef {
|
|
8
|
+
* @typedef {'setup'|'init'|'teardown'|'before-show'|'show'|'hide'|'add'|'remove'} OverlayPhase
|
|
8
9
|
* @typedef {import('@lion/ui/types/overlays.js').ViewportConfig} ViewportConfig
|
|
9
|
-
* @typedef {import('@
|
|
10
|
+
* @typedef {import('@lion/ui/types/overlays.js').OverlayConfig} OverlayConfig
|
|
10
11
|
* @typedef {import('@popperjs/core').Options} PopperOptions
|
|
11
12
|
* @typedef {import('@popperjs/core').Placement} Placement
|
|
13
|
+
* @typedef {import('@popperjs/core').createPopper} Popper
|
|
12
14
|
* @typedef {{ createPopper: Popper }} PopperModule
|
|
13
|
-
* @typedef {'setup'|'init'|'teardown'|'before-show'|'show'|'hide'|'add'|'remove'} OverlayPhase
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -103,6 +104,8 @@ async function preloadPopper() {
|
|
|
103
104
|
return /** @type {* & Promise<PopperModule>} */ (import('@popperjs/core/dist/esm/popper.js'));
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
const childDialogsClosedInEventLoopWeakmap = new WeakMap();
|
|
108
|
+
|
|
106
109
|
/**
|
|
107
110
|
* OverlayController is the fundament for every single type of overlay. With the right
|
|
108
111
|
* configuration, it can be used to build (modal) dialogs, tooltips, dropdowns, popovers,
|
|
@@ -498,9 +501,6 @@ export class OverlayController extends EventTarget {
|
|
|
498
501
|
'[OverlayController] .isTooltip only takes effect when .handlesAccessibility is enabled',
|
|
499
502
|
);
|
|
500
503
|
}
|
|
501
|
-
// if (newConfig.popperConfig.modifiers.arrow && !newConfig.contentWrapperNode) {
|
|
502
|
-
// throw new Error('You need to provide a .contentWrapperNode when Popper arrow is enabled');
|
|
503
|
-
// }
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
/**
|
|
@@ -1146,11 +1146,40 @@ export class OverlayController extends EventTarget {
|
|
|
1146
1146
|
ev.preventDefault();
|
|
1147
1147
|
}
|
|
1148
1148
|
|
|
1149
|
-
/**
|
|
1150
|
-
|
|
1151
|
-
|
|
1149
|
+
/**
|
|
1150
|
+
* @param {KeyboardEvent} event
|
|
1151
|
+
* @returns {void}
|
|
1152
|
+
*/
|
|
1153
|
+
__escKeyHandler(event) {
|
|
1154
|
+
if (event.key !== 'Escape' || childDialogsClosedInEventLoopWeakmap.has(event)) return;
|
|
1155
|
+
|
|
1156
|
+
const hasPressedInside =
|
|
1157
|
+
event.composedPath().includes(this.contentNode) ||
|
|
1158
|
+
deepContains(this.contentNode, /** @type {HTMLElement|ShadowRoot} */ (event.target));
|
|
1159
|
+
if (hasPressedInside) {
|
|
1160
|
+
this.hide();
|
|
1161
|
+
// We could do event.stopPropagation() here, but we don't want to hide info for
|
|
1162
|
+
// the outside world about user interactions. Instead, we store the event in a WeakMap
|
|
1163
|
+
// that will be garbage collected after the event loop.
|
|
1164
|
+
childDialogsClosedInEventLoopWeakmap.set(event, this);
|
|
1165
|
+
}
|
|
1152
1166
|
}
|
|
1153
1167
|
|
|
1168
|
+
/**
|
|
1169
|
+
* @param {KeyboardEvent} event
|
|
1170
|
+
* @returns {void}
|
|
1171
|
+
*/
|
|
1172
|
+
#outsideEscKeyHandler = event => {
|
|
1173
|
+
if (event.key !== 'Escape') return;
|
|
1174
|
+
|
|
1175
|
+
const hasPressedInside =
|
|
1176
|
+
event.composedPath().includes(this.contentNode) ||
|
|
1177
|
+
deepContains(this.contentNode, /** @type {HTMLElement|ShadowRoot} */ (event.target));
|
|
1178
|
+
if (!hasPressedInside) {
|
|
1179
|
+
this.hide();
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1154
1183
|
/**
|
|
1155
1184
|
* @param {{ phase: OverlayPhase }} config
|
|
1156
1185
|
* @protected
|
|
@@ -1175,11 +1204,9 @@ export class OverlayController extends EventTarget {
|
|
|
1175
1204
|
*/
|
|
1176
1205
|
_handleHidesOnOutsideEsc({ phase }) {
|
|
1177
1206
|
if (phase === 'show') {
|
|
1178
|
-
|
|
1179
|
-
ev.key === 'Escape' && this.hide();
|
|
1180
|
-
document.addEventListener('keyup', this.__escKeyHandler);
|
|
1207
|
+
document.addEventListener('keyup', this.#outsideEscKeyHandler);
|
|
1181
1208
|
} else if (phase === 'hide') {
|
|
1182
|
-
document.removeEventListener('keyup', this
|
|
1209
|
+
document.removeEventListener('keyup', this.#outsideEscKeyHandler);
|
|
1183
1210
|
}
|
|
1184
1211
|
}
|
|
1185
1212
|
|
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
/* eslint-disable no-new */
|
|
2
|
+
import { OverlayController, overlays } from '@lion/ui/overlays.js';
|
|
3
|
+
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
|
4
|
+
import sinon from 'sinon';
|
|
2
5
|
import {
|
|
3
|
-
|
|
6
|
+
unsafeStatic,
|
|
7
|
+
fixtureSync,
|
|
4
8
|
defineCE,
|
|
5
|
-
|
|
9
|
+
aTimeout,
|
|
6
10
|
fixture,
|
|
11
|
+
expect,
|
|
7
12
|
html,
|
|
8
|
-
unsafeStatic,
|
|
9
|
-
fixtureSync,
|
|
10
13
|
} from '@open-wc/testing';
|
|
11
|
-
|
|
12
|
-
import { OverlayController, overlays } from '@lion/ui/overlays.js';
|
|
13
|
-
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
|
14
|
-
import { keyCodes } from '../src/utils/key-codes.js';
|
|
15
|
-
import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
16
|
-
import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
|
|
14
|
+
|
|
17
15
|
import { createShadowHost } from '../test-helpers/createShadowHost.js';
|
|
16
|
+
import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
|
|
17
|
+
import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
18
|
+
import { keyCodes } from '../src/utils/key-codes.js';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
|
-
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
21
21
|
* @typedef {import('../types/OverlayConfig.js').ViewportPlacement} ViewportPlacement
|
|
22
|
+
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
25
|
const wrappingDialogNodeStyle = 'display: none; z-index: 9999; padding: 0px;';
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A small wrapper function that closely mimics an escape press from a user
|
|
29
|
+
* (prevents common mistakes like no bubbling or keydown)
|
|
30
|
+
* @param {Element|Document} element
|
|
31
|
+
*/
|
|
32
|
+
async function mimicEscapePress(element) {
|
|
33
|
+
element.dispatchEvent(
|
|
34
|
+
new KeyboardEvent('keyup', { key: 'Escape', bubbles: true, composed: true }),
|
|
35
|
+
);
|
|
36
|
+
await aTimeout(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
/**
|
|
27
40
|
* Make sure that all browsers serialize html in a similar way
|
|
28
41
|
* (Firefox tends to output empty style attrs)
|
|
@@ -74,6 +87,50 @@ const withLocalTestConfig = () =>
|
|
|
74
87
|
),
|
|
75
88
|
});
|
|
76
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @param {HTMLDivElement} parentContent
|
|
92
|
+
* @returns {Promise<{parentOverlay: OverlayController; childOverlay: OverlayController}>}
|
|
93
|
+
*/
|
|
94
|
+
async function createNestedEscControllers(parentContent) {
|
|
95
|
+
const childContent = /** @type {HTMLDivElement} */ (parentContent.querySelector('div[id]'));
|
|
96
|
+
// Assert valid fixure
|
|
97
|
+
const isValid =
|
|
98
|
+
(parentContent.id === 'parent-overlay--hidesOnEsc' ||
|
|
99
|
+
parentContent.id === 'parent-overlay--hidesOnOutsideEsc') &&
|
|
100
|
+
(childContent.id === 'child-overlay--hidesOnEsc' ||
|
|
101
|
+
childContent.id === 'child-overlay--hidesOnOutsideEsc');
|
|
102
|
+
if (!isValid) {
|
|
103
|
+
throw new Error('Provide a valid fixture');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (parentContent.hasAttribute('data-convert-to-shadow-root')) {
|
|
107
|
+
const shadowRootParent = parentContent.attachShadow({ mode: 'open' });
|
|
108
|
+
shadowRootParent.appendChild(childContent);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const parentHasOutsideOnEsc = parentContent.id === 'parent-overlay--hidesOnOutsideEsc';
|
|
112
|
+
const childHasOutsideOnEsc = childContent.id === 'child-overlay--hidesOnOutsideEsc';
|
|
113
|
+
|
|
114
|
+
const parentConfig = parentHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
|
|
115
|
+
const childConfig = childHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
|
|
116
|
+
|
|
117
|
+
const parentOverlay = new OverlayController({
|
|
118
|
+
...withGlobalTestConfig(),
|
|
119
|
+
contentNode: parentContent,
|
|
120
|
+
...parentConfig,
|
|
121
|
+
});
|
|
122
|
+
const childOverlay = new OverlayController({
|
|
123
|
+
...withGlobalTestConfig(),
|
|
124
|
+
contentNode: childContent,
|
|
125
|
+
...childConfig,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await parentOverlay.show();
|
|
129
|
+
await childOverlay.show();
|
|
130
|
+
|
|
131
|
+
return { parentOverlay, childOverlay };
|
|
132
|
+
}
|
|
133
|
+
|
|
77
134
|
afterEach(() => {
|
|
78
135
|
overlays.teardown();
|
|
79
136
|
});
|
|
@@ -574,74 +631,221 @@ describe('OverlayController', () => {
|
|
|
574
631
|
});
|
|
575
632
|
|
|
576
633
|
describe('hidesOnEsc', () => {
|
|
577
|
-
it('hides
|
|
634
|
+
it('hides on [Escape] press', async () => {
|
|
578
635
|
const ctrl = new OverlayController({
|
|
579
636
|
...withGlobalTestConfig(),
|
|
580
637
|
hidesOnEsc: true,
|
|
581
638
|
});
|
|
582
639
|
await ctrl.show();
|
|
583
|
-
ctrl.contentNode
|
|
584
|
-
await aTimeout(0);
|
|
640
|
+
await mimicEscapePress(ctrl.contentNode);
|
|
585
641
|
expect(ctrl.isShown).to.be.false;
|
|
586
642
|
});
|
|
587
643
|
|
|
588
|
-
it(
|
|
644
|
+
it('stays shown on [Escape] press with `.hidesOnEsc` set to false', async () => {
|
|
589
645
|
const ctrl = new OverlayController({
|
|
590
646
|
...withGlobalTestConfig(),
|
|
591
647
|
hidesOnEsc: false,
|
|
592
648
|
});
|
|
593
649
|
await ctrl.show();
|
|
594
|
-
ctrl.contentNode
|
|
595
|
-
await aTimeout(0);
|
|
650
|
+
await mimicEscapePress(ctrl.contentNode);
|
|
596
651
|
expect(ctrl.isShown).to.be.true;
|
|
597
652
|
});
|
|
598
653
|
|
|
599
|
-
it('stays shown
|
|
654
|
+
it('stays shown on [Escape] press on outside element', async () => {
|
|
600
655
|
const ctrl = new OverlayController({
|
|
601
656
|
...withGlobalTestConfig(),
|
|
602
657
|
hidesOnEsc: true,
|
|
603
658
|
});
|
|
604
659
|
await ctrl.show();
|
|
605
|
-
|
|
660
|
+
await mimicEscapePress(document);
|
|
606
661
|
expect(ctrl.isShown).to.be.true;
|
|
607
662
|
});
|
|
608
663
|
|
|
609
|
-
it('
|
|
664
|
+
it('stays shown on [Escape] press with modal <dialog> and `.hidesOnEsc` is false', async () => {
|
|
610
665
|
const ctrl = new OverlayController({
|
|
611
666
|
...withGlobalTestConfig(),
|
|
612
667
|
trapsKeyboardFocus: true,
|
|
613
668
|
hidesOnEsc: false,
|
|
614
669
|
});
|
|
615
670
|
await ctrl.show();
|
|
616
|
-
ctrl.contentNode
|
|
617
|
-
await aTimeout(0);
|
|
671
|
+
await mimicEscapePress(ctrl.contentNode);
|
|
618
672
|
expect(ctrl.isShown).to.be.true;
|
|
619
673
|
});
|
|
674
|
+
|
|
675
|
+
it('parent stays shown on [Escape] press in a nested overlay', async () => {
|
|
676
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
677
|
+
await fixture(
|
|
678
|
+
html` <!-- -->
|
|
679
|
+
<div id="parent-overlay--hidesOnEsc">
|
|
680
|
+
<div id="child-overlay--hidesOnEsc">we press [Escape] here</div>
|
|
681
|
+
</div>`,
|
|
682
|
+
)
|
|
683
|
+
);
|
|
684
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
685
|
+
await mimicEscapePress(childOverlay.contentNode);
|
|
686
|
+
|
|
687
|
+
expect(parentOverlay.isShown).to.be.true;
|
|
688
|
+
expect(childOverlay.isShown).to.be.false;
|
|
689
|
+
});
|
|
620
690
|
});
|
|
621
691
|
|
|
622
692
|
describe('hidesOnOutsideEsc', () => {
|
|
623
|
-
it('hides
|
|
693
|
+
it('hides on [Escape] press on outside element', async () => {
|
|
624
694
|
const ctrl = new OverlayController({
|
|
625
695
|
...withGlobalTestConfig(),
|
|
626
696
|
hidesOnOutsideEsc: true,
|
|
627
697
|
});
|
|
628
698
|
await ctrl.show();
|
|
629
|
-
|
|
630
|
-
await aTimeout(0);
|
|
699
|
+
await mimicEscapePress(document);
|
|
631
700
|
expect(ctrl.isShown).to.be.false;
|
|
632
701
|
});
|
|
633
702
|
|
|
634
|
-
it('stays shown
|
|
703
|
+
it('stays shown on [Escape] press on inside element', async () => {
|
|
635
704
|
const ctrl = new OverlayController({
|
|
636
705
|
...withGlobalTestConfig(),
|
|
637
706
|
hidesOnOutsideEsc: true,
|
|
638
707
|
});
|
|
639
708
|
await ctrl.show();
|
|
640
|
-
ctrl.contentNode
|
|
709
|
+
await mimicEscapePress(ctrl.contentNode);
|
|
641
710
|
expect(ctrl.isShown).to.be.true;
|
|
642
711
|
});
|
|
712
|
+
|
|
713
|
+
it('stays shown on [Escape] press in a nested overlay', async () => {
|
|
714
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
715
|
+
await fixture(
|
|
716
|
+
html` <!-- -->
|
|
717
|
+
<div id="parent-overlay--hidesOnOutsideEsc">
|
|
718
|
+
<div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
|
|
719
|
+
</div>`,
|
|
720
|
+
)
|
|
721
|
+
);
|
|
722
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
723
|
+
mimicEscapePress(childOverlay.contentNode);
|
|
724
|
+
|
|
725
|
+
expect(parentOverlay.isShown).to.be.true;
|
|
726
|
+
expect(childOverlay.isShown).to.be.true;
|
|
727
|
+
});
|
|
643
728
|
});
|
|
644
729
|
|
|
730
|
+
describe('Nested hidesOnEsc / hidesOnOutsideEsc', () => {
|
|
731
|
+
describe('Parent has hidesOnEsc and child has hidesOnOutsideEsc', () => {
|
|
732
|
+
it('on [Escape] press in child overlay: parent hides, child stays shown', async () => {
|
|
733
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
734
|
+
await fixture(
|
|
735
|
+
html` <!-- -->
|
|
736
|
+
<div id="parent-overlay--hidesOnEsc">
|
|
737
|
+
<div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
|
|
738
|
+
</div>`,
|
|
739
|
+
)
|
|
740
|
+
);
|
|
741
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
742
|
+
await mimicEscapePress(childOverlay.contentNode);
|
|
743
|
+
|
|
744
|
+
expect(parentOverlay.isShown).to.be.false;
|
|
745
|
+
expect(childOverlay.isShown).to.be.true;
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it('on [Escape] press outside overlays: parent stays shown, child hides', async () => {
|
|
749
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
750
|
+
await fixture(
|
|
751
|
+
html` <!-- we press [Escape] here -->
|
|
752
|
+
<div id="parent-overlay--hidesOnEsc">
|
|
753
|
+
<div id="child-overlay--hidesOnOutsideEsc"></div>
|
|
754
|
+
</div>`,
|
|
755
|
+
)
|
|
756
|
+
);
|
|
757
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
758
|
+
await mimicEscapePress(document);
|
|
759
|
+
|
|
760
|
+
expect(parentOverlay.isShown).to.be.true;
|
|
761
|
+
expect(childOverlay.isShown).to.be.false;
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
it('on [Escape] press in parent overlay: parent is hidden, child is hidden', async () => {
|
|
765
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
766
|
+
await fixture(
|
|
767
|
+
html` <!-- -->
|
|
768
|
+
<div id="parent-overlay--hidesOnEsc">
|
|
769
|
+
we press [Escape] here
|
|
770
|
+
<div id="child-overlay--hidesOnOutsideEsc"></div>
|
|
771
|
+
</div>`,
|
|
772
|
+
)
|
|
773
|
+
);
|
|
774
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
775
|
+
await mimicEscapePress(parentContent);
|
|
776
|
+
|
|
777
|
+
expect(parentOverlay.isShown).to.be.false;
|
|
778
|
+
expect(childOverlay.isShown).to.be.false;
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
describe('Parent has hidesOnOutsideEsc and child has hidesOnEsc', () => {
|
|
782
|
+
it('on [Escape] press in child overlay: parent stays shown, child hides', async () => {
|
|
783
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
784
|
+
await fixture(
|
|
785
|
+
html` <!-- -->
|
|
786
|
+
<div id="parent-overlay--hidesOnOutsideEsc">
|
|
787
|
+
<div id="child-overlay--hidesOnEsc">we press [Escape] here</div>
|
|
788
|
+
</div>`,
|
|
789
|
+
)
|
|
790
|
+
);
|
|
791
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
792
|
+
await mimicEscapePress(childOverlay.contentNode);
|
|
793
|
+
|
|
794
|
+
expect(parentOverlay.isShown).to.be.true;
|
|
795
|
+
expect(childOverlay.isShown).to.be.false;
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
it('on [Escape] press outside overlays: parent hides, child stays shown', async () => {
|
|
799
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
800
|
+
await fixture(
|
|
801
|
+
html` <!-- we press [Escape] here -->
|
|
802
|
+
<div id="parent-overlay--hidesOnOutsideEsc">
|
|
803
|
+
<div id="child-overlay--hidesOnEsc"></div>
|
|
804
|
+
</div>`,
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
808
|
+
await mimicEscapePress(document);
|
|
809
|
+
|
|
810
|
+
expect(parentOverlay.isShown).to.be.false;
|
|
811
|
+
expect(childOverlay.isShown).to.be.true;
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it('on [Escape] press in parent overlay: parent hides, child stays shown', async () => {
|
|
815
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
816
|
+
await fixture(
|
|
817
|
+
html` <!-- we press [Escape] here -->
|
|
818
|
+
<div id="parent-overlay--hidesOnOutsideEsc">
|
|
819
|
+
<div id="child-overlay--hidesOnEsc"></div>
|
|
820
|
+
</div>`,
|
|
821
|
+
)
|
|
822
|
+
);
|
|
823
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
824
|
+
await mimicEscapePress(document);
|
|
825
|
+
|
|
826
|
+
expect(parentOverlay.isShown).to.be.false;
|
|
827
|
+
expect(childOverlay.isShown).to.be.true;
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
describe('With shadow dom', () => {
|
|
832
|
+
it('on [Escape] press in child overlay in shadow root: parent hides, child stays shown', async () => {
|
|
833
|
+
const parentContent = /** @type {HTMLDivElement} */ (
|
|
834
|
+
await fixture(
|
|
835
|
+
html` <!-- -->
|
|
836
|
+
<div id="parent-overlay--hidesOnEsc" data-convert-to-shadow-root>
|
|
837
|
+
<div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
|
|
838
|
+
</div>`,
|
|
839
|
+
)
|
|
840
|
+
);
|
|
841
|
+
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
|
|
842
|
+
await mimicEscapePress(childOverlay.contentNode);
|
|
843
|
+
|
|
844
|
+
expect(parentOverlay.isShown).to.be.false;
|
|
845
|
+
expect(childOverlay.isShown).to.be.true;
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
});
|
|
645
849
|
describe('hidesOnOutsideClick', () => {
|
|
646
850
|
it('hides on outside click', async () => {
|
|
647
851
|
const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
|
|
@@ -684,9 +888,8 @@ describe('OverlayController', () => {
|
|
|
684
888
|
expect(ctrl.isShown).to.be.true;
|
|
685
889
|
|
|
686
890
|
// Don't hide on inside mousedown & outside mouseup
|
|
687
|
-
ctrl.contentNode.
|
|
688
|
-
|
|
689
|
-
document.body.dispatchEvent(new MouseEvent('mouseup'));
|
|
891
|
+
await mimicClick(ctrl.contentNode, { releaseElement: document.body, isAsync: true });
|
|
892
|
+
|
|
690
893
|
await aTimeout(0);
|
|
691
894
|
expect(ctrl.isShown).to.be.true;
|
|
692
895
|
|
|
@@ -8,9 +8,9 @@ async function sleep(t = 0) {
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @param {HTMLElement} el
|
|
11
|
-
* @param {{isAsync?:boolean, releaseElement?: HTMLElement}} config
|
|
11
|
+
* @param {{isAsync?:boolean, releaseElement?: HTMLElement}} config releaseElement can be different when the mouse is dragged before release
|
|
12
12
|
*/
|
|
13
|
-
export async function mimicClick(el, { isAsync, releaseElement } = {
|
|
13
|
+
export async function mimicClick(el, { isAsync = false, releaseElement } = {}) {
|
|
14
14
|
const releaseEl = releaseElement || el;
|
|
15
15
|
el.dispatchEvent(new MouseEvent('mousedown'));
|
|
16
16
|
if (isAsync) {
|
package/custom-elements.json
CHANGED
|
@@ -114306,10 +114306,11 @@
|
|
|
114306
114306
|
}
|
|
114307
114307
|
},
|
|
114308
114308
|
{
|
|
114309
|
-
"name": "{ isAsync, releaseElement }",
|
|
114310
|
-
"default": "{
|
|
114309
|
+
"name": "{ isAsync = false, releaseElement }",
|
|
114310
|
+
"default": "{}"
|
|
114311
114311
|
},
|
|
114312
114312
|
{
|
|
114313
|
+
"description": "releaseElement can be different when the mouse is dragged before release",
|
|
114313
114314
|
"name": "config",
|
|
114314
114315
|
"type": {
|
|
114315
114316
|
"text": "{isAsync?:boolean, releaseElement?: HTMLElement}"
|
|
@@ -114997,10 +114998,36 @@
|
|
|
114997
114998
|
"name": "__escKeyHandler",
|
|
114998
114999
|
"parameters": [
|
|
114999
115000
|
{
|
|
115000
|
-
"name": "
|
|
115001
|
+
"name": "event",
|
|
115002
|
+
"type": {
|
|
115003
|
+
"text": "KeyboardEvent"
|
|
115004
|
+
}
|
|
115001
115005
|
}
|
|
115002
115006
|
],
|
|
115003
|
-
"
|
|
115007
|
+
"return": {
|
|
115008
|
+
"type": {
|
|
115009
|
+
"text": "void"
|
|
115010
|
+
}
|
|
115011
|
+
},
|
|
115012
|
+
"privacy": "protected"
|
|
115013
|
+
},
|
|
115014
|
+
{
|
|
115015
|
+
"kind": "field",
|
|
115016
|
+
"name": "#outsideEscKeyHandler",
|
|
115017
|
+
"privacy": "private",
|
|
115018
|
+
"parameters": [
|
|
115019
|
+
{
|
|
115020
|
+
"name": "event",
|
|
115021
|
+
"type": {
|
|
115022
|
+
"text": "KeyboardEvent"
|
|
115023
|
+
}
|
|
115024
|
+
}
|
|
115025
|
+
],
|
|
115026
|
+
"return": {
|
|
115027
|
+
"type": {
|
|
115028
|
+
"text": "void"
|
|
115029
|
+
}
|
|
115030
|
+
}
|
|
115004
115031
|
},
|
|
115005
115032
|
{
|
|
115006
115033
|
"kind": "method",
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @param {LionForm} formGroupEl
|
|
7
7
|
*/
|
|
8
|
-
export function getAllFormElements(formGroupEl: LionForm): any
|
|
8
|
+
export function getAllFormElements(formGroupEl: LionForm): any;
|
|
9
9
|
/**
|
|
10
10
|
* @param {LionForm} formGroupEl
|
|
11
11
|
*/
|
|
12
|
-
export function getAllTagNames(formGroupEl: LionForm): any
|
|
12
|
+
export function getAllTagNames(formGroupEl: LionForm): any;
|
|
13
13
|
/**
|
|
14
14
|
* @param {LionForm} formGroupEl
|
|
15
15
|
*/
|
|
16
|
-
export function getAllFieldsAndFormGroups(formGroupEl: LionForm): any
|
|
16
|
+
export function getAllFieldsAndFormGroups(formGroupEl: LionForm): any;
|
|
17
17
|
export type LionForm = import('../../../form/src/LionForm.js').LionForm;
|
|
18
18
|
export type LionField = import('../../../form-core/src/LionField.js').LionField;
|
|
19
19
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../components/form-integrations/test/helpers/helpers.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,gDAFW,QAAQ,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../components/form-integrations/test/helpers/helpers.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,gDAFW,QAAQ,OAWlB;AAED;;GAEG;AACH,4CAFW,QAAQ,OAWlB;AAED;;GAEG;AACH,uDAFW,QAAQ,OAKlB;uBAtCY,OAAO,+BAA+B,EAAE,QAAQ;wBAChD,OAAO,qCAAqC,EAAE,SAAS"}
|
|
@@ -31,8 +31,11 @@ export class OverlayController extends EventTarget {
|
|
|
31
31
|
private __hasActiveTrapsKeyboardFocus;
|
|
32
32
|
/** @private */
|
|
33
33
|
private __hasActiveBackdrop;
|
|
34
|
-
/**
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @param {KeyboardEvent} event
|
|
36
|
+
* @returns {void}
|
|
37
|
+
*/
|
|
38
|
+
__escKeyHandler(event: KeyboardEvent): void;
|
|
36
39
|
/**
|
|
37
40
|
* When the overlay is a modal dialog hidesOnEsc works out of the box, so we prevent that.
|
|
38
41
|
*
|
|
@@ -434,17 +437,18 @@ export class OverlayController extends EventTarget {
|
|
|
434
437
|
private __createPopperInstance;
|
|
435
438
|
_popper: any;
|
|
436
439
|
_hasDisabledInvoker(): boolean;
|
|
440
|
+
#private;
|
|
437
441
|
}
|
|
438
442
|
export namespace OverlayController {
|
|
439
443
|
const popperModule: Promise<PopperModule> | undefined;
|
|
440
444
|
}
|
|
441
|
-
export type
|
|
445
|
+
export type OverlayPhase = 'setup' | 'init' | 'teardown' | 'before-show' | 'show' | 'hide' | 'add' | 'remove';
|
|
442
446
|
export type ViewportConfig = import('@lion/ui/types/overlays.js').ViewportConfig;
|
|
443
|
-
export type
|
|
447
|
+
export type OverlayConfig = import('@lion/ui/types/overlays.js').OverlayConfig;
|
|
444
448
|
export type PopperOptions = import('@popperjs/core').Options;
|
|
445
449
|
export type Placement = import('@popperjs/core').Placement;
|
|
450
|
+
export type Popper = any;
|
|
446
451
|
export type PopperModule = {
|
|
447
452
|
createPopper: Popper;
|
|
448
453
|
};
|
|
449
|
-
export type OverlayPhase = 'setup' | 'init' | 'teardown' | 'before-show' | 'show' | 'hide' | 'add' | 'remove';
|
|
450
454
|
//# sourceMappingURL=OverlayController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayController.d.ts","sourceRoot":"","sources":["../../../../components/overlays/src/OverlayController.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OverlayController.d.ts","sourceRoot":"","sources":["../../../../components/overlays/src/OverlayController.js"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type OverlayConfig = import('../types/OverlayConfig.js').OverlayConfig;
|
|
2
1
|
export type ViewportPlacement = import('../types/OverlayConfig.js').ViewportPlacement;
|
|
2
|
+
export type OverlayConfig = import('../types/OverlayConfig.js').OverlayConfig;
|
|
3
3
|
//# sourceMappingURL=OverlayController.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayController.test.d.ts","sourceRoot":"","sources":["../../../../components/overlays/test/OverlayController.test.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OverlayController.test.d.ts","sourceRoot":"","sources":["../../../../components/overlays/test/OverlayController.test.js"],"names":[],"mappings":"gCAoBa,OAAO,2BAA2B,EAAE,iBAAiB;4BACrD,OAAO,2BAA2B,EAAE,aAAa"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @param {HTMLElement} el
|
|
3
|
-
* @param {{isAsync?:boolean, releaseElement?: HTMLElement}} config
|
|
3
|
+
* @param {{isAsync?:boolean, releaseElement?: HTMLElement}} config releaseElement can be different when the mouse is dragged before release
|
|
4
4
|
*/
|
|
5
5
|
export function mimicClick(el: HTMLElement, { isAsync, releaseElement }?: {
|
|
6
6
|
isAsync?: boolean;
|