@progress/kendo-angular-toolbar 18.1.0-develop.3 → 18.1.0-develop.30

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 (36) hide show
  1. package/common/overflow-mode.d.ts +8 -0
  2. package/common/overflow-settings.d.ts +53 -0
  3. package/common/scroll-buttons.d.ts +12 -0
  4. package/esm2022/common/overflow-mode.mjs +5 -0
  5. package/esm2022/common/overflow-settings.mjs +5 -0
  6. package/esm2022/common/scroll-buttons.mjs +5 -0
  7. package/esm2022/localization/messages.mjs +14 -2
  8. package/esm2022/navigation.service.mjs +5 -3
  9. package/esm2022/package-metadata.mjs +2 -2
  10. package/esm2022/renderer.component.mjs +8 -0
  11. package/esm2022/scroll.service.mjs +102 -0
  12. package/esm2022/scrollable-button.component.mjs +162 -0
  13. package/esm2022/toolbar.component.mjs +716 -124
  14. package/esm2022/tools/toolbar-button.component.mjs +62 -2
  15. package/esm2022/tools/toolbar-buttongroup.component.mjs +87 -6
  16. package/esm2022/tools/toolbar-dropdownbutton.component.mjs +67 -11
  17. package/esm2022/tools/toolbar-separator.component.mjs +8 -0
  18. package/esm2022/tools/toolbar-splitbutton.component.mjs +61 -5
  19. package/esm2022/tools/toolbar-tool.component.mjs +9 -1
  20. package/esm2022/tools/tools.service.mjs +3 -0
  21. package/esm2022/util.mjs +17 -0
  22. package/fesm2022/progress-kendo-angular-toolbar.mjs +1300 -155
  23. package/index.d.ts +3 -0
  24. package/localization/messages.d.ts +10 -2
  25. package/package.json +9 -9
  26. package/render-location.d.ts +1 -1
  27. package/scroll.service.d.ts +42 -0
  28. package/scrollable-button.component.d.ts +44 -0
  29. package/toolbar.component.d.ts +77 -6
  30. package/tools/toolbar-button.component.d.ts +1 -0
  31. package/tools/toolbar-buttongroup.component.d.ts +1 -0
  32. package/tools/toolbar-dropdownbutton.component.d.ts +2 -1
  33. package/tools/toolbar-splitbutton.component.d.ts +1 -0
  34. package/tools/toolbar-tool.component.d.ts +6 -0
  35. package/tools/tools.service.d.ts +1 -0
  36. package/util.d.ts +5 -0
@@ -12,7 +12,7 @@ import { packageMetadata } from './package-metadata';
12
12
  import { RefreshService } from './refresh.service';
13
13
  import { NavigationService } from './navigation.service';
14
14
  import { ToolBarToolComponent } from './tools/toolbar-tool.component';
15
- import { innerWidth, closest, isPresent, getStylingClasses, SIZES } from './util';
15
+ import { innerWidth, closest, isPresent, getStylingClasses, SIZES, normalizeOverflowSettings } from './util';
16
16
  import { Keys } from '@progress/kendo-angular-common';
17
17
  import { PreventableEvent } from './common/preventable-event';
18
18
  import { ToolBarRendererComponent } from './renderer.component';
@@ -20,17 +20,20 @@ import { Subscription, fromEvent, Subject, merge } from 'rxjs';
20
20
  import { take, takeUntil } from 'rxjs/operators';
21
21
  import { filter } from 'rxjs/operators';
22
22
  import { isDocumentAvailable } from '@progress/kendo-angular-common';
23
- import { moreVerticalIcon } from '@progress/kendo-svg-icons';
24
- import { ButtonComponent } from '@progress/kendo-angular-buttons';
23
+ import { caretAltLeftIcon, caretAltRightIcon, moreHorizontalIcon, moreVerticalIcon } from '@progress/kendo-svg-icons';
24
+ import { ButtonComponent, ButtonGroupComponent } from '@progress/kendo-angular-buttons';
25
25
  import { NgFor, NgIf, NgClass, NgTemplateOutlet } from '@angular/common';
26
26
  import { LocalizedToolbarMessagesDirective } from './localization/localized-toolbar-messages.directive';
27
27
  import { ToolbarToolsService } from './tools/tools.service';
28
+ import { ScrollService } from './scroll.service';
29
+ import { ToolbarScrollableButtonComponent } from './scrollable-button.component';
28
30
  import * as i0 from "@angular/core";
29
31
  import * as i1 from "@progress/kendo-angular-l10n";
30
32
  import * as i2 from "@progress/kendo-angular-popup";
31
33
  import * as i3 from "./refresh.service";
32
34
  import * as i4 from "./navigation.service";
33
35
  import * as i5 from "./tools/tools.service";
36
+ import * as i6 from "./scroll.service";
34
37
  const DEFAULT_SIZE = 'medium';
35
38
  const DEFAULT_FILL_MODE = 'solid';
36
39
  const immediateResizeThreshold = 300;
@@ -52,13 +55,27 @@ export class ToolBarComponent {
52
55
  renderer;
53
56
  _cdr;
54
57
  toolsService;
58
+ scrollService;
55
59
  get overflowClass() {
56
60
  return `k-button-${SIZES[this.size]}`;
57
61
  }
58
62
  /**
59
- * Hides the overflowing tools in a popup.
63
+ * Configures the overflow mode. Used to specify how tools will be rendered when the total size of all tools is greater than the size of the Toolbar container.
64
+ * @default false
60
65
  */
61
- overflow = false;
66
+ set overflow(overflow) {
67
+ this._overflow = overflow;
68
+ this.zone.onStable.pipe(take(1)).subscribe(() => this.onResize());
69
+ }
70
+ get overflow() {
71
+ return this._overflow;
72
+ }
73
+ get show() {
74
+ const buttonsVisibility = this.normalizedOverflow.scrollButtons;
75
+ const showAuto = buttonsVisibility === 'auto' && this.showAutoButtons;
76
+ const showAlways = buttonsVisibility === 'visible';
77
+ return this.isScrollMode && (showAuto || showAlways);
78
+ }
62
79
  /**
63
80
  * @hidden
64
81
  */
@@ -66,10 +83,39 @@ export class ToolBarComponent {
66
83
  this.overflow = value;
67
84
  }
68
85
  get resizable() {
69
- return this.overflow;
86
+ return this.showMenu;
87
+ }
88
+ /**
89
+ * @hidden
90
+ */
91
+ get hasScrollButtons() {
92
+ const visible = this.normalizedOverflow.mode === 'scroll' && this.normalizedOverflow.scrollButtons !== 'hidden';
93
+ const position = this.normalizedOverflow.scrollButtonsPosition;
94
+ return {
95
+ visible,
96
+ position
97
+ };
98
+ }
99
+ /**
100
+ * @hidden
101
+ */
102
+ get isScrollMode() {
103
+ return this.normalizedOverflow.mode === 'scroll';
104
+ }
105
+ /**
106
+ * @hidden
107
+ */
108
+ get showMenu() {
109
+ return this.normalizedOverflow.mode === 'menu' || this.normalizedOverflow.mode === 'section';
110
+ }
111
+ /**
112
+ * @hidden
113
+ */
114
+ get overflowEnabled() {
115
+ return this.normalizedOverflow.mode !== 'none';
70
116
  }
71
117
  /**
72
- * Configures the popup of the ToolBar overflow button ([see example]({% slug responsive_toolbar %}#toc-popup-customization)).
118
+ * Configures the popup of the ToolBar overflow button ([see example](slug:responsive_toolbar#customizing-the-popup)).
73
119
  *
74
120
  * The available options are:
75
121
  * - `animate: Boolean`—Controls the popup animation. By default, the open and close animations are enabled.
@@ -136,8 +182,15 @@ export class ToolBarComponent {
136
182
  allTools;
137
183
  overflowButton;
138
184
  popupTemplate;
185
+ popupSectionTemplate;
186
+ scrollContainer;
139
187
  resizeSensor;
140
188
  container;
189
+ prevScrollButton;
190
+ nextScrollButton;
191
+ startButtonGroup;
192
+ endButtonGroup;
193
+ scrollSeparator;
141
194
  popupRef;
142
195
  direction;
143
196
  get appendTo() {
@@ -166,17 +219,40 @@ export class ToolBarComponent {
166
219
  get popupOpen() {
167
220
  return this._open;
168
221
  }
222
+ /**
223
+ * @hidden
224
+ */
225
+ prevButtonIcon = caretAltLeftIcon;
226
+ /**
227
+ * @hidden
228
+ */
229
+ nextButtonIcon = caretAltRightIcon;
169
230
  hostClass = true;
231
+ get scrollableClass() {
232
+ return this.isScrollMode;
233
+ }
234
+ get sectionClass() {
235
+ return this.normalizedOverflow.mode === 'section';
236
+ }
237
+ _overflow = false;
170
238
  _popupSettings;
171
239
  cachedOverflowAnchorWidth;
172
240
  _open;
173
241
  toolbarKeydownListener;
174
242
  overflowKeydownListener;
243
+ sectionKeydownListener;
175
244
  cancelRenderedToolsSubscription$ = new Subject();
176
245
  cachedGap;
177
246
  _size = DEFAULT_SIZE;
178
247
  _fillMode = DEFAULT_FILL_MODE;
179
248
  overflowButtonClickedTime = null;
249
+ showAutoButtons = false;
250
+ /**
251
+ * @hidden
252
+ */
253
+ get normalizedOverflow() {
254
+ return normalizeOverflowSettings(this.overflow);
255
+ }
180
256
  subscriptions = new Subscription();
181
257
  popupSubs = new Subscription();
182
258
  /**
@@ -204,12 +280,11 @@ export class ToolBarComponent {
204
280
  return this.direction;
205
281
  }
206
282
  get resizableClass() {
207
- return this.overflow;
283
+ return this.resizable;
208
284
  }
209
- moreVerticalIcon = moreVerticalIcon;
210
285
  constructor(localization, popupService, refreshService, navigationService,
211
286
  // Needs to be public as it is being accessed in the Editor component
212
- element, zone, renderer, _cdr, toolsService) {
287
+ element, zone, renderer, _cdr, toolsService, scrollService) {
213
288
  this.localization = localization;
214
289
  this.popupService = popupService;
215
290
  this.refreshService = refreshService;
@@ -219,13 +294,19 @@ export class ToolBarComponent {
219
294
  this.renderer = renderer;
220
295
  this._cdr = _cdr;
221
296
  this.toolsService = toolsService;
297
+ this.scrollService = scrollService;
222
298
  validatePackage(packageMetadata);
223
299
  this.direction = localization.rtl ? 'rtl' : 'ltr';
300
+ this.scrollService.owner = this;
224
301
  }
225
302
  ngAfterContentInit() {
226
303
  this.toolsService.allTools = this.allTools.toArray();
227
304
  this.subscriptions.add(this.allTools.changes.subscribe(() => {
305
+ this.toolsService.reset();
228
306
  this.toolsService.allTools = this.allTools.toArray();
307
+ this.allTools.forEach((tool) => {
308
+ this.refreshService.refresh(tool);
309
+ });
229
310
  this.zone.onStable.pipe(take(1)).subscribe(() => this.onResize());
230
311
  }));
231
312
  }
@@ -282,9 +363,11 @@ export class ToolBarComponent {
282
363
  }
283
364
  });
284
365
  });
285
- if (this.overflow) {
366
+ if (this.overflowEnabled) {
286
367
  this.subscriptions.add(merge(this.resizeSensor.resize, this.toolsService.renderedToolsChange).subscribe(() => this.onResize()));
287
- this.navigationService.overflowButton = this.overflowButton;
368
+ if (this.showMenu) {
369
+ this.navigationService.overflowButton = this.overflowButton;
370
+ }
288
371
  // because of https://github.com/telerik/kendo-angular-buttons/pull/276
289
372
  // button icons are not rendered until onResize() is called
290
373
  this.zone.runOutsideAngular(() => {
@@ -295,6 +378,38 @@ export class ToolBarComponent {
295
378
  });
296
379
  });
297
380
  }
381
+ if (this.isScrollMode) {
382
+ if (this.show) {
383
+ if (this.normalizedOverflow.scrollButtons === 'visible' && !this.scrollService.toolsOverflow) {
384
+ this.renderer.addClass(this.nextScrollButton.nativeElement, 'k-disabled');
385
+ this.renderer.addClass(this.prevScrollButton.nativeElement, 'k-disabled');
386
+ }
387
+ else {
388
+ const buttonToDisable = this.direction === 'rtl' ? this.nextScrollButton : this.prevScrollButton;
389
+ this.renderer.addClass(buttonToDisable.nativeElement, 'k-disabled');
390
+ }
391
+ }
392
+ if (this.hasScrollButtons.visible) {
393
+ this.subscriptions.add(this.scrollService.scrollButtonActiveStateChange.subscribe((activeButtonSettings) => {
394
+ if (this.show) {
395
+ const action = activeButtonSettings.active ? 'remove' : 'add';
396
+ const scrollButton = this[`${activeButtonSettings.buttonType}ScrollButton`].nativeElement;
397
+ this.renderer[`${action}Class`](scrollButton, 'k-disabled');
398
+ action === 'add' && this[`${activeButtonSettings.buttonType}ScrollButton`].nativeElement.blur();
399
+ }
400
+ }));
401
+ }
402
+ this.zone.runOutsideAngular(() => {
403
+ this.subscriptions.add(this.renderer.listen(this.scrollContainer.nativeElement, 'scroll', (e) => {
404
+ if (!this.hasScrollButtons.visible) {
405
+ this.setScrollableOverlayClasses();
406
+ }
407
+ else {
408
+ this.scrollService.onScroll(e);
409
+ }
410
+ }));
411
+ });
412
+ }
298
413
  this.navigationService.setRenderedTools(this.toolsService.renderedTools);
299
414
  const stylingOptions = ['size', 'fillMode'];
300
415
  stylingOptions.forEach(option => {
@@ -328,6 +443,10 @@ export class ToolBarComponent {
328
443
  this.cancelRenderedToolsSubscription$.next();
329
444
  this.subscriptions.unsubscribe();
330
445
  }
446
+ /**
447
+ * @hidden
448
+ */
449
+ showOverflowSeparator = false;
331
450
  /**
332
451
  * @hidden
333
452
  */
@@ -340,6 +459,31 @@ export class ToolBarComponent {
340
459
  get cdr() {
341
460
  return this._cdr;
342
461
  }
462
+ /**
463
+ * @hidden
464
+ */
465
+ get sectionSizeClass() {
466
+ return this.size === 'none' ? '' : `k-toolbar-items-list-${SIZES[this.size]}`;
467
+ }
468
+ /**
469
+ * @hidden
470
+ */
471
+ getScrollButtonTitle(buttonType) {
472
+ let currentButton;
473
+ if (this.localization.rtl) {
474
+ currentButton = buttonType === 'prev' ? 'nextToolButton' : 'previousToolButton';
475
+ }
476
+ else {
477
+ currentButton = buttonType === 'prev' ? 'previousToolButton' : 'nextToolButton';
478
+ }
479
+ return this.localization.get(currentButton);
480
+ }
481
+ /**
482
+ * @hidden
483
+ */
484
+ scrollTools(dir) {
485
+ this.scrollService.scrollTools(dir);
486
+ }
343
487
  /**
344
488
  * @hidden
345
489
  */
@@ -347,6 +491,17 @@ export class ToolBarComponent {
347
491
  this.navigationService.click(data);
348
492
  this.element.nativeElement.setAttribute('tabindex', '-1');
349
493
  }
494
+ /**
495
+ * @hidden
496
+ */
497
+ overflowButtonIcon(iconType) {
498
+ if (iconType === 'svg') {
499
+ return this.normalizedOverflow.mode === 'section' ? moreHorizontalIcon : moreVerticalIcon;
500
+ }
501
+ else {
502
+ return this.normalizedOverflow.mode === 'section' ? 'more-horizontal' : 'more-vertical';
503
+ }
504
+ }
350
505
  /**
351
506
  * @hidden
352
507
  */
@@ -365,17 +520,30 @@ export class ToolBarComponent {
365
520
  this.popupRef = null;
366
521
  }
367
522
  if (this.popupOpen) {
368
- this.popupRef = this.popupService.open({
369
- anchor: this.overflowButton,
370
- anchorAlign: this.popupSettings.anchorAlign,
371
- popupAlign: this.popupSettings.popupAlign,
372
- content: this.popupTemplate,
373
- appendTo: this.appendTo,
374
- animate: this.popupSettings.animate,
375
- popupClass: this.normalizePopupClasses(this.popupSettings.popupClass),
376
- positionMode: 'absolute'
377
- });
378
- this.setPopupContentDimensions();
523
+ let settings;
524
+ const isSection = this.normalizedOverflow.mode === 'section';
525
+ if (isSection) {
526
+ settings = {
527
+ anchor: this.element.nativeElement,
528
+ content: this.popupSectionTemplate,
529
+ popupClass: this.normalizePopupClasses(),
530
+ positionMode: 'absolute'
531
+ };
532
+ }
533
+ else {
534
+ settings = {
535
+ anchor: this.overflowButton,
536
+ anchorAlign: this.popupSettings.anchorAlign,
537
+ popupAlign: this.popupSettings.popupAlign,
538
+ content: this.popupTemplate,
539
+ appendTo: this.appendTo,
540
+ animate: this.popupSettings.animate,
541
+ popupClass: this.normalizePopupClasses(this.popupSettings.popupClass),
542
+ positionMode: 'absolute'
543
+ };
544
+ }
545
+ this.popupRef = this.popupService.open(settings);
546
+ this.setPopupContentDimensions(isSection);
379
547
  this.popupSubs.add(this.popupRef.popupOpen.subscribe(this.onPopupOpen.bind(this)));
380
548
  this.popupSubs.add(this.popupRef.popupClose.subscribe(this.onPopupClose.bind(this)));
381
549
  }
@@ -385,15 +553,51 @@ export class ToolBarComponent {
385
553
  */
386
554
  onResize() {
387
555
  if (isDocumentAvailable()) {
388
- const containerWidth = innerWidth(this.element.nativeElement) - this.overflowAnchorWidth;
389
- this.shrink(containerWidth, this.childrenWidth);
390
- this.stretch(containerWidth, this.childrenWidth);
391
- this.displayAnchor();
392
- this.resizeSensor?.acceptSize();
393
- const isImmediateResize = (Date.now() - this.overflowButtonClickedTime) < immediateResizeThreshold;
394
- if (this.popupOpen && !isImmediateResize) {
395
- this.toggle();
556
+ if (this.showMenu) {
557
+ const containerWidth = innerWidth(this.element.nativeElement) - this.overflowAnchorWidth;
558
+ this.shrink(containerWidth, this.childrenWidth);
559
+ this.stretch(containerWidth, this.childrenWidth);
560
+ this.displayAnchor();
561
+ const isImmediateResize = (Date.now() - this.overflowButtonClickedTime) < immediateResizeThreshold;
562
+ if (this.popupOpen && !isImmediateResize) {
563
+ this.toggle();
564
+ }
396
565
  }
566
+ else if (this.isScrollMode) {
567
+ if (this.normalizedOverflow.scrollButtons === 'auto') {
568
+ const containerWidth = innerWidth(this.element.nativeElement);
569
+ let scrollButtonsWidth = 0;
570
+ if (this.showAutoButtons) {
571
+ const separatorWidth = this.scrollSeparator.nativeElement.getBoundingClientRect().width + 2 * this.gap;
572
+ if (this.hasScrollButtons.position === 'split') {
573
+ scrollButtonsWidth = innerWidth(this.prevScrollButton.nativeElement) + innerWidth(this.nextScrollButton.nativeElement) + 2 * separatorWidth;
574
+ }
575
+ else if (this.hasScrollButtons.position === 'end') {
576
+ scrollButtonsWidth = innerWidth(this.endButtonGroup.nativeElement) + separatorWidth;
577
+ }
578
+ else {
579
+ scrollButtonsWidth = innerWidth(this.startButtonGroup.nativeElement) + separatorWidth;
580
+ }
581
+ }
582
+ const shouldShowButtons = (this.childrenWidth + scrollButtonsWidth) > containerWidth;
583
+ if (shouldShowButtons !== this.showAutoButtons) {
584
+ this.showAutoButtons = shouldShowButtons;
585
+ this.cdr.detectChanges();
586
+ }
587
+ this.scrollService.toggleScrollButtonsState();
588
+ }
589
+ else if (!this.hasScrollButtons.visible) {
590
+ this.setScrollableOverlayClasses();
591
+ }
592
+ else if (!this.scrollService.toolsOverflow) {
593
+ this.renderer.addClass(this.nextScrollButton.nativeElement, 'k-disabled');
594
+ this.renderer.addClass(this.prevScrollButton.nativeElement, 'k-disabled');
595
+ }
596
+ else {
597
+ this.scrollService.toggleScrollButtonsState();
598
+ }
599
+ }
600
+ this.resizeSensor?.acceptSize();
397
601
  }
398
602
  }
399
603
  /**
@@ -401,45 +605,94 @@ export class ToolBarComponent {
401
605
  */
402
606
  onPopupOpen() {
403
607
  this.zone.runOutsideAngular(() => {
404
- this.overflowKeydownListener = this.renderer.listen(this.popupRef.popupElement, 'keydown', (ev) => {
405
- switch (ev.keyCode) {
406
- case Keys.ArrowUp:
407
- this.zone.run(() => {
408
- ev.preventDefault();
409
- this.navigationService.focusPrev(ev);
410
- });
411
- break;
412
- case Keys.ArrowDown:
413
- this.zone.run(() => {
414
- ev.preventDefault();
415
- this.navigationService.focusNext(ev);
416
- });
417
- break;
418
- case Keys.Escape:
419
- this.zone.run(() => this.toggle(false));
420
- const eventArgs = new PreventableEvent();
421
- this.close.emit(eventArgs);
422
- break;
423
- case Keys.Tab:
424
- this.zone.run(() => {
425
- this.toggle(false);
426
- this.navigationService.resetNavigation();
427
- });
428
- break;
429
- case Keys.Enter:
430
- case Keys.Space:
431
- this.zone.run(() => {
432
- if (ev.target.closest('.k-menu-item')) {
608
+ if (this.normalizedOverflow.mode === 'section') {
609
+ this.sectionKeydownListener = this.renderer.listen(this.popupRef.popupElement, 'keydown', (ev) => {
610
+ switch (ev.keyCode) {
611
+ case Keys.ArrowLeft:
612
+ this.zone.run(() => {
433
613
  ev.preventDefault();
434
- ev.target.click();
435
- ev.target.focus();
436
- }
437
- });
438
- break;
439
- default:
440
- break;
441
- }
442
- });
614
+ if (this.direction === 'ltr') {
615
+ this.navigationService.focusPrev(ev);
616
+ }
617
+ else {
618
+ this.navigationService.focusNext(ev);
619
+ }
620
+ // prevents ExpressionChangedAfterItHasBeenCheckedError when tools with popup are opened/closed asynchronously
621
+ this.element.nativeElement.setAttribute('tabindex', '-1');
622
+ });
623
+ break;
624
+ case Keys.ArrowRight:
625
+ this.zone.run(() => {
626
+ ev.preventDefault();
627
+ if (this.direction === 'ltr') {
628
+ this.navigationService.focusNext(ev);
629
+ }
630
+ else {
631
+ this.navigationService.focusPrev(ev);
632
+ }
633
+ // prevents ExpressionChangedAfterItHasBeenCheckedError when tools with popup are opened/closed asynchronously
634
+ this.element.nativeElement.setAttribute('tabindex', '-1');
635
+ });
636
+ break;
637
+ case Keys.Escape: {
638
+ this.zone.run(() => this.toggle(false));
639
+ const eventArgs = new PreventableEvent();
640
+ this.close.emit(eventArgs);
641
+ break;
642
+ }
643
+ case Keys.Tab:
644
+ this.zone.run(() => {
645
+ this.toggle(false);
646
+ this.navigationService.resetNavigation();
647
+ });
648
+ break;
649
+ default:
650
+ break;
651
+ }
652
+ });
653
+ }
654
+ else {
655
+ this.overflowKeydownListener = this.renderer.listen(this.popupRef.popupElement, 'keydown', (ev) => {
656
+ switch (ev.keyCode) {
657
+ case Keys.ArrowUp:
658
+ this.zone.run(() => {
659
+ ev.preventDefault();
660
+ this.navigationService.focusPrev(ev);
661
+ });
662
+ break;
663
+ case Keys.ArrowDown:
664
+ this.zone.run(() => {
665
+ ev.preventDefault();
666
+ this.navigationService.focusNext(ev);
667
+ });
668
+ break;
669
+ case Keys.Escape: {
670
+ this.zone.run(() => this.toggle(false));
671
+ const eventArgs = new PreventableEvent();
672
+ this.close.emit(eventArgs);
673
+ break;
674
+ }
675
+ case Keys.Tab:
676
+ this.zone.run(() => {
677
+ this.toggle(false);
678
+ this.navigationService.resetNavigation();
679
+ });
680
+ break;
681
+ case Keys.Enter:
682
+ case Keys.Space:
683
+ this.zone.run(() => {
684
+ if (ev.target.closest('.k-menu-item')) {
685
+ ev.preventDefault();
686
+ ev.target.click();
687
+ ev.target.focus();
688
+ }
689
+ });
690
+ break;
691
+ default:
692
+ break;
693
+ }
694
+ });
695
+ }
443
696
  });
444
697
  this.cancelRenderedToolsSubscription$.next();
445
698
  this.navigationService.setRenderedTools(this.toolsService.overflowTools);
@@ -462,6 +715,9 @@ export class ToolBarComponent {
462
715
  if (this.overflowKeydownListener) {
463
716
  this.overflowKeydownListener();
464
717
  }
718
+ if (this.sectionKeydownListener) {
719
+ this.sectionKeydownListener();
720
+ }
465
721
  this.renderer.removeAttribute(this.overflowButton.nativeElement, 'aria-controls');
466
722
  }
467
723
  /**
@@ -475,6 +731,11 @@ export class ToolBarComponent {
475
731
  displayAnchor() {
476
732
  const visibility = this.allTools.filter(t => t.overflows && t.responsive).length > 0 ? 'visible' : 'hidden';
477
733
  this.overflowButton && this.renderer.setStyle(this.overflowButton.nativeElement, 'visibility', visibility);
734
+ const isVisible = visibility === 'visible';
735
+ if (isVisible !== this.showOverflowSeparator) {
736
+ this.showOverflowSeparator = isVisible;
737
+ this.cdr.detectChanges();
738
+ }
478
739
  }
479
740
  get popupWidth() {
480
741
  if (!this.popupSettings || !this.popupSettings.width) {
@@ -489,7 +750,7 @@ export class ToolBarComponent {
489
750
  return isNaN(this.popupSettings.height) ? this.popupSettings.height : `${this.popupSettings.height}px`;
490
751
  }
491
752
  get overflowAnchorWidth() {
492
- if (!this.overflow) {
753
+ if (!this.showMenu) {
493
754
  return 0;
494
755
  }
495
756
  if (!this.cachedOverflowAnchorWidth) {
@@ -556,7 +817,7 @@ export class ToolBarComponent {
556
817
  return r.tool === tool;
557
818
  });
558
819
  const width = renderedElement.width;
559
- tool.overflows = this.overflow;
820
+ tool.overflows = this.showMenu;
560
821
  this.refreshService.refresh(tool);
561
822
  return width;
562
823
  }
@@ -578,11 +839,17 @@ export class ToolBarComponent {
578
839
  this.refreshService.refresh(tool);
579
840
  return renderedElement.width; // returns 0 if `overflows` is true
580
841
  }
581
- setPopupContentDimensions() {
842
+ setPopupContentDimensions(isSection) {
582
843
  const popupContentContainer = this.popupRef.popup.instance.contentContainer.nativeElement;
583
- popupContentContainer.style.width = this.popupWidth;
584
- popupContentContainer.style.height = this.popupHeight;
585
- popupContentContainer.style.overflow = 'auto';
844
+ if (isSection) {
845
+ const toolbarWidth = this.element.nativeElement.getBoundingClientRect().width;
846
+ popupContentContainer.style.width = `${toolbarWidth}px`;
847
+ }
848
+ else {
849
+ popupContentContainer.style.width = this.popupWidth;
850
+ popupContentContainer.style.height = this.popupHeight;
851
+ popupContentContainer.style.overflow = 'auto';
852
+ }
586
853
  }
587
854
  destroyPopup() {
588
855
  if (this.popupRef) {
@@ -602,7 +869,10 @@ export class ToolBarComponent {
602
869
  }
603
870
  }
604
871
  normalizePopupClasses(classList) {
605
- let classes = ['k-menu-popup', 'k-toolbar-popup'];
872
+ let classes = ['k-toolbar-popup'];
873
+ if (this.normalizedOverflow.mode === 'menu') {
874
+ classes.push('k-menu-popup');
875
+ }
606
876
  if (!classList) {
607
877
  return classes;
608
878
  }
@@ -619,62 +889,204 @@ export class ToolBarComponent {
619
889
  }
620
890
  return classes;
621
891
  }
622
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ToolBarComponent, deps: [{ token: i1.LocalizationService }, { token: i2.PopupService }, { token: i3.RefreshService }, { token: i4.NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i5.ToolbarToolsService }], target: i0.ɵɵFactoryTarget.Component });
623
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ToolBarComponent, isStandalone: true, selector: "kendo-toolbar", inputs: { overflow: "overflow", resizable: "resizable", popupSettings: "popupSettings", fillMode: "fillMode", tabindex: "tabindex", size: "size", tabIndex: "tabIndex" }, outputs: { open: "open", close: "close" }, host: { listeners: { "focus": "onFocus($event)", "focusout": "onFocusOut($event)" }, properties: { "class.k-toolbar": "this.hostClass", "attr.role": "this.role", "attr.dir": "this.getDir", "class.k-toolbar-resizable": "this.resizableClass" } }, providers: [
892
+ setScrollableOverlayClasses() {
893
+ const wrapper = this.element.nativeElement;
894
+ const container = this.scrollContainer?.nativeElement;
895
+ if (!container) {
896
+ return;
897
+ }
898
+ const scrollOffset = container.scrollLeft;
899
+ const defaultOffset = 1;
900
+ if (this.scrollService.toolsOverflow) {
901
+ this.renderer.addClass(wrapper, 'k-toolbar-scrollable-overlay');
902
+ if (scrollOffset === 0) {
903
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-end');
904
+ this.renderer.addClass(wrapper, 'k-toolbar-scrollable-start');
905
+ }
906
+ else if ((scrollOffset > 0 && scrollOffset < this.scrollService.scrollContainerOverflowSize - defaultOffset) || (scrollOffset < 0 && Math.abs(scrollOffset) < this.scrollService.scrollContainerOverflowSize - defaultOffset)) {
907
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-end');
908
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-start');
909
+ }
910
+ else {
911
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-start');
912
+ this.renderer.addClass(wrapper, 'k-toolbar-scrollable-end');
913
+ }
914
+ }
915
+ else {
916
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-overlay');
917
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-end');
918
+ this.renderer.removeClass(wrapper, 'k-toolbar-scrollable-start');
919
+ }
920
+ }
921
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ToolBarComponent, deps: [{ token: i1.LocalizationService }, { token: i2.PopupService }, { token: i3.RefreshService }, { token: i4.NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i5.ToolbarToolsService }, { token: i6.ScrollService }], target: i0.ɵɵFactoryTarget.Component });
922
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ToolBarComponent, isStandalone: true, selector: "kendo-toolbar", inputs: { overflow: "overflow", resizable: "resizable", popupSettings: "popupSettings", fillMode: "fillMode", tabindex: "tabindex", size: "size", tabIndex: "tabIndex" }, outputs: { open: "open", close: "close" }, host: { listeners: { "focus": "onFocus($event)", "focusout": "onFocusOut($event)" }, properties: { "class.k-toolbar": "this.hostClass", "class.k-toolbar-scrollable": "this.scrollableClass", "class.k-toolbar-section": "this.sectionClass", "attr.role": "this.role", "attr.dir": "this.getDir", "class.k-toolbar-resizable": "this.resizableClass" } }, providers: [
624
923
  RefreshService,
625
924
  NavigationService,
626
925
  LocalizationService,
627
926
  ToolbarToolsService,
927
+ ScrollService,
628
928
  {
629
929
  provide: L10N_PREFIX,
630
930
  useValue: 'kendo.toolbar'
631
931
  }
632
- ], queries: [{ propertyName: "allTools", predicate: ToolBarToolComponent }], viewQueries: [{ propertyName: "overflowButton", first: true, predicate: ["overflowButton"], descendants: true, read: ElementRef }, { propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true, static: true }, { propertyName: "resizeSensor", first: true, predicate: ["resizeSensor"], descendants: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], exportAs: ["kendoToolBar"], usesOnChanges: true, ngImport: i0, template: `
932
+ ], queries: [{ propertyName: "allTools", predicate: ToolBarToolComponent }], viewQueries: [{ propertyName: "overflowButton", first: true, predicate: ["overflowButton"], descendants: true, read: ElementRef }, { propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true, static: true }, { propertyName: "popupSectionTemplate", first: true, predicate: ["popupSectionTemplate"], descendants: true, static: true }, { propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, read: ElementRef }, { propertyName: "resizeSensor", first: true, predicate: ["resizeSensor"], descendants: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "prevScrollButton", first: true, predicate: ["prevScrollButton"], descendants: true, read: ElementRef }, { propertyName: "nextScrollButton", first: true, predicate: ["nextScrollButton"], descendants: true, read: ElementRef }, { propertyName: "startButtonGroup", first: true, predicate: ["startButtonGroup"], descendants: true, read: ElementRef }, { propertyName: "endButtonGroup", first: true, predicate: ["endButtonGroup"], descendants: true, read: ElementRef }, { propertyName: "scrollSeparator", first: true, predicate: ["scrollSeparator"], descendants: true, read: ElementRef }], exportAs: ["kendoToolBar"], usesOnChanges: true, ngImport: i0, template: `
633
933
  <ng-container kendoToolbarLocalizedMessages
634
- i18n-moreToolsTitle="kendo.toolbar.moreToolsTitle|The title of the **more tools** button in a responsive ToolBar"
635
- moreToolsTitle="More tools"
934
+ i18n-moreToolsTitle="kendo.toolbar.moreToolsTitle|The title of the **more tools** button in a responsive ToolBar"
935
+ moreToolsTitle="More tools"
936
+
937
+ i18n-previousToolButton="kendo.toolbar.previousToolButton|The title for the **Previous Tool** button when the Toolbar is scrollable."
938
+ previousToolButton="Scroll left"
939
+
940
+ i18n-nextToolButton="kendo.toolbar.nextToolButton|The title for the **Next Tool** button when the Toolbar is scrollable."
941
+ nextToolButton="Scroll right"
636
942
  >
637
943
  </ng-container>
638
- <ng-container *ngFor="let tool of allTools; let index = index"
639
- kendoToolbarRenderer
640
- [tool]="tool"
641
- location="toolbar"
642
- [resizable]="overflow"
643
- (rendererClick)="onRendererClick($event)"
644
- [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
645
- <ng-template #wrapper>
646
- <div class="k-toolbar-item">
647
- <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
648
- </div>
649
- </ng-template>
944
+ <ng-container *ngIf="show && (hasScrollButtons.position === 'split' || hasScrollButtons.position === 'start')">
945
+ <span *ngIf="hasScrollButtons.position === 'split'" #prevScrollButton
946
+ kendoToolbarScrollableButton
947
+ [prev]="true"
948
+ [overflow]="normalizedOverflow"
949
+ [title]="getScrollButtonTitle('prev')"
950
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
951
+ [ngClass]="{
952
+ 'k-button-sm': size === 'small',
953
+ 'k-button-md': size === 'medium' || !size,
954
+ 'k-button-lg': size === 'large'
955
+ }"
956
+ (onClick)="scrollTools($event)">
957
+ </span>
958
+ <div class="k-button-group k-button-group-solid" *ngIf="hasScrollButtons.position === 'start'" #startButtonGroup>
959
+ <span #prevScrollButton
960
+ kendoToolbarScrollableButton
961
+ [prev]="true"
962
+ [overflow]="normalizedOverflow"
963
+ [title]="getScrollButtonTitle('prev')"
964
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
965
+ [ngClass]="{
966
+ 'k-button-sm': size === 'small',
967
+ 'k-button-md': size === 'medium' || !size,
968
+ 'k-button-lg': size === 'large'
969
+ }"
970
+ (onClick)="scrollTools($event)">
971
+ </span>
972
+ <span #nextScrollButton
973
+ kendoToolbarScrollableButton
974
+ [prev]="false"
975
+ [overflow]="normalizedOverflow"
976
+ [title]="getScrollButtonTitle('next')"
977
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
978
+ [ngClass]="{
979
+ 'k-button-sm': size === 'small',
980
+ 'k-button-md': size === 'medium' || !size,
981
+ 'k-button-lg': size === 'large'
982
+ }"
983
+ (onClick)="scrollTools($event)">
984
+ </span>
985
+ </div>
986
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator" #scrollSeparator></div>
650
987
  </ng-container>
988
+ <div class="k-toolbar-items k-toolbar-items-scroll" *ngIf="isScrollMode; else noScroll" #scrollContainer>
989
+ <ng-container *ngFor="let tool of allTools; let index = index"
990
+ kendoToolbarRenderer
991
+ [tool]="tool"
992
+ location="toolbar"
993
+ [resizable]="resizable"
994
+ (rendererClick)="onRendererClick($event)"
995
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
996
+ <ng-template #wrapper>
997
+ <div class="k-toolbar-item">
998
+ <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
999
+ </div>
1000
+ </ng-template>
1001
+ </ng-container>
1002
+ </div>
1003
+ <ng-template #noScroll>
1004
+ <ng-container *ngFor="let tool of allTools; let index = index"
1005
+ kendoToolbarRenderer
1006
+ [tool]="tool"
1007
+ location="toolbar"
1008
+ [resizable]="resizable"
1009
+ (rendererClick)="onRendererClick($event)"
1010
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
1011
+ <ng-template #wrapper>
1012
+ <div class="k-toolbar-item">
1013
+ <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
1014
+ </div>
1015
+ </ng-template>
1016
+ </ng-container>
1017
+ </ng-template>
1018
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator" *ngIf="showOverflowSeparator"></div>
651
1019
  <button
652
1020
  kendoButton
653
1021
  fillMode="flat"
654
1022
  #overflowButton
655
1023
  type="button"
656
- icon="more-vertical"
657
- [svgIcon]="moreVerticalIcon"
1024
+ [icon]="overflowButtonIcon('font')"
1025
+ [svgIcon]="overflowButtonIcon('svg')"
658
1026
  tabindex="-1"
659
1027
  [title]="moreToolsTitle"
660
1028
  [attr.aria-label]="moreToolsTitle"
661
1029
  [attr.aria-expanded]="popupOpen"
662
1030
  [id]="overflowBtnId"
663
- aria-haspopup="menu"
664
- *ngIf="overflow"
1031
+ [attr.aria-haspopup]="normalizedOverflow.mode === 'section' ? null : 'menu'"
1032
+ *ngIf="showMenu"
665
1033
  [style.visibility]="'hidden'"
666
1034
  [style.position]="'relative'"
667
- [style.margin-inline-start]="'auto'"
668
1035
  class="k-toolbar-overflow-button"
669
1036
  [ngClass]="overflowClass"
670
1037
  (click)="showPopup()"
671
1038
  >
672
1039
  </button>
1040
+ <ng-container *ngIf="show && (hasScrollButtons.position === 'split' || hasScrollButtons.position === 'end')">
1041
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator"></div>
1042
+ <span *ngIf="hasScrollButtons.position === 'split'" #nextScrollButton
1043
+ kendoToolbarScrollableButton
1044
+ [prev]="false"
1045
+ [overflow]="normalizedOverflow"
1046
+ [title]="getScrollButtonTitle('next')"
1047
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1048
+ [ngClass]="{
1049
+ 'k-button-sm': size === 'small',
1050
+ 'k-button-md': size === 'medium' || !size,
1051
+ 'k-button-lg': size === 'large'
1052
+ }"
1053
+ (onClick)="scrollTools($event)">
1054
+ </span>
1055
+ <div class="k-button-group k-button-group-solid" *ngIf="hasScrollButtons.position === 'end'" #endButtonGroup>
1056
+ <span #prevScrollButton
1057
+ kendoToolbarScrollableButton
1058
+ [prev]="true"
1059
+ [overflow]="normalizedOverflow"
1060
+ [title]="getScrollButtonTitle('prev')"
1061
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1062
+ [ngClass]="{
1063
+ 'k-button-sm': size === 'small',
1064
+ 'k-button-md': size === 'medium' || !size,
1065
+ 'k-button-lg': size === 'large'
1066
+ }"
1067
+ (onClick)="scrollTools($event)">
1068
+ </span>
1069
+ <span #nextScrollButton
1070
+ kendoToolbarScrollableButton
1071
+ [prev]="false"
1072
+ [overflow]="normalizedOverflow"
1073
+ [title]="getScrollButtonTitle('next')"
1074
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1075
+ [ngClass]="{
1076
+ 'k-button-sm': size === 'small',
1077
+ 'k-button-md': size === 'medium' || !size,
1078
+ 'k-button-lg': size === 'large'
1079
+ }"
1080
+ (onClick)="scrollTools($event)">
1081
+ </span>
1082
+ </div>
1083
+ </ng-container>
673
1084
  <ng-template #popupTemplate>
674
1085
  <div
675
1086
  class="k-menu-group k-menu-group-md"
676
1087
  role="menu"
677
1088
  [id]="popupId"
1089
+ [attr.dir]="direction === 'rtl' ? 'rtl' : null"
678
1090
  [attr.aria-labelledby]="overflowBtnId">
679
1091
  <ng-container *ngFor="let tool of overflowTools; let index = index">
680
1092
  <ng-template
@@ -682,7 +1094,7 @@ export class ToolBarComponent {
682
1094
  kendoToolbarRenderer
683
1095
  [tool]="tool"
684
1096
  location="overflow"
685
- [resizable]="overflow"
1097
+ [resizable]="resizable"
686
1098
  (rendererClick)="onRendererClick($event)"
687
1099
  [ngTemplateOutlet]="tool.isBuiltInTool ? tool.popupTemplate : popupWrapper"></ng-template>
688
1100
  <ng-template #popupWrapper>
@@ -693,9 +1105,29 @@ export class ToolBarComponent {
693
1105
  </ng-container>
694
1106
  </div>
695
1107
  </ng-template>
1108
+ <ng-template #popupSectionTemplate>
1109
+ <span class="k-toolbar-items-list k-toolbar-items-list-solid"
1110
+ [ngClass]="sectionSizeClass"
1111
+ role="toolbar"
1112
+ [id]="popupId"
1113
+ [attr.dir]="direction === 'rtl' ? 'rtl' : null"
1114
+ [attr.aria-labelledby]="overflowBtnId">
1115
+ <ng-container *ngFor="let tool of overflowTools; let index = index"
1116
+ kendoToolbarRenderer
1117
+ [tool]="tool"
1118
+ location="section"
1119
+ [resizable]="resizable"
1120
+ (rendererClick)="onRendererClick($event)"
1121
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.sectionTemplate : wrapper">
1122
+ <ng-template #wrapper>
1123
+ <ng-container [ngTemplateOutlet]="tool.sectionTemplate"></ng-container>
1124
+ </ng-template>
1125
+ </ng-container>
1126
+ </span>
1127
+ </ng-template>
696
1128
  <ng-container #container></ng-container>
697
- <kendo-resize-sensor *ngIf="overflow" #resizeSensor></kendo-resize-sensor>
698
- `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: LocalizedToolbarMessagesDirective, selector: "[kendoToolbarLocalizedMessages]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ToolBarRendererComponent, selector: "[kendoToolbarRenderer]", inputs: ["tool", "location", "resizable"], outputs: ["rendererClick"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }] });
1129
+ <kendo-resize-sensor *ngIf="overflowEnabled" #resizeSensor></kendo-resize-sensor>
1130
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: LocalizedToolbarMessagesDirective, selector: "[kendoToolbarLocalizedMessages]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ToolBarRendererComponent, selector: "[kendoToolbarRenderer]", inputs: ["tool", "location", "resizable"], outputs: ["rendererClick"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }, { kind: "component", type: ToolbarScrollableButtonComponent, selector: "[kendoToolbarScrollableButton]", inputs: ["prev", "overflow"], outputs: ["onClick"] }] });
699
1131
  }
700
1132
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ToolBarComponent, decorators: [{
701
1133
  type: Component,
@@ -706,6 +1138,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
706
1138
  NavigationService,
707
1139
  LocalizationService,
708
1140
  ToolbarToolsService,
1141
+ ScrollService,
709
1142
  {
710
1143
  provide: L10N_PREFIX,
711
1144
  useValue: 'kendo.toolbar'
@@ -714,50 +1147,162 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
714
1147
  selector: 'kendo-toolbar',
715
1148
  template: `
716
1149
  <ng-container kendoToolbarLocalizedMessages
717
- i18n-moreToolsTitle="kendo.toolbar.moreToolsTitle|The title of the **more tools** button in a responsive ToolBar"
718
- moreToolsTitle="More tools"
1150
+ i18n-moreToolsTitle="kendo.toolbar.moreToolsTitle|The title of the **more tools** button in a responsive ToolBar"
1151
+ moreToolsTitle="More tools"
1152
+
1153
+ i18n-previousToolButton="kendo.toolbar.previousToolButton|The title for the **Previous Tool** button when the Toolbar is scrollable."
1154
+ previousToolButton="Scroll left"
1155
+
1156
+ i18n-nextToolButton="kendo.toolbar.nextToolButton|The title for the **Next Tool** button when the Toolbar is scrollable."
1157
+ nextToolButton="Scroll right"
719
1158
  >
720
1159
  </ng-container>
721
- <ng-container *ngFor="let tool of allTools; let index = index"
722
- kendoToolbarRenderer
723
- [tool]="tool"
724
- location="toolbar"
725
- [resizable]="overflow"
726
- (rendererClick)="onRendererClick($event)"
727
- [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
728
- <ng-template #wrapper>
729
- <div class="k-toolbar-item">
730
- <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
731
- </div>
732
- </ng-template>
1160
+ <ng-container *ngIf="show && (hasScrollButtons.position === 'split' || hasScrollButtons.position === 'start')">
1161
+ <span *ngIf="hasScrollButtons.position === 'split'" #prevScrollButton
1162
+ kendoToolbarScrollableButton
1163
+ [prev]="true"
1164
+ [overflow]="normalizedOverflow"
1165
+ [title]="getScrollButtonTitle('prev')"
1166
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1167
+ [ngClass]="{
1168
+ 'k-button-sm': size === 'small',
1169
+ 'k-button-md': size === 'medium' || !size,
1170
+ 'k-button-lg': size === 'large'
1171
+ }"
1172
+ (onClick)="scrollTools($event)">
1173
+ </span>
1174
+ <div class="k-button-group k-button-group-solid" *ngIf="hasScrollButtons.position === 'start'" #startButtonGroup>
1175
+ <span #prevScrollButton
1176
+ kendoToolbarScrollableButton
1177
+ [prev]="true"
1178
+ [overflow]="normalizedOverflow"
1179
+ [title]="getScrollButtonTitle('prev')"
1180
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1181
+ [ngClass]="{
1182
+ 'k-button-sm': size === 'small',
1183
+ 'k-button-md': size === 'medium' || !size,
1184
+ 'k-button-lg': size === 'large'
1185
+ }"
1186
+ (onClick)="scrollTools($event)">
1187
+ </span>
1188
+ <span #nextScrollButton
1189
+ kendoToolbarScrollableButton
1190
+ [prev]="false"
1191
+ [overflow]="normalizedOverflow"
1192
+ [title]="getScrollButtonTitle('next')"
1193
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1194
+ [ngClass]="{
1195
+ 'k-button-sm': size === 'small',
1196
+ 'k-button-md': size === 'medium' || !size,
1197
+ 'k-button-lg': size === 'large'
1198
+ }"
1199
+ (onClick)="scrollTools($event)">
1200
+ </span>
1201
+ </div>
1202
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator" #scrollSeparator></div>
733
1203
  </ng-container>
1204
+ <div class="k-toolbar-items k-toolbar-items-scroll" *ngIf="isScrollMode; else noScroll" #scrollContainer>
1205
+ <ng-container *ngFor="let tool of allTools; let index = index"
1206
+ kendoToolbarRenderer
1207
+ [tool]="tool"
1208
+ location="toolbar"
1209
+ [resizable]="resizable"
1210
+ (rendererClick)="onRendererClick($event)"
1211
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
1212
+ <ng-template #wrapper>
1213
+ <div class="k-toolbar-item">
1214
+ <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
1215
+ </div>
1216
+ </ng-template>
1217
+ </ng-container>
1218
+ </div>
1219
+ <ng-template #noScroll>
1220
+ <ng-container *ngFor="let tool of allTools; let index = index"
1221
+ kendoToolbarRenderer
1222
+ [tool]="tool"
1223
+ location="toolbar"
1224
+ [resizable]="resizable"
1225
+ (rendererClick)="onRendererClick($event)"
1226
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.toolbarTemplate : wrapper">
1227
+ <ng-template #wrapper>
1228
+ <div class="k-toolbar-item">
1229
+ <ng-container [ngTemplateOutlet]="tool.toolbarTemplate"></ng-container>
1230
+ </div>
1231
+ </ng-template>
1232
+ </ng-container>
1233
+ </ng-template>
1234
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator" *ngIf="showOverflowSeparator"></div>
734
1235
  <button
735
1236
  kendoButton
736
1237
  fillMode="flat"
737
1238
  #overflowButton
738
1239
  type="button"
739
- icon="more-vertical"
740
- [svgIcon]="moreVerticalIcon"
1240
+ [icon]="overflowButtonIcon('font')"
1241
+ [svgIcon]="overflowButtonIcon('svg')"
741
1242
  tabindex="-1"
742
1243
  [title]="moreToolsTitle"
743
1244
  [attr.aria-label]="moreToolsTitle"
744
1245
  [attr.aria-expanded]="popupOpen"
745
1246
  [id]="overflowBtnId"
746
- aria-haspopup="menu"
747
- *ngIf="overflow"
1247
+ [attr.aria-haspopup]="normalizedOverflow.mode === 'section' ? null : 'menu'"
1248
+ *ngIf="showMenu"
748
1249
  [style.visibility]="'hidden'"
749
1250
  [style.position]="'relative'"
750
- [style.margin-inline-start]="'auto'"
751
1251
  class="k-toolbar-overflow-button"
752
1252
  [ngClass]="overflowClass"
753
1253
  (click)="showPopup()"
754
1254
  >
755
1255
  </button>
1256
+ <ng-container *ngIf="show && (hasScrollButtons.position === 'split' || hasScrollButtons.position === 'end')">
1257
+ <div class="k-toolbar-separator k-toolbar-button-separator k-separator"></div>
1258
+ <span *ngIf="hasScrollButtons.position === 'split'" #nextScrollButton
1259
+ kendoToolbarScrollableButton
1260
+ [prev]="false"
1261
+ [overflow]="normalizedOverflow"
1262
+ [title]="getScrollButtonTitle('next')"
1263
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1264
+ [ngClass]="{
1265
+ 'k-button-sm': size === 'small',
1266
+ 'k-button-md': size === 'medium' || !size,
1267
+ 'k-button-lg': size === 'large'
1268
+ }"
1269
+ (onClick)="scrollTools($event)">
1270
+ </span>
1271
+ <div class="k-button-group k-button-group-solid" *ngIf="hasScrollButtons.position === 'end'" #endButtonGroup>
1272
+ <span #prevScrollButton
1273
+ kendoToolbarScrollableButton
1274
+ [prev]="true"
1275
+ [overflow]="normalizedOverflow"
1276
+ [title]="getScrollButtonTitle('prev')"
1277
+ class="k-toolbar-prev k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1278
+ [ngClass]="{
1279
+ 'k-button-sm': size === 'small',
1280
+ 'k-button-md': size === 'medium' || !size,
1281
+ 'k-button-lg': size === 'large'
1282
+ }"
1283
+ (onClick)="scrollTools($event)">
1284
+ </span>
1285
+ <span #nextScrollButton
1286
+ kendoToolbarScrollableButton
1287
+ [prev]="false"
1288
+ [overflow]="normalizedOverflow"
1289
+ [title]="getScrollButtonTitle('next')"
1290
+ class="k-toolbar-next k-icon-button k-button k-button-solid k-button-solid-base k-rounded-md"
1291
+ [ngClass]="{
1292
+ 'k-button-sm': size === 'small',
1293
+ 'k-button-md': size === 'medium' || !size,
1294
+ 'k-button-lg': size === 'large'
1295
+ }"
1296
+ (onClick)="scrollTools($event)">
1297
+ </span>
1298
+ </div>
1299
+ </ng-container>
756
1300
  <ng-template #popupTemplate>
757
1301
  <div
758
1302
  class="k-menu-group k-menu-group-md"
759
1303
  role="menu"
760
1304
  [id]="popupId"
1305
+ [attr.dir]="direction === 'rtl' ? 'rtl' : null"
761
1306
  [attr.aria-labelledby]="overflowBtnId">
762
1307
  <ng-container *ngFor="let tool of overflowTools; let index = index">
763
1308
  <ng-template
@@ -765,7 +1310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
765
1310
  kendoToolbarRenderer
766
1311
  [tool]="tool"
767
1312
  location="overflow"
768
- [resizable]="overflow"
1313
+ [resizable]="resizable"
769
1314
  (rendererClick)="onRendererClick($event)"
770
1315
  [ngTemplateOutlet]="tool.isBuiltInTool ? tool.popupTemplate : popupWrapper"></ng-template>
771
1316
  <ng-template #popupWrapper>
@@ -776,13 +1321,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
776
1321
  </ng-container>
777
1322
  </div>
778
1323
  </ng-template>
1324
+ <ng-template #popupSectionTemplate>
1325
+ <span class="k-toolbar-items-list k-toolbar-items-list-solid"
1326
+ [ngClass]="sectionSizeClass"
1327
+ role="toolbar"
1328
+ [id]="popupId"
1329
+ [attr.dir]="direction === 'rtl' ? 'rtl' : null"
1330
+ [attr.aria-labelledby]="overflowBtnId">
1331
+ <ng-container *ngFor="let tool of overflowTools; let index = index"
1332
+ kendoToolbarRenderer
1333
+ [tool]="tool"
1334
+ location="section"
1335
+ [resizable]="resizable"
1336
+ (rendererClick)="onRendererClick($event)"
1337
+ [ngTemplateOutlet]="tool.isBuiltInTool ? tool.sectionTemplate : wrapper">
1338
+ <ng-template #wrapper>
1339
+ <ng-container [ngTemplateOutlet]="tool.sectionTemplate"></ng-container>
1340
+ </ng-template>
1341
+ </ng-container>
1342
+ </span>
1343
+ </ng-template>
779
1344
  <ng-container #container></ng-container>
780
- <kendo-resize-sensor *ngIf="overflow" #resizeSensor></kendo-resize-sensor>
1345
+ <kendo-resize-sensor *ngIf="overflowEnabled" #resizeSensor></kendo-resize-sensor>
781
1346
  `,
782
1347
  standalone: true,
783
- imports: [NgTemplateOutlet, LocalizedToolbarMessagesDirective, NgFor, ToolBarRendererComponent, NgIf, ButtonComponent, NgClass, ResizeSensorComponent]
1348
+ imports: [NgTemplateOutlet, LocalizedToolbarMessagesDirective, NgFor, ToolBarRendererComponent, NgIf, ButtonComponent, NgClass, ResizeSensorComponent, ButtonGroupComponent, ToolbarScrollableButtonComponent]
784
1349
  }]
785
- }], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i2.PopupService }, { type: i3.RefreshService }, { type: i4.NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i5.ToolbarToolsService }]; }, propDecorators: { overflow: [{
1350
+ }], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i2.PopupService }, { type: i3.RefreshService }, { type: i4.NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i5.ToolbarToolsService }, { type: i6.ScrollService }]; }, propDecorators: { overflow: [{
786
1351
  type: Input
787
1352
  }], resizable: [{
788
1353
  type: Input
@@ -810,15 +1375,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
810
1375
  }], popupTemplate: [{
811
1376
  type: ViewChild,
812
1377
  args: ['popupTemplate', { static: true }]
1378
+ }], popupSectionTemplate: [{
1379
+ type: ViewChild,
1380
+ args: ['popupSectionTemplate', { static: true }]
1381
+ }], scrollContainer: [{
1382
+ type: ViewChild,
1383
+ args: ['scrollContainer', { read: ElementRef, static: false }]
813
1384
  }], resizeSensor: [{
814
1385
  type: ViewChild,
815
1386
  args: ['resizeSensor', { static: false }]
816
1387
  }], container: [{
817
1388
  type: ViewChild,
818
1389
  args: ['container', { read: ViewContainerRef, static: true }]
1390
+ }], prevScrollButton: [{
1391
+ type: ViewChild,
1392
+ args: ['prevScrollButton', { read: ElementRef }]
1393
+ }], nextScrollButton: [{
1394
+ type: ViewChild,
1395
+ args: ['nextScrollButton', { read: ElementRef }]
1396
+ }], startButtonGroup: [{
1397
+ type: ViewChild,
1398
+ args: ['startButtonGroup', { read: ElementRef }]
1399
+ }], endButtonGroup: [{
1400
+ type: ViewChild,
1401
+ args: ['endButtonGroup', { read: ElementRef }]
1402
+ }], scrollSeparator: [{
1403
+ type: ViewChild,
1404
+ args: ['scrollSeparator', { read: ElementRef }]
819
1405
  }], hostClass: [{
820
1406
  type: HostBinding,
821
1407
  args: ['class.k-toolbar']
1408
+ }], scrollableClass: [{
1409
+ type: HostBinding,
1410
+ args: ['class.k-toolbar-scrollable']
1411
+ }], sectionClass: [{
1412
+ type: HostBinding,
1413
+ args: ['class.k-toolbar-section']
822
1414
  }], onFocus: [{
823
1415
  type: HostListener,
824
1416
  args: ['focus', ['$event']]