@lion/ui 0.0.9 → 0.0.11
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/accordion/src/LionAccordion.js +2 -2
- package/components/core/src/SlotMixin.js +2 -1
- package/components/dialog/src/LionDialog.js +0 -28
- package/components/dialog/test/lion-dialog.test.js +11 -10
- package/components/form-integrations/test/form-group-methods.test.js +6 -4
- package/components/form-integrations/test/form-integrations.test.js +10 -5
- package/components/form-integrations/test/helpers/umbrella-form.js +10 -0
- package/components/form-integrations/test/model-value-consistency.test.js +29 -20
- package/components/input-datepicker/src/LionInputDatepicker.js +66 -104
- package/components/input-datepicker/src/localizeNamespaceLoader.js +188 -0
- package/components/input-datepicker/test/lion-input-datepicker.test.js +15 -20
- package/components/input-datepicker/test-helpers/DatepickerInputObject.js +3 -3
- package/components/input-tel/src/parsers.js +1 -1
- package/components/listbox/test-suites/ListboxMixin.suite.js +3 -3
- package/components/localize/src/singleton.js +1 -1
- package/components/localize/test/number/formatNumber.test.js +2 -6
- package/components/overlays/src/OverlayController.js +292 -291
- package/components/overlays/src/OverlayMixin.js +17 -18
- package/components/overlays/src/OverlaysManager.js +28 -53
- package/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.js +32 -0
- package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +76 -0
- package/components/overlays/src/configurations/withBottomSheetConfig.js +3 -0
- package/components/overlays/src/configurations/withDropdownConfig.js +3 -0
- package/components/overlays/src/configurations/withModalDialogConfig.js +3 -0
- package/components/overlays/src/configurations/withTooltipConfig.js +29 -0
- package/components/overlays/src/overlayDocumentStyle.js +24 -0
- package/components/overlays/src/overlayShadowDomStyle.js +138 -0
- package/components/overlays/src/singleton.js +3 -1
- package/components/overlays/test/ArrowMixin.test.js +0 -1
- package/components/overlays/test/OverlayController.test.js +372 -274
- package/components/overlays/test/OverlaysManager.test.js +23 -32
- package/components/overlays/test/global-positioning.test.js +4 -15
- package/components/overlays/test/local-positioning.test.js +65 -38
- package/components/overlays/test-suites/OverlayMixin.suite.js +18 -26
- package/components/overlays/types/OverlayConfig.ts +38 -11
- package/components/overlays/types/OverlayMixinTypes.ts +2 -2
- package/components/select-rich/src/LionSelectInvoker.js +2 -3
- package/components/select-rich/src/LionSelectRich.js +22 -20
- package/components/select-rich/test/lion-select-rich.test.js +5 -7
- package/components/tooltip/src/LionTooltip.js +3 -90
- package/components/tooltip/test/lion-tooltip.test.js +52 -20
- package/custom-elements.json +535 -503
- package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +0 -2
- package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
- package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts +4 -0
- package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts.map +1 -1
- package/dist-types/components/form-integrations/test/model-value-consistency.test.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +3 -3
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts +4 -0
- package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -0
- package/dist-types/components/overlays/src/OverlayController.d.ts +56 -101
- 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/OverlaysManager.d.ts +0 -7
- package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
- package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.d.ts +12 -0
- package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.d.ts.map +1 -0
- package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts +18 -0
- package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts.map +1 -0
- package/dist-types/components/overlays/src/configurations/withBottomSheetConfig.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/withModalDialogConfig.d.ts.map +1 -1
- package/dist-types/components/overlays/src/configurations/withTooltipConfig.d.ts +8 -0
- package/dist-types/components/overlays/src/configurations/withTooltipConfig.d.ts.map +1 -0
- package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts +2 -0
- package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -0
- package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts +2 -0
- package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts.map +1 -0
- package/dist-types/components/overlays/src/singleton.d.ts +2 -1
- package/dist-types/components/overlays/src/singleton.d.ts.map +1 -1
- package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayConfig.d.ts +19 -10
- package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +2 -2
- package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -27
- package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +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/components/tooltip/src/LionTooltip.d.ts +4 -20
- package/dist-types/components/tooltip/src/LionTooltip.d.ts.map +1 -1
- package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts.map +1 -1
- package/dist-types/exports/input-datepicker.d.ts +0 -1
- package/dist-types/exports/overlays.d.ts +1 -1
- package/dist-types/exports/types/overlays.d.ts +1 -0
- package/dist-types/exports/types/overlays.d.ts.map +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 +5 -9
- package/docs/components/dialog/use-cases.md +43 -87
- 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-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/radio-group/overview.md +3 -3
- 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/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/use-cases.md +4 -0
- package/docs/fundamentals/systems/form/validate.md +1 -1
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/assets/{applyDemoOverlayStyles.js → applyDemoOverlayStyles.mjs} +2 -1
- package/docs/fundamentals/systems/overlays/assets/demo-el-using-overlaymixin.mjs +119 -0
- package/docs/fundamentals/systems/overlays/assets/{demo-overlay-backdrop.js → demo-overlay-backdrop.mjs} +3 -4
- package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +537 -0
- package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +9 -2
- package/docs/fundamentals/systems/overlays/configuration.md +56 -54
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +83 -77
- 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 +6 -6
- package/docs/guides/how-to/extend-a-native-input.md +3 -3
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/exports/input-datepicker.js +0 -1
- package/exports/overlays.js +1 -1
- package/exports/types/overlays.ts +1 -0
- package/package.json +2 -1
- package/components/input-datepicker/src/LionCalendarOverlayFrame.js +0 -125
- package/components/overlays/src/globalOverlaysStyle.js +0 -139
- package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts +0 -10
- package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts.map +0 -1
- package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts +0 -2
- package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts.map +0 -1
- package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts +0 -2
- package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts.map +0 -1
- package/docs/fundamentals/systems/overlays/assets/demo-overlay-system.js +0 -42
- package/docs/fundamentals/systems/overlays/form-integration.md +0 -65
- package/docs/fundamentals/systems/overlays/scope.md +0 -176
- package/exports/define/lion-calendar-overlay-frame.js +0 -3
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import sinon from 'sinon';
|
|
12
12
|
import { OverlayController, overlays } from '@lion/ui/overlays.js';
|
|
13
13
|
import { mimicClick } from '@lion/ui/overlays-test-helpers.js';
|
|
14
|
-
|
|
14
|
+
import { overlayShadowDomStyle } from '../src/overlayShadowDomStyle.js';
|
|
15
15
|
import { keyCodes } from '../src/utils/key-codes.js';
|
|
16
16
|
import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
17
17
|
|
|
@@ -20,6 +20,33 @@ import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
|
20
20
|
* @typedef {import('../types/OverlayConfig.js').ViewportPlacement} ViewportPlacement
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
const wrappingDialogNodeStyle = 'display: none; z-index: 9999;';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns element that adopts stylesheet
|
|
27
|
+
* @param {Element} shadowOrBodyEl
|
|
28
|
+
* @returns {ShadowRoot}
|
|
29
|
+
*/
|
|
30
|
+
function getRootNodeOrBodyElThatAdoptsStylesheet(shadowOrBodyEl) {
|
|
31
|
+
const rootNode = /** @type {* & DocumentOrShadowRoot} */ (shadowOrBodyEl.getRootNode());
|
|
32
|
+
if (rootNode === document) {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
return document.body;
|
|
35
|
+
}
|
|
36
|
+
return rootNode;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Make sure that all browsers serialize html in a similar way
|
|
41
|
+
* (Firefox tends to output empty style attrs)
|
|
42
|
+
* @param {HTMLElement} node
|
|
43
|
+
*/
|
|
44
|
+
function normalizeOverlayContentWapper(node) {
|
|
45
|
+
if (node.hasAttribute('style') && !node.style.cssText) {
|
|
46
|
+
node.removeAttribute('style');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
23
50
|
/**
|
|
24
51
|
* @param {OverlayController} overlayControllerEl
|
|
25
52
|
*/
|
|
@@ -66,7 +93,56 @@ describe('OverlayController', () => {
|
|
|
66
93
|
...withGlobalTestConfig(),
|
|
67
94
|
});
|
|
68
95
|
expect(ctrl.content).not.to.be.undefined;
|
|
69
|
-
expect(ctrl.contentNode.parentElement).to.equal(ctrl.
|
|
96
|
+
expect(ctrl.contentNode.parentElement).to.equal(ctrl.contentWrapperNode);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('Stylesheets', () => {
|
|
100
|
+
it('adds a stylesheet to the body when contentWrapper is located there', async () => {
|
|
101
|
+
new OverlayController({
|
|
102
|
+
...withLocalTestConfig(),
|
|
103
|
+
});
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
if (document.body.adoptedStyleSheets) {
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
expect(document.body.adoptedStyleSheets).to.include(overlayShadowDomStyle.styleSheet);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('adds a stylesheet to the shadowRoot when contentWrappeNode is located there', async () => {
|
|
112
|
+
const contentNode = /** @type {HTMLElement} */ (await fixture('<div>contentful</div>'));
|
|
113
|
+
const shadowHost = document.createElement('div');
|
|
114
|
+
shadowHost.attachShadow({ mode: 'open' });
|
|
115
|
+
/** @type {ShadowRoot} */ (shadowHost.shadowRoot).innerHTML = `<slot></slot>`;
|
|
116
|
+
shadowHost.appendChild(contentNode);
|
|
117
|
+
document.body.appendChild(shadowHost);
|
|
118
|
+
const ctrl = new OverlayController({
|
|
119
|
+
...withLocalTestConfig(),
|
|
120
|
+
contentNode,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const rootNodeOrBody = getRootNodeOrBodyElThatAdoptsStylesheet(ctrl.contentWrapperNode);
|
|
124
|
+
expect(rootNodeOrBody).to.not.equal(document.body);
|
|
125
|
+
|
|
126
|
+
if (rootNodeOrBody.adoptedStyleSheets) {
|
|
127
|
+
expect(rootNodeOrBody.adoptedStyleSheets).to.include(overlayShadowDomStyle.styleSheet);
|
|
128
|
+
}
|
|
129
|
+
document.body.removeChild(shadowHost);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('does not add same stylesheet twice', async () => {
|
|
133
|
+
// @ts-ignore
|
|
134
|
+
if (!document.body.adoptedStyleSheets) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
new OverlayController({ ...withLocalTestConfig() });
|
|
139
|
+
// @ts-ignore
|
|
140
|
+
const amountOfStylesheetsAfterOneInit = document.body.adoptedStyleSheets.length;
|
|
141
|
+
|
|
142
|
+
new OverlayController({ ...withLocalTestConfig() });
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
expect(document.body.adoptedStyleSheets.length).to.equal(amountOfStylesheetsAfterOneInit);
|
|
145
|
+
});
|
|
70
146
|
});
|
|
71
147
|
|
|
72
148
|
describe('Z-index on local overlays', () => {
|
|
@@ -106,17 +182,21 @@ describe('OverlayController', () => {
|
|
|
106
182
|
contentNode: await createZNode('auto', { mode: 'global' }),
|
|
107
183
|
});
|
|
108
184
|
await ctrl.show();
|
|
109
|
-
expect
|
|
185
|
+
// @ts-expect-error find out why config would/could be undfined
|
|
186
|
+
expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
|
|
110
187
|
ctrl.updateConfig({ contentNode: await createZNode('auto', { mode: 'inline' }) });
|
|
111
188
|
await ctrl.show();
|
|
112
|
-
expect
|
|
189
|
+
// @ts-expect-error find out why config would/could be undfined
|
|
190
|
+
expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
|
|
113
191
|
|
|
114
192
|
ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'global' }) });
|
|
115
193
|
await ctrl.show();
|
|
116
|
-
expect
|
|
194
|
+
// @ts-expect-error find out why config would/could be undfined
|
|
195
|
+
expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
|
|
117
196
|
ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'inline' }) });
|
|
118
197
|
await ctrl.show();
|
|
119
|
-
expect
|
|
198
|
+
// @ts-expect-error find out why config would/could be undfined
|
|
199
|
+
expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
|
|
120
200
|
});
|
|
121
201
|
|
|
122
202
|
it.skip("doesn't set a z-index when contentNode already has >= 1", async () => {
|
|
@@ -147,42 +227,7 @@ describe('OverlayController', () => {
|
|
|
147
227
|
});
|
|
148
228
|
});
|
|
149
229
|
|
|
150
|
-
describe('
|
|
151
|
-
it('creates global target for placement mode "global"', async () => {
|
|
152
|
-
const ctrl = new OverlayController({
|
|
153
|
-
...withGlobalTestConfig(),
|
|
154
|
-
});
|
|
155
|
-
const { renderTarget } = getProtectedMembers(ctrl);
|
|
156
|
-
expect(renderTarget).to.equal(overlays.globalRootNode);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it.skip('creates local target next to sibling for placement mode "local"', async () => {
|
|
160
|
-
const ctrl = new OverlayController({
|
|
161
|
-
...withLocalTestConfig(),
|
|
162
|
-
invokerNode: /** @type {HTMLElement} */ (await fixture(html`<button>Invoker</button>`)),
|
|
163
|
-
});
|
|
164
|
-
const { renderTarget } = getProtectedMembers(ctrl);
|
|
165
|
-
expect(renderTarget).to.be.undefined;
|
|
166
|
-
expect(ctrl.content).to.equal(ctrl.invokerNode?.nextElementSibling);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('keeps local target for placement mode "local" when already connected', async () => {
|
|
170
|
-
const parentNode = /** @type {HTMLElement} */ (
|
|
171
|
-
await fixture(html`
|
|
172
|
-
<div id="parent">
|
|
173
|
-
<div id="content">Content</div>
|
|
174
|
-
</div>
|
|
175
|
-
`)
|
|
176
|
-
);
|
|
177
|
-
const contentNode = /** @type {HTMLElement} */ (parentNode.querySelector('#content'));
|
|
178
|
-
const ctrl = new OverlayController({
|
|
179
|
-
...withLocalTestConfig(),
|
|
180
|
-
contentNode,
|
|
181
|
-
});
|
|
182
|
-
const { renderTarget } = getProtectedMembers(ctrl);
|
|
183
|
-
expect(renderTarget).to.equal(parentNode);
|
|
184
|
-
});
|
|
185
|
-
|
|
230
|
+
describe('Offline content', () => {
|
|
186
231
|
it('throws when passing a content node that was created "offline"', async () => {
|
|
187
232
|
const contentNode = document.createElement('div');
|
|
188
233
|
const createOverlayController = () => {
|
|
@@ -197,113 +242,250 @@ describe('OverlayController', () => {
|
|
|
197
242
|
});
|
|
198
243
|
|
|
199
244
|
it('succeeds when passing a content node that was created "online"', async () => {
|
|
200
|
-
const contentNode =
|
|
201
|
-
document.body.appendChild(contentNode);
|
|
245
|
+
const contentNode = /** @type {HTMLElement} */ (fixtureSync('<div>'));
|
|
202
246
|
const overlay = new OverlayController({
|
|
203
247
|
...withLocalTestConfig(),
|
|
204
248
|
contentNode,
|
|
205
249
|
});
|
|
206
|
-
const { renderTarget } = getProtectedMembers(overlay);
|
|
207
|
-
|
|
208
250
|
expect(overlay.contentNode.isConnected).to.be.true;
|
|
209
|
-
expect(renderTarget).to.not.be.undefined;
|
|
210
251
|
});
|
|
211
252
|
});
|
|
212
253
|
});
|
|
213
254
|
|
|
214
255
|
// TODO: Add teardown feature tests
|
|
215
|
-
describe('Teardown', () => {
|
|
216
|
-
it('removes the contentWrapperNode from global rootnode upon teardown', async () => {
|
|
217
|
-
const ctrl = new OverlayController({
|
|
218
|
-
...withGlobalTestConfig(),
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
expect(ctrl.manager.globalRootNode.children.length).to.equal(1);
|
|
222
|
-
ctrl.teardown();
|
|
223
|
-
expect(ctrl.manager.globalRootNode.children.length).to.equal(0);
|
|
224
|
-
});
|
|
256
|
+
describe('Teardown', () => {});
|
|
225
257
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
258
|
+
describe('Node Configuration', () => {
|
|
259
|
+
describe('Content', async () => {
|
|
260
|
+
it('accepts a .contentNode for displaying content of the overlay', async () => {
|
|
261
|
+
const myContentNode = /** @type {HTMLElement} */ (fixtureSync('<p>direct node</p>'));
|
|
262
|
+
const ctrl = new OverlayController({
|
|
263
|
+
...withGlobalTestConfig(),
|
|
264
|
+
contentNode: myContentNode,
|
|
265
|
+
});
|
|
266
|
+
expect(ctrl.contentNode).to.have.trimmed.text('direct node');
|
|
267
|
+
expect(ctrl.contentNode).to.equal(myContentNode);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
describe('Embedded dom structure', async () => {
|
|
271
|
+
describe('When projected in shadow dom', async () => {
|
|
272
|
+
it('wraps a .contentWrapperNode for style application and a <dialog role="none"> for top layer paints', async () => {
|
|
273
|
+
const tagString = defineCE(
|
|
274
|
+
class extends HTMLElement {
|
|
275
|
+
constructor() {
|
|
276
|
+
super();
|
|
277
|
+
this.attachShadow({ mode: 'open' });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
connectedCallback() {
|
|
281
|
+
/** @type {ShadowRoot} */
|
|
282
|
+
(this.shadowRoot).innerHTML = '<slot name="content"></slot>';
|
|
283
|
+
this.innerHTML = '<div slot="content">projected</div>';
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
|
|
289
|
+
const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
|
|
290
|
+
const ctrl = new OverlayController({
|
|
291
|
+
...withGlobalTestConfig(),
|
|
292
|
+
contentNode: myContentNode,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(ctrl.contentNode.assignedSlot?.parentElement).to.equal(ctrl.contentWrapperNode);
|
|
296
|
+
expect(ctrl.contentWrapperNode.parentElement?.tagName).to.equal('DIALOG');
|
|
297
|
+
|
|
298
|
+
normalizeOverlayContentWapper(ctrl.contentWrapperNode);
|
|
299
|
+
|
|
300
|
+
// The total dom structure created...
|
|
301
|
+
expect(el).shadowDom.to.equal(`
|
|
302
|
+
<dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
|
|
303
|
+
<div data-id="content-wrapper">
|
|
304
|
+
<slot name="content">
|
|
305
|
+
</slot>
|
|
306
|
+
</div>
|
|
307
|
+
</dialog>
|
|
308
|
+
`);
|
|
309
|
+
|
|
310
|
+
expect(el).lightDom.to.equal(`<div slot="content">projected</div>`);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
240
313
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
314
|
+
describe('When in light dom', async () => {
|
|
315
|
+
it('wraps a .contentWrapperNode for style application and a <dialog role="none"> for top layer paints', async () => {
|
|
316
|
+
const el = fixtureSync('<section><div id="content">non projected</div></section>');
|
|
317
|
+
const myContentNode = /** @type {HTMLElement} */ (el.querySelector('#content'));
|
|
318
|
+
const ctrl = new OverlayController({
|
|
319
|
+
...withGlobalTestConfig(),
|
|
320
|
+
contentNode: myContentNode,
|
|
321
|
+
});
|
|
322
|
+
expect(ctrl.contentNode.parentElement).to.equal(ctrl.contentWrapperNode);
|
|
323
|
+
expect(ctrl.contentWrapperNode.parentElement?.tagName).to.equal('DIALOG');
|
|
324
|
+
|
|
325
|
+
normalizeOverlayContentWapper(ctrl.contentWrapperNode);
|
|
326
|
+
|
|
327
|
+
// The total dom structure created...
|
|
328
|
+
expect(el).lightDom.to.equal(`
|
|
329
|
+
<dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
|
|
330
|
+
<div data-id="content-wrapper">
|
|
331
|
+
<div id="content">non projected</div>
|
|
332
|
+
</div>
|
|
333
|
+
</dialog>
|
|
334
|
+
`);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
244
337
|
|
|
245
|
-
|
|
246
|
-
|
|
338
|
+
describe('When .contenWrapperNode provided', async () => {
|
|
339
|
+
it('keeps the .contentWrapperNode for style application and wraps a <dialog role="none"> for top layer paints', async () => {
|
|
340
|
+
const tagString = defineCE(
|
|
341
|
+
class extends HTMLElement {
|
|
342
|
+
constructor() {
|
|
343
|
+
super();
|
|
344
|
+
this.attachShadow({ mode: 'open' });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
connectedCallback() {
|
|
348
|
+
/** @type {ShadowRoot} */
|
|
349
|
+
(this.shadowRoot).innerHTML = '<div><slot name="content"></slot></div>';
|
|
350
|
+
this.innerHTML = '<div slot="content">projected</div>';
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
|
|
356
|
+
const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
|
|
357
|
+
const myContentWrapper = /** @type {HTMLElement} */ (
|
|
358
|
+
el.shadowRoot?.querySelector('div')
|
|
359
|
+
);
|
|
360
|
+
const ctrl = new OverlayController({
|
|
361
|
+
...withGlobalTestConfig(),
|
|
362
|
+
contentNode: myContentNode,
|
|
363
|
+
contentWrapperNode: myContentWrapper,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
normalizeOverlayContentWapper(ctrl.contentWrapperNode);
|
|
367
|
+
|
|
368
|
+
// The total dom structure created...
|
|
369
|
+
expect(el).shadowDom.to.equal(`
|
|
370
|
+
<dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
|
|
371
|
+
<div data-id="content-wrapper">
|
|
372
|
+
<slot name="content"></slot>
|
|
373
|
+
</div>
|
|
374
|
+
</dialog>
|
|
375
|
+
`);
|
|
376
|
+
});
|
|
247
377
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
378
|
+
it("uses the .contentWrapperNode as container for Popper's arrow", async () => {
|
|
379
|
+
const tagString = defineCE(
|
|
380
|
+
class extends HTMLElement {
|
|
381
|
+
constructor() {
|
|
382
|
+
super();
|
|
383
|
+
this.attachShadow({ mode: 'open' });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
connectedCallback() {
|
|
387
|
+
/** @type {ShadowRoot} */
|
|
388
|
+
(this.shadowRoot).innerHTML = `
|
|
389
|
+
<div>
|
|
390
|
+
<div id="arrow"></div>
|
|
391
|
+
<slot name="content"></slot>
|
|
392
|
+
</div>`;
|
|
393
|
+
this.innerHTML = '<div slot="content">projected</div>';
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
|
|
399
|
+
const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
|
|
400
|
+
const myContentWrapper = /** @type {HTMLElement} */ (
|
|
401
|
+
el.shadowRoot?.querySelector('div')
|
|
402
|
+
);
|
|
403
|
+
const ctrl = new OverlayController({
|
|
404
|
+
...withLocalTestConfig(),
|
|
405
|
+
contentNode: myContentNode,
|
|
406
|
+
contentWrapperNode: myContentWrapper,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
normalizeOverlayContentWapper(ctrl.contentWrapperNode);
|
|
410
|
+
|
|
411
|
+
// The total dom structure created...
|
|
412
|
+
expect(el).shadowDom.to.equal(`
|
|
413
|
+
<dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
|
|
414
|
+
<div data-id="content-wrapper">
|
|
415
|
+
<div id="arrow"></div>
|
|
416
|
+
<slot name="content"></slot>
|
|
417
|
+
</div>
|
|
418
|
+
</dialog>
|
|
419
|
+
`);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
253
422
|
});
|
|
254
|
-
|
|
255
|
-
// has no children as content gets moved to the body
|
|
256
|
-
expect(shadowHost.children.length).to.equal(0);
|
|
257
|
-
ctrl.teardown();
|
|
258
|
-
|
|
259
|
-
// restores original light dom in teardown
|
|
260
|
-
expect(shadowHost.children.length).to.equal(1);
|
|
261
423
|
});
|
|
262
|
-
});
|
|
263
424
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
425
|
+
describe('Invoker / Reference', async () => {
|
|
426
|
+
it('accepts a .invokerNode to directly set invoker', async () => {
|
|
427
|
+
const myInvokerNode = /** @type {HTMLElement} */ (fixtureSync('<button>invoke</button>'));
|
|
428
|
+
const ctrl = new OverlayController({
|
|
429
|
+
...withGlobalTestConfig(),
|
|
430
|
+
invokerNode: myInvokerNode,
|
|
431
|
+
});
|
|
432
|
+
expect(ctrl.invokerNode).to.equal(myInvokerNode);
|
|
433
|
+
expect(ctrl.referenceNode).to.equal(undefined);
|
|
269
434
|
});
|
|
270
|
-
expect(ctrl.contentNode).to.have.trimmed.text('direct node');
|
|
271
|
-
});
|
|
272
435
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
436
|
+
it('accepts a .referenceNode as positioning anchor different from .invokerNode', async () => {
|
|
437
|
+
const myInvokerNode = /** @type {HTMLElement} */ (fixtureSync('<button>invoke</button>'));
|
|
438
|
+
const myReferenceNode = /** @type {HTMLElement} */ (fixtureSync('<div>anchor</div>'));
|
|
439
|
+
const ctrl = new OverlayController({
|
|
440
|
+
...withGlobalTestConfig(),
|
|
441
|
+
invokerNode: myInvokerNode,
|
|
442
|
+
referenceNode: myReferenceNode,
|
|
443
|
+
});
|
|
444
|
+
expect(ctrl.referenceNode).to.equal(myReferenceNode);
|
|
445
|
+
expect(ctrl.invokerNode).to.not.equal(ctrl.referenceNode);
|
|
277
446
|
});
|
|
278
|
-
expect(ctrl.invokerNode).to.have.trimmed.text('invoke');
|
|
279
447
|
});
|
|
280
448
|
|
|
281
|
-
describe('
|
|
282
|
-
it('
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
</div>
|
|
290
|
-
`;
|
|
291
|
-
const contentNode = document.createElement('div');
|
|
292
|
-
contentNode.slot = 'contentNode';
|
|
293
|
-
shadowHost.appendChild(contentNode);
|
|
449
|
+
describe('Backdrop', () => {
|
|
450
|
+
it('creates a .backdropNode inside <dialog> for guaranteed top layer paints and positioning opportunities', async () => {
|
|
451
|
+
const tagString = defineCE(
|
|
452
|
+
class extends HTMLElement {
|
|
453
|
+
constructor() {
|
|
454
|
+
super();
|
|
455
|
+
this.attachShadow({ mode: 'open' });
|
|
456
|
+
}
|
|
294
457
|
|
|
295
|
-
|
|
296
|
-
|
|
458
|
+
connectedCallback() {
|
|
459
|
+
/** @type {ShadowRoot} */
|
|
460
|
+
(this.shadowRoot).innerHTML = '<slot name="content"></slot>';
|
|
461
|
+
this.innerHTML = '<div slot="content">projected</div>';
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
|
|
467
|
+
const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
|
|
297
468
|
|
|
298
469
|
const ctrl = new OverlayController({
|
|
299
|
-
...
|
|
300
|
-
contentNode,
|
|
301
|
-
|
|
302
|
-
/** @type {ShadowRoot} */ (shadowHost.shadowRoot).getElementById('contentWrapperNode')
|
|
303
|
-
),
|
|
470
|
+
...withGlobalTestConfig(),
|
|
471
|
+
contentNode: myContentNode,
|
|
472
|
+
hasBackdrop: true,
|
|
304
473
|
});
|
|
305
474
|
|
|
306
|
-
|
|
475
|
+
normalizeOverlayContentWapper(ctrl.contentWrapperNode);
|
|
476
|
+
|
|
477
|
+
// The total dom structure created...
|
|
478
|
+
expect(el).shadowDom.to.equal(
|
|
479
|
+
`
|
|
480
|
+
<dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
|
|
481
|
+
<div class="overlays__backdrop"></div>
|
|
482
|
+
<div data-id="content-wrapper">
|
|
483
|
+
<slot name="content">
|
|
484
|
+
</slot>
|
|
485
|
+
</div>
|
|
486
|
+
</dialog>
|
|
487
|
+
`,
|
|
488
|
+
);
|
|
307
489
|
});
|
|
308
490
|
});
|
|
309
491
|
|
|
@@ -446,6 +628,18 @@ describe('OverlayController', () => {
|
|
|
446
628
|
document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
|
|
447
629
|
expect(ctrl.isShown).to.be.true;
|
|
448
630
|
});
|
|
631
|
+
|
|
632
|
+
it('does not hide when [escape] is pressed with modal <dialog> and "hidesOnEsc" is false', async () => {
|
|
633
|
+
const ctrl = new OverlayController({
|
|
634
|
+
...withGlobalTestConfig(),
|
|
635
|
+
trapsKeyboardFocus: true,
|
|
636
|
+
hidesOnEsc: false,
|
|
637
|
+
});
|
|
638
|
+
await ctrl.show();
|
|
639
|
+
ctrl.contentNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
|
|
640
|
+
await aTimeout(0);
|
|
641
|
+
expect(ctrl.isShown).to.be.true;
|
|
642
|
+
});
|
|
449
643
|
});
|
|
450
644
|
|
|
451
645
|
describe('hidesOnOutsideEsc', () => {
|
|
@@ -760,6 +954,35 @@ describe('OverlayController', () => {
|
|
|
760
954
|
expect(document.activeElement).to.equal(input);
|
|
761
955
|
});
|
|
762
956
|
|
|
957
|
+
it('supports elementToFocusAfterHide option when shadowRoot involved involved', async () => {
|
|
958
|
+
const input = /** @type {HTMLElement} */ (await fixture('<input />'));
|
|
959
|
+
const contentNode = /** @type {HTMLElement} */ (
|
|
960
|
+
await fixture('<div><textarea></textarea></div>')
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
const shadowHost = document.createElement('div');
|
|
964
|
+
shadowHost.attachShadow({ mode: 'open' });
|
|
965
|
+
/** @type {ShadowRoot} */ (shadowHost.shadowRoot).innerHTML = `<slot></slot>`;
|
|
966
|
+
shadowHost.appendChild(contentNode);
|
|
967
|
+
document.body.appendChild(shadowHost);
|
|
968
|
+
|
|
969
|
+
const ctrl = new OverlayController({
|
|
970
|
+
...withGlobalTestConfig(),
|
|
971
|
+
elementToFocusAfterHide: input,
|
|
972
|
+
contentNode,
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
await ctrl.show();
|
|
976
|
+
const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
|
|
977
|
+
textarea.focus();
|
|
978
|
+
expect(document.activeElement).to.equal(textarea);
|
|
979
|
+
|
|
980
|
+
await ctrl.hide();
|
|
981
|
+
expect(document.activeElement).to.equal(input);
|
|
982
|
+
|
|
983
|
+
document.body.removeChild(shadowHost);
|
|
984
|
+
});
|
|
985
|
+
|
|
763
986
|
it(`only sets focus when outside world didn't take over already`, async () => {
|
|
764
987
|
const input = /** @type {HTMLElement} */ (await fixture('<input />'));
|
|
765
988
|
const outsideButton = /** @type {HTMLButtonElement} */ (await fixture('<button></button>'));
|
|
@@ -810,10 +1033,10 @@ describe('OverlayController', () => {
|
|
|
810
1033
|
});
|
|
811
1034
|
|
|
812
1035
|
await ctrl.show();
|
|
813
|
-
expect(
|
|
1036
|
+
expect(Array.from(document.body.classList)).to.contain('overlays-scroll-lock');
|
|
814
1037
|
|
|
815
1038
|
await ctrl.hide();
|
|
816
|
-
expect(
|
|
1039
|
+
expect(Array.from(document.body.classList)).to.not.contain('overlays-scroll-lock');
|
|
817
1040
|
});
|
|
818
1041
|
|
|
819
1042
|
it('keeps preventing of scrolling when multiple overlays are opened and closed', async () => {
|
|
@@ -829,7 +1052,7 @@ describe('OverlayController', () => {
|
|
|
829
1052
|
await ctrl0.show();
|
|
830
1053
|
await ctrl1.show();
|
|
831
1054
|
await ctrl1.hide();
|
|
832
|
-
expect(
|
|
1055
|
+
expect(Array.from(document.body.classList)).to.contain('overlays-scroll-lock');
|
|
833
1056
|
});
|
|
834
1057
|
});
|
|
835
1058
|
|
|
@@ -856,7 +1079,7 @@ describe('OverlayController', () => {
|
|
|
856
1079
|
hasBackdrop: true,
|
|
857
1080
|
});
|
|
858
1081
|
await controllerWithBackdrop.show();
|
|
859
|
-
expect(controllerWithBackdrop.backdropNode).to.have.class('
|
|
1082
|
+
expect(controllerWithBackdrop.backdropNode).to.have.class('overlays__backdrop');
|
|
860
1083
|
});
|
|
861
1084
|
|
|
862
1085
|
it('reenables the backdrop when shown/hidden/shown', async () => {
|
|
@@ -865,10 +1088,10 @@ describe('OverlayController', () => {
|
|
|
865
1088
|
hasBackdrop: true,
|
|
866
1089
|
});
|
|
867
1090
|
await ctrl.show();
|
|
868
|
-
expect(ctrl.backdropNode).to.have.class('
|
|
1091
|
+
expect(ctrl.backdropNode).to.have.class('overlays__backdrop');
|
|
869
1092
|
await ctrl.hide();
|
|
870
1093
|
await ctrl.show();
|
|
871
|
-
expect(ctrl.backdropNode).to.have.class('
|
|
1094
|
+
expect(ctrl.backdropNode).to.have.class('overlays__backdrop');
|
|
872
1095
|
});
|
|
873
1096
|
|
|
874
1097
|
it('adds and stacks backdrops if .hasBackdrop is enabled', async () => {
|
|
@@ -877,14 +1100,14 @@ describe('OverlayController', () => {
|
|
|
877
1100
|
hasBackdrop: true,
|
|
878
1101
|
});
|
|
879
1102
|
await ctrl0.show();
|
|
880
|
-
expect(ctrl0.backdropNode).to.have.class('
|
|
1103
|
+
expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
|
|
881
1104
|
|
|
882
1105
|
const ctrl1 = new OverlayController({
|
|
883
1106
|
...withGlobalTestConfig(),
|
|
884
1107
|
hasBackdrop: false,
|
|
885
1108
|
});
|
|
886
1109
|
await ctrl1.show();
|
|
887
|
-
expect(ctrl0.backdropNode).to.have.class('
|
|
1110
|
+
expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
|
|
888
1111
|
expect(ctrl1.backdropNode).to.be.undefined;
|
|
889
1112
|
|
|
890
1113
|
const ctrl2 = new OverlayController({
|
|
@@ -893,9 +1116,9 @@ describe('OverlayController', () => {
|
|
|
893
1116
|
});
|
|
894
1117
|
await ctrl2.show();
|
|
895
1118
|
|
|
896
|
-
expect(ctrl0.backdropNode).to.have.class('
|
|
1119
|
+
expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
|
|
897
1120
|
expect(ctrl1.backdropNode).to.be.undefined;
|
|
898
|
-
expect(ctrl2.backdropNode).to.have.class('
|
|
1121
|
+
expect(ctrl2.backdropNode).to.have.class('overlays__backdrop');
|
|
899
1122
|
});
|
|
900
1123
|
});
|
|
901
1124
|
|
|
@@ -1003,24 +1226,24 @@ describe('OverlayController', () => {
|
|
|
1003
1226
|
await ctrl0.show();
|
|
1004
1227
|
await ctrl1.show();
|
|
1005
1228
|
await ctrl2.show(); // blocking
|
|
1006
|
-
expect(ctrl0.
|
|
1007
|
-
expect(ctrl1.
|
|
1008
|
-
expect(ctrl2.
|
|
1229
|
+
expect(ctrl0.__wrappingDialogNode).to.not.be.displayed;
|
|
1230
|
+
expect(ctrl1.__wrappingDialogNode).to.not.be.displayed;
|
|
1231
|
+
expect(ctrl2.__wrappingDialogNode).to.be.displayed;
|
|
1009
1232
|
|
|
1010
1233
|
await ctrl3.show();
|
|
1011
1234
|
await ctrl3._showComplete;
|
|
1012
|
-
expect(ctrl3.
|
|
1235
|
+
expect(ctrl3.__wrappingDialogNode).to.be.displayed;
|
|
1013
1236
|
|
|
1014
1237
|
await ctrl2.hide();
|
|
1015
1238
|
await ctrl2._hideComplete;
|
|
1016
|
-
expect(ctrl0.
|
|
1017
|
-
expect(ctrl1.
|
|
1239
|
+
expect(ctrl0.__wrappingDialogNode).to.be.displayed;
|
|
1240
|
+
expect(ctrl1.__wrappingDialogNode).to.be.displayed;
|
|
1018
1241
|
|
|
1019
1242
|
await ctrl2.show(); // blocking
|
|
1020
|
-
expect(ctrl0.
|
|
1021
|
-
expect(ctrl1.
|
|
1022
|
-
expect(ctrl2.
|
|
1023
|
-
expect(ctrl3.
|
|
1243
|
+
expect(ctrl0.__wrappingDialogNode).to.not.be.displayed;
|
|
1244
|
+
expect(ctrl1.__wrappingDialogNode).to.not.be.displayed;
|
|
1245
|
+
expect(ctrl2.__wrappingDialogNode).to.be.displayed;
|
|
1246
|
+
expect(ctrl3.__wrappingDialogNode).to.not.be.displayed;
|
|
1024
1247
|
});
|
|
1025
1248
|
|
|
1026
1249
|
it('keeps backdrop status when used in combination with blocking', async () => {
|
|
@@ -1197,11 +1420,11 @@ describe('OverlayController', () => {
|
|
|
1197
1420
|
|
|
1198
1421
|
ctrl.hide();
|
|
1199
1422
|
|
|
1200
|
-
expect(getComputedStyle(ctrl.
|
|
1423
|
+
expect(getComputedStyle(ctrl.content).display).to.equal('block');
|
|
1201
1424
|
setTimeout(() => {
|
|
1202
1425
|
hideTransitionFinished();
|
|
1203
1426
|
setTimeout(() => {
|
|
1204
|
-
expect(getComputedStyle(ctrl.
|
|
1427
|
+
expect(getComputedStyle(ctrl.content).display).to.equal('none');
|
|
1205
1428
|
done();
|
|
1206
1429
|
}, 0);
|
|
1207
1430
|
}, 0);
|
|
@@ -1285,15 +1508,11 @@ describe('OverlayController', () => {
|
|
|
1285
1508
|
});
|
|
1286
1509
|
|
|
1287
1510
|
ctrl.show();
|
|
1288
|
-
expect(
|
|
1289
|
-
ctrl.contentWrapperNode.classList.contains('global-overlays__overlay-container--center'),
|
|
1290
|
-
);
|
|
1511
|
+
expect(ctrl.contentWrapperNode.classList.contains('overlays__overlay-container--center'));
|
|
1291
1512
|
expect(ctrl.isShown).to.be.true;
|
|
1292
1513
|
|
|
1293
1514
|
ctrl.updateConfig({ viewportConfig: { placement: 'top-right' } });
|
|
1294
|
-
expect(
|
|
1295
|
-
ctrl.contentWrapperNode.classList.contains('global-overlays__overlay-container--top-right'),
|
|
1296
|
-
);
|
|
1515
|
+
expect(ctrl.contentWrapperNode.classList.contains('overlays__overlay-container--top-right'));
|
|
1297
1516
|
expect(ctrl.isShown).to.be.true;
|
|
1298
1517
|
});
|
|
1299
1518
|
});
|
|
@@ -1379,89 +1598,9 @@ describe('OverlayController', () => {
|
|
|
1379
1598
|
expect(properlyInstantiated).to.be.true;
|
|
1380
1599
|
});
|
|
1381
1600
|
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
trapsKeyboardFocus: true,
|
|
1386
|
-
});
|
|
1387
|
-
|
|
1388
|
-
const sibling1 = document.createElement('div');
|
|
1389
|
-
const sibling2 = document.createElement('div');
|
|
1390
|
-
document.body.insertBefore(sibling1, ctrl.manager.globalRootNode);
|
|
1391
|
-
document.body.appendChild(sibling2);
|
|
1392
|
-
|
|
1393
|
-
await ctrl.show();
|
|
1394
|
-
|
|
1395
|
-
[sibling1, sibling2].forEach(sibling => {
|
|
1396
|
-
expect(sibling).to.have.attribute('aria-hidden', 'true');
|
|
1397
|
-
expect(sibling).to.have.attribute('inert');
|
|
1398
|
-
});
|
|
1399
|
-
expect(ctrl.content.hasAttribute('aria-hidden')).to.be.false;
|
|
1400
|
-
expect(ctrl.content.hasAttribute('inert')).to.be.false;
|
|
1401
|
-
|
|
1402
|
-
await ctrl.hide();
|
|
1403
|
-
|
|
1404
|
-
[sibling1, sibling2].forEach(sibling => {
|
|
1405
|
-
expect(sibling).to.not.have.attribute('aria-hidden');
|
|
1406
|
-
expect(sibling).to.not.have.attribute('inert');
|
|
1407
|
-
});
|
|
1408
|
-
|
|
1409
|
-
// cleanup
|
|
1410
|
-
document.body.removeChild(sibling1);
|
|
1411
|
-
document.body.removeChild(sibling2);
|
|
1412
|
-
});
|
|
1413
|
-
|
|
1414
|
-
/**
|
|
1415
|
-
* style.userSelect:
|
|
1416
|
-
* - chrome: 'none'
|
|
1417
|
-
* - rest: undefined
|
|
1418
|
-
*
|
|
1419
|
-
* style.pointerEvents:
|
|
1420
|
-
* - chrome: auto
|
|
1421
|
-
* - IE11: visiblePainted
|
|
1422
|
-
*/
|
|
1423
|
-
it('disables pointer events and selection on inert elements', async () => {
|
|
1424
|
-
const ctrl = new OverlayController({
|
|
1425
|
-
...withGlobalTestConfig(),
|
|
1426
|
-
trapsKeyboardFocus: true,
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
|
-
// show+hide are needed to create a root node
|
|
1430
|
-
await ctrl.show();
|
|
1431
|
-
await ctrl.hide();
|
|
1432
|
-
|
|
1433
|
-
const sibling1 = document.createElement('div');
|
|
1434
|
-
const sibling2 = document.createElement('div');
|
|
1435
|
-
document.body.insertBefore(sibling1, ctrl.manager.globalRootNode);
|
|
1436
|
-
document.body.appendChild(sibling2);
|
|
1437
|
-
|
|
1438
|
-
await ctrl.show();
|
|
1439
|
-
|
|
1440
|
-
[sibling1, sibling2].forEach(sibling => {
|
|
1441
|
-
expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['none', undefined]);
|
|
1442
|
-
expect(window.getComputedStyle(sibling).pointerEvents).to.equal('none');
|
|
1443
|
-
});
|
|
1444
|
-
|
|
1445
|
-
expect(window.getComputedStyle(ctrl.contentNode).userSelect).to.be.oneOf(['auto', undefined]);
|
|
1446
|
-
expect(window.getComputedStyle(ctrl.contentNode).pointerEvents).to.be.oneOf([
|
|
1447
|
-
'auto',
|
|
1448
|
-
'visiblePainted',
|
|
1449
|
-
]);
|
|
1450
|
-
|
|
1451
|
-
await ctrl.hide();
|
|
1452
|
-
|
|
1453
|
-
[sibling1, sibling2].forEach(sibling => {
|
|
1454
|
-
expect(window.getComputedStyle(sibling).userSelect).to.be.oneOf(['auto', undefined]);
|
|
1455
|
-
expect(window.getComputedStyle(sibling).pointerEvents).to.be.oneOf([
|
|
1456
|
-
'auto',
|
|
1457
|
-
'visiblePainted',
|
|
1458
|
-
]);
|
|
1459
|
-
});
|
|
1460
|
-
|
|
1461
|
-
// cleanup
|
|
1462
|
-
document.body.removeChild(sibling1);
|
|
1463
|
-
document.body.removeChild(sibling2);
|
|
1464
|
-
});
|
|
1601
|
+
// TODO: check if we covered all functionality. "Inertness" should be handled by the platform with a modal overlay...
|
|
1602
|
+
it.skip('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => {});
|
|
1603
|
+
it.skip('disables pointer events and selection on inert elements', async () => {});
|
|
1465
1604
|
|
|
1466
1605
|
describe('Tooltip', () => {
|
|
1467
1606
|
it('adds [aria-describedby] on invoker', async () => {
|
|
@@ -1616,47 +1755,6 @@ describe('OverlayController', () => {
|
|
|
1616
1755
|
}).to.throw('[OverlayController] You need to provide a .contentNode');
|
|
1617
1756
|
});
|
|
1618
1757
|
|
|
1619
|
-
it('throws if contentNodeWrapper is not provided for projected contentNode', async () => {
|
|
1620
|
-
const shadowHost = document.createElement('div');
|
|
1621
|
-
shadowHost.attachShadow({ mode: 'open' });
|
|
1622
|
-
/** @type {ShadowRoot} */ (shadowHost.shadowRoot).innerHTML = `
|
|
1623
|
-
<div id="contentWrapperNode">
|
|
1624
|
-
<slot name="contentNode"></slot>
|
|
1625
|
-
<my-arrow></my-arrow>
|
|
1626
|
-
</div>
|
|
1627
|
-
`;
|
|
1628
|
-
const contentNode = document.createElement('div');
|
|
1629
|
-
contentNode.slot = 'contentNode';
|
|
1630
|
-
shadowHost.appendChild(contentNode);
|
|
1631
|
-
|
|
1632
|
-
// Ensure the contentNode is connected to DOM
|
|
1633
|
-
document.body.appendChild(shadowHost);
|
|
1634
|
-
|
|
1635
|
-
expect(() => {
|
|
1636
|
-
new OverlayController({
|
|
1637
|
-
...withLocalTestConfig(),
|
|
1638
|
-
contentNode,
|
|
1639
|
-
});
|
|
1640
|
-
}).to.throw(
|
|
1641
|
-
'[OverlayController] You need to provide a .contentWrapperNode when .contentNode is projected',
|
|
1642
|
-
);
|
|
1643
|
-
});
|
|
1644
|
-
|
|
1645
|
-
it('throws if placementMode is global for a tooltip', async () => {
|
|
1646
|
-
const contentNode = document.createElement('div');
|
|
1647
|
-
document.body.appendChild(contentNode);
|
|
1648
|
-
expect(() => {
|
|
1649
|
-
new OverlayController({
|
|
1650
|
-
placementMode: 'global',
|
|
1651
|
-
contentNode,
|
|
1652
|
-
isTooltip: true,
|
|
1653
|
-
handlesAccessibility: true,
|
|
1654
|
-
});
|
|
1655
|
-
}).to.throw(
|
|
1656
|
-
'[OverlayController] .isTooltip should be configured with .placementMode "local"',
|
|
1657
|
-
);
|
|
1658
|
-
});
|
|
1659
|
-
|
|
1660
1758
|
it('throws if handlesAccessibility is false for a tooltip', async () => {
|
|
1661
1759
|
const contentNode = document.createElement('div');
|
|
1662
1760
|
document.body.appendChild(contentNode);
|