@ni/nimble-components 30.1.4 → 30.1.5

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,4 +1,4 @@
1
- import { Menu as FoundationMenu } from '@microsoft/fast-foundation';
1
+ import { Menu as FoundationMenu } from './menu.foundation';
2
2
  declare global {
3
3
  interface HTMLElementTagNameMap {
4
4
  'nimble-menu': Menu;
@@ -1,4 +1,6 @@
1
- import { DesignSystem, Menu as FoundationMenu, menuTemplate as template } from '@microsoft/fast-foundation';
1
+ import { DesignSystem } from '@microsoft/fast-foundation';
2
+ import { Menu as FoundationMenu } from './menu.foundation';
3
+ import { template } from './template';
2
4
  import { styles } from './styles';
3
5
  /**
4
6
  * A nimble-styled menu
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/menu/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,IAAI,IAAI,cAAc,EACtB,YAAY,IAAI,QAAQ,EAC3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAQlC;;GAEG;AACH,MAAM,OAAO,IAAK,SAAQ,cAAc;CAAG;AAE3C;;;;;;;;GAQG;AACH,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,cAAc;IACzB,QAAQ;IACR,MAAM;CACT,CAAC,CAAC;AAEH,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC","sourcesContent":["import {\n DesignSystem,\n Menu as FoundationMenu,\n menuTemplate as template\n} from '@microsoft/fast-foundation';\nimport { styles } from './styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-menu': Menu;\n }\n}\n\n/**\n * A nimble-styled menu\n */\nexport class Menu extends FoundationMenu {}\n\n/**\n * A function that returns a nimble-menu registration for configuring the component with a DesignSystem.\n * Implements {@link @microsoft/fast-foundation#menuTemplate}\n *\n * @public\n * @remarks\n * Generates HTML Element: \\<nimble-menu\\>\n *\n */\nconst nimbleMenu = Menu.compose({\n baseName: 'menu',\n baseClass: FoundationMenu,\n template,\n styles\n});\n\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleMenu());\nexport const menuTag = 'nimble-menu';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/menu/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAQlC;;GAEG;AACH,MAAM,OAAO,IAAK,SAAQ,cAAc;CAAG;AAE3C;;;;;;;;GAQG;AACH,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,cAAc;IACzB,QAAQ;IACR,MAAM;CACT,CAAC,CAAC;AAEH,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC","sourcesContent":["import { DesignSystem } from '@microsoft/fast-foundation';\nimport { Menu as FoundationMenu } from './menu.foundation';\nimport { template } from './template';\nimport { styles } from './styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-menu': Menu;\n }\n}\n\n/**\n * A nimble-styled menu\n */\nexport class Menu extends FoundationMenu {}\n\n/**\n * A function that returns a nimble-menu registration for configuring the component with a DesignSystem.\n * Implements {@link @microsoft/fast-foundation#menuTemplate}\n *\n * @public\n * @remarks\n * Generates HTML Element: \\<nimble-menu\\>\n *\n */\nconst nimbleMenu = Menu.compose({\n baseName: 'menu',\n baseClass: FoundationMenu,\n template,\n styles\n});\n\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleMenu());\nexport const menuTag = 'nimble-menu';\n"]}
@@ -0,0 +1,83 @@
1
+ import { FoundationElement } from '@microsoft/fast-foundation';
2
+ /**
3
+ * A Menu Custom HTML Element.
4
+ * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.
5
+ *
6
+ * @slot - The default slot for the menu items
7
+ *
8
+ * @public
9
+ */
10
+ export declare class Menu extends FoundationElement {
11
+ private static readonly focusableElementRoles;
12
+ /**
13
+ * @internal
14
+ */
15
+ items: HTMLSlotElement;
16
+ /**
17
+ * @internal
18
+ */
19
+ itemIcons?: Element[];
20
+ private menuItems;
21
+ private expandedItem;
22
+ /**
23
+ * The index of the focusable element in the items array
24
+ * defaults to -1
25
+ */
26
+ private focusIndex;
27
+ /**
28
+ * @internal
29
+ */
30
+ connectedCallback(): void;
31
+ /**
32
+ * @internal
33
+ */
34
+ disconnectedCallback(): void;
35
+ /**
36
+ * @internal
37
+ */
38
+ readonly isNestedMenu: () => boolean;
39
+ /**
40
+ * Focuses the first item in the menu.
41
+ *
42
+ * @public
43
+ */
44
+ focus(): void;
45
+ /**
46
+ * Collapses any expanded menu items.
47
+ *
48
+ * @public
49
+ */
50
+ collapseExpandedItem(): void;
51
+ /**
52
+ * @internal
53
+ */
54
+ handleMenuKeyDown(e: KeyboardEvent): boolean;
55
+ /**
56
+ * if focus is moving out of the menu, reset to a stable initial state
57
+ * @internal
58
+ */
59
+ handleFocusOut: (e: FocusEvent) => void;
60
+ private readonly handleItemFocus;
61
+ private readonly handleExpandedChanged;
62
+ private readonly removeItemListeners;
63
+ private itemsChanged;
64
+ private itemIconsChanged;
65
+ private readonly setItems;
66
+ /**
67
+ * handle change from child element
68
+ */
69
+ private readonly changeHandler;
70
+ /**
71
+ * get an array of valid DOM children
72
+ */
73
+ private domChildren;
74
+ /**
75
+ * check if the item is a menu item
76
+ */
77
+ private readonly isMenuItemElement;
78
+ /**
79
+ * check if the item is focusable
80
+ */
81
+ private readonly isFocusableElement;
82
+ private setFocus;
83
+ }
@@ -0,0 +1,306 @@
1
+ import { __decorate } from "tslib";
2
+ /**
3
+ * Based on implementation in FAST repo: https://github.com/microsoft/fast/blob/9c6dbb66615e6d229fc0ebf8065a67f109139f26/packages/web-components/fast-foundation/src/menu/menu.ts
4
+ */
5
+ import { DOM, observable } from '@microsoft/fast-element';
6
+ import { isHTMLElement, keyArrowDown, keyArrowUp, keyEnd, keyHome } from '@microsoft/fast-web-utilities';
7
+ import { FoundationElement, MenuItem, MenuItemRole, roleForMenuItem } from '@microsoft/fast-foundation';
8
+ /**
9
+ * A Menu Custom HTML Element.
10
+ * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.
11
+ *
12
+ * @slot - The default slot for the menu items
13
+ *
14
+ * @public
15
+ */
16
+ export class Menu extends FoundationElement {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.expandedItem = null;
20
+ /**
21
+ * The index of the focusable element in the items array
22
+ * defaults to -1
23
+ */
24
+ this.focusIndex = -1;
25
+ /**
26
+ * @internal
27
+ */
28
+ this.isNestedMenu = () => {
29
+ return (this.parentElement !== null
30
+ && isHTMLElement(this.parentElement)
31
+ && this.parentElement.getAttribute('role') === 'menuitem');
32
+ };
33
+ /**
34
+ * if focus is moving out of the menu, reset to a stable initial state
35
+ * @internal
36
+ */
37
+ this.handleFocusOut = (e) => {
38
+ if (!this.contains(e.relatedTarget)
39
+ && this.menuItems !== undefined) {
40
+ this.collapseExpandedItem();
41
+ // find our first focusable element
42
+ const focusIndex = this.menuItems.findIndex(this.isFocusableElement);
43
+ // set the current focus index's tabindex to -1
44
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
45
+ // set the first focusable element tabindex to 0
46
+ this.menuItems[focusIndex]?.setAttribute('tabindex', '0');
47
+ // set the focus index
48
+ this.focusIndex = focusIndex;
49
+ }
50
+ };
51
+ this.handleItemFocus = (e) => {
52
+ const targetItem = e.target;
53
+ if (this.menuItems !== undefined
54
+ && targetItem !== this.menuItems[this.focusIndex]) {
55
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
56
+ this.focusIndex = this.menuItems.indexOf(targetItem);
57
+ targetItem.setAttribute('tabindex', '0');
58
+ }
59
+ };
60
+ this.handleExpandedChanged = (e) => {
61
+ if (e.defaultPrevented
62
+ || e.target === null
63
+ || this.menuItems === undefined
64
+ || !this.menuItems.includes(e.target)) {
65
+ return;
66
+ }
67
+ e.preventDefault();
68
+ const changedItem = e.target;
69
+ // closing an expanded item without opening another
70
+ if (this.expandedItem !== null
71
+ && changedItem === this.expandedItem
72
+ && changedItem.expanded === false) {
73
+ this.expandedItem = null;
74
+ return;
75
+ }
76
+ if (changedItem.expanded) {
77
+ if (this.expandedItem !== null
78
+ && this.expandedItem !== changedItem) {
79
+ this.expandedItem.expanded = false;
80
+ }
81
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
82
+ this.expandedItem = changedItem;
83
+ this.focusIndex = this.menuItems.indexOf(changedItem);
84
+ changedItem.setAttribute('tabindex', '0');
85
+ }
86
+ };
87
+ this.removeItemListeners = () => {
88
+ if (this.menuItems !== undefined) {
89
+ this.menuItems.forEach((item) => {
90
+ item.removeEventListener('expanded-change', this.handleExpandedChanged);
91
+ item.removeEventListener('focus', this.handleItemFocus);
92
+ });
93
+ }
94
+ };
95
+ this.setItems = () => {
96
+ const newItems = this.domChildren();
97
+ this.removeItemListeners();
98
+ this.menuItems = newItems;
99
+ const menuItems = this.menuItems.filter(this.isMenuItemElement);
100
+ // if our focus index is not -1 we have items
101
+ if (menuItems.length) {
102
+ this.focusIndex = 0;
103
+ }
104
+ function elementIndent(el) {
105
+ const role = el.getAttribute('role');
106
+ const startSlot = el.querySelector('[slot=start]');
107
+ if (role !== MenuItemRole.menuitem && startSlot === null) {
108
+ return 1;
109
+ }
110
+ if (role === MenuItemRole.menuitem && startSlot !== null) {
111
+ return 1;
112
+ }
113
+ if (role !== MenuItemRole.menuitem && startSlot !== null) {
114
+ return 2;
115
+ }
116
+ return 0;
117
+ }
118
+ const indent = menuItems.reduce((accum, current) => {
119
+ const elementValue = elementIndent(current);
120
+ return accum > elementValue ? accum : elementValue;
121
+ }, 0);
122
+ menuItems.forEach((item, index) => {
123
+ item.setAttribute('tabindex', index === 0 ? '0' : '-1');
124
+ item.addEventListener('expanded-change', this.handleExpandedChanged);
125
+ item.addEventListener('focus', this.handleItemFocus);
126
+ if (item instanceof MenuItem || 'startColumnCount' in item) {
127
+ item.startColumnCount = indent;
128
+ }
129
+ });
130
+ };
131
+ /**
132
+ * handle change from child element
133
+ */
134
+ this.changeHandler = (e) => {
135
+ if (this.menuItems === undefined) {
136
+ return;
137
+ }
138
+ const changedMenuItem = e.target;
139
+ const changeItemIndex = this.menuItems.indexOf(changedMenuItem);
140
+ if (changeItemIndex === -1) {
141
+ return;
142
+ }
143
+ if (changedMenuItem.role === 'menuitemradio'
144
+ && changedMenuItem.checked === true) {
145
+ for (let i = changeItemIndex - 1; i >= 0; --i) {
146
+ const item = this.menuItems[i];
147
+ const role = item.getAttribute('role');
148
+ if (role === MenuItemRole.menuitemradio) {
149
+ item.checked = false;
150
+ }
151
+ if (role === 'separator') {
152
+ break;
153
+ }
154
+ }
155
+ const maxIndex = this.menuItems.length - 1;
156
+ for (let i = changeItemIndex + 1; i <= maxIndex; ++i) {
157
+ const item = this.menuItems[i];
158
+ const role = item.getAttribute('role');
159
+ if (role === MenuItemRole.menuitemradio) {
160
+ item.checked = false;
161
+ }
162
+ if (role === 'separator') {
163
+ break;
164
+ }
165
+ }
166
+ }
167
+ };
168
+ /**
169
+ * check if the item is a menu item
170
+ */
171
+ this.isMenuItemElement = (el) => {
172
+ return (isHTMLElement(el)
173
+ && Object.prototype.hasOwnProperty.call(Menu.focusableElementRoles, el.getAttribute('role')));
174
+ };
175
+ /**
176
+ * check if the item is focusable
177
+ */
178
+ this.isFocusableElement = (el) => {
179
+ return this.isMenuItemElement(el);
180
+ };
181
+ }
182
+ /**
183
+ * @internal
184
+ */
185
+ connectedCallback() {
186
+ super.connectedCallback();
187
+ DOM.queueUpdate(() => {
188
+ // wait until children have had a chance to
189
+ // connect before setting/checking their props/attributes
190
+ this.setItems();
191
+ });
192
+ this.addEventListener('change', this.changeHandler);
193
+ }
194
+ /**
195
+ * @internal
196
+ */
197
+ disconnectedCallback() {
198
+ super.disconnectedCallback();
199
+ this.removeItemListeners();
200
+ this.menuItems = undefined;
201
+ this.removeEventListener('change', this.changeHandler);
202
+ }
203
+ /**
204
+ * Focuses the first item in the menu.
205
+ *
206
+ * @public
207
+ */
208
+ focus() {
209
+ this.setFocus(0, 1);
210
+ }
211
+ /**
212
+ * Collapses any expanded menu items.
213
+ *
214
+ * @public
215
+ */
216
+ collapseExpandedItem() {
217
+ if (this.expandedItem !== null) {
218
+ this.expandedItem.expanded = false;
219
+ this.expandedItem = null;
220
+ }
221
+ }
222
+ /**
223
+ * @internal
224
+ */
225
+ handleMenuKeyDown(e) {
226
+ if (e.defaultPrevented || this.menuItems === undefined) {
227
+ return false;
228
+ }
229
+ switch (e.key) {
230
+ case keyArrowDown:
231
+ // go forward one index
232
+ this.setFocus(this.focusIndex + 1, 1);
233
+ return false;
234
+ case keyArrowUp:
235
+ // go back one index
236
+ this.setFocus(this.focusIndex - 1, -1);
237
+ return false;
238
+ case keyEnd:
239
+ // set focus on last item
240
+ this.setFocus(this.menuItems.length - 1, -1);
241
+ return false;
242
+ case keyHome:
243
+ // set focus on first item
244
+ this.setFocus(0, 1);
245
+ return false;
246
+ default:
247
+ // if we are not handling the event, do not prevent default
248
+ return true;
249
+ }
250
+ }
251
+ itemsChanged() {
252
+ // only update children after the component is connected and
253
+ // the setItems has run on connectedCallback
254
+ // (menuItems is undefined until then)
255
+ if (this.$fastController.isConnected && this.menuItems !== undefined) {
256
+ this.setItems();
257
+ }
258
+ }
259
+ itemIconsChanged(oldIcons, newIcons) {
260
+ // must check if set of icon elements is actually different
261
+ if (this.$fastController.isConnected
262
+ && this.menuItems !== undefined
263
+ && (oldIcons.length !== newIcons.length
264
+ || new Set(oldIcons.concat(newIcons)).size !== oldIcons.length)) {
265
+ this.setItems();
266
+ }
267
+ }
268
+ /**
269
+ * get an array of valid DOM children
270
+ */
271
+ domChildren() {
272
+ return Array.from(this.children).filter(child => !child.hasAttribute('hidden'));
273
+ }
274
+ setFocus(focusIndex, adjustment) {
275
+ if (this.menuItems === undefined) {
276
+ return;
277
+ }
278
+ let updatedIndex = focusIndex;
279
+ while (updatedIndex >= 0 && updatedIndex < this.menuItems.length) {
280
+ const child = this.menuItems[updatedIndex];
281
+ if (this.isFocusableElement(child)) {
282
+ // change the previous index to -1
283
+ if (this.focusIndex > -1
284
+ && this.menuItems.length >= this.focusIndex - 1) {
285
+ this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');
286
+ }
287
+ // update the focus index
288
+ this.focusIndex = updatedIndex;
289
+ // update the tabindex of next focusable element
290
+ child.setAttribute('tabindex', '0');
291
+ // focus the element
292
+ child.focus();
293
+ break;
294
+ }
295
+ updatedIndex += adjustment;
296
+ }
297
+ }
298
+ }
299
+ Menu.focusableElementRoles = roleForMenuItem;
300
+ __decorate([
301
+ observable
302
+ ], Menu.prototype, "items", void 0);
303
+ __decorate([
304
+ observable
305
+ ], Menu.prototype, "itemIcons", void 0);
306
+ //# sourceMappingURL=menu.foundation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.foundation.js","sourceRoot":"","sources":["../../../src/menu/menu.foundation.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Based on implementation in FAST repo: https://github.com/microsoft/fast/blob/9c6dbb66615e6d229fc0ebf8065a67f109139f26/packages/web-components/fast-foundation/src/menu/menu.ts\n */\nimport { DOM, observable } from '@microsoft/fast-element';\nimport {\n isHTMLElement,\n keyArrowDown,\n keyArrowUp,\n keyEnd,\n keyHome\n} from '@microsoft/fast-web-utilities';\nimport {\n FoundationElement,\n MenuItem,\n MenuItemColumnCount,\n MenuItemRole,\n roleForMenuItem\n} from '@microsoft/fast-foundation';\n\n/**\n * A Menu Custom HTML Element.\n * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }.\n *\n * @slot - The default slot for the menu items\n *\n * @public\n */\nexport class Menu extends FoundationElement {\n private static readonly focusableElementRoles: { [key: string]: string } = roleForMenuItem;\n\n /**\n * @internal\n */\n @observable\n public items!: HTMLSlotElement;\n\n /**\n * @internal\n */\n @observable\n public itemIcons?: Element[];\n\n private menuItems: Element[] | undefined;\n\n private expandedItem: MenuItem | null = null;\n\n /**\n * The index of the focusable element in the items array\n * defaults to -1\n */\n private focusIndex = -1;\n\n /**\n * @internal\n */\n public override connectedCallback(): void {\n super.connectedCallback();\n DOM.queueUpdate(() => {\n // wait until children have had a chance to\n // connect before setting/checking their props/attributes\n this.setItems();\n });\n\n this.addEventListener('change', this.changeHandler);\n }\n\n /**\n * @internal\n */\n public override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeItemListeners();\n this.menuItems = undefined;\n this.removeEventListener('change', this.changeHandler);\n }\n\n /**\n * @internal\n */\n public readonly isNestedMenu = (): boolean => {\n return (\n this.parentElement !== null\n && isHTMLElement(this.parentElement)\n && this.parentElement.getAttribute('role') === 'menuitem'\n );\n };\n\n /**\n * Focuses the first item in the menu.\n *\n * @public\n */\n public override focus(): void {\n this.setFocus(0, 1);\n }\n\n /**\n * Collapses any expanded menu items.\n *\n * @public\n */\n public collapseExpandedItem(): void {\n if (this.expandedItem !== null) {\n this.expandedItem.expanded = false;\n this.expandedItem = null;\n }\n }\n\n /**\n * @internal\n */\n public handleMenuKeyDown(e: KeyboardEvent): boolean {\n if (e.defaultPrevented || this.menuItems === undefined) {\n return false;\n }\n switch (e.key) {\n case keyArrowDown:\n // go forward one index\n this.setFocus(this.focusIndex + 1, 1);\n return false;\n case keyArrowUp:\n // go back one index\n this.setFocus(this.focusIndex - 1, -1);\n return false;\n case keyEnd:\n // set focus on last item\n this.setFocus(this.menuItems.length - 1, -1);\n return false;\n case keyHome:\n // set focus on first item\n this.setFocus(0, 1);\n return false;\n\n default:\n // if we are not handling the event, do not prevent default\n return true;\n }\n }\n\n /**\n * if focus is moving out of the menu, reset to a stable initial state\n * @internal\n */\n public handleFocusOut = (e: FocusEvent): void => {\n if (\n !this.contains(e.relatedTarget as Element)\n && this.menuItems !== undefined\n ) {\n this.collapseExpandedItem();\n // find our first focusable element\n const focusIndex: number = this.menuItems.findIndex(\n this.isFocusableElement\n );\n // set the current focus index's tabindex to -1\n this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');\n // set the first focusable element tabindex to 0\n this.menuItems[focusIndex]?.setAttribute('tabindex', '0');\n // set the focus index\n this.focusIndex = focusIndex;\n }\n };\n\n private readonly handleItemFocus = (e: Event): void => {\n const targetItem: HTMLElement = e.target as HTMLElement;\n\n if (\n this.menuItems !== undefined\n && targetItem !== this.menuItems[this.focusIndex]\n ) {\n this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');\n this.focusIndex = this.menuItems.indexOf(targetItem);\n targetItem.setAttribute('tabindex', '0');\n }\n };\n\n private readonly handleExpandedChanged = (e: Event): void => {\n if (\n e.defaultPrevented\n || e.target === null\n || this.menuItems === undefined\n || !this.menuItems.includes(e.target as Element)\n ) {\n return;\n }\n\n e.preventDefault();\n const changedItem: MenuItem = e.target as MenuItem;\n\n // closing an expanded item without opening another\n if (\n this.expandedItem !== null\n && changedItem === this.expandedItem\n && changedItem.expanded === false\n ) {\n this.expandedItem = null;\n return;\n }\n\n if (changedItem.expanded) {\n if (\n this.expandedItem !== null\n && this.expandedItem !== changedItem\n ) {\n this.expandedItem.expanded = false;\n }\n this.menuItems[this.focusIndex]?.setAttribute('tabindex', '-1');\n this.expandedItem = changedItem;\n this.focusIndex = this.menuItems.indexOf(changedItem);\n changedItem.setAttribute('tabindex', '0');\n }\n };\n\n private readonly removeItemListeners = (): void => {\n if (this.menuItems !== undefined) {\n this.menuItems.forEach((item: Element) => {\n item.removeEventListener(\n 'expanded-change',\n this.handleExpandedChanged\n );\n item.removeEventListener('focus', this.handleItemFocus);\n });\n }\n };\n\n private itemsChanged(): void {\n // only update children after the component is connected and\n // the setItems has run on connectedCallback\n // (menuItems is undefined until then)\n if (this.$fastController.isConnected && this.menuItems !== undefined) {\n this.setItems();\n }\n }\n\n private itemIconsChanged(oldIcons: Element[], newIcons: Element[]): void {\n // must check if set of icon elements is actually different\n if (\n this.$fastController.isConnected\n && this.menuItems !== undefined\n && (oldIcons.length !== newIcons.length\n || new Set(oldIcons.concat(newIcons)).size !== oldIcons.length)\n ) {\n this.setItems();\n }\n }\n\n private readonly setItems = (): void => {\n const newItems: Element[] = this.domChildren();\n\n this.removeItemListeners();\n this.menuItems = newItems;\n\n const menuItems = this.menuItems.filter(this.isMenuItemElement);\n\n // if our focus index is not -1 we have items\n if (menuItems.length) {\n this.focusIndex = 0;\n }\n\n function elementIndent(el: HTMLElement): MenuItemColumnCount {\n const role = el.getAttribute('role');\n const startSlot = el.querySelector('[slot=start]');\n\n if (role !== MenuItemRole.menuitem && startSlot === null) {\n return 1;\n }\n if (role === MenuItemRole.menuitem && startSlot !== null) {\n return 1;\n }\n if (role !== MenuItemRole.menuitem && startSlot !== null) {\n return 2;\n }\n return 0;\n }\n\n const indent: MenuItemColumnCount = menuItems.reduce<MenuItemColumnCount>((accum, current) => {\n const elementValue = elementIndent(current);\n\n return accum > elementValue ? accum : elementValue;\n }, 0);\n\n menuItems.forEach((item: HTMLElement, index: number) => {\n item.setAttribute('tabindex', index === 0 ? '0' : '-1');\n item.addEventListener(\n 'expanded-change',\n this.handleExpandedChanged\n );\n item.addEventListener('focus', this.handleItemFocus);\n\n if (item instanceof MenuItem || 'startColumnCount' in item) {\n (item as unknown as MenuItem).startColumnCount = indent;\n }\n });\n };\n\n /**\n * handle change from child element\n */\n private readonly changeHandler = (e: Event): void => {\n if (this.menuItems === undefined) {\n return;\n }\n const changedMenuItem: MenuItem = e.target as MenuItem;\n const changeItemIndex: number = this.menuItems.indexOf(changedMenuItem);\n\n if (changeItemIndex === -1) {\n return;\n }\n\n if (\n changedMenuItem.role === 'menuitemradio'\n && changedMenuItem.checked === true\n ) {\n for (let i = changeItemIndex - 1; i >= 0; --i) {\n const item: Element = this.menuItems[i]!;\n const role: string | null = item.getAttribute('role');\n if (role === MenuItemRole.menuitemradio) {\n (item as MenuItem).checked = false;\n }\n if (role === 'separator') {\n break;\n }\n }\n const maxIndex: number = this.menuItems.length - 1;\n for (let i = changeItemIndex + 1; i <= maxIndex; ++i) {\n const item: Element = this.menuItems[i]!;\n const role: string | null = item.getAttribute('role');\n if (role === MenuItemRole.menuitemradio) {\n (item as MenuItem).checked = false;\n }\n if (role === 'separator') {\n break;\n }\n }\n }\n };\n\n /**\n * get an array of valid DOM children\n */\n private domChildren(): Element[] {\n return Array.from(this.children).filter(\n child => !child.hasAttribute('hidden')\n );\n }\n\n /**\n * check if the item is a menu item\n */\n private readonly isMenuItemElement = (el: Element): el is HTMLElement => {\n return (\n isHTMLElement(el)\n && Object.prototype.hasOwnProperty.call(\n Menu.focusableElementRoles,\n el.getAttribute('role')!\n )\n );\n };\n\n /**\n * check if the item is focusable\n */\n private readonly isFocusableElement = (el: Element): el is HTMLElement => {\n return this.isMenuItemElement(el);\n };\n\n private setFocus(focusIndex: number, adjustment: number): void {\n if (this.menuItems === undefined) {\n return;\n }\n\n let updatedIndex = focusIndex;\n while (updatedIndex >= 0 && updatedIndex < this.menuItems.length) {\n const child: Element = this.menuItems[updatedIndex]!;\n\n if (this.isFocusableElement(child)) {\n // change the previous index to -1\n if (\n this.focusIndex > -1\n && this.menuItems.length >= this.focusIndex - 1\n ) {\n this.menuItems[this.focusIndex]?.setAttribute(\n 'tabindex',\n '-1'\n );\n }\n\n // update the focus index\n this.focusIndex = updatedIndex;\n\n // update the tabindex of next focusable element\n child.setAttribute('tabindex', '0');\n\n // focus the element\n child.focus();\n\n break;\n }\n\n updatedIndex += adjustment;\n }\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { type ViewTemplate } from '@microsoft/fast-element';
2
+ import type { FoundationElementTemplate } from '@microsoft/fast-foundation';
3
+ import type { Menu } from '.';
4
+ export declare const template: FoundationElementTemplate<ViewTemplate<Menu>>;
@@ -0,0 +1,21 @@
1
+ import { children, html, slotted } from '@microsoft/fast-element';
2
+ /* eslint-disable @typescript-eslint/indent */
3
+ // prettier-ignore
4
+ export const template = () => html `
5
+ <template
6
+ slot="${x => {
7
+ if (x.slot) {
8
+ return x.slot;
9
+ }
10
+ return x.isNestedMenu() ? 'submenu' : undefined;
11
+ }}"
12
+ role="menu"
13
+ @keydown="${(x, c) => x.handleMenuKeyDown(c.event)}"
14
+ @focusout="${(x, c) => x.handleFocusOut(c.event)}"
15
+ ${children({ property: 'itemIcons', subtree: true, attributeFilter: ['slot'], selector: ':scope > * > [slot="start"]' })}
16
+ >
17
+ <slot ${slotted('items')}></slot>
18
+ </template>
19
+ `;
20
+ /* eslint-enable @typescript-eslint/indent */
21
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/menu/template.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,IAAI,EACJ,OAAO,EAEV,MAAM,yBAAyB,CAAC;AAIjC,8CAA8C;AAC9C,kBAAkB;AAClB,MAAM,CAAC,MAAM,QAAQ,GAEjB,GAAG,EAAE,CAAC,IAAI,CAAA;;gBAEE,CAAC,CAAC,EAAE;IACR,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,CAAC,IAAI,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;;oBAEW,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAsB,CAAC;qBACtD,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAmB,CAAC;UAC5D,QAAQ,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,6BAA6B,EAAE,CAAC;;gBAEhH,OAAO,CAAC,OAAO,CAAC;;CAE/B,CAAC;AACF,6CAA6C","sourcesContent":["import {\n children,\n html,\n slotted,\n type ViewTemplate\n} from '@microsoft/fast-element';\nimport type { FoundationElementTemplate } from '@microsoft/fast-foundation';\nimport type { Menu } from '.';\n\n/* eslint-disable @typescript-eslint/indent */\n// prettier-ignore\nexport const template: FoundationElementTemplate<\nViewTemplate<Menu>\n> = () => html`\n <template\n slot=\"${x => {\n if (x.slot) {\n return x.slot;\n }\n return x.isNestedMenu() ? 'submenu' : undefined;\n }}\"\n role=\"menu\"\n @keydown=\"${(x, c) => x.handleMenuKeyDown(c.event as KeyboardEvent)}\"\n @focusout=\"${(x, c) => x.handleFocusOut(c.event as FocusEvent)}\"\n ${children({ property: 'itemIcons', subtree: true, attributeFilter: ['slot'], selector: ':scope > * > [slot=\"start\"]' })}\n >\n <slot ${slotted('items')}></slot>\n </template>\n`;\n/* eslint-enable @typescript-eslint/indent */\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ni/nimble-components",
3
- "version": "30.1.4",
3
+ "version": "30.1.5",
4
4
  "description": "Styled web components for the NI Nimble Design System",
5
5
  "scripts": {
6
6
  "build": "npm run generate-icons && npm run generate-workers && npm run build-components && npm run bundle-components && npm run generate-scss",