From 3378c68aedcf1b69283d4813238e37b385fe391d Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Sat, 26 Jan 2019 11:02:45 -0500 Subject: [PATCH] Starting to add SVG components --- src/components/Render/index.js | 20 +++------- src/rendering/SVG/index.js | 71 ++++++++++++++++++++++++++++++++++ src/rendering/SVG/style.js | 5 +++ src/rendering/Text/index.js | 70 +++++++++++++++++++++++++++++++++ src/rendering/Text/style.js | 8 ++++ src/rendering/style.js | 20 ++++++++++ 6 files changed, 180 insertions(+), 14 deletions(-) create mode 100644 src/rendering/SVG/index.js create mode 100644 src/rendering/SVG/style.js create mode 100644 src/rendering/Text/index.js create mode 100644 src/rendering/Text/style.js create mode 100644 src/rendering/style.js diff --git a/src/components/Render/index.js b/src/components/Render/index.js index 3aadb09..291faad 100644 --- a/src/components/Render/index.js +++ b/src/components/Render/index.js @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import PlaceholderIcon from 'react-feather/dist/icons/file-text'; +import SVG from 'rendering/SVG'; +import Text from 'rendering/Text'; import style from './style.module.css'; @@ -13,7 +14,7 @@ class Render extends React.PureComponent { svgContainer = React.createRef() - provideSVGData() { + provideSVGData = () => { if (!this.svgContainer.current) { return; } @@ -26,23 +27,14 @@ class Render extends React.PureComponent { }); } - componentDidMount() { - this.provideSVGData(); - } - - componentDidUpdate() { - this.provideSVGData(); - } - render() { const { expr } = this.props; - // eslint-disable-next-line no-console - console.log('Render:', this.constructor.name, expr); - // Demo rendering for now return
- + + { this.constructor.name } => { expr } +
; } } diff --git a/src/rendering/SVG/index.js b/src/rendering/SVG/index.js new file mode 100644 index 0000000..4db45d6 --- /dev/null +++ b/src/rendering/SVG/index.js @@ -0,0 +1,71 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import * as style from './style'; + +const namespaceProps = { + 'xmlns': 'http://www.w3.org/2000/svg', + 'xmlns:cc': 'http://creativecommons.org/ns#', + 'xmlns:rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' +}; +/* eslint-disable max-len */ +const metadata = ` + + + + + + + +`; +/* eslint-enable max-len */ + +class SVG extends React.PureComponent { + static propTypes = { + onReflow: PropTypes.func, + children: PropTypes.node, + padding: PropTypes.number + } + + static defaultProps = { + padding: 10 + } + + state = { + width: 0, + height: 0 + } + + handleReflow = box => { + const { padding } = this.props; + + this.setState({ + width: Math.round(box.width + 2 * padding), + height: Math.round(box.height + 2 * padding) + }, () => this.props.onReflow(this)); + } + + render() { + const { width, height } = this.state; + const { padding, children } = this.props; + + const svgProps = { + width, + height, + viewBox: [0, 0, width, height].join(' '), + style: style.image, + ...namespaceProps + }; + + return + + + { React.cloneElement(React.Children.only(children), { + onReflow: this.handleReflow + }) } + + ; + } +} + +export default SVG; diff --git a/src/rendering/SVG/style.js b/src/rendering/SVG/style.js new file mode 100644 index 0000000..12cf68b --- /dev/null +++ b/src/rendering/SVG/style.js @@ -0,0 +1,5 @@ +import { white } from 'rendering/style'; + +export const image = { + backgroundColor: white +}; diff --git a/src/rendering/Text/index.js b/src/rendering/Text/index.js new file mode 100644 index 0000000..0b446fd --- /dev/null +++ b/src/rendering/Text/index.js @@ -0,0 +1,70 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import * as style from './style'; + +class Text extends React.PureComponent { + static propTypes = { + quoted: PropTypes.bool, + onReflow: PropTypes.func, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]).isRequired + } + + state = { + transform: '' + } + + textRef = React.createRef() + + componentDidMount() { + this.reflow(); + } + + componentDidUpdate() { + this.reflow(); + } + + reflow() { + const box = this.textRef.current.getBBox(); + const transform = `translate(${ -box.x } ${ -box.y })`; + + if (transform === this.state.transform) { + return; // No update required + } + + this.setState({ transform }, () => this.props.onReflow(box)); + } + + renderContent() { + const { children, quoted } = this.props; + + if (!quoted) { + return children; + } + + return <> + + { children } + + ; + } + + render() { + const { transform } = this.state; + + const textProps = { + style: style.text, + transform, + ref: this.textRef + }; + + return + { this.renderContent() } + ; + } +} + +export default Text; diff --git a/src/rendering/Text/style.js b/src/rendering/Text/style.js new file mode 100644 index 0000000..514c0a3 --- /dev/null +++ b/src/rendering/Text/style.js @@ -0,0 +1,8 @@ +import { fontSize, fontFamily, grey } from 'rendering/style'; + +export const text = { + fontSize, fontFamily +}; +export const quote = { + fill: grey +}; diff --git a/src/rendering/style.js b/src/rendering/style.js new file mode 100644 index 0000000..2f896a0 --- /dev/null +++ b/src/rendering/style.js @@ -0,0 +1,20 @@ +// Styles are in JS instead of CSS so they will be inlined as attributes +// instead of served as a CSS file. This is so styles are included in +// downloaded SVG files. + +export const green = '#bada55'; +export const brown = '#6b6659'; +export const tan = '#cbcbba'; +export const black = '#000'; +export const grey = '#908c83'; +export const white = '#fff'; +export const blue = '#dae9e5'; + +export const fontFamily = 'Arial'; +export const fontSize = '16px'; +export const fontSizeSmall = '12px'; + +export const strokeBase = { + strokeWidth: '2px', + stroke: black +};