diff --git a/packages/react-core/src/components/Tabs/Tabs.tsx b/packages/react-core/src/components/Tabs/Tabs.tsx index f71abb5da30..b7fb44dc119 100644 --- a/packages/react-core/src/components/Tabs/Tabs.tsx +++ b/packages/react-core/src/components/Tabs/Tabs.tsx @@ -126,6 +126,8 @@ export class Tabs extends React.Component { } } + scrollTimeout: NodeJS.Timeout = null; + static defaultProps: PickOptional = { activeKey: 0, onSelect: () => undefined as any, @@ -179,28 +181,32 @@ export class Tabs extends React.Component { } handleScrollButtons = () => { - const container = this.tabList.current; - let disableLeftScrollButton = true; - let disableRightScrollButton = true; - let showScrollButtons = false; + // add debounce to the scroll event + clearTimeout(this.scrollTimeout); + this.scrollTimeout = setTimeout(() => { + const container = this.tabList.current; + let disableLeftScrollButton = true; + let disableRightScrollButton = true; + let showScrollButtons = false; - if (container && !this.props.isVertical) { - // get first element and check if it is in view - const overflowOnLeft = !isElementInView(container, container.firstChild as HTMLElement, false); + if (container && !this.props.isVertical) { + // get first element and check if it is in view + const overflowOnLeft = !isElementInView(container, container.firstChild as HTMLElement, false); - // get last element and check if it is in view - const overflowOnRight = !isElementInView(container, container.lastChild as HTMLElement, false); + // get last element and check if it is in view + const overflowOnRight = !isElementInView(container, container.lastChild as HTMLElement, false); - showScrollButtons = overflowOnLeft || overflowOnRight; + showScrollButtons = overflowOnLeft || overflowOnRight; - disableLeftScrollButton = !overflowOnLeft; - disableRightScrollButton = !overflowOnRight; - } - this.setState({ - showScrollButtons, - disableLeftScrollButton, - disableRightScrollButton - }); + disableLeftScrollButton = !overflowOnLeft; + disableRightScrollButton = !overflowOnRight; + } + this.setState({ + showScrollButtons, + disableLeftScrollButton, + disableRightScrollButton + }); + }, 100); }; scrollLeft = () => { @@ -258,6 +264,7 @@ export class Tabs extends React.Component { window.removeEventListener('resize', this.handleScrollButtons, false); } } + clearTimeout(this.scrollTimeout); } componentDidUpdate(prevProps: TabsProps) { diff --git a/packages/react-core/src/helpers/util.ts b/packages/react-core/src/helpers/util.ts index 5640921a717..603876f0b1f 100644 --- a/packages/react-core/src/helpers/util.ts +++ b/packages/react-core/src/helpers/util.ts @@ -39,24 +39,30 @@ export function debounce(this: any, func: (...args: any[]) => any, wait: number) * @param {HTMLElement} container The container to check if the element is in view of. * @param {HTMLElement} element The element to check if it is view * @param {boolean} partial true if partial view is allowed + * @param {boolean} strict true if strict mode is set, never consider the container width and element width * * @returns { boolean } True if the component is in View. */ -export function isElementInView(container: HTMLElement, element: HTMLElement, partial: boolean) { +export function isElementInView( + container: HTMLElement, + element: HTMLElement, + partial: boolean, + strict: boolean = false +): boolean { if (!container || !element) { return false; } const containerBounds = container.getBoundingClientRect(); const elementBounds = element.getBoundingClientRect(); - const containerBoundsLeft = Math.floor(containerBounds.left); + const containerBoundsLeft = Math.ceil(containerBounds.left); const containerBoundsRight = Math.floor(containerBounds.right); - const elementBoundsLeft = Math.floor(elementBounds.left); + const elementBoundsLeft = Math.ceil(elementBounds.left); const elementBoundsRight = Math.floor(elementBounds.right); // Check if in view const isTotallyInView = elementBoundsLeft >= containerBoundsLeft && elementBoundsRight <= containerBoundsRight; const isPartiallyInView = - partial && + (partial || (!strict && containerBounds.width < elementBounds.width)) && ((elementBoundsLeft < containerBoundsLeft && elementBoundsRight > containerBoundsLeft) || (elementBoundsRight > containerBoundsRight && elementBoundsLeft < containerBoundsRight));