Skip to content

Commit

Permalink
Merge pull request #98 from probablyup/master
Browse files Browse the repository at this point in the history
upgrade to use React v16 context, polyfill for older Reacts
  • Loading branch information
sofiapoh authored Oct 15, 2018
2 parents 25ff27f + e1db4e7 commit 0d1bff5
Show file tree
Hide file tree
Showing 8 changed files with 427 additions and 293 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"dependencies": {
"buble": "^0.19.3",
"core-js": "^2.4.1",
"create-react-context": "^0.2.3",
"dom-iterator": "^1.0.0",
"prismjs": "1.6",
"prop-types": "^15.5.8",
Expand Down Expand Up @@ -49,6 +50,7 @@
"rollup-plugin-node-resolve": "^3.0.2",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-uglify-es": "^0.0.1",
"styled-components": "^4.0.0-beta.8",
"typescript": "^2.9.2",
"typings-tester": "^0.3.1"
},
Expand Down
44 changes: 23 additions & 21 deletions src/components/Live/LiveEditor.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import React from 'react'
import PropTypes from 'prop-types'
import { LiveContextTypes } from './LiveProvider'
import Editor from '../Editor'
import React from 'react';
import PropTypes from 'prop-types';
import { LiveContext } from './LiveProvider';
import Editor from '../Editor';

const LiveEditor = (props, { live }) => (
<Editor
{...props}
code={live.code}
onChange={code => {
live.onChange(code)
export default function LiveEditor(props) {
return (
<LiveContext.Consumer>
{({ code, onChange }) => (
<Editor
{...props}
code={code}
onChange={code => {
onChange(code);

if (typeof props.onChange === 'function') {
props.onChange(code)
}
}}
/>
)

LiveEditor.contextTypes = LiveContextTypes
LiveEditor.propTypes = { onChange: PropTypes.func }

export default LiveEditor
if (typeof props.onChange === 'function') {
props.onChange(code);
}
}}
/>
)}
</LiveContext.Consumer>
);
}

LiveEditor.propTypes = { onChange: PropTypes.func };
31 changes: 16 additions & 15 deletions src/components/Live/LiveError.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React from 'react'
import { LiveContextTypes } from './LiveProvider'
import cn from '../../utils/cn'
import React from 'react';
import { LiveContext } from './LiveProvider';
import cn from '../../utils/cn';

const LiveError = ({ className, ...rest }, { live }) => live.error ? (
<div
{...rest}
className={cn('react-live-error', className)}
>
{live.error}
</div>
) : null

LiveError.contextTypes = LiveContextTypes

export default LiveError
export default function LiveError({ className, ...rest }) {
return (
<LiveContext.Consumer>
{({ error }) =>
error ? (
<div {...rest} className={cn('react-live-error', className)}>
{error}
</div>
) : null
}
</LiveContext.Consumer>
);
}
23 changes: 8 additions & 15 deletions src/components/Live/LivePreview.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import React from 'react'
import { LiveContextTypes } from './LiveProvider'
import cn from '../../utils/cn'

const LivePreview = ({ className, ...rest }, { live: { element }}) => {
const Element = element;
import React from 'react';
import { LiveContext } from './LiveProvider';
import cn from '../../utils/cn';

export default function LivePreview({ className, ...rest }) {
return (
<div
{...rest}
className={cn('react-live-preview', className)}
>
{Element && <Element />}
<div {...rest} className={cn('react-live-preview', className)}>
<LiveContext.Consumer>
{({ element: Element }) => Element && <Element />}
</LiveContext.Consumer>
</div>
);
}

LivePreview.contextTypes = LiveContextTypes

export default LivePreview
112 changes: 45 additions & 67 deletions src/components/Live/LiveProvider.js
Original file line number Diff line number Diff line change
@@ -1,92 +1,66 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { generateElement, renderElementAsync } from '../../utils/transpile'
import cn from '../../utils/cn'
import Style from '../Editor/Style'
import createContext from 'create-react-context';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { generateElement, renderElementAsync } from '../../utils/transpile';
import cn from '../../utils/cn';
import Style from '../Editor/Style';

export const LiveContextTypes = {
live: PropTypes.shape({
code: PropTypes.string,
error: PropTypes.string,

onError: PropTypes.func,
onChange: PropTypes.func,

element: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.element,
PropTypes.func
])
})
}

class LiveProvider extends Component {
static childContextTypes = LiveContextTypes
export const LiveContext = createContext('live');

export default class LiveProvider extends Component {
static defaultProps = {
code: '',
mountStylesheet: true,
noInline: false
}
noInline: false,
};

static propTypes = {
className: PropTypes.string,
code: PropTypes.string,
scope: PropTypes.object,
mountStylesheet: PropTypes.bool,
noInline: PropTypes.bool,
transformCode: PropTypes.func
}
transformCode: PropTypes.func,
};

onChange = code => {
const { scope, transformCode, noInline } = this.props
this.transpile({ code, scope, transformCode, noInline })
}
const { scope, transformCode, noInline } = this.props;
this.transpile({ code, scope, transformCode, noInline });
};

onError = error => {
this.setState({ error: error.toString() })
}
this.setState({ error: error.toString() });
};

transpile = ({ code, scope, transformCode, noInline = false }) => {
// Transpilation arguments
const input = {
code: transformCode ? transformCode(code) : code,
scope
}
const errorCallback = err => this.setState({ element: undefined, error: err.toString() })
const renderElement = element => this.setState({ ...state, element })
scope,
};
const errorCallback = err =>
this.setState({ element: undefined, error: err.toString() });
const renderElement = element => this.setState({ ...state, element });

// State reset object
const state = { unsafeWrapperError: undefined, error: undefined }
const state = { unsafeWrapperError: undefined, error: undefined };

try {
if (noInline) {
this.setState({ ...state, element: null }) // Reset output for async (no inline) evaluation
renderElementAsync(input, renderElement, errorCallback)
this.setState({ ...state, element: null }); // Reset output for async (no inline) evaluation
renderElementAsync(input, renderElement, errorCallback);
} else {
renderElement(
generateElement(input, errorCallback)
)
renderElement(generateElement(input, errorCallback));
}
} catch (error) {
this.setState({ ...state, error: error.toString() })
this.setState({ ...state, error: error.toString() });
}
}

getChildContext = () => ({
live: {
...this.state,
code: this.props.code,
onError: this.onError,
onChange: this.onChange
}
})
};

componentWillMount() {
const { code, scope, transformCode, noInline } = this.props
const { code, scope, transformCode, noInline } = this.props;

this.transpile({ code, scope, transformCode, noInline })
this.transpile({ code, scope, transformCode, noInline });
}

componentWillReceiveProps({ code, scope, noInline, transformCode }) {
Expand All @@ -96,7 +70,7 @@ class LiveProvider extends Component {
noInline !== this.props.noInline ||
transformCode !== this.props.transformCode
) {
this.transpile({ code, scope, transformCode, noInline })
this.transpile({ code, scope, transformCode, noInline });
}
}

Expand All @@ -110,18 +84,22 @@ class LiveProvider extends Component {
transformCode,
scope,
...rest
} = this.props
} = this.props;

return (
<div
className={cn('react-live', className)}
{...rest}
<LiveContext.Provider
value={{
...this.state,
code: this.props.code,
onError: this.onError,
onChange: this.onChange,
}}
>
{mountStylesheet && <Style />}
{children}
</div>
)
<div className={cn('react-live', className)} {...rest}>
{mountStylesheet && <Style />}
{children}
</div>
</LiveContext.Provider>
);
}
}

export default LiveProvider
19 changes: 9 additions & 10 deletions src/hoc/withLive.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React, { Component } from 'react'
import { LiveContextTypes } from '../components/Live/LiveProvider'
import React, { Component } from 'react';
import { LiveContext } from '../components/Live/LiveProvider';

const withLive = WrappedComponent => {
export default function withLive(WrappedComponent) {
class WithLive extends Component {
static contextTypes = LiveContextTypes

render() {
const { live } = this.context
return <WrappedComponent live={live} {...this.props} />
return (
<LiveContext.Consumer>
{live => <WrappedComponent live={live} {...this.props} />}
</LiveContext.Consumer>
);
}
}

return WithLive
return WithLive;
}

export default withLive
30 changes: 18 additions & 12 deletions stories/Live.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import React from 'react';
import styled from 'styled-components';
import { storiesOf } from '@storybook/react';
import { withKnobs, boolean } from '@storybook/addon-knobs/react';

import {
LiveProvider,
LiveEditor,
LiveError,
LivePreview
} from '../src/index'
import { LiveProvider, LiveEditor, LiveError, LivePreview } from '../src/index';

const code = (`
const code = `
<strong>
Hello World!
Next Indent Level
</strong>
`).trim()
`.trim();

const StyledLivePreview = styled(LivePreview)`
background: green;
color: white;
padding: 3px;
`;

storiesOf('Live', module)
.addDecorator(withKnobs)
.add('default', () => (
<LiveProvider
code={code}
noInline={boolean('No inline evaluation', false)}
>
<LiveProvider code={code} noInline={boolean('No inline evaluation', false)}>
<LiveEditor />
<LiveError />
<LivePreview />
</LiveProvider>
))
.add('styled subcomponents', () => (
<LiveProvider code={code} noInline={boolean('No inline evaluation', false)}>
<LiveEditor />
<LiveError />
<StyledLivePreview />
</LiveProvider>
));
Loading

0 comments on commit 0d1bff5

Please sign in to comment.