Moving to using a decorator mixin instead of base class for SVGs
This commit is contained in:
parent
44e6dae289
commit
6e8d7c297a
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
77
src/components/SVG/reflowable.js
Normal file
77
src/components/SVG/reflowable.js
Normal 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;
|
16
yarn.lock
16
yarn.lock
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user