diff --git a/src/dropdown/dropdownview.js b/src/dropdown/dropdownview.js index 87280d83..1c71cd61 100644 --- a/src/dropdown/dropdownview.js +++ b/src/dropdown/dropdownview.js @@ -8,8 +8,10 @@ */ import View from '../view'; +import IconView from '../icon/iconview'; import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler'; +import dropdownArrowIcon from '../../theme/icons/dropdown-arrow.svg'; import '../../theme/components/dropdown/dropdown.css'; @@ -108,6 +110,14 @@ export default class DropdownView extends View { */ this.keystrokes = new KeystrokeHandler(); + /** + * The arrow icon of the dropdown. + * + * @readonly + * @member {module:ui/icon/iconview~IconView} #arrowView + */ + const arrowView = this.arrowView = new IconView(); + this.setTemplate( { tag: 'div', @@ -120,10 +130,18 @@ export default class DropdownView extends View { children: [ buttonView, + arrowView, panelView ] } ); + arrowView.content = dropdownArrowIcon; + arrowView.extendTemplate( { + attributes: { + class: 'ck-dropdown__arrow' + } + } ); + buttonView.extendTemplate( { attributes: { class: [ diff --git a/src/labeledinput/labeledinputview.js b/src/labeledinput/labeledinputview.js index 80273e11..f10332d1 100644 --- a/src/labeledinput/labeledinputview.js +++ b/src/labeledinput/labeledinputview.js @@ -73,6 +73,7 @@ export default class LabeledInputView extends View { tag: 'div', attributes: { class: [ + 'ck-labeled-input', bind.if( 'isReadOnly', 'ck-disabled' ) ] }, diff --git a/src/panel/balloon/balloonpanelview.js b/src/panel/balloon/balloonpanelview.js index 34aa4c0c..57acba81 100644 --- a/src/panel/balloon/balloonpanelview.js +++ b/src/panel/balloon/balloonpanelview.js @@ -222,8 +222,10 @@ export default class BalloonPanelView extends View { const positionOptions = Object.assign( {}, { element: this.element, positions: [ + defaultPositions.southArrowNorth, defaultPositions.southArrowNorthWest, defaultPositions.southArrowNorthEast, + defaultPositions.northArrowSouth, defaultPositions.northArrowSouthWest, defaultPositions.northArrowSouthEast ], @@ -391,7 +393,7 @@ function getDomElement( object ) { * @default 30 * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset */ -BalloonPanelView.arrowHorizontalOffset = 30; +BalloonPanelView.arrowHorizontalOffset = 25; /** * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS. @@ -410,7 +412,7 @@ BalloonPanelView.arrowHorizontalOffset = 30; * @default 15 * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset */ -BalloonPanelView.arrowVerticalOffset = 15; +BalloonPanelView.arrowVerticalOffset = 10; /** * A default set of positioning functions used by the balloon panel view diff --git a/tests/dropdown/dropdownview.js b/tests/dropdown/dropdownview.js index 5e98cb67..48624516 100644 --- a/tests/dropdown/dropdownview.js +++ b/tests/dropdown/dropdownview.js @@ -8,6 +8,7 @@ import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler'; import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; import ButtonView from '../../src/button/buttonview'; +import IconView from '../../src/icon/iconview'; import DropdownPanelView from '../../src/dropdown/dropdownpanelview'; describe( 'DropdownView', () => { @@ -54,14 +55,21 @@ describe( 'DropdownView', () => { it( 'creates #element from template', () => { expect( view.element.classList.contains( 'ck-dropdown' ) ).to.be.true; - expect( view.element.firstChild ).to.equal( buttonView.element ); - expect( view.element.lastChild ).to.equal( panelView.element ); + expect( view.element.children ).to.have.length( 3 ); + expect( view.element.children[ 0 ] ).to.equal( buttonView.element ); + expect( view.element.children[ 1 ] ).to.equal( view.arrowView.element ); + expect( view.element.children[ 2 ] ).to.equal( panelView.element ); } ); it( 'sets view#buttonView class', () => { expect( view.buttonView.element.classList.contains( 'ck-dropdown__button' ) ).to.be.true; } ); + it( 'creates #arrowView icon instance', () => { + expect( view.arrowView ).to.be.instanceOf( IconView ); + expect( view.arrowView.element.classList.contains( 'ck-dropdown__arrow' ) ); + } ); + describe( 'bindings', () => { describe( 'view#isOpen to view.buttonView#execute', () => { it( 'is activated', () => { diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index ac3ffd41..f4231e11 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -37,6 +37,10 @@ describe( 'LabeledInputView', () => { } ); describe( 'template', () => { + it( 'should have the CSS class', () => { + expect( view.element.classList.contains( 'ck-labeled-input' ) ).to.be.true; + } ); + it( 'should have label view', () => { expect( view.template.children[ 0 ] ).to.equal( view.labelView ); } ); diff --git a/tests/panel/balloon/balloonpanelview.js b/tests/panel/balloon/balloonpanelview.js index 22be8232..8dde6a03 100644 --- a/tests/panel/balloon/balloonpanelview.js +++ b/tests/panel/balloon/balloonpanelview.js @@ -180,8 +180,10 @@ describe( 'BalloonPanelView', () => { element: view.element, target, positions: [ + BalloonPanelView.defaultPositions.southArrowNorth, BalloonPanelView.defaultPositions.southArrowNorthWest, BalloonPanelView.defaultPositions.southArrowNorthEast, + BalloonPanelView.defaultPositions.northArrowSouth, BalloonPanelView.defaultPositions.northArrowSouthWest, BalloonPanelView.defaultPositions.northArrowSouthEast ], @@ -212,7 +214,7 @@ describe( 'BalloonPanelView', () => { view.attachTo( { target, limiter } ); - expect( view.position ).to.equal( 'arrow_nw' ); + expect( view.position ).to.equal( 'arrow_n' ); } ); it( 'should put balloon on the `south east` side of the target element when ' + @@ -297,8 +299,8 @@ describe( 'BalloonPanelView', () => { view.attachTo( { target, limiter } ); - expect( view.top ).to.equal( 15 ); - expect( view.left ).to.equal( -80 ); + expect( view.top ).to.equal( BalloonPanelView.arrowVerticalOffset ); + expect( view.left ).to.equal( -100 ); positionedAncestor.remove(); } ); @@ -322,8 +324,8 @@ describe( 'BalloonPanelView', () => { view.attachTo( { target, limiter } ); - expect( view.top ).to.equal( 115 ); - expect( view.left ).to.equal( 20 ); + expect( view.top ).to.equal( BalloonPanelView.arrowVerticalOffset + 100 ); + expect( view.left ).to.equal( 0 ); positionedAncestor.remove(); } ); @@ -669,10 +671,12 @@ describe( 'BalloonPanelView', () => { } ); describe( 'defaultPositions', () => { - let positions, balloonRect, targetRect; + let positions, balloonRect, targetRect, arrowHOffset, arrowVOffset; beforeEach( () => { positions = BalloonPanelView.defaultPositions; + arrowHOffset = BalloonPanelView.arrowHorizontalOffset; + arrowVOffset = BalloonPanelView.arrowVerticalOffset; targetRect = { top: 100, @@ -701,7 +705,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northArrowSouth" position', () => { expect( positions.northArrowSouth( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, + top: 50 - arrowVOffset, left: 125, name: 'arrow_s' } ); @@ -709,16 +713,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northArrowSouthEast" position', () => { expect( positions.northArrowSouthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 130, + top: 50 - arrowVOffset, + left: 100 + arrowHOffset, name: 'arrow_se' } ); } ); it( 'should define the "northArrowSouthWest" position', () => { expect( positions.northArrowSouthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 120, + top: 50 - arrowVOffset, + left: 150 - arrowHOffset, name: 'arrow_sw' } ); } ); @@ -727,7 +731,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northWestArrowSouth" position', () => { expect( positions.northWestArrowSouth( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, + top: 50 - arrowVOffset, left: 75, name: 'arrow_s' } ); @@ -735,16 +739,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northWestArrowSouthWest" position', () => { expect( positions.northWestArrowSouthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 70, + top: 50 - arrowVOffset, + left: 100 - arrowHOffset, name: 'arrow_sw' } ); } ); it( 'should define the "northWestArrowSouthEast" position', () => { expect( positions.northWestArrowSouthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 80, + top: 50 - arrowVOffset, + left: 50 + arrowHOffset, name: 'arrow_se' } ); } ); @@ -753,7 +757,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northEastArrowSouth" position', () => { expect( positions.northEastArrowSouth( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, + top: 50 - arrowVOffset, left: 175, name: 'arrow_s' } ); @@ -761,16 +765,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "northEastArrowSouthEast" position', () => { expect( positions.northEastArrowSouthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 180, + top: 50 - arrowVOffset, + left: 150 + arrowHOffset, name: 'arrow_se' } ); } ); it( 'should define the "northEastArrowSouthWest" position', () => { expect( positions.northEastArrowSouthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 35, - left: 170, + top: 50 - arrowVOffset, + left: 200 - arrowHOffset, name: 'arrow_sw' } ); } ); @@ -779,7 +783,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southArrowNorth" position', () => { expect( positions.southArrowNorth( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, + top: 200 + arrowVOffset, left: 125, name: 'arrow_n' } ); @@ -787,16 +791,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southArrowNorthEast" position', () => { expect( positions.southArrowNorthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 130, + top: 200 + arrowVOffset, + left: 100 + arrowHOffset, name: 'arrow_ne' } ); } ); it( 'should define the "southArrowNorthWest" position', () => { expect( positions.southArrowNorthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 120, + top: 200 + arrowVOffset, + left: 150 - arrowHOffset, name: 'arrow_nw' } ); } ); @@ -805,7 +809,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southWestArrowNorth" position', () => { expect( positions.southWestArrowNorth( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, + top: 200 + arrowVOffset, left: 75, name: 'arrow_n' } ); @@ -813,16 +817,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southWestArrowNorthWest" position', () => { expect( positions.southWestArrowNorthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 70, + top: 200 + arrowVOffset, + left: 100 - arrowHOffset, name: 'arrow_nw' } ); } ); it( 'should define the "southWestArrowNorthEast" position', () => { expect( positions.southWestArrowNorthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 80, + top: 200 + arrowVOffset, + left: 50 + arrowHOffset, name: 'arrow_ne' } ); } ); @@ -831,7 +835,7 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southEastArrowNorth" position', () => { expect( positions.southEastArrowNorth( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, + top: 200 + arrowVOffset, left: 175, name: 'arrow_n' } ); @@ -839,16 +843,16 @@ describe( 'BalloonPanelView', () => { it( 'should define the "southEastArrowNorthEast" position', () => { expect( positions.southEastArrowNorthEast( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 180, + top: 200 + arrowVOffset, + left: 150 + arrowHOffset, name: 'arrow_ne' } ); } ); it( 'should define the "southEastArrowNorthWest" position', () => { expect( positions.southEastArrowNorthWest( targetRect, balloonRect ) ).to.deep.equal( { - top: 215, - left: 170, + top: 200 + arrowVOffset, + left: 200 - arrowHOffset, name: 'arrow_nw' } ); } ); diff --git a/theme/components/button/button.css b/theme/components/button/button.css index bbfe4fb4..6cac0be2 100644 --- a/theme/components/button/button.css +++ b/theme/components/button/button.css @@ -12,13 +12,8 @@ a.ck-button { @mixin ck-unselectable; @mixin ck-tooltip_enabled; - display: inline-block; position: relative; - @mixin ck-button-icon { - display: inline-block; - } - &.ck-button_with-text { & .ck-button__label { display: inline-block; diff --git a/theme/components/dropdown/dropdown.css b/theme/components/dropdown/dropdown.css index f8dffff8..d4ce77d8 100644 --- a/theme/components/dropdown/dropdown.css +++ b/theme/components/dropdown/dropdown.css @@ -9,11 +9,7 @@ display: inline-block; position: relative; - /* A triangle displayed to indicate this is actually a dropdown. */ - &::after { - content: ''; - width: 0; - height: 0; + & .ck-dropdown__arrow { pointer-events: none; z-index: var(--ck-z-default); diff --git a/theme/components/icon/icon.css b/theme/components/icon/icon.css index 74589289..ba421f05 100644 --- a/theme/components/icon/icon.css +++ b/theme/components/icon/icon.css @@ -4,8 +4,13 @@ */ svg.ck-icon { - font-size: 1em; + /* Multiplied by the height of the line in "px" should give SVG "viewport" dimensions */ + font-size: 0.8333333333em; + + /* Must be consistent with .ck-button__label's vertical align. Otherwise, buttons with and + without labels (but with icons) have different sizes in Chrome */ vertical-align: middle; + color: inherit; /* Inherit cursor style (#5). */ diff --git a/theme/icons/dropdown-arrow.svg b/theme/icons/dropdown-arrow.svg new file mode 100644 index 00000000..f2a77a4d --- /dev/null +++ b/theme/icons/dropdown-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file