Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ComponentExample): clipboard and active state #2796

Merged
merged 1 commit into from
May 18, 2018
Merged
Changes from all commits
Commits
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
108 changes: 66 additions & 42 deletions docs/app/Components/ComponentDoc/ComponentExample/ComponentExample.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import * as Babel from '@babel/standalone'
import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component, createElement, isValidElement } from 'react'
import React, { PureComponent, createElement, isValidElement } from 'react'
import { withRouter } from 'react-router'
import { renderToStaticMarkup } from 'react-dom/server'
import { html } from 'js-beautify'
import copyToClipboard from 'copy-to-clipboard'

import { exampleContext, repoURL, scrollToAnchor } from 'docs/app/utils'
import { Divider, Grid, Menu, Visibility } from 'src'
import { shallowEqual } from 'src/lib'
import Editor from 'docs/app/Components/Editor/Editor'
import ComponentControls from '../ComponentControls'
import ComponentExampleTitle from './ComponentExampleTitle'
Expand Down Expand Up @@ -51,7 +50,7 @@ const errorStyle = {
* Renders a `component` and the raw `code` that produced it.
* Allows toggling the the raw `code` code block.
*/
class ComponentExample extends Component {
class ComponentExample extends PureComponent {
static contextTypes = {
onPassed: PropTypes.func,
}
Expand All @@ -68,32 +67,35 @@ class ComponentExample extends Component {
}

componentWillMount() {
const { examplePath, location } = this.props
const { examplePath } = this.props
const sourceCode = this.getOriginalSourceCode()

this.anchorName = _.kebabCase(_.last(examplePath.split('/')))

// show code for direct links to examples
const showCode = this.anchorName === location.hash.replace('#', '')
const exampleElement = this.renderOriginalExample()
const markup = renderToStaticMarkup(exampleElement)

this.setState({
exampleElement,
showCode,
handleMouseLeave: this.handleMouseLeave,
handleMouseMove: this.handleMouseMove,
showCode: this.isActiveHash(),
sourceCode,
markup,
})
}

componentWillReceiveProps(nextProps) {
const isActive = nextProps.location.hash === `#${this.anchorName}`
isActiveState = () => {
const { showCode, showHTML } = this.state

this.setState(() => ({ isActive }))
return showCode || showHTML
}

shouldComponentUpdate(nextProps, nextState) {
return !shallowEqual(this.state, nextState)
isActiveHash = () => this.anchorName === this.props.location.hash.replace('#', '')

updateHash = () => {
if (this.isActiveState()) this.setHashAndScroll()
else if (this.isActiveHash()) this.removeHash()
}

setHashAndScroll = () => {
Expand All @@ -105,47 +107,50 @@ class ComponentExample extends Component {

removeHash = () => {
const { history, location } = this.props

history.replace(location.pathname)

this.setState({
showCode: false,
showHTML: false,
})
}

handleDirectLinkClick = () => {
this.setHashAndScroll()
copyToClipboard(window.location.href)
}

handleMouseMove = _.throttle(
() => {
const { controlsVisible } = this.state
if (controlsVisible) return

this.setState({ controlsVisible: true })
},
200,
{ trailing: false },
)
handleMouseLeave = () => {
this.setState({
isHovering: false,
handleMouseLeave: null,
handleMouseMove: this.handleMouseMove,
})
}

handleMouseLeave = () => this.setState({ controlsVisible: false })
handleMouseMove = () => {
this.setState({
isHovering: true,
handleMouseLeave: this.handleMouseLeave,
handleMouseMove: null,
})
}

handleShowCodeClick = (e) => {
e.preventDefault()

const { showCode, showHTML } = this.state

this.setState({ showCode: !showCode })
const { showCode } = this.state

if (!showCode) this.setHashAndScroll()
else if (!showHTML) this.removeHash()
this.setState({ showCode: !showCode }, this.updateHash)
}

handleShowHTMLClick = (e) => {
e.preventDefault()

const { showCode, showHTML } = this.state

this.setState({ showHTML: !showHTML })
const { showHTML } = this.state

if (!showHTML) this.setHashAndScroll()
else if (!showCode) this.removeHash()
this.setState({ showHTML: !showHTML }, this.updateHash)
}

handlePass = () => {
Expand All @@ -163,8 +168,8 @@ class ComponentExample extends Component {
resetJSX = () => {
const { sourceCode } = this.state
const original = this.getOriginalSourceCode()
// eslint-disable-next-line no-alert
if (sourceCode !== original && confirm('Lose your changes?')) {
// eslint-disable-line no-alert
this.setState({ sourceCode: original })
this.renderSourceCode()
}
Expand Down Expand Up @@ -289,8 +294,7 @@ class ComponentExample extends Component {
}, 100)

handleChangeCode = (sourceCode) => {
this.setState({ sourceCode })
this.renderSourceCode()
this.setState({ sourceCode }, this.renderSourceCode)
}

setGitHubHrefs = () => {
Expand Down Expand Up @@ -432,20 +436,40 @@ class ComponentExample extends Component {

render() {
const { children, description, suiVersion, title } = this.props
const { controlsVisible, exampleElement, isActive, showCode, showHTML } = this.state
const {
handleMouseLeave,
handleMouseMove,
exampleElement,
isHovering,
showCode,
showHTML,
} = this.state

const isActive = this.isActiveHash() || this.isActiveState()

const exampleStyle = {
marginBottom: '1em',
boxShadow: isActive && '0 0 30px #ccc',
position: 'relative',
transition: 'box-shadow 200ms, background 200ms',
...(isActive
? {
background: '#fff',
boxShadow: '0 0 30px #ccc',
}
: isHovering && {
background: '#fff',
boxShadow: '0 0 10px #ccc',
zIndex: 1,
}),
}

return (
<Visibility once={false} onTopPassed={this.handlePass} onTopPassedReverse={this.handlePass}>
<Grid
className='docs-example'
padded='vertically'
id={this.anchorName}
onMouseMove={this.handleMouseMove}
onMouseLeave={this.handleMouseLeave}
onMouseLeave={handleMouseLeave}
onMouseMove={handleMouseMove}
style={exampleStyle}
>
<Grid.Row>
Expand All @@ -464,7 +488,7 @@ class ComponentExample extends Component {
onShowHTML={this.handleShowHTMLClick}
showCode={showCode}
showHTML={showHTML}
visible={controlsVisible}
visible={isActive || isHovering}
/>
</Grid.Column>
</Grid.Row>
Expand Down