@material/tabs
Version:
The Material Components for the web tabs component
248 lines • 12.9 kB
JavaScript
/**
* @license
* Copyright 2017 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import * as tslib_1 from "tslib";
import { MDCFoundation } from '@material/base/foundation';
import { cssClasses, strings } from './constants';
var INTERACTION_EVENTS = ['touchstart', 'mousedown', 'focus'];
var MDCTabBarScrollerFoundation = /** @class */ (function (_super) {
tslib_1.__extends(MDCTabBarScrollerFoundation, _super);
function MDCTabBarScrollerFoundation(adapter) {
var _this = _super.call(this, tslib_1.__assign({}, MDCTabBarScrollerFoundation.defaultAdapter, adapter)) || this;
_this.pointerDownRecognized_ = false;
_this.currentTranslateOffset_ = 0;
_this.focusedTarget_ = null;
_this.layoutFrame_ = 0;
_this.scrollFrameScrollLeft_ = 0;
_this.forwardIndicatorClickHandler_ = function (evt) { return _this.scrollForward(evt); };
_this.backIndicatorClickHandler_ = function (evt) { return _this.scrollBack(evt); };
_this.resizeHandler_ = function () { return _this.layout(); };
_this.interactionHandler_ = function (evt) {
if (evt.type === 'touchstart' || evt.type === 'mousedown') {
_this.pointerDownRecognized_ = true;
}
_this.handlePossibleTabKeyboardFocus_(evt);
if (evt.type === 'focus') {
_this.pointerDownRecognized_ = false;
}
};
return _this;
}
Object.defineProperty(MDCTabBarScrollerFoundation, "cssClasses", {
get: function () {
return cssClasses;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MDCTabBarScrollerFoundation, "strings", {
get: function () {
return strings;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MDCTabBarScrollerFoundation, "defaultAdapter", {
get: function () {
// tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
return {
addClass: function () { return undefined; },
removeClass: function () { return undefined; },
eventTargetHasClass: function () { return false; },
addClassToForwardIndicator: function () { return undefined; },
removeClassFromForwardIndicator: function () { return undefined; },
addClassToBackIndicator: function () { return undefined; },
removeClassFromBackIndicator: function () { return undefined; },
isRTL: function () { return false; },
registerBackIndicatorClickHandler: function () { return undefined; },
deregisterBackIndicatorClickHandler: function () { return undefined; },
registerForwardIndicatorClickHandler: function () { return undefined; },
deregisterForwardIndicatorClickHandler: function () { return undefined; },
registerCapturedInteractionHandler: function () { return undefined; },
deregisterCapturedInteractionHandler: function () { return undefined; },
registerWindowResizeHandler: function () { return undefined; },
deregisterWindowResizeHandler: function () { return undefined; },
getNumberOfTabs: function () { return 0; },
getComputedWidthForTabAtIndex: function () { return 0; },
getComputedLeftForTabAtIndex: function () { return 0; },
getOffsetWidthForScrollFrame: function () { return 0; },
getScrollLeftForScrollFrame: function () { return 0; },
setScrollLeftForScrollFrame: function () { return undefined; },
getOffsetWidthForTabBar: function () { return 0; },
setTransformStyleForTabBar: function () { return undefined; },
getOffsetLeftForEventTarget: function () { return 0; },
getOffsetWidthForEventTarget: function () { return 0; },
};
// tslint:enable:object-literal-sort-keys
},
enumerable: true,
configurable: true
});
MDCTabBarScrollerFoundation.prototype.init = function () {
var _this = this;
this.adapter_.registerBackIndicatorClickHandler(this.backIndicatorClickHandler_);
this.adapter_.registerForwardIndicatorClickHandler(this.forwardIndicatorClickHandler_);
this.adapter_.registerWindowResizeHandler(this.resizeHandler_);
INTERACTION_EVENTS.forEach(function (evtType) {
_this.adapter_.registerCapturedInteractionHandler(evtType, _this.interactionHandler_);
});
this.layout();
};
MDCTabBarScrollerFoundation.prototype.destroy = function () {
var _this = this;
this.adapter_.deregisterBackIndicatorClickHandler(this.backIndicatorClickHandler_);
this.adapter_.deregisterForwardIndicatorClickHandler(this.forwardIndicatorClickHandler_);
this.adapter_.deregisterWindowResizeHandler(this.resizeHandler_);
INTERACTION_EVENTS.forEach(function (evtType) {
_this.adapter_.deregisterCapturedInteractionHandler(evtType, _this.interactionHandler_);
});
};
MDCTabBarScrollerFoundation.prototype.scrollBack = function (evt) {
if (evt) {
evt.preventDefault();
}
var tabWidthAccumulator = 0;
var scrollTargetIndex = 0;
for (var i = this.adapter_.getNumberOfTabs() - 1; i > 0; i--) {
var tabOffsetLeft = this.adapter_.getComputedLeftForTabAtIndex(i);
var tabBarWidthLessTabOffsetLeft = this.adapter_.getOffsetWidthForTabBar() - tabOffsetLeft;
var tabIsNotOccluded = tabOffsetLeft > this.currentTranslateOffset_;
if (this.isRTL_()) {
tabIsNotOccluded = tabBarWidthLessTabOffsetLeft > this.currentTranslateOffset_;
}
if (tabIsNotOccluded) {
continue;
}
tabWidthAccumulator += this.adapter_.getComputedWidthForTabAtIndex(i);
var scrollTargetDetermined = tabWidthAccumulator > this.adapter_.getOffsetWidthForScrollFrame();
if (scrollTargetDetermined) {
scrollTargetIndex = this.isRTL_() ? i + 1 : i;
break;
}
}
this.scrollToTabAtIndex(scrollTargetIndex);
};
MDCTabBarScrollerFoundation.prototype.scrollForward = function (evt) {
if (evt) {
evt.preventDefault();
}
var scrollFrameOffsetWidth = this.adapter_.getOffsetWidthForScrollFrame() + this.currentTranslateOffset_;
var scrollTargetIndex = 0;
for (var i = 0; i < this.adapter_.getNumberOfTabs(); i++) {
var tabOffsetLeftAndWidth = this.adapter_.getComputedLeftForTabAtIndex(i) + this.adapter_.getComputedWidthForTabAtIndex(i);
var scrollTargetDetermined = tabOffsetLeftAndWidth > scrollFrameOffsetWidth;
if (this.isRTL_()) {
var frameOffsetAndTabWidth = scrollFrameOffsetWidth - this.adapter_.getComputedWidthForTabAtIndex(i);
var tabRightOffset = this.adapter_.getOffsetWidthForTabBar() - tabOffsetLeftAndWidth;
scrollTargetDetermined = tabRightOffset > frameOffsetAndTabWidth;
}
if (scrollTargetDetermined) {
scrollTargetIndex = i;
break;
}
}
this.scrollToTabAtIndex(scrollTargetIndex);
};
MDCTabBarScrollerFoundation.prototype.layout = function () {
var _this = this;
cancelAnimationFrame(this.layoutFrame_);
this.scrollFrameScrollLeft_ = this.adapter_.getScrollLeftForScrollFrame();
this.layoutFrame_ = requestAnimationFrame(function () { return _this.layout_(); });
};
MDCTabBarScrollerFoundation.prototype.scrollToTabAtIndex = function (index) {
var _this = this;
var scrollTargetOffsetLeft = this.adapter_.getComputedLeftForTabAtIndex(index);
var scrollTargetOffsetWidth = this.adapter_.getComputedWidthForTabAtIndex(index);
this.currentTranslateOffset_ =
this.normalizeForRTL_(scrollTargetOffsetLeft, scrollTargetOffsetWidth);
requestAnimationFrame(function () { return _this.shiftFrame_(); });
};
MDCTabBarScrollerFoundation.prototype.layout_ = function () {
var frameWidth = this.adapter_.getOffsetWidthForScrollFrame();
var isOverflowing = this.adapter_.getOffsetWidthForTabBar() > frameWidth;
if (!isOverflowing) {
this.currentTranslateOffset_ = 0;
}
this.shiftFrame_();
this.updateIndicatorEnabledStates_();
};
MDCTabBarScrollerFoundation.prototype.shiftFrame_ = function () {
var shiftAmount = this.isRTL_() ?
this.currentTranslateOffset_ : -this.currentTranslateOffset_;
this.adapter_.setTransformStyleForTabBar("translateX(" + shiftAmount + "px)");
this.updateIndicatorEnabledStates_();
};
MDCTabBarScrollerFoundation.prototype.handlePossibleTabKeyboardFocus_ = function (evt) {
var target = evt.target;
if (!this.adapter_.eventTargetHasClass(target, cssClasses.TAB) || this.pointerDownRecognized_) {
return;
}
var resetAmt = this.isRTL_() ? this.scrollFrameScrollLeft_ : 0;
this.adapter_.setScrollLeftForScrollFrame(resetAmt);
this.focusedTarget_ = target;
var scrollFrameWidth = this.adapter_.getOffsetWidthForScrollFrame();
var tabBarWidth = this.adapter_.getOffsetWidthForTabBar();
var leftEdge = this.adapter_.getOffsetLeftForEventTarget(this.focusedTarget_);
var rightEdge = leftEdge + this.adapter_.getOffsetWidthForEventTarget(this.focusedTarget_);
var shouldScrollBack = rightEdge <= this.currentTranslateOffset_;
var shouldScrollForward = rightEdge > this.currentTranslateOffset_ + scrollFrameWidth;
if (this.isRTL_()) {
var normalizedLeftOffset = tabBarWidth - leftEdge;
shouldScrollBack = leftEdge >= tabBarWidth - this.currentTranslateOffset_;
shouldScrollForward = normalizedLeftOffset > scrollFrameWidth + this.currentTranslateOffset_;
}
if (shouldScrollForward) {
this.scrollForward();
}
else if (shouldScrollBack) {
this.scrollBack();
}
this.pointerDownRecognized_ = false;
};
MDCTabBarScrollerFoundation.prototype.updateIndicatorEnabledStates_ = function () {
var INDICATOR_ENABLED = cssClasses.INDICATOR_ENABLED;
if (this.currentTranslateOffset_ === 0) {
this.adapter_.removeClassFromBackIndicator(INDICATOR_ENABLED);
}
else {
this.adapter_.addClassToBackIndicator(INDICATOR_ENABLED);
}
var remainingTabBarWidth = this.adapter_.getOffsetWidthForTabBar() - this.currentTranslateOffset_;
if (remainingTabBarWidth > this.adapter_.getOffsetWidthForScrollFrame()) {
this.adapter_.addClassToForwardIndicator(INDICATOR_ENABLED);
}
else {
this.adapter_.removeClassFromForwardIndicator(INDICATOR_ENABLED);
}
};
MDCTabBarScrollerFoundation.prototype.normalizeForRTL_ = function (left, width) {
return this.isRTL_() ? this.adapter_.getOffsetWidthForTabBar() - (left + width) : left;
};
MDCTabBarScrollerFoundation.prototype.isRTL_ = function () {
return this.adapter_.isRTL();
};
return MDCTabBarScrollerFoundation;
}(MDCFoundation));
export { MDCTabBarScrollerFoundation };
// tslint:disable-next-line:no-default-export Needed for backward compatibility with MDC Web v0.44.0 and earlier.
export default MDCTabBarScrollerFoundation;
//# sourceMappingURL=foundation.js.map