dockview-core 5.1.0 → 5.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.
@@ -19,6 +19,8 @@ export declare class Tab extends CompositeDisposable {
19
19
  readonly onDrop: Event<DroptargetEvent>;
20
20
  private readonly _onDragStart;
21
21
  readonly onDragStart: Event<DragEvent>;
22
+ private readonly _onDragEnd;
23
+ readonly onDragEnd: Event<DragEvent>;
22
24
  readonly onWillShowOverlay: Event<WillShowOverlayEvent>;
23
25
  get element(): HTMLElement;
24
26
  constructor(panel: IDockviewPanel, accessor: DockviewComponent, group: DockviewGroupPanel);
@@ -58,6 +58,8 @@ var Tab = /** @class */ (function (_super) {
58
58
  _this.onDrop = _this._onDropped.event;
59
59
  _this._onDragStart = new events_1.Emitter();
60
60
  _this.onDragStart = _this._onDragStart.event;
61
+ _this._onDragEnd = new events_1.Emitter();
62
+ _this.onDragEnd = _this._onDragEnd.event;
61
63
  _this._element = document.createElement('div');
62
64
  _this._element.className = 'dv-tab';
63
65
  _this._element.tabIndex = 0;
@@ -73,6 +75,10 @@ var Tab = /** @class */ (function (_super) {
73
75
  }
74
76
  var data = (0, dataTransfer_1.getPanelData)();
75
77
  if (data && _this.accessor.id === data.viewId) {
78
+ if (_this.accessor.options.tabAnimation === 'smooth' &&
79
+ data.groupId === _this.group.id) {
80
+ return false;
81
+ }
76
82
  return true;
77
83
  }
78
84
  return _this.group.model.canDisplayOverlay(event, position, 'tab');
@@ -80,7 +86,7 @@ var Tab = /** @class */ (function (_super) {
80
86
  getOverrideTarget: function () { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
81
87
  });
82
88
  _this.onWillShowOverlay = _this.dropTarget.onWillShowOverlay;
83
- _this.addDisposables(_this._onPointDown, _this._onDropped, _this._onDragStart, _this.dragHandler.onDragStart(function (event) {
89
+ _this.addDisposables(_this._onPointDown, _this._onDropped, _this._onDragStart, _this._onDragEnd, _this.dragHandler.onDragStart(function (event) {
84
90
  if (event.dataTransfer) {
85
91
  var style_1 = getComputedStyle(_this.element);
86
92
  var newNode_1 = _this.element.cloneNode(true);
@@ -94,6 +100,16 @@ var Tab = /** @class */ (function (_super) {
94
100
  });
95
101
  }
96
102
  _this._onDragStart.fire(event);
103
+ if (_this.accessor.options.tabAnimation === 'smooth') {
104
+ // Delay collapse to next frame so the browser
105
+ // captures the full drag image first
106
+ requestAnimationFrame(function () {
107
+ (0, dom_1.toggleClass)(_this.element, 'dv-tab--dragging', true);
108
+ });
109
+ }
110
+ }), (0, events_1.addDisposableListener)(_this._element, 'dragend', function (event) {
111
+ (0, dom_1.toggleClass)(_this.element, 'dv-tab--dragging', false);
112
+ _this._onDragEnd.fire(event);
97
113
  }), _this.dragHandler, (0, events_1.addDisposableListener)(_this._element, 'pointerdown', function (event) {
98
114
  _this._onPointDown.fire(event);
99
115
  }), _this.dropTarget.onDrop(function (event) {
@@ -18,6 +18,7 @@ export declare class Tabs extends CompositeDisposable {
18
18
  private selectedIndex;
19
19
  private _showTabsOverflowControl;
20
20
  private _direction;
21
+ private _animState;
21
22
  private readonly _onTabDragStart;
22
23
  readonly onTabDragStart: Event<TabDragEvent>;
23
24
  private readonly _onDrop;
@@ -48,4 +49,11 @@ export declare class Tabs extends CompositeDisposable {
48
49
  private addTab;
49
50
  private toggleDropdown;
50
51
  updateDragAndDropState(): void;
52
+ private snapshotTabPositions;
53
+ private getAverageTabWidth;
54
+ private handleDragOver;
55
+ private applyDragOverTransforms;
56
+ private resetTabTransforms;
57
+ private resetDragAnimation;
58
+ private runFlipAnimation;
51
59
  }
@@ -71,6 +71,7 @@ var Tabs = /** @class */ (function (_super) {
71
71
  _this.selectedIndex = -1;
72
72
  _this._showTabsOverflowControl = false;
73
73
  _this._direction = 'horizontal';
74
+ _this._animState = null;
74
75
  _this._onTabDragStart = new events_1.Emitter();
75
76
  _this.onTabDragStart = _this._onTabDragStart.event;
76
77
  _this._onDrop = new events_1.Emitter();
@@ -99,8 +100,89 @@ var Tabs = /** @class */ (function (_super) {
99
100
  if (isLeftClick) {
100
101
  _this.accessor.doSetGroupActive(_this.group);
101
102
  }
102
- }), lifecycle_1.Disposable.from(function () {
103
+ }), (0, events_1.addDisposableListener)(_this._tabsList, 'dragover', function (event) {
104
+ if (!_this._animState) {
105
+ // Check for external drag from another group
106
+ if (_this.accessor.options.tabAnimation !== 'smooth' ||
107
+ _this.accessor.options.disableDnd) {
108
+ return;
109
+ }
110
+ var data = (0, dataTransfer_1.getPanelData)();
111
+ if (data &&
112
+ data.panelId &&
113
+ data.groupId !== _this.group.id) {
114
+ _this._animState = {
115
+ sourceTabId: data.panelId,
116
+ sourceIndex: -1,
117
+ tabPositions: _this.snapshotTabPositions(),
118
+ currentInsertionIndex: null,
119
+ };
120
+ }
121
+ else {
122
+ return;
123
+ }
124
+ }
125
+ _this.handleDragOver(event);
126
+ }, true), (0, events_1.addDisposableListener)(_this._tabsList, 'dragleave', function (event) {
127
+ if (!_this._animState) {
128
+ return;
129
+ }
130
+ // Only handle if leaving the container itself, not moving between children
131
+ if (event.relatedTarget &&
132
+ _this._tabsList.contains(event.relatedTarget)) {
133
+ return;
134
+ }
135
+ _this.resetTabTransforms();
136
+ if (_this._animState) {
137
+ if (_this._animState.sourceIndex === -1) {
138
+ // External drag left — clear state entirely
139
+ // (no dragend will fire on this tab list)
140
+ _this._animState = null;
141
+ }
142
+ else {
143
+ _this._animState.currentInsertionIndex = null;
144
+ }
145
+ }
146
+ }, true), (0, events_1.addDisposableListener)(_this._tabsList, 'dragend', function () {
147
+ // Only fires for cancel (not after successful drop, since
148
+ // source tab is removed from DOM and doesn't bubble)
149
+ _this.resetDragAnimation();
150
+ }), (0, events_1.addDisposableListener)(_this._tabsList, 'drop', function (event) {
151
+ if (_this.accessor.options.tabAnimation !== 'smooth' ||
152
+ !_this._animState ||
153
+ _this._animState.currentInsertionIndex === null) {
154
+ return;
155
+ }
156
+ event.stopPropagation();
157
+ event.preventDefault();
158
+ var animState = _this._animState;
159
+ _this._animState = null;
160
+ var insertionIndex = animState.currentInsertionIndex;
161
+ var sourceIndex = animState.sourceIndex;
162
+ // After the source tab is removed, indices after it shift
163
+ // down by one, so adjust the target index accordingly.
164
+ var adjustedIndex = insertionIndex -
165
+ (sourceIndex !== -1 && sourceIndex < insertionIndex
166
+ ? 1
167
+ : 0);
168
+ // No-op: drop at the same position, nothing to animate
169
+ if (adjustedIndex === sourceIndex) {
170
+ _this.resetTabTransforms();
171
+ return;
172
+ }
173
+ // Snapshot current visual positions (with margins still applied)
174
+ // before resetting transforms, so FLIP starts from what the
175
+ // user currently sees — not from a teleported state.
176
+ var firstPositions = _this.snapshotTabPositions();
177
+ _this.resetTabTransforms();
178
+ _this._onDrop.fire({ event: event, index: adjustedIndex });
179
+ _this.runFlipAnimation(firstPositions, animState.sourceTabId, animState.sourceIndex === -1, {
180
+ from: Math.min(sourceIndex, adjustedIndex),
181
+ to: Math.max(sourceIndex, adjustedIndex),
182
+ });
183
+ }, true), lifecycle_1.Disposable.from(function () {
103
184
  var e_1, _a;
185
+ _this.resetDragAnimation();
104
186
  try {
105
187
  for (var _b = __values(_this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
106
188
  var _d = _c.value, value = _d.value, disposable = _d.disposable;
@@ -239,6 +321,14 @@ var Tabs = /** @class */ (function (_super) {
239
321
  tab.setContent(panel.view.tab);
240
322
  var disposable = new lifecycle_1.CompositeDisposable(tab.onDragStart(function (event) {
241
323
  _this._onTabDragStart.fire({ nativeEvent: event, panel: panel });
324
+ if (_this.accessor.options.tabAnimation === 'smooth') {
325
+ _this._animState = {
326
+ sourceTabId: panel.id,
327
+ sourceIndex: _this._tabs.findIndex(function (x) { return x.value === tab; }),
328
+ tabPositions: _this.snapshotTabPositions(),
329
+ currentInsertionIndex: null,
330
+ };
331
+ }
242
332
  }), tab.onPointerDown(function (event) {
243
333
  if (event.defaultPrevented) {
244
334
  return;
@@ -268,10 +358,29 @@ var Tabs = /** @class */ (function (_super) {
268
358
  break;
269
359
  }
270
360
  }), tab.onDrop(function (event) {
271
- _this._onDrop.fire({
272
- event: event.nativeEvent,
273
- index: _this._tabs.findIndex(function (x) { return x.value === tab; }),
274
- });
361
+ var animState = _this._animState;
362
+ _this._animState = null;
363
+ var dropIndex = _this._tabs.findIndex(function (x) { return x.value === tab; });
364
+ if (animState) {
365
+ var firstPositions = _this.snapshotTabPositions();
366
+ _this.resetTabTransforms();
367
+ _this._onDrop.fire({
368
+ event: event.nativeEvent,
369
+ index: dropIndex,
370
+ });
371
+ _this.runFlipAnimation(firstPositions, animState.sourceTabId, animState.sourceIndex === -1, animState.sourceIndex !== -1
372
+ ? {
373
+ from: Math.min(animState.sourceIndex, dropIndex),
374
+ to: Math.max(animState.sourceIndex, dropIndex),
375
+ }
376
+ : undefined);
377
+ }
378
+ else {
379
+ _this._onDrop.fire({
380
+ event: event.nativeEvent,
381
+ index: dropIndex,
382
+ });
383
+ }
275
384
  }), tab.onWillShowOverlay(function (event) {
276
385
  _this._onWillShowOverlay.fire(new events_2.DockviewWillShowOverlayLocationEvent(event, {
277
386
  kind: 'tab',
@@ -283,14 +392,29 @@ var Tabs = /** @class */ (function (_super) {
283
392
  }));
284
393
  var value = { value: tab, disposable: disposable };
285
394
  this.addTab(value, index);
395
+ // If a tab was added during active drag, refresh positions
396
+ if (this._animState) {
397
+ this._animState.tabPositions = this.snapshotTabPositions();
398
+ this.applyDragOverTransforms();
399
+ }
286
400
  };
287
401
  Tabs.prototype.delete = function (id) {
402
+ var _a;
403
+ if (((_a = this._animState) === null || _a === void 0 ? void 0 : _a.sourceTabId) === id) {
404
+ this.resetTabTransforms();
405
+ this._animState = null;
406
+ }
288
407
  var index = this.indexOf(id);
289
408
  var tabToRemove = this._tabs.splice(index, 1)[0];
290
409
  var value = tabToRemove.value, disposable = tabToRemove.disposable;
291
410
  disposable.dispose();
292
411
  value.dispose();
293
412
  value.element.remove();
413
+ // If a non-source tab was removed during active drag, refresh positions
414
+ if (this._animState) {
415
+ this._animState.tabPositions = this.snapshotTabPositions();
416
+ this.applyDragOverTransforms();
417
+ }
294
418
  };
295
419
  Tabs.prototype.addTab = function (tab, index) {
296
420
  if (index === void 0) { index = this._tabs.length; }
@@ -332,6 +456,229 @@ var Tabs = /** @class */ (function (_super) {
332
456
  finally { if (e_3) throw e_3.error; }
333
457
  }
334
458
  };
459
+ Tabs.prototype.snapshotTabPositions = function () {
460
+ var e_4, _a;
461
+ var positions = new Map();
462
+ try {
463
+ for (var _b = __values(this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
464
+ var tab = _c.value;
465
+ positions.set(tab.value.panel.id, tab.value.element.getBoundingClientRect());
466
+ }
467
+ }
468
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
469
+ finally {
470
+ try {
471
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
472
+ }
473
+ finally { if (e_4) throw e_4.error; }
474
+ }
475
+ return positions;
476
+ };
477
+ Tabs.prototype.getAverageTabWidth = function () {
478
+ var e_5, _a;
479
+ if (this._tabs.length === 0) {
480
+ return 0;
481
+ }
482
+ var totalWidth = 0;
483
+ try {
484
+ for (var _b = __values(this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
485
+ var tab = _c.value;
486
+ totalWidth += tab.value.element.getBoundingClientRect().width;
487
+ }
488
+ }
489
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
490
+ finally {
491
+ try {
492
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
493
+ }
494
+ finally { if (e_5) throw e_5.error; }
495
+ }
496
+ return totalWidth / this._tabs.length;
497
+ };
498
+ Tabs.prototype.handleDragOver = function (event) {
499
+ if (!this._animState) {
500
+ return;
501
+ }
502
+ var mouseX = event.clientX;
503
+ var insertionIndex = null;
504
+ for (var i = 0; i < this._tabs.length; i++) {
505
+ var tab = this._tabs[i].value;
506
+ if (tab.panel.id === this._animState.sourceTabId) {
507
+ continue;
508
+ }
509
+ var rect = tab.element.getBoundingClientRect();
510
+ var midpoint = rect.left + rect.width / 2;
511
+ if (mouseX < midpoint) {
512
+ insertionIndex = i;
513
+ break;
514
+ }
515
+ insertionIndex = i + 1;
516
+ }
517
+ if (insertionIndex === this._animState.currentInsertionIndex) {
518
+ return;
519
+ }
520
+ this._animState.currentInsertionIndex = insertionIndex;
521
+ this.applyDragOverTransforms();
522
+ };
523
+ Tabs.prototype.applyDragOverTransforms = function () {
524
+ if (!this._animState ||
525
+ this._animState.currentInsertionIndex === null) {
526
+ this.resetTabTransforms();
527
+ return;
528
+ }
529
+ var insertionIndex = this._animState.currentInsertionIndex;
530
+ var sourceRect = this._animState.tabPositions.get(this._animState.sourceTabId);
531
+ var gapWidth = sourceRect
532
+ ? sourceRect.width
533
+ : this.getAverageTabWidth();
534
+ // Find the first non-source tab at insertionIndex to receive the gap margin
535
+ var gapApplied = false;
536
+ var _loop_1 = function (i) {
537
+ var tab = this_1._tabs[i].value;
538
+ if (tab.panel.id === this_1._animState.sourceTabId) {
539
+ return "continue";
540
+ }
541
+ if (!gapApplied && i >= insertionIndex) {
542
+ tab.element.style.marginLeft = "".concat(gapWidth, "px");
543
+ (0, dom_1.toggleClass)(tab.element, 'dv-tab--shifting', true);
544
+ gapApplied = true;
545
+ }
546
+ else {
547
+ // Keep shifting class while margin animates back to 0,
548
+ // then remove both once the transition ends
549
+ if (tab.element.style.marginLeft) {
550
+ tab.element.style.marginLeft = '0px';
551
+ (0, dom_1.toggleClass)(tab.element, 'dv-tab--shifting', true);
552
+ var onEnd_1 = function () {
553
+ tab.element.style.removeProperty('margin-left');
554
+ (0, dom_1.toggleClass)(tab.element, 'dv-tab--shifting', false);
555
+ tab.element.removeEventListener('transitionend', onEnd_1);
556
+ };
557
+ tab.element.addEventListener('transitionend', onEnd_1);
558
+ }
559
+ else {
560
+ (0, dom_1.toggleClass)(tab.element, 'dv-tab--shifting', false);
561
+ }
562
+ }
563
+ };
564
+ var this_1 = this;
565
+ for (var i = 0; i < this._tabs.length; i++) {
566
+ _loop_1(i);
567
+ }
568
+ };
569
+ Tabs.prototype.resetTabTransforms = function () {
570
+ var e_6, _a;
571
+ try {
572
+ for (var _b = __values(this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
573
+ var tab = _c.value;
574
+ tab.value.element.style.removeProperty('margin-left');
575
+ tab.value.element.style.removeProperty('transform');
576
+ (0, dom_1.toggleClass)(tab.value.element, 'dv-tab--shifting', false);
577
+ }
578
+ }
579
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
580
+ finally {
581
+ try {
582
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
583
+ }
584
+ finally { if (e_6) throw e_6.error; }
585
+ }
586
+ };
587
+ Tabs.prototype.resetDragAnimation = function () {
588
+ var e_7, _a;
589
+ this.resetTabTransforms();
590
+ this._animState = null;
591
+ try {
592
+ for (var _b = __values(this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
593
+ var tab = _c.value;
594
+ (0, dom_1.toggleClass)(tab.value.element, 'dv-tab--dragging', false);
595
+ }
596
+ }
597
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
598
+ finally {
599
+ try {
600
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
601
+ }
602
+ finally { if (e_7) throw e_7.error; }
603
+ }
604
+ };
605
+ Tabs.prototype.runFlipAnimation = function (firstPositions, sourceTabId, isCrossGroup, animRange) {
606
+ var _this = this;
607
+ if (isCrossGroup === void 0) { isCrossGroup = false; }
608
+ var hasAnimation = false;
609
+ for (var i = 0; i < this._tabs.length; i++) {
610
+ var tab = this._tabs[i];
611
+ var panelId = tab.value.panel.id;
612
+ if (panelId === sourceTabId) {
613
+ if (isCrossGroup) {
614
+ // Newly inserted tab: slide in from the right
615
+ var rect = tab.value.element.getBoundingClientRect();
616
+ tab.value.element.style.transform = "translateX(".concat(rect.width, "px)");
617
+ (0, dom_1.toggleClass)(tab.value.element, 'dv-tab--shifting', true);
618
+ hasAnimation = true;
619
+ }
620
+ continue;
621
+ }
622
+ // Skip tabs outside the affected range (they don't logically move)
623
+ if (animRange !== undefined &&
624
+ (i < animRange.from || i > animRange.to)) {
625
+ continue;
626
+ }
627
+ var firstRect = firstPositions.get(panelId);
628
+ if (!firstRect) {
629
+ continue;
630
+ }
631
+ var lastRect = tab.value.element.getBoundingClientRect();
632
+ var deltaX = firstRect.left - lastRect.left;
633
+ if (Math.abs(deltaX) < 1) {
634
+ continue;
635
+ }
636
+ tab.value.element.style.transform = "translateX(".concat(deltaX, "px)");
637
+ (0, dom_1.toggleClass)(tab.value.element, 'dv-tab--shifting', true);
638
+ hasAnimation = true;
639
+ }
640
+ if (!hasAnimation) {
641
+ return;
642
+ }
643
+ requestAnimationFrame(function () {
644
+ var e_8, _a;
645
+ try {
646
+ for (var _b = __values(_this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
647
+ var tab = _c.value;
648
+ if (tab.value.element.style.transform) {
649
+ tab.value.element.style.transform = '';
650
+ }
651
+ }
652
+ }
653
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
654
+ finally {
655
+ try {
656
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
657
+ }
658
+ finally { if (e_8) throw e_8.error; }
659
+ }
660
+ var onTransitionEnd = function (event) {
661
+ var e_9, _a;
662
+ if (event.propertyName === 'transform') {
663
+ _this._tabsList.removeEventListener('transitionend', onTransitionEnd);
664
+ try {
665
+ for (var _b = __values(_this._tabs), _c = _b.next(); !_c.done; _c = _b.next()) {
666
+ var tab = _c.value;
667
+ (0, dom_1.toggleClass)(tab.value.element, 'dv-tab--shifting', false);
668
+ }
669
+ }
670
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
671
+ finally {
672
+ try {
673
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
674
+ }
675
+ finally { if (e_9) throw e_9.error; }
676
+ }
677
+ }
678
+ };
679
+ _this._tabsList.addEventListener('transitionend', onTransitionEnd);
680
+ });
681
+ };
335
682
  return Tabs;
336
683
  }(lifecycle_1.CompositeDisposable));
337
684
  exports.Tabs = Tabs;
@@ -69,7 +69,20 @@ export interface DockviewOptions {
69
69
  * This is only applied to the tab header section. Defaults to `custom`.
70
70
  */
71
71
  scrollbars?: 'native' | 'custom';
72
+ /**
73
+ * Controls tab drag-and-drop reorder animation style.
74
+ *
75
+ * - `"smooth"`: tabs animate smoothly during drag-and-drop reorder —
76
+ * tabs slide apart to reveal the insertion gap, then animate to their
77
+ * final positions on drop (Chrome-like behavior).
78
+ * - `"default"`: standard tab reorder behavior without animation.
79
+ *
80
+ * Defaults to `"default"`.
81
+ */
82
+ tabAnimation?: TabAnimation;
72
83
  }
84
+ export type TabAnimation = 'smooth' | 'default';
85
+ export declare const DEFAULT_TAB_ANIMATION: TabAnimation;
73
86
  export interface DockviewDndOverlayEvent extends IAcceptableEvent {
74
87
  nativeEvent: DragEvent;
75
88
  target: DockviewGroupDropLocation;
@@ -15,8 +15,9 @@ var __extends = (this && this.__extends) || (function () {
15
15
  };
16
16
  })();
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.isGroupOptionsWithGroup = exports.isGroupOptionsWithPanel = exports.isPanelOptionsWithGroup = exports.isPanelOptionsWithPanel = exports.PROPERTY_KEYS_DOCKVIEW = exports.DockviewUnhandledDragOverEvent = void 0;
18
+ exports.isGroupOptionsWithGroup = exports.isGroupOptionsWithPanel = exports.isPanelOptionsWithGroup = exports.isPanelOptionsWithPanel = exports.PROPERTY_KEYS_DOCKVIEW = exports.DockviewUnhandledDragOverEvent = exports.DEFAULT_TAB_ANIMATION = void 0;
19
19
  var events_1 = require("../events");
20
+ exports.DEFAULT_TAB_ANIMATION = 'default';
20
21
  var DockviewUnhandledDragOverEvent = /** @class */ (function (_super) {
21
22
  __extends(DockviewUnhandledDragOverEvent, _super);
22
23
  function DockviewUnhandledDragOverEvent(nativeEvent, target, position, getData, group) {
@@ -55,6 +56,7 @@ exports.PROPERTY_KEYS_DOCKVIEW = (function () {
55
56
  theme: undefined,
56
57
  disableTabsOverflowList: undefined,
57
58
  scrollbars: undefined,
59
+ tabAnimation: undefined,
58
60
  };
59
61
  return Object.keys(properties);
60
62
  })();