UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

439 lines (436 loc) • 16.6 kB
/** * DevExtreme (cjs/__internal/ui/toolbar/internal/toolbar.menu.js) * Version: 25.2.7 * Build date: Tue May 05 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _devices = _interopRequireDefault(require("../../../../core/devices")); var _renderer = _interopRequireDefault(require("../../../../core/renderer")); var _child_default_template = require("../../../../core/templates/child_default_template"); var _size = require("../../../../core/utils/size"); var _window = require("../../../../core/utils/window"); var _themes = require("../../../../ui/themes"); var _widget = _interopRequireDefault(require("../../../core/widget/widget")); var _wrapper = _interopRequireDefault(require("../../../ui/button/wrapper")); var _m_popup = _interopRequireDefault(require("../../../ui/popup/m_popup")); var _toolbarMenu = _interopRequireWildcard(require("../../../ui/toolbar/internal/toolbar.menu.list")); var _toolbar = require("../../../ui/toolbar/toolbar.utils"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) { var r = new WeakMap, n = new WeakMap } return (_interopRequireWildcard = function(e, t) { if (!t && e && e.__esModule) { return e } var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) { return f } if (o = t ? n : r) { if (o.has(e)) { return o.get(e) } o.set(e, f) } for (const t in e) { "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]) } return f })(e, t) } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const DROP_DOWN_MENU_CLASS = "dx-dropdownmenu"; const DROP_DOWN_MENU_POPUP_CLASS = "dx-dropdownmenu-popup"; const DROP_DOWN_MENU_POPUP_WRAPPER_CLASS = "dx-dropdownmenu-popup-wrapper"; const DROP_DOWN_MENU_LIST_CLASS = "dx-dropdownmenu-list"; const DROP_DOWN_MENU_BUTTON_CLASS = "dx-dropdownmenu-button"; const POPUP_BOUNDARY_VERTICAL_OFFSET = 10; const POPUP_VERTICAL_OFFSET = 3; class DropDownMenu extends _widget.default { _supportedKeys() { var _this$_list; let extension = {}; const { opened: opened } = this.option(); if (!opened || !(null !== (_this$_list = this._list) && void 0 !== _this$_list && _this$_list.option("focusedElement"))) { extension = this._button._supportedKeys() } return Object.assign({}, super._supportedKeys(), extension, { tab() { var _this$_popup; null === (_this$_popup = this._popup) || void 0 === _this$_popup || _this$_popup.hide() } }) } _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { items: [], dataSource: null, itemTemplate: "item", activeStateEnabled: true, hoverStateEnabled: true, opened: false, closeOnClick: true, useInkRipple: false, container: void 0, animation: { show: { type: "fade", from: 0, to: 1 }, hide: { type: "fade", to: 0 } } }) } _defaultOptionsRules() { return super._defaultOptionsRules().concat([{ device: () => "desktop" === _devices.default.real().deviceType && !_devices.default.isSimulator(), options: { focusStateEnabled: true } }, { device: () => (0, _themes.isMaterialBased)((0, _themes.current)()), options: { useInkRipple: true, animation: { show: { type: "pop", duration: 200, from: { scale: 0 }, to: { scale: 1 } }, hide: { type: "pop", duration: 200, from: { scale: 1 }, to: { scale: 0 } } } } }]) } _init() { super._init(); this.$element().addClass("dx-dropdownmenu"); this._initItemClickAction(); this._initButtonClickAction() } _initItemClickAction() { this._itemClickAction = this._createActionByOption("onItemClick", {}) } _initButtonClickAction() { this._buttonClickAction = this._createActionByOption("onButtonClick", {}) } _initTemplates() { this._templateManager.addDefaultTemplates({ content: new _child_default_template.ChildDefaultTemplate("content") }); super._initTemplates() } _initMarkup() { this._renderButton(); super._initMarkup() } _render() { super._render(); const { opened: opened } = this.option(); this.setAria({ haspopup: true, expanded: opened }) } _renderContentImpl() { const { opened: opened } = this.option(); if (opened) { this._renderPopup() } } _clean() { var _this$_list2, _this$_popup2; this._cleanFocusState(); null === (_this$_list2 = this._list) || void 0 === _this$_list2 || _this$_list2.$element().remove(); null === (_this$_popup2 = this._popup) || void 0 === _this$_popup2 || _this$_popup2.$element().remove(); delete this._list; delete this._popup } _renderButton() { const $button = this.$element().addClass("dx-dropdownmenu-button"); const { useInkRipple: useInkRipple } = this.option(); this._button = this._createComponent($button, _wrapper.default, { icon: "overflow", template: "content", stylingMode: (0, _themes.isFluent)((0, _themes.current)()) ? "text" : "contained", useInkRipple: useInkRipple, hoverStateEnabled: false, focusStateEnabled: false, onClick: e => { var _this$_buttonClickAct; this.option("opened", !this.option("opened")); null === (_this$_buttonClickAct = this._buttonClickAction) || void 0 === _this$_buttonClickAct || _this$_buttonClickAct.call(this, e) } }) } _toggleActiveState($element, value) { this._button._toggleActiveState($element[0], value) } _toggleMenuVisibility(opened) { var _this$_popup3, _this$_popup4; const state = opened ?? !(null !== (_this$_popup3 = this._popup) && void 0 !== _this$_popup3 && _this$_popup3.option("visible")); if (opened) { this._renderPopup() } null === (_this$_popup4 = this._popup) || void 0 === _this$_popup4 || _this$_popup4.toggle(state); this.setAria("expanded", state) } _renderPopup() { if (this._$popup) { return } this._$popup = (0, _renderer.default)("<div>").appendTo(this.$element()); const { rtlEnabled: rtlEnabled, container: container, animation: animation } = this.option(); this._popup = this._createComponent(this._$popup, _m_popup.default, { onInitialized(e) { const { component: component } = e; component.$wrapper().addClass("dx-dropdownmenu-popup-wrapper").addClass("dx-dropdownmenu-popup") }, deferRendering: false, preventScrollEvents: false, _ignorePreventScrollEventsDeprecation: true, contentTemplate: contentElement => this._renderList(contentElement), _ignoreFunctionValueDeprecation: true, maxHeight: () => this._getMaxHeight(), position: { my: "top " + (rtlEnabled ? "left" : "right"), at: "bottom " + (rtlEnabled ? "left" : "right"), collision: "fit flip", offset: { v: 3 }, of: this.$element() }, animation: animation, onOptionChanged: _ref => { let { name: name, value: value } = _ref; if ("visible" === name) { this.option("opened", value) } }, container: container, autoResizeEnabled: false, height: "auto", width: "auto", hideOnOutsideClick: e => this._closeOutsideDropDownHandler(e), hideOnParentScroll: true, shading: false, dragEnabled: false, showTitle: false, fullScreen: false, ignoreChildEvents: false, _fixWrapperPosition: true }); this._popup.registerKeyHandler("space", e => { this._popupKeyHandler(e) }); this._popup.registerKeyHandler("enter", e => { this._popupKeyHandler(e) }); this._popup.registerKeyHandler("escape", e => { var _this$_popup5; if (null !== (_this$_popup5 = this._popup) && void 0 !== _this$_popup5 && _this$_popup5.$overlayContent().is((0, _renderer.default)(e.target))) { this.option("opened", false) } }) } _getMaxHeight() { var _$element$offset; const $element = this.$element(); const offsetTop = (null === (_$element$offset = $element.offset()) || void 0 === _$element$offset ? void 0 : _$element$offset.top) ?? 0; const windowHeight = (0, _size.getOuterHeight)((0, _window.getWindow)()); const maxHeight = Math.max(offsetTop, windowHeight - offsetTop - (0, _size.getOuterHeight)($element)); return Math.min(windowHeight, maxHeight - 3 - 10) } _closeOutsideDropDownHandler(e) { const isOutsideClick = !(0, _renderer.default)(e.target).closest(this.$element()).length; return isOutsideClick } _renderList(contentElement) { const $content = (0, _renderer.default)(contentElement); $content.addClass("dx-dropdownmenu-list"); const { itemTemplate: itemTemplate, onItemRendered: onItemRendered } = this.option(); this._list = this._createComponent($content, _toolbarMenu.default, { dataSource: this._getListDataSource(), pageLoadMode: "scrollBottom", indicateLoading: false, noDataText: "", itemTemplate: itemTemplate, onItemClick: e => { this._itemClickHandler(e) }, tabIndex: -1, focusStateEnabled: false, activeStateEnabled: true, onItemRendered: onItemRendered, _itemAttributes: { role: "menuitem" }, _onItemsRendered: () => { if (this.option("templatesRenderAsynchronously")) { var _this$_popup6; null === (_this$_popup6 = this._popup) || void 0 === _this$_popup6 || _this$_popup6._renderGeometry() } } }) } _popupKeyHandler(e) { if ((0, _renderer.default)(e.target).closest(`.${_toolbarMenu.TOOLBAR_MENU_ACTION_CLASS}`).length) { this._closePopup() } } _closePopup() { const { closeOnClick: closeOnClick } = this.option(); if (closeOnClick) { this.option("opened", false) } } _itemClickHandler(e) { var _this$_itemClickActio; this._closePopup(); null === (_this$_itemClickActio = this._itemClickAction) || void 0 === _this$_itemClickActio || _this$_itemClickActio.call(this, e) } _itemOptionChanged(item, property, value) { var _this$_list3; null === (_this$_list3 = this._list) || void 0 === _this$_list3 || _this$_list3._itemOptionChanged(item, property, value); (0, _toolbar.toggleItemFocusableElementTabIndex)(this._list, item) } _getListDataSource() { const { dataSource: dataSource, items: items = [] } = this.option(); return dataSource ?? items } _setListDataSource() { var _this$_list4; null === (_this$_list4 = this._list) || void 0 === _this$_list4 || _this$_list4.option("dataSource", this._getListDataSource()); delete this._deferRendering } _getKeyboardListeners() { return super._getKeyboardListeners().concat([this._list]) } _toggleVisibility(visible) { var _this$_button; super._toggleVisibility(visible); null === (_this$_button = this._button) || void 0 === _this$_button || _this$_button.option("visible", visible) } _optionChanged(args) { var _this$_list5, _this$_list6, _this$_list7, _this$_popup7; const { name: name, value: value } = args; switch (name) { case "items": case "dataSource": if (!this.option("opened")) { this._deferRendering = true } else { this._setListDataSource() } break; case "itemTemplate": null === (_this$_list5 = this._list) || void 0 === _this$_list5 || _this$_list5.option(name, this._getTemplate(value)); break; case "onItemClick": this._initItemClickAction(); break; case "onButtonClick": this._initButtonClickAction(); break; case "useInkRipple": this._invalidate(); break; case "focusStateEnabled": null === (_this$_list6 = this._list) || void 0 === _this$_list6 || _this$_list6.option(name, value); super._optionChanged(args); break; case "onItemRendered": null === (_this$_list7 = this._list) || void 0 === _this$_list7 || _this$_list7.option(name, value); break; case "opened": if (this._deferRendering) { this._setListDataSource() } this._toggleMenuVisibility(value); this._updateFocusableItemsTabIndex(); break; case "closeOnClick": break; case "container": null === (_this$_popup7 = this._popup) || void 0 === _this$_popup7 || _this$_popup7.option(name, value); break; case "disabled": if (this._list) { this._updateFocusableItemsTabIndex() } break; default: super._optionChanged(args) } } _updateFocusableItemsTabIndex() { const { items: items = [] } = this.option(); items.forEach(item => (0, _toolbar.toggleItemFocusableElementTabIndex)(this._list, item)) } } exports.default = DropDownMenu;