@lion/ui 0.0.9 → 0.0.10
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/core/src/SlotMixin.js +2 -1
- package/components/dialog/test/lion-dialog.test.js +3 -7
- 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 +64 -100
- 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/test/number/formatNumber.test.js +2 -6
- package/components/overlays/src/OverlayController.js +236 -289
- package/components/overlays/src/OverlayMixin.js +17 -18
- package/components/overlays/src/OverlaysManager.js +28 -53
- 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 +306 -273
- 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 +32 -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/custom-elements.json +251 -362
- package/dist-types/components/core/src/SlotMixin.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 +46 -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/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 +14 -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/exports/input-datepicker.d.ts +0 -1
- package/dist-types/exports/overlays.d.ts +0 -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 +0 -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
|
@@ -1,89 +1,117 @@
|
|
|
1
1
|
import { EventTargetShim } from '@lion/ui/core.js';
|
|
2
|
+
import { adoptStyles } from 'lit';
|
|
2
3
|
import { overlays } from './singleton.js';
|
|
3
4
|
import { containFocus } from './utils/contain-focus.js';
|
|
5
|
+
import { overlayShadowDomStyle } from './overlayShadowDomStyle.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* @typedef {import('
|
|
7
|
-
* @typedef {import('
|
|
8
|
-
* @typedef {import('@popperjs/core
|
|
9
|
-
* @typedef {import('@popperjs/core
|
|
10
|
-
* @typedef {import('@popperjs/core
|
|
8
|
+
* @typedef {import('@lion/ui/types/overlays.js').OverlayConfig} OverlayConfig
|
|
9
|
+
* @typedef {import('@lion/ui/types/overlays.js').ViewportConfig} ViewportConfig
|
|
10
|
+
* @typedef {import('@popperjs/core').createPopper} Popper
|
|
11
|
+
* @typedef {import('@popperjs/core').Options} PopperOptions
|
|
12
|
+
* @typedef {import('@popperjs/core').Placement} Placement
|
|
11
13
|
* @typedef {{ createPopper: Popper }} PopperModule
|
|
12
14
|
* @typedef {'setup'|'init'|'teardown'|'before-show'|'show'|'hide'|'add'|'remove'} OverlayPhase
|
|
13
15
|
*/
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* From:
|
|
19
|
+
* - wrappingDialogNodeL1: `<dialog role="none"/>`
|
|
20
|
+
* - contentWrapperNodeL2: `<div id="content-wrapper-node"/>`
|
|
21
|
+
* - contentNodeL3: `<div slot="my-content"/>`
|
|
22
|
+
* To:
|
|
23
|
+
* ```html
|
|
24
|
+
* <dialog role="none">
|
|
25
|
+
* <div id="content-wrapper-node">
|
|
26
|
+
* <!-- this was the (slot for) original content node -->
|
|
27
|
+
* <slot name="my-content"></slot>
|
|
28
|
+
* </div>
|
|
29
|
+
* </dialog>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* `<slot name="my-content">` belonging to `<div slot="content"/>` will be wrapped with wrappingDialogNodeL1 and contentWrapperNodeL2
|
|
33
|
+
* inside shadow dom. With the help of temp markers, `<slot name="my-content">`'s original position will be respected.
|
|
34
|
+
*
|
|
35
|
+
* @param {{ wrappingDialogNodeL1:HTMLDialogElement|HTMLDivElement; contentWrapperNodeL2:Element; contentNodeL3: Element }} opts
|
|
36
|
+
*/
|
|
37
|
+
function rearrangeNodes({ wrappingDialogNodeL1, contentWrapperNodeL2, contentNodeL3 }) {
|
|
38
|
+
if (!(contentWrapperNodeL2.isConnected || contentNodeL3.isConnected)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
'[OverlayController] Could not find a render target, since the provided contentNode is not connected to the DOM. Make sure that it is connected, e.g. by doing "document.body.appendChild(contentNode)", before passing it on.',
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let parentElement;
|
|
45
|
+
const tempMarker = document.createComment('temp-marker');
|
|
46
|
+
|
|
47
|
+
if (contentWrapperNodeL2.isConnected) {
|
|
48
|
+
// This is the case when contentWrapperNode (living in shadow dom, wrapping <slot name="my-content-outlet">) is already provided via controller.
|
|
49
|
+
parentElement = contentWrapperNodeL2.parentElement || contentWrapperNodeL2.getRootNode();
|
|
50
|
+
parentElement.insertBefore(tempMarker, contentWrapperNodeL2);
|
|
51
|
+
// Wrap...
|
|
52
|
+
wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
|
|
53
|
+
}
|
|
54
|
+
// if contentNodeL3.isConnected
|
|
55
|
+
else {
|
|
56
|
+
const contentIsProjected = contentNodeL3.assignedSlot;
|
|
57
|
+
if (contentIsProjected) {
|
|
58
|
+
parentElement =
|
|
59
|
+
contentNodeL3.assignedSlot.parentElement || contentNodeL3.assignedSlot.getRootNode();
|
|
60
|
+
parentElement.insertBefore(tempMarker, contentNodeL3.assignedSlot);
|
|
61
|
+
wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
|
|
62
|
+
// Important: we do not move around contentNodeL3, but the assigned slot
|
|
63
|
+
contentWrapperNodeL2.appendChild(contentNodeL3.assignedSlot);
|
|
64
|
+
} else {
|
|
65
|
+
parentElement = contentNodeL3.parentElement || contentNodeL3.getRootNode();
|
|
66
|
+
parentElement.insertBefore(tempMarker, contentNodeL3);
|
|
67
|
+
wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
|
|
68
|
+
contentWrapperNodeL2.appendChild(contentNodeL3);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* From:
|
|
74
|
+
* ```html
|
|
75
|
+
* #shadow-root:
|
|
76
|
+
* <div>
|
|
77
|
+
* <!-- tempMarker -->
|
|
78
|
+
* <slot name="x"/>
|
|
79
|
+
* </div>
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* To:
|
|
83
|
+
* ```html
|
|
84
|
+
* #shadow-root:
|
|
85
|
+
* <div>
|
|
86
|
+
* <!-- tempMarker -->
|
|
87
|
+
* <dialog role="none">
|
|
88
|
+
* <div id="content-wrapper-node">
|
|
89
|
+
* <slot name="x"/>
|
|
90
|
+
* </div>
|
|
91
|
+
* </dialog>
|
|
92
|
+
* </div>
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
parentElement.insertBefore(wrappingDialogNodeL1, tempMarker);
|
|
96
|
+
parentElement?.removeChild(tempMarker);
|
|
97
|
+
}
|
|
98
|
+
|
|
15
99
|
/**
|
|
16
100
|
* @returns {Promise<PopperModule>}
|
|
17
101
|
*/
|
|
18
102
|
async function preloadPopper() {
|
|
19
|
-
|
|
20
|
-
// @ts-ignore
|
|
103
|
+
// @ts-ignore [external]: import complains about untyped module, but we typecast it ourselves
|
|
21
104
|
return /** @type {* & Promise<PopperModule>} */ (import('@popperjs/core/dist/esm/popper.js'));
|
|
22
|
-
/* eslint-enable import/no-extraneous-dependencies */
|
|
23
105
|
}
|
|
24
106
|
|
|
25
|
-
const GLOBAL_OVERLAYS_CONTAINER_CLASS = 'global-overlays__overlay-container';
|
|
26
|
-
const GLOBAL_OVERLAYS_CLASS = 'global-overlays__overlay';
|
|
27
107
|
// @ts-expect-error [external]: CSS not yet typed
|
|
28
108
|
const supportsCSSTypedObject = window.CSS?.number && document.body.attributeStyleMap?.set;
|
|
29
109
|
|
|
30
110
|
/**
|
|
31
|
-
*
|
|
111
|
+
* OverlayController is the fundament for every single type of overlay. With the right
|
|
32
112
|
* configuration, it can be used to build (modal) dialogs, tooltips, dropdowns, popovers,
|
|
33
113
|
* bottom/top/left/right sheets etc.
|
|
34
114
|
*
|
|
35
|
-
* ### About contentNode, contentWrapperNode and renderTarget.
|
|
36
|
-
*
|
|
37
|
-
* #### contentNode
|
|
38
|
-
* Node containing actual overlay contents.
|
|
39
|
-
* It will not be touched by the OverlayController, it will only set attributes needed
|
|
40
|
-
* for accessibility.
|
|
41
|
-
*
|
|
42
|
-
* #### contentWrapperNode
|
|
43
|
-
* The 'positioning' element.
|
|
44
|
-
* For local overlays, this node will be provided to Popper and all
|
|
45
|
-
* inline positioning styles will be added here. It will also act as the container of an arrow
|
|
46
|
-
* element (the arrow needs to be a sibling of contentNode for Popper to work correctly).
|
|
47
|
-
* When projecting a contentNode from a shadowRoot, it is essential to have the wrapper in
|
|
48
|
-
* shadow dom, so that contentNode can be styled via `::slotted` from the shadow root.
|
|
49
|
-
* The Popper arrow can then be styled from that same shadow root as well.
|
|
50
|
-
* For global overlays, the contentWrapperNode will be appended to the globalRootNode structure.
|
|
51
|
-
*
|
|
52
|
-
* #### renderTarget
|
|
53
|
-
* Usually the parent node of contentWrapperNode that either exists locally or globally.
|
|
54
|
-
* When a responsive scenario is created (in which we switch from global to local or vice versa)
|
|
55
|
-
* we need to know where we should reappend contentWrapperNode (or contentNode in case it's projected)
|
|
56
|
-
*
|
|
57
|
-
* So a regular flow can be summarized as follows:
|
|
58
|
-
* 1. Application Developer spawns an OverlayController with a contentNode reference
|
|
59
|
-
* 2. OverlayController will create a contentWrapperNode around contentNode (or consumes when provided)
|
|
60
|
-
* 3. contentWrapperNode will be appended to the right renderTarget
|
|
61
|
-
*
|
|
62
|
-
* There are subtle differences depending on the following factors:
|
|
63
|
-
* - whether in global/local placement mode
|
|
64
|
-
* - whether contentNode projected
|
|
65
|
-
* - whether an arrow is provided
|
|
66
|
-
*
|
|
67
|
-
* This leads to the following possible combinations:
|
|
68
|
-
* - [l1]. local + no content projection + no arrow
|
|
69
|
-
* - [l2]. local + content projection + no arrow
|
|
70
|
-
* - [l3]. local + no content projection + arrow
|
|
71
|
-
* - [l4]. local + content projection + arrow
|
|
72
|
-
* - [g1]. global
|
|
73
|
-
*
|
|
74
|
-
* #### html structure for a content projected node
|
|
75
|
-
* <div id="contentWrapperNode">
|
|
76
|
-
* <slot name="contentNode"></slot>
|
|
77
|
-
* <div x-arrow></div>
|
|
78
|
-
* </div>
|
|
79
|
-
*
|
|
80
|
-
* Structure above depicts [l4]
|
|
81
|
-
* So in case of [l1] and [l3], the <slot> element would be a regular element
|
|
82
|
-
* In case of [l1] and [l2], there would be no arrow.
|
|
83
|
-
* Note that a contentWrapperNode should be provided for [l2], [l3] and [l4]
|
|
84
|
-
* In case of a global overlay ([g1]), it's enough to provide just the contentNode.
|
|
85
|
-
* In case of a local overlay or a responsive overlay switching from placementMode, one should
|
|
86
|
-
* always configure as if it were a local overlay.
|
|
87
115
|
*/
|
|
88
116
|
export class OverlayController extends EventTargetShim {
|
|
89
117
|
/**
|
|
@@ -97,6 +125,9 @@ export class OverlayController extends EventTargetShim {
|
|
|
97
125
|
/** @private */
|
|
98
126
|
this.__sharedConfig = config;
|
|
99
127
|
|
|
128
|
+
/** @type {OverlayConfig} */
|
|
129
|
+
this.config = {};
|
|
130
|
+
|
|
100
131
|
/**
|
|
101
132
|
* @type {OverlayConfig}
|
|
102
133
|
* @protected
|
|
@@ -123,7 +154,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
123
154
|
handlesAccessibility: false,
|
|
124
155
|
popperConfig: {
|
|
125
156
|
placement: 'top',
|
|
126
|
-
strategy: '
|
|
157
|
+
strategy: 'fixed',
|
|
127
158
|
modifiers: [
|
|
128
159
|
{
|
|
129
160
|
name: 'preventOverflow',
|
|
@@ -156,6 +187,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
156
187
|
viewportConfig: {
|
|
157
188
|
placement: 'center',
|
|
158
189
|
},
|
|
190
|
+
zIndex: 9999,
|
|
159
191
|
};
|
|
160
192
|
|
|
161
193
|
this.manager.add(this);
|
|
@@ -163,25 +195,11 @@ export class OverlayController extends EventTargetShim {
|
|
|
163
195
|
this._contentId = `overlay-content--${Math.random().toString(36).substr(2, 10)}`;
|
|
164
196
|
/** @private */
|
|
165
197
|
this.__originalAttrs = new Map();
|
|
166
|
-
if (this._defaultConfig.contentNode) {
|
|
167
|
-
if (!this._defaultConfig.contentNode.isConnected) {
|
|
168
|
-
throw new Error(
|
|
169
|
-
'[OverlayController] Could not find a render target, since the provided contentNode is not connected to the DOM. Make sure that it is connected, e.g. by doing "document.body.appendChild(contentNode)", before passing it on.',
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
this.__isContentNodeProjected = Boolean(this._defaultConfig.contentNode.assignedSlot);
|
|
173
|
-
}
|
|
174
198
|
this.updateConfig(config);
|
|
175
199
|
/** @private */
|
|
176
200
|
this.__hasActiveTrapsKeyboardFocus = false;
|
|
177
201
|
/** @private */
|
|
178
202
|
this.__hasActiveBackdrop = true;
|
|
179
|
-
/**
|
|
180
|
-
* @type {HTMLElement | undefined}
|
|
181
|
-
* @private
|
|
182
|
-
*/
|
|
183
|
-
this.__backdropNodeToBeTornDown = undefined;
|
|
184
|
-
|
|
185
203
|
/** @private */
|
|
186
204
|
this.__escKeyHandler = this.__escKeyHandler.bind(this);
|
|
187
205
|
}
|
|
@@ -196,10 +214,10 @@ export class OverlayController extends EventTargetShim {
|
|
|
196
214
|
|
|
197
215
|
/**
|
|
198
216
|
* The contentWrapperNode
|
|
199
|
-
* @type {
|
|
217
|
+
* @type {HTMLDialogElement | HTMLDivElement}
|
|
200
218
|
*/
|
|
201
219
|
get content() {
|
|
202
|
-
return /** @type {
|
|
220
|
+
return /** @type {HTMLDialogElement | HTMLDivElement} */ (this.__wrappingDialogNode);
|
|
203
221
|
}
|
|
204
222
|
|
|
205
223
|
/**
|
|
@@ -385,28 +403,6 @@ export class OverlayController extends EventTargetShim {
|
|
|
385
403
|
return /** @type {ViewportConfig} */ (this.config?.viewportConfig);
|
|
386
404
|
}
|
|
387
405
|
|
|
388
|
-
/**
|
|
389
|
-
* Usually the parent node of contentWrapperNode that either exists locally or globally.
|
|
390
|
-
* When a responsive scenario is created (in which we switch from global to local or vice versa)
|
|
391
|
-
* we need to know where we should reappend contentWrapperNode (or contentNode in case it's
|
|
392
|
-
* projected).
|
|
393
|
-
* @type {HTMLElement}
|
|
394
|
-
* @protected
|
|
395
|
-
*/
|
|
396
|
-
get _renderTarget() {
|
|
397
|
-
/** config [g1] */
|
|
398
|
-
if (this.placementMode === 'global') {
|
|
399
|
-
return this.manager.globalRootNode;
|
|
400
|
-
}
|
|
401
|
-
/** config [l2] or [l4] */
|
|
402
|
-
if (this.__isContentNodeProjected) {
|
|
403
|
-
// @ts-expect-error [external]: fix Node types
|
|
404
|
-
return this.__originalContentParent?.getRootNode().host;
|
|
405
|
-
}
|
|
406
|
-
/** config [l1] or [l3] */
|
|
407
|
-
return /** @type {HTMLElement} */ (this.__originalContentParent);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
406
|
/**
|
|
411
407
|
* @desc The element our local overlay will be positioned relative to.
|
|
412
408
|
* @type {HTMLElement | undefined}
|
|
@@ -420,12 +416,8 @@ export class OverlayController extends EventTargetShim {
|
|
|
420
416
|
* @param {number} value
|
|
421
417
|
*/
|
|
422
418
|
set elevation(value) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
if (this.backdropNode) {
|
|
427
|
-
this.backdropNode.style.zIndex = `${value}`;
|
|
428
|
-
}
|
|
419
|
+
// @ts-expect-error find out why config would/could be undfined
|
|
420
|
+
this.__wrappingDialogNode.style.zIndex = `${this.config.zIndex + value}`;
|
|
429
421
|
}
|
|
430
422
|
|
|
431
423
|
/**
|
|
@@ -450,7 +442,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
450
442
|
* @type {OverlayConfig}
|
|
451
443
|
* @private
|
|
452
444
|
*/
|
|
453
|
-
this.__prevConfig = this.config
|
|
445
|
+
this.__prevConfig = this.config;
|
|
454
446
|
|
|
455
447
|
/** @type {OverlayConfig} */
|
|
456
448
|
this.config = {
|
|
@@ -472,9 +464,9 @@ export class OverlayController extends EventTargetShim {
|
|
|
472
464
|
};
|
|
473
465
|
|
|
474
466
|
/** @private */
|
|
475
|
-
this.__validateConfiguration(
|
|
467
|
+
this.__validateConfiguration(this.config);
|
|
476
468
|
/** @protected */
|
|
477
|
-
this._init(
|
|
469
|
+
this._init();
|
|
478
470
|
/** @private */
|
|
479
471
|
this.__elementToFocusAfterHide = undefined;
|
|
480
472
|
}
|
|
@@ -498,16 +490,6 @@ export class OverlayController extends EventTargetShim {
|
|
|
498
490
|
if (!newConfig.contentNode) {
|
|
499
491
|
throw new Error('[OverlayController] You need to provide a .contentNode');
|
|
500
492
|
}
|
|
501
|
-
if (this.__isContentNodeProjected && !newConfig.contentWrapperNode) {
|
|
502
|
-
throw new Error(
|
|
503
|
-
'[OverlayController] You need to provide a .contentWrapperNode when .contentNode is projected',
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
if (newConfig.isTooltip && newConfig.placementMode !== 'local') {
|
|
507
|
-
throw new Error(
|
|
508
|
-
'[OverlayController] .isTooltip should be configured with .placementMode "local"',
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
493
|
if (newConfig.isTooltip && !newConfig.handlesAccessibility) {
|
|
512
494
|
throw new Error(
|
|
513
495
|
'[OverlayController] .isTooltip only takes effect when .handlesAccessibility is enabled',
|
|
@@ -519,85 +501,95 @@ export class OverlayController extends EventTargetShim {
|
|
|
519
501
|
}
|
|
520
502
|
|
|
521
503
|
/**
|
|
522
|
-
* @param {{ cfgToAdd: OverlayConfig }} options
|
|
523
504
|
* @protected
|
|
524
505
|
*/
|
|
525
|
-
_init(
|
|
526
|
-
this.
|
|
527
|
-
|
|
506
|
+
_init() {
|
|
507
|
+
if (!this.__contentHasBeenInitialized) {
|
|
508
|
+
this.__initContentDomStructure();
|
|
509
|
+
this.__contentHasBeenInitialized = true;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Reset all positioning styles (local, c.q. Popper) and classes (global)
|
|
513
|
+
this.contentWrapperNode.removeAttribute('style');
|
|
514
|
+
this.contentWrapperNode.removeAttribute('class');
|
|
528
515
|
|
|
529
516
|
if (this.placementMode === 'local') {
|
|
530
517
|
// Lazily load Popper if not done yet
|
|
531
518
|
if (!OverlayController.popperModule) {
|
|
532
|
-
// a@ts-expect-error FIXME: for some reason createPopper is missing here
|
|
533
519
|
OverlayController.popperModule = preloadPopper();
|
|
534
520
|
}
|
|
535
521
|
}
|
|
522
|
+
const rootNode = /** @type {ShadowRoot} */ (this.contentWrapperNode.getRootNode());
|
|
523
|
+
adoptStyles(rootNode, [...(rootNode.adoptedStyleSheets || []), overlayShadowDomStyle]);
|
|
536
524
|
this._handleFeatures({ phase: 'init' });
|
|
537
525
|
}
|
|
538
526
|
|
|
539
|
-
/** @private */
|
|
540
|
-
__initConnectionTarget() {
|
|
541
|
-
// Now, add our node to the right place in dom (renderTarget)
|
|
542
|
-
if (this.contentWrapperNode !== this.__prevConfig?.contentWrapperNode) {
|
|
543
|
-
if (this.config?.placementMode === 'global' || !this.__isContentNodeProjected) {
|
|
544
|
-
/** @type {HTMLElement} */
|
|
545
|
-
(this.contentWrapperNode).appendChild(this.contentNode);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (!this._renderTarget) {
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if (this.__isContentNodeProjected && this.placementMode === 'local') {
|
|
554
|
-
// We add the contentNode in its slot, so that it will be projected by contentWrapperNode
|
|
555
|
-
this._renderTarget.appendChild(this.contentNode);
|
|
556
|
-
} else {
|
|
557
|
-
const isInsideRenderTarget = this._renderTarget === this.contentWrapperNode.parentNode;
|
|
558
|
-
const nodeContainsTarget = this.contentWrapperNode.contains(this._renderTarget);
|
|
559
|
-
if (!isInsideRenderTarget && !nodeContainsTarget) {
|
|
560
|
-
// contentWrapperNode becomes the direct (non projected) parent of contentNode
|
|
561
|
-
this._renderTarget.appendChild(this.contentWrapperNode);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
527
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
528
|
+
* Here we arrange our content node via:
|
|
529
|
+
* 1. HTMLDialogElement: the content will always be painted to the browser's top layer
|
|
530
|
+
* - no matter what context the contentNode lives in, the overlay will be painted correctly via the <dialog> element,
|
|
531
|
+
* even if 'overflow:hidden' or a css transform is applied in its parent hierarchy.
|
|
532
|
+
* - the dialog element will be unstyled, but will span the whole screen
|
|
533
|
+
* - a backdrop element will be a child of the dialog element, so it leverages the capabilities of the parent
|
|
534
|
+
* (filling the whole screen if wanted an always painted to top layer)
|
|
535
|
+
* 2. ContentWrapper: the content receives the right positioning styles in a clean/non conflicting way:
|
|
536
|
+
* - local positioning: receive inline (position) styling that can never conflict with the already existing computed styles
|
|
537
|
+
* - global positioning: receive flex (child) classes that position the content correctly relative to the viewport
|
|
538
|
+
*
|
|
539
|
+
* The resulting structure that will be created looks like this:
|
|
540
|
+
*
|
|
541
|
+
* ...
|
|
542
|
+
* <dialog role="none">
|
|
543
|
+
* <div id="optional-backdrop"></div>
|
|
544
|
+
* <div id="content-wrapper-node">
|
|
545
|
+
* <!-- this was the (slot for) original content node -->
|
|
546
|
+
* <slot name="content"></slot>
|
|
547
|
+
* </div>
|
|
548
|
+
* </dialog>
|
|
549
|
+
* ...
|
|
550
|
+
*
|
|
570
551
|
* @private
|
|
571
552
|
*/
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
553
|
+
__initContentDomStructure() {
|
|
554
|
+
const wrappingDialogElement = document.createElement(
|
|
555
|
+
this.config?._noDialogEl ? 'div' : 'dialog',
|
|
556
|
+
);
|
|
557
|
+
// We use a dialog for its visual capabilities: it renders to the top layer.
|
|
558
|
+
// A11y will depend on the type of overlay and is arranged on contentNode level.
|
|
559
|
+
// Also see: https://www.scottohara.me/blog/2019/03/05/open-dialog.html
|
|
560
|
+
wrappingDialogElement.setAttribute('role', 'none');
|
|
561
|
+
wrappingDialogElement.setAttribute('data-overlay-outer-wrapper', '');
|
|
562
|
+
// N.B. position: fixed is needed to escape out of 'overflow: hidden'
|
|
563
|
+
// We give a high z-index for non-modal dialogs, so that we at least win from all siblings of our
|
|
564
|
+
// parent stacking context
|
|
565
|
+
wrappingDialogElement.style.cssText = `display:none; z-index: ${this.config.zIndex};`;
|
|
566
|
+
this.__wrappingDialogNode = wrappingDialogElement;
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Based on the configuration of the developer, multiple scenarios are accounted for
|
|
570
|
+
* A. We already have a contentWrapperNode ()
|
|
571
|
+
*/
|
|
572
|
+
if (!this.config?.contentWrapperNode) {
|
|
578
573
|
this.__contentWrapperNode = document.createElement('div');
|
|
579
574
|
}
|
|
575
|
+
this.contentWrapperNode.setAttribute('data-id', 'content-wrapper');
|
|
576
|
+
|
|
577
|
+
rearrangeNodes({
|
|
578
|
+
wrappingDialogNodeL1: wrappingDialogElement,
|
|
579
|
+
contentWrapperNodeL2: this.contentWrapperNode,
|
|
580
|
+
contentNodeL3: this.contentNode,
|
|
581
|
+
});
|
|
582
|
+
// @ts-ignore
|
|
583
|
+
wrappingDialogElement.open = true;
|
|
580
584
|
|
|
581
|
-
this.
|
|
582
|
-
this.contentWrapperNode.style.
|
|
585
|
+
this.__wrappingDialogNode.style.display = 'none';
|
|
586
|
+
this.contentWrapperNode.style.zIndex = '1';
|
|
583
587
|
|
|
584
588
|
if (getComputedStyle(this.contentNode).position === 'absolute') {
|
|
585
589
|
// Having a _contWrapperNode and a contentNode with 'position:absolute' results in
|
|
586
590
|
// computed height of 0...
|
|
587
591
|
this.contentNode.style.position = 'static';
|
|
588
592
|
}
|
|
589
|
-
|
|
590
|
-
if (this.__isContentNodeProjected && this.contentWrapperNode.isConnected) {
|
|
591
|
-
// We need to keep track of the original local context.
|
|
592
|
-
/** config [l2], [l4] */
|
|
593
|
-
this.__originalContentParent = /** @type {HTMLElement} */ (
|
|
594
|
-
this.contentWrapperNode.parentNode
|
|
595
|
-
);
|
|
596
|
-
} else if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) {
|
|
597
|
-
// We need to keep track of the original local context.
|
|
598
|
-
/** config [l1], [l3], [g1] */
|
|
599
|
-
this.__originalContentParent = /** @type {HTMLElement} */ (this.contentNode?.parentNode);
|
|
600
|
-
}
|
|
601
593
|
}
|
|
602
594
|
|
|
603
595
|
/**
|
|
@@ -613,7 +605,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
613
605
|
if (phase === 'setup') {
|
|
614
606
|
const zIndexNumber = Number(getComputedStyle(this.contentNode).zIndex);
|
|
615
607
|
if (zIndexNumber < 1 || Number.isNaN(zIndexNumber)) {
|
|
616
|
-
this.
|
|
608
|
+
this.contentNode.style.zIndex = '1';
|
|
617
609
|
}
|
|
618
610
|
}
|
|
619
611
|
}
|
|
@@ -686,7 +678,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
686
678
|
}
|
|
687
679
|
|
|
688
680
|
get isShown() {
|
|
689
|
-
return Boolean(this.
|
|
681
|
+
return Boolean(this.__wrappingDialogNode?.style.display !== 'none');
|
|
690
682
|
}
|
|
691
683
|
|
|
692
684
|
/**
|
|
@@ -717,7 +709,11 @@ export class OverlayController extends EventTargetShim {
|
|
|
717
709
|
const event = new CustomEvent('before-show', { cancelable: true });
|
|
718
710
|
this.dispatchEvent(event);
|
|
719
711
|
if (!event.defaultPrevented) {
|
|
720
|
-
this.
|
|
712
|
+
if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
713
|
+
this.__wrappingDialogNode.show();
|
|
714
|
+
}
|
|
715
|
+
// @ts-ignore
|
|
716
|
+
this.__wrappingDialogNode.style.display = '';
|
|
721
717
|
this._keepBodySize({ phase: 'before-show' });
|
|
722
718
|
await this._handleFeatures({ phase: 'show' });
|
|
723
719
|
this._keepBodySize({ phase: 'show' });
|
|
@@ -739,11 +735,17 @@ export class OverlayController extends EventTargetShim {
|
|
|
739
735
|
*/
|
|
740
736
|
async _handlePosition({ phase }) {
|
|
741
737
|
if (this.placementMode === 'global') {
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
738
|
+
const placementClass = `overlays__overlay-container--${this.viewportConfig.placement}`;
|
|
739
|
+
|
|
740
|
+
if (phase === 'show') {
|
|
741
|
+
this.contentWrapperNode.classList.add('overlays__overlay-container');
|
|
742
|
+
this.contentWrapperNode.classList.add(placementClass);
|
|
743
|
+
this.contentNode.classList.add('overlays__overlay');
|
|
744
|
+
} else if (phase === 'hide') {
|
|
745
|
+
this.contentWrapperNode.classList.remove('overlays__overlay-container');
|
|
746
|
+
this.contentWrapperNode.classList.remove(placementClass);
|
|
747
|
+
this.contentNode.classList.remove('overlays__overlay');
|
|
748
|
+
}
|
|
747
749
|
} else if (this.placementMode === 'local' && phase === 'show') {
|
|
748
750
|
/**
|
|
749
751
|
* Popper is weird about properly positioning the popper element when it is recreated so
|
|
@@ -753,7 +755,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
753
755
|
* This is however necessary for initial placement.
|
|
754
756
|
*/
|
|
755
757
|
await this.__createPopperInstance();
|
|
756
|
-
|
|
758
|
+
this._popper.forceUpdate();
|
|
757
759
|
}
|
|
758
760
|
}
|
|
759
761
|
|
|
@@ -829,7 +831,11 @@ export class OverlayController extends EventTargetShim {
|
|
|
829
831
|
contentNode: this.contentNode,
|
|
830
832
|
});
|
|
831
833
|
|
|
832
|
-
this.
|
|
834
|
+
if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
835
|
+
this.__wrappingDialogNode.close();
|
|
836
|
+
}
|
|
837
|
+
// @ts-ignore
|
|
838
|
+
this.__wrappingDialogNode.style.display = 'none';
|
|
833
839
|
this._handleFeatures({ phase: 'hide' });
|
|
834
840
|
this._keepBodySize({ phase: 'hide' });
|
|
835
841
|
this.dispatchEvent(new Event('hide'));
|
|
@@ -843,6 +849,7 @@ export class OverlayController extends EventTargetShim {
|
|
|
843
849
|
*
|
|
844
850
|
* @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} hideConfig
|
|
845
851
|
*/
|
|
852
|
+
// @ts-ignore
|
|
846
853
|
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
|
847
854
|
async transitionHide(hideConfig) {}
|
|
848
855
|
|
|
@@ -851,48 +858,27 @@ export class OverlayController extends EventTargetShim {
|
|
|
851
858
|
* @protected
|
|
852
859
|
*/
|
|
853
860
|
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
|
854
|
-
async _transitionHide(
|
|
861
|
+
async _transitionHide({ backdropNode, contentNode }) {
|
|
855
862
|
// `this.transitionHide` is a hook for our users
|
|
856
|
-
await this.transitionHide({ backdropNode
|
|
857
|
-
|
|
858
|
-
if (
|
|
859
|
-
|
|
860
|
-
`${this.placementMode}-overlays__backdrop--animation-in`,
|
|
861
|
-
);
|
|
862
|
-
/** @type {() => void} */
|
|
863
|
-
let afterFadeOut = () => {};
|
|
864
|
-
hideConfig.backdropNode.classList.add(
|
|
865
|
-
`${this.placementMode}-overlays__backdrop--animation-out`,
|
|
866
|
-
);
|
|
867
|
-
this.__backdropAnimation = new Promise(resolve => {
|
|
868
|
-
afterFadeOut = () => {
|
|
869
|
-
if (hideConfig.backdropNode) {
|
|
870
|
-
hideConfig.backdropNode.classList.remove(
|
|
871
|
-
`${this.placementMode}-overlays__backdrop--animation-out`,
|
|
872
|
-
);
|
|
873
|
-
hideConfig.backdropNode.classList.remove(
|
|
874
|
-
`${this.placementMode}-overlays__backdrop--visible`,
|
|
875
|
-
);
|
|
876
|
-
hideConfig.backdropNode.removeEventListener('animationend', afterFadeOut);
|
|
877
|
-
}
|
|
878
|
-
resolve(undefined);
|
|
879
|
-
};
|
|
880
|
-
});
|
|
881
|
-
|
|
882
|
-
hideConfig.backdropNode.addEventListener('animationend', afterFadeOut);
|
|
863
|
+
await this.transitionHide({ backdropNode, contentNode });
|
|
864
|
+
this._handlePosition({ phase: 'hide' });
|
|
865
|
+
if (!backdropNode) {
|
|
866
|
+
return;
|
|
883
867
|
}
|
|
868
|
+
backdropNode.classList.remove(`overlays__backdrop--animation-in`);
|
|
884
869
|
}
|
|
885
870
|
|
|
886
871
|
/**
|
|
887
872
|
* To be overridden by subclassers
|
|
888
873
|
*
|
|
889
|
-
* @param {{backdropNode:HTMLElement
|
|
874
|
+
* @param {{backdropNode:HTMLElement; contentNode:HTMLElement}} showConfig
|
|
890
875
|
*/
|
|
876
|
+
// @ts-ignore
|
|
891
877
|
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
|
892
878
|
async transitionShow(showConfig) {}
|
|
893
879
|
|
|
894
880
|
/**
|
|
895
|
-
* @param {{backdropNode:HTMLElement
|
|
881
|
+
* @param {{backdropNode:HTMLElement; contentNode:HTMLElement}} showConfig
|
|
896
882
|
*/
|
|
897
883
|
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
|
|
898
884
|
async _transitionShow(showConfig) {
|
|
@@ -900,28 +886,25 @@ export class OverlayController extends EventTargetShim {
|
|
|
900
886
|
await this.transitionShow({ backdropNode: this.backdropNode, contentNode: this.contentNode });
|
|
901
887
|
|
|
902
888
|
if (showConfig.backdropNode) {
|
|
903
|
-
showConfig.backdropNode.classList.add(
|
|
904
|
-
`${this.placementMode}-overlays__backdrop--animation-in`,
|
|
905
|
-
);
|
|
889
|
+
showConfig.backdropNode.classList.add(`overlays__backdrop--animation-in`);
|
|
906
890
|
}
|
|
907
891
|
}
|
|
908
892
|
|
|
909
893
|
/** @protected */
|
|
910
894
|
_restoreFocus() {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
if (
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
895
|
+
// We only are allowed to move focus if we (still) 'own' the active element.
|
|
896
|
+
// Otherwise we assume the 'outside world' has purposefully taken over
|
|
897
|
+
const { activeElement } = /** @type {ShadowRoot} */ (this.contentNode.getRootNode());
|
|
898
|
+
const weStillOwnActiveElement =
|
|
899
|
+
activeElement instanceof HTMLElement && this.contentNode.contains(activeElement);
|
|
900
|
+
if (!weStillOwnActiveElement) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (this.elementToFocusAfterHide) {
|
|
905
|
+
this.elementToFocusAfterHide.focus();
|
|
906
|
+
} else {
|
|
907
|
+
activeElement.blur();
|
|
925
908
|
}
|
|
926
909
|
}
|
|
927
910
|
|
|
@@ -1010,55 +993,28 @@ export class OverlayController extends EventTargetShim {
|
|
|
1010
993
|
* @protected
|
|
1011
994
|
*/
|
|
1012
995
|
_handleBackdrop({ phase }) {
|
|
996
|
+
// eslint-disable-next-line default-case
|
|
1013
997
|
switch (phase) {
|
|
1014
998
|
case 'init': {
|
|
1015
|
-
if (!this.
|
|
1016
|
-
this.
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
let insertionBefore = this.contentNode;
|
|
1025
|
-
if (this.placementMode === 'global') {
|
|
1026
|
-
insertionAnchor = /** @type {HTMLElement} */ (this.contentWrapperNode.parentElement);
|
|
1027
|
-
insertionBefore = this.contentWrapperNode;
|
|
999
|
+
if (!this.__backdropInitialized) {
|
|
1000
|
+
if (!this.config?.backdropNode) {
|
|
1001
|
+
this.__backdropNode = document.createElement('div');
|
|
1002
|
+
// If backdropNode existed in config, styles are applied by implementing party
|
|
1003
|
+
this.__backdropNode.classList.add(`overlays__backdrop`);
|
|
1004
|
+
}
|
|
1005
|
+
// @ts-ignore
|
|
1006
|
+
this.__wrappingDialogNode.prepend(this.backdropNode);
|
|
1007
|
+
this.__backdropInitialized = true;
|
|
1028
1008
|
}
|
|
1029
|
-
insertionAnchor.insertBefore(this.backdropNode, insertionBefore);
|
|
1030
1009
|
break;
|
|
1031
1010
|
}
|
|
1032
1011
|
case 'show':
|
|
1033
|
-
this.backdropNode.classList.add(
|
|
1012
|
+
this.backdropNode.classList.add(`overlays__backdrop--visible`);
|
|
1034
1013
|
this.__hasActiveBackdrop = true;
|
|
1035
1014
|
break;
|
|
1036
1015
|
case 'hide':
|
|
1037
|
-
if (!this.backdropNode) {
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
1016
|
this.__hasActiveBackdrop = false;
|
|
1041
1017
|
break;
|
|
1042
|
-
case 'teardown':
|
|
1043
|
-
if (!this.backdropNode || !this.backdropNode.parentNode) {
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
if (this.__backdropAnimation) {
|
|
1047
|
-
this.__backdropNodeToBeTornDown = this.backdropNode;
|
|
1048
|
-
|
|
1049
|
-
this.__backdropAnimation.then(() => {
|
|
1050
|
-
if (this.__backdropNodeToBeTornDown && this.__backdropNodeToBeTornDown.parentNode) {
|
|
1051
|
-
this.__backdropNodeToBeTornDown.parentNode.removeChild(
|
|
1052
|
-
this.__backdropNodeToBeTornDown,
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
});
|
|
1056
|
-
} else {
|
|
1057
|
-
this.backdropNode.parentNode.removeChild(this.backdropNode);
|
|
1058
|
-
}
|
|
1059
|
-
this.__backdropNode = undefined;
|
|
1060
|
-
break;
|
|
1061
|
-
/* no default */
|
|
1062
1018
|
}
|
|
1063
1019
|
}
|
|
1064
1020
|
|
|
@@ -1072,7 +1028,16 @@ export class OverlayController extends EventTargetShim {
|
|
|
1072
1028
|
*/
|
|
1073
1029
|
_handleTrapsKeyboardFocus({ phase }) {
|
|
1074
1030
|
if (phase === 'show') {
|
|
1031
|
+
// @ts-ignore
|
|
1032
|
+
if ('showModal' in this.__wrappingDialogNode) {
|
|
1033
|
+
// @ts-ignore
|
|
1034
|
+
this.__wrappingDialogNode.close();
|
|
1035
|
+
// @ts-ignore
|
|
1036
|
+
this.__wrappingDialogNode.showModal();
|
|
1037
|
+
}
|
|
1038
|
+
// else {
|
|
1075
1039
|
this.enableTrapsKeyboardFocus();
|
|
1040
|
+
// }
|
|
1076
1041
|
} else if (phase === 'hide' || phase === 'teardown') {
|
|
1077
1042
|
this.disableTrapsKeyboardFocus();
|
|
1078
1043
|
}
|
|
@@ -1271,24 +1236,6 @@ export class OverlayController extends EventTargetShim {
|
|
|
1271
1236
|
|
|
1272
1237
|
teardown() {
|
|
1273
1238
|
this._handleFeatures({ phase: 'teardown' });
|
|
1274
|
-
|
|
1275
|
-
if (this.placementMode === 'global' && this.__isContentNodeProjected) {
|
|
1276
|
-
/** @type {HTMLElement} */ (this.__originalContentParent).appendChild(this.contentNode);
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Remove the content node wrapper from the global rootnode
|
|
1280
|
-
this._teardownContentWrapperNode();
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
/** @protected */
|
|
1284
|
-
_teardownContentWrapperNode() {
|
|
1285
|
-
if (
|
|
1286
|
-
this.placementMode === 'global' &&
|
|
1287
|
-
this.contentWrapperNode &&
|
|
1288
|
-
this.contentWrapperNode.parentNode
|
|
1289
|
-
) {
|
|
1290
|
-
this.contentWrapperNode.parentNode.removeChild(this.contentWrapperNode);
|
|
1291
|
-
}
|
|
1292
1239
|
}
|
|
1293
1240
|
|
|
1294
1241
|
/** @private */
|