@lion/ui 0.0.11 → 0.0.13
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 +22 -9
- package/components/accordion/test/lion-accordion.test.js +29 -32
- package/components/input-tel/translations/bg.js +3 -1
- package/components/input-tel/translations/cs.js +3 -1
- package/components/input-tel/translations/de.js +3 -1
- package/components/input-tel/translations/en.js +3 -1
- package/components/input-tel/translations/es.js +3 -1
- package/components/input-tel/translations/fr.js +3 -1
- package/components/input-tel/translations/hu.js +3 -1
- package/components/input-tel/translations/it.js +3 -1
- package/components/input-tel/translations/nl.js +3 -1
- package/components/input-tel/translations/pl.js +3 -1
- package/components/input-tel/translations/ro.js +3 -1
- package/components/input-tel/translations/ru.js +3 -1
- package/components/input-tel/translations/sk.js +3 -1
- package/components/input-tel/translations/uk.js +3 -1
- package/components/input-tel/translations/zh.js +3 -1
- package/components/input-tel-dropdown/src/LionInputTelDropdown.js +5 -5
- package/components/listbox/src/ListboxMixin.js +0 -4
- package/components/listbox/types/ListboxMixinTypes.ts +1 -4
- package/components/overlays/src/OverlayController.js +28 -34
- package/components/overlays/src/utils/adopt-styles.js +136 -0
- package/components/overlays/test/OverlayController.test.js +24 -55
- package/components/overlays/test/local-positioning.test.js +1 -1
- package/components/overlays/test/utils-tests/adopt-styles.test.js +177 -0
- package/components/overlays/test-helpers/createShadowHost.js +16 -0
- package/components/overlays/{test/utils-tests/local-positioning-helpers.js → test-helpers/normalizeTransformStyle.js} +0 -0
- package/components/select-rich/src/LionSelectRich.js +14 -6
- package/components/select-rich/test/lion-select-rich.test.js +25 -1
- package/components/tooltip/src/LionTooltip.js +16 -2
- package/components/tooltip/test/lion-tooltip.test.js +1 -2
- package/custom-elements.json +432 -183
- package/dist-types/components/accordion/src/LionAccordion.d.ts.map +1 -1
- package/dist-types/components/input-tel/translations/bg-BG.d.ts +3 -1
- package/dist-types/components/input-tel/translations/bg.d.ts +3 -1
- package/dist-types/components/input-tel/translations/cs-CZ.d.ts +3 -1
- package/dist-types/components/input-tel/translations/cs.d.ts +3 -1
- package/dist-types/components/input-tel/translations/de-DE.d.ts +3 -1
- package/dist-types/components/input-tel/translations/de.d.ts +3 -1
- package/dist-types/components/input-tel/translations/en-AU.d.ts +3 -1
- package/dist-types/components/input-tel/translations/en-GB.d.ts +3 -1
- package/dist-types/components/input-tel/translations/en-US.d.ts +3 -1
- package/dist-types/components/input-tel/translations/en.d.ts +3 -1
- package/dist-types/components/input-tel/translations/es-ES.d.ts +3 -1
- package/dist-types/components/input-tel/translations/es.d.ts +3 -1
- package/dist-types/components/input-tel/translations/fr-BE.d.ts +3 -1
- package/dist-types/components/input-tel/translations/fr-FR.d.ts +3 -1
- package/dist-types/components/input-tel/translations/fr.d.ts +3 -1
- package/dist-types/components/input-tel/translations/hu-HU.d.ts +3 -1
- package/dist-types/components/input-tel/translations/hu.d.ts +3 -1
- package/dist-types/components/input-tel/translations/it-IT.d.ts +3 -1
- package/dist-types/components/input-tel/translations/it.d.ts +3 -1
- package/dist-types/components/input-tel/translations/nl-BE.d.ts +3 -1
- package/dist-types/components/input-tel/translations/nl-NL.d.ts +3 -1
- package/dist-types/components/input-tel/translations/nl.d.ts +3 -1
- package/dist-types/components/input-tel/translations/pl-PL.d.ts +3 -1
- package/dist-types/components/input-tel/translations/pl.d.ts +3 -1
- package/dist-types/components/input-tel/translations/ro-RO.d.ts +3 -1
- package/dist-types/components/input-tel/translations/ro.d.ts +3 -1
- package/dist-types/components/input-tel/translations/ru-RU.d.ts +3 -1
- package/dist-types/components/input-tel/translations/ru.d.ts +3 -1
- package/dist-types/components/input-tel/translations/sk-SK.d.ts +3 -1
- package/dist-types/components/input-tel/translations/sk.d.ts +3 -1
- package/dist-types/components/input-tel/translations/uk-UA.d.ts +3 -1
- package/dist-types/components/input-tel/translations/uk.d.ts +3 -1
- package/dist-types/components/input-tel/translations/zh.d.ts +3 -1
- package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
- package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts +1 -2
- package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +8 -5
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/overlays/src/utils/adopt-styles.d.ts +24 -0
- package/dist-types/components/overlays/src/utils/adopt-styles.d.ts.map +1 -0
- package/dist-types/components/overlays/test/OverlayController.test.d.ts.map +1 -1
- package/dist-types/components/overlays/test/utils-tests/adopt-styles.test.d.ts +2 -0
- package/dist-types/components/overlays/test/utils-tests/adopt-styles.test.d.ts.map +1 -0
- package/dist-types/components/overlays/test-helpers/createShadowHost.d.ts +8 -0
- package/dist-types/components/overlays/test-helpers/createShadowHost.d.ts.map +1 -0
- package/dist-types/components/overlays/{test/utils-tests/local-positioning-helpers.d.ts → test-helpers/normalizeTransformStyle.d.ts} +1 -1
- package/dist-types/components/overlays/test-helpers/normalizeTransformStyle.d.ts.map +1 -0
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +35 -3
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/components/tooltip/src/LionTooltip.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/button/use-cases.md +2 -0
- 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/src/demo-selection-display.js +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/dialog/src/demoStyle.js +18 -0
- 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 +30 -24
- 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/validate.md +1 -1
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/assets/demo-el-using-overlaymixin.mjs +0 -16
- package/docs/fundamentals/systems/overlays/configuration.md +18 -32
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +5 -5
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/.gitignore +1 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/demo-app.js +93 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/overlays/instance.js +4 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-a/page-a.js +35 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/node_modules/overlays/instance.js +4 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/node_modules/page-b/page-b.js +49 -0
- package/docs/fundamentals/tools/singleton-manager/example-complex/overlayCompatibility.js +70 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/demo-app.js +91 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/overlays/instance.js +3 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-a/page-a.js +34 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-b/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-b/node_modules/overlays/instance.js +3 -0
- package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/page-b/page-b.js +34 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/demo-app.js +93 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/overlays/instance.js +4 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-a/page-a.js +34 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-b/node_modules/overlays/index.js +30 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-b/node_modules/overlays/instance.js +4 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/page-b/page-b.js +34 -0
- package/docs/fundamentals/tools/singleton-manager/example-success/overlayCompatibility.js +23 -0
- 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/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 +2 -2
- package/dist-types/components/overlays/test/utils-tests/local-positioning-helpers.d.ts.map +0 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// See: https://github.com/ing-bank/lion/issues/1880
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('lit').CSSResult|CSSStyleSheet} AdoptableStyle
|
|
5
|
+
* @typedef {(renderRoot:DocumentOrShadowRoot, style: AdoptableStyle, opts?: {teardown?: boolean}) => void} AdoptStyleFn
|
|
6
|
+
* @typedef {(renderRoot:DocumentOrShadowRoot, styles: AdoptableStyle[], opts?: {teardown?: boolean}) => void} AdoptStylesFn
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Shared protected object that can be spied/mocked in tests
|
|
10
|
+
export const _adoptStyleUtils = {
|
|
11
|
+
// Mocking Document.prototype.adoptedStyleSheets seemed impossible
|
|
12
|
+
supportsAdoptingStyleSheets:
|
|
13
|
+
window.ShadowRoot &&
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
(window.ShadyCSS === undefined || window.ShadyCSS.nativeShadow) &&
|
|
16
|
+
'adoptedStyleSheets' in Document.prototype &&
|
|
17
|
+
'replace' in CSSStyleSheet.prototype,
|
|
18
|
+
/** @type {AdoptStyleFn} */
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
adoptStyle: undefined,
|
|
21
|
+
/** @type {AdoptStylesFn} */
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
adoptStyles: undefined,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const styleCache = new Map();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {CSSStyleSheet} cssStyleSheet
|
|
30
|
+
*/
|
|
31
|
+
export function serializeConstructableStylesheet(cssStyleSheet) {
|
|
32
|
+
return Array.from(cssStyleSheet.cssRules)
|
|
33
|
+
.map(r => r.cssText)
|
|
34
|
+
.join('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {DocumentOrShadowRoot} renderRoot
|
|
39
|
+
* @param {AdoptableStyle} style
|
|
40
|
+
* @param {{teardown?: boolean}} opts
|
|
41
|
+
*/
|
|
42
|
+
function adoptStyleWhenAdoptedStylesheetsNotSupported(
|
|
43
|
+
renderRoot,
|
|
44
|
+
style,
|
|
45
|
+
{ teardown = false } = {},
|
|
46
|
+
) {
|
|
47
|
+
const adoptRoot = /** @type {ShadowRoot|Document['body']} */ (
|
|
48
|
+
renderRoot === document ? document.body : renderRoot
|
|
49
|
+
);
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
const styleText = style.cssText || serializeConstructableStylesheet(style);
|
|
52
|
+
|
|
53
|
+
if (!teardown) {
|
|
54
|
+
const styleEl = document.createElement('style');
|
|
55
|
+
// keep notation, so it's not renamed in minification/build
|
|
56
|
+
// eslint-disable-next-line dot-notation
|
|
57
|
+
const nonce = window['litNonce'];
|
|
58
|
+
if (nonce !== undefined) {
|
|
59
|
+
styleEl.setAttribute('nonce', nonce);
|
|
60
|
+
}
|
|
61
|
+
styleEl.textContent = styleText;
|
|
62
|
+
adoptRoot.appendChild(styleEl);
|
|
63
|
+
} else {
|
|
64
|
+
const foundStyleEls = Array.from(adoptRoot.querySelectorAll('style'));
|
|
65
|
+
|
|
66
|
+
for (const foundStyleEl of foundStyleEls) {
|
|
67
|
+
if (foundStyleEl.textContent === styleText) {
|
|
68
|
+
foundStyleEl.remove();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {DocumentOrShadowRoot} renderRoot
|
|
77
|
+
* @param {AdoptableStyle} style
|
|
78
|
+
* @param {{teardown?: boolean}} opts
|
|
79
|
+
*/
|
|
80
|
+
function handleCache(renderRoot, style, { teardown = false } = {}) {
|
|
81
|
+
let haltFurtherExecution = false;
|
|
82
|
+
if (!styleCache.has(renderRoot)) {
|
|
83
|
+
styleCache.set(renderRoot, []);
|
|
84
|
+
}
|
|
85
|
+
const addedStylesForRoot = styleCache.get(renderRoot);
|
|
86
|
+
const foundStyle = addedStylesForRoot.find(
|
|
87
|
+
(/** @type {import("lit").CSSResultOrNative} */ addedStyle) => style === addedStyle,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (foundStyle && teardown) {
|
|
91
|
+
addedStylesForRoot.splice(addedStylesForRoot.indexOf(style), 1);
|
|
92
|
+
} else if (!foundStyle && !teardown) {
|
|
93
|
+
addedStylesForRoot.push(style);
|
|
94
|
+
} else if ((foundStyle && !teardown) || (!foundStyle && teardown)) {
|
|
95
|
+
// Already removed or added. We're done
|
|
96
|
+
haltFurtherExecution = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { haltFurtherExecution };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** @type {AdoptStyleFn} */
|
|
103
|
+
export function adoptStyle(renderRoot, style, { teardown = false } = {}) {
|
|
104
|
+
const { haltFurtherExecution } = handleCache(renderRoot, style, { teardown });
|
|
105
|
+
if (haltFurtherExecution) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!_adoptStyleUtils.supportsAdoptingStyleSheets) {
|
|
110
|
+
adoptStyleWhenAdoptedStylesheetsNotSupported(renderRoot, style, { teardown });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const sheet = style instanceof CSSStyleSheet ? style : style.styleSheet;
|
|
115
|
+
if (!sheet) {
|
|
116
|
+
throw new Error(`Please provide a CSSResultOrNative style`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!teardown) {
|
|
120
|
+
// @ts-ignore
|
|
121
|
+
// eslint-disable-next-line no-param-reassign
|
|
122
|
+
renderRoot.adoptedStyleSheets.push(sheet);
|
|
123
|
+
} else if (renderRoot.adoptedStyleSheets.includes(sheet)) {
|
|
124
|
+
renderRoot.adoptedStyleSheets.splice(renderRoot.adoptedStyleSheets.indexOf(sheet), 1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** @type {AdoptStylesFn} */
|
|
129
|
+
export function adoptStyles(renderRoot, styles, { teardown = false } = {}) {
|
|
130
|
+
for (const style of styles) {
|
|
131
|
+
_adoptStyleUtils.adoptStyle(renderRoot, style, { teardown });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
_adoptStyleUtils.adoptStyle = adoptStyle;
|
|
136
|
+
_adoptStyleUtils.adoptStyles = adoptStyles;
|
|
@@ -11,9 +11,10 @@ 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
|
-
import { overlayShadowDomStyle } from '../src/overlayShadowDomStyle.js';
|
|
15
14
|
import { keyCodes } from '../src/utils/key-codes.js';
|
|
16
15
|
import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
16
|
+
import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
|
|
17
|
+
import { createShadowHost } from '../test-helpers/createShadowHost.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
@@ -22,20 +23,6 @@ import { simulateTab } from '../src/utils/simulate-tab.js';
|
|
|
22
23
|
|
|
23
24
|
const wrappingDialogNodeStyle = 'display: none; z-index: 9999;';
|
|
24
25
|
|
|
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
26
|
/**
|
|
40
27
|
* Make sure that all browsers serialize html in a similar way
|
|
41
28
|
* (Firefox tends to output empty style attrs)
|
|
@@ -97,51 +84,17 @@ describe('OverlayController', () => {
|
|
|
97
84
|
});
|
|
98
85
|
|
|
99
86
|
describe('Stylesheets', () => {
|
|
100
|
-
it('
|
|
101
|
-
|
|
102
|
-
|
|
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 () => {
|
|
87
|
+
it('calls adoptStyles', async () => {
|
|
88
|
+
const spy = sinon.spy(_adoptStyleUtils, 'adoptStyle');
|
|
89
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
112
90
|
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
91
|
shadowHost.appendChild(contentNode);
|
|
117
|
-
|
|
118
|
-
const ctrl = new OverlayController({
|
|
92
|
+
new OverlayController({
|
|
119
93
|
...withLocalTestConfig(),
|
|
120
94
|
contentNode,
|
|
121
95
|
});
|
|
122
|
-
|
|
123
|
-
|
|
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);
|
|
96
|
+
expect(spy).to.have.been.called;
|
|
97
|
+
cleanupShadowHost();
|
|
145
98
|
});
|
|
146
99
|
});
|
|
147
100
|
|
|
@@ -1515,6 +1468,22 @@ describe('OverlayController', () => {
|
|
|
1515
1468
|
expect(ctrl.contentWrapperNode.classList.contains('overlays__overlay-container--top-right'));
|
|
1516
1469
|
expect(ctrl.isShown).to.be.true;
|
|
1517
1470
|
});
|
|
1471
|
+
|
|
1472
|
+
it('disables backdrop when switching to hasBackrop "false"', async () => {
|
|
1473
|
+
const ctrl = new OverlayController({
|
|
1474
|
+
...withLocalTestConfig(),
|
|
1475
|
+
contentNode: /** @type {HTMLElement} */ (await fixture(html`<div>content1</div>`)),
|
|
1476
|
+
hasBackdrop: true,
|
|
1477
|
+
});
|
|
1478
|
+
await ctrl.show(); // Popper adds inline styles
|
|
1479
|
+
expect(ctrl.backdropNode).not.to.be.undefined;
|
|
1480
|
+
expect(Array.from(ctrl.backdropNode.classList)).to.include('overlays__backdrop--visible');
|
|
1481
|
+
|
|
1482
|
+
ctrl.updateConfig({
|
|
1483
|
+
hasBackdrop: false,
|
|
1484
|
+
});
|
|
1485
|
+
expect(Array.from(ctrl.backdropNode.classList)).to.not.include('overlays__backdrop--visible');
|
|
1486
|
+
});
|
|
1518
1487
|
});
|
|
1519
1488
|
|
|
1520
1489
|
describe('Accessibility', () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { expect, fixture, fixtureSync } from '@open-wc/testing';
|
|
3
3
|
import { html } from 'lit/static-html.js';
|
|
4
4
|
import { OverlayController } from '@lion/ui/overlays.js';
|
|
5
|
-
import { normalizeTransformStyle } from '
|
|
5
|
+
import { normalizeTransformStyle } from '../test-helpers/normalizeTransformStyle.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { css } from 'lit';
|
|
3
|
+
import sinon from 'sinon';
|
|
4
|
+
import {
|
|
5
|
+
adoptStyle,
|
|
6
|
+
adoptStyles,
|
|
7
|
+
serializeConstructableStylesheet,
|
|
8
|
+
_adoptStyleUtils,
|
|
9
|
+
} from '../../src/utils/adopt-styles.js';
|
|
10
|
+
import { createShadowHost } from '../../test-helpers/createShadowHost.js';
|
|
11
|
+
|
|
12
|
+
function mockNoSupportAdoptedStylesheets() {
|
|
13
|
+
_adoptStyleUtils.supportsAdoptingStyleSheets = false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function restoreMockNoSupportAdoptedStylesheets() {
|
|
17
|
+
_adoptStyleUtils.supportsAdoptingStyleSheets = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('adoptStyle()', () => {
|
|
21
|
+
it('adds a stylesheet from a CSSResult to the shadowRoot', async () => {
|
|
22
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
23
|
+
const myCssResult = css``;
|
|
24
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
25
|
+
|
|
26
|
+
adoptStyle(root, myCssResult);
|
|
27
|
+
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
|
|
28
|
+
|
|
29
|
+
cleanupShadowHost();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('adds a stylesheet from a CSSStyleSheet to the shadowRoot', async () => {
|
|
33
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
34
|
+
const myCSSStyleSheet = new CSSStyleSheet();
|
|
35
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
36
|
+
|
|
37
|
+
adoptStyle(root, myCSSStyleSheet);
|
|
38
|
+
expect(root.adoptedStyleSheets).to.include(myCSSStyleSheet);
|
|
39
|
+
|
|
40
|
+
cleanupShadowHost();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('does not add same stylesheet twice', async () => {
|
|
44
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
45
|
+
const myCssResult = css``;
|
|
46
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
47
|
+
|
|
48
|
+
adoptStyle(root, myCssResult);
|
|
49
|
+
const amountOfStylesheetsAfterOneInit = root.adoptedStyleSheets.length;
|
|
50
|
+
adoptStyle(root, myCssResult);
|
|
51
|
+
expect(root.adoptedStyleSheets.length).to.equal(amountOfStylesheetsAfterOneInit);
|
|
52
|
+
|
|
53
|
+
cleanupShadowHost();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('works as well when document is the root', async () => {
|
|
57
|
+
const myCssResult = css``;
|
|
58
|
+
const root = document;
|
|
59
|
+
|
|
60
|
+
adoptStyle(root, myCssResult);
|
|
61
|
+
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('Teardown', () => {
|
|
65
|
+
it('removes stylesheets from the shadowRoot', async () => {
|
|
66
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
67
|
+
const myCssResult = css``;
|
|
68
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
69
|
+
|
|
70
|
+
adoptStyle(root, myCssResult);
|
|
71
|
+
expect(root.adoptedStyleSheets).to.include(myCssResult.styleSheet);
|
|
72
|
+
adoptStyle(root, myCssResult, { teardown: true });
|
|
73
|
+
expect(root.adoptedStyleSheets).to.not.include(myCssResult.styleSheet);
|
|
74
|
+
|
|
75
|
+
const myCSSStyleSheet = new CSSStyleSheet();
|
|
76
|
+
adoptStyle(root, myCSSStyleSheet);
|
|
77
|
+
expect(root.adoptedStyleSheets).to.include(myCSSStyleSheet);
|
|
78
|
+
adoptStyle(root, myCSSStyleSheet, { teardown: true });
|
|
79
|
+
expect(root.adoptedStyleSheets).to.not.include(myCSSStyleSheet);
|
|
80
|
+
|
|
81
|
+
cleanupShadowHost();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Fallback when adoptedStyleSheets are not supported', () => {
|
|
86
|
+
beforeEach(() => {
|
|
87
|
+
mockNoSupportAdoptedStylesheets();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(() => {
|
|
91
|
+
restoreMockNoSupportAdoptedStylesheets();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('adds a "traditional" stylesheet to the shadowRoot', async () => {
|
|
95
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
96
|
+
const myCssResult = css`
|
|
97
|
+
.check {
|
|
98
|
+
color: blue;
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
102
|
+
|
|
103
|
+
adoptStyle(root, myCssResult);
|
|
104
|
+
const sheets = Array.from(root.querySelectorAll('style'));
|
|
105
|
+
const lastAddedSheet = sheets[sheets.length - 1];
|
|
106
|
+
expect(lastAddedSheet.textContent).to.equal(myCssResult.cssText);
|
|
107
|
+
|
|
108
|
+
cleanupShadowHost();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('adds a "traditional" stylesheet to the body', async () => {
|
|
112
|
+
mockNoSupportAdoptedStylesheets();
|
|
113
|
+
|
|
114
|
+
const myCssResult = css`
|
|
115
|
+
.check {
|
|
116
|
+
color: blue;
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
const root = document;
|
|
120
|
+
adoptStyle(root, myCssResult);
|
|
121
|
+
|
|
122
|
+
const sheets = Array.from(document.body.querySelectorAll('style'));
|
|
123
|
+
const lastAddedSheet = sheets[sheets.length - 1];
|
|
124
|
+
expect(lastAddedSheet.textContent).to.equal(myCssResult.cssText);
|
|
125
|
+
restoreMockNoSupportAdoptedStylesheets();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('Teardown', () => {
|
|
129
|
+
it('removes a "traditional" stylesheet from the shadowRoot', async () => {
|
|
130
|
+
const { shadowHost, cleanupShadowHost } = createShadowHost();
|
|
131
|
+
const myCssResult = css`
|
|
132
|
+
.check {
|
|
133
|
+
color: blue;
|
|
134
|
+
}
|
|
135
|
+
`;
|
|
136
|
+
const root = /** @type {ShadowRoot} */ (shadowHost.shadowRoot);
|
|
137
|
+
|
|
138
|
+
adoptStyle(root, myCssResult);
|
|
139
|
+
const sheets1 = Array.from(root.querySelectorAll('style'));
|
|
140
|
+
const lastAddedSheet1 = sheets1[sheets1.length - 1];
|
|
141
|
+
expect(lastAddedSheet1.textContent).to.equal(myCssResult.cssText);
|
|
142
|
+
adoptStyle(root, myCssResult, { teardown: true });
|
|
143
|
+
const sheets2 = Array.from(root.querySelectorAll('style'));
|
|
144
|
+
const lastAddedSheet2 = sheets2[sheets2.length - 1];
|
|
145
|
+
expect(lastAddedSheet2?.textContent).to.not.equal(myCssResult.cssText);
|
|
146
|
+
|
|
147
|
+
const myCSSStyleSheet = new CSSStyleSheet();
|
|
148
|
+
myCSSStyleSheet.insertRule('.check { color: blue; }');
|
|
149
|
+
|
|
150
|
+
adoptStyle(root, myCSSStyleSheet);
|
|
151
|
+
const sheets3 = Array.from(root.querySelectorAll('style'));
|
|
152
|
+
const lastAddedSheet3 = sheets3[sheets3.length - 1];
|
|
153
|
+
expect(lastAddedSheet3.textContent).to.equal(
|
|
154
|
+
serializeConstructableStylesheet(myCSSStyleSheet),
|
|
155
|
+
);
|
|
156
|
+
adoptStyle(root, myCSSStyleSheet, { teardown: true });
|
|
157
|
+
const sheets4 = Array.from(root.querySelectorAll('style'));
|
|
158
|
+
const lastAddedSheet4 = sheets4[sheets4.length - 1];
|
|
159
|
+
expect(lastAddedSheet4?.textContent).to.not.equal(myCSSStyleSheet);
|
|
160
|
+
|
|
161
|
+
cleanupShadowHost();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('adoptStyles()', () => {
|
|
168
|
+
it('calls "adoptStyle" for all entries in CSSResult|CSSStylesheet[]', async () => {
|
|
169
|
+
const spy = sinon.spy(_adoptStyleUtils, 'adoptStyle');
|
|
170
|
+
|
|
171
|
+
const myCssResult = css``;
|
|
172
|
+
const myCSSStyleSheet = new CSSStyleSheet();
|
|
173
|
+
|
|
174
|
+
adoptStyles(document, [myCssResult, myCSSStyleSheet]);
|
|
175
|
+
expect(spy).to.have.been.calledTwice;
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Useful in tests when no need for wc
|
|
3
|
+
*/
|
|
4
|
+
export function createShadowHost() {
|
|
5
|
+
const shadowHost = document.createElement('div');
|
|
6
|
+
shadowHost.attachShadow({ mode: 'open' });
|
|
7
|
+
/** @type {ShadowRoot} */ (shadowHost.shadowRoot).innerHTML = `<slot></slot>`;
|
|
8
|
+
document.body.appendChild(shadowHost);
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
shadowHost,
|
|
12
|
+
cleanupShadowHost: () => {
|
|
13
|
+
document.body.removeChild(shadowHost);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
File without changes
|
|
@@ -67,14 +67,11 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
67
67
|
`;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/** @type {SlotsMap} */
|
|
70
71
|
get slots() {
|
|
71
72
|
return {
|
|
72
73
|
...super.slots,
|
|
73
|
-
invoker: () =>
|
|
74
|
-
const invokerEl = this.createScopedElement('lion-select-invoker');
|
|
75
|
-
invokerEl.setAttribute('data-tag-name', 'lion-select-invoker');
|
|
76
|
-
return invokerEl;
|
|
77
|
-
},
|
|
74
|
+
invoker: () => html`<lion-select-invoker></lion-select-invoker>`,
|
|
78
75
|
};
|
|
79
76
|
}
|
|
80
77
|
|
|
@@ -88,6 +85,15 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
88
85
|
);
|
|
89
86
|
}
|
|
90
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @protected
|
|
90
|
+
* @configure FocusMixin
|
|
91
|
+
*/
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
get _focusableNode() {
|
|
94
|
+
return this._invokerNode;
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
/**
|
|
92
98
|
* @configure ListboxMixin
|
|
93
99
|
* @protected
|
|
@@ -262,7 +268,7 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
262
268
|
|
|
263
269
|
/** @protected */
|
|
264
270
|
_onFormElementsChanged() {
|
|
265
|
-
this.singleOption = this.formElements.length === 1;
|
|
271
|
+
this.singleOption = this.formElements.length === 1 && !this.hasNoDefaultSelected;
|
|
266
272
|
this._invokerNode.singleOption = this.singleOption;
|
|
267
273
|
}
|
|
268
274
|
|
|
@@ -336,6 +342,8 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
|
|
336
342
|
_defineOverlayConfig() {
|
|
337
343
|
return {
|
|
338
344
|
...withDropdownConfig(),
|
|
345
|
+
// Needs more advanced behavior (see `__invokerOnClick`)
|
|
346
|
+
visibilityTriggerFunction: undefined,
|
|
339
347
|
};
|
|
340
348
|
}
|
|
341
349
|
|
|
@@ -49,10 +49,21 @@ describe('lion-select-rich', () => {
|
|
|
49
49
|
expect(document.activeElement === document.body).to.be.true;
|
|
50
50
|
const { _labelNode, _invokerNode } = getSelectRichMembers(el);
|
|
51
51
|
_labelNode.click();
|
|
52
|
-
|
|
53
52
|
expect(document.activeElement === _invokerNode).to.be.true;
|
|
54
53
|
});
|
|
55
54
|
|
|
55
|
+
it('has an attribute focused when focused', async () => {
|
|
56
|
+
const el = await fixture(html` <lion-select-rich label="foo"> </lion-select-rich> `);
|
|
57
|
+
|
|
58
|
+
el.focus();
|
|
59
|
+
await el.updateComplete;
|
|
60
|
+
expect(el.hasAttribute('focused')).to.be.true;
|
|
61
|
+
|
|
62
|
+
el.blur();
|
|
63
|
+
await el.updateComplete;
|
|
64
|
+
expect(el.hasAttribute('focused')).to.be.false;
|
|
65
|
+
});
|
|
66
|
+
|
|
56
67
|
it('checks the first enabled option', async () => {
|
|
57
68
|
const el = await fixture(html`
|
|
58
69
|
<lion-select-rich>
|
|
@@ -400,6 +411,19 @@ describe('lion-select-rich', () => {
|
|
|
400
411
|
expect(el.singleOption).to.be.false;
|
|
401
412
|
expect(_invokerNode.singleOption).to.be.false;
|
|
402
413
|
});
|
|
414
|
+
|
|
415
|
+
it('should have singleOption only if one option and no hasNoDefaultSelected', async () => {
|
|
416
|
+
const el = await fixture(html`
|
|
417
|
+
<lion-select-rich has-no-default-selected>
|
|
418
|
+
<lion-option .choiceValue=${10}>Item 1</lion-option>
|
|
419
|
+
</lion-select-rich>
|
|
420
|
+
`);
|
|
421
|
+
|
|
422
|
+
const { _invokerNode } = getSelectRichMembers(el);
|
|
423
|
+
|
|
424
|
+
expect(el.singleOption).to.be.false;
|
|
425
|
+
expect(_invokerNode.singleOption).to.be.false;
|
|
426
|
+
});
|
|
403
427
|
});
|
|
404
428
|
|
|
405
429
|
describe('interaction-mode', () => {
|
|
@@ -32,6 +32,10 @@ export class LionTooltip extends ArrowMixin(OverlayMixin(LitElement)) {
|
|
|
32
32
|
:host([hidden]) {
|
|
33
33
|
display: none;
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
::slotted([slot='content']) {
|
|
37
|
+
width: max-content;
|
|
38
|
+
}
|
|
35
39
|
`,
|
|
36
40
|
];
|
|
37
41
|
}
|
|
@@ -54,9 +58,19 @@ export class LionTooltip extends ArrowMixin(OverlayMixin(LitElement)) {
|
|
|
54
58
|
/** @protected */
|
|
55
59
|
// eslint-disable-next-line class-methods-use-this
|
|
56
60
|
_defineOverlayConfig() {
|
|
61
|
+
const superCfg = super._defineOverlayConfig();
|
|
62
|
+
const tooltipCfg = withTooltipConfig({ invokerRelation: this.invokerRelation });
|
|
57
63
|
return /** @type {OverlayConfig} */ ({
|
|
58
|
-
...
|
|
59
|
-
...
|
|
64
|
+
...superCfg,
|
|
65
|
+
...tooltipCfg,
|
|
66
|
+
popperConfig: {
|
|
67
|
+
...(superCfg.popperConfig || {}),
|
|
68
|
+
...(tooltipCfg.popperConfig || {}),
|
|
69
|
+
modifiers: [
|
|
70
|
+
...(superCfg.popperConfig?.modifiers || []),
|
|
71
|
+
...(tooltipCfg.popperConfig?.modifiers || []),
|
|
72
|
+
],
|
|
73
|
+
},
|
|
60
74
|
});
|
|
61
75
|
}
|
|
62
76
|
}
|
|
@@ -227,8 +227,7 @@ describe('lion-tooltip', () => {
|
|
|
227
227
|
expect(el._arrowNode).to.be.displayed;
|
|
228
228
|
});
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
it.skip('makes sure positioning of the arrow is correct', async () => {
|
|
230
|
+
it('makes sure positioning of the arrow is correct', async () => {
|
|
232
231
|
const el = /** @type {LionTooltip} */ (
|
|
233
232
|
await fixture(html`
|
|
234
233
|
<lion-tooltip
|