diff --git a/packages/main/src/Tab.js b/packages/main/src/Tab.js index 882f13898f0b..bc9a3559518e 100644 --- a/packages/main/src/Tab.js +++ b/packages/main/src/Tab.js @@ -1,9 +1,8 @@ import Bootstrap from "@ui5/webcomponents-base/src/Bootstrap"; import URI from "@ui5/webcomponents-base/src/types/URI"; -import Integer from "@ui5/webcomponents-base/src/types/Integer"; +import Function from "@ui5/webcomponents-base/src/types/Function"; import TabBase from "./TabBase"; import TabTemplateContext from "./TabTemplateContext"; -import TabDesignMode from "./types/TabDesignMode"; import IconColor from "./types/IconColor"; import Icon from "./Icon"; import TabRenderer from "./build/compiled/TabRenderer.lit"; @@ -47,14 +46,15 @@ const metadata = { */ disabled: { type: Boolean, + defaultValue: false, }, /** - * Represents the "count" text, which is displayed in the tab filter. + * Represents the "additionalText" text, which is displayed in the tab filter. * @type {String} * @public */ - count: { + additionalText: { type: String, defaultValue: "", }, @@ -85,27 +85,19 @@ const metadata = { defaultValue: IconColor.Default, }, - /** - * Specifies whether the icon and the texts are placed vertically or horizontally. - * @type {TabDesignMode} - * @public - */ - design: { - type: TabDesignMode, - defaultValue: TabDesignMode.Vertical, + selected: { + type: Boolean, + defaultValue: false, + }, + + _tabIndex: { + type: String, + defaultValue: "-1", }, - _showAll: { type: Boolean }, - _isSelected: { type: Boolean, defaultValue: false }, - _isInline: { type: Boolean }, - _isNoIcon: { type: Boolean }, - _isNoText: { type: Boolean }, - _tabIndex: { type: String, defaultValue: "-1" }, - _posinset: { type: Integer }, - _setsize: { type: Integer }, - _contentId: { type: String, defaultValue: " " }, - _labelledbyControls: { type: String, defaultValue: " " }, - _isIconColorRead: { type: Boolean }, + _getTabContainerHeaderItemCallback: { + type: Function, + }, }, events: /** @lends sap.ui.webcomponents.main.Tab.prototype */ { @@ -143,6 +135,16 @@ class Tab extends TabBase { super.define(...params); } + + getFocusDomRef() { + let focusedDomRef = super.getFocusDomRef(); + + if (this._getTabContainerHeaderItemCallback) { + focusedDomRef = this._getTabContainerHeaderItemCallback(); + } + + return focusedDomRef; + } } Bootstrap.boot().then(_ => { diff --git a/packages/main/src/TabBase.js b/packages/main/src/TabBase.js index db9d8cc205a5..e5c754d07401 100644 --- a/packages/main/src/TabBase.js +++ b/packages/main/src/TabBase.js @@ -24,6 +24,10 @@ class TabBase extends WebComponent { static get metadata() { return metadata; } + + isSeparator() { + return false; + } } export default TabBase; diff --git a/packages/main/src/TabContainer.hbs b/packages/main/src/TabContainer.hbs index c2fb33fca126..bc50ec27da80 100644 --- a/packages/main/src/TabContainer.hbs +++ b/packages/main/src/TabContainer.hbs @@ -1,155 +1,146 @@
index="0"
.
- *
- * @type {String}
- * @public
- */
- selectedIndex: {
- type: String,
- defaultValue: null,
- },
-
- /**
- * Specifies the background color of the IconTabBar.
- * Solid
(default), Translucent
, or Transparent
.
- *
- * @type {BackgroundDesign}
- * @public
- * @defaultvalue BackgroundDesign.Solid
- */
- backgroundDesign: {
- type: BackgroundDesign,
- defaultValue: BackgroundDesign.Solid,
- },
-
- /**
- * Specifies the header mode. Available options are: Standard
and Inline
.
- * Standard
mode the count
and the text
- * are displayed in two separate lines.
- * In Inline
mode the count
and the text
- * are displayed in single line.
- * Inline
mode works only when no icons are set.
- *
- * @type {TabContainerHeaderMode}
- * @public
- */
- headerMode: {
- type: TabContainerHeaderMode,
- defaultValue: TabContainerHeaderMode.Standard,
- },
-
/**
* Specifies if the overflow select list is displayed.
* Solid
(default), Translucent
, or Transparent
.
- *
- * @type {BackgroundDesign}
- * @public
- */
- headerBackgroundDesign: {
- type: BackgroundDesign,
- defaultValue: BackgroundDesign.Solid,
+ _headerItem: {
+ type: Object,
},
- _selectedContent: {
- type: HTMLElement,
- multiple: true,
- association: true,
+ _overflowButton: {
+ type: Object,
},
- _selectedTab: {
- type: Tab,
- association: true,
+ _headerBackArrow: {
+ type: Object,
},
- _scrollable: { type: Boolean },
- _scrollForward: { type: Boolean },
- _scrollBack: { type: Boolean },
-
- _isNoIcon: { type: Boolean },
- _isNoText: { type: Boolean },
- _isNoIconAndCount: { type: Boolean },
+ _headerForwardArrow: {
+ type: Object,
+ },
- _isInline: { type: Boolean },
+ _overflowList: {
+ type: Object,
+ },
- _leftArrow: { type: Object },
- _rightArrow: { type: Object },
+ _selectedTab: {
+ type: TabBase,
+ association: true,
+ },
- _overflowButton: { type: Object },
- _overflowList: { type: Object },
+ _scrollable: {
+ type: Boolean,
+ },
- _headerItems: { type: Object, multiple: true },
+ _scrollableBack: {
+ type: Boolean,
+ },
- _navigationItems: { type: Object, multiple: true },
+ _scrollableForward: {
+ type: Boolean,
+ },
},
events: /** @lends sap.ui.webcomponents.main.TabContainer.prototype */ {
/**
@@ -218,8 +133,6 @@ const metadata = {
},
};
-const scrollStep = 128;
-
/**
* @class
*
@@ -260,508 +173,185 @@ class TabContainer extends WebComponent {
return TabContainerRenderer;
}
- static _checkIfNoIcon(tabs) {
- for (let i = 0; i < tabs.length; i++) {
- if (tabs[i].icon) {
- return false;
- }
- }
-
- return true;
- }
-
- static _checkIfNoText(tabs) {
- for (let i = 0; i < tabs.length; i++) {
- if (tabs[i].text) {
- return false;
- }
- }
-
- return true;
- }
-
- static _checkIfNoIconAndCount(tabs) {
- let tab;
-
- for (let i = 0; i < tabs.length; i++) {
- tab = tabs[i];
- if (tab.icon || tab.count) {
- return false;
- }
- }
-
- return true;
- }
-
- static _findClosestTab(target) {
- let maxLevel = 4;
-
- while (target && maxLevel) {
- if (target.classList.contains("sapMITBItem")) {
- return target;
- }
-
- target = target.parentElement;
- maxLevel--;
- }
- }
-
constructor() {
super();
- this._updateScrollingHandler = this._updateScrolling.bind(this);
-
- this._scrollEnablement = new ScrollEnablement();
- this._scrollEnablement.attachEvent("scroll", this._updateScrollingHandler);
- this._delegates.push(this._scrollEnablement);
+ this._onHeaderItemSelect = this._onHeaderItemSelect.bind(this);
+ this._onHeaderItemKeyDown = this._onHeaderItemKeyDown.bind(this);
+ this._onHeaderItemKeyUp = this._onHeaderItemKeyUp.bind(this);
+ this._onOverflowListItemSelect = this._onOverflowListItemSelect.bind(this);
+ this._onOverflowButtonClick = this._onOverflowButtonClick.bind(this);
+ this._onHeaderBackArrowClick = this._onHeaderBackArrowClick.bind(this);
+ this._onHeaderForwardArrowClick = this._onHeaderForwardArrowClick.bind(this);
+ this._handleHeaderResize = this._handleHeaderResize.bind(this);
+ this._updateScrolling = this._updateScrolling.bind(this);
+
+ this._headerItem = {
+ click: this._onHeaderItemSelect,
+ keydown: this._onHeaderItemKeyDown,
+ keyup: this._onHeaderItemKeyUp,
+ };
- this._leftArrow = {
- onPress: this._scrollLeft.bind(this),
- classes: "sapMITBArrowScroll sapMITHVerticallyCenteredArrow sapMITBArrowScrollLeft",
+ this._overflowButton = {
+ click: this._onOverflowButtonClick,
};
- this._rightArrow = {
- onPress: this._scrollRight.bind(this),
- classes: "sapMITBArrowScroll sapMITHVerticallyCenteredArrow sapMITBArrowScrollRight",
+ this._headerBackArrow = {
+ click: this._onHeaderBackArrowClick,
};
- this._overflowButton = {
- _customAttributes: {
- tabindex: -1,
- },
- onPress: this._openOverflowList.bind(this),
- classes: "",
+ this._headerForwardArrow = {
+ click: this._onHeaderForwardArrowClick,
};
this._overflowList = {
- onItemPress: this._overflowItemSelected.bind(this),
- items: [],
+ click: this._onOverflowListItemSelect,
};
- this._itemNavigation = new ItemNavigation(this, {
- cyclic: false,
- });
- this._delegates.push(this._itemNavigation);
-
- this._itemNavigation.getItemsCallback = function getItemsCallback() {
- return this._navigationItems;
- }.bind(this);
+ // Init ScrollEnablement
+ this._scrollEnablement = new ScrollEnablement();
+ this._scrollEnablement.attachEvent("scroll", this._updateScrolling);
+ this._delegates.push(this._scrollEnablement);
- this._itemNavigation.setItemsCallback = function setItemsCallback(items) {
- this._navigationItems = items;
- }.bind(this);
+ // Init ItemNavigation
+ this._initItemNavigation();
}
-
onBeforeRendering() {
- const tabs = this.getTabs();
-
- if (!tabs.length) {
- return;
- }
-
- this._initSelectedTab();
-
- this._isNoIcon = TabContainer._checkIfNoIcon(tabs);
- this._isNoText = TabContainer._checkIfNoText(tabs);
- this._isNoIconAndCount = TabContainer._checkIfNoIconAndCount(tabs);
- this._isInline = this._isNoIconAndCount
- || (this._isNoIcon && this.headerMode === TabContainerHeaderMode.Inline);
-
- const suffix = this._isNoIcon ? "TextOnly" : "";
-
- this._leftArrow.classes = `sapMITBArrowScroll sapMITHVerticallyCenteredArrow sapMITBArrowScrollLeft${suffix}`;
- this._rightArrow.classes = `sapMITBArrowScroll sapMITHVerticallyCenteredArrow sapMITBArrowScrollRight${suffix}`;
-
- if (this.showOverflow) {
- let buttonCustomClass = "";
-
- if (this._isInline) {
- buttonCustomClass = "sapMBtnInline";
- } else if (this._isNoIconAndCount) {
- buttonCustomClass = "sapMBtnTextOnly";
- } else if (this._isNoText) {
- buttonCustomClass = "sapMBtnNoText";
- }
+ const hasSelected = this.items.some(item => item.selected);
+ this.items.forEach(item => {
+ item._getTabContainerHeaderItemCallback = _ => {
+ return this.getDomRef().querySelector(`#${item._id}`);
+ };
+ });
- this._overflowButton.classes = `sapMITHBtn sapMITHVerticallyCenteredArrow ${buttonCustomClass}`;
+ if (!hasSelected) {
+ this.items[0].selected = true;
}
-
- this._prepareHeaderTabs();
- this._prepareOverflowList();
-
- this._itemNavigation.init();
}
onAfterRendering() {
- this._scrollEnablement.scrollContainer = this._getScrollContainer();
-
- if (!this._isFirstAfterRendering) {
- this._updateScrolling();
- this._scrollIntoView();
- this._isFirstAfterRendering = true;
- }
+ this._scrollEnablement.scrollContainer = this._getHeaderScrollContainer();
+ this._updateScrolling();
}
onEnterDOM() {
- ResizeHandler.register(this._getScrollContainer(), this._updateScrollingHandler);
+ ResizeHandler.register(this._getHeader(), this._handleHeaderResize);
}
onExitDOM() {
- ResizeHandler.deregister(this._getScrollContainer(), this._updateScrollingHandler);
- }
-
- _initSelectedTab() {
- const tabs = this.getTabs();
- const selectedTab = tabs[this._normalizeSelectedIndex(this.selectedIndex)];
- this.setSelectedTab(selectedTab);
+ ResizeHandler.deregister(this._getHeader(), this._handleHeaderResize);
}
- _normalizeSelectedIndex(index) {
- const tabs = this.getTabs();
- const parsedIndex = Number.parseInt(index);
-
- if (Number.isNaN(parsedIndex)) {
- return 0;
+ _onHeaderItemKeyDown(event) {
+ if (isEnter(event)) {
+ this._onHeaderItemSelect(event);
}
- if (parsedIndex < 0 || parsedIndex > tabs.length - 1) {
- return 0;
- }
-
- return parsedIndex;
- }
-
- _prepareHeaderTabs() {
- const items = this.items;
- const tabs = this.getTabs();
-
- let ariaIndex = 1;
- const length = tabs.length;
- const contentId = `${this._id}-content`;
-
- const headerItems = [];
- const navigationItems = [];
-
- items.forEach(tab => {
- if (tab instanceof TabSeparator) {
- headerItems.push({
- isSeparator: true,
- });
-
- return;
- }
-
- const isIconColorRead = tab.iconColor === IconColor.Positive
- || tab.iconColor === IconColor.Critical
- || tab.iconColor === IconColor.Negative;
-
- const isHorizontalDesign = tab.design === TabDesignMode.Horizontal;
-
- let displayText = tab.text;
- if (this._isInline && tab.count) {
- displayText += ` (${tab.count})`;
- }
-
- const ids = [];
-
- if (tab.text) {
- ids.push(`${tab._id}-text`);
- }
- if (tab.count) {
- ids.push(`${tab._id}-count`);
- }
- if (tab.icon) {
- ids.push(`${tab._id}-icon`);
- }
- if (isIconColorRead) {
- ids.push(`${tab._id}-iconColor`);
- }
-
- const labelledbyControls = ids.join(" ");
- const showAll = !this._isNoIcon && !tab.icon;
-
- const mainClasses = {
- sapMITBItem: true,
- sapMITBSelected: tab._isSelected,
- sapMITBItemNoCount: !tab.count,
- sapMITBHorizontal: isHorizontalDesign,
- sapMITBVertical: !isHorizontalDesign,
- sapMITBAll: showAll,
- sapMITBFilter: !showAll,
- sapMITBDisabled: !!tab.disabled,
- };
-
- if (isIconColorRead) {
- mainClasses[`sapMITBFilter${tab.iconColor}`] = true;
- }
- const headerItem = {
-
- id: `${tab._id}-header`,
- _tabIndex: this._navigationItems[ariaIndex - 1]
- ? this._navigationItems[ariaIndex - 1]._tabIndex : -1,
-
- isIconColorRead,
- labelledbyControls,
- displayText,
- isDisabled: tab.disabled ? true : undefined,
- isHorizontalDesign,
-
- text: tab.text,
- count: tab.count,
- icon: tab.icon,
- iconColor: tab.iconColor,
-
- isInline: this._isInline,
- isNoIcon: this._isNoIcon,
- isNoText: this._isNoText,
- isInlineOrTextOnly: this._isInline || this._isNoIcon,
-
- showAll,
-
- posinset: ariaIndex++,
- setsize: length,
- contentId,
- classes: {
- main: _convertSingleClass(mainClasses),
- },
- };
-
- headerItems.push(headerItem);
- navigationItems.push(headerItem);
- });
-
- this._headerItems = headerItems;
- this._navigationItems = navigationItems;
- }
-
- _prepareOverflowList() {
- if (!this.showOverflow) {
- return;
+ // Prevent Scrolling
+ if (isSpace(event)) {
+ event.preventDefault();
}
-
- const tabs = this.getTabs();
- const listItems = [];
-
- tabs.forEach(tab => {
- const isIconColorRead = tab.iconColor === IconColor.Positive
- || tab.iconColor === IconColor.Critical
- || tab.iconColor === IconColor.Negative;
-
- let displayText = tab.text;
- if (tab.count) {
- displayText += ` (${tab.count})`;
- }
-
- const overflowTab = {
- id: `${tab._id}-overflow`,
-
- isIconColorRead,
- displayText,
-
- text: tab.text,
- count: tab.count,
- icon: tab.icon,
- iconColor: tab.iconColor,
-
- _isInline: this._isInline,
- _isNoIcon: this._isNoIcon,
- _isNoText: this._isNoText,
- };
-
- const listItem = {
- id: tab._id,
- type: tab.disabled ? ListItemType.Inactive : ListItemType.Active,
- selected: tab._isSelected,
- content: overflowTab,
- classes: `sapMITBFilter${tab.iconColor}`,
- innerClasses: tab.disabled ? "sapMITBOverflowItem sapMITBDisabled" : "sapMITBOverflowItem",
- };
-
- listItems.push(listItem);
- });
-
- this._overflowList.items = listItems;
}
- _getScrollContainer() {
- const domRef = this.getDomRef();
- return domRef && domRef.querySelector(".sapMITBScrollContainer");
+ _onHeaderItemKeyUp(event) {
+ if (isSpace(event)) {
+ this._onHeaderItemSelect(event);
+ }
}
- _openOverflowList() {
- const popover = this.getDomRef().querySelector("ui5-popover");
- const overflowButton = this.getDomRef().querySelector("ui5-button");
+ _initItemNavigation() {
+ this._itemNavigation = new ItemNavigation(this);
+ this._itemNavigation.getItemsCallback = () => this._getTabs();
- popover.openBy(overflowButton);
+ this._delegates.push(this._itemNavigation);
}
- _overflowItemSelected(event) {
- const pressedItem = event.detail.item;
- const tabs = this.getTabs();
- const selectedTab = tabs.filter(item => item._id === pressedItem.id)[0];
-
- this.setSelectedTab(selectedTab, true /* user interaction */);
-
- const popover = this.getDomRef().querySelector("ui5-popover");
- popover.close();
-
- const headerTab = this.getDomRef().querySelector(`#${pressedItem.id}-header`);
- if (headerTab) {
- headerTab.focus();
+ _onHeaderItemSelect(event) {
+ if (!event.target.getAttribute("disabled")) {
+ this._onItemSelect(event.target);
}
}
- _scrollIntoView() {
- if (!this._scrollable) {
- return;
- }
-
- const selectedTab = this.getSelectedTab();
- if (!selectedTab) {
- return;
- }
+ _onOverflowListItemSelect(event) {
+ this._onItemSelect(event.detail.item);
+ this._getPopover().close();
+ this.shadowRoot.querySelector(`#${event.detail.item.id}`).focus();
+ }
- const scrollContainer = this._getScrollContainer();
- const scrollContainerWidth = scrollContainer.offsetWidth;
+ _onItemSelect(target) {
+ const selectedIndex = findIndex(this.items, item => item._id === target.id);
+ const selectedTabIndex = findIndex(this._getTabs(), item => item._id === target.id);
+ const currentSelectedTab = this.items[selectedIndex];
- const tabContainerDomRef = this.getDomRef();
- const headerTabDomRef = tabContainerDomRef.querySelector(`#${selectedTab._id}-header`);
+ // update selected items
+ this.items.forEach((item, index) => {
+ if (!item.isSeparator()) {
+ const selected = selectedIndex === index;
+ item.selected = selected;
- const itemLeft = headerTabDomRef.offsetLeft - scrollContainer.scrollLeft;
- const itemRight = itemLeft + headerTabDomRef.offsetWidth;
+ if (selected) {
+ this._itemNavigation.current = selectedTabIndex;
+ }
+ }
+ }, this);
- if (itemLeft < 0) {
- scrollContainer.scrollLeft += itemLeft;
- } else if (itemRight > scrollContainerWidth) {
- scrollContainer.scrollLeft += itemRight - scrollContainerWidth;
+ // update collapsed state
+ if (!this.fixed) {
+ if (currentSelectedTab === this._selectedTab) {
+ this.collapsed = !this.collapsed;
+ } else {
+ this.collapsed = false;
+ }
}
- this._updateScrolling();
+ // select the tab
+ this._selectedTab = currentSelectedTab;
+ this.fireEvent("itemSelect", {
+ item: currentSelectedTab,
+ });
}
- _updateScrolling() {
- const scrollContainer = this._getScrollContainer();
- if (!scrollContainer) {
- return;
- }
-
- const scrollContainerContent = scrollContainer.querySelector(".sapMITBHead");
-
- const scrollContainerWidth = scrollContainer.offsetWidth;
- const scrollContainerContentWidth = scrollContainerContent.offsetWidth;
-
- if (scrollContainerWidth >= scrollContainerContentWidth) {
- this._scrollable = false;
- this._scrollForward = false;
- this._scrollBack = false;
- } else {
- this._scrollable = true;
- this._scrollForward = scrollContainer.scrollLeft
- + scrollContainerWidth < scrollContainerContentWidth;
- this._scrollBack = scrollContainer.scrollLeft > 0;
- }
+ _onOverflowButtonClick(event) {
+ this._getPopover().openBy(event.target);
}
- _scrollLeft() {
- this._scrollEnablement.move(-scrollStep, 0).promise()
+ _onHeaderBackArrowClick() {
+ this._scrollEnablement.move(-SCROLL_STEP, 0).promise()
.then(_ => this._updateScrolling());
}
- _scrollRight() {
- this._scrollEnablement.move(scrollStep, 0).promise()
+ _onHeaderForwardArrowClick() {
+ this._scrollEnablement.move(SCROLL_STEP, 0).promise()
.then(_ => this._updateScrolling());
}
- _findSelectedTab(event) {
- const tabElement = TabContainer._findClosestTab(event.ui5target);
- if (!tabElement) {
- return;
- }
-
- const tabs = this.getTabs();
- return tabs.filter(item => `${item._id}-header` === tabElement.id)[0];
+ _handleHeaderResize() {
+ this._updateScrolling();
}
- setSelectedTab(tab, userInteraction) {
- if (!tab || tab.disabled) {
- return;
- }
-
- const tabs = this.getTabs();
-
- if (!tabs.length) {
- return;
- }
-
- this._selectedContent = tab._state.content.length ? [tab] : this._state.content;
-
- if (this._selectedTab === tab) {
- if (userInteraction && !this.fixed) {
- this.collapsed = !this.collapsed;
- }
- return;
- }
-
- if (!this.fixed) {
- this.collapsed = false;
- }
-
- this.selectedIndex = tabs.indexOf(tab);
- this._itemNavigation.currentIndex = tabs.indexOf(this.selectedIndex);
-
- this._selectedTab = tab;
-
- tabs.forEach(item => {
- item._isSelected = item === tab;
- });
-
- if (userInteraction) {
- this.fireEvent("itemSelect", {
- item: this._selectedTab,
- });
- }
+ _updateScrolling() {
+ const headerScrollContainer = this._getHeaderScrollContainer();
- this._scrollIntoView();
+ this._scrollable = headerScrollContainer.offsetWidth < headerScrollContainer.scrollWidth;
+ this._scrollableBack = headerScrollContainer.scrollLeft > 0;
+ this._scrollableForward = Math.ceil(headerScrollContainer.scrollLeft) < headerScrollContainer.scrollWidth - headerScrollContainer.offsetWidth;
}
- getSelectedTab() {
- return this._selectedTab;
+ _getHeader() {
+ return this.shadowRoot.querySelector(`#${this._id}-header`);
}
- getTabs() {
- const items = this.items || [];
-
- return items.filter(item => item instanceof Tab);
+ _getTabs() {
+ return this.items.filter(item => !item.isSeparator());
}
- onkeydown(event) {
- if (isSpace(event) || isEnter(event)) {
- const selectedTab = this._findSelectedTab(event);
- this.setSelectedTab(selectedTab, true);
- event.preventDefault();
- }
+ _getHeaderScrollContainer() {
+ return this.shadowRoot.querySelector(`#${this._id}-headerScrollContainer`);
}
- onclick(event) {
- const icon = event.composedPath().filter(element => {
- return element.classList && element.classList.contains("sapMITBArrowScroll");
- })[0];
-
- if (icon) {
- this._navigationIconPress(icon);
- }
-
- const selectedTab = this._findSelectedTab(event);
- this.setSelectedTab(selectedTab, true);
- }
-
- _navigationIconPress(icon) {
- if (icon.classList.contains("sapMITBArrowScrollLeft") || icon.classList.contains("sapMITBArrowScrollLeftTextOnly")) {
- this._leftArrow.onPress();
- } else {
- this._rightArrow.onPress();
- }
+ _getPopover() {
+ return this.shadowRoot.querySelector(`#${this._id}-overflowMenu`);
}
static get calculateTemplateContext() {
@@ -770,9 +360,9 @@ class TabContainer extends WebComponent {
static async define(...params) {
await Promise.all([
- Icon.define(),
Button.define(),
CustomListItem.define(),
+ Icon.define(),
List.define(),
Popover.define(),
]);
@@ -781,6 +371,18 @@ class TabContainer extends WebComponent {
}
}
+const findIndex = (arr, predicate) => {
+ for (let i = 0; i < arr.length; i++) {
+ const result = predicate(arr[i]);
+
+ if (result) {
+ return i;
+ }
+ }
+
+ return -1;
+};
+
Bootstrap.boot().then(_ => {
TabContainer.define();
});
diff --git a/packages/main/src/TabContainerTemplateContext.js b/packages/main/src/TabContainerTemplateContext.js
index 47e116eb789b..aa8ecdfa113c 100644
--- a/packages/main/src/TabContainerTemplateContext.js
+++ b/packages/main/src/TabContainerTemplateContext.js
@@ -1,43 +1,196 @@
+import IconColor from "./types/IconColor";
+
class TabContainerTemplateContext {
static calculate(state) {
const context = {
ctr: state,
classes: {
main: {
- sapMITB: true,
- sapMITBCollapsed: state.collapsed,
+ "ui5-tab-container": true,
},
- tablist: {
- sapMITH: true,
- sapContrastPlus: true,
- sapMITHOverflowList: state.showOverflow,
- sapMITBScrollable: state._scrollable,
- sapMITBNotScrollable: !state._scrollable,
-
- sapMITBScrollForward: state._scrollable && state._scrollForward,
- sapMITBNoScrollForward: state._scrollable && !state._scrollForward,
-
- sapMITBScrollBack: state._scrollable && state._scrollBack,
- sapMITBNoScrollBack: state._scrollable && !state._scrollBack,
+ header: {
+ "ui5-tc__header": true,
+ "ui5-tc__header--scrollable": state._scrollable,
+ },
+ headerScrollContainer: {
+ "ui-tc__headerScrollContainer": true,
+ },
+ headerList: {
+ "ui5-tc__headerList": true,
+ },
+ separator: {
+ "ui5-tc__separator": true,
+ },
+ headerBackArrow: {
+ "ui5-tc__headerArrow": true,
+ "ui5-tc__headerArrowLeft": true,
+ "ui5-tc__headerArrow--visible": state._scrollableBack,
+ },
+ headerForwardArrow: {
+ "ui5-tc__headerArrow": true,
+ "ui5-tc__headerArrowRight": true,
+ "ui5-tc__headerArrow--visible": state._scrollableForward,
},
- head: {
- sapMITBHead: true,
- sapMITBTextOnly: state._isNoIcon,
- sapMITBNoText: state._isNoText,
- sapMITBInLine: state._isInline,
+ overflowButton: {
+ "ui-tc__overflowButton": true,
+ "ui-tc__overflowButton--visible": state._scrollable,
},
content: {
- sapMITBContainerContent: true,
- sapMITBContentClosed: state.collapsed,
+ "ui5-tc__content": true,
+ "ui5-tc__content--collapsed": state.collapsed,
},
},
+ renderItems: [],
+ mixedMode: state.items.some(item => item.icon) && state.items.some(item => item.text),
};
- context.classes.tablist[`sapMITHBackgroundDesign${state.headerBackgroundDesign}`] = true;
- context.classes.main[`sapMITBBackgroundDesign${state.backgroundDesign}`] = true;
+ context.renderItems = context.ctr.items.map((item, index) => {
+ const isSeparator = item.isSeparator();
+
+ if (isSeparator) {
+ return { isSeparator, _tabIndex: item._tabIndex, _id: item._id };
+ }
+
+ return {
+ item,
+ isMixedModeTab: !item.icon && context.mixedMode,
+ isTextOnlyTab: !item.icon && !context.mixedMode,
+ isIconTab: item.icon,
+ position: index + 1,
+ disabled: item.disabled || undefined,
+ selected: item.selected || undefined,
+ ariaLabelledBy: calculateAriaLabelledBy(item),
+ contentItemClasses: calculateContentItemClasses(item),
+ headerItemClasses: calculateHeaderItemClasses(item, context),
+ headerItemContentClasses: calculateHeaderItemContentClasses(item),
+ headerItemIconClasses: calculateHeaderItemIconClasses(item),
+ headerItemSemanticIconClasses: calculateHeaderItemSemanticIconClasses(item),
+ headerItemTextClasses: calculateHeaderItemTextClasses(item),
+ headerItemAdditionalTextClasses: calculateHeaderItemAdditionalTextClasses(item),
+ overflowItemClasses: calculateOverflowItemClasses(item),
+ overflowItemContentClasses: calculateOverflowItemContentClasses(item),
+ overflowItemState: calculateOverflowItemState(item),
+ };
+ });
return context;
}
}
+const calculateAriaLabelledBy = item => {
+ const labels = [];
+
+ if (item.text) {
+ labels.push(`${item._id}-text`);
+ }
+
+ if (item.additionalText) {
+ labels.push(`${item._id}-additionalText`);
+ }
+
+ if (item.icon) {
+ labels.push(`${item._id}-icon`);
+ }
+
+ return labels.join(" ");
+};
+
+const calculateHeaderItemClasses = (item, context) => {
+ const classes = ["ui5-tc__headerItem"];
+
+ if (item.selected) {
+ classes.push("ui5-tc__headerItem--selected");
+ }
+
+ if (item.disabled) {
+ classes.push("ui5-tc__headerItem--disabled");
+ }
+
+ if (!item.icon && !context.mixedMode) {
+ classes.push("ui5-tc__headerItem--textOnly");
+ }
+
+ if (item.icon) {
+ classes.push("ui5-tc__headerItem--withIcon");
+ }
+
+ if (!item.icon && context.mixedMode) {
+ classes.push("ui5-tc__headerItem--mixedMode");
+ }
+
+ if (item.iconColor !== IconColor.Default) {
+ classes.push(`ui5-tc__headerItem--${item.iconColor.toLowerCase()}`);
+ }
+
+ return classes.join(" ");
+};
+
+const calculateHeaderItemContentClasses = item => {
+ const classes = ["ui5-tc__headerItemContent"];
+
+ return classes.join(" ");
+};
+
+const calculateHeaderItemIconClasses = item => {
+ const classes = ["ui5-tc-headerItemIcon"];
+
+ return classes.join(" ");
+};
+
+const calculateHeaderItemSemanticIconClasses = item => {
+ const classes = ["ui5-tc-headerItemSemanticIcon"];
+
+ if (item.iconColor !== IconColor.Default) {
+ classes.push(`ui5-tc-headerItemSemanticIcon--${item.iconColor.toLowerCase()}`);
+ }
+
+ return classes.join(" ");
+};
+
+const calculateHeaderItemTextClasses = item => {
+ const classes = ["ui5-tc__headerItemText"];
+
+ return classes.join(" ");
+};
+
+const calculateHeaderItemAdditionalTextClasses = item => {
+ const classes = ["ui5-tc__headerItemAdditionalText"];
+
+ return classes.join(" ");
+};
+
+const calculateOverflowItemClasses = item => {
+ const classes = ["ui5-tc__overflowItem"];
+
+ if (item.iconColor !== IconColor.Default) {
+ classes.push(`ui5-tc__overflowItem--${item.iconColor.toLowerCase()}`);
+ }
+
+ if (item.disabled) {
+ classes.push("ui5-tc__overflowItem--disabled");
+ }
+
+ return classes.join(" ");
+};
+
+const calculateOverflowItemContentClasses = item => {
+ const classes = ["ui5-tc__overflowItemContent"];
+
+ return classes.join(" ");
+};
+
+const calculateOverflowItemState = item => {
+ return item.disabled ? "Inactive" : "Active";
+};
+
+const calculateContentItemClasses = item => {
+ const classes = ["ui5-tc__contentItem"];
+
+ if (!item.selected) {
+ classes.push(" ui5-tc__contentItem--hidden");
+ }
+
+ return classes.join(" ");
+};
+
export default TabContainerTemplateContext;
diff --git a/packages/main/src/TabSeparator.hbs b/packages/main/src/TabSeparator.hbs
index 0ef72a27b235..720dc067a537 100644
--- a/packages/main/src/TabSeparator.hbs
+++ b/packages/main/src/TabSeparator.hbs
@@ -1 +1 @@
-count
and the text
are set,
- * they are displayed in two separate lines.
- * @public
- */
- Standard: "Standard",
- /**
- * Inline. In this mode when the count
and the text
are set,
- * they are displayed in one line.
- * @public
- */
- Inline: "Inline",
-};
-
-class TabContainerHeaderMode extends DataType {
- static isValid(value) {
- return !!TabContainerHeaderModes[value];
- }
-}
-
-TabContainerHeaderMode.generataTypeAcessors(TabContainerHeaderModes);
-
-export default TabContainerHeaderMode;
diff --git a/packages/main/src/types/TabDesignMode.js b/packages/main/src/types/TabDesignMode.js
deleted file mode 100644
index 80ed105b8a00..000000000000
--- a/packages/main/src/types/TabDesignMode.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import DataType from "@ui5/webcomponents-base/src/types/DataType";
-
-const TabDesignModes = {
- /**
- * A horizontally layouted design providing more space for texts.
- * @public
- */
- Horizontal: "Horizontal",
-
- /**
- * A vertically layouted design using minimum horizontal space.
- * @public
- */
- Vertical: "Vertical",
-};
-
-class TabDesignMode extends DataType {
- static isValid(value) {
- return !!TabDesignModes[value];
- }
-}
-
-TabDesignMode.generataTypeAcessors(TabDesignModes);
-
-export default TabDesignMode;
diff --git a/packages/main/test/sap/ui/webcomponents/main/pages/TabContainer.html b/packages/main/test/sap/ui/webcomponents/main/pages/TabContainer.html
index 4016bc3c2d33..7affe957ab7a 100644
--- a/packages/main/test/sap/ui/webcomponents/main/pages/TabContainer.html
+++ b/packages/main/test/sap/ui/webcomponents/main/pages/TabContainer.html
@@ -1,11 +1,14 @@
+
-
- - - + + - Quibusdam, veniam! Architecto debitis iusto ad et, asperiores quisquam perferendis reprehenderit ipsa voluptate minus minima, perspiciatis cum. Totam harum necessitatibus numquam voluptatum. + Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga magni facere error dicta beatae optio repudiandae vero, quidem voluptatibus perferendis eum maiores rem tempore voluptates aperiam eos enim delectus unde. @@ -84,18 +84,18 @@ Basic TabContainer
Text Only TabContainer
-+ - + - + - + diff --git a/packages/main/test/specs/TabContainer.spec.js b/packages/main/test/specs/TabContainer.spec.js index dc7b1739ebb3..f65a8e1e2bde 100644 --- a/packages/main/test/specs/TabContainer.spec.js +++ b/packages/main/test/specs/TabContainer.spec.js @@ -4,26 +4,21 @@ describe("TabContainer general interaction", () => { browser.url("http://localhost:8080/test-resources/sap/ui/webcomponents/main/pages/TabContainer.html"); it("tests itemSelect event", () => { - const item = browser.findElementDeep("#tabContainer1 >>> .sapMITBItem:nth-child(3)"); - const field = browser.$("#field"); - const field2 = browser.$("#field2"); - const field3 = browser.$("#field3"); + const item = browser.findElementDeep("#tabContainer1 >>> .ui5-tc__headerItem:nth-child(3)"); + const result = browser.$("#result"); - const SELECTED_TAB_KEY = "item2"; - const SELECTED_TAB_TEXT = "Tab 2"; + const SELECTED_TAB_TEXT = "Laptops"; item.click(); - assert.strictEqual(field.getProperty("value"), "1", "itemSelect event should be fired once"); - assert.strictEqual(field2.getProperty("value"), SELECTED_TAB_KEY, "Item data-key is retrieved correctly"); - assert.strictEqual(field3.getProperty("value"), SELECTED_TAB_TEXT, "Item text is retrieved correctly."); + assert.strictEqual(result.getText(), SELECTED_TAB_TEXT, "Item text is retrieved correctly."); }); it("scroll works on iconsOnly TabContainer", () => { - browser.setWindowSize(250, 1080); + browser.setWindowSize(310, 1080); - const arrowLeft = browser.findElementDeep("#tabContainerIconOnly >>> .sapMITBArrowScrollLeft"); - const arrowRight = browser.findElementDeep("#tabContainerIconOnly >>> .sapMITBArrowScrollRight"); + const arrowLeft = browser.findElementDeep("#tabContainerIconOnly >>> .ui5-tc__headerArrowLeft"); + const arrowRight = browser.findElementDeep("#tabContainerIconOnly >>> .ui5-tc__headerArrowRight"); assert.ok(!arrowLeft.isDisplayed(), "'Left Arrow' should be initially hidden"); assert.ok(arrowRight.isDisplayed(), "'Right Arrow' should be initially shown"); @@ -42,11 +37,11 @@ describe("TabContainer general interaction", () => { }); it("scroll works on textOnly TabContainer", () => { - browser.setWindowSize(250, 1080); + browser.setWindowSize(310, 1080); browser.findElementDeep("#tabContainerTextOnly").scrollIntoView(); - const arrowLeft = browser.findElementDeep("#tabContainerTextOnly >>> .sapMITBArrowScrollLeftTextOnly"); - const arrowRight = browser.findElementDeep("#tabContainerTextOnly >>> .sapMITBArrowScrollRightTextOnly"); + const arrowLeft = browser.findElementDeep("#tabContainerTextOnly >>> .ui5-tc__headerArrowLeft"); + const arrowRight = browser.findElementDeep("#tabContainerTextOnly >>> .ui5-tc__headerArrowRight"); assert.ok(!arrowLeft.isDisplayed(), "'Left Arrow' should be initially hidden"); assert.ok(arrowRight.isDisplayed(), "'Right Arrow' should be initially shown");