@ckeditor/ckeditor5-ui 35.0.1 → 35.2.0

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.
Files changed (88) hide show
  1. package/lang/contexts.json +3 -1
  2. package/lang/translations/ar.po +8 -0
  3. package/lang/translations/ast.po +8 -0
  4. package/lang/translations/az.po +8 -0
  5. package/lang/translations/bg.po +8 -0
  6. package/lang/translations/bn.po +8 -0
  7. package/lang/translations/ca.po +8 -0
  8. package/lang/translations/cs.po +8 -0
  9. package/lang/translations/da.po +8 -0
  10. package/lang/translations/de-ch.po +8 -0
  11. package/lang/translations/de.po +8 -0
  12. package/lang/translations/el.po +8 -0
  13. package/lang/translations/en-au.po +9 -1
  14. package/lang/translations/en-gb.po +8 -0
  15. package/lang/translations/en.po +8 -0
  16. package/lang/translations/eo.po +8 -0
  17. package/lang/translations/es.po +8 -0
  18. package/lang/translations/et.po +8 -0
  19. package/lang/translations/eu.po +8 -0
  20. package/lang/translations/fa.po +8 -0
  21. package/lang/translations/fi.po +8 -0
  22. package/lang/translations/fr.po +8 -0
  23. package/lang/translations/gl.po +9 -1
  24. package/lang/translations/he.po +8 -0
  25. package/lang/translations/hi.po +8 -0
  26. package/lang/translations/hr.po +8 -0
  27. package/lang/translations/hu.po +8 -0
  28. package/lang/translations/id.po +8 -0
  29. package/lang/translations/it.po +8 -0
  30. package/lang/translations/ja.po +8 -0
  31. package/lang/translations/km.po +8 -0
  32. package/lang/translations/kn.po +8 -0
  33. package/lang/translations/ko.po +11 -3
  34. package/lang/translations/ku.po +8 -0
  35. package/lang/translations/lt.po +8 -0
  36. package/lang/translations/lv.po +8 -0
  37. package/lang/translations/ms.po +8 -0
  38. package/lang/translations/nb.po +8 -0
  39. package/lang/translations/ne.po +8 -0
  40. package/lang/translations/nl.po +8 -0
  41. package/lang/translations/no.po +8 -0
  42. package/lang/translations/pl.po +8 -0
  43. package/lang/translations/pt-br.po +8 -0
  44. package/lang/translations/pt.po +8 -0
  45. package/lang/translations/ro.po +8 -0
  46. package/lang/translations/ru.po +8 -0
  47. package/lang/translations/sk.po +8 -0
  48. package/lang/translations/sl.po +8 -0
  49. package/lang/translations/sq.po +8 -0
  50. package/lang/translations/sr-latn.po +9 -1
  51. package/lang/translations/sr.po +9 -1
  52. package/lang/translations/sv.po +8 -0
  53. package/lang/translations/th.po +8 -0
  54. package/lang/translations/tk.po +8 -0
  55. package/lang/translations/tr.po +8 -0
  56. package/lang/translations/tt.po +113 -0
  57. package/lang/translations/ug.po +8 -0
  58. package/lang/translations/uk.po +8 -0
  59. package/lang/translations/ur.po +8 -0
  60. package/lang/translations/uz.po +8 -0
  61. package/lang/translations/vi.po +8 -0
  62. package/lang/translations/zh-cn.po +8 -0
  63. package/lang/translations/zh.po +8 -0
  64. package/package.json +21 -19
  65. package/src/bindings/addkeyboardhandlingforgrid.js +76 -0
  66. package/src/button/button.jsdoc +2 -2
  67. package/src/button/buttonview.js +5 -29
  68. package/src/colorgrid/colorgridview.js +19 -25
  69. package/src/dropdown/button/dropdownbuttonview.js +2 -1
  70. package/src/dropdown/button/splitbuttonview.js +4 -1
  71. package/src/dropdown/dropdownview.js +16 -9
  72. package/src/dropdown/utils.js +58 -4
  73. package/src/icon/iconview.js +3 -1
  74. package/src/index.js +2 -2
  75. package/src/list/listitemview.js +14 -1
  76. package/src/panel/balloon/balloonpanelview.js +128 -74
  77. package/src/toolbar/balloon/balloontoolbar.js +17 -5
  78. package/src/toolbar/block/blocktoolbar.js +36 -0
  79. package/src/toolbar/toolbarview.js +132 -21
  80. package/src/tooltipmanager.js +430 -0
  81. package/theme/components/button/button.css +0 -11
  82. package/theme/components/dropdown/dropdown.css +0 -12
  83. package/theme/components/dropdown/splitbutton.css +0 -7
  84. package/theme/components/responsive-form/responsiveform.css +28 -16
  85. package/theme/components/tooltip/tooltip.css +3 -26
  86. package/src/toolbar/enabletoolbarkeyboardfocus.js +0 -64
  87. package/src/tooltip/tooltipview.js +0 -107
  88. package/theme/components/tooltip/mixins/_tooltip.css +0 -54
@@ -49,7 +49,8 @@ export default class DropdownButtonView extends ButtonView {
49
49
 
50
50
  this.extendTemplate( {
51
51
  attributes: {
52
- 'aria-haspopup': true
52
+ 'aria-haspopup': true,
53
+ 'aria-expanded': this.bindTemplate.to( 'isOn', value => String( value ) )
53
54
  }
54
55
  } );
55
56
 
@@ -222,7 +222,10 @@ export default class SplitButtonView extends View {
222
222
 
223
223
  arrowView.extendTemplate( {
224
224
  attributes: {
225
- class: 'ck-splitbutton__arrow',
225
+ class: [
226
+ 'ck-splitbutton__arrow'
227
+ ],
228
+ 'data-cke-tooltip-disabled': bind.to( 'isOn' ),
226
229
  'aria-haspopup': true,
227
230
  'aria-expanded': bind.to( 'isOn', value => String( value ) )
228
231
  }
@@ -9,6 +9,7 @@
9
9
 
10
10
  import View from '../view';
11
11
  import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
12
+ import { FocusTracker } from '@ckeditor/ckeditor5-utils';
12
13
 
13
14
  import '../../theme/components/dropdown/dropdown.css';
14
15
 
@@ -170,6 +171,14 @@ export default class DropdownView extends View {
170
171
  */
171
172
  this.keystrokes = new KeystrokeHandler();
172
173
 
174
+ /**
175
+ * Tracks information about the DOM focus in the dropdown.
176
+ *
177
+ * @readonly
178
+ * @member {module:utils/focustracker~FocusTracker}
179
+ */
180
+ this.focusTracker = new FocusTracker();
181
+
173
182
  this.setTemplate( {
174
183
  tag: 'div',
175
184
 
@@ -194,7 +203,8 @@ export default class DropdownView extends View {
194
203
  attributes: {
195
204
  class: [
196
205
  'ck-dropdown__button'
197
- ]
206
+ ],
207
+ 'data-cke-tooltip-disabled': bind.to( 'isOpen' )
198
208
  }
199
209
  } );
200
210
 
@@ -240,6 +250,9 @@ export default class DropdownView extends View {
240
250
  render() {
241
251
  super.render();
242
252
 
253
+ this.focusTracker.add( this.buttonView.element );
254
+ this.focusTracker.add( this.panelView.element );
255
+
243
256
  // Toggle the dropdown when its button has been clicked.
244
257
  this.listenTo( this.buttonView, 'open', () => {
245
258
  this.isOpen = !this.isOpen;
@@ -250,11 +263,8 @@ export default class DropdownView extends View {
250
263
 
251
264
  // Let the dropdown control the position of the panel. The position must
252
265
  // be updated every time the dropdown is open.
253
- this.on( 'change:isOpen', () => {
254
- if ( !this.isOpen ) {
255
- // If the dropdown was closed, move the focus back to the button (#12125).
256
- this.focus();
257
-
266
+ this.on( 'change:isOpen', ( evt, name, isOpen ) => {
267
+ if ( !isOpen ) {
258
268
  return;
259
269
  }
260
270
 
@@ -270,9 +280,6 @@ export default class DropdownView extends View {
270
280
  } else {
271
281
  this.panelView.position = this.panelPosition;
272
282
  }
273
-
274
- // Focus the first item in the dropdown when the dropdown opened
275
- this.panelView.focus();
276
283
  } );
277
284
 
278
285
  // Listen for keystrokes coming from within #element.
@@ -19,7 +19,7 @@ import SwitchButtonView from '../button/switchbuttonview';
19
19
 
20
20
  import clickOutsideHandler from '../bindings/clickoutsidehandler';
21
21
 
22
- import { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
22
+ import { global, priorities, logWarning } from '@ckeditor/ckeditor5-utils';
23
23
 
24
24
  import '../../theme/components/dropdown/toolbardropdown.css';
25
25
  import '../../theme/components/dropdown/listdropdown.css';
@@ -288,22 +288,28 @@ export function focusChildOnDropdownOpen( dropdownView, childSelectorCallback )
288
288
  */
289
289
  logWarning( 'ui-dropdown-focus-child-on-open-child-missing-focus', { view: childToFocus } );
290
290
  }
291
- }, { priority: 'low' } );
291
+
292
+ // * Let the panel show up first (do not focus an invisible element).
293
+ // * Execute after focusDropdownPanelOnOpen(). See focusDropdownPanelOnOpen() to learn more.
294
+ }, { priority: priorities.low - 10 } );
292
295
  }
293
296
 
294
297
  // Add a set of default behaviors to dropdown view.
295
298
  //
296
299
  // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
297
300
  function addDefaultBehavior( dropdownView ) {
298
- closeDropdownOnBlur( dropdownView );
301
+ closeDropdownOnClickOutside( dropdownView );
299
302
  closeDropdownOnExecute( dropdownView );
303
+ closeDropdownOnBlur( dropdownView );
300
304
  focusDropdownContentsOnArrows( dropdownView );
305
+ focusDropdownButtonOnClose( dropdownView );
306
+ focusDropdownPanelOnOpen( dropdownView );
301
307
  }
302
308
 
303
309
  // Adds a behavior to a dropdownView that closes opened dropdown when user clicks outside the dropdown.
304
310
  //
305
311
  // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
306
- function closeDropdownOnBlur( dropdownView ) {
312
+ function closeDropdownOnClickOutside( dropdownView ) {
307
313
  dropdownView.on( 'render', () => {
308
314
  clickOutsideHandler( {
309
315
  emitter: dropdownView,
@@ -331,6 +337,17 @@ function closeDropdownOnExecute( dropdownView ) {
331
337
  } );
332
338
  }
333
339
 
340
+ // Adds a behavior to a dropdown view that closes opened dropdown when it loses focus.
341
+ //
342
+ // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
343
+ function closeDropdownOnBlur( dropdownView ) {
344
+ dropdownView.focusTracker.on( 'change:isFocused', ( evt, name, isFocused ) => {
345
+ if ( dropdownView.isOpen && !isFocused ) {
346
+ dropdownView.isOpen = false;
347
+ }
348
+ } );
349
+ }
350
+
334
351
  // Adds a behavior to a dropdownView that focuses the dropdown's panel view contents on keystrokes.
335
352
  //
336
353
  // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
@@ -352,6 +369,43 @@ function focusDropdownContentsOnArrows( dropdownView ) {
352
369
  } );
353
370
  }
354
371
 
372
+ // Adds a behavior that focuses the #buttonView when the dropdown was closed but focus was within the #panelView element.
373
+ // This makes sure the focus is never lost.
374
+ //
375
+ // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
376
+ function focusDropdownButtonOnClose( dropdownView ) {
377
+ dropdownView.on( 'change:isOpen', ( evt, name, isOpen ) => {
378
+ if ( isOpen ) {
379
+ return;
380
+ }
381
+
382
+ // If the dropdown was closed, move the focus back to the button (#12125).
383
+ // Don't touch the focus, if it moved somewhere else (e.g. moved to the editing root on #execute) (#12178).
384
+ // Note: Don't use the state of the DropdownView#focusTracker here. It fires #blur with the timeout.
385
+ if ( dropdownView.panelView.element.contains( global.document.activeElement ) ) {
386
+ dropdownView.buttonView.focus();
387
+ }
388
+ } );
389
+ }
390
+
391
+ // Adds a behavior that focuses the #panelView when dropdown gets open (accessibility).
392
+ //
393
+ // @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
394
+ function focusDropdownPanelOnOpen( dropdownView ) {
395
+ dropdownView.on( 'change:isOpen', ( evt, name, isOpen ) => {
396
+ if ( !isOpen ) {
397
+ return;
398
+ }
399
+
400
+ // Focus the first item in the dropdown when the dropdown opened.
401
+ dropdownView.panelView.focus();
402
+
403
+ // * Let the panel show up first (do not focus an invisible element).
404
+ // * Also, execute before focusChildOnDropdownOpen() to make sure this helper does not break the
405
+ // focus of a specific child by kicking in too late and resetting the focus in the panel.
406
+ }, { priority: 'low' } );
407
+ }
408
+
355
409
  /**
356
410
  * A definition of the list item used by the {@link module:ui/dropdown/utils~addListToDropdown}
357
411
  * utility.
@@ -103,7 +103,9 @@ export default class IconView extends View {
103
103
  this.viewBox = viewBox;
104
104
  }
105
105
 
106
- this.element.innerHTML = '';
106
+ while ( this.element.firstChild ) {
107
+ this.element.removeChild( this.element.firstChild );
108
+ }
107
109
 
108
110
  while ( svg.childNodes.length > 0 ) {
109
111
  this.element.appendChild( svg.childNodes[ 0 ] );
package/src/index.js CHANGED
@@ -10,6 +10,7 @@
10
10
  export { default as clickOutsideHandler } from './bindings/clickoutsidehandler';
11
11
  export { default as injectCssTransitionDisabler } from './bindings/injectcsstransitiondisabler';
12
12
  export { default as submitHandler } from './bindings/submithandler';
13
+ export { default as addKeyboardHandlingForGrid } from './bindings/addkeyboardhandlingforgrid';
13
14
 
14
15
  export { default as BodyCollection } from './editorui/bodycollection';
15
16
 
@@ -52,12 +53,11 @@ export { default as BalloonPanelView } from './panel/balloon/balloonpanelview';
52
53
  export { default as ContextualBalloon } from './panel/balloon/contextualballoon';
53
54
  export { default as StickyPanelView } from './panel/sticky/stickypanelview';
54
55
 
55
- export { default as TooltipView } from './tooltip/tooltipview';
56
+ export { default as TooltipManager } from './tooltipmanager';
56
57
  export { default as Template } from './template';
57
58
 
58
59
  export { default as ToolbarView } from './toolbar/toolbarview';
59
60
  export { default as ToolbarSeparatorView } from './toolbar/toolbarseparatorview';
60
- export { default as enableToolbarKeyboardFocus } from './toolbar/enabletoolbarkeyboardfocus';
61
61
  export { default as normalizeToolbarConfig } from './toolbar/normalizetoolbarconfig';
62
62
  export { default as BalloonToolbar } from './toolbar/balloon/balloontoolbar';
63
63
  export { default as BlockToolbar } from './toolbar/block/blocktoolbar';
@@ -21,6 +21,18 @@ export default class ListItemView extends View {
21
21
  constructor( locale ) {
22
22
  super( locale );
23
23
 
24
+ const bind = this.bindTemplate;
25
+
26
+ /**
27
+ * Controls whether the item view is visible. Visible by default, list items are hidden
28
+ * using a CSS class.
29
+ *
30
+ * @observable
31
+ * @default true
32
+ * @member {Boolean} #isVisible
33
+ */
34
+ this.set( 'isVisible', true );
35
+
24
36
  /**
25
37
  * Collection of the child views inside of the list item {@link #element}.
26
38
  *
@@ -35,7 +47,8 @@ export default class ListItemView extends View {
35
47
  attributes: {
36
48
  class: [
37
49
  'ck',
38
- 'ck-list__item'
50
+ 'ck-list__item',
51
+ bind.if( 'isVisible', 'ck-hidden', value => !value )
39
52
  ]
40
53
  },
41
54
 
@@ -392,60 +392,74 @@ function getDomElement( object ) {
392
392
  }
393
393
 
394
394
  /**
395
- * A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.
396
- *
397
- * +-----|---------...
398
- * | |
399
- * | |
400
- * | |
401
- * | |
402
- * +--+ | +------...
403
- * \ | /
404
- * \|/
405
- * >|-----|<---------------- horizontal offset
395
+ * A side offset of the arrow tip from the edge of the balloon. Controlled by CSS.
396
+ *
397
+ * ┌───────────────────────┐
398
+ * │ │
399
+ * │ Balloon │
400
+ * │ Content │
401
+ * │ │
402
+ * └──+ +───────────────┘
403
+ * | \ /
404
+ * | \/
405
+ * >┼─────┼< ─────────────────────── side offset
406
+ *
406
407
  *
407
408
  * @default 25
408
- * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset
409
+ * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowSideOffset
409
410
  */
410
- BalloonPanelView.arrowHorizontalOffset = 25;
411
+ BalloonPanelView.arrowSideOffset = 25;
411
412
 
412
413
  /**
413
- * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.
414
- *
415
- * +-------------...
416
- * |
417
- * |
418
- * | /-- vertical offset
419
- * | V
420
- * +--+ +-----... ---------
421
- * \ / |
422
- * \/ |
423
- * -------------------------------
424
- * ^
414
+ * A height offset of the arrow from the edge of the balloon. Controlled by CSS.
415
+ *
416
+ * ┌───────────────────────┐
417
+ * │ │
418
+ * │ Balloon │
419
+ * │ Content │ ╱-- arrow height offset
420
+ * │ │ V
421
+ * └──+ +───────────────┘ --- ─┼───────
422
+ * \ /
423
+ * \/
424
+ * ────────────────────────────────┼───────
425
+ * ^
426
+ *
427
+ *
428
+ * >┼────┼< arrow height offset
429
+ * │ │
430
+ * │ ┌────────────────────────┐
431
+ * │ │ │
432
+ * │ ╱ │
433
+ * │ ╱ Balloon │
434
+ * │ ╲ Content │
435
+ * │ ╲ │
436
+ * │ │ │
437
+ * │ └────────────────────────┘
438
+ *
425
439
  *
426
440
  * @default 10
427
- * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset
441
+ * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHeightOffset
428
442
  */
429
- BalloonPanelView.arrowVerticalOffset = 10;
443
+ BalloonPanelView.arrowHeightOffset = 10;
430
444
 
431
445
  /**
432
446
  * A vertical offset of the balloon panel from the edge of the viewport if sticky.
433
447
  * It helps in accessing toolbar buttons underneath the balloon panel.
434
448
  *
435
- * +---------------------------------------------------+
436
- * | Target |
437
- * | |
438
- * | /-- vertical offset |
439
- * +-----------------------------V-------------------------+
440
- * | Toolbar +-------------+ |
441
- * +--------------------| Balloon |--------------------+
442
- * | | +-------------+ | |
443
- * | | | |
444
- * | | | |
445
- * | | | |
446
- * | +---------------------------------------------------+ |
447
- * | Viewport |
448
- * +-------------------------------------------------------+
449
+ * ┌───────────────────────────────────────────────────┐
450
+ * Target
451
+ *
452
+ * /── vertical offset
453
+ * ┌─────────────────────────────V─────────────────────────┐
454
+ * Toolbar ┌─────────────┐
455
+ * ├────────────────────│ Balloon │────────────────────┤
456
+ * └─────────────┘
457
+ *
458
+ *
459
+ *
460
+ * └───────────────────────────────────────────────────┘
461
+ * Viewport
462
+ * └───────────────────────────────────────────────────────┘
449
463
  *
450
464
  * @default 20
451
465
  * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.stickyVerticalOffset
@@ -697,7 +711,7 @@ BalloonPanelView._getOptimalPosition = getOptimalPosition;
697
711
  * +-----------------+
698
712
  * | Balloon |
699
713
  * +-----------------+
700
- * * `southEastArrowNorthMiddleWest`
714
+ * * `southEastArrowNorthMiddleWest`
701
715
  *
702
716
  * [ Target ]
703
717
  * ^
@@ -729,6 +743,28 @@ BalloonPanelView._getOptimalPosition = getOptimalPosition;
729
743
  * | Balloon |
730
744
  * +-----------------+
731
745
  *
746
+ *
747
+ *
748
+ * **West**
749
+ *
750
+ * * `westArrowEast`
751
+ *
752
+ * +-----------------+
753
+ * | Balloon |>[ Target ]
754
+ * +-----------------+
755
+ *
756
+ * **East**
757
+ *
758
+ * * `eastArrowWest`
759
+ *
760
+ * +-----------------+
761
+ * [ Target ]<| Balloon |
762
+ * +-----------------+
763
+ *
764
+ *
765
+ *
766
+ * **Sticky**
767
+ *
732
768
  * * `viewportStickyNorth`
733
769
  *
734
770
  * +---------------------------+
@@ -768,11 +804,11 @@ BalloonPanelView.defaultPositions = generatePositions();
768
804
  * @protected
769
805
  * @param {Object} [options] Options to generate positions. If not specified, this helper will simply return
770
806
  * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
771
- * @param {Number} [options.horizontalOffset] A custom horizontal offset (in pixels) of each position. If
772
- * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset the default value}
807
+ * @param {Number} [options.sideOffset] A custom side offset (in pixels) of each position. If
808
+ * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowSideOffset the default value}
773
809
  * will be used.
774
- * @param {Number} [options.verticalOffset] A custom vertical offset (in pixels) of each position. If
775
- * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset the default value}
810
+ * @param {Number} [options.heightOffset] A custom height offset (in pixels) of each position. If
811
+ * not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHeightOffset the default value}
776
812
  * will be used.
777
813
  * @param {Number} [options.stickyVerticalOffset] A custom offset (in pixels) of the `viewportStickyNorth` positioning function.
778
814
  * If not specified, {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.stickyVerticalOffset the default value}
@@ -783,8 +819,8 @@ BalloonPanelView.defaultPositions = generatePositions();
783
819
  * @returns {Object.<String,module:utils/dom/position~PositioningFunction>}
784
820
  */
785
821
  export function generatePositions( {
786
- horizontalOffset = BalloonPanelView.arrowHorizontalOffset,
787
- verticalOffset = BalloonPanelView.arrowVerticalOffset,
822
+ sideOffset = BalloonPanelView.arrowSideOffset,
823
+ heightOffset = BalloonPanelView.arrowHeightOffset,
788
824
  stickyVerticalOffset = BalloonPanelView.stickyVerticalOffset,
789
825
  config
790
826
  } = {} ) {
@@ -793,14 +829,14 @@ export function generatePositions( {
793
829
 
794
830
  northWestArrowSouthWest: ( targetRect, balloonRect ) => ( {
795
831
  top: getNorthTop( targetRect, balloonRect ),
796
- left: targetRect.left - horizontalOffset,
832
+ left: targetRect.left - sideOffset,
797
833
  name: 'arrow_sw',
798
834
  ...( config && { config } )
799
835
  } ),
800
836
 
801
837
  northWestArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
802
838
  top: getNorthTop( targetRect, balloonRect ),
803
- left: targetRect.left - ( balloonRect.width * .25 ) - horizontalOffset,
839
+ left: targetRect.left - ( balloonRect.width * .25 ) - sideOffset,
804
840
  name: 'arrow_smw',
805
841
  ...( config && { config } )
806
842
  } ),
@@ -814,14 +850,14 @@ export function generatePositions( {
814
850
 
815
851
  northWestArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
816
852
  top: getNorthTop( targetRect, balloonRect ),
817
- left: targetRect.left - ( balloonRect.width * .75 ) + horizontalOffset,
853
+ left: targetRect.left - ( balloonRect.width * .75 ) + sideOffset,
818
854
  name: 'arrow_sme',
819
855
  ...( config && { config } )
820
856
  } ),
821
857
 
822
858
  northWestArrowSouthEast: ( targetRect, balloonRect ) => ( {
823
859
  top: getNorthTop( targetRect, balloonRect ),
824
- left: targetRect.left - balloonRect.width + horizontalOffset,
860
+ left: targetRect.left - balloonRect.width + sideOffset,
825
861
  name: 'arrow_se',
826
862
  ...( config && { config } )
827
863
  } ),
@@ -830,14 +866,14 @@ export function generatePositions( {
830
866
 
831
867
  northArrowSouthWest: ( targetRect, balloonRect ) => ( {
832
868
  top: getNorthTop( targetRect, balloonRect ),
833
- left: targetRect.left + targetRect.width / 2 - horizontalOffset,
869
+ left: targetRect.left + targetRect.width / 2 - sideOffset,
834
870
  name: 'arrow_sw',
835
871
  ...( config && { config } )
836
872
  } ),
837
873
 
838
874
  northArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
839
875
  top: getNorthTop( targetRect, balloonRect ),
840
- left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - horizontalOffset,
876
+ left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - sideOffset,
841
877
  name: 'arrow_smw',
842
878
  ...( config && { config } )
843
879
  } ),
@@ -851,14 +887,14 @@ export function generatePositions( {
851
887
 
852
888
  northArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
853
889
  top: getNorthTop( targetRect, balloonRect ),
854
- left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + horizontalOffset,
890
+ left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + sideOffset,
855
891
  name: 'arrow_sme',
856
892
  ...( config && { config } )
857
893
  } ),
858
894
 
859
895
  northArrowSouthEast: ( targetRect, balloonRect ) => ( {
860
896
  top: getNorthTop( targetRect, balloonRect ),
861
- left: targetRect.left + targetRect.width / 2 - balloonRect.width + horizontalOffset,
897
+ left: targetRect.left + targetRect.width / 2 - balloonRect.width + sideOffset,
862
898
  name: 'arrow_se',
863
899
  ...( config && { config } )
864
900
  } ),
@@ -867,14 +903,14 @@ export function generatePositions( {
867
903
 
868
904
  northEastArrowSouthWest: ( targetRect, balloonRect ) => ( {
869
905
  top: getNorthTop( targetRect, balloonRect ),
870
- left: targetRect.right - horizontalOffset,
906
+ left: targetRect.right - sideOffset,
871
907
  name: 'arrow_sw',
872
908
  ...( config && { config } )
873
909
  } ),
874
910
 
875
911
  northEastArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {
876
912
  top: getNorthTop( targetRect, balloonRect ),
877
- left: targetRect.right - ( balloonRect.width * .25 ) - horizontalOffset,
913
+ left: targetRect.right - ( balloonRect.width * .25 ) - sideOffset,
878
914
  name: 'arrow_smw',
879
915
  ...( config && { config } )
880
916
  } ),
@@ -888,14 +924,14 @@ export function generatePositions( {
888
924
 
889
925
  northEastArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {
890
926
  top: getNorthTop( targetRect, balloonRect ),
891
- left: targetRect.right - ( balloonRect.width * .75 ) + horizontalOffset,
927
+ left: targetRect.right - ( balloonRect.width * .75 ) + sideOffset,
892
928
  name: 'arrow_sme',
893
929
  ...( config && { config } )
894
930
  } ),
895
931
 
896
932
  northEastArrowSouthEast: ( targetRect, balloonRect ) => ( {
897
933
  top: getNorthTop( targetRect, balloonRect ),
898
- left: targetRect.right - balloonRect.width + horizontalOffset,
934
+ left: targetRect.right - balloonRect.width + sideOffset,
899
935
  name: 'arrow_se',
900
936
  ...( config && { config } )
901
937
  } ),
@@ -904,14 +940,14 @@ export function generatePositions( {
904
940
 
905
941
  southWestArrowNorthWest: ( targetRect, balloonRect ) => ( {
906
942
  top: getSouthTop( targetRect, balloonRect ),
907
- left: targetRect.left - horizontalOffset,
943
+ left: targetRect.left - sideOffset,
908
944
  name: 'arrow_nw',
909
945
  ...( config && { config } )
910
946
  } ),
911
947
 
912
948
  southWestArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
913
949
  top: getSouthTop( targetRect, balloonRect ),
914
- left: targetRect.left - ( balloonRect.width * .25 ) - horizontalOffset,
950
+ left: targetRect.left - ( balloonRect.width * .25 ) - sideOffset,
915
951
  name: 'arrow_nmw',
916
952
  ...( config && { config } )
917
953
  } ),
@@ -925,14 +961,14 @@ export function generatePositions( {
925
961
 
926
962
  southWestArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
927
963
  top: getSouthTop( targetRect, balloonRect ),
928
- left: targetRect.left - ( balloonRect.width * .75 ) + horizontalOffset,
964
+ left: targetRect.left - ( balloonRect.width * .75 ) + sideOffset,
929
965
  name: 'arrow_nme',
930
966
  ...( config && { config } )
931
967
  } ),
932
968
 
933
969
  southWestArrowNorthEast: ( targetRect, balloonRect ) => ( {
934
970
  top: getSouthTop( targetRect, balloonRect ),
935
- left: targetRect.left - balloonRect.width + horizontalOffset,
971
+ left: targetRect.left - balloonRect.width + sideOffset,
936
972
  name: 'arrow_ne',
937
973
  ...( config && { config } )
938
974
  } ),
@@ -941,14 +977,14 @@ export function generatePositions( {
941
977
 
942
978
  southArrowNorthWest: ( targetRect, balloonRect ) => ( {
943
979
  top: getSouthTop( targetRect, balloonRect ),
944
- left: targetRect.left + targetRect.width / 2 - horizontalOffset,
980
+ left: targetRect.left + targetRect.width / 2 - sideOffset,
945
981
  name: 'arrow_nw',
946
982
  ...( config && { config } )
947
983
  } ),
948
984
 
949
985
  southArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
950
986
  top: getSouthTop( targetRect, balloonRect ),
951
- left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - horizontalOffset,
987
+ left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - sideOffset,
952
988
  name: 'arrow_nmw',
953
989
  ...( config && { config } )
954
990
  } ),
@@ -962,14 +998,14 @@ export function generatePositions( {
962
998
 
963
999
  southArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
964
1000
  top: getSouthTop( targetRect, balloonRect ),
965
- left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + horizontalOffset,
1001
+ left: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + sideOffset,
966
1002
  name: 'arrow_nme',
967
1003
  ...( config && { config } )
968
1004
  } ),
969
1005
 
970
1006
  southArrowNorthEast: ( targetRect, balloonRect ) => ( {
971
1007
  top: getSouthTop( targetRect, balloonRect ),
972
- left: targetRect.left + targetRect.width / 2 - balloonRect.width + horizontalOffset,
1008
+ left: targetRect.left + targetRect.width / 2 - balloonRect.width + sideOffset,
973
1009
  name: 'arrow_ne',
974
1010
  ...( config && { config } )
975
1011
  } ),
@@ -978,14 +1014,14 @@ export function generatePositions( {
978
1014
 
979
1015
  southEastArrowNorthWest: ( targetRect, balloonRect ) => ( {
980
1016
  top: getSouthTop( targetRect, balloonRect ),
981
- left: targetRect.right - horizontalOffset,
1017
+ left: targetRect.right - sideOffset,
982
1018
  name: 'arrow_nw',
983
1019
  ...( config && { config } )
984
1020
  } ),
985
1021
 
986
1022
  southEastArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {
987
1023
  top: getSouthTop( targetRect, balloonRect ),
988
- left: targetRect.right - ( balloonRect.width * .25 ) - horizontalOffset,
1024
+ left: targetRect.right - ( balloonRect.width * .25 ) - sideOffset,
989
1025
  name: 'arrow_nmw',
990
1026
  ...( config && { config } )
991
1027
  } ),
@@ -999,18 +1035,36 @@ export function generatePositions( {
999
1035
 
1000
1036
  southEastArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {
1001
1037
  top: getSouthTop( targetRect, balloonRect ),
1002
- left: targetRect.right - ( balloonRect.width * .75 ) + horizontalOffset,
1038
+ left: targetRect.right - ( balloonRect.width * .75 ) + sideOffset,
1003
1039
  name: 'arrow_nme',
1004
1040
  ...( config && { config } )
1005
1041
  } ),
1006
1042
 
1007
1043
  southEastArrowNorthEast: ( targetRect, balloonRect ) => ( {
1008
1044
  top: getSouthTop( targetRect, balloonRect ),
1009
- left: targetRect.right - balloonRect.width + horizontalOffset,
1045
+ left: targetRect.right - balloonRect.width + sideOffset,
1010
1046
  name: 'arrow_ne',
1011
1047
  ...( config && { config } )
1012
1048
  } ),
1013
1049
 
1050
+ // ------- West
1051
+
1052
+ westArrowEast: ( targetRect, balloonRect ) => ( {
1053
+ top: targetRect.top + targetRect.height / 2 - balloonRect.height / 2,
1054
+ left: targetRect.left - balloonRect.width - heightOffset,
1055
+ name: 'arrow_e',
1056
+ ...( config && { config } )
1057
+ } ),
1058
+
1059
+ // ------- East
1060
+
1061
+ eastArrowWest: ( targetRect, balloonRect ) => ( {
1062
+ top: targetRect.top + targetRect.height / 2 - balloonRect.height / 2,
1063
+ left: targetRect.right + heightOffset,
1064
+ name: 'arrow_w',
1065
+ ...( config && { config } )
1066
+ } ),
1067
+
1014
1068
  // ------- Sticky
1015
1069
 
1016
1070
  viewportStickyNorth: ( targetRect, balloonRect, viewportRect ) => {
@@ -1037,7 +1091,7 @@ export function generatePositions( {
1037
1091
  // @param {utils/dom/rect~Rect} elementRect A rect of the balloon.
1038
1092
  // @returns {Number}
1039
1093
  function getNorthTop( targetRect, balloonRect ) {
1040
- return targetRect.top - balloonRect.height - verticalOffset;
1094
+ return targetRect.top - balloonRect.height - heightOffset;
1041
1095
  }
1042
1096
 
1043
1097
  // Returns the top coordinate for positions starting with `south*`.
@@ -1047,6 +1101,6 @@ export function generatePositions( {
1047
1101
  // @param {utils/dom/rect~Rect} elementRect A rect of the balloon.
1048
1102
  // @returns {Number}
1049
1103
  function getSouthTop( targetRect ) {
1050
- return targetRect.bottom + verticalOffset;
1104
+ return targetRect.bottom + heightOffset;
1051
1105
  }
1052
1106
  }