@momentum-design/components 0.111.0 → 0.111.1
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 +223 -219
- package/dist/browser/index.js.map +4 -4
- package/dist/components/list/list.component.d.ts +29 -35
- package/dist/components/list/list.component.js +77 -79
- package/dist/components/list/list.constants.d.ts +5 -1
- package/dist/components/list/list.constants.js +5 -1
- package/dist/components/list/list.styles.js +4 -0
- package/dist/components/listbox/listbox.component.d.ts +1 -1
- package/dist/components/listbox/listbox.component.js +1 -1
- package/dist/custom-elements.json +4373 -4281
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +4 -4
- package/dist/utils/mixins/ListNavigationMixin.d.ts +3 -2
- package/dist/utils/mixins/ListNavigationMixin.js +34 -18
- package/package.json +1 -1
@@ -1,5 +1,6 @@
|
|
1
1
|
import type { CSSResult } from 'lit';
|
2
2
|
import { Component } from '../../models';
|
3
|
+
declare const List_base: import("../../utils/mixins/index.types").Constructor<Component & import("../../utils/mixins/ListNavigationMixin").ListNavigationMixinInterface> & import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/lifecycle/CaptureDestroyEventForChildElement").CaptureDestroyEventForChildElementInterface> & typeof Component;
|
3
4
|
/**
|
4
5
|
* mdc-list component is used to display a group of list items. It is used as a container to wrap other list items.
|
5
6
|
*
|
@@ -13,55 +14,48 @@ import { Component } from '../../models';
|
|
13
14
|
*
|
14
15
|
* @csspart container - The container slot around the list items
|
15
16
|
*/
|
16
|
-
declare class List extends
|
17
|
+
declare class List extends List_base {
|
17
18
|
/**
|
18
19
|
* @internal
|
19
|
-
* Get all listitem elements which are not disabled in the list.
|
20
20
|
*/
|
21
|
-
private
|
22
|
-
constructor();
|
23
|
-
connectedCallback(): void;
|
21
|
+
private itemsStore;
|
24
22
|
/**
|
25
|
-
*
|
26
|
-
* If
|
27
|
-
* and
|
28
|
-
*
|
29
|
-
*
|
23
|
+
* Whether to loop navigation when reaching the end of the list.
|
24
|
+
* If 'true', pressing the down arrow on the last item will focus the first item,
|
25
|
+
* and pressing the up arrow on the first item will focus the last item.
|
26
|
+
* If 'false', navigation will stop at the first or last item.
|
27
|
+
*
|
28
|
+
* @default ''
|
30
29
|
*/
|
31
|
-
|
30
|
+
loop: 'true' | 'false';
|
32
31
|
/**
|
33
|
-
*
|
34
|
-
* If the
|
35
|
-
*
|
36
|
-
* @
|
37
|
-
* @returns The index of the target element in the listItems array.
|
32
|
+
* The index of the item that should receive focus when the list is first rendered.
|
33
|
+
* If the index is out of bounds, the first item (index 0) will receive focus.
|
34
|
+
*
|
35
|
+
* @default 0
|
38
36
|
*/
|
39
|
-
|
37
|
+
initialFocus: number;
|
38
|
+
constructor();
|
39
|
+
connectedCallback(): void;
|
40
40
|
/**
|
41
|
-
*
|
42
|
-
* Supports navigation keys for moving focus within a list.
|
43
|
-
* @param key - The key that was pressed.
|
44
|
-
* @param currentIndex - The current index of the focused list item.
|
45
|
-
* @param wrappedDivsCount - The total number of list items.
|
46
|
-
* @returns The new index to focus on, or undefined if the key is not supported.
|
41
|
+
* @internal
|
47
42
|
*/
|
48
|
-
|
43
|
+
get navItems(): HTMLElement[];
|
49
44
|
/**
|
50
|
-
*
|
51
|
-
*
|
52
|
-
*
|
53
|
-
* @param event - The mouse event.
|
45
|
+
* Update the tabIndex of the list items when a new item is added.
|
46
|
+
*
|
47
|
+
* @internal
|
54
48
|
*/
|
55
|
-
|
49
|
+
private handleCreatedEvent;
|
56
50
|
/**
|
57
|
-
*
|
58
|
-
*
|
59
|
-
* element. This is used when navigating the list via keyboard.
|
51
|
+
* Update the focus when an item is removed.
|
52
|
+
* If there is a next item, focus it. If not, focus the previous item.
|
60
53
|
*
|
61
|
-
* @
|
54
|
+
* @internal
|
62
55
|
*/
|
63
|
-
private
|
64
|
-
|
56
|
+
private handleDestroyEvent;
|
57
|
+
/** @internal */
|
58
|
+
private isValidItem;
|
65
59
|
render(): import("lit-html").TemplateResult<1>;
|
66
60
|
static styles: Array<CSSResult>;
|
67
61
|
}
|
@@ -8,12 +8,16 @@ 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
10
|
import { html } from 'lit';
|
11
|
-
import {
|
11
|
+
import { property } from 'lit/decorators.js';
|
12
12
|
import { Component } from '../../models';
|
13
|
-
import { KEYS } from '../../utils/keys';
|
14
13
|
import { ROLE } from '../../utils/roles';
|
14
|
+
import { ListNavigationMixin } from '../../utils/mixins/ListNavigationMixin';
|
15
15
|
import { TAG_NAME as LISTITEM_TAGNAME } from '../listitem/listitem.constants';
|
16
|
+
import { ElementStore } from '../../utils/controllers/ElementStore';
|
17
|
+
import { CaptureDestroyEventForChildElement } from '../../utils/mixins/lifecycle/CaptureDestroyEventForChildElement';
|
18
|
+
import { LIFE_CYCLE_EVENTS } from '../../utils/mixins/lifecycle/lifecycle.contants';
|
16
19
|
import styles from './list.styles';
|
20
|
+
import { DEFAULTS } from './list.constants';
|
17
21
|
/**
|
18
22
|
* mdc-list component is used to display a group of list items. It is used as a container to wrap other list items.
|
19
23
|
*
|
@@ -27,10 +31,65 @@ import styles from './list.styles';
|
|
27
31
|
*
|
28
32
|
* @csspart container - The container slot around the list items
|
29
33
|
*/
|
30
|
-
class List extends Component {
|
34
|
+
class List extends ListNavigationMixin(CaptureDestroyEventForChildElement(Component)) {
|
31
35
|
constructor() {
|
32
36
|
super();
|
33
|
-
|
37
|
+
/**
|
38
|
+
* Whether to loop navigation when reaching the end of the list.
|
39
|
+
* If 'true', pressing the down arrow on the last item will focus the first item,
|
40
|
+
* and pressing the up arrow on the first item will focus the last item.
|
41
|
+
* If 'false', navigation will stop at the first or last item.
|
42
|
+
*
|
43
|
+
* @default ''
|
44
|
+
*/
|
45
|
+
this.loop = DEFAULTS.LOOP;
|
46
|
+
/**
|
47
|
+
* The index of the item that should receive focus when the list is first rendered.
|
48
|
+
* If the index is out of bounds, the first item (index 0) will receive focus.
|
49
|
+
*
|
50
|
+
* @default 0
|
51
|
+
*/
|
52
|
+
this.initialFocus = DEFAULTS.INITIAL_FOCUS;
|
53
|
+
/**
|
54
|
+
* Update the tabIndex of the list items when a new item is added.
|
55
|
+
*
|
56
|
+
* @internal
|
57
|
+
*/
|
58
|
+
this.handleCreatedEvent = (event) => {
|
59
|
+
const createdElement = event.target;
|
60
|
+
if (!this.isValidItem(createdElement)) {
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
createdElement.tabIndex = -1;
|
64
|
+
};
|
65
|
+
/**
|
66
|
+
* Update the focus when an item is removed.
|
67
|
+
* If there is a next item, focus it. If not, focus the previous item.
|
68
|
+
*
|
69
|
+
* @internal
|
70
|
+
*/
|
71
|
+
this.handleDestroyEvent = (event) => {
|
72
|
+
const destroyedElement = event.target;
|
73
|
+
if (!this.isValidItem(destroyedElement) || destroyedElement.tabIndex !== 0) {
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
const destroyedItemIndex = this.navItems.findIndex(node => node === destroyedElement);
|
77
|
+
if (destroyedItemIndex === -1) {
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
let newIndex = destroyedItemIndex + 1;
|
81
|
+
if (newIndex >= this.navItems.length) {
|
82
|
+
newIndex = destroyedItemIndex - 1;
|
83
|
+
}
|
84
|
+
this.resetTabIndexes(newIndex);
|
85
|
+
};
|
86
|
+
this.addEventListener(LIFE_CYCLE_EVENTS.CREATED, this.handleCreatedEvent);
|
87
|
+
this.addEventListener(LIFE_CYCLE_EVENTS.DESTROYED, this.handleDestroyEvent);
|
88
|
+
// This must be initialized after the destroyed event listener
|
89
|
+
// to keep the element in the itemStore in order to move the focus correctly
|
90
|
+
this.itemsStore = new ElementStore(this, {
|
91
|
+
isValidItem: this.isValidItem,
|
92
|
+
});
|
34
93
|
}
|
35
94
|
connectedCallback() {
|
36
95
|
super.connectedCallback();
|
@@ -38,91 +97,30 @@ class List extends Component {
|
|
38
97
|
this.setAttribute('role', ROLE.LIST);
|
39
98
|
}
|
40
99
|
/**
|
41
|
-
*
|
42
|
-
* If the key is 'ArrowUp' or 'ArrowDown', it focuses to the previous or next list item
|
43
|
-
* and sets the active tabindex of the list item.
|
44
|
-
* Prevents the default event behavior.
|
45
|
-
* @param event - The keyboard event.
|
46
|
-
*/
|
47
|
-
handleKeyDown(event) {
|
48
|
-
var _a;
|
49
|
-
const currentIndex = this.getCurrentIndex(event.target);
|
50
|
-
const newIndex = this.getNewIndexBasedOnKey(event.key, currentIndex, this.listItems.length);
|
51
|
-
if (newIndex !== undefined) {
|
52
|
-
(_a = this.listItems[newIndex]) === null || _a === void 0 ? void 0 : _a.focus();
|
53
|
-
this.resetTabIndexAndSetActiveTabIndex(newIndex);
|
54
|
-
}
|
55
|
-
}
|
56
|
-
/**
|
57
|
-
* Returns the index of the given target in the listItems array.
|
58
|
-
* If the target is not a list item, but a child element of a list item,
|
59
|
-
* it returns the index of the parent list item.
|
60
|
-
* @param target - The target element to find the index of.
|
61
|
-
* @returns The index of the target element in the listItems array.
|
100
|
+
* @internal
|
62
101
|
*/
|
63
|
-
|
64
|
-
return this.
|
102
|
+
get navItems() {
|
103
|
+
return this.itemsStore.items;
|
65
104
|
}
|
66
|
-
/**
|
67
|
-
|
68
|
-
|
69
|
-
* @param key - The key that was pressed.
|
70
|
-
* @param currentIndex - The current index of the focused list item.
|
71
|
-
* @param wrappedDivsCount - The total number of list items.
|
72
|
-
* @returns The new index to focus on, or undefined if the key is not supported.
|
73
|
-
*/
|
74
|
-
getNewIndexBasedOnKey(key, currentIndex, wrappedDivsCount) {
|
75
|
-
switch (key) {
|
76
|
-
case KEYS.ARROW_DOWN:
|
77
|
-
return (currentIndex + 1) % wrappedDivsCount;
|
78
|
-
case KEYS.ARROW_UP:
|
79
|
-
return (currentIndex - 1 + wrappedDivsCount) % wrappedDivsCount;
|
80
|
-
case KEYS.HOME:
|
81
|
-
return 0;
|
82
|
-
case KEYS.END:
|
83
|
-
return wrappedDivsCount - 1;
|
84
|
-
default:
|
85
|
-
return undefined;
|
86
|
-
}
|
87
|
-
}
|
88
|
-
/**
|
89
|
-
* Handles the mouse click event on the list element.
|
90
|
-
* Finds the index of the target element in the list items array and calls
|
91
|
-
* `resetTabIndexAndSetActiveTabIndex` with that index.
|
92
|
-
* @param event - The mouse event.
|
93
|
-
*/
|
94
|
-
handleMouseClick(event) {
|
95
|
-
const newIndex = this.getCurrentIndex(event.target);
|
96
|
-
this.resetTabIndexAndSetActiveTabIndex(newIndex);
|
97
|
-
}
|
98
|
-
/**
|
99
|
-
* Resets all list items tabindex to -1 and sets the tabindex of the
|
100
|
-
* element at the given index to 0, effectively setting the active
|
101
|
-
* element. This is used when navigating the list via keyboard.
|
102
|
-
*
|
103
|
-
* @param newIndex - The index of the new active element in the list.
|
104
|
-
*/
|
105
|
-
resetTabIndexAndSetActiveTabIndex(newIndex) {
|
106
|
-
this.listItems.forEach((node, index) => {
|
107
|
-
const newTabindex = newIndex === index ? '0' : '-1';
|
108
|
-
node === null || node === void 0 ? void 0 : node.setAttribute('tabindex', newTabindex);
|
109
|
-
});
|
110
|
-
}
|
111
|
-
firstUpdated() {
|
112
|
-
// For the first, we set the first element only as active.
|
113
|
-
this.resetTabIndexAndSetActiveTabIndex(0);
|
105
|
+
/** @internal */
|
106
|
+
isValidItem(item) {
|
107
|
+
return item.matches(`${LISTITEM_TAGNAME}:not([disabled])`);
|
114
108
|
}
|
115
109
|
render() {
|
116
110
|
return html `
|
117
111
|
<slot name="list-header"></slot>
|
118
112
|
<!-- make the container slot role presentation to keep it ignored in a11y tree -->
|
119
|
-
<slot part="container"
|
113
|
+
<slot part="container" role="presentation"></slot>
|
120
114
|
`;
|
121
115
|
}
|
122
116
|
}
|
123
117
|
List.styles = [...Component.styles, ...styles];
|
124
118
|
__decorate([
|
125
|
-
|
126
|
-
__metadata("design:type",
|
127
|
-
], List.prototype, "
|
119
|
+
property({ type: String, reflect: true }),
|
120
|
+
__metadata("design:type", String)
|
121
|
+
], List.prototype, "loop", void 0);
|
122
|
+
__decorate([
|
123
|
+
property({ type: Number, reflect: true, attribute: 'initial-focus' }),
|
124
|
+
__metadata("design:type", Number)
|
125
|
+
], List.prototype, "initialFocus", void 0);
|
128
126
|
export default List;
|
@@ -1,4 +1,8 @@
|
|
1
1
|
import utils from '../../utils/tag-name';
|
2
2
|
const TAG_NAME = utils.constructTagName('list');
|
3
3
|
const HEADER_ID = 'header-id';
|
4
|
-
|
4
|
+
const DEFAULTS = {
|
5
|
+
LOOP: 'true',
|
6
|
+
INITIAL_FOCUS: 0,
|
7
|
+
};
|
8
|
+
export { TAG_NAME, HEADER_ID, DEFAULTS };
|
@@ -3,12 +3,16 @@ const styles = css `
|
|
3
3
|
:host {
|
4
4
|
display: flex;
|
5
5
|
flex-direction: column;
|
6
|
+
scroll-padding-top: 0.25rem;
|
7
|
+
scroll-padding-bottom: 0.25rem;
|
6
8
|
}
|
7
9
|
|
8
10
|
:host::part(container) {
|
9
11
|
display: flex;
|
10
12
|
flex-direction: column;
|
11
13
|
gap: 0rem;
|
14
|
+
scroll-padding-top: 0.25rem;
|
15
|
+
scroll-padding-bottom: 0.25rem;
|
12
16
|
}
|
13
17
|
`;
|
14
18
|
export default [styles];
|
@@ -49,7 +49,7 @@ class ListBox extends ListNavigationMixin(CaptureDestroyEventForChildElement(Com
|
|
49
49
|
* https://www.w3.org/WAI/ARIA/apg/practices/listbox
|
50
50
|
* @internal
|
51
51
|
*/
|
52
|
-
this.loop = false;
|
52
|
+
this.loop = 'false';
|
53
53
|
/**
|
54
54
|
* The name attribute is used to identify the listbox
|
55
55
|
*/
|