diff --git a/src/components/App/context.js b/src/components/App/context.js
index e4dab10..0207df5 100644
--- a/src/components/App/context.js
+++ b/src/components/App/context.js
@@ -1,5 +1,149 @@
import React from 'react';
+import PropTypes from 'prop-types';
+import URLSearchParams from '@ungap/url-search-params';
const AppContext = React.createContext();
+const toUrl = params => new URLSearchParams(params).toString();
+
+const readURLHash = () => {
+ const query = document.location.hash.slice(1);
+ const params = new URLSearchParams(query);
+
+ if (params.get('syntax')) {
+ return {
+ syntax: params.get('syntax'),
+ expr: params.get('expr')
+ };
+ } else {
+ // Assuming old-style URL
+ return {
+ syntax: 'js',
+ expr: query || ''
+ };
+ }
+};
+
+const createSvgLink = async ({ svg }) => {
+ try {
+ const type = 'image/svg+xml';
+ const blob = new Blob([svg], { type });
+
+ return {
+ url: URL.createObjectURL(blob),
+ label: 'Download SVG',
+ filename: 'image.svg',
+ type
+ };
+ }
+ catch (e) {
+ console.error(e); // eslint-disable-line no-console
+ }
+};
+
+const createPngLink = async ({ svg, width, height }) => {
+ try {
+ const type = 'image/png';
+ const canvas = document.createElement('canvas');
+ const context = canvas.getContext('2d');
+ const loader = new Image();
+
+ loader.width = canvas.width = Number(width) * 2;
+ loader.height = canvas.height = Number(height) * 2;
+
+ await new Promise(resolve => {
+ loader.onload = resolve;
+ loader.src = 'data:image/svg+xml,' + encodeURIComponent(svg);
+ });
+
+ context.drawImage(loader, 0, 0, loader.width, loader.height);
+
+ const blob = await new Promise(resolve => canvas.toBlob(resolve, type));
+
+ return {
+ url: URL.createObjectURL(blob),
+ label: 'Download PNG',
+ filename: 'image.png',
+ type
+ };
+ }
+ catch (e) {
+ console.error(e); // eslint-disable-line no-console
+ }
+};
+
+class AppContextProvider extends React.PureComponent {
+ state = {}
+
+ mutations = {
+ svgData: async ({ svg, width, height }) => {
+ if (svg !== this.state.svg) {
+ this.setState({
+ svg,
+ svgLink: await createSvgLink({ svg }),
+ pngLink: await createPngLink({ svg, width, height })
+ });
+ }
+ },
+
+ renderExpr: ({ syntax, expr }) => {
+ if (expr) {
+ document.location.hash = toUrl({ syntax, expr });
+ }
+ }
+ }
+
+ componentDidMount() {
+ // Gatsby doesn't have document.location, so readURLHash can't be called
+ // until here
+ this.setState(readURLHash());
+
+ window.addEventListener('hashchange', this.handleHashChange);
+ this.handleHashChange();
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('hashchange', this.handleHashChange);
+ }
+
+ handleHashChange = () => {
+ const { expr, syntax } = readURLHash();
+
+ if (!expr) {
+ return;
+ }
+
+ this.setState({
+ syntax,
+ expr,
+ permalinkUrl: document.location.toString()
+ });
+
+ if (this.props.onExpressionChange) {
+ this.props.onExpressionChange({ syntax, expr });
+ }
+ }
+
+ render() {
+ const { children } = this.props;
+ const context = {
+ ...this.state,
+ ...this.mutations
+ };
+
+ return
+ { children }
+ ;
+ }
+}
+
+AppContextProvider.propTypes = {
+ onExpressionChange: PropTypes.func,
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node
+ ]).isRequired
+};
+
+export { AppContextProvider };
export default AppContext;
diff --git a/src/components/App/index.js b/src/components/App/index.js
index 009c171..724ce63 100644
--- a/src/components/App/index.js
+++ b/src/components/App/index.js
@@ -1,151 +1,26 @@
import React from 'react';
-import URLSearchParams from '@ungap/url-search-params';
-import AppContext from 'components/App/context';
+import { AppContextProvider } from 'components/App/context';
import Form from 'components/Form';
import Loader from 'components/Loader';
import Message from 'components/Message';
import SVG from 'components/SVG';
-const toUrl = params => new URLSearchParams(params).toString();
-
-const readURLHash = () => {
- const query = document.location.hash.slice(1);
- const params = new URLSearchParams(query);
-
- if (params.get('syntax')) {
- return {
- syntax: params.get('syntax'),
- expr: params.get('expr')
- };
- } else {
- // Assuming old-style URL
- return {
- syntax: 'js',
- expr: query || ''
- };
- }
-};
-
-const createSvgLink = async ({ svg }) => {
- try {
- const type = 'image/svg+xml';
- const blob = new Blob([svg], { type });
-
- return {
- url: URL.createObjectURL(blob),
- label: 'Download SVG',
- filename: 'image.svg',
- type
- };
- }
- catch (e) {
- console.error(e); // eslint-disable-line no-console
- }
-};
-
-const createPngLink = async ({ svg, width, height }) => {
- try {
- const type = 'image/png';
- const canvas = document.createElement('canvas');
- const context = canvas.getContext('2d');
- const loader = new Image();
-
- loader.width = canvas.width = Number(width) * 2;
- loader.height = canvas.height = Number(height) * 2;
-
- await new Promise(resolve => {
- loader.onload = resolve;
- loader.src = 'data:image/svg+xml,' + encodeURIComponent(svg);
- });
-
- context.drawImage(loader, 0, 0, loader.width, loader.height);
-
- const blob = await new Promise(resolve => canvas.toBlob(resolve, type));
-
- return {
- url: URL.createObjectURL(blob),
- label: 'Download PNG',
- filename: 'image.png',
- type
- };
- }
- catch (e) {
- console.error(e); // eslint-disable-line no-console
- }
-};
-
class App extends React.PureComponent {
state={}
- componentDidMount() {
- // Gatsby doesn't have document.location, so readURLHash can't be called
- // until here
- this.setState(readURLHash());
-
- window.addEventListener('hashchange', this.handleHashChange);
- this.handleHashChange();
- }
-
- componentWillUnmount() {
- window.removeEventListener('hashchange', this.handleHashChange);
- }
-
- handleHashChange = () => {
- const { expr, syntax } = readURLHash();
-
- if (!expr) {
- return;
- }
-
- this.setState({
- syntax,
- expr,
- permalinkUrl: document.location.toString()
- });
+ handleRender = ({ syntax, expr }) => {
console.log('Render:', syntax, expr); // eslint-disable-line no-console
+ this.setState({ syntax, expr });
}
handleRetry = event => {
event.preventDefault();
- this.handleHashChange();
- }
-
- renderExpr = ({ expr, syntax }) => {
- if (expr) {
- document.location.hash = toUrl({ syntax, expr });
- }
- }
-
- svgData = async ({ svg, width, height }) => {
- if (svg !== this.state.svg) {
- this.setState({
- svg,
- svgLink: await createSvgLink({ svg }),
- pngLink: await createPngLink({ svg, width, height })
- });
- }
+ this.handleRender(this.state);
}
render() {
- const {
- svgLink,
- pngLink,
- permalinkUrl,
- expr,
- syntax
- } = this.state;
- const context = {
- svgLink,
- pngLink,
- permalinkUrl,
- expr,
- syntax,
- renderExpr: this.renderExpr,
- svgData: this.svgData
- };
-
- return
+ return
@@ -156,7 +31,7 @@ class App extends React.PureComponent {
- ;
+ ;
}
}