Skip to content

Commit

Permalink
LG-2728: migrate from Box to Polymorphic in tabs package (#2359)
Browse files Browse the repository at this point in the history
* LG-2728: migrate from Box to Polymorphic

* Address feedback
  • Loading branch information
stephl3 authored May 30, 2024
1 parent 248aeca commit 9053f74
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 92 deletions.
2 changes: 1 addition & 1 deletion packages/tabs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
},
"dependencies": {
"@leafygreen-ui/a11y": "^1.4.13",
"@leafygreen-ui/box": "^3.1.9",
"@leafygreen-ui/descendants": "^0.1.1",
"@leafygreen-ui/emotion": "^4.0.8",
"@leafygreen-ui/hooks": "^8.1.3",
"@leafygreen-ui/lib": "^13.3.0",
"@leafygreen-ui/palette": "^4.0.9",
"@leafygreen-ui/polymorphic": "^1.3.7",
"@leafygreen-ui/tokens": "^2.7.0",
"@leafygreen-ui/typography": "^19.1.1",
"@lg-tools/test-harnesses": "0.1.2"
Expand Down
140 changes: 66 additions & 74 deletions packages/tabs/src/TabTitle/TabTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, { RefObject, useCallback, useMemo, useRef } from 'react';
import React, { useCallback, useMemo } from 'react';

import Box, { ExtendableBox } from '@leafygreen-ui/box';
import { useDescendant } from '@leafygreen-ui/descendants';
import { cx } from '@leafygreen-ui/emotion';
import { getNodeTextContent, Theme } from '@leafygreen-ui/lib';
import {
InferredPolymorphic,
useInferredPolymorphic,
} from '@leafygreen-ui/polymorphic';
import { BaseFontSize } from '@leafygreen-ui/tokens';
import { useUpdatedBaseFontSize } from '@leafygreen-ui/typography';

Expand All @@ -20,89 +23,78 @@ import {
} from './TabTitle.styles';
import { BaseTabTitleProps } from './TabTitle.types';

const TabTitle: ExtendableBox<BaseTabTitleProps, 'button'> = ({
children,
className,
darkMode,
disabled = false,
onClick,
selectedIndex,
...rest
}: BaseTabTitleProps) => {
const baseFontSize: BaseFontSize = useUpdatedBaseFontSize();
const titleRef = useRef<HTMLAnchorElement | HTMLButtonElement>(null);
const { index, ref, id } = useDescendant(TabDescendantsContext);
const { tabPanelDescendants } = useTabPanelDescendantsContext();
const TabTitle = InferredPolymorphic<BaseTabTitleProps, 'button'>(
(
{
as,
children,
className,
darkMode,
disabled = false,
onClick,
selectedIndex,
...rest
},
fwdRef,
) => {
const baseFontSize: BaseFontSize = useUpdatedBaseFontSize();
const { Component } = useInferredPolymorphic(as, rest, 'button');
const { index, ref, id } = useDescendant(TabDescendantsContext);
const { tabPanelDescendants } = useTabPanelDescendantsContext();

const theme = darkMode ? Theme.Dark : Theme.Light;
const selected = index === selectedIndex;
const theme = darkMode ? Theme.Dark : Theme.Light;
const selected = index === selectedIndex;

const relatedTabPanel = useMemo(() => {
return tabPanelDescendants.find(
tabPanelDescendant => tabPanelDescendant.index === index,
);
}, [tabPanelDescendants, index]);
const relatedTabPanel = useMemo(() => {
return tabPanelDescendants.find(
tabPanelDescendant => tabPanelDescendant.index === index,
);
}, [tabPanelDescendants, index]);

const handleClick = useCallback(
(event: React.MouseEvent) => {
onClick(event, index);
},
[index, onClick],
);
const handleClick = useCallback(
(event: React.MouseEvent) => {
onClick(event, index);
},
[index, onClick],
);

const nodeText = getNodeTextContent(rest.name);
const nodeText = getNodeTextContent(rest.name);

const sharedTabProps = {
...rest,
className: cx(
listTitleFontSize[baseFontSize],
listTitleStyles,
listTitleModeStyles[theme].base,
{
[listTitleModeStyles[theme].selected]: !disabled && selected,
[listTitleModeStyles[theme].hover]: !disabled && !selected,
[listTitleModeStyles[theme].disabled]: disabled,
},
listTitleModeStyles[theme].focus,
className,
),
disabled,
id,
name: nodeText,
onClick: handleClick,
role: 'tab',
tabIndex: selected ? 0 : -1,
['aria-controls']: relatedTabPanel?.id,
['aria-selected']: !disabled && selected,
['data-text']: nodeText,
} as const;
const componentProps = {
...rest,
className: cx(
listTitleFontSize[baseFontSize],
listTitleStyles,
listTitleModeStyles[theme].base,
{
[listTitleModeStyles[theme].selected]: !disabled && selected,
[listTitleModeStyles[theme].hover]: !disabled && !selected,
[listTitleModeStyles[theme].disabled]: disabled,
},
listTitleModeStyles[theme].focus,
className,
),
disabled,
id,
name: nodeText,
onClick: handleClick,
ref: fwdRef,
role: 'tab',
tabIndex: selected ? 0 : -1,
['aria-controls']: relatedTabPanel?.id,
['aria-selected']: !disabled && selected,
['data-text']: nodeText,
} as const;

if (typeof rest.href === 'string') {
return (
<Box
as="a"
ref={titleRef as RefObject<HTMLAnchorElement>}
{...sharedTabProps}
>
<Component {...componentProps}>
<div className={listTitleChildrenStyles} ref={ref}>
{children}
</div>
</Box>
</Component>
);
}

return (
<Box
as="button"
ref={titleRef as RefObject<HTMLButtonElement>}
{...sharedTabProps}
>
<div className={listTitleChildrenStyles} ref={ref}>
{children}
</div>
</Box>
);
};
},
);

TabTitle.displayName = 'TabTitle';

Expand Down
4 changes: 3 additions & 1 deletion packages/tabs/src/Tabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import {
storybookArgTypes,
storybookExcludedControlParams,
StoryMetaType,
} from '@lg-tools/storybook-utils';
Expand Down Expand Up @@ -31,7 +32,6 @@ const Lipsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec u
const defaultExcludedControls = [
...storybookExcludedControlParams,
'children',
'as',
'setSelected',
];

Expand All @@ -50,6 +50,7 @@ const meta: StoryMetaType<typeof Tabs> = {
},
},
args: {
as: 'button',
darkMode: false,
children: [
<Tab key="Tab 1" default name="Tab 1">
Expand Down Expand Up @@ -89,6 +90,7 @@ const meta: StoryMetaType<typeof Tabs> = {
],
},
argTypes: {
as: storybookArgTypes.as,
selected: { control: 'number' },
},
// TODO: Add subcomponent controls for Tab when supported by Storybook
Expand Down
8 changes: 1 addition & 7 deletions packages/tabs/src/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const Tabs = (props: AccessibleTabsProps) => {
validateAriaLabelProps(props, 'Tabs');

const {
as = 'button',
as,
baseFontSize: baseFontSizeProp,
children,
className,
Expand Down Expand Up @@ -210,12 +210,6 @@ Tabs.propTypes = {
setSelected: PropTypes.func,
selected: PropTypes.number,
className: PropTypes.string,
as: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.elementType,
PropTypes.element,
]),
};

export default Tabs;
5 changes: 2 additions & 3 deletions packages/tabs/src/Tabs/Tabs.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Either, HTMLElementProps, LgIdProps } from '@leafygreen-ui/lib';
import { PolymorphicAs } from '@leafygreen-ui/polymorphic';
import { BaseFontSize } from '@leafygreen-ui/tokens';

export interface TabsProps extends HTMLElementProps<'div'>, LgIdProps {
Expand Down Expand Up @@ -33,10 +34,8 @@ export interface TabsProps extends HTMLElementProps<'div'>, LgIdProps {

/**
* HTML Element that wraps title in Tab List.
*
* @type HTMLElement | React.Component
*/
as?: React.ElementType<any>;
as?: PolymorphicAs;

/**
* Accessible label that describes the set of tabs
Expand Down
6 changes: 3 additions & 3 deletions packages/tabs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
{
"path": "../a11y"
},
{
"path": "../box"
},
{
"path": "../descendants"
},
Expand All @@ -36,6 +33,9 @@
{
"path": "../palette"
},
{
"path": "../polymorphic"
},
{
"path": "../tokens"
},
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7453,9 +7453,9 @@ camelcase@^7.0.0:
integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==

caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001585, caniuse-lite@^1.0.30001587:
version "1.0.30001620"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz#78bb6f35b8fe315b96b8590597094145d0b146b4"
integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==
version "1.0.30001625"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz#ead1b155ea691d6a87938754d3cb119c24465b03"
integrity sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==

case-sensitive-paths-webpack-plugin@^2.4.0:
version "2.4.0"
Expand Down

0 comments on commit 9053f74

Please sign in to comment.