UNPKG

14.1 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2018 Google Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23import { __extends } from "tslib";
24import { MDCComponent } from '@material/base/component';
25import { closest } from '@material/dom/ponyfill';
26import { MDCList } from '@material/list/component';
27import { numbers as listConstants } from '@material/list/constants';
28import { MDCListFoundation } from '@material/list/foundation';
29import { MDCMenuSurface } from '@material/menu-surface/component';
30import { MDCMenuSurfaceFoundation } from '@material/menu-surface/foundation';
31import { cssClasses, strings } from './constants';
32import { MDCMenuFoundation } from './foundation';
33var MDCMenu = /** @class */ (function (_super) {
34 __extends(MDCMenu, _super);
35 function MDCMenu() {
36 return _super !== null && _super.apply(this, arguments) || this;
37 }
38 MDCMenu.attachTo = function (root) {
39 return new MDCMenu(root);
40 };
41 MDCMenu.prototype.initialize = function (menuSurfaceFactory, listFactory) {
42 if (menuSurfaceFactory === void 0) { menuSurfaceFactory = function (el) { return new MDCMenuSurface(el); }; }
43 if (listFactory === void 0) { listFactory = function (el) { return new MDCList(el); }; }
44 this.menuSurfaceFactory = menuSurfaceFactory;
45 this.listFactory = listFactory;
46 };
47 MDCMenu.prototype.initialSyncWithDOM = function () {
48 var _this = this;
49 this.menuSurface = this.menuSurfaceFactory(this.root);
50 var list = this.root.querySelector(strings.LIST_SELECTOR);
51 if (list) {
52 this.list = this.listFactory(list);
53 this.list.wrapFocus = true;
54 }
55 else {
56 this.list = null;
57 }
58 this.handleKeydown = function (evt) {
59 _this.foundation.handleKeydown(evt);
60 };
61 this.handleItemAction = function (evt) {
62 _this.foundation.handleItemAction(_this.items[evt.detail.index]);
63 };
64 this.handleMenuSurfaceOpened = function () {
65 _this.foundation.handleMenuSurfaceOpened();
66 };
67 this.menuSurface.listen(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, this.handleMenuSurfaceOpened);
68 this.listen('keydown', this.handleKeydown);
69 this.listen(MDCListFoundation.strings.ACTION_EVENT, this.handleItemAction);
70 };
71 MDCMenu.prototype.destroy = function () {
72 if (this.list) {
73 this.list.destroy();
74 }
75 this.menuSurface.destroy();
76 this.menuSurface.unlisten(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, this.handleMenuSurfaceOpened);
77 this.unlisten('keydown', this.handleKeydown);
78 this.unlisten(MDCListFoundation.strings.ACTION_EVENT, this.handleItemAction);
79 _super.prototype.destroy.call(this);
80 };
81 Object.defineProperty(MDCMenu.prototype, "open", {
82 get: function () {
83 return this.menuSurface.isOpen();
84 },
85 set: function (value) {
86 if (value) {
87 this.menuSurface.open();
88 }
89 else {
90 this.menuSurface.close();
91 }
92 },
93 enumerable: false,
94 configurable: true
95 });
96 Object.defineProperty(MDCMenu.prototype, "wrapFocus", {
97 get: function () {
98 return this.list ? this.list.wrapFocus : false;
99 },
100 set: function (value) {
101 if (this.list) {
102 this.list.wrapFocus = value;
103 }
104 },
105 enumerable: false,
106 configurable: true
107 });
108 Object.defineProperty(MDCMenu.prototype, "hasTypeahead", {
109 /**
110 * Sets whether the menu has typeahead functionality.
111 * @param value Whether typeahead is enabled.
112 */
113 set: function (value) {
114 if (this.list) {
115 this.list.hasTypeahead = value;
116 }
117 },
118 enumerable: false,
119 configurable: true
120 });
121 Object.defineProperty(MDCMenu.prototype, "typeaheadInProgress", {
122 /**
123 * @return Whether typeahead logic is currently matching some user prefix.
124 */
125 get: function () {
126 return this.list ? this.list.typeaheadInProgress : false;
127 },
128 enumerable: false,
129 configurable: true
130 });
131 /**
132 * Given the next desired character from the user, adds it to the typeahead
133 * buffer. Then, attempts to find the next option matching the buffer. Wraps
134 * around if at the end of options.
135 *
136 * @param nextChar The next character to add to the prefix buffer.
137 * @param startingIndex The index from which to start matching. Only relevant
138 * when starting a new match sequence. To start a new match sequence,
139 * clear the buffer using `clearTypeaheadBuffer`, or wait for the buffer
140 * to clear after a set interval defined in list foundation. Defaults to
141 * the currently focused index.
142 * @return The index of the matched item, or -1 if no match.
143 */
144 MDCMenu.prototype.typeaheadMatchItem = function (nextChar, startingIndex) {
145 if (this.list) {
146 return this.list.typeaheadMatchItem(nextChar, startingIndex);
147 }
148 return -1;
149 };
150 /**
151 * Layout the underlying list element in the case of any dynamic updates
152 * to its structure.
153 */
154 MDCMenu.prototype.layout = function () {
155 if (this.list) {
156 this.list.layout();
157 }
158 };
159 Object.defineProperty(MDCMenu.prototype, "items", {
160 /**
161 * Return the items within the menu. Note that this only contains the set of elements within
162 * the items container that are proper list items, and not supplemental / presentational DOM
163 * elements.
164 */
165 get: function () {
166 return this.list ? this.list.listElements : [];
167 },
168 enumerable: false,
169 configurable: true
170 });
171 Object.defineProperty(MDCMenu.prototype, "singleSelection", {
172 /**
173 * Turns on/off the underlying list's single selection mode. Used mainly
174 * by select menu.
175 *
176 * @param singleSelection Whether to enable single selection mode.
177 */
178 set: function (singleSelection) {
179 if (this.list) {
180 this.list.singleSelection = singleSelection;
181 }
182 },
183 enumerable: false,
184 configurable: true
185 });
186 Object.defineProperty(MDCMenu.prototype, "selectedIndex", {
187 /**
188 * Retrieves the selected index. Only applicable to select menus.
189 * @return The selected index, which is a number for single selection and
190 * radio lists, and an array of numbers for checkbox lists.
191 */
192 get: function () {
193 return this.list ? this.list.selectedIndex : listConstants.UNSET_INDEX;
194 },
195 /**
196 * Sets the selected index of the list. Only applicable to select menus.
197 * @param index The selected index, which is a number for single selection and
198 * radio lists, and an array of numbers for checkbox lists.
199 */
200 set: function (index) {
201 if (this.list) {
202 this.list.selectedIndex = index;
203 }
204 },
205 enumerable: false,
206 configurable: true
207 });
208 Object.defineProperty(MDCMenu.prototype, "quickOpen", {
209 set: function (quickOpen) {
210 this.menuSurface.quickOpen = quickOpen;
211 },
212 enumerable: false,
213 configurable: true
214 });
215 /**
216 * Sets default focus state where the menu should focus every time when menu
217 * is opened. Focuses the list root (`DefaultFocusState.LIST_ROOT`) element by
218 * default.
219 * @param focusState Default focus state.
220 */
221 MDCMenu.prototype.setDefaultFocusState = function (focusState) {
222 this.foundation.setDefaultFocusState(focusState);
223 };
224 /**
225 * @param corner Default anchor corner alignment of top-left menu corner.
226 */
227 MDCMenu.prototype.setAnchorCorner = function (corner) {
228 this.menuSurface.setAnchorCorner(corner);
229 };
230 MDCMenu.prototype.setAnchorMargin = function (margin) {
231 this.menuSurface.setAnchorMargin(margin);
232 };
233 /**
234 * Sets the list item as the selected row at the specified index.
235 * @param index Index of list item within menu.
236 */
237 MDCMenu.prototype.setSelectedIndex = function (index) {
238 this.foundation.setSelectedIndex(index);
239 };
240 /**
241 * Sets the enabled state to isEnabled for the menu item at the given index.
242 * @param index Index of the menu item
243 * @param isEnabled The desired enabled state of the menu item.
244 */
245 MDCMenu.prototype.setEnabled = function (index, isEnabled) {
246 this.foundation.setEnabled(index, isEnabled);
247 };
248 /**
249 * @return The item within the menu at the index specified.
250 */
251 MDCMenu.prototype.getOptionByIndex = function (index) {
252 var items = this.items;
253 if (index < items.length) {
254 return this.items[index];
255 }
256 else {
257 return null;
258 }
259 };
260 /**
261 * @param index A menu item's index.
262 * @return The primary text within the menu at the index specified.
263 */
264 MDCMenu.prototype.getPrimaryTextAtIndex = function (index) {
265 var item = this.getOptionByIndex(index);
266 if (item && this.list) {
267 return this.list.getPrimaryText(item) || '';
268 }
269 return '';
270 };
271 MDCMenu.prototype.setFixedPosition = function (isFixed) {
272 this.menuSurface.setFixedPosition(isFixed);
273 };
274 MDCMenu.prototype.setIsHoisted = function (isHoisted) {
275 this.menuSurface.setIsHoisted(isHoisted);
276 };
277 MDCMenu.prototype.setAbsolutePosition = function (x, y) {
278 this.menuSurface.setAbsolutePosition(x, y);
279 };
280 /**
281 * Sets the element that the menu-surface is anchored to.
282 */
283 MDCMenu.prototype.setAnchorElement = function (element) {
284 this.menuSurface.anchorElement = element;
285 };
286 MDCMenu.prototype.getDefaultFoundation = function () {
287 var _this = this;
288 // DO NOT INLINE this variable. For backward compatibility, foundations take a Partial<MDCFooAdapter>.
289 // To ensure we don't accidentally omit any methods, we need a separate, strongly typed adapter variable.
290 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
291 var adapter = {
292 addClassToElementAtIndex: function (index, className) {
293 var list = _this.items;
294 list[index].classList.add(className);
295 },
296 removeClassFromElementAtIndex: function (index, className) {
297 var list = _this.items;
298 list[index].classList.remove(className);
299 },
300 addAttributeToElementAtIndex: function (index, attr, value) {
301 var list = _this.items;
302 list[index].setAttribute(attr, value);
303 },
304 removeAttributeFromElementAtIndex: function (index, attr) {
305 var list = _this.items;
306 list[index].removeAttribute(attr);
307 },
308 getAttributeFromElementAtIndex: function (index, attr) {
309 var list = _this.items;
310 return list[index].getAttribute(attr);
311 },
312 elementContainsClass: function (element, className) {
313 return element.classList.contains(className);
314 },
315 closeSurface: function (skipRestoreFocus) {
316 _this.menuSurface.close(skipRestoreFocus);
317 },
318 getElementIndex: function (element) { return _this.items.indexOf(element); },
319 notifySelected: function (evtData) {
320 _this.emit(strings.SELECTED_EVENT, {
321 index: evtData.index,
322 item: _this.items[evtData.index],
323 });
324 },
325 getMenuItemCount: function () { return _this.items.length; },
326 focusItemAtIndex: function (index) {
327 _this.items[index].focus();
328 },
329 focusListRoot: function () {
330 _this.root.querySelector(strings.LIST_SELECTOR).focus();
331 },
332 isSelectableItemAtIndex: function (index) {
333 return !!closest(_this.items[index], "." + cssClasses.MENU_SELECTION_GROUP);
334 },
335 getSelectedSiblingOfItemAtIndex: function (index) {
336 var selectionGroupEl = closest(_this.items[index], "." + cssClasses.MENU_SELECTION_GROUP);
337 var selectedItemEl = selectionGroupEl.querySelector("." + cssClasses.MENU_SELECTED_LIST_ITEM);
338 return selectedItemEl ? _this.items.indexOf(selectedItemEl) : -1;
339 },
340 };
341 // tslint:enable:object-literal-sort-keys
342 return new MDCMenuFoundation(adapter);
343 };
344 return MDCMenu;
345}(MDCComponent));
346export { MDCMenu };
347//# sourceMappingURL=component.js.map
\No newline at end of file