From 30595bed1d5ec2de1a7d3d1759d6a2398c904c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Fri, 21 Oct 2022 15:06:35 -0500 Subject: [PATCH 1/5] feat(@clayui/tabs): add new API to configure browsing behavior between tabs --- packages/clay-tabs/src/Item.tsx | 2 +- packages/clay-tabs/src/index.tsx | 103 ++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/packages/clay-tabs/src/Item.tsx b/packages/clay-tabs/src/Item.tsx index 0f73d90567..f4075a431f 100644 --- a/packages/clay-tabs/src/Item.tsx +++ b/packages/clay-tabs/src/Item.tsx @@ -69,7 +69,7 @@ const Item = React.forwardRef( onClick={onClick} ref={ref} role="tab" - tabIndex={!active ? -1 : undefined} + tabIndex={!active ? -1 : 0} > {children} diff --git a/packages/clay-tabs/src/index.tsx b/packages/clay-tabs/src/index.tsx index 96848b8271..323f733f04 100644 --- a/packages/clay-tabs/src/index.tsx +++ b/packages/clay-tabs/src/index.tsx @@ -3,8 +3,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ +import { + FOCUSABLE_ELEMENTS, + InternalDispatch, + Keys, + useInternalState, +} from '@clayui/shared'; import classNames from 'classnames'; -import React from 'react'; +import React, {useRef} from 'react'; import Content from './Content'; import Item from './Item'; @@ -13,6 +19,25 @@ import TabPane from './TabPane'; export type DisplayType = null | 'basic' | 'underline'; export interface IProps extends React.HTMLAttributes { + /** + * Flag to indicate the navigation behavior in the tab. + * + * - manual - it will just move the focus and tab activation is done just + * by pressing space or enter. + * - automatic - moves the focus to the tab and activates the tab. + */ + activation?: 'manual' | 'automatic'; + + /** + * The current tab active (controlled). + */ + active?: number; + + /** + * Initial active tab when rendering component (uncontrolled). + */ + defaultActive?: number; + /** * Determines how tab is displayed. */ @@ -27,6 +52,11 @@ export interface IProps extends React.HTMLAttributes { * Applies a modern style to the tab. */ modern?: boolean; + + /** + * Callback is called when the active tab changes (controlled). + */ + onActiveChange?: InternalDispatch; } function ClayTabs(props: IProps): JSX.Element & { @@ -37,13 +67,28 @@ function ClayTabs(props: IProps): JSX.Element & { }; function ClayTabs({ + activation = 'manual', + active: externalActive, children, className, + defaultActive = 0, displayType, justified, modern = true, + onActiveChange, ...otherProps }: IProps) { + const tabsRef = useRef(null); + + const [active, setActive] = useInternalState({ + defaultName: 'defaultActive', + defaultValue: defaultActive, + handleName: 'onActiveChange', + name: 'active', + onChange: onActiveChange, + value: externalActive, + }); + return (
    { + if (!tabsRef.current) { + return; + } + + if (event.key === Keys.Left || event.key === Keys.Right) { + const tabs = Array.from( + tabsRef.current.querySelectorAll( + FOCUSABLE_ELEMENTS.join(',') + ) + ); + const activeElement = document.activeElement as HTMLElement; + + const position = tabs.indexOf(activeElement); + + const tab = + tabs[ + event.key === Keys.Left + ? position - 1 + : position + 1 + ]; + + if (tab) { + tab.focus(); + + if (activation === 'automatic') { + const newActive = Array.from( + tabsRef.current.querySelectorAll('a, button') + ).indexOf(tab); + + setActive(newActive); + } + } + } + }} + ref={tabsRef} role="tablist" > - {children} + {React.Children.map(children, (child, index) => + React.cloneElement(child as React.ReactElement, { + active: + (child as React.ReactElement).props.active !== undefined + ? (child as React.ReactElement).props.active + : active === index, + onClick: ( + event: React.MouseEvent + ) => { + const {onClick} = (child as React.ReactElement).props; + + if (onClick) { + onClick(event); + } else { + setActive(index); + } + }, + }) + )}
); } From d235191896eddb8cb644a6d3ff54d95933c5f06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Fri, 21 Oct 2022 15:40:58 -0500 Subject: [PATCH 2/5] chore(@clayui/tabs): update story examples --- packages/clay-tabs/stories/Tabs.stories.tsx | 156 +++----------------- 1 file changed, 20 insertions(+), 136 deletions(-) diff --git a/packages/clay-tabs/stories/Tabs.stories.tsx b/packages/clay-tabs/stories/Tabs.stories.tsx index 95aa27d53f..71b5f37852 100644 --- a/packages/clay-tabs/stories/Tabs.stories.tsx +++ b/packages/clay-tabs/stories/Tabs.stories.tsx @@ -3,31 +3,16 @@ * SPDX-License-Identifier: BSD-3-Clause */ -import ClayDropDown, {Align} from '@clayui/drop-down'; -import ClayIcon from '@clayui/icon'; import React, {useState} from 'react'; import ClayTabs from '../src'; -const DropDownWithState = ({children, trigger, ...others}: any) => { - const [active, setActive] = useState(false); - - return ( - setActive(newVal)} - trigger={trigger} - {...others} - > - {children} - - ); -}; - export default { argTypes: { + activation: { + control: {type: 'select'}, + options: ['manual', 'automatic', null], + }, displayType: { control: {type: 'select'}, options: ['basic', 'underline', null], @@ -38,119 +23,53 @@ export default { }; export const Default = (args: any) => { - const [activeIndex, setActiveIndex] = useState(0); - - const dropdownTabsItems = [ - { - disabled: true, - label: 'Tab 6', - tabkey: 5, - }, - { - label: 'Tab 7', - tabkey: 6, - }, - { - label: 'Tab 8', - tabkey: 7, - }, - ]; + const [active, setActive] = useState(0); return ( <> setActiveIndex(0)} > Tab 1 setActiveIndex(1)} > Tab 2 setActiveIndex(2)} > Tab 3 setActiveIndex(3)} > Tab 4 - - setActiveIndex(4)} - > - Tab 5 - - - } - > - - {dropdownTabsItems.map( - ({disabled = false, label, tabkey}, i) => { - return ( - setActiveIndex(tabkey)} - role="tab" - symbolRight={ - activeIndex === tabkey - ? 'check' - : undefined - } - > - {label} - - ); - } - )} - - - - + + {`1. Single origin, extra id beans, eu to go, skinny americano ut aftertas te sugar. At americano, viennese variety iced grounds, grinder froth and pumpkin spice @@ -160,7 +79,7 @@ export const Default = (args: any) => { plunger pot. Single shot variety pumpkin spice seasonal skinny barista carajillo robust cream.`} - + {`2. Single origin, extra id beans, eu to go, skinny americano ut aftertaste sugar. At americano, viennese variety iced grounds, grinder froth and pumpkin spice @@ -170,7 +89,7 @@ export const Default = (args: any) => { plunger pot. Single shot variety pumpkin spice seasonal skinny barista carajillo robust cream.`} - + {`3. Single origin, extra id beans, eu to go, skinny americano ut aftertaste sugar. At americano, viennese variety iced grounds, grinder froth and pumpkin spice @@ -180,7 +99,7 @@ export const Default = (args: any) => { plunger pot. Single shot variety pumpkin spice seasonal skinny barista carajillo robust cream.`} - + {`4. Single origin, extra id beans, eu to go, skinny americano ut aftertaste sugar. At americano, viennese variety iced grounds, grinder froth and pumpkin spice @@ -190,7 +109,7 @@ export const Default = (args: any) => { plunger pot. Single shot variety pumpkin spice seasonal skinny barista carajillo robust cream.`} - + {`4. Single origin, extra id beans, eu to go, skinny americano ut aftertaste sugar. At americano, viennese variety iced grounds, grinder froth and pumpkin spice @@ -200,42 +119,13 @@ export const Default = (args: any) => { plunger pot. Single shot variety pumpkin spice seasonal skinny barista carajillo robust cream.`} - - {`6. Single origin, extra id beans, eu to go, skinny - americano ut aftertaste sugar. At americano, viennese - variety iced grounds, grinder froth and pumpkin spice - aromatic. Cultivar aged lungo, grounds café au lait, - skinny, blue mountain, in variety sugar shop roast. - Wings, blue mountain affogato organic cappuccino java - plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream.`} - - - {`7. Single origin, extra id beans, eu to go, skinny - americano ut aftertaste sugar. At americano, viennese - variety iced grounds, grinder froth and pumpkin spice - aromatic. Cultivar aged lungo, grounds café au lait, - skinny, blue mountain, in variety sugar shop roast. - Wings, blue mountain affogato organic cappuccino java - plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream.`} - - - {`8. Single origin, extra id beans, eu to go, skinny - americano ut aftertaste sugar. At americano, viennese - variety iced grounds, grinder froth and pumpkin spice - aromatic. Cultivar aged lungo, grounds café au lait, - skinny, blue mountain, in variety sugar shop roast. - Wings, blue mountain affogato organic cappuccino java - plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream.`} - ); }; Default.args = { + activation: 'manual', disabledFirstTab: false, disabledFourthTab: false, disabledSecondTab: true, @@ -246,23 +136,17 @@ Default.args = { }; export const WithState = () => { - const [activeIndex, setActiveIndex] = useState(0); + const [active, setActive] = useState(0); return (
- - {['Tab 1', 'Tab 2', 'Tab 3'].map((item, index) => ( - setActiveIndex(index)} - > - {item} - + + {['Tab 1', 'Tab 2', 'Tab 3'].map((item) => ( + {item} ))} - + Single origin, extra id beans, eu to go, skinny americano ut aftertaste sugar. At americano, viennese variety iced From d51b165bc8a494ffa9ca904e758e38f84dbfe784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Fri, 21 Oct 2022 15:41:18 -0500 Subject: [PATCH 3/5] chore(@clayui/tabs): update test --- .../__tests__/__snapshots__/index.tsx.snap | 1 + packages/clay-tabs/src/__tests__/index.tsx | 33 +++++-------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/packages/clay-tabs/src/__tests__/__snapshots__/index.tsx.snap b/packages/clay-tabs/src/__tests__/__snapshots__/index.tsx.snap index b826449173..e377002c03 100644 --- a/packages/clay-tabs/src/__tests__/__snapshots__/index.tsx.snap +++ b/packages/clay-tabs/src/__tests__/__snapshots__/index.tsx.snap @@ -24,6 +24,7 @@ exports[`ClayTabs renders with items 1`] = ` class="nav-link active btn btn-unstyled" data-testid="tabItem" role="tab" + tabindex="0" type="button" > Dummy1 diff --git a/packages/clay-tabs/src/__tests__/index.tsx b/packages/clay-tabs/src/__tests__/index.tsx index f730302dee..be37821d8a 100644 --- a/packages/clay-tabs/src/__tests__/index.tsx +++ b/packages/clay-tabs/src/__tests__/index.tsx @@ -9,32 +9,16 @@ import {cleanup, fireEvent, render} from '@testing-library/react'; import React from 'react'; const ClayTabsWithItems = () => { - const [activeTabKeyValue, setActiveTabKeyValue] = React.useState(0); + const [active, setActive] = React.useState(0); return ( <> - - setActiveTabKeyValue(0)} - > - Dummy1 - - setActiveTabKeyValue(1)} - > - Dummy2 - - setActiveTabKeyValue(2)} - > - Dummy3 - + + Dummy1 + Dummy2 + Dummy3 - + Tab Content 1 @@ -96,8 +80,9 @@ describe('ClayTabs', () => { const {getAllByTestId} = render( <> - - One + + One + Two From 18431ed9f530599761f2169a0218974330f33f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Fri, 21 Oct 2022 15:41:30 -0500 Subject: [PATCH 4/5] docs(@clayui/tabs): update docs --- packages/clay-tabs/docs/index.js | 73 +++++++++++++------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/packages/clay-tabs/docs/index.js b/packages/clay-tabs/docs/index.js index a78ecc40d2..333a675636 100644 --- a/packages/clay-tabs/docs/index.js +++ b/packages/clay-tabs/docs/index.js @@ -13,48 +13,42 @@ const tabsImportsCode = `import ClayTabs from '@clayui/tabs'; `; const tabsCode = `const Component = () => { - const [activeTabKeyValue, setActiveTabKeyValue] = useState(0); + const [active, setActive] = useState(0); return ( <> - + setActiveTabKeyValue(0)} > - {'Tab 1'} + Tab 1 setActiveTabKeyValue(1)} > - {'Tab 2'} + Tab 2 setActiveTabKeyValue(2)} > - {'Tab 3'} + Tab 3 - + - {\`1. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 1. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`2. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 2. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`3. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 3. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. @@ -96,7 +90,7 @@ const tabsDropdownCode = `const Component = () => { ); }; - const [activeTabKeyValue, setActiveTabKeyValue] = useState(0); + const [active, setActive] = useState(0); const dropdownTabsItems = [ { @@ -116,54 +110,45 @@ const tabsDropdownCode = `const Component = () => { return ( - + setActiveTabKeyValue(0)} > - {'Tab 1'} + Tab 1 setActiveTabKeyValue(1)} > - {'Tab 2'} + Tab 2 setActiveTabKeyValue(2)} > - {'Tab 3'} + Tab 3 setActiveTabKeyValue(3)} > - {'Tab 4'} + Tab 4 setActiveTabKeyValue(4)} > - {'More'} + More } @@ -174,10 +159,10 @@ const tabsDropdownCode = `const Component = () => { return ( { role="tab" spritemap={spritemap} symbolRight={ - activeTabKeyValue === tabkey + active === tabkey ? 'check' : undefined } @@ -201,32 +186,32 @@ const tabsDropdownCode = `const Component = () => { - {\`1. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 1. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`2. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 2. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`3. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 3. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`4. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 4. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`5. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 5. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`6. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 6. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`7. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 7. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. - {\`8. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu.\`} + 8. Proin efficitur imperdiet dolor, a iaculis orci lacinia eu. From c0669bc9eff095042181ba1745904240b2c3d618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Fri, 21 Oct 2022 16:05:31 -0500 Subject: [PATCH 5/5] chore(@clayui/tabs): update test threshold --- jest.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jest.config.js b/jest.config.js index 605d8a82d0..f00149daa2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -212,10 +212,10 @@ module.exports = { statements: 100, }, './packages/clay-tabs/src/': { - branches: 84, + branches: 58, functions: 66, - lines: 94, - statements: 90, + lines: 78, + statements: 76, }, './packages/clay-time-picker/src/': { branches: 85,