Skip to content

Commit 6c86b56

Browse files
ptitFicusfabienjuif
authored andcommitted
✨ fallback component (#85)
1 parent b3f2b3a commit 6c86b56

File tree

24 files changed

+6184
-139
lines changed

24 files changed

+6184
-139
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,23 @@ The default `print` parameter value is `true`. It means that in this example the
7474

7575
### Print as a function
7676
The `print` parameter can also be a function. Then the `props` and `context` are given to it (in this order), and it should return a boolean indicating wether or not the actual component should be displayed.
77+
78+
### Error handling
79+
The `error` parameter allows to specify a prop that indicates wether or not a placeholder error component should be displayed in replacement of the real component.
80+
It's usefull when data that are required for the correct display of a component are missing.
81+
82+
Like for the `print` prop, `error` can be a `boolean`, a `string` (referencing a prop name), an array of `string` (an array of prop names) or a `function` (whose result will be converted to `boolean`).
83+
84+
```js
85+
// default error component will be displayed if 'error' prop is truthy
86+
export default loader()(MyComponent)
87+
88+
// default error component will be displayed
89+
export default loader({ error: true })(MyComponent)
90+
91+
// default error component will be displayed if 'errorMessage' prop is truthy
92+
export default loader({ error: 'errorMessage' })(MyComponent)
93+
94+
// CustomErrorComponent will be displayed if 'error' prop is truthy
95+
export default loader({ ErrorIndicator: CustomErrorComponent })(MyComponent)
96+
```

build/ErrorCross/ErrorCross.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8+
9+
var _react = require('react');
10+
11+
var _react2 = _interopRequireDefault(_react);
12+
13+
var _propTypes = require('prop-types');
14+
15+
var _propTypes2 = _interopRequireDefault(_propTypes);
16+
17+
var _utils = require('../utils');
18+
19+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20+
21+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
22+
23+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
24+
25+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
26+
27+
var Cross = function (_Component) {
28+
_inherits(Cross, _Component);
29+
30+
function Cross(props) {
31+
_classCallCheck(this, Cross);
32+
33+
var _this = _possibleConstructorReturn(this, (Cross.__proto__ || Object.getPrototypeOf(Cross)).call(this, props));
34+
35+
_this.attach = function (div) {
36+
var newColor = (0, _utils.findCorrectColor)(div);
37+
if (_this.state.color !== newColor) {
38+
_this.setState({ color: newColor });
39+
}
40+
};
41+
42+
_this.state = {
43+
color: _utils.INITIAL_COLOR
44+
};
45+
return _this;
46+
}
47+
48+
_createClass(Cross, [{
49+
key: 'render',
50+
value: function render() {
51+
var color = this.state.color;
52+
var _props = this.props,
53+
style = _props.style,
54+
className = _props.className,
55+
message = _props.message;
56+
57+
58+
return _react2.default.createElement(
59+
'div',
60+
{
61+
title: message,
62+
ref: this.attach
63+
},
64+
_react2.default.createElement(
65+
'svg',
66+
{
67+
height: '38',
68+
width: '38',
69+
viewBox: '0 0 38 38',
70+
className: className,
71+
style: style,
72+
xmlns: 'http://www.w3.org/2000/svg'
73+
},
74+
_react2.default.createElement('path', {
75+
stroke: color,
76+
strokeWidth: '3',
77+
strokeLinecap: 'round',
78+
id: 'path3728',
79+
d: 'M 1.5341128,1.5341128 36.465887,36.465887 m 0,-34.9317742 L 1.5341128,36.465887'
80+
})
81+
)
82+
);
83+
}
84+
}]);
85+
86+
return Cross;
87+
}(_react.Component);
88+
89+
var string = _propTypes2.default.string,
90+
object = _propTypes2.default.object;
91+
92+
Cross.propTypes = {
93+
message: string,
94+
className: string,
95+
style: object
96+
};
97+
98+
Cross.defaultProps = {
99+
message: 'An error occured',
100+
className: '',
101+
style: {}
102+
};
103+
104+
exports.default = Cross;

build/ErrorCross/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = undefined;
7+
8+
var _ErrorCross = require('./ErrorCross');
9+
10+
var _ErrorCross2 = _interopRequireDefault(_ErrorCross);
11+
12+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13+
14+
exports.default = _ErrorCross2.default;

build/TailSpin/TailSpin.js

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ var _propTypes = require('prop-types');
1414

1515
var _propTypes2 = _interopRequireDefault(_propTypes);
1616

17-
var _tinycolor = require('tinycolor2');
18-
19-
var _tinycolor2 = _interopRequireDefault(_tinycolor);
17+
var _utils = require('../utils');
2018

2119
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2220

@@ -26,13 +24,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
2624

2725
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
2826

29-
/* global window */
30-
var getBackgroundColor = function getBackgroundColor(node) {
31-
return window.getComputedStyle(node, null).getPropertyValue('background-color');
32-
};
33-
3427
// from https://github.com/SamHerbert/SVG-Loaders
35-
3628
var TailSpin = function (_Component) {
3729
_inherits(TailSpin, _Component);
3830

@@ -41,41 +33,22 @@ var TailSpin = function (_Component) {
4133

4234
var _this = _possibleConstructorReturn(this, (TailSpin.__proto__ || Object.getPrototypeOf(TailSpin)).call(this, props));
4335

44-
_this.setColor = function () {
45-
var parent = _this.svg && _this.svg.parentNode;
46-
var parentColor = parent ? getBackgroundColor(parent) : undefined;
47-
48-
while (parent && !parentColor) {
49-
parent = parent.parentNode;
50-
if (parent) parentColor = getBackgroundColor(parent);
51-
}
52-
53-
if (parentColor) {
54-
var tinyC = (0, _tinycolor2.default)(parentColor);
55-
var color = tinyC.isDark() ? tinyC.lighten(20) : tinyC.darken(20);
56-
57-
_this.setState({
58-
color: color.toHexString()
59-
});
36+
_this.attach = function (svg) {
37+
var newColor = (0, _utils.findCorrectColor)(svg);
38+
if (_this.state.color !== newColor) {
39+
_this.setState({ color: newColor });
6040
}
6141
};
6242

6343
_this.state = {
64-
color: '#cecece'
44+
color: _utils.INITIAL_COLOR
6545
};
6646
return _this;
6747
}
6848

6949
_createClass(TailSpin, [{
70-
key: 'componentDidMount',
71-
value: function componentDidMount() {
72-
this.setColor();
73-
}
74-
}, {
7550
key: 'render',
7651
value: function render() {
77-
var _this2 = this;
78-
7952
var color = this.state.color;
8053
var _props = this.props,
8154
style = _props.style,
@@ -85,9 +58,7 @@ var TailSpin = function (_Component) {
8558
return _react2.default.createElement(
8659
'svg',
8760
{
88-
ref: function ref(c) {
89-
_this2.svg = c;
90-
},
61+
ref: this.attach,
9162
width: '38', height: '38',
9263
viewBox: '0 0 38 38',
9364
xmlns: 'http://www.w3.org/2000/svg',

build/core.js

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,49 +39,49 @@ var isString = function isString(stringToCheck) {
3939
return type && type === '[object String]';
4040
};
4141

42+
var hasStatus = function hasStatus(prop, propProcessor, defaultProp, defaultValue) {
43+
return function (props, state, context) {
44+
if (prop === undefined) {
45+
var status = props[defaultProp];
46+
return status === undefined ? defaultValue : !!status;
47+
}
48+
49+
if (Array.isArray(prop)) {
50+
var boolProps = prop.map(function (p) {
51+
return !!props[p];
52+
});
53+
return propProcessor(boolProps);
54+
}
55+
56+
if (isFunction(prop)) {
57+
return !!prop(props, context);
58+
}
59+
60+
return !!prop;
61+
};
62+
};
63+
4264
var getDisplayName = function getDisplayName(c) {
4365
return c.displayName || c.name || 'Component';
4466
};
4567

4668
exports.default = function () {
4769
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
4870
LoadingIndicator = _ref.LoadingIndicator,
71+
ErrorIndicator = _ref.ErrorIndicator,
4972
print = _ref.print,
50-
load = _ref.load;
73+
load = _ref.load,
74+
error = _ref.error;
5175

5276
var loadFunctionName = isString(load) ? load : 'load';
53-
var isPrintArray = Array.isArray(print);
54-
var isPrintFunction = isFunction(print);
5577
var isLoadFunction = isFunction(load);
5678

57-
var isLoaded = function isLoaded(props, state, context) {
58-
// Print is undefined,
59-
// we rely on 'props.loaded' if present
60-
// if not, we directly print the component
61-
if (print === undefined) {
62-
var loaded = props.loaded;
63-
64-
return loaded === undefined ? true : !!loaded;
65-
}
66-
67-
// Print is an array
68-
// Implicitly meaning that this is an array of props
69-
if (isPrintArray) {
70-
return print.map(function (p) {
71-
return Boolean(props[p]);
72-
}).reduce(function (allProps, currentProp) {
73-
return allProps && currentProp;
74-
});
75-
}
76-
77-
// Print is a function
78-
if (isPrintFunction) {
79-
return !!print(props, context);
80-
}
81-
82-
// Anything else
83-
return !!print;
84-
};
79+
var isLoaded = hasStatus(print, function (bs) {
80+
return !bs.includes(false);
81+
}, 'loaded', true);
82+
var isInError = hasStatus(error, function (bs) {
83+
return bs.includes(true);
84+
}, 'error', false);
8585

8686
return function (ComposedComponent) {
8787
var _class, _temp2;
@@ -137,10 +137,15 @@ exports.default = function () {
137137
}, {
138138
key: 'render',
139139
value: function render() {
140-
if (!isLoaded(this.props, this.state, this.context)) {
141-
return _react2.default.createElement(LoadingIndicator, this.state.props);
140+
if (isInError(this.props, this.state, this.context)) {
141+
return _react2.default.createElement(ErrorIndicator, this.state.props);
142142
}
143-
return _react2.default.createElement(ComposedComponent, this.state.props);
143+
144+
if (isLoaded(this.props, this.state, this.context)) {
145+
return _react2.default.createElement(ComposedComponent, this.state.props);
146+
}
147+
148+
return _react2.default.createElement(LoadingIndicator, this.state.props);
144149
}
145150
}]);
146151

build/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ var _TailSpin = require('./TailSpin');
1414

1515
var _TailSpin2 = _interopRequireDefault(_TailSpin);
1616

17+
var _ErrorCross = require('./ErrorCross');
18+
19+
var _ErrorCross2 = _interopRequireDefault(_ErrorCross);
20+
1721
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1822

1923
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
@@ -23,7 +27,9 @@ exports.default = function () {
2327

2428
var _ref$LoadingIndicator = _ref.LoadingIndicator,
2529
LoadingIndicator = _ref$LoadingIndicator === undefined ? _TailSpin2.default : _ref$LoadingIndicator,
26-
rest = _objectWithoutProperties(_ref, ['LoadingIndicator']);
30+
_ref$ErrorIndicator = _ref.ErrorIndicator,
31+
ErrorIndicator = _ref$ErrorIndicator === undefined ? _ErrorCross2.default : _ref$ErrorIndicator,
32+
rest = _objectWithoutProperties(_ref, ['LoadingIndicator', 'ErrorIndicator']);
2733

28-
return (0, _core2.default)(_extends({}, rest, { LoadingIndicator: LoadingIndicator }));
34+
return (0, _core2.default)(_extends({}, rest, { LoadingIndicator: LoadingIndicator, ErrorIndicator: ErrorIndicator }));
2935
};

build/utils/colorUtil.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.findCorrectColor = exports.INITIAL_COLOR = undefined;
7+
8+
var _tinycolor = require('tinycolor2');
9+
10+
var _tinycolor2 = _interopRequireDefault(_tinycolor);
11+
12+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13+
14+
/* global window */
15+
var getBackgroundColor = function getBackgroundColor(node) {
16+
return window.getComputedStyle(node, null).getPropertyValue('background-color');
17+
};
18+
19+
var INITIAL_COLOR = exports.INITIAL_COLOR = '#cecece';
20+
21+
var findCorrectColor = exports.findCorrectColor = function findCorrectColor(svg) {
22+
var parent = svg && svg.parentNode;
23+
var parentColor = parent ? getBackgroundColor(parent) : undefined;
24+
25+
while (parent && !parentColor) {
26+
parent = parent.parentNode;
27+
if (parent) parentColor = getBackgroundColor(parent);
28+
}
29+
30+
if (parentColor) {
31+
var tinyC = (0, _tinycolor2.default)(parentColor);
32+
var color = tinyC.isDark() ? tinyC.lighten(20) : tinyC.darken(20);
33+
34+
return color.toHexString();
35+
}
36+
37+
return INITIAL_COLOR;
38+
};

0 commit comments

Comments
 (0)