Skip to content

Commit

Permalink
Typescript Story: Breadcrumbs (#746)
Browse files Browse the repository at this point in the history
* 🚚 JSX to TSX

* 🚚 Export Props

* ♻️ Breadcrumbs typed

* ♻️ Breadcrumb typed

* ♻️ BreadcrumbsProps updated with HTMLElement instead of JSX

Mismatch with ref and legacyref if I used JSX... 🤯

* ♻️ Children should be ReactNode

* 💡 Children description

* ♻️ Export merged types
  • Loading branch information
pomfrida authored and vnys committed Nov 13, 2020
1 parent 7885ad0 commit 60f3569
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 148 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react'
import { withKnobs, boolean, number } from '@storybook/addon-knobs'
import styled from 'styled-components'
import { Breadcrumbs, Typography } from '@equinor/eds-core-react'
import {
Breadcrumbs,
BreadcrumbsProps,
Typography,
} from '@equinor/eds-core-react'
import { action } from '@storybook/addon-actions'
import { Meta, Story } from '@storybook/react'

const { Breadcrumb } = Breadcrumbs

Expand All @@ -24,27 +28,40 @@ const WrapContainer = styled.div`
export default {
title: 'Components/Breadcrumbs',
component: Breadcrumbs,
decorators: [withKnobs],
}
subcomponents: {
Breadcrumb,
},
} as Meta

const handleClick = (e) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
action('handleClick')(e.target.textContent)
}

export const Variations = () => {
export const Default: Story<BreadcrumbsProps> = (args) => {
return (
<Body>
<Breadcrumbs {...args}>
<Breadcrumb>Label One</Breadcrumb>
<Breadcrumb>Label Two</Breadcrumb>
<Breadcrumb>Label Three</Breadcrumb>
<Breadcrumb>Label Four</Breadcrumb>
<Breadcrumb>Label Five</Breadcrumb>
</Breadcrumbs>
</Body>
)
}

export const Variations: Story<BreadcrumbsProps> = () => {
return (
<Body>
<TextWrapper>
<Typography variant="h2">Normal</Typography>
</TextWrapper>
<Breadcrumbs>
<Breadcrumb href="#" onClick={handleClick}>
Store
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick}>
Fruits
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick} aria-current="page">
<Breadcrumb onClick={handleClick}>Store</Breadcrumb>
<Breadcrumb onClick={handleClick}>Fruits</Breadcrumb>
<Breadcrumb onClick={handleClick} aria-current="page">
Apple
</Breadcrumb>
</Breadcrumbs>
Expand All @@ -56,16 +73,10 @@ export const Variations = () => {
</Typography>
</TextWrapper>
<Breadcrumbs collapse>
<Breadcrumb href="#" onClick={handleClick}>
Store
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick}>
Fruits
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick}>
Apple
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick} aria-current="page">
<Breadcrumb onClick={handleClick}>Store</Breadcrumb>
<Breadcrumb onClick={handleClick}>Fruits</Breadcrumb>
<Breadcrumb onClick={handleClick}>Apple</Breadcrumb>
<Breadcrumb onClick={handleClick} aria-current="page">
Apple Juice
</Breadcrumb>
</Breadcrumbs>
Expand All @@ -77,18 +88,13 @@ export const Variations = () => {
</Typography>
</TextWrapper>
<Breadcrumbs>
<Breadcrumb maxWidth={30} href="#" onClick={handleClick}>
<Breadcrumb maxWidth={30} onClick={handleClick}>
Store
</Breadcrumb>
<Breadcrumb maxWidth={30} href="#" onClick={handleClick}>
<Breadcrumb maxWidth={30} onClick={handleClick}>
Fruits
</Breadcrumb>
<Breadcrumb
maxWidth={30}
href="#"
onClick={handleClick}
aria-current="page"
>
<Breadcrumb maxWidth={30} onClick={handleClick} aria-current="page">
Apple
</Breadcrumb>
</Breadcrumbs>
Expand All @@ -100,35 +106,13 @@ export const Variations = () => {
</TextWrapper>
<WrapContainer>
<Breadcrumbs>
<Breadcrumb href="#" onClick={handleClick}>
Store
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick}>
Fruits
</Breadcrumb>
<Breadcrumb href="#" onClick={handleClick} aria-current="page">
<Breadcrumb onClick={handleClick}>Store</Breadcrumb>
<Breadcrumb onClick={handleClick}>Fruits</Breadcrumb>
<Breadcrumb onClick={handleClick} aria-current="page">
Apple
</Breadcrumb>
</Breadcrumbs>
</WrapContainer>
</Body>
)
}

export const WithKnobs = () => {
const collapse = boolean('Collapse', false)
const maxWidth = number('Max Width', null)
return (
<Body>
<Breadcrumbs collapse={collapse}>
<Breadcrumb maxWidth={maxWidth}>Label One</Breadcrumb>
<Breadcrumb maxWidth={maxWidth}>Label Two</Breadcrumb>
<Breadcrumb maxWidth={maxWidth}>Label Three</Breadcrumb>
<Breadcrumb maxWidth={maxWidth}>Label Four</Breadcrumb>
<Breadcrumb maxWidth={maxWidth} aria-current="page">
Label Five
</Breadcrumb>
</Breadcrumbs>
</Body>
)
}
57 changes: 27 additions & 30 deletions libraries/core-react/src/Breadcrumbs/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Typography } from '../Typography'
import { Tooltip } from '../Tooltip'
import { breadcrumbs as tokens } from './Breadcrumbs.tokens'

type StyledProps = Pick<Props, 'maxWidth'>
type StyledProps = Pick<BreadcrumbProps, 'maxWidth'>

const StyledTypography = styled(Typography)<StyledProps>`
&:hover {
Expand All @@ -27,45 +27,42 @@ const StyledTypography = styled(Typography)<StyledProps>`
${({ maxWidth }) => css({ maxWidth })}
`

type Props = {
type BreadcrumbProps = {
/* Max label width in pixels,
* truncate long labels based on this width */
maxWidth?: number
/* click handler function */
onClick?: () => void
/** click handler function */
onClick?: (e: MouseEvent | KeyboardEvent) => void
/** Children is breadcrumb text */
children: string
/** Classname */
className?: string
}
} & JSX.IntrinsicElements['div']

export const Breadcrumb = forwardRef<HTMLDivElement, Props>(function Breadcrumb(
{ children, maxWidth, ...other },
ref,
) {
const props = {
...other,
ref,
maxWidth: maxWidth,
}
export const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>(
function Breadcrumb({ children, maxWidth, ...other }, ref) {
const props = {
...other,
ref,
maxWidth: maxWidth,
}

const tooltip = Boolean(maxWidth)

const tooltip = Boolean(maxWidth)
const WithTooltip = (
<Tooltip title={children}>
<StyledTypography link variant="body_short" {...props}>
{children}
</StyledTypography>
</Tooltip>
)

const WithTooltip = (
<Tooltip title={children}>
return tooltip ? (
WithTooltip
) : (
<StyledTypography link variant="body_short" {...props}>
{children}
</StyledTypography>
</Tooltip>
)

return tooltip ? (
WithTooltip
) : (
<StyledTypography link variant="body_short" {...props}>
{children}
</StyledTypography>
)
})
)
},
)

// Breadcrumb.displayName = 'eds-breadcrumb'
125 changes: 66 additions & 59 deletions libraries/core-react/src/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { forwardRef, useState, Fragment } from 'react'
import React, {
forwardRef,
useState,
Fragment,
HTMLAttributes,
ReactNode,
} from 'react'
import styled from 'styled-components'
import { breadcrumbs as tokens } from './Breadcrumbs.tokens'
import { Typography } from '../Typography'
Expand Down Expand Up @@ -36,73 +42,74 @@ const Collapsed = styled(Typography)`
text-decoration: none;
`

type Props = {
export type BreadcrumbsProps = {
/* Collapses the list of breadcrumbs so that only the first
* and last breadcrumb will be shown, with an ellipsis in between. */
collapse?: boolean
} & JSX.IntrinsicElements['nav']
/** Children should be of Breadcrumb component */
children: ReactNode
} & HTMLAttributes<HTMLElement>

export const Breadcrumbs = forwardRef<HTMLElement, Props>(function Breadcrumbs(
{ children, collapse, ...rest },
ref,
) {
const props = {
...rest,
ref,
}
export const Breadcrumbs = forwardRef<HTMLElement, BreadcrumbsProps>(
function Breadcrumbs({ children, collapse, ...rest }, ref) {
const props = {
...rest,
ref,
}

const [expanded, setExpanded] = useState(false)
const [expanded, setExpanded] = useState(false)

const collapsedCrumbs = (allCrumbs) => {
const handleExpandClick = () => {
setExpanded(true)
}
const collapsedCrumbs = (allCrumbs: JSX.Element[]) => {
const handleExpandClick = () => {
setExpanded(true)
}

if (allCrumbs.length < 3) {
return allCrumbs
}
if (allCrumbs.length < 3) {
return allCrumbs
}

return [
allCrumbs[0],
<Fragment key="collapsed">
<ListItem>
<Collapsed
link
role="button"
variant="body_short"
onClick={handleExpandClick}
tabIndex={0}
>
</Collapsed>
</ListItem>
<li aria-hidden>
<Separator variant="body_short">/</Separator>
</li>
</Fragment>,
allCrumbs[allCrumbs.length - 1],
]
}
return [
allCrumbs[0],
<Fragment key="collapsed">
<ListItem>
<Collapsed
link
role="button"
variant="body_short"
onClick={handleExpandClick}
tabIndex={0}
>
</Collapsed>
</ListItem>
<li aria-hidden>
<Separator variant="body_short">/</Separator>
</li>
</Fragment>,
allCrumbs[allCrumbs.length - 1],
]
}

const allCrumbs = React.Children.toArray(children).map((child, index) => (
// eslint-disable-next-line react/no-array-index-key
<Fragment key={`breadcrumb-${index}`}>
<ListItem>{child}</ListItem>
{index !== React.Children.toArray(children).length - 1 && (
<li aria-hidden>
<Separator variant="body_short">/</Separator>
</li>
)}
</Fragment>
))
const allCrumbs = React.Children.toArray(children).map((child, index) => (
// eslint-disable-next-line react/no-array-index-key
<Fragment key={`breadcrumb-${index}`}>
<ListItem>{child}</ListItem>
{index !== React.Children.toArray(children).length - 1 && (
<li aria-hidden>
<Separator variant="body_short">/</Separator>
</li>
)}
</Fragment>
))

return (
<nav {...props} aria-label="breadcrumbs">
<OrderedList>
{collapse && !expanded ? collapsedCrumbs(allCrumbs) : allCrumbs}
</OrderedList>
</nav>
)
})
return (
<nav {...props} aria-label="breadcrumbs">
<OrderedList>
{collapse && !expanded ? collapsedCrumbs(allCrumbs) : allCrumbs}
</OrderedList>
</nav>
)
},
)

// Breadcrumbs.displayName = 'eds-breadcrumbs'
6 changes: 3 additions & 3 deletions libraries/core-react/src/Breadcrumbs/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Breadcrumbs as BaseComponent } from './Breadcrumbs'
import { Breadcrumb } from './Breadcrumb'

type BreadcrumbsTypes = typeof BaseComponent & {
type BreadcrumbsProps = typeof BaseComponent & {
Breadcrumb: typeof Breadcrumb
}

const Breadcrumbs = BaseComponent as BreadcrumbsTypes
const Breadcrumbs = BaseComponent as BreadcrumbsProps

Breadcrumbs.Breadcrumb = Breadcrumb

export { Breadcrumbs }
export { Breadcrumbs, BreadcrumbsProps }
2 changes: 1 addition & 1 deletion libraries/core-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export { Popover } from './Popover'
export * from './Banner'
export * from './SelectionControls'
export * from './Progress'
export { Breadcrumbs } from './Breadcrumbs'
export * from './Breadcrumbs'
export { Menu } from './Menu'
export * from './Pagination'
/* eslint-enable */

0 comments on commit 60f3569

Please sign in to comment.