| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /**
- * @license
- * Copyright 2018 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 { __assign, __extends } from "tslib";
- import { MDCFoundation } from '@material/base/foundation';
- import { numbers, strings } from './constants';
- var ACCEPTABLE_KEYS = new Set();
- // IE11 has no support for new Set with iterable so we need to initialize this
- // by hand
- ACCEPTABLE_KEYS.add(strings.ARROW_LEFT_KEY);
- ACCEPTABLE_KEYS.add(strings.ARROW_RIGHT_KEY);
- ACCEPTABLE_KEYS.add(strings.END_KEY);
- ACCEPTABLE_KEYS.add(strings.HOME_KEY);
- ACCEPTABLE_KEYS.add(strings.ENTER_KEY);
- ACCEPTABLE_KEYS.add(strings.SPACE_KEY);
- var KEYCODE_MAP = new Map();
- // IE11 has no support for new Map with iterable so we need to initialize this
- // by hand
- KEYCODE_MAP.set(numbers.ARROW_LEFT_KEYCODE, strings.ARROW_LEFT_KEY);
- KEYCODE_MAP.set(numbers.ARROW_RIGHT_KEYCODE, strings.ARROW_RIGHT_KEY);
- KEYCODE_MAP.set(numbers.END_KEYCODE, strings.END_KEY);
- KEYCODE_MAP.set(numbers.HOME_KEYCODE, strings.HOME_KEY);
- KEYCODE_MAP.set(numbers.ENTER_KEYCODE, strings.ENTER_KEY);
- KEYCODE_MAP.set(numbers.SPACE_KEYCODE, strings.SPACE_KEY);
- /** MDC Tab Bar Foundation */
- var MDCTabBarFoundation = /** @class */ (function (_super) {
- __extends(MDCTabBarFoundation, _super);
- function MDCTabBarFoundation(adapter) {
- var _this = _super.call(this, __assign(__assign({}, MDCTabBarFoundation.defaultAdapter), adapter)) || this;
- _this.useAutomaticActivation = false;
- return _this;
- }
- Object.defineProperty(MDCTabBarFoundation, "strings", {
- get: function () {
- return strings;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(MDCTabBarFoundation, "numbers", {
- get: function () {
- return numbers;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(MDCTabBarFoundation, "defaultAdapter", {
- get: function () {
- // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
- return {
- scrollTo: function () { return undefined; },
- incrementScroll: function () { return undefined; },
- getScrollPosition: function () { return 0; },
- getScrollContentWidth: function () { return 0; },
- getOffsetWidth: function () { return 0; },
- isRTL: function () { return false; },
- setActiveTab: function () { return undefined; },
- activateTabAtIndex: function () { return undefined; },
- deactivateTabAtIndex: function () { return undefined; },
- focusTabAtIndex: function () { return undefined; },
- getTabIndicatorClientRectAtIndex: function () {
- return ({ top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 });
- },
- getTabDimensionsAtIndex: function () {
- return ({ rootLeft: 0, rootRight: 0, contentLeft: 0, contentRight: 0 });
- },
- getPreviousActiveTabIndex: function () { return -1; },
- getFocusedTabIndex: function () { return -1; },
- getIndexOfTabById: function () { return -1; },
- getTabListLength: function () { return 0; },
- notifyTabActivated: function () { return undefined; },
- };
- // tslint:enable:object-literal-sort-keys
- },
- enumerable: false,
- configurable: true
- });
- /**
- * Switches between automatic and manual activation modes.
- * See https://www.w3.org/TR/wai-aria-practices/#tabpanel for examples.
- */
- MDCTabBarFoundation.prototype.setUseAutomaticActivation = function (useAutomaticActivation) {
- this.useAutomaticActivation = useAutomaticActivation;
- };
- MDCTabBarFoundation.prototype.activateTab = function (index) {
- var previousActiveIndex = this.adapter.getPreviousActiveTabIndex();
- if (!this.indexIsInRange(index) || index === previousActiveIndex) {
- return;
- }
- var previousClientRect;
- if (previousActiveIndex !== -1) {
- this.adapter.deactivateTabAtIndex(previousActiveIndex);
- previousClientRect =
- this.adapter.getTabIndicatorClientRectAtIndex(previousActiveIndex);
- }
- this.adapter.activateTabAtIndex(index, previousClientRect);
- this.scrollIntoView(index);
- this.adapter.notifyTabActivated(index);
- };
- MDCTabBarFoundation.prototype.handleKeyDown = function (evt) {
- // Get the key from the event
- var key = this.getKeyFromEvent(evt);
- // Early exit if the event key isn't one of the keyboard navigation keys
- if (key === undefined) {
- return;
- }
- // Prevent default behavior for movement keys, but not for activation keys,
- // since :active is used to apply ripple
- if (!this.isActivationKey(key)) {
- evt.preventDefault();
- }
- if (this.useAutomaticActivation && this.isActivationKey(key)) {
- return;
- }
- var focusedTabIndex = this.adapter.getFocusedTabIndex();
- if (this.isActivationKey(key)) {
- this.adapter.setActiveTab(focusedTabIndex);
- return;
- }
- var index = this.determineTargetFromKey(focusedTabIndex, key);
- this.adapter.focusTabAtIndex(index);
- this.scrollIntoView(index);
- if (this.useAutomaticActivation) {
- this.adapter.setActiveTab(index);
- }
- };
- /**
- * Handles the MDCTab:interacted event
- */
- MDCTabBarFoundation.prototype.handleTabInteraction = function (evt) {
- this.adapter.setActiveTab(this.adapter.getIndexOfTabById(evt.detail.tabId));
- };
- /**
- * Scrolls the tab at the given index into view
- * @param index The tab index to make visible
- */
- MDCTabBarFoundation.prototype.scrollIntoView = function (index) {
- // Early exit if the index is out of range
- if (!this.indexIsInRange(index)) {
- return;
- }
- // Always scroll to 0 if scrolling to the 0th index
- if (index === 0) {
- this.adapter.scrollTo(0);
- return;
- }
- // Always scroll to the max value if scrolling to the Nth index
- // MDCTabScroller.scrollTo() will never scroll past the max possible value
- if (index === this.adapter.getTabListLength() - 1) {
- this.adapter.scrollTo(this.adapter.getScrollContentWidth());
- return;
- }
- if (this.isRTL()) {
- this.scrollIntoViewImplRTL(index);
- return;
- }
- this.scrollIntoViewImpl(index);
- };
- /**
- * Private method for determining the index of the destination tab based on
- * what key was pressed
- * @param origin The original index from which to determine the destination
- * @param key The name of the key
- */
- MDCTabBarFoundation.prototype.determineTargetFromKey = function (origin, key) {
- var isRTL = this.isRTL();
- var maxIndex = this.adapter.getTabListLength() - 1;
- var shouldGoToEnd = key === strings.END_KEY;
- var shouldDecrement = key === strings.ARROW_LEFT_KEY && !isRTL ||
- key === strings.ARROW_RIGHT_KEY && isRTL;
- var shouldIncrement = key === strings.ARROW_RIGHT_KEY && !isRTL ||
- key === strings.ARROW_LEFT_KEY && isRTL;
- var index = origin;
- if (shouldGoToEnd) {
- index = maxIndex;
- }
- else if (shouldDecrement) {
- index -= 1;
- }
- else if (shouldIncrement) {
- index += 1;
- }
- else {
- index = 0;
- }
- if (index < 0) {
- index = maxIndex;
- }
- else if (index > maxIndex) {
- index = 0;
- }
- return index;
- };
- /**
- * Calculates the scroll increment that will make the tab at the given index
- * visible
- * @param index The index of the tab
- * @param nextIndex The index of the next tab
- * @param scrollPosition The current scroll position
- * @param barWidth The width of the Tab Bar
- */
- MDCTabBarFoundation.prototype.calculateScrollIncrement = function (index, nextIndex, scrollPosition, barWidth) {
- var nextTabDimensions = this.adapter.getTabDimensionsAtIndex(nextIndex);
- var relativeContentLeft = nextTabDimensions.contentLeft - scrollPosition - barWidth;
- var relativeContentRight = nextTabDimensions.contentRight - scrollPosition;
- var leftIncrement = relativeContentRight - numbers.EXTRA_SCROLL_AMOUNT;
- var rightIncrement = relativeContentLeft + numbers.EXTRA_SCROLL_AMOUNT;
- if (nextIndex < index) {
- return Math.min(leftIncrement, 0);
- }
- return Math.max(rightIncrement, 0);
- };
- /**
- * Calculates the scroll increment that will make the tab at the given index
- * visible in RTL
- * @param index The index of the tab
- * @param nextIndex The index of the next tab
- * @param scrollPosition The current scroll position
- * @param barWidth The width of the Tab Bar
- * @param scrollContentWidth The width of the scroll content
- */
- MDCTabBarFoundation.prototype.calculateScrollIncrementRTL = function (index, nextIndex, scrollPosition, barWidth, scrollContentWidth) {
- var nextTabDimensions = this.adapter.getTabDimensionsAtIndex(nextIndex);
- var relativeContentLeft = scrollContentWidth - nextTabDimensions.contentLeft - scrollPosition;
- var relativeContentRight = scrollContentWidth -
- nextTabDimensions.contentRight - scrollPosition - barWidth;
- var leftIncrement = relativeContentRight + numbers.EXTRA_SCROLL_AMOUNT;
- var rightIncrement = relativeContentLeft - numbers.EXTRA_SCROLL_AMOUNT;
- if (nextIndex > index) {
- return Math.max(leftIncrement, 0);
- }
- return Math.min(rightIncrement, 0);
- };
- /**
- * Determines the index of the adjacent tab closest to either edge of the Tab
- * Bar
- * @param index The index of the tab
- * @param tabDimensions The dimensions of the tab
- * @param scrollPosition The current scroll position
- * @param barWidth The width of the tab bar
- */
- MDCTabBarFoundation.prototype.findAdjacentTabIndexClosestToEdge = function (index, tabDimensions, scrollPosition, barWidth) {
- /**
- * Tabs are laid out in the Tab Scroller like this:
- *
- * Scroll Position
- * +---+
- * | | Bar Width
- * | +-----------------------------------+
- * | | |
- * | V V
- * | +-----------------------------------+
- * V | Tab Scroller |
- * +------------+--------------+-------------------+
- * | Tab | Tab | Tab |
- * +------------+--------------+-------------------+
- * | |
- * +-----------------------------------+
- *
- * To determine the next adjacent index, we look at the Tab root left and
- * Tab root right, both relative to the scroll position. If the Tab root
- * left is less than 0, then we know it's out of view to the left. If the
- * Tab root right minus the bar width is greater than 0, we know the Tab is
- * out of view to the right. From there, we either increment or decrement
- * the index.
- */
- var relativeRootLeft = tabDimensions.rootLeft - scrollPosition;
- var relativeRootRight = tabDimensions.rootRight - scrollPosition - barWidth;
- var relativeRootDelta = relativeRootLeft + relativeRootRight;
- var leftEdgeIsCloser = relativeRootLeft < 0 || relativeRootDelta < 0;
- var rightEdgeIsCloser = relativeRootRight > 0 || relativeRootDelta > 0;
- if (leftEdgeIsCloser) {
- return index - 1;
- }
- if (rightEdgeIsCloser) {
- return index + 1;
- }
- return -1;
- };
- /**
- * Determines the index of the adjacent tab closest to either edge of the Tab
- * Bar in RTL
- * @param index The index of the tab
- * @param tabDimensions The dimensions of the tab
- * @param scrollPosition The current scroll position
- * @param barWidth The width of the tab bar
- * @param scrollContentWidth The width of the scroller content
- */
- MDCTabBarFoundation.prototype.findAdjacentTabIndexClosestToEdgeRTL = function (index, tabDimensions, scrollPosition, barWidth, scrollContentWidth) {
- var rootLeft = scrollContentWidth - tabDimensions.rootLeft - barWidth - scrollPosition;
- var rootRight = scrollContentWidth - tabDimensions.rootRight - scrollPosition;
- var rootDelta = rootLeft + rootRight;
- var leftEdgeIsCloser = rootLeft > 0 || rootDelta > 0;
- var rightEdgeIsCloser = rootRight < 0 || rootDelta < 0;
- if (leftEdgeIsCloser) {
- return index + 1;
- }
- if (rightEdgeIsCloser) {
- return index - 1;
- }
- return -1;
- };
- /**
- * Returns the key associated with a keydown event
- * @param evt The keydown event
- */
- MDCTabBarFoundation.prototype.getKeyFromEvent = function (evt) {
- if (ACCEPTABLE_KEYS.has(evt.key)) {
- return evt.key;
- }
- return KEYCODE_MAP.get(evt.keyCode);
- };
- MDCTabBarFoundation.prototype.isActivationKey = function (key) {
- return key === strings.SPACE_KEY || key === strings.ENTER_KEY;
- };
- /**
- * Returns whether a given index is inclusively between the ends
- * @param index The index to test
- */
- MDCTabBarFoundation.prototype.indexIsInRange = function (index) {
- return index >= 0 && index < this.adapter.getTabListLength();
- };
- /**
- * Returns the view's RTL property
- */
- MDCTabBarFoundation.prototype.isRTL = function () {
- return this.adapter.isRTL();
- };
- /**
- * Scrolls the tab at the given index into view for left-to-right user agents.
- * @param index The index of the tab to scroll into view
- */
- MDCTabBarFoundation.prototype.scrollIntoViewImpl = function (index) {
- var scrollPosition = this.adapter.getScrollPosition();
- var barWidth = this.adapter.getOffsetWidth();
- var tabDimensions = this.adapter.getTabDimensionsAtIndex(index);
- var nextIndex = this.findAdjacentTabIndexClosestToEdge(index, tabDimensions, scrollPosition, barWidth);
- if (!this.indexIsInRange(nextIndex)) {
- return;
- }
- var scrollIncrement = this.calculateScrollIncrement(index, nextIndex, scrollPosition, barWidth);
- this.adapter.incrementScroll(scrollIncrement);
- };
- /**
- * Scrolls the tab at the given index into view in RTL
- * @param index The tab index to make visible
- */
- MDCTabBarFoundation.prototype.scrollIntoViewImplRTL = function (index) {
- var scrollPosition = this.adapter.getScrollPosition();
- var barWidth = this.adapter.getOffsetWidth();
- var tabDimensions = this.adapter.getTabDimensionsAtIndex(index);
- var scrollWidth = this.adapter.getScrollContentWidth();
- var nextIndex = this.findAdjacentTabIndexClosestToEdgeRTL(index, tabDimensions, scrollPosition, barWidth, scrollWidth);
- if (!this.indexIsInRange(nextIndex)) {
- return;
- }
- var scrollIncrement = this.calculateScrollIncrementRTL(index, nextIndex, scrollPosition, barWidth, scrollWidth);
- this.adapter.incrementScroll(scrollIncrement);
- };
- return MDCTabBarFoundation;
- }(MDCFoundation));
- export { MDCTabBarFoundation };
- // tslint:disable-next-line:no-default-export Needed for backward compatibility with MDC Web v0.44.0 and earlier.
- export default MDCTabBarFoundation;
- //# sourceMappingURL=foundation.js.map
|