@cloudflare/component-loading
Advanced tools
Comparing version 1.0.3 to 1.0.4
@@ -6,2 +6,16 @@ # Change Log | ||
<a name="1.0.4"></a> | ||
## [1.0.4](http://stash.cfops.it:7999/www/cf-ux/compare/@cloudflare/component-loading@1.0.3...@cloudflare/component-loading@1.0.4) (2018-05-23) | ||
### Bug Fixes | ||
* **component-loading:** UI-708 - Check that canvas is available ([6e5ca60](http://stash.cfops.it:7999/www/cf-ux/commits/6e5ca60)) | ||
* **component-loading:** UI-708 - Fix tests ([78fb682](http://stash.cfops.it:7999/www/cf-ux/commits/78fb682)) | ||
* **component-loading:** UI-708 - Rewrite loading component using Canvas ([758e73c](http://stash.cfops.it:7999/www/cf-ux/commits/758e73c)) | ||
* **component-loading:** UI-708 - Stop frame engine on unmount ([22983c1](http://stash.cfops.it:7999/www/cf-ux/commits/22983c1)) | ||
<a name="1.0.3"></a> | ||
@@ -8,0 +22,0 @@ ## [1.0.3](http://stash.cfops.it:7999/www/cf-ux/compare/@cloudflare/component-loading@1.0.2...@cloudflare/component-loading@1.0.3) (2018-05-14) |
@@ -1,8 +0,1 @@ | ||
import LoadingUnstyled from './Loading'; | ||
import LoadingTheme from './LoadingTheme'; | ||
import { applyTheme } from '@cloudflare/style-container'; | ||
var Loading = applyTheme(LoadingUnstyled, LoadingTheme); | ||
export { Loading, LoadingUnstyled, LoadingTheme }; | ||
export { default as Loading } from './Loading'; |
@@ -11,64 +11,12 @@ 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; }; }(); | ||
import PropTypes from 'prop-types'; | ||
import { createComponent } from '@cloudflare/style-container'; | ||
var getHeight = function getHeight(size) { | ||
var height = void 0; | ||
switch (size) { | ||
case '1.5x': | ||
height = 22; | ||
break; | ||
case '2x': | ||
height = 30; | ||
break; | ||
case '2.5x': | ||
height = 37; | ||
break; | ||
case '3x': | ||
height = 45; | ||
break; | ||
case '3.5x': | ||
height = 52; | ||
break; | ||
case '4x': | ||
height = 60; | ||
break; | ||
default: | ||
height = 15; | ||
} | ||
return height; | ||
}; | ||
import { withTheme, createComponent } from '@cloudflare/style-container'; | ||
var loadingStyles = function loadingStyles(_ref) { | ||
var theme = _ref.theme, | ||
size = _ref.size; | ||
var SquareCanvas = createComponent(function (_ref) { | ||
var side = _ref.side; | ||
return { | ||
height: getHeight(size), | ||
animationDuration: '2.5s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear', | ||
'>svg': { | ||
height: '100%', | ||
fill: 'transparent', | ||
strokeWidth: 6, | ||
stroke: theme.colors.gray[5], | ||
animationName: { | ||
'0%': { | ||
strokeDasharray: '1,95', | ||
strokeDashoffset: 0, | ||
transform: 'rotate(0deg)' | ||
}, | ||
'50%': { strokeDasharray: '85,95', strokeDashoffset: -25 }, | ||
'100%': { | ||
strokeDasharray: '85,95', | ||
strokeDashoffset: -93, | ||
transform: 'rotate(360deg)' | ||
} | ||
}, | ||
animationDuration: '1.9s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear' | ||
} | ||
width: side + 'px', | ||
height: side + 'px' | ||
}; | ||
}; | ||
}, 'canvas', ['width', 'height']); | ||
@@ -79,22 +27,112 @@ var Loading = function (_React$Component) { | ||
function Loading() { | ||
var _ref2; | ||
var _temp, _this, _ret; | ||
_classCallCheck(this, Loading); | ||
return _possibleConstructorReturn(this, (Loading.__proto__ || Object.getPrototypeOf(Loading)).apply(this, arguments)); | ||
} | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref2 = Loading.__proto__ || Object.getPrototypeOf(Loading)).call.apply(_ref2, [this].concat(args))), _this), _this.state = {}, _temp), _possibleConstructorReturn(_this, _ret); | ||
} // px | ||
// relative to diameter | ||
// radians/frame (regulates animation speed) | ||
// ratio of full circle | ||
// ratio of full circle | ||
_createClass(Loading, [{ | ||
key: 'componentDidMount', | ||
value: function componentDidMount() { | ||
var theme = this.props.theme; | ||
var size = this.state.height; | ||
var ctx = this.ctx; | ||
if (!ctx) { | ||
return; // canvas not available (f.e. in tests) | ||
} | ||
// Keep it crisp on retina devices | ||
var scaleFactor = window.devicePixelRatio || 1; | ||
ctx.scale(scaleFactor, scaleFactor); | ||
var radius = size / 2; | ||
var arcThickness = Math.floor(size * Loading.ARC_THICKNESS); | ||
var angleStep = Loading.ANGLE_STEP; | ||
var arcLengthRange = [Loading.MIN_ARC_LENGTH, Loading.MAX_ARC_LENGTH].map(function (p) { | ||
return p * 2 * Math.PI; | ||
}); | ||
var arcProps = [0, // center X | ||
0, // center Y | ||
radius - arcThickness / 2 // radius | ||
]; | ||
ctx.translate(radius, radius); // center at (0,0) | ||
ctx.strokeStyle = theme.colors.gray[5]; | ||
ctx.lineWidth = arcThickness; | ||
var arcLength = 0; | ||
var fwd = true; | ||
var self = this; | ||
(function onFrame() { | ||
ctx.clearRect(-radius, -radius, size, size); | ||
ctx.rotate(angleStep); | ||
var halfArcLength = Math.max(0, arcLength / 2); | ||
ctx.beginPath(); | ||
ctx.arc.apply(ctx, arcProps.concat([-halfArcLength, halfArcLength])); | ||
ctx.stroke(); | ||
if (arcLength <= arcLengthRange[0]) { | ||
fwd = true; | ||
} | ||
if (arcLength >= arcLengthRange[1]) { | ||
fwd = false; | ||
} | ||
arcLength += (fwd ? 1 : -1) * angleStep; | ||
self.rafId = requestAnimationFrame(onFrame); | ||
})(); | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
value: function componentWillUnmount() { | ||
if (this.rafId) { | ||
// stop frame ticker | ||
cancelAnimationFrame(this.rafId); | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var className = this.props.className; | ||
var _this2 = this; | ||
var height = this.state.height; | ||
var scaledHeight = height * (window.devicePixelRatio || 1); | ||
return React.createElement( | ||
'div', | ||
{ className: className }, | ||
React.createElement( | ||
'svg', | ||
{ xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 40 40' }, | ||
React.createElement('circle', { cx: '50%', cy: '50%', r: '40%' }) | ||
) | ||
null, | ||
React.createElement(SquareCanvas, { | ||
innerRef: function innerRef(el) { | ||
return el && (_this2.ctx = el.getContext('2d')); | ||
}, | ||
side: height, | ||
width: scaledHeight, | ||
height: scaledHeight | ||
}) | ||
); | ||
} | ||
}], [{ | ||
key: 'getDerivedStateFromProps', | ||
value: function getDerivedStateFromProps(nextProps) { | ||
return { | ||
height: Math.round(Loading.DEFAULT_HEIGHT * +nextProps.size.replace('x', '')) | ||
}; | ||
} | ||
}]); | ||
@@ -105,7 +143,16 @@ | ||
Loading.DEFAULT_HEIGHT = 15; | ||
Loading.ARC_THICKNESS = 0.151; | ||
Loading.ANGLE_STEP = Math.PI / 30; | ||
Loading.MIN_ARC_LENGTH = 0.01; | ||
Loading.MAX_ARC_LENGTH = 0.8; | ||
Loading.propTypes = { | ||
className: PropTypes.string, | ||
size: PropTypes.oneOf(['1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
theme: PropTypes.object.isRequired, | ||
size: PropTypes.oneOf(['1x', '1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
}; | ||
Loading.displayName = 'Loading'; | ||
export default createComponent(loadingStyles, Loading); | ||
Loading.defaultProps = { | ||
size: '1x' | ||
}; | ||
export default withTheme(Loading); |
@@ -6,20 +6,12 @@ 'use strict'; | ||
}); | ||
exports.LoadingTheme = exports.LoadingUnstyled = exports.Loading = undefined; | ||
var _Loading = require('./Loading'); | ||
var _Loading2 = _interopRequireDefault(_Loading); | ||
Object.defineProperty(exports, 'Loading', { | ||
enumerable: true, | ||
get: function () { | ||
return _interopRequireDefault(_Loading).default; | ||
} | ||
}); | ||
var _LoadingTheme = require('./LoadingTheme'); | ||
var _LoadingTheme2 = _interopRequireDefault(_LoadingTheme); | ||
var _styleContainer = require('@cloudflare/style-container'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const Loading = (0, _styleContainer.applyTheme)(_Loading2.default, _LoadingTheme2.default); | ||
exports.Loading = Loading; | ||
exports.LoadingUnstyled = _Loading2.default; | ||
exports.LoadingTheme = _LoadingTheme2.default; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
@@ -19,71 +19,96 @@ 'use strict'; | ||
const getHeight = size => { | ||
let height; | ||
switch (size) { | ||
case '1.5x': | ||
height = 22; | ||
break; | ||
case '2x': | ||
height = 30; | ||
break; | ||
case '2.5x': | ||
height = 37; | ||
break; | ||
case '3x': | ||
height = 45; | ||
break; | ||
case '3.5x': | ||
height = 52; | ||
break; | ||
case '4x': | ||
height = 60; | ||
break; | ||
default: | ||
height = 15; | ||
const SquareCanvas = (0, _styleContainer.createComponent)(({ side }) => ({ | ||
width: `${side}px`, | ||
height: `${side}px` | ||
}), 'canvas', ['width', 'height']); | ||
class Loading extends _react2.default.Component { | ||
constructor(...args) { | ||
var _temp; | ||
return _temp = super(...args), this.state = {}, _temp; | ||
} // px | ||
// relative to diameter | ||
// radians/frame (regulates animation speed) | ||
// ratio of full circle | ||
// ratio of full circle | ||
static getDerivedStateFromProps(nextProps) { | ||
return { | ||
height: Math.round(Loading.DEFAULT_HEIGHT * +nextProps.size.replace('x', '')) | ||
}; | ||
} | ||
return height; | ||
}; | ||
const loadingStyles = ({ theme, size }) => { | ||
return { | ||
height: getHeight(size), | ||
animationDuration: '2.5s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear', | ||
'>svg': { | ||
height: '100%', | ||
fill: 'transparent', | ||
strokeWidth: 6, | ||
stroke: theme.colors.gray[5], | ||
animationName: { | ||
'0%': { | ||
strokeDasharray: '1,95', | ||
strokeDashoffset: 0, | ||
transform: 'rotate(0deg)' | ||
}, | ||
'50%': { strokeDasharray: '85,95', strokeDashoffset: -25 }, | ||
'100%': { | ||
strokeDasharray: '85,95', | ||
strokeDashoffset: -93, | ||
transform: 'rotate(360deg)' | ||
} | ||
}, | ||
animationDuration: '1.9s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear' | ||
componentDidMount() { | ||
const { theme } = this.props; | ||
const { height: size } = this.state; | ||
const { ctx } = this; | ||
if (!ctx) { | ||
return; // canvas not available (f.e. in tests) | ||
} | ||
}; | ||
}; | ||
class Loading extends _react2.default.Component { | ||
// Keep it crisp on retina devices | ||
const scaleFactor = window.devicePixelRatio || 1; | ||
ctx.scale(scaleFactor, scaleFactor); | ||
const radius = size / 2; | ||
const arcThickness = Math.floor(size * Loading.ARC_THICKNESS); | ||
const angleStep = Loading.ANGLE_STEP; | ||
const arcLengthRange = [Loading.MIN_ARC_LENGTH, Loading.MAX_ARC_LENGTH].map(p => p * 2 * Math.PI); | ||
const arcProps = [0, // center X | ||
0, // center Y | ||
radius - arcThickness / 2 // radius | ||
]; | ||
ctx.translate(radius, radius); // center at (0,0) | ||
ctx.strokeStyle = theme.colors.gray[5]; | ||
ctx.lineWidth = arcThickness; | ||
let arcLength = 0; | ||
let fwd = true; | ||
const self = this; | ||
(function onFrame() { | ||
ctx.clearRect(-radius, -radius, size, size); | ||
ctx.rotate(angleStep); | ||
const halfArcLength = Math.max(0, arcLength / 2); | ||
ctx.beginPath(); | ||
ctx.arc(...arcProps, -halfArcLength, halfArcLength); | ||
ctx.stroke(); | ||
if (arcLength <= arcLengthRange[0]) { | ||
fwd = true; | ||
} | ||
if (arcLength >= arcLengthRange[1]) { | ||
fwd = false; | ||
} | ||
arcLength += (fwd ? 1 : -1) * angleStep; | ||
self.rafId = requestAnimationFrame(onFrame); | ||
})(); | ||
} | ||
componentWillUnmount() { | ||
if (this.rafId) { | ||
// stop frame ticker | ||
cancelAnimationFrame(this.rafId); | ||
} | ||
} | ||
render() { | ||
const { className } = this.props; | ||
const { height } = this.state; | ||
const scaledHeight = height * (window.devicePixelRatio || 1); | ||
return _react2.default.createElement( | ||
'div', | ||
{ className: className }, | ||
_react2.default.createElement( | ||
'svg', | ||
{ xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 40 40' }, | ||
_react2.default.createElement('circle', { cx: '50%', cy: '50%', r: '40%' }) | ||
) | ||
null, | ||
_react2.default.createElement(SquareCanvas, { | ||
innerRef: el => el && (this.ctx = el.getContext('2d')), | ||
side: height, | ||
width: scaledHeight, | ||
height: scaledHeight | ||
}) | ||
); | ||
@@ -93,7 +118,14 @@ } | ||
Loading.DEFAULT_HEIGHT = 15; | ||
Loading.ARC_THICKNESS = 0.151; | ||
Loading.ANGLE_STEP = Math.PI / 30; | ||
Loading.MIN_ARC_LENGTH = 0.01; | ||
Loading.MAX_ARC_LENGTH = 0.8; | ||
Loading.propTypes = { | ||
className: _propTypes2.default.string, | ||
size: _propTypes2.default.oneOf(['1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
theme: _propTypes2.default.object.isRequired, | ||
size: _propTypes2.default.oneOf(['1x', '1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
}; | ||
Loading.displayName = 'Loading'; | ||
exports.default = (0, _styleContainer.createComponent)(loadingStyles, Loading); | ||
Loading.defaultProps = { | ||
size: '1x' | ||
}; | ||
exports.default = (0, _styleContainer.withTheme)(Loading); |
{ | ||
"name": "@cloudflare/component-loading", | ||
"description": "Cloudflare Loading Component", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"main": "lib/index.js", | ||
@@ -15,3 +15,2 @@ "module": "es/index.js", | ||
"dependencies": { | ||
"@cloudflare/component-icon": "^1.0.3", | ||
"@cloudflare/style-container": "^1.0.3", | ||
@@ -23,2 +22,5 @@ "prop-types": "^15.6.0" | ||
}, | ||
"devDependencies": { | ||
"canvas-prebuilt": "^1.6.0" | ||
}, | ||
"stratus": { | ||
@@ -25,0 +27,0 @@ "srcDirectory": "./src", |
@@ -1,8 +0,1 @@ | ||
import LoadingUnstyled from './Loading'; | ||
import LoadingTheme from './LoadingTheme'; | ||
import { applyTheme } from '@cloudflare/style-container'; | ||
const Loading = applyTheme(LoadingUnstyled, LoadingTheme); | ||
export { Loading, LoadingUnstyled, LoadingTheme }; | ||
export { default as Loading } from './Loading'; |
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { createComponent } from '@cloudflare/style-container'; | ||
const getHeight = size => { | ||
let height; | ||
switch (size) { | ||
case '1.5x': | ||
height = 22; | ||
break; | ||
case '2x': | ||
height = 30; | ||
break; | ||
case '2.5x': | ||
height = 37; | ||
break; | ||
case '3x': | ||
height = 45; | ||
break; | ||
case '3.5x': | ||
height = 52; | ||
break; | ||
case '4x': | ||
height = 60; | ||
break; | ||
default: | ||
height = 15; | ||
import { withTheme, createComponent } from '@cloudflare/style-container'; | ||
const SquareCanvas = createComponent( | ||
({ side }) => ({ | ||
width: `${side}px`, | ||
height: `${side}px` | ||
}), | ||
'canvas', | ||
['width', 'height'] | ||
); | ||
class Loading extends React.Component { | ||
static DEFAULT_HEIGHT = 15; // px | ||
static ARC_THICKNESS = 0.151; // relative to diameter | ||
static ANGLE_STEP = Math.PI / 30; // radians/frame (regulates animation speed) | ||
static MIN_ARC_LENGTH = 0.01; // ratio of full circle | ||
static MAX_ARC_LENGTH = 0.8; // ratio of full circle | ||
static propTypes = { | ||
theme: PropTypes.object.isRequired, | ||
size: PropTypes.oneOf(['1x', '1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
}; | ||
static defaultProps = { | ||
size: '1x' | ||
}; | ||
state = {}; | ||
static getDerivedStateFromProps(nextProps) { | ||
return { | ||
height: Math.round( | ||
Loading.DEFAULT_HEIGHT * +nextProps.size.replace('x', '') | ||
) | ||
}; | ||
} | ||
return height; | ||
}; | ||
const loadingStyles = ({ theme, size }) => { | ||
return { | ||
height: getHeight(size), | ||
animationDuration: '2.5s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear', | ||
'>svg': { | ||
height: '100%', | ||
fill: 'transparent', | ||
strokeWidth: 6, | ||
stroke: theme.colors.gray[5], | ||
animationName: { | ||
'0%': { | ||
strokeDasharray: '1,95', | ||
strokeDashoffset: 0, | ||
transform: 'rotate(0deg)' | ||
}, | ||
'50%': { strokeDasharray: '85,95', strokeDashoffset: -25 }, | ||
'100%': { | ||
strokeDasharray: '85,95', | ||
strokeDashoffset: -93, | ||
transform: 'rotate(360deg)' | ||
} | ||
}, | ||
animationDuration: '1.9s', | ||
animationIterationCount: 'infinite', | ||
animationTimingFunction: 'linear' | ||
componentDidMount() { | ||
const { theme } = this.props; | ||
const { height: size } = this.state; | ||
const { ctx } = this; | ||
if (!ctx) { | ||
return; // canvas not available (f.e. in tests) | ||
} | ||
}; | ||
}; | ||
class Loading extends React.Component { | ||
// Keep it crisp on retina devices | ||
const scaleFactor = window.devicePixelRatio || 1; | ||
ctx.scale(scaleFactor, scaleFactor); | ||
const radius = size / 2; | ||
const arcThickness = Math.floor(size * Loading.ARC_THICKNESS); | ||
const angleStep = Loading.ANGLE_STEP; | ||
const arcLengthRange = [Loading.MIN_ARC_LENGTH, Loading.MAX_ARC_LENGTH].map( | ||
p => p * 2 * Math.PI | ||
); | ||
const arcProps = [ | ||
0, // center X | ||
0, // center Y | ||
radius - arcThickness / 2 // radius | ||
]; | ||
ctx.translate(radius, radius); // center at (0,0) | ||
ctx.strokeStyle = theme.colors.gray[5]; | ||
ctx.lineWidth = arcThickness; | ||
let arcLength = 0; | ||
let fwd = true; | ||
const self = this; | ||
(function onFrame() { | ||
ctx.clearRect(-radius, -radius, size, size); | ||
ctx.rotate(angleStep); | ||
const halfArcLength = Math.max(0, arcLength / 2); | ||
ctx.beginPath(); | ||
ctx.arc(...arcProps, -halfArcLength, halfArcLength); | ||
ctx.stroke(); | ||
if (arcLength <= arcLengthRange[0]) { | ||
fwd = true; | ||
} | ||
if (arcLength >= arcLengthRange[1]) { | ||
fwd = false; | ||
} | ||
arcLength += (fwd ? 1 : -1) * angleStep; | ||
self.rafId = requestAnimationFrame(onFrame); | ||
})(); | ||
} | ||
componentWillUnmount() { | ||
if (this.rafId) { | ||
// stop frame ticker | ||
cancelAnimationFrame(this.rafId); | ||
} | ||
} | ||
render() { | ||
const { className } = this.props; | ||
const { height } = this.state; | ||
const scaledHeight = height * (window.devicePixelRatio || 1); | ||
return ( | ||
<div className={className}> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"> | ||
<circle cx="50%" cy="50%" r="40%" /> | ||
</svg> | ||
<div> | ||
<SquareCanvas | ||
innerRef={el => el && (this.ctx = el.getContext('2d'))} | ||
side={height} | ||
width={scaledHeight} | ||
height={scaledHeight} | ||
/> | ||
</div> | ||
@@ -76,7 +120,2 @@ ); | ||
Loading.propTypes = { | ||
className: PropTypes.string, | ||
size: PropTypes.oneOf(['1.5x', '2x', '2.5x', '3x', '3.5x', '4x']) | ||
}; | ||
Loading.displayName = 'Loading'; | ||
export default createComponent(loadingStyles, Loading); | ||
export default withTheme(Loading); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
25849
3
337
1
9
1
- Removed@cloudflare/component-icon@^1.0.3
- Removed@cloudflare/component-icon@1.2.9(transitive)
- Removed@cloudflare/intl-types@1.5.6(transitive)
- Removed@cloudflare/style-const@2.5.3(transitive)
- Removed@cloudflare/style-container@3.0.3(transitive)
- Removed@cloudflare/types@6.29.1(transitive)
- Removed@cloudflare/util-en-garde@8.0.10(transitive)
- Removedfp-ts@2.16.9(transitive)
- Removedio-ts@2.2.22(transitive)