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-runtime",
|
||||||
"transform-class-properties",
|
"transform-class-properties",
|
||||||
"transform-object-rest-spread",
|
"transform-object-rest-spread",
|
||||||
|
"transform-decorators-legacy",
|
||||||
"syntax-dynamic-import"
|
"syntax-dynamic-import"
|
||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
@ -59,6 +60,7 @@
|
|||||||
"transform-runtime",
|
"transform-runtime",
|
||||||
"transform-class-properties",
|
"transform-class-properties",
|
||||||
"transform-object-rest-spread",
|
"transform-object-rest-spread",
|
||||||
|
"transform-decorators-legacy",
|
||||||
"syntax-dynamic-import"
|
"syntax-dynamic-import"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -145,6 +147,7 @@
|
|||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
"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-object-rest-spread": "^6.26.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
|
||||||
import React from 'react';
|
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() {
|
reflow() {
|
||||||
return this.setBBox(this.props.bbox);
|
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 React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
import reflowable from './reflowable';
|
||||||
class Box extends Base {
|
|
||||||
|
@reflowable
|
||||||
|
class Box extends React.PureComponent {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
padding: 5,
|
padding: 5,
|
||||||
radius: 3
|
radius: 3
|
||||||
|
@ -2,12 +2,13 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { List } from 'immutable';
|
import { List } from 'immutable';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
|
import reflowable from './reflowable';
|
||||||
import Path from './path';
|
import Path from './path';
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
@reflowable
|
||||||
class HorizontalLayout extends Base {
|
class HorizontalLayout extends React.PureComponent {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
withConnectors: false,
|
withConnectors: false,
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
|
import reflowable from './reflowable';
|
||||||
|
|
||||||
const namespaceProps = {
|
const namespaceProps = {
|
||||||
'xmlns': 'http://www.w3.org/2000/svg',
|
'xmlns': 'http://www.w3.org/2000/svg',
|
||||||
'xmlns:cc': 'http://creativecommons.org/ns#',
|
'xmlns:cc': 'http://creativecommons.org/ns#',
|
||||||
@ -19,8 +20,8 @@ const metadata = `<rdf:rdf>
|
|||||||
</cc:license>
|
</cc:license>
|
||||||
</rdf:rdf>`;
|
</rdf:rdf>`;
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
@reflowable
|
||||||
class Image extends Base {
|
class Image extends React.PureComponent {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
padding: 10
|
padding: 10
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
|
import reflowable from './reflowable';
|
||||||
import Path from './path';
|
import Path from './path';
|
||||||
|
|
||||||
const skipPath = (box, greedy) => {
|
const skipPath = (box, greedy) => {
|
||||||
@ -54,8 +55,8 @@ const repeatPath = (box, greedy) => {
|
|||||||
.quadraticCurveTo({ cx: 0, cy: -10, x: -10, y: -10 });
|
.quadraticCurveTo({ cx: 0, cy: -10, x: -10, y: -10 });
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
@reflowable
|
||||||
class Loop extends Base {
|
class Loop extends React.PureComponent {
|
||||||
get contentOffset() {
|
get contentOffset() {
|
||||||
const { skip, repeat } = this.props;
|
const { skip, repeat } = this.props;
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
import reflowable from './reflowable';
|
||||||
class Pin extends Base {
|
|
||||||
|
@reflowable
|
||||||
|
class Pin extends React.PureComponent {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
radius: 5
|
radius: 5
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
import reflowable from './reflowable';
|
||||||
class Text extends Base {
|
|
||||||
|
@reflowable
|
||||||
|
class Text extends React.PureComponent {
|
||||||
reflow() {
|
reflow() {
|
||||||
const box = this.text.getBBox();
|
const box = this.text.getBBox();
|
||||||
|
|
||||||
|
@ -2,14 +2,15 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { List } from 'immutable';
|
import { List } from 'immutable';
|
||||||
|
|
||||||
import Base from './Base';
|
|
||||||
import style from './style';
|
import style from './style';
|
||||||
|
|
||||||
|
import reflowable from './reflowable';
|
||||||
import Path from './path';
|
import Path from './path';
|
||||||
|
|
||||||
const connectorMargin = 20;
|
const connectorMargin = 20;
|
||||||
|
|
||||||
/** @extends React.PureComponent */
|
@reflowable
|
||||||
class VerticalLayout extends Base {
|
class VerticalLayout extends React.PureComponent {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
withConnectors: false,
|
withConnectors: false,
|
||||||
spacing: 10
|
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"
|
version "6.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
|
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:
|
babel-plugin-syntax-dynamic-import@^6.18.0:
|
||||||
version "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"
|
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-runtime "^6.22.0"
|
||||||
babel-template "^6.24.1"
|
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:
|
babel-plugin-transform-es2015-arrow-functions@^6.22.0:
|
||||||
version "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"
|
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"
|
mkdirp "^0.5.1"
|
||||||
source-map-support "^0.4.15"
|
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"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||||
dependencies:
|
dependencies:
|
||||||
core-js "^2.4.0"
|
core-js "^2.4.0"
|
||||||
regenerator-runtime "^0.11.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"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
|
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Loading…
Reference in New Issue
Block a user