UNPKG

materialuiupgraded

Version:

Material-UI's workspace package

286 lines (268 loc) 8.83 kB
import React from 'react'; import LZString from 'lz-string'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import copy from 'clipboard-copy'; import { withStyles } from '@material-ui/core/styles'; import IconButton from '@material-ui/core/IconButton'; import Collapse from '@material-ui/core/Collapse'; import EditIcon from '@material-ui/icons/Edit'; import CodeIcon from '@material-ui/icons/Code'; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import Tooltip from '@material-ui/core/Tooltip'; import Github from '@material-ui/docs/svgIcons/GitHub'; import MarkdownElement from '@material-ui/docs/MarkdownElement'; import { getDependencies } from 'docs/src/modules/utils/helpers'; function compress(object) { return LZString.compressToBase64(JSON.stringify(object)) .replace(/\+/g, '-') // Convert '+' to '-' .replace(/\//g, '_') // Convert '/' to '_' .replace(/=+$/, ''); // Remove ending '=' } function addHiddenInput(form, name, value) { const input = document.createElement('input'); input.type = 'hidden'; input.name = name; input.value = value; form.appendChild(input); } function getDemo(props) { return { title: 'Material demo', description: props.githubLocation, dependencies: getDependencies(props.raw), files: { 'demo.js': props.raw, 'index.js': ` import React from 'react'; import ReactDOM from 'react-dom'; import Demo from './demo'; ReactDOM.render(<Demo />, document.querySelector('#root')); `, 'index.html': ` <body> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <div id="root"></div> </body> `, }, }; } const styles = theme => ({ root: { position: 'relative', marginBottom: 40, marginLeft: -theme.spacing.unit * 2, marginRight: -theme.spacing.unit * 2, [theme.breakpoints.up('sm')]: { padding: `0 ${theme.spacing.unit}px`, marginLeft: 0, marginRight: 0, }, }, demo: theme.mixins.gutters({ borderRadius: theme.shape.borderRadius, backgroundColor: theme.palette.type === 'light' ? theme.palette.grey[200] : theme.palette.grey[900], display: 'flex', justifyContent: 'center', paddingTop: theme.spacing.unit * 2, paddingBottom: theme.spacing.unit * 2, [theme.breakpoints.up('sm')]: { paddingLeft: theme.spacing.unit * 3, paddingRight: theme.spacing.unit * 3, paddingTop: theme.spacing.unit * 6, paddingBottom: theme.spacing.unit * 3, }, }), demoHiddenHeader: { paddingTop: theme.spacing.unit * 2, [theme.breakpoints.up('sm')]: { paddingTop: theme.spacing.unit * 3, }, }, header: { display: 'none', [theme.breakpoints.up('sm')]: { display: 'flex', flip: false, position: 'absolute', top: 0, right: theme.spacing.unit, }, }, code: { display: 'none', padding: 0, margin: 0, [theme.breakpoints.up('sm')]: { display: 'block', }, '& pre': { overflow: 'auto', margin: '0px !important', borderRadius: '0px !important', }, }, }); class Demo extends React.Component { state = { anchorEl: null, codeOpen: false, }; handleClickMore = event => { this.setState({ anchorEl: event.currentTarget }); }; handleCloseMore = () => { this.setState({ anchorEl: null }); }; handleClickCodeOpen = () => { this.setState(state => ({ codeOpen: !state.codeOpen, })); }; handleClickCodeSandbox = () => { const demo = getDemo(this.props); const parameters = compress({ files: { 'package.json': { content: { title: demo.title, description: demo.description, dependencies: demo.dependencies, }, }, 'demo.js': { content: demo.files['demo.js'], }, 'index.js': { content: demo.files['index.js'], }, 'index.html': { content: demo.files['index.html'], }, }, }); const form = document.createElement('form'); form.method = 'POST'; form.target = '_blank'; form.action = 'https://codeSandbox.io/api/v1/sandboxes/define'; addHiddenInput(form, 'parameters', parameters); document.body.appendChild(form); form.submit(); document.body.removeChild(form); }; handleClickCopy = async () => { try { await copy(this.props.raw); } finally { this.handleCloseMore(); } }; handleClickStackBlitz = () => { const demo = getDemo(this.props); const form = document.createElement('form'); form.method = 'POST'; form.target = '_blank'; form.action = 'https://stackblitz.com/run'; addHiddenInput(form, 'project[template]', 'javascript'); addHiddenInput(form, 'project[title]', demo.title); addHiddenInput(form, 'project[description]', demo.description); addHiddenInput(form, 'project[dependencies]', JSON.stringify(demo.dependencies)); Object.entries(demo.files).forEach(([key, value]) => { addHiddenInput(form, `project[files][${key}]`, value); }); document.body.appendChild(form); form.submit(); document.body.removeChild(form); this.handleCloseMore(); }; render() { const { classes, demoOptions, githubLocation, index, js: DemoComponent, raw } = this.props; const { anchorEl, codeOpen } = this.state; return ( <div className={classes.root}> {demoOptions.hideHeader ? null : ( <div> <div className={classes.header}> <Tooltip title="See the source on GitHub" placement="top"> <IconButton href={githubLocation} target="_blank" aria-label="GitHub"> <Github /> </IconButton> </Tooltip> {demoOptions.hideEditButton ? null : ( <Tooltip title="Edit in CodeSandbox" placement="top"> <IconButton onClick={this.handleClickCodeSandbox} aria-label="CodeSandbox"> <EditIcon /> </IconButton> </Tooltip> )} <Tooltip title={codeOpen ? 'Hide the source' : 'Show the source'} placement="top"> <IconButton onClick={this.handleClickCodeOpen} aria-label={`Source of demo n°${index}`} > <CodeIcon /> </IconButton> </Tooltip> <IconButton onClick={this.handleClickMore} aria-owns={anchorEl ? 'demo-menu-more' : null} aria-haspopup="true" aria-label="See more" > <MoreVertIcon /> </IconButton> <Menu id="demo-menu-more" anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={this.handleCloseMore} getContentAnchorEl={null} anchorOrigin={{ vertical: 'top', horizontal: 'right', }} transformOrigin={{ vertical: 'top', horizontal: 'right', }} > <MenuItem onClick={this.handleClickCopy}>Copy the source</MenuItem> {demoOptions.hideEditButton ? null : ( <MenuItem onClick={this.handleClickStackBlitz}>Edit in StackBlitz</MenuItem> )} </Menu> </div> <Collapse in={codeOpen} unmountOnExit> <MarkdownElement dir="ltr" className={classes.code} text={`\`\`\`jsx\n${raw}\n\`\`\``} /> </Collapse> </div> )} <div className={classNames(classes.demo, { [classes.demoHiddenHeader]: demoOptions.hideHeader, })} > <DemoComponent /> </div> </div> ); } } Demo.propTypes = { classes: PropTypes.object.isRequired, demoOptions: PropTypes.object.isRequired, githubLocation: PropTypes.string.isRequired, index: PropTypes.number.isRequired, js: PropTypes.func.isRequired, raw: PropTypes.string.isRequired, }; export default withStyles(styles)(Demo);