@lion/ui 0.17.0-menu-system.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/collapsible.js +0 -1
- package/components/button/src/LionButton.js +0 -4
- package/components/button/test-suites/LionButton.suite.js +0 -1
- package/components/calendar/src/LionCalendar.js +0 -2
- package/components/combobox/test/lion-combobox.test.js +0 -1
- package/components/form-core/src/form-group/FormGroupMixin.js +0 -7
- package/components/form-core/src/registration/FormRegistrarMixin.js +0 -11
- package/components/form-core/test/FormControlMixin.test.js +0 -1
- package/components/form-core/test/validate/Validator.test.js +0 -2
- package/components/form-core/test-suites/ValidateMixin.suite.js +0 -2
- package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +0 -1
- package/components/input-datepicker/src/localizeNamespaceLoader.js +0 -1
- package/components/input-datepicker/test/lion-input-datepicker.test.js +6 -5
- package/components/localize/test/date/formatDate.test.js +0 -1
- package/components/overlays/src/OverlayController.js +111 -244
- package/components/overlays/src/OverlayMixin.js +11 -58
- package/components/overlays/src/OverlaysManager.js +2 -2
- package/components/overlays/src/utils/adopt-styles.js +1 -2
- package/components/overlays/src/utils/get-focusable-elements.js +0 -4
- package/components/overlays/src/utils/is-equal-config.js +6 -10
- package/components/overlays/test/OverlayController.test.js +3 -5
- package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
- package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
- package/components/overlays/types/OverlayConfig.ts +5 -16
- package/components/select-rich/test/lion-select-rich.test.js +0 -3
- package/custom-elements.json +1910 -13871
- package/dist-types/components/button/src/LionButton.d.ts +0 -1
- package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
- package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +1 -3
- package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
- package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
- package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +13 -9
- 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/utils/get-focusable-elements.d.ts.map +1 -1
- package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -10
- package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -8
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/exports/overlays.d.ts +0 -3
- package/dist-types/exports/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/api-table.md +8 -21
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/api-table.md +6 -31
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/form/use-cases.md +2 -2
- 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/api-table.md +4 -21
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/api-table.md +5 -21
- package/docs/components/select-rich/use-cases.md +2 -2
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/tooltip/api-table.md +11 -36
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/rationales/accessibility.md +1 -1
- package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +2 -2
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/api-table.md +34 -34
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/create-a-form.md +4 -4
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/how-to/index.md +1 -1
- 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/collapsible.js +0 -1
- package/exports/overlays.js +0 -6
- package/overlays.js +0 -6
- package/package.json +1 -1
- package/components/collapsible/src/DisclosureMixin.js +0 -313
- package/components/collapsible/types/DisclosureMixinTypes.ts +0 -48
- package/components/menu/CHANGELOG.md +0 -37
- package/components/menu/README.md +0 -335
- package/components/menu/index.js +0 -2
- package/components/menu/lion-menu-overlay.js +0 -3
- package/components/menu/lion-menu.js +0 -3
- package/components/menu/lion-spinbutton.js +0 -3
- package/components/menu/lion-toolbar.js +0 -3
- package/components/menu/lion-tree.js +0 -3
- package/components/menu/package.json +0 -46
- package/components/menu/requirements.temp.md +0 -12
- package/components/menu/src/InteractiveListMixin.js +0 -796
- package/components/menu/src/LionMenu.js +0 -250
- package/components/menu/src/LionMenuHybrid.js +0 -46
- package/components/menu/src/LionMenuOverlay.js +0 -155
- package/components/menu/src/LionSpinbutton.js +0 -213
- package/components/menu/src/LionToolbar.js +0 -94
- package/components/menu/src/LionTree.js +0 -52
- package/components/menu/src/MultiLevelListMixin.js +0 -274
- package/components/menu/src/utils/isInView.js +0 -26
- package/components/menu/src/utils/listItemInteractions.js +0 -104
- package/components/menu/src/utils/uuid.js +0 -3
- package/components/menu/test/lion-menu.test.js +0 -3
- package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -142
- package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -82
- package/components/navigation-bar/README.md +0 -1
- package/components/navigation-bar/src/LionNavigationBar.js +0 -422
- package/components/navigation-bar/src/types.js +0 -41
- package/components/overlays/NEXT.md +0 -49
- package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +0 -3
- package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +0 -1
- package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +0 -24
- package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +0 -1
- package/dist-types/components/menu/index.d.ts +0 -3
- package/dist-types/components/menu/index.d.ts.map +0 -1
- package/dist-types/components/menu/lion-menu-overlay.d.ts +0 -2
- package/dist-types/components/menu/lion-menu-overlay.d.ts.map +0 -1
- package/dist-types/components/menu/lion-menu.d.ts +0 -2
- package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
- package/dist-types/components/menu/lion-spinbutton.d.ts +0 -2
- package/dist-types/components/menu/lion-spinbutton.d.ts.map +0 -1
- package/dist-types/components/menu/lion-toolbar.d.ts +0 -2
- package/dist-types/components/menu/lion-toolbar.d.ts.map +0 -1
- package/dist-types/components/menu/lion-tree.d.ts +0 -2
- package/dist-types/components/menu/lion-tree.d.ts.map +0 -1
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts +0 -611
- package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenu.d.ts +0 -563
- package/dist-types/components/menu/src/LionMenu.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenuHybrid.d.ts +0 -19
- package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts +0 -1007
- package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionSpinbutton.d.ts +0 -58
- package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionToolbar.d.ts +0 -8
- package/dist-types/components/menu/src/LionToolbar.d.ts.map +0 -1
- package/dist-types/components/menu/src/LionTree.d.ts +0 -445
- package/dist-types/components/menu/src/LionTree.d.ts.map +0 -1
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +0 -493
- package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +0 -1
- package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
- package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
- package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -42
- package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
- package/dist-types/components/menu/src/utils/uuid.d.ts +0 -2
- package/dist-types/components/menu/src/utils/uuid.d.ts.map +0 -1
- package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
- package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -13
- package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
- package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +0 -238
- package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +0 -1
- package/dist-types/components/navigation-bar/src/types.d.ts +0 -85
- package/dist-types/components/navigation-bar/src/types.d.ts.map +0 -1
- package/dist-types/exports/define/lion-item.d.ts +0 -2
- package/dist-types/exports/define/lion-item.d.ts.map +0 -1
- package/dist-types/exports/define/lion-menu-overlay.d.ts +0 -2
- package/dist-types/exports/define/lion-menu-overlay.d.ts.map +0 -1
- package/dist-types/exports/define/lion-menu.d.ts +0 -2
- package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
- package/dist-types/exports/define/lion-navigation-bar.d.ts +0 -2
- package/dist-types/exports/define/lion-navigation-bar.d.ts.map +0 -1
- package/dist-types/exports/define/lion-toolbar.d.ts +0 -2
- package/dist-types/exports/define/lion-toolbar.d.ts.map +0 -1
- package/dist-types/exports/define/lion-tree.d.ts +0 -2
- package/dist-types/exports/define/lion-tree.d.ts.map +0 -1
- package/dist-types/exports/menu.d.ts +0 -7
- package/dist-types/exports/menu.d.ts.map +0 -1
- package/dist-types/exports/navigation-bar.d.ts +0 -2
- package/dist-types/exports/navigation-bar.d.ts.map +0 -1
- package/docs/components/menu/api-table.md +0 -450
- package/docs/components/menu/applyMenuDemoStyles.js +0 -173
- package/docs/components/menu/extensions.md +0 -216
- package/docs/components/menu/index.md +0 -13
- package/docs/components/menu/overview.md +0 -422
- package/exports/define/lion-item.js +0 -3
- package/exports/define/lion-menu-overlay.js +0 -3
- package/exports/define/lion-menu.js +0 -3
- package/exports/define/lion-navigation-bar.js +0 -3
- package/exports/define/lion-toolbar.js +0 -3
- package/exports/define/lion-tree.js +0 -3
- package/exports/menu.js +0 -6
- package/exports/navigation-bar.js +0 -1
- package/menu.js +0 -6
- package/navigation-bar.js +0 -1
|
@@ -3,7 +3,6 @@ import { deepContains } from './utils/deep-contains.js';
|
|
|
3
3
|
import { overlayShadowDomStyle } from './overlayShadowDomStyle.js';
|
|
4
4
|
import { _adoptStyleUtils } from './utils/adopt-styles.js';
|
|
5
5
|
import { getFocusableElements } from './utils/get-focusable-elements.js';
|
|
6
|
-
import { isEqualConfig } from './utils/is-equal-config.js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @typedef {import('@lion/ui/types/overlays.js').OverlayPhase} OverlayPhase
|
|
@@ -33,37 +32,27 @@ import { isEqualConfig } from './utils/is-equal-config.js';
|
|
|
33
32
|
* `<slot name="my-content">` belonging to `<div slot="content"/>` will be wrapped with wrappingDialogNodeL1 and contentWrapperNodeL2
|
|
34
33
|
* inside shadow dom. With the help of temp markers, `<slot name="my-content">`'s original position will be respected.
|
|
35
34
|
*
|
|
36
|
-
* @param {{
|
|
37
|
-
* wrappingDialogNodeL1: HTMLDialogElement|HTMLDivElement;
|
|
38
|
-
* contentWrapperNodeL2:Element;
|
|
39
|
-
* contentNodeL3: Element;
|
|
40
|
-
* }} opts
|
|
35
|
+
* @param {{ wrappingDialogNodeL1:HTMLDialogElement|HTMLDivElement; contentWrapperNodeL2:Element; contentNodeL3: Element }} opts
|
|
41
36
|
*/
|
|
42
37
|
function rearrangeNodes({ wrappingDialogNodeL1, contentWrapperNodeL2, contentNodeL3 }) {
|
|
43
|
-
|
|
44
|
-
// we assume it lives in shadow dom around a slot.
|
|
45
|
-
const hasLegacyMethodOfProvidingWrapperNode = Boolean(contentWrapperNodeL2.isConnected);
|
|
46
|
-
// We could be initialized via a directive (in offline dom). It's important that we know about the parents,
|
|
47
|
-
// as we cannot deal with single content nodes
|
|
48
|
-
const hasContentNodeAttachmentPoints = Boolean(contentNodeL3.parentNode);
|
|
49
|
-
|
|
50
|
-
if (!hasLegacyMethodOfProvidingWrapperNode && !hasContentNodeAttachmentPoints) {
|
|
38
|
+
if (!(contentWrapperNodeL2.isConnected || contentNodeL3.isConnected)) {
|
|
51
39
|
throw new Error(
|
|
52
|
-
'[OverlayController] Could not find a render target,
|
|
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.',
|
|
53
41
|
);
|
|
54
42
|
}
|
|
55
43
|
|
|
56
|
-
/** @type {Node} */
|
|
57
44
|
let parentElement;
|
|
58
|
-
const tempMarker = document.createComment('
|
|
45
|
+
const tempMarker = document.createComment('tempMarker');
|
|
59
46
|
|
|
60
|
-
if (
|
|
47
|
+
if (contentWrapperNodeL2.isConnected) {
|
|
61
48
|
// This is the case when contentWrapperNode (living in shadow dom, wrapping <slot name="my-content-outlet">) is already provided via controller.
|
|
62
49
|
parentElement = contentWrapperNodeL2.parentElement || contentWrapperNodeL2.getRootNode();
|
|
63
50
|
parentElement.insertBefore(tempMarker, contentWrapperNodeL2);
|
|
64
51
|
// Wrap...
|
|
65
52
|
wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
|
|
66
|
-
}
|
|
53
|
+
}
|
|
54
|
+
// if contentNodeL3.isConnected
|
|
55
|
+
else {
|
|
67
56
|
const contentIsProjected = contentNodeL3.assignedSlot;
|
|
68
57
|
if (contentIsProjected) {
|
|
69
58
|
parentElement =
|
|
@@ -104,22 +93,7 @@ function rearrangeNodes({ wrappingDialogNodeL1, contentWrapperNodeL2, contentNod
|
|
|
104
93
|
* ```
|
|
105
94
|
*/
|
|
106
95
|
parentElement.insertBefore(wrappingDialogNodeL1, tempMarker);
|
|
107
|
-
|
|
108
|
-
return function cleanup() {
|
|
109
|
-
if (hasLegacyMethodOfProvidingWrapperNode) {
|
|
110
|
-
parentElement?.insertBefore(contentWrapperNodeL2, tempMarker);
|
|
111
|
-
} else {
|
|
112
|
-
parentElement?.insertBefore(contentNodeL3, tempMarker);
|
|
113
|
-
if (parentElement.contains(contentWrapperNodeL2)) {
|
|
114
|
-
contentWrapperNodeL2.remove();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
parentElement?.removeChild(tempMarker);
|
|
118
|
-
|
|
119
|
-
if (parentElement.contains(wrappingDialogNodeL1)) {
|
|
120
|
-
parentElement?.removeChild(wrappingDialogNodeL1);
|
|
121
|
-
}
|
|
122
|
-
};
|
|
96
|
+
parentElement?.removeChild(tempMarker);
|
|
123
97
|
}
|
|
124
98
|
|
|
125
99
|
/**
|
|
@@ -132,21 +106,6 @@ async function preloadPopper() {
|
|
|
132
106
|
|
|
133
107
|
const childDialogsClosedInEventLoopWeakmap = new WeakMap();
|
|
134
108
|
|
|
135
|
-
/**
|
|
136
|
-
* @param {HTMLElement | null} el
|
|
137
|
-
* @param {string} selector
|
|
138
|
-
* @returns {HTMLElement | null}
|
|
139
|
-
*/
|
|
140
|
-
function deepClosest(el, selector) {
|
|
141
|
-
// @ts-ignore - comparing HTMLElement to document/window for safety
|
|
142
|
-
return (
|
|
143
|
-
// @ts-ignore - type comparison check
|
|
144
|
-
(el && el !== document && el !== window && el.closest(selector)) ||
|
|
145
|
-
// @ts-ignore - host property on ShadowRoot
|
|
146
|
-
deepClosest(el.getRootNode().host, selector)
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
109
|
/**
|
|
151
110
|
* OverlayController is the fundament for every single type of overlay. With the right
|
|
152
111
|
* configuration, it can be used to build (modal) dialogs, tooltips, dropdowns, popovers,
|
|
@@ -237,21 +196,10 @@ export class OverlayController extends EventTarget {
|
|
|
237
196
|
placement: 'center',
|
|
238
197
|
},
|
|
239
198
|
zIndex: 9999,
|
|
240
|
-
// TODO: rename to isActivated
|
|
241
|
-
isOpenable: true,
|
|
242
|
-
focusContentOnOpen: false,
|
|
243
|
-
// This means that content will have visually-hidden / sr-only styles. This is handy for:
|
|
244
|
-
// - hidden menus that should be "indexable" by screen readers (like the Links list in VO: https://support.apple.com/en-gb/guide/voiceover/mchlp2719/mac)
|
|
245
|
-
// - "more" menus that put content in a dropdown that do not fit in the current row
|
|
246
|
-
// - menus that should generally open on tab.
|
|
247
|
-
// @ts-ignore - hideVisually is an extension property
|
|
248
|
-
hideVisually: false,
|
|
249
|
-
requireConnectedNodes: true,
|
|
250
199
|
};
|
|
251
200
|
|
|
252
201
|
/** @protected */
|
|
253
202
|
this._contentId = `overlay-content--${Math.random().toString(36).slice(2, 10)}`;
|
|
254
|
-
|
|
255
203
|
/** @private */
|
|
256
204
|
this.__originalAttrs = new Map();
|
|
257
205
|
/** @private */
|
|
@@ -272,8 +220,6 @@ export class OverlayController extends EventTarget {
|
|
|
272
220
|
this.__escKeyHandlerCalled = false;
|
|
273
221
|
}
|
|
274
222
|
|
|
275
|
-
#hasSetup = false;
|
|
276
|
-
|
|
277
223
|
/**
|
|
278
224
|
* The invokerNode
|
|
279
225
|
* @type {HTMLElement | undefined}
|
|
@@ -292,7 +238,7 @@ export class OverlayController extends EventTarget {
|
|
|
292
238
|
|
|
293
239
|
/**
|
|
294
240
|
* Determines the connection point in DOM (body vs next to invoker).
|
|
295
|
-
* @type {'global' | 'local' |
|
|
241
|
+
* @type {'global' | 'local' | undefined}
|
|
296
242
|
*/
|
|
297
243
|
get placementMode() {
|
|
298
244
|
return this.config?.placementMode;
|
|
@@ -517,14 +463,17 @@ export class OverlayController extends EventTarget {
|
|
|
517
463
|
* @param { OverlayConfig } cfgToAdd
|
|
518
464
|
*/
|
|
519
465
|
updateConfig(cfgToAdd) {
|
|
466
|
+
// Teardown all previous configs
|
|
467
|
+
this.teardown();
|
|
468
|
+
|
|
520
469
|
/**
|
|
521
470
|
* @type {OverlayConfig}
|
|
522
471
|
* @private
|
|
523
472
|
*/
|
|
524
|
-
|
|
473
|
+
this.__prevConfig = this.config;
|
|
525
474
|
|
|
526
475
|
/** @type {OverlayConfig} */
|
|
527
|
-
|
|
476
|
+
this.config = {
|
|
528
477
|
...this._defaultConfig, // our basic ingredients
|
|
529
478
|
...this.__sharedConfig, // the initial configured overlayController
|
|
530
479
|
...cfgToAdd, // the added config
|
|
@@ -540,18 +489,12 @@ export class OverlayController extends EventTarget {
|
|
|
540
489
|
},
|
|
541
490
|
};
|
|
542
491
|
|
|
543
|
-
const shouldUpdate = !this.#hasSetup || !isEqualConfig(prevConfig, newConfig);
|
|
544
|
-
if (!shouldUpdate) return;
|
|
545
|
-
// Teardown all previous configs
|
|
546
|
-
|
|
547
|
-
this.teardown();
|
|
548
|
-
|
|
549
|
-
this.config = newConfig;
|
|
550
|
-
|
|
551
492
|
/** @private */
|
|
552
493
|
this.__validateConfiguration(this.config);
|
|
553
494
|
/** @protected */
|
|
554
495
|
this._init();
|
|
496
|
+
/** @private */
|
|
497
|
+
this.__elementToFocusAfterHide = undefined;
|
|
555
498
|
|
|
556
499
|
if (!this.#isRegisteredOnManager()) {
|
|
557
500
|
this.manager.add(this);
|
|
@@ -573,7 +516,7 @@ export class OverlayController extends EventTarget {
|
|
|
573
516
|
'[OverlayController] You need to provide a .placementMode ("global"|"local")',
|
|
574
517
|
);
|
|
575
518
|
}
|
|
576
|
-
if (!['global', 'local'
|
|
519
|
+
if (!['global', 'local'].includes(newConfig.placementMode)) {
|
|
577
520
|
throw new Error(
|
|
578
521
|
`[OverlayController] "${newConfig.placementMode}" is not a valid .placementMode, use ("global"|"local")`,
|
|
579
522
|
);
|
|
@@ -592,23 +535,14 @@ export class OverlayController extends EventTarget {
|
|
|
592
535
|
* @protected
|
|
593
536
|
*/
|
|
594
537
|
_init() {
|
|
595
|
-
if (!this.
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
// and popper.js, (use popover and anchor positioning and popperjs as fallback, but we can put styles on contentNode),
|
|
600
|
-
// we dont need to create complex wrappers
|
|
601
|
-
// if (!this.__contentHasBeenInitialized) {
|
|
602
|
-
this.__initContentDomStructure();
|
|
603
|
-
// this.__contentHasBeenInitialized = true;
|
|
604
|
-
// }
|
|
605
|
-
this.__initVisibility();
|
|
538
|
+
if (!this.__contentHasBeenInitialized) {
|
|
539
|
+
this.__initContentDomStructure();
|
|
540
|
+
this.__contentHasBeenInitialized = true;
|
|
541
|
+
}
|
|
606
542
|
|
|
607
543
|
// Reset all positioning styles (local, c.q. Popper) and classes (global)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
this.contentWrapperNode.removeAttribute('class');
|
|
611
|
-
}
|
|
544
|
+
this.contentWrapperNode.removeAttribute('style');
|
|
545
|
+
this.contentWrapperNode.removeAttribute('class');
|
|
612
546
|
|
|
613
547
|
if (this.placementMode === 'local') {
|
|
614
548
|
// Lazily load Popper as soon as the first local overlay is used...
|
|
@@ -618,27 +552,8 @@ export class OverlayController extends EventTarget {
|
|
|
618
552
|
}
|
|
619
553
|
this.__handleOverlayStyles({ phase: 'init' });
|
|
620
554
|
this._handleFeatures({ phase: 'init' });
|
|
621
|
-
|
|
622
|
-
/** @private */
|
|
623
|
-
this.__elementToFocusAfterHide = undefined;
|
|
624
|
-
|
|
625
|
-
this.contentNode.dataset.content = '';
|
|
626
|
-
|
|
627
|
-
// Use event delegation to listen for clicks on close buttons...
|
|
628
|
-
this.contentNode.addEventListener('click', this.#hideOnCloseButtonClick);
|
|
629
|
-
|
|
630
|
-
this.#hasSetup = true;
|
|
631
555
|
}
|
|
632
556
|
|
|
633
|
-
#hideOnCloseButtonClick = (/** @type {{ target: any; }} */ ev) => {
|
|
634
|
-
const isOurCloseButton =
|
|
635
|
-
ev.target.hasAttribute('data-close') &&
|
|
636
|
-
deepClosest(ev.target, '[data-content]') === this.contentNode;
|
|
637
|
-
if (!isOurCloseButton) return;
|
|
638
|
-
|
|
639
|
-
this.hide();
|
|
640
|
-
};
|
|
641
|
-
|
|
642
557
|
/**
|
|
643
558
|
* @param {{ phase: OverlayPhase }} config
|
|
644
559
|
* @private
|
|
@@ -679,108 +594,84 @@ export class OverlayController extends EventTarget {
|
|
|
679
594
|
* @private
|
|
680
595
|
*/
|
|
681
596
|
__initContentDomStructure() {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
// @ts-ignore - 'custom' is a valid extension of placementMode
|
|
700
|
-
if (this.config.placementMode === 'custom') {
|
|
701
|
-
// The user should have full freedom to control the content node, so its wrapper nodes should remain neutral.
|
|
702
|
-
wrappingDialogElement.style.cssText += `position: static;`;
|
|
703
|
-
}
|
|
704
|
-
this.__wrappingDialogNode = wrappingDialogElement;
|
|
597
|
+
const wrappingDialogElement = document.createElement('dialog');
|
|
598
|
+
// We use a dialog for its visual capabilities: it renders to the top layer.
|
|
599
|
+
// A11y will depend on the type of overlay and is arranged on contentNode level.
|
|
600
|
+
// Also see: https://www.scottohara.me/blog/2019/03/05/open-dialog.html
|
|
601
|
+
//
|
|
602
|
+
// The role="dialog" is set on the contentNode (or another role), so role="none"
|
|
603
|
+
// is valid here, although AXE complains about this setup.
|
|
604
|
+
// For now we need to add `ignoredRules: ['aria-allowed-role']` in your AXE tests.
|
|
605
|
+
// see: https://lion.js.org/fundamentals/systems/overlays/rationale/#considerations
|
|
606
|
+
wrappingDialogElement.setAttribute('role', 'none');
|
|
607
|
+
wrappingDialogElement.setAttribute('data-overlay-outer-wrapper', '');
|
|
608
|
+
// N.B. position: fixed is needed to escape out of 'overflow: hidden'
|
|
609
|
+
// We give a high z-index for non-modal dialogs, so that we at least win from all siblings of our
|
|
610
|
+
// parent stacking context
|
|
611
|
+
// padding reset so we don't get a weird dialog visual square showing up
|
|
612
|
+
wrappingDialogElement.style.cssText = `display:none; z-index: ${this.config.zIndex}; padding: 0;`;
|
|
613
|
+
this.__wrappingDialogNode = wrappingDialogElement;
|
|
705
614
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
this.__rearrangeNodesCleanup = rearrangeNodes({
|
|
718
|
-
wrappingDialogNodeL1: wrappingDialogElement,
|
|
719
|
-
contentWrapperNodeL2: this.contentWrapperNode,
|
|
720
|
-
contentNodeL3: this.contentNode,
|
|
721
|
-
// requireConnectedNodes: Boolean(this.config.requireConnectedNodes),
|
|
722
|
-
});
|
|
723
|
-
wrappingDialogElement.open = true;
|
|
615
|
+
/**
|
|
616
|
+
* Based on the configuration of the developer, multiple scenarios are accounted for
|
|
617
|
+
* A. We already have a contentWrapperNode ()
|
|
618
|
+
*/
|
|
619
|
+
if (!this.config?.contentWrapperNode) {
|
|
620
|
+
this.__contentWrapperNode = document.createElement('div');
|
|
621
|
+
}
|
|
622
|
+
this.contentWrapperNode.setAttribute('data-id', 'content-wrapper');
|
|
623
|
+
// 'hack' that makes sure popperjs (that is applied one level lower) works correctly in deeply nested shadow roots
|
|
624
|
+
this.contentWrapperNode.style.transform = 'translateZ(0px)';
|
|
724
625
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
// Having a _contWrapperNode and a contentNode with 'position:absolute' results in
|
|
732
|
-
// computed height of 0...
|
|
733
|
-
this.contentNode.style.position = 'static';
|
|
734
|
-
}
|
|
626
|
+
rearrangeNodes({
|
|
627
|
+
wrappingDialogNodeL1: wrappingDialogElement,
|
|
628
|
+
contentWrapperNodeL2: this.contentWrapperNode,
|
|
629
|
+
contentNodeL3: this.contentNode,
|
|
630
|
+
});
|
|
631
|
+
wrappingDialogElement.open = true;
|
|
735
632
|
|
|
736
|
-
|
|
737
|
-
//
|
|
738
|
-
|
|
739
|
-
const hasClosedBySupport = HTMLDialogElement && 'closedBy' in HTMLDialogElement.prototype;
|
|
740
|
-
if (hasClosedBySupport) {
|
|
741
|
-
// @ts-ignore - closedBy is a newer property not in all TypeScript versions
|
|
742
|
-
wrappingDialogElement.closedBy = 'none';
|
|
743
|
-
} else {
|
|
744
|
-
wrappingDialogElement.addEventListener(
|
|
745
|
-
'keydown',
|
|
746
|
-
(/** @type {* & KeyboardEvent} */ event) => {
|
|
747
|
-
if (event.key === 'Escape') {
|
|
748
|
-
event.preventDefault();
|
|
749
|
-
}
|
|
750
|
-
},
|
|
751
|
-
);
|
|
752
|
-
wrappingDialogElement.addEventListener(
|
|
753
|
-
'keyup',
|
|
754
|
-
(/** @type {* & KeyboardEvent} */ event) => {
|
|
755
|
-
if (event.key === 'Escape') {
|
|
756
|
-
event.preventDefault();
|
|
757
|
-
}
|
|
758
|
-
},
|
|
759
|
-
);
|
|
760
|
-
wrappingDialogElement.addEventListener('cancel', event => {
|
|
761
|
-
event.stopPropagation();
|
|
762
|
-
});
|
|
763
|
-
wrappingDialogElement.addEventListener('close', event => {
|
|
764
|
-
event.stopPropagation();
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
} else {
|
|
768
|
-
// quick hack to make none-popper/global flows work...
|
|
769
|
-
this.__contentWrapperNode = this.contentNode;
|
|
770
|
-
this.__wrappingDialogNode = this.contentNode;
|
|
633
|
+
if (this.isTooltip) {
|
|
634
|
+
// needed to prevent tooltip getting focus in Safari and Firefox
|
|
635
|
+
wrappingDialogElement.setAttribute('tabindex', '-1');
|
|
771
636
|
}
|
|
772
|
-
}
|
|
773
637
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
638
|
+
this.__wrappingDialogNode.style.display = 'none';
|
|
639
|
+
this.contentWrapperNode.style.zIndex = '1';
|
|
640
|
+
|
|
641
|
+
if (getComputedStyle(this.contentNode).position === 'absolute') {
|
|
642
|
+
// Having a _contWrapperNode and a contentNode with 'position:absolute' results in
|
|
643
|
+
// computed height of 0...
|
|
644
|
+
this.contentNode.style.position = 'static';
|
|
645
|
+
}
|
|
778
646
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
647
|
+
// Here we prevent any interference of the native <dialog> element with the keyboard behavior
|
|
648
|
+
// as defined by the OverlayController. This is needed until we can configure `closedby="none"`
|
|
649
|
+
// on the native dialog for all browsers: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog#closedby
|
|
650
|
+
const hasClosedBySupport = HTMLDialogElement && 'closedBy' in HTMLDialogElement.prototype;
|
|
651
|
+
if (hasClosedBySupport) {
|
|
652
|
+
// @ts-expect-error
|
|
653
|
+
wrappingDialogElement.closedBy = 'none';
|
|
654
|
+
} else {
|
|
655
|
+
wrappingDialogElement.addEventListener(
|
|
656
|
+
'keydown',
|
|
657
|
+
(/** @type {* & KeyboardEvent} */ event) => {
|
|
658
|
+
if (event.key === 'Escape') {
|
|
659
|
+
event.preventDefault();
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
);
|
|
663
|
+
wrappingDialogElement.addEventListener('keyup', (/** @type {* & KeyboardEvent} */ event) => {
|
|
664
|
+
if (event.key === 'Escape') {
|
|
665
|
+
event.preventDefault();
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
wrappingDialogElement.addEventListener('cancel', event => {
|
|
669
|
+
event.stopPropagation();
|
|
670
|
+
});
|
|
671
|
+
wrappingDialogElement.addEventListener('close', event => {
|
|
672
|
+
event.stopPropagation();
|
|
673
|
+
});
|
|
674
|
+
}
|
|
784
675
|
}
|
|
785
676
|
|
|
786
677
|
/**
|
|
@@ -851,7 +742,6 @@ export class OverlayController extends EventTarget {
|
|
|
851
742
|
* @private
|
|
852
743
|
*/
|
|
853
744
|
__storeOriginalAttrs(node, attrs) {
|
|
854
|
-
/** @type {Record<string, string | null>} */
|
|
855
745
|
const attrMap = {};
|
|
856
746
|
attrs.forEach(attrName => {
|
|
857
747
|
attrMap[attrName] = node.getAttribute(attrName);
|
|
@@ -908,7 +798,6 @@ export class OverlayController extends EventTarget {
|
|
|
908
798
|
if ('HTMLDialogElement' in window && this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
909
799
|
this.__wrappingDialogNode.open = true;
|
|
910
800
|
}
|
|
911
|
-
|
|
912
801
|
// @ts-ignore
|
|
913
802
|
this.__wrappingDialogNode.style.display = '';
|
|
914
803
|
this._keepBodySize({ phase: 'before-show' });
|
|
@@ -922,14 +811,6 @@ export class OverlayController extends EventTarget {
|
|
|
922
811
|
contentNode: this.contentNode,
|
|
923
812
|
});
|
|
924
813
|
}
|
|
925
|
-
|
|
926
|
-
// a styling/debug hook for open state
|
|
927
|
-
this.contentNode.setAttribute('data-open', '');
|
|
928
|
-
|
|
929
|
-
if (this.config.focusContentOnOpen) {
|
|
930
|
-
this.contentNode.focus();
|
|
931
|
-
}
|
|
932
|
-
|
|
933
814
|
/** @type {function} */
|
|
934
815
|
(this._showResolve)();
|
|
935
816
|
}
|
|
@@ -962,7 +843,6 @@ export class OverlayController extends EventTarget {
|
|
|
962
843
|
await this.__createPopperInstance();
|
|
963
844
|
this._popper.forceUpdate();
|
|
964
845
|
}
|
|
965
|
-
// N.B. leave it up to the user if placementMode === 'custom'
|
|
966
846
|
}
|
|
967
847
|
|
|
968
848
|
/**
|
|
@@ -970,7 +850,9 @@ export class OverlayController extends EventTarget {
|
|
|
970
850
|
* @protected
|
|
971
851
|
*/
|
|
972
852
|
_keepBodySize({ phase }) {
|
|
973
|
-
if (!this.preventsScroll)
|
|
853
|
+
if (!this.preventsScroll) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
974
856
|
|
|
975
857
|
this.manager.requestToKeepBodySize({ phase });
|
|
976
858
|
}
|
|
@@ -980,9 +862,6 @@ export class OverlayController extends EventTarget {
|
|
|
980
862
|
* @event hide right after the overlay is hidden
|
|
981
863
|
*/
|
|
982
864
|
async hide() {
|
|
983
|
-
// Function like a no-op for dynamic edge cases...
|
|
984
|
-
if (!this.config.isOpenable) return;
|
|
985
|
-
|
|
986
865
|
this._hideComplete = new Promise(resolve => {
|
|
987
866
|
this._hideResolve = resolve;
|
|
988
867
|
});
|
|
@@ -1015,6 +894,7 @@ export class OverlayController extends EventTarget {
|
|
|
1015
894
|
if ('HTMLDialogElement' in window && this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
1016
895
|
this.__wrappingDialogNode.close();
|
|
1017
896
|
}
|
|
897
|
+
|
|
1018
898
|
// @ts-ignore
|
|
1019
899
|
this.__wrappingDialogNode.style.display = 'none';
|
|
1020
900
|
this._handleFeatures({ phase: 'hide' });
|
|
@@ -1023,8 +903,6 @@ export class OverlayController extends EventTarget {
|
|
|
1023
903
|
this._restoreFocus();
|
|
1024
904
|
}
|
|
1025
905
|
/** @type {function} */ (this._hideResolve)();
|
|
1026
|
-
|
|
1027
|
-
this.contentNode.removeAttribute('data-open');
|
|
1028
906
|
}
|
|
1029
907
|
|
|
1030
908
|
/**
|
|
@@ -1135,24 +1013,23 @@ export class OverlayController extends EventTarget {
|
|
|
1135
1013
|
if (this.visibilityTriggerFunction) {
|
|
1136
1014
|
this._handleVisibilityTriggers({ phase });
|
|
1137
1015
|
}
|
|
1138
|
-
|
|
1139
|
-
if (phase === 'init' && this.config.focusContentOnOpen) {
|
|
1140
|
-
this.contentNode?.setAttribute('tabindex', '-1');
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
if (phase === 'teardown' && this.config.focusContentOnOpen) {
|
|
1144
|
-
// TODO: capture initial attr, use Resettable mechanism of VisibilityToggleCtrl in whole Controller
|
|
1145
|
-
this.contentNode?.removeAttribute('tabindex');
|
|
1146
|
-
}
|
|
1147
1016
|
}
|
|
1148
1017
|
|
|
1149
1018
|
/**
|
|
1150
1019
|
* @param {{ phase: OverlayPhase }} config
|
|
1151
1020
|
*/
|
|
1152
1021
|
_handleVisibilityTriggers({ phase }) {
|
|
1153
|
-
if (typeof this.visibilityTriggerFunction
|
|
1154
|
-
|
|
1155
|
-
|
|
1022
|
+
if (typeof this.visibilityTriggerFunction === 'function') {
|
|
1023
|
+
if (phase === 'init') {
|
|
1024
|
+
this.__visibilityTriggerHandler = this.visibilityTriggerFunction({
|
|
1025
|
+
phase,
|
|
1026
|
+
controller: this,
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
if (this.__visibilityTriggerHandler[phase]) {
|
|
1030
|
+
this.__visibilityTriggerHandler[phase]();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1156
1033
|
}
|
|
1157
1034
|
|
|
1158
1035
|
/**
|
|
@@ -1309,9 +1186,7 @@ export class OverlayController extends EventTarget {
|
|
|
1309
1186
|
if (phase === 'show') {
|
|
1310
1187
|
this.#handleShiftKeyPress();
|
|
1311
1188
|
this.#handleFocusInsideDialog();
|
|
1312
|
-
// @ts-ignore - HTMLDialogElement methods
|
|
1313
1189
|
this.__wrappingDialogNode?.close();
|
|
1314
|
-
// @ts-ignore - HTMLDialogElement methods
|
|
1315
1190
|
this.__wrappingDialogNode?.showModal();
|
|
1316
1191
|
/**
|
|
1317
1192
|
* At this moment `#handleFocusInsideDialog` should handle the focus.
|
|
@@ -1562,7 +1437,6 @@ export class OverlayController extends EventTarget {
|
|
|
1562
1437
|
}
|
|
1563
1438
|
|
|
1564
1439
|
teardown() {
|
|
1565
|
-
if (!this.#hasSetup) return;
|
|
1566
1440
|
this.__handleOverlayStyles({ phase: 'teardown' });
|
|
1567
1441
|
if (this.isShown) {
|
|
1568
1442
|
this._keepBodySize({ phase: 'teardown' });
|
|
@@ -1571,13 +1445,6 @@ export class OverlayController extends EventTarget {
|
|
|
1571
1445
|
if (this.#isRegisteredOnManager()) {
|
|
1572
1446
|
this.manager.remove(this);
|
|
1573
1447
|
}
|
|
1574
|
-
|
|
1575
|
-
this.contentNode?.removeEventListener('click', this.#hideOnCloseButtonClick);
|
|
1576
|
-
|
|
1577
|
-
this.__rearrangeNodesCleanup?.();
|
|
1578
|
-
this.__teardownVisibility();
|
|
1579
|
-
|
|
1580
|
-
this.#hasSetup = false;
|
|
1581
1448
|
}
|
|
1582
1449
|
|
|
1583
1450
|
/** @private */
|