@momentum-design/components 0.110.2 → 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.
@@ -1,6 +1,6 @@
1
1
  export { default as Accordion } from './accordion';
2
- export { default as AccordionButton } from './accordionbutton';
3
2
  export { default as AccordionGroup } from './accordiongroup';
3
+ export { default as AccordionButton } from './accordionbutton';
4
4
  export { default as AlertChip } from './alertchip';
5
5
  export { default as Animation } from './animation';
6
6
  export { default as Appheader } from './appheader';
@@ -13,15 +13,14 @@ export { default as Button } from './button';
13
13
  export { default as ButtonGroup } from './buttongroup';
14
14
  export { default as ButtonLink } from './buttonlink';
15
15
  export { default as Buttonsimple } from './buttonsimple';
16
- export { default as Card } from './card';
17
16
  export { default as CardButton } from './cardbutton';
18
17
  export { default as CardCheckbox } from './cardcheckbox';
19
18
  export { default as CardRadio } from './cardradio';
19
+ export { default as Card } from './card';
20
20
  export { default as Checkbox } from './checkbox';
21
21
  export { default as Chip } from './chip';
22
22
  export { default as Coachmark } from './coachmark';
23
23
  export { default as Combobox } from './combobox';
24
- export { default as Dialog } from './dialog';
25
24
  export { default as Divider } from './divider';
26
25
  export { default as FilterChip } from './filterchip';
27
26
  export { default as FormfieldGroup } from './formfieldgroup';
@@ -35,6 +34,7 @@ export { default as LinkButton } from './linkbutton';
35
34
  export { default as Linksimple } from './linksimple';
36
35
  export { default as List } from './list';
37
36
  export { default as ListBox } from './listbox';
37
+ export { default as Dialog } from './dialog';
38
38
  export { default as Listheader } from './listheader';
39
39
  export { default as ListItem } from './listitem';
40
40
  export { default as Marker } from './marker';
@@ -1,6 +1,6 @@
1
1
  export { default as Accordion } from './accordion';
2
- export { default as AccordionButton } from './accordionbutton';
3
2
  export { default as AccordionGroup } from './accordiongroup';
3
+ export { default as AccordionButton } from './accordionbutton';
4
4
  export { default as AlertChip } from './alertchip';
5
5
  export { default as Animation } from './animation';
6
6
  export { default as Appheader } from './appheader';
@@ -13,15 +13,14 @@ export { default as Button } from './button';
13
13
  export { default as ButtonGroup } from './buttongroup';
14
14
  export { default as ButtonLink } from './buttonlink';
15
15
  export { default as Buttonsimple } from './buttonsimple';
16
- export { default as Card } from './card';
17
16
  export { default as CardButton } from './cardbutton';
18
17
  export { default as CardCheckbox } from './cardcheckbox';
19
18
  export { default as CardRadio } from './cardradio';
19
+ export { default as Card } from './card';
20
20
  export { default as Checkbox } from './checkbox';
21
21
  export { default as Chip } from './chip';
22
22
  export { default as Coachmark } from './coachmark';
23
23
  export { default as Combobox } from './combobox';
24
- export { default as Dialog } from './dialog';
25
24
  export { default as Divider } from './divider';
26
25
  export { default as FilterChip } from './filterchip';
27
26
  export { default as FormfieldGroup } from './formfieldgroup';
@@ -35,6 +34,7 @@ export { default as LinkButton } from './linkbutton';
35
34
  export { default as Linksimple } from './linksimple';
36
35
  export { default as List } from './list';
37
36
  export { default as ListBox } from './listbox';
37
+ export { default as Dialog } from './dialog';
38
38
  export { default as Listheader } from './listheader';
39
39
  export { default as ListItem } from './listitem';
40
40
  export { default as Marker } from './marker';
@@ -1,10 +1,11 @@
1
1
  import type { Component } from '../../models';
2
2
  import type { Constructor } from './index.types';
3
3
  export declare abstract class ListNavigationMixinInterface {
4
- protected loop: boolean;
4
+ protected loop: 'true' | 'false';
5
5
  protected propagateAllKeyEvents: boolean;
6
- protected resetTabIndexes(index: number): void;
6
+ protected initialFocus: number;
7
7
  protected abstract get navItems(): HTMLElement[];
8
+ protected resetTabIndexes(index: number): void;
8
9
  protected resetTabIndexAndSetFocus(newIndex: number, oldIndex?: number, focusNewItem?: boolean): void;
9
10
  }
10
11
  /**
@@ -23,14 +23,14 @@ export const ListNavigationMixin = (superClass) => {
23
23
  super(...rest);
24
24
  /**
25
25
  * Whether to loop navigation when reaching the end of the list.
26
- * If true, pressing the down arrow on the last item will focus the first item,
26
+ * If 'true', pressing the down arrow on the last item will focus the first item,
27
27
  * and pressing the up arrow on the first item will focus the last item.
28
- * If false, navigation will stop at the first or last item.
28
+ * If 'false', navigation will stop at the first or last item.
29
29
  *
30
- * @default true
30
+ * @default 'true'
31
31
  * @internal
32
32
  */
33
- this.loop = true;
33
+ this.loop = 'true';
34
34
  /**
35
35
  * Whether to propagate all key events to parent components.
36
36
  * If true, all key events will bubble up and can be handled by parent components.
@@ -40,6 +40,13 @@ export const ListNavigationMixin = (superClass) => {
40
40
  * @internal
41
41
  */
42
42
  this.propagateAllKeyEvents = false;
43
+ /**
44
+ * The index of the item to focus initially when the component is first updated.
45
+ *
46
+ * @default 0
47
+ * @internal
48
+ */
49
+ this.initialFocus = 0;
43
50
  /**
44
51
  * Handles keydown events for navigation within the list.
45
52
  * It allows users to navigate through the list items using arrow keys, home, and end keys.
@@ -52,41 +59,40 @@ export const ListNavigationMixin = (superClass) => {
52
59
  * @internal
53
60
  */
54
61
  this.handleNavigationKeyDown = (event) => {
55
- let isKeyHandled = false;
62
+ const keysToHandle = new Set([KEYS.ARROW_DOWN, KEYS.ARROW_UP, KEYS.HOME, KEYS.END]);
63
+ const isRtl = window.getComputedStyle(this).direction === 'rtl';
64
+ const targetKey = this.resolveDirectionKey(event.key, isRtl);
65
+ if (!keysToHandle.has(targetKey)) {
66
+ return;
67
+ }
56
68
  const target = event.target;
57
69
  const currentIndex = this.getCurrentIndex(target);
58
70
  if (currentIndex === -1)
59
71
  return;
60
72
  this.resetTabIndexes(currentIndex);
61
- const isRtl = window.getComputedStyle(this).direction === 'rtl';
62
- const targetKey = this.resolveDirectionKey(event.key, isRtl);
63
73
  switch (targetKey) {
64
74
  case KEYS.HOME: {
65
75
  // Move focus to the first item
66
76
  this.resetTabIndexAndSetFocus(0, currentIndex);
67
- isKeyHandled = true;
68
77
  break;
69
78
  }
70
79
  case KEYS.END: {
71
80
  // Move focus to the last item
72
81
  this.resetTabIndexAndSetFocus(this.navItems.length - 1, currentIndex);
73
- isKeyHandled = true;
74
82
  break;
75
83
  }
76
84
  case KEYS.ARROW_DOWN: {
77
85
  // Move focus to the next item
78
- const eolIndex = this.loop ? 0 : currentIndex;
86
+ const eolIndex = this.shouldLoop() ? 0 : currentIndex;
79
87
  const newIndex = currentIndex + 1 === this.navItems.length ? eolIndex : currentIndex + 1;
80
88
  this.resetTabIndexAndSetFocus(newIndex, currentIndex);
81
- isKeyHandled = true;
82
89
  break;
83
90
  }
84
91
  case KEYS.ARROW_UP: {
85
92
  // Move focus to the prev item
86
- const eolIndex = this.loop ? this.navItems.length - 1 : currentIndex;
93
+ const eolIndex = this.shouldLoop() ? this.navItems.length - 1 : currentIndex;
87
94
  const newIndex = currentIndex - 1 === -1 ? eolIndex : currentIndex - 1;
88
95
  this.resetTabIndexAndSetFocus(newIndex, currentIndex);
89
- isKeyHandled = true;
90
96
  break;
91
97
  }
92
98
  default:
@@ -94,7 +100,7 @@ export const ListNavigationMixin = (superClass) => {
94
100
  }
95
101
  // When the component consume any of the pressed key, we need to stop propagation
96
102
  // to prevent the event from bubbling up and being handled by parent components which might use the same key.
97
- if (isKeyHandled && !this.propagateAllKeyEvents) {
103
+ if (!this.propagateAllKeyEvents) {
98
104
  event.stopPropagation();
99
105
  event.preventDefault();
100
106
  }
@@ -120,7 +126,8 @@ export const ListNavigationMixin = (superClass) => {
120
126
  */
121
127
  async firstUpdated(changedProperties) {
122
128
  super.firstUpdated(changedProperties);
123
- this.resetTabIndexAndSetFocus(0, undefined, false);
129
+ const indexToFocus = Math.max(Math.min(this.initialFocus, this.navItems.length - 1), 0);
130
+ this.resetTabIndexAndSetFocus(indexToFocus, undefined, false);
124
131
  }
125
132
  /**
126
133
  * Retrieves the current index of the item that triggered the event.
@@ -129,7 +136,9 @@ export const ListNavigationMixin = (superClass) => {
129
136
  * @returns - The index of the current item in the `navItems` array.
130
137
  */
131
138
  getCurrentIndex(target) {
132
- return this.navItems.findIndex(node => node === target);
139
+ return this.navItems.findIndex(node => node === target ||
140
+ // eslint-disable-next-line no-bitwise
141
+ !!(node.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_CONTAINED_BY));
133
142
  }
134
143
  /**
135
144
  * Reset all tabindex to -1 and set the tabindex of the current item to 0
@@ -162,13 +171,17 @@ export const ListNavigationMixin = (superClass) => {
162
171
  if (newIndex === oldIndex && newItem && newItem.getAttribute('tabindex') === '0') {
163
172
  return;
164
173
  }
165
- if (oldIndex !== undefined && navItems[oldIndex]) {
174
+ if (oldIndex === undefined) {
175
+ navItems.forEach(item => item.setAttribute('tabindex', '-1'));
176
+ }
177
+ else if (navItems[oldIndex]) {
166
178
  // Reset tabindex of the old item
167
179
  navItems[oldIndex].setAttribute('tabindex', '-1');
168
180
  }
169
181
  newItem.setAttribute('tabindex', '0');
170
182
  if (focusNewItem) {
171
- newItem.focus();
183
+ newItem.focus({ preventScroll: true });
184
+ newItem.scrollIntoView({ block: 'nearest' });
172
185
  }
173
186
  }
174
187
  /**
@@ -193,6 +206,9 @@ export const ListNavigationMixin = (superClass) => {
193
206
  return key;
194
207
  }
195
208
  }
209
+ shouldLoop() {
210
+ return this.loop !== 'false';
211
+ }
196
212
  }
197
213
  // Cast return type to your mixin's interface intersected with the superClass type
198
214
  return InnerMixinClass;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@momentum-design/components",
3
3
  "packageManager": "yarn@3.2.4",
4
- "version": "0.110.2",
4
+ "version": "0.111.1",
5
5
  "engines": {
6
6
  "node": ">=20.0.0",
7
7
  "npm": ">=8.0.0"