typescript src/tabs, src/typography (#491)

* first iteration

* tabs generic - remove as from typography

* typography using React.component function

* comma mistake

* ...

* review + add back `as` option for typography.

* linter

* quick fix

* us location descriptor
This commit is contained in:
Timo 2022-08-11 17:59:00 +02:00 committed by GitHub
parent 1dfffce606
commit c09380644b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 87 deletions

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import React from "react"; import React from "react";
import { TabContainer, TabItem } from "./Tabs"; import { TabContainer, TabItem } from "./Tabs";
import { ReactComponent as AudioIcon } from "../icons/Audio.svg"; import { ReactComponent as AudioIcon } from "../icons/Audio.svg";
import { ReactComponent as VideoIcon } from "../icons/Video.svg"; import { ReactComponent as VideoIcon } from "../icons/Video.svg";
@ -29,7 +30,7 @@ export default {
}, },
}; };
export const Tabs = () => ( export const Tabs: React.FC<{}> = () => (
<TabContainer> <TabContainer>
<TabItem <TabItem
title={ title={

View file

@ -17,19 +17,28 @@ limitations under the License.
import React, { useRef } from "react"; import React, { useRef } from "react";
import { useTabList, useTab, useTabPanel } from "@react-aria/tabs"; import { useTabList, useTab, useTabPanel } from "@react-aria/tabs";
import { Item } from "@react-stately/collections"; import { Item } from "@react-stately/collections";
import { useTabListState } from "@react-stately/tabs"; import { useTabListState, TabListState } from "@react-stately/tabs";
import styles from "./Tabs.module.css";
import classNames from "classnames"; import classNames from "classnames";
import { AriaTabPanelProps, TabListProps } from "@react-types/tabs";
import { Node } from "@react-types/shared";
export function TabContainer(props) { import styles from "./Tabs.module.css";
const state = useTabListState(props);
const ref = useRef(); interface TabContainerProps<T> extends TabListProps<T> {
className?: string;
}
export function TabContainer<T extends object>(
props: TabContainerProps<T>
): JSX.Element {
const state = useTabListState<T>(props);
const ref = useRef<HTMLUListElement>();
const { tabListProps } = useTabList(props, state, ref); const { tabListProps } = useTabList(props, state, ref);
return ( return (
<div className={classNames(styles.tabContainer, props.className)}> <div className={classNames(styles.tabContainer, props.className)}>
<ul {...tabListProps} ref={ref} className={styles.tabList}> <ul {...tabListProps} ref={ref} className={styles.tabList}>
{[...state.collection].map((item) => ( {[...state.collection].map((item) => (
<Tab key={item.key} item={item} state={state} /> <Tab item={item} state={state} />
))} ))}
</ul> </ul>
<TabPanel key={state.selectedItem?.key} state={state} /> <TabPanel key={state.selectedItem?.key} state={state} />
@ -37,9 +46,14 @@ export function TabContainer(props) {
); );
} }
function Tab({ item, state }) { interface TabProps<T> {
item: Node<T>;
state: TabListState<T>;
}
function Tab<T>({ item, state }: TabProps<T>): JSX.Element {
const { key, rendered } = item; const { key, rendered } = item;
const ref = useRef(); const ref = useRef<HTMLLIElement>();
const { tabProps } = useTab({ key }, state, ref); const { tabProps } = useTab({ key }, state, ref);
return ( return (
@ -56,8 +70,12 @@ function Tab({ item, state }) {
); );
} }
function TabPanel({ state, ...props }) { interface TabPanelProps<T> extends AriaTabPanelProps {
const ref = useRef(); state: TabListState<T>;
}
function TabPanel<T>({ state, ...props }: TabPanelProps<T>): JSX.Element {
const ref = useRef<HTMLDivElement>();
const { tabPanelProps } = useTabPanel(props, state, ref); const { tabPanelProps } = useTabPanel(props, state, ref);
return ( return (
<div {...tabPanelProps} ref={ref} className={styles.tabPanel}> <div {...tabPanelProps} ref={ref} className={styles.tabPanel}>

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import React from "react"; import React from "react";
import { Headline, Title, Subtitle, Body, Caption, Micro } from "./Typography"; import { Headline, Title, Subtitle, Body, Caption, Micro } from "./Typography";
export default { export default {
@ -24,7 +25,7 @@ export default {
}, },
}; };
export const Typography = () => ( export const Typography: React.FC<{}> = () => (
<> <>
<Headline>Headline Semi Bold</Headline> <Headline>Headline Semi Bold</Headline>
<Title>Title</Title> <Title>Title</Title>

View file

@ -14,12 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { forwardRef } from "react"; import { createElement, forwardRef, ReactNode } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { Link as RouterLink } from "react-router-dom"; import { Link as RouterLink } from "react-router-dom";
import * as H from "history";
import styles from "./Typography.module.css"; import styles from "./Typography.module.css";
export const Headline = forwardRef( interface TypographyProps {
children: ReactNode;
fontWeight?: string;
className?: string;
overflowEllipsis?: boolean;
as?: string;
}
export const Headline = forwardRef<HTMLHeadingElement, TypographyProps>(
( (
{ {
as: Component = "h1", as: Component = "h1",
@ -31,23 +41,23 @@ export const Headline = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Title = forwardRef( export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
( (
{ {
as: Component = "h2", as: Component = "h2",
@ -59,23 +69,23 @@ export const Title = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Subtitle = forwardRef( export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
( (
{ {
as: Component = "h3", as: Component = "h3",
@ -87,23 +97,23 @@ export const Subtitle = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Body = forwardRef( export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
( (
{ {
as: Component = "p", as: Component = "p",
@ -115,23 +125,23 @@ export const Body = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Caption = forwardRef( export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
( (
{ {
as: Component = "p", as: Component = "p",
@ -143,24 +153,24 @@ export const Caption = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles.caption, styles.caption,
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Micro = forwardRef( export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
( (
{ {
as: Component = "p", as: Component = "p",
@ -172,24 +182,29 @@ export const Micro = forwardRef(
}, },
ref ref
) => { ) => {
return ( return createElement(
<Component Component,
{...rest} {
className={classNames( ...rest,
className: classNames(
styles.micro, styles.micro,
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref,
> },
{children} children
</Component>
); );
} }
); );
export const Link = forwardRef( interface LinkProps extends TypographyProps {
to?: H.LocationDescriptor<unknown>;
color?: string;
href?: string;
}
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
( (
{ {
as, as,
@ -204,8 +219,8 @@ export const Link = forwardRef(
}, },
ref ref
) => { ) => {
const Component = as || (to ? RouterLink : "a"); const Component: string | RouterLink = as || (to ? RouterLink : "a");
let externalLinkProps; let externalLinkProps: { href: string; target: string; rel: string };
if (href) { if (href) {
externalLinkProps = { externalLinkProps = {
@ -215,21 +230,21 @@ export const Link = forwardRef(
}; };
} }
return ( return createElement(
<Component Component,
{...externalLinkProps} {
{...rest} ...externalLinkProps,
to={to} ...rest,
className={classNames( to: to,
className: classNames(
styles[color], styles[color],
styles[fontWeight], styles[fontWeight],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className
)} ),
ref={ref} ref: ref,
> },
{children} children
</Component>
); );
} }
); );