@momentum-design/components 0.83.1 → 0.83.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.js +178 -178
- package/dist/browser/index.js.map +4 -4
- package/dist/components/dialog/dialog.component.d.ts +7 -2
- package/dist/components/dialog/dialog.component.js +28 -9
- package/dist/components/popover/popover.component.d.ts +19 -7
- package/dist/components/popover/popover.component.js +69 -24
- package/dist/components/popover/popover.constants.d.ts +1 -0
- package/dist/components/popover/popover.constants.js +1 -0
- package/dist/components/tooltip/tooltip.component.js +1 -1
- package/dist/custom-elements.json +1411 -1150
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +2 -2
- package/dist/utils/mixins/FocusTrapMixin.d.ts +2 -2
- package/dist/utils/mixins/FocusTrapMixin.js +78 -40
- package/dist/utils/mixins/PreventScrollMixin.d.ts +9 -0
- package/dist/utils/mixins/PreventScrollMixin.js +32 -0
- package/package.json +1 -1
package/dist/react/index.d.ts
CHANGED
@@ -5,8 +5,8 @@ export { default as Avatar } from './avatar';
|
|
5
5
|
export { default as AvatarButton } from './avatarbutton';
|
6
6
|
export { default as Badge } from './badge';
|
7
7
|
export { default as Brandvisual } from './brandvisual';
|
8
|
-
export { default as Button } from './button';
|
9
8
|
export { default as Bullet } from './bullet';
|
9
|
+
export { default as Button } from './button';
|
10
10
|
export { default as ButtonGroup } from './buttongroup';
|
11
11
|
export { default as ButtonLink } from './buttonlink';
|
12
12
|
export { default as Buttonsimple } from './buttonsimple';
|
@@ -14,8 +14,8 @@ export { default as Card } from './card';
|
|
14
14
|
export { default as CardButton } from './cardbutton';
|
15
15
|
export { default as CardCheckbox } from './cardcheckbox';
|
16
16
|
export { default as CardRadio } from './cardradio';
|
17
|
-
export { default as Checkbox } from './checkbox';
|
18
17
|
export { default as Chip } from './chip';
|
18
|
+
export { default as Checkbox } from './checkbox';
|
19
19
|
export { default as Coachmark } from './coachmark';
|
20
20
|
export { default as Dialog } from './dialog';
|
21
21
|
export { default as Divider } from './divider';
|
package/dist/react/index.js
CHANGED
@@ -5,8 +5,8 @@ export { default as Avatar } from './avatar';
|
|
5
5
|
export { default as AvatarButton } from './avatarbutton';
|
6
6
|
export { default as Badge } from './badge';
|
7
7
|
export { default as Brandvisual } from './brandvisual';
|
8
|
-
export { default as Button } from './button';
|
9
8
|
export { default as Bullet } from './bullet';
|
9
|
+
export { default as Button } from './button';
|
10
10
|
export { default as ButtonGroup } from './buttongroup';
|
11
11
|
export { default as ButtonLink } from './buttonlink';
|
12
12
|
export { default as Buttonsimple } from './buttonsimple';
|
@@ -14,8 +14,8 @@ export { default as Card } from './card';
|
|
14
14
|
export { default as CardButton } from './cardbutton';
|
15
15
|
export { default as CardCheckbox } from './cardcheckbox';
|
16
16
|
export { default as CardRadio } from './cardradio';
|
17
|
-
export { default as Checkbox } from './checkbox';
|
18
17
|
export { default as Chip } from './chip';
|
18
|
+
export { default as Checkbox } from './checkbox';
|
19
19
|
export { default as Coachmark } from './coachmark';
|
20
20
|
export { default as Dialog } from './dialog';
|
21
21
|
export { default as Divider } from './divider';
|
@@ -2,9 +2,9 @@ import type { Component } from '../../models';
|
|
2
2
|
import type { Constructor } from './index.types';
|
3
3
|
export declare abstract class FocusTrapClassInterface {
|
4
4
|
protected abstract focusTrap: boolean;
|
5
|
-
enabledPreventScroll: boolean;
|
6
5
|
setInitialFocus(elementIndexToReceiveFocus?: number): void;
|
7
6
|
activateFocusTrap(): void;
|
8
7
|
deactivateFocusTrap(): void;
|
8
|
+
private setIsFocusTrapActivated;
|
9
9
|
}
|
10
|
-
export declare const FocusTrapMixin: <T extends Constructor<Component>>(superClass: T) => Constructor<
|
10
|
+
export declare const FocusTrapMixin: <T extends Constructor<Component>>(superClass: T) => Constructor<Component & FocusTrapClassInterface> & T;
|
@@ -7,8 +7,69 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
9
9
|
};
|
10
|
+
/* eslint-disable no-use-before-define */
|
10
11
|
/* eslint-disable max-classes-per-file */
|
11
12
|
import { property } from 'lit/decorators.js';
|
13
|
+
/**
|
14
|
+
* FocusTrapStack manages a stack of active focus traps,
|
15
|
+
* ensuring only one focus trap is active at a time.
|
16
|
+
*
|
17
|
+
* This also makes sure there is only one keydown listener active at a time,
|
18
|
+
* which is necessary to handle focus trapping correctly.
|
19
|
+
*/
|
20
|
+
class FocusTrapStack {
|
21
|
+
static get stackArray() {
|
22
|
+
return Array.from(this.stack);
|
23
|
+
}
|
24
|
+
static addKeydownListener(keydownListener) {
|
25
|
+
this.currentKeydownListener = keydownListener;
|
26
|
+
document.addEventListener('keydown', keydownListener);
|
27
|
+
}
|
28
|
+
static removeKeydownListener() {
|
29
|
+
if (this.currentKeydownListener) {
|
30
|
+
document.removeEventListener('keydown', this.currentKeydownListener);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
/**
|
34
|
+
* Activates a focus trap by adding it to the stack.
|
35
|
+
* It deactivates all other traps in the stack to ensure only one trap is active
|
36
|
+
*
|
37
|
+
* @param trap - The focus trap to activate.
|
38
|
+
*/
|
39
|
+
static activate(trap) {
|
40
|
+
// Deactivate all other traps
|
41
|
+
this.stackArray.forEach((activeTrap) => {
|
42
|
+
if (activeTrap !== trap) {
|
43
|
+
activeTrap.setIsFocusTrapActivated(false);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
this.stack.add(trap);
|
47
|
+
// remove the current keydown listener if it exists
|
48
|
+
// and add a new one for the current trap
|
49
|
+
this.removeKeydownListener();
|
50
|
+
this.addKeydownListener(trap.handleTabKeydown.bind(trap));
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* Deactivates a focus trap by removing it from the stack.
|
54
|
+
* Activates the previous trap in the stack if any.
|
55
|
+
*
|
56
|
+
* @param trap - The focus trap to deactivate.
|
57
|
+
*/
|
58
|
+
static deactivate(trap) {
|
59
|
+
this.stack.delete(trap);
|
60
|
+
this.removeKeydownListener();
|
61
|
+
// activate the previous trap in the stack if any
|
62
|
+
if (this.stack.size > 0) {
|
63
|
+
const lastTrap = this.stackArray.pop();
|
64
|
+
if (lastTrap) {
|
65
|
+
lastTrap.setIsFocusTrapActivated(true);
|
66
|
+
this.addKeydownListener(lastTrap.handleTabKeydown.bind(lastTrap));
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
FocusTrapStack.stack = new Set();
|
72
|
+
FocusTrapStack.currentKeydownListener = null;
|
12
73
|
export const FocusTrapMixin = (superClass) => {
|
13
74
|
class FocusTrap extends superClass {
|
14
75
|
constructor() {
|
@@ -17,15 +78,10 @@ export const FocusTrapMixin = (superClass) => {
|
|
17
78
|
* Determines whether focus should wrap around when reaching the first or last focusable element.
|
18
79
|
* If true, focus will cycle from end to start and vice versa.
|
19
80
|
*
|
20
|
-
* This only applies when `
|
81
|
+
* This only applies when `focusTrap` is true.
|
21
82
|
* @default true
|
22
83
|
*/
|
23
84
|
this.shouldFocusTrapWrap = true;
|
24
|
-
/**
|
25
|
-
* Prevent outside scrolling when element is shown.
|
26
|
-
* @default false
|
27
|
-
*/
|
28
|
-
this.enabledPreventScroll = false;
|
29
85
|
/** @internal */
|
30
86
|
this.focusTrapIndex = -1;
|
31
87
|
/** @internal */
|
@@ -33,41 +89,23 @@ export const FocusTrapMixin = (superClass) => {
|
|
33
89
|
/** @internal */
|
34
90
|
this.isFocusTrapActivated = false;
|
35
91
|
}
|
36
|
-
|
37
|
-
|
38
|
-
document.addEventListener('keydown', this.handleTabKeydown.bind(this));
|
39
|
-
}
|
40
|
-
disconnectedCallback() {
|
41
|
-
super.disconnectedCallback();
|
42
|
-
document.removeEventListener('keydown', this.handleTabKeydown.bind(this));
|
43
|
-
}
|
44
|
-
async updated(changedProperties) {
|
45
|
-
super.updated(changedProperties);
|
46
|
-
if (changedProperties.has('focusTrap')) {
|
47
|
-
if (!this.focusTrap) {
|
48
|
-
this.deactivateFocusTrap();
|
49
|
-
}
|
50
|
-
}
|
92
|
+
setIsFocusTrapActivated(isActivated) {
|
93
|
+
this.isFocusTrapActivated = isActivated;
|
51
94
|
}
|
52
95
|
/**
|
53
96
|
* Activate the focus trap
|
54
|
-
* This calculates the focusable elements within the component's shadow root
|
55
97
|
*/
|
56
98
|
activateFocusTrap() {
|
57
|
-
|
58
|
-
|
59
|
-
this.setFocusableElements();
|
60
|
-
}
|
99
|
+
this.setIsFocusTrapActivated(true);
|
100
|
+
FocusTrapStack.activate(this);
|
61
101
|
}
|
62
102
|
/**
|
63
103
|
* Deactivate the focus trap.
|
64
104
|
*/
|
65
105
|
deactivateFocusTrap() {
|
66
|
-
this.
|
106
|
+
this.setIsFocusTrapActivated(false);
|
107
|
+
FocusTrapStack.deactivate(this);
|
67
108
|
this.focusTrapIndex = -1;
|
68
|
-
// todo: this should not override the body overflow style, but reset it instead
|
69
|
-
this.enabledPreventScroll = false;
|
70
|
-
document.body.style.overflow = '';
|
71
109
|
}
|
72
110
|
/**
|
73
111
|
* Checks if the element has no client rectangles (not visible in the viewport).
|
@@ -185,6 +223,8 @@ export const FocusTrapMixin = (superClass) => {
|
|
185
223
|
/**
|
186
224
|
* Recursively finds all focusable elements within the given root and its descendants.
|
187
225
|
*
|
226
|
+
* Make sure this is performant, as it will be called multiple times.
|
227
|
+
*
|
188
228
|
* @param root - The root element to search for focusable elements.
|
189
229
|
* @param matches - The set of focusable elements.
|
190
230
|
* @returns The list of focusable elements.
|
@@ -230,14 +270,13 @@ export const FocusTrapMixin = (superClass) => {
|
|
230
270
|
* @param elementIndexToReceiveFocus - The index of the preferable element to focus.
|
231
271
|
*/
|
232
272
|
setInitialFocus(elementIndexToReceiveFocus = 0) {
|
233
|
-
|
273
|
+
this.setFocusableElements();
|
274
|
+
if (this.focusableElements.length === 0 || !this.focusTrap) {
|
234
275
|
return;
|
235
|
-
if (this.enabledPreventScroll) {
|
236
|
-
document.body.style.overflow = 'hidden';
|
237
276
|
}
|
238
277
|
if (this.focusableElements[elementIndexToReceiveFocus]) {
|
239
278
|
this.focusTrapIndex = elementIndexToReceiveFocus;
|
240
|
-
this.focusableElements[elementIndexToReceiveFocus].focus();
|
279
|
+
this.focusableElements[elementIndexToReceiveFocus].focus({ preventScroll: true });
|
241
280
|
}
|
242
281
|
}
|
243
282
|
/**
|
@@ -309,6 +348,8 @@ export const FocusTrapMixin = (superClass) => {
|
|
309
348
|
* If true, the focus will be trapped in the previous element.
|
310
349
|
*/
|
311
350
|
trapFocus(direction) {
|
351
|
+
// calculate the focusable elements
|
352
|
+
this.setFocusableElements();
|
312
353
|
if (this.focusableElements.length === 0) {
|
313
354
|
return;
|
314
355
|
}
|
@@ -322,7 +363,7 @@ export const FocusTrapMixin = (superClass) => {
|
|
322
363
|
}
|
323
364
|
const nextElement = this.focusableElements[this.focusTrapIndex];
|
324
365
|
if (nextElement) {
|
325
|
-
nextElement.focus();
|
366
|
+
nextElement.focus({ preventScroll: true });
|
326
367
|
}
|
327
368
|
}
|
328
369
|
/**
|
@@ -330,8 +371,9 @@ export const FocusTrapMixin = (superClass) => {
|
|
330
371
|
*
|
331
372
|
* @param event - The keyboard event.
|
332
373
|
*/
|
374
|
+
// @ts-ignore - this is a method which will be called in the stack
|
333
375
|
handleTabKeydown(event) {
|
334
|
-
if (!this.isFocusTrapActivated
|
376
|
+
if (!this.isFocusTrapActivated) {
|
335
377
|
return;
|
336
378
|
}
|
337
379
|
if (event.key === 'Tab') {
|
@@ -344,9 +386,5 @@ export const FocusTrapMixin = (superClass) => {
|
|
344
386
|
property({ type: Boolean, reflect: true, attribute: 'should-focus-trap-wrap' }),
|
345
387
|
__metadata("design:type", Boolean)
|
346
388
|
], FocusTrap.prototype, "shouldFocusTrapWrap", void 0);
|
347
|
-
__decorate([
|
348
|
-
property({ type: Boolean }),
|
349
|
-
__metadata("design:type", Boolean)
|
350
|
-
], FocusTrap.prototype, "enabledPreventScroll", void 0);
|
351
389
|
return FocusTrap;
|
352
390
|
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { LitElement } from 'lit';
|
2
|
+
import type { Constructor } from './index.types';
|
3
|
+
import type { Component } from '../../models';
|
4
|
+
export declare abstract class PreventScrollMixinInterface {
|
5
|
+
protected abstract preventScroll?: boolean;
|
6
|
+
protected activatePreventScroll(): void;
|
7
|
+
protected deactivatePreventScroll(): void;
|
8
|
+
}
|
9
|
+
export declare const PreventScrollMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<Component & PreventScrollMixinInterface> & T;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
export const PreventScrollMixin = (superClass) => {
|
2
|
+
class PreventScroll extends superClass {
|
3
|
+
constructor() {
|
4
|
+
super(...arguments);
|
5
|
+
/**
|
6
|
+
* @internal
|
7
|
+
*/
|
8
|
+
this.isPreventScrollActive = false;
|
9
|
+
/**
|
10
|
+
* @internal
|
11
|
+
*/
|
12
|
+
this.previousDocumentBodyStyleOverflow = '';
|
13
|
+
}
|
14
|
+
activatePreventScroll() {
|
15
|
+
if (this.preventScroll && !this.isPreventScrollActive) {
|
16
|
+
this.isPreventScrollActive = true;
|
17
|
+
// Store the previous body overflow style
|
18
|
+
this.previousDocumentBodyStyleOverflow = document.body.style.overflow;
|
19
|
+
// Set body overflow to hidden to prevent scrolling
|
20
|
+
document.body.style.overflow = 'hidden';
|
21
|
+
}
|
22
|
+
}
|
23
|
+
deactivatePreventScroll() {
|
24
|
+
if (this.isPreventScrollActive) {
|
25
|
+
this.isPreventScrollActive = false;
|
26
|
+
// Restore the previous body overflow style
|
27
|
+
document.body.style.overflow = this.previousDocumentBodyStyleOverflow;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
return PreventScroll;
|
32
|
+
};
|
package/package.json
CHANGED