From 67ed829e291c1552f90b07b8b8cb86ecc4296dbd Mon Sep 17 00:00:00 2001 From: Sergey Novikov <57402891+novsstation@users.noreply.github.com> Date: Wed, 20 May 2020 09:22:58 +0300 Subject: [PATCH] Toolbar - button group support (#13119) * Toolbar - support for button group (#12838) * Toolbar now supports button group widget * Fix rtl issue * Fix icon size issue for material theme * fix toolbar icons issues * Fix less gulp task processing https://devextreme-ci.devexpress.com/DevExpress/DevExtreme/31311/126 * Try to fix gulp task * Try to determine why sass test is failed * Fix regular expression for valid translation to sass * Fix translations to sass * dirty realization of focus navigation * Fix keyboard navigation logic * Remove custom keyboard navigation logic * Fix layout in case of multiple button groups * Simple test for toolbar * Fix test in case if open menu method is broken * Toolbar - fix rtl for button group inside menu (#13098) * Fix rtl for button group in toolbar menu * Correct fix of rtl mode for button group --- build/gulp/scss/theme-replacements.js | 4 +- js/ui/toolbar/ui.toolbar.menu.js | 5 +++ styles/widgets/common/toolbar.less | 32 +++++++++++++++ styles/widgets/generic/toolbar.generic.less | 13 ++++++ styles/widgets/material/toolbar.material.less | 20 +++++++++ .../DevExpress.ui.widgets/toolbar.tests.js | 41 ++++++++++++++++--- 6 files changed, 107 insertions(+), 8 deletions(-) diff --git a/build/gulp/scss/theme-replacements.js b/build/gulp/scss/theme-replacements.js index 918fd1a4ef46..582ad2e7bda3 100644 --- a/build/gulp/scss/theme-replacements.js +++ b/build/gulp/scss/theme-replacements.js @@ -188,9 +188,9 @@ module.exports = { { regex: /@mixin dx-toolbar-item-padding\(\$MATERIAL_TOOLBAR_ITEM_SPACING\),/, replacement: '@include dx-toolbar-item-padding($MATERIAL_TOOLBAR_ITEM_SPACING);' }, { regex: /.dx-toolbar-item-padding\(\$MATERIAL_MOBILE_TOOLBAR_ITEM_SPACING\),/, replacement: '@include dx-toolbar-item-padding($MATERIAL_MOBILE_TOOLBAR_ITEM_SPACING);' }, { regex: /(-bg|-color|: 0|MATERIAL_LIST_ITEM_HEIGHT|MATERIAL_LIST_ITEM_HORIZONTAL_PADDING|4px|2 0|50%),/g, replacement: '$1;' }, - { regex: /@mixin dx-icon-sizing\(\$MATERIAL_BUTTON_ICON_SIZE\),/, replacement: '@include dx-icon-sizing($MATERIAL_BUTTON_ICON_SIZE);' }, + { regex: /(@mixin\s|\.)dx-icon-sizing\(\$MATERIAL_BUTTON_ICON_SIZE\),/g, replacement: '@include dx-icon-sizing($MATERIAL_BUTTON_ICON_SIZE);' }, { regex: /\.dx-button-onlyicon-sizing\(\),/g, replacement: '@include dx-button-onlyicon-sizing();' }, - { regex: /\.dx-icon-margin\(6px\),/, replacement: '@include dx-icon-margin(6px);' }, + { regex: /\.dx-icon-margin\(6px\),/, replacement: '@include dx-icon-margin(6px);' } ], 'popup': [ { import: '../../base/icons', type: 'index' }, diff --git a/js/ui/toolbar/ui.toolbar.menu.js b/js/ui/toolbar/ui.toolbar.menu.js index cc3a8f8f7e01..b621ec430b98 100644 --- a/js/ui/toolbar/ui.toolbar.menu.js +++ b/js/ui/toolbar/ui.toolbar.menu.js @@ -5,6 +5,7 @@ const List = require('../list/ui.list.base'); const TOOLBAR_MENU_ACTION_CLASS = 'dx-toolbar-menu-action'; const TOOLBAR_HIDDEN_BUTTON_CLASS = 'dx-toolbar-hidden-button'; +const TOOLBAR_HIDDEN_BUTTON_GROUP_CLASS = 'dx-toolbar-hidden-button-group'; const TOOLBAR_MENU_SECTION_CLASS = 'dx-toolbar-menu-section'; const TOOLBAR_MENU_LAST_SECTION_CLASS = 'dx-toolbar-menu-last-section'; @@ -69,6 +70,10 @@ const ToolbarMenu = List.inherit({ itemElement.addClass(TOOLBAR_HIDDEN_BUTTON_CLASS); } + if(item.widget === 'dxButtonGroup') { + itemElement.addClass(TOOLBAR_HIDDEN_BUTTON_GROUP_CLASS); + } + itemElement.addClass(item.cssClass); return itemElement; diff --git a/styles/widgets/common/toolbar.less b/styles/widgets/common/toolbar.less index 7336d6f494b7..24d9f60ef253 100644 --- a/styles/widgets/common/toolbar.less +++ b/styles/widgets/common/toolbar.less @@ -184,3 +184,35 @@ .dx-toolbar-item-invisible { display: none; } + +.dx-toolbar-hidden-button-group { + &.dx-state-hover { + background-color: transparent; + } + + .dx-list-item-content { + padding: 0; + + .dx-toolbar-item-auto-hide { + padding: 0; + } + } + + .dx-buttongroup { + width: 100%; + + .dx-buttongroup-wrapper { + flex-direction: column; + + .dx-buttongroup-item { + border: none; + text-align: left; + + .dx-rtl&, + .dx-rtl & { + text-align: right; + } + } + } + } +} diff --git a/styles/widgets/generic/toolbar.generic.less b/styles/widgets/generic/toolbar.generic.less index 5eb1293c72b3..6ff067a70179 100644 --- a/styles/widgets/generic/toolbar.generic.less +++ b/styles/widgets/generic/toolbar.generic.less @@ -208,3 +208,16 @@ } } } + +.dx-toolbar-hidden-button-group { + margin-top: @GENERIC_TOOLBAR_ITEM_SPACING; + margin-bottom: @GENERIC_TOOLBAR_ITEM_SPACING; + + .dx-buttongroup-wrapper { + .dx-buttongroup-item.dx-button { + .dx-button-content { + padding: @GENERIC_TOOLBAR_ITEM_SPACING 2 * @GENERIC_TOOLBAR_ITEM_SPACING; + } + } + } +} diff --git a/styles/widgets/material/toolbar.material.less b/styles/widgets/material/toolbar.material.less index 136d1218613a..9a09c4e4b9df 100644 --- a/styles/widgets/material/toolbar.material.less +++ b/styles/widgets/material/toolbar.material.less @@ -178,6 +178,11 @@ .dx-button-content { padding: 4px; + + .dx-icon { + color: @toolbar-color; + .dx-icon-sizing(@MATERIAL_BUTTON_ICON_SIZE); + } } .dx-toolbar-item-auto-hide { @@ -242,3 +247,18 @@ .dx-toolbar .dx-tab { padding: 4px; } + +.dx-toolbar-hidden-button-group { + margin-top: @MATERIAL_TOOLBAR_PADDING; + margin-bottom: @MATERIAL_TOOLBAR_PADDING; + + .dx-buttongroup-wrapper { + .dx-buttongroup-item.dx-button { + box-shadow: none; + + .dx-button-content { + padding: @MATERIAL_TOOLBAR_PADDING @MATERIAL_LIST_ITEM_HORIZONTAL_PADDING; + } + } + } +} diff --git a/testing/tests/DevExpress.ui.widgets/toolbar.tests.js b/testing/tests/DevExpress.ui.widgets/toolbar.tests.js index 2f196a28d3fa..d03f3c9b5f92 100644 --- a/testing/tests/DevExpress.ui.widgets/toolbar.tests.js +++ b/testing/tests/DevExpress.ui.widgets/toolbar.tests.js @@ -10,6 +10,8 @@ import resizeCallbacks from 'core/utils/resize_callbacks'; import themes from 'ui/themes'; import eventsEngine from 'events/core/events_engine'; +import 'ui/button_group'; + import 'common.css!'; import 'ui/button'; import 'ui/tabs'; @@ -41,7 +43,7 @@ const TOOLBAR_LABEL_CLASS = 'dx-toolbar-label'; const TOOLBAR_MENU_BUTTON_CLASS = 'dx-toolbar-menu-button'; const TOOLBAR_MENU_SECTION_CLASS = 'dx-toolbar-menu-section'; const LIST_ITEM_CLASS = 'dx-list-item'; - +const BUTTON_GROUP_CLASS = 'dx-buttongroup'; const DROP_DOWN_MENU_CLASS = 'dx-dropdownmenu'; const DROP_DOWN_MENU_POPUP_WRAPPER_CLASS = 'dx-dropdownmenu-popup-wrapper'; @@ -422,11 +424,11 @@ QUnit.module('disabled state', () => { [true, false].forEach((changeDisabledOrder) => { ['never', 'always'].forEach((locateInMenu) => { QUnit.test(`new dxToolbar({ - toolbar.disabled: ${isToolbarDisabled}, - button.disabled: ${isButtonDisabled}), - toolbar.disabled new: ${isToolbarDisabledNew}, - button.disabled new: ${isButtonDisabledNew}, - changeDisableOrder: ${changeDisabledOrder}, + toolbar.disabled: ${isToolbarDisabled}, + button.disabled: ${isButtonDisabled}), + toolbar.disabled new: ${isToolbarDisabledNew}, + button.disabled new: ${isButtonDisabledNew}, + changeDisableOrder: ${changeDisabledOrder}, locateInMenu: ${locateInMenu}`, function(assert) { const itemClickHandler = sinon.spy(); @@ -1138,6 +1140,33 @@ QUnit.module('adaptivity', { assert.equal($section.find('.dx-list-item').text(), 'test text', 'button text was rendered'); }); + QUnit.test('buttonGroup.locateInMenu: auto -> toolbar.setWidth(100) -> toolbar.openMenu', function(assert) { + const toolbar = $('#widget').dxToolbar({ + items: [ + { locateInMenu: 'never', template: function() { return $('
').width(100); } }, + { locateInMenu: 'auto', widget: 'dxButtonGroup', options: { width: 100, items: [ { text: 'text1' } ] } } + ] + }).dxToolbar('instance'); + + const getButtonGroupToolbarItem = () => toolbar.$element().find(`.${BUTTON_GROUP_CLASS}`).closest(`.${TOOLBAR_ITEM_CLASS}`); + + let $buttonGroupToolbarItem = getButtonGroupToolbarItem(); + assert.equal($buttonGroupToolbarItem.hasClass(TOOLBAR_ITEM_INVISIBLE_CLASS), false, 'buttonGroup is visible in toolbar'); + + toolbar.option('width', 100); + $buttonGroupToolbarItem = getButtonGroupToolbarItem(); + assert.equal($buttonGroupToolbarItem.hasClass(TOOLBAR_ITEM_INVISIBLE_CLASS), true, 'buttonGroup is hidden in toolbar'); + + const done = assert.async(); + const $dropDown = toolbar.$element().find('.' + DROP_DOWN_MENU_CLASS); + const dropDown = $dropDown.dxDropDownMenu('instance'); + dropDown.option('onItemRendered', function(args) { + assert.equal($(args.itemElement).find(`.${BUTTON_GROUP_CLASS}`).length, 1, 'button group was rendered in menu'); + done(); + }); + dropDown.open(); + }); + QUnit.test('overflow item should rendered with correct template in menu and in toolbar', function(assert) { assert.expect(4);