Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

docs(components): tab UI #1784

Merged
merged 22 commits into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3822b48
initial commit
lucivpav Aug 12, 2019
b7d6d99
hide empty tabs; move description under definition tab
lucivpav Aug 13, 2019
6724b5e
fix initial Definition tab not loading
lucivpav Aug 15, 2019
2b3d3db
Merge branch 'master' into docs/component-tabs
lucivpav Aug 15, 2019
cb36ca3
fix links to sections
lucivpav Aug 15, 2019
273122e
update changelog
lucivpav Aug 15, 2019
14fe7fd
fix highlight by using /definition suffix implicitly
lucivpav Aug 15, 2019
f8efb8b
use tabListBehavior for tab accessibility
lucivpav Aug 16, 2019
1e40fe8
Merge branch 'master' into docs/component-tabs
lucivpav Aug 16, 2019
5fcf4b1
redirect to default on incorrect component path suffix
lucivpav Aug 16, 2019
6215875
extract regex to constant
lucivpav Aug 16, 2019
0d2f2d0
Merge branch 'master' into docs/component-tabs
lucivpav Aug 16, 2019
c026628
show examples under Definition tab too
lucivpav Aug 16, 2019
ae90252
Merge branch 'master' into docs/component-tabs
lucivpav Aug 16, 2019
3f63422
Merge branch 'master' into docs/component-tabs
lucivpav Aug 16, 2019
5597554
Merge branch 'master' into docs/component-tabs
lucivpav Aug 19, 2019
26c1008
Merge branch 'docs/component-tabs' of github.com:stardust-ui/react in…
lucivpav Aug 19, 2019
83969d9
improve Definition and Usage tabs
lucivpav Aug 19, 2019
b881330
Merge branch 'master' into docs/component-tabs
lucivpav Aug 19, 2019
10a5b6b
move button example under Usage
lucivpav Aug 19, 2019
2c42ca1
Merge branch 'docs/component-tabs' of github.com:stardust-ui/react in…
lucivpav Aug 19, 2019
f6c1e8c
Merge branch 'master' into docs/component-tabs
lucivpav Aug 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add prototype for expandable control messages in `Chat` @sophieH29 ([#1765](https://github.com/stardust-ui/react/pull/1765))
- Remove Font Awesome icons from docs examples @lucivpav ([#1764](https://github.com/stardust-ui/react/pull/1764))
- Improve QuickStart code example @lucivpav ([#1797](https://github.com/stardust-ui/react/pull/1797))
- Implement component tab UI @lucivpav ([#1784](https://github.com/stardust-ui/react/pull/1784))

<!--------------------------------[ v0.36.1 ]------------------------------- -->
## [v0.36.1](https://github.com/stardust-ui/react/tree/v0.36.1) (2019-08-09)
Expand Down
40 changes: 40 additions & 0 deletions docs/src/components/ComponentDoc/ComponentBestPractices.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as _ from 'lodash'
import * as PropTypes from 'prop-types'
import * as React from 'react'

import { exampleBestPracticesContext } from 'docs/src/utils'
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'

interface ComponentBestPracticesProps {
displayName: string
}

export default class ComponentBestPractices extends React.Component<
ComponentBestPracticesProps,
any
> {
static propTypes = {
displayName: PropTypes.string.isRequired,
}

render() {
const { displayName } = this.props

const bestPracticesPath = _.find(exampleBestPracticesContext.keys(), path =>
new RegExp(`\/${displayName}\/BestPractices\/${displayName}BestPractices\.tsx$`).test(path),
)

if (!bestPracticesPath) {
return null
}

const bestPracticesElement = React.createElement(
exampleBestPracticesContext(bestPracticesPath).default,
) as any
if (!bestPracticesElement) {
return null
}

return <ExampleSection title="Best Practices">{bestPracticesElement}</ExampleSection>
}
}
144 changes: 120 additions & 24 deletions docs/src/components/ComponentDoc/ComponentDoc.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import * as React from 'react'
import { RouteComponentProps, withRouter } from 'react-router-dom'
import { Flex, Header, Icon, Dropdown, Text, Grid } from '@stardust-ui/react'
import { Flex, Header, Icon, Dropdown, Text, Grid, Menu, Box } from '@stardust-ui/react'

import { scrollToAnchor, examplePathToHash, getFormattedHash } from 'docs/src/utils'
import { getFormattedHash } from 'docs/src/utils'
import ComponentDocLinks from './ComponentDocLinks'
import ComponentDocSee from './ComponentDocSee'
import ComponentExamples from './ComponentExamples'
import { ComponentExamples } from './ComponentExamples'
import { ComponentUsage } from './ComponentUsage'
import ComponentProps from './ComponentProps'
import ComponentAccessibility from './ComponentDocAccessibility'
import { ComponentDocAccessibility } from './ComponentDocAccessibility'
import { ThemeContext } from 'docs/src/context/ThemeContext'
import ExampleContext from 'docs/src/context/ExampleContext'
import ComponentPlayground from 'docs/src/components/ComponentPlayground/ComponentPlayground'
import { ComponentInfo } from 'docs/src/types'
import ComponentBestPractices from './ComponentBestPractices'
import { tabListBehavior } from 'src/lib/accessibility'
import * as _ from 'lodash'

const exampleEndStyle: React.CSSProperties = {
textAlign: 'center',
Expand All @@ -21,22 +25,51 @@ const exampleEndStyle: React.CSSProperties = {

type ComponentDocProps = {
info: ComponentInfo
tabs: string[]
} & RouteComponentProps<{}>

class ComponentDoc extends React.Component<ComponentDocProps, any> {
state: any = {}

tabRegex = new RegExp(/[^\/]*$/)

getTabIndexOrRedirectToDefault(tab: string) {
const lowercaseTabs = _.map(this.props.tabs, tab => tab.toLowerCase())
const index = lowercaseTabs.indexOf(tab)
if (index === -1) {
const { history, location } = this.props
const at = location.pathname
const newLocation = at.replace(this.tabRegex, 'definition')
history.replace(newLocation)
return 0
}
return index
}

getCurrentTabTitle() {
return this.props.tabs[this.state.currentTabIndex]
}

componentWillMount() {
const { history, location } = this.props
const tab = location.pathname.match(this.tabRegex)[0]
const tabIndex = this.getTabIndexOrRedirectToDefault(tab)
this.setState({ currentTabIndex: tabIndex })

if (location.hash) {
const activePath = getFormattedHash(location.hash)
history.replace(`${location.pathname}#${activePath}`)
this.setState({ activePath })
if (this.props.tabs[tabIndex] === 'Props') {
this.setState({ defaultPropComponent: activePath })
}
}
}

componentWillReceiveProps({ info }) {
componentWillReceiveProps({ info, location }) {
const tab = location.pathname.match(this.tabRegex)[0]
this.setState({ currentTabIndex: this.getTabIndexOrRedirectToDefault(tab) })

if (info.displayName !== this.props.info.displayName) {
this.setState({ activePath: undefined })
}
Expand All @@ -48,6 +81,7 @@ class ComponentDoc extends React.Component<ComponentDocProps, any> {

handleExamplesRef = examplesRef => this.setState({ examplesRef })

/* TODO: bring back the right floating menu
handleSidebarItemClick = (e, { examplePath }) => {
const { history, location } = this.props
const activePath = examplePathToHash(examplePath)
Expand All @@ -56,6 +90,22 @@ class ComponentDoc extends React.Component<ComponentDocProps, any> {
// set active hash path
this.setState({ activePath }, scrollToAnchor)
}
*/

handleTabClick = (e, props) => {
const newIndex = props.index
const { history, location } = this.props
const at = location.pathname
const newLocation = at.replace(this.tabRegex, this.props.tabs[newIndex].toLowerCase())

history.replace(newLocation)
this.setState({ currentTabIndex: newIndex })
}

onPropComponentSelected = (e, props) => {
const { history, location } = this.props
history.replace(`${location.pathname}#${props.value}`)
}

render() {
const getA11ySelectionMessage = {
Expand Down Expand Up @@ -124,33 +174,74 @@ class ComponentDoc extends React.Component<ComponentDocProps, any> {
/>
</Flex.Item>
</Flex>
<Text styles={{ marginBottom: '1.4rem' }} content={info.docblock.description} />
<ComponentAccessibility info={info} />
<Menu
underlined
primary
defaultActiveIndex={0}
activeIndex={this.state.currentTabIndex}
items={this.props.tabs}
onItemClick={this.handleTabClick}
accessibility={tabListBehavior}
/>
<ComponentDocSee displayName={info.displayName} />
<ComponentProps displayName={info.displayName} props={info.props} />
</>
</Flex.Item>
</Flex>

<ComponentPlayground componentName={info.displayName} key={info.displayName} />
{this.getCurrentTabTitle() === 'Accessibility' && <ComponentDocAccessibility info={info} />}

{this.getCurrentTabTitle() === 'Props' && (
<ComponentProps
displayName={info.displayName}
props={info.props}
defaultComponentProp={this.state.defaultPropComponent}
onPropComponentSelected={this.onPropComponentSelected}
/>
)}

<Grid columns="auto 300px" styles={{ justifyContent: 'normal', justifyItems: 'stretch' }}>
<div ref={this.handleExamplesRef}>
<ExampleContext.Provider
value={{
activeAnchorName: activePath,
onExamplePassed: this.handleExamplePassed,
}}
{this.getCurrentTabTitle() === 'Definition' && (
<>
<Text
size="large"
styles={{ marginBottom: '1.4rem' }}
content={info.docblock.description}
/>
<Box styles={{ height: '10px' }} />
<ComponentPlayground componentName={info.displayName} key={info.displayName} />
<Grid
columns="auto 300px"
styles={{ justifyContent: 'normal', justifyItems: 'stretch' }}
>
<ComponentExamples displayName={info.displayName} />
</ExampleContext.Provider>
<div>
<ComponentBestPractices displayName={info.displayName} />
<div ref={this.handleExamplesRef}>
<ExampleContext.Provider
value={{
activeAnchorName: activePath,
onExamplePassed: this.handleExamplePassed,
}}
>
<ComponentExamples displayName={info.displayName} />
</ExampleContext.Provider>
</div>
</div>
</Grid>
</>
)}

<div style={exampleEndStyle}>
This is the bottom <Icon name="pointing down" />
{this.getCurrentTabTitle() === 'Usage' && (
<Grid columns="auto 300px" styles={{ justifyContent: 'normal', justifyItems: 'stretch' }}>
<div>
<ExampleContext.Provider
value={{
activeAnchorName: activePath,
onExamplePassed: this.handleExamplePassed,
}}
>
<ComponentUsage displayName={info.displayName} />
</ExampleContext.Provider>
</div>
</div>

{/* TODO: bring back the right floating menu
{/* TODO: bring back the right floating menu
<Box styles={{ width: '25%', paddingLeft: '14px' }}>
<ComponentSidebar
activePath={activePath}
Expand All @@ -160,7 +251,12 @@ class ComponentDoc extends React.Component<ComponentDocProps, any> {
/>
</Box>
*/}
</Grid>
</Grid>
)}

<div style={exampleEndStyle}>
This is the bottom <Icon name="pointing down" />
</div>
</div>
)
}
Expand Down
47 changes: 24 additions & 23 deletions docs/src/components/ComponentDoc/ComponentDocAccessibility.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import * as React from 'react'
import * as _ from 'lodash'
import { Flex, Loader, Text, Accordion } from '@stardust-ui/react'
import { Flex, Loader, Text, Provider } from '@stardust-ui/react'

const InlineMarkdown = React.lazy(() => import('./InlineMarkdown'))

const behaviorMenu = require('docs/src/behaviorMenu')

const ComponentDocAccessibility = ({ info }) => {
const description = _.get(_.find(info.docblock.tags, { title: 'accessibility' }), 'description')
export function containsAccessibility(info) {
const stem = getStem(info)
return !!getDescription(info) || !!getBehaviorName(stem)
}

function getDescription(info) {
return _.get(_.find(info.docblock.tags, { title: 'accessibility' }), 'description')
}

function getStem(info) {
const defaultValue = _.get(_.find(info.props, { name: 'accessibility' }), 'defaultValue')
return defaultValue && defaultValue.split('.').pop()
}

const stem = defaultValue && defaultValue.split('.').pop()
function getBehaviorName(stem) {
const filename = stem && `${stem}.ts`

const behaviorName = behaviorMenu.reduce((acc, next) => {
return behaviorMenu.reduce((acc, next) => {
return _.find(next.variations, { name: filename }) ? next.displayName : acc
}, null)
}

export const ComponentDocAccessibility = ({ info }) => {
const stem = getStem(info)
const description = getDescription(info)
const behaviorName = getBehaviorName(stem)

if (!behaviorName && !description) return null

Expand Down Expand Up @@ -57,28 +73,13 @@ const ComponentDocAccessibility = ({ info }) => {
</>
)

const accessPanels = [
{
key: 'accessibility',
content: { content: accessibilityDetails, styles: { paddingLeft: '14px' } },
title: {
content: <Text content="Accessibility" />,
as: 'span',
'aria-level': '2',
styles: { paddingBottom: '0', paddingTop: '0' },
},
},
]

return (
<Flex column>
<Flex.Item>
<>
<Accordion panels={accessPanels} />
</>
<Provider styles={{ paddingLeft: '14px', background: 'transparent' }}>
{accessibilityDetails}
</Provider>
</Flex.Item>
</Flex>
)
}

export default ComponentDocAccessibility
Loading