Moving to using a decorator mixin instead of base class for SVGs

This commit is contained in:
Jeff Avallone 2018-02-17 16:58:49 -05:00
parent 44e6dae289
commit 6e8d7c297a
12 changed files with 127 additions and 101 deletions

View File

@ -42,6 +42,7 @@
"transform-runtime",
"transform-class-properties",
"transform-object-rest-spread",
"transform-decorators-legacy",
"syntax-dynamic-import"
],
"env": {
@ -59,6 +60,7 @@
"transform-runtime",
"transform-class-properties",
"transform-object-rest-spread",
"transform-decorators-legacy",
"syntax-dynamic-import"
]
}
@ -145,6 +147,7 @@
"babel-loader": "^7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",

View File

@ -1,8 +1,11 @@
/* eslint-disable react/prop-types */
import React from 'react';
import Base from 'components/SVG/Base';
import reflowable from 'components/SVG/reflowable';
class SVGElement extends Base {
@reflowable
class SVGElement extends React.PureComponent {
reflow() {
return this.setBBox(this.props.bbox);
}

View File

@ -1,76 +0,0 @@
import React from 'react';
import { Map } from 'immutable';
class Base extends React.PureComponent {
_currentBBox() {
return this.tempBBox ? this.tempBBox : (this.state || {}).bbox;
}
setStateAsync(state) {
return new Promise(resolve => {
this.setState(state, resolve);
});
}
async setBBox(box, recalculate = {}) {
const bbox = (this._currentBBox() || Map({ width: 0, height: 0})).withMutations(bbox => {
bbox.merge(box);
if (!bbox.has('axisY') || recalculate.axisY) {
bbox.set('axisY', bbox.get('height') / 2);
}
if (!bbox.has('axisX1') || recalculate.axisX1) {
bbox.set('axisX1', 0);
}
if (!bbox.has('axisX2') || recalculate.axisX2) {
bbox.set('axisX2', bbox.get('width'));
}
});
this.tempBBox = bbox; // Want to get the updated bbox while setState is pending
await this.setStateAsync({ bbox });
this.tempBBox = null;
}
getBBox() {
const bbox = this._currentBBox() || Map();
return {
width: 0,
height: 0,
axisY: 0,
axisX1: 0,
axisX2: 0,
...bbox.toJS()
};
}
async reflowChildren() {
// No child components
if (this.children === undefined) {
return true;
}
const reflowed = await Promise.all(this.children.map(c => c.doReflow()));
return reflowed.reduce((memo, value) => memo || value, false);
}
async doReflow() {
const oldBBox = this._currentBBox();
const shouldReflow = await this.reflowChildren();
if (shouldReflow) {
this.reflow();
}
return this._currentBBox() !== oldBBox;
}
reflow() {
// Implemented in subclasses
}
}
export default Base;

View File

@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import Base from './Base';
import style from './style';
/** @extends React.PureComponent */
class Box extends Base {
import reflowable from './reflowable';
@reflowable
class Box extends React.PureComponent {
static defaultProps = {
padding: 5,
radius: 3

View File

@ -2,12 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { List } from 'immutable';
import Base from './Base';
import style from './style';
import reflowable from './reflowable';
import Path from './path';
/** @extends React.PureComponent */
class HorizontalLayout extends Base {
@reflowable
class HorizontalLayout extends React.PureComponent {
static defaultProps = {
withConnectors: false,
spacing: 10

View File

@ -1,9 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import Base from './Base';
import style from './style';
import reflowable from './reflowable';
const namespaceProps = {
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:cc': 'http://creativecommons.org/ns#',
@ -19,8 +20,8 @@ const metadata = `<rdf:rdf>
</cc:license>
</rdf:rdf>`;
/** @extends React.PureComponent */
class Image extends Base {
@reflowable
class Image extends React.PureComponent {
static defaultProps = {
padding: 10
}

View File

@ -1,8 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import Base from './Base';
import style from './style';
import reflowable from './reflowable';
import Path from './path';
const skipPath = (box, greedy) => {
@ -54,8 +55,8 @@ const repeatPath = (box, greedy) => {
.quadraticCurveTo({ cx: 0, cy: -10, x: -10, y: -10 });
};
/** @extends React.PureComponent */
class Loop extends Base {
@reflowable
class Loop extends React.PureComponent {
get contentOffset() {
const { skip, repeat } = this.props;

View File

@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import Base from './Base';
import style from './style';
/** @extends React.PureComponent */
class Pin extends Base {
import reflowable from './reflowable';
@reflowable
class Pin extends React.PureComponent {
static defaultProps = {
radius: 5
}

View File

@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import Base from './Base';
import style from './style';
/** @extends React.PureComponent */
class Text extends Base {
import reflowable from './reflowable';
@reflowable
class Text extends React.PureComponent {
reflow() {
const box = this.text.getBBox();

View File

@ -2,14 +2,15 @@ import React from 'react';
import PropTypes from 'prop-types';
import { List } from 'immutable';
import Base from './Base';
import style from './style';
import reflowable from './reflowable';
import Path from './path';
const connectorMargin = 20;
/** @extends React.PureComponent */
class VerticalLayout extends Base {
@reflowable
class VerticalLayout extends React.PureComponent {
static defaultProps = {
withConnectors: false,
spacing: 10

View File

@ -0,0 +1,77 @@
import { Map } from 'immutable';
const reflowable = Component => {
Object.assign(Component.prototype, {
_currentBBox() {
return this.tempBBox ? this.tempBBox : (this.state || {}).bbox;
},
setStateAsync(state) {
return new Promise(resolve => {
this.setState(state, resolve);
});
},
async setBBox(box, recalculate = {}) {
const bbox = (this._currentBBox() || Map({ width: 0, height: 0})).withMutations(bbox => {
bbox.merge(box);
if (!bbox.has('axisY') || recalculate.axisY) {
bbox.set('axisY', bbox.get('height') / 2);
}
if (!bbox.has('axisX1') || recalculate.axisX1) {
bbox.set('axisX1', 0);
}
if (!bbox.has('axisX2') || recalculate.axisX2) {
bbox.set('axisX2', bbox.get('width'));
}
});
this.tempBBox = bbox; // Want to get the updated bbox while setState is pending
await this.setStateAsync({ bbox });
this.tempBBox = null;
},
getBBox() {
const bbox = this._currentBBox() || Map();
return {
width: 0,
height: 0,
axisY: 0,
axisX1: 0,
axisX2: 0,
...bbox.toJS()
};
},
async reflowChildren() {
// No child components
if (this.children === undefined) {
return true;
}
const reflowed = await Promise.all(this.children.map(c => c.doReflow()));
return reflowed.reduce((memo, value) => memo || value, false);
},
async doReflow() {
const oldBBox = this._currentBBox();
const shouldReflow = await this.reflowChildren();
if (shouldReflow) {
this.reflow();
}
return this._currentBBox() !== oldBBox;
},
...Component.prototype
});
return Component;
};
export default reflowable;

View File

@ -634,6 +634,10 @@ babel-plugin-syntax-class-properties@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
babel-plugin-syntax-decorators@^6.1.18:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b"
babel-plugin-syntax-dynamic-import@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
@ -675,6 +679,14 @@ babel-plugin-transform-class-properties@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-decorators-legacy@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz#741b58f6c5bce9e6027e0882d9c994f04f366925"
dependencies:
babel-plugin-syntax-decorators "^6.1.18"
babel-runtime "^6.2.0"
babel-template "^6.3.0"
babel-plugin-transform-es2015-arrow-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
@ -983,14 +995,14 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0:
babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
dependencies: