Skip to content
This repository has been archived by the owner on Nov 27, 2021. It is now read-only.

Commit

Permalink
material spinner for desktop
Browse files Browse the repository at this point in the history
  • Loading branch information
Yusuke Shibata committed Nov 26, 2017
1 parent 49dc7d3 commit 20b58b9
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 43 deletions.
2 changes: 2 additions & 0 deletions demo/src/App.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 82 additions & 26 deletions src/component/index.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,102 @@
import React from 'react'
import { StyleSheet, css } from 'aphrodite'

const rotateKey = {
'0%': {
transform: 'rotate(0deg)'
},
'100%': {
transform: 'rotate(270deg)'
}
}
const dashKey = {
'0%': {
strokeDashoffset: 62
},
'50%': {
strokeDashoffset: 62 / 4,
transform: 'rotate(135deg)'
},
'100%': {
strokeDashoffset: 62,
transform: 'rotate(450deg)'
}
}

const styles = StyleSheet.create({
comp: {
width: '100%',
backgroundColor: 'gray',
overflow: 'hidden',
color: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
refreshing: {
backgroundColor: 'blue'
position: 'absolute',
left: '50%',
borderRadius: 20,
width: 40,
height: 40,
boxShadow: '0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)'
},
refreshed: {
backgroundColor: 'green'
rotate: {
transformOrigin: 'center',
animationName: rotateKey,
animationDuration: '1400ms',
animationTimingFunction: 'linear',
animationIterationCount: 'infinite'
},
willRefresh: {
backgroundColor: 'red'
dash: {
strokeDasharray: 62,
transformOrigin: 'center',
animationName: dashKey,
animationDuration: '1400ms',
animationTimingFunction: 'ease-in-out',
animationIterationCount: 'infinite'
}
})

export default (props, state, children) => {
const p = Math.atan(state.y / props.max)
const { yMax, y, refreshing, refreshed } = state
const p = Math.atan(y / props.max)
const pMax = Math.atan(yMax / props.max)
const r = Math.PI * 10 * 2
return [
<div
key='pull'
className={css(
styles.comp,
state.refreshing && styles.refreshing,
state.refreshed && styles.refreshed,
state.willRefresh && styles.willRefresh
)}
className={css(styles.comp)}
style={{
height: Math.max(p * props.max, 0)
top: Math.max(refreshed ? Math.atan(1) : p, 0) * props.max - 10,
transform: `translate(-50%, -100%) scale(${refreshed ? p : 1},${refreshed ? p : 1})`,
backgroundColor: props.bgColor
}}
>
{ state.refreshing && 'refreshing :' }
{ state.refreshed && 'refreshed :' }
{ state.willRefresh && 'willRefresh :' }
{ parseInt(state.y, 10) }
<svg
style={{
transform:`rotate(${yMax}deg)`
}}
className={css(refreshing && styles.rotate)}
width={40}
height={40}
viewBox='0 0 40 40'
>
<circle
className={css(refreshing && styles.dash)}
style={{ opacity:pMax }}
stroke={props.color}
strokeWidth={2.5}
strokeDasharray={[r * pMax * 0.6, r * (1 - pMax * 0.6)]}
strokeDashoffset={-r * (1 - pMax * 0.6)}
fill='none'
cx={20}
cy={20}
r={10}
/>
{ !refreshing &&
<polygon
style={{
opacity: pMax,
transformOrigin: '50% 0%',
transform: `scale(${Math.min(pMax,1)}, ${Math.min(pMax,1)})`
}}
fill={props.color}
points='30,24 26,20 34,20'
/>
}
</svg>
</div>,
children
]
Expand Down
49 changes: 49 additions & 0 deletions src/component/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import { StyleSheet, css } from 'aphrodite'

const styles = StyleSheet.create({
comp: {
width: '100%',
backgroundColor: 'gray',
overflow: 'hidden',
color: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
refreshing: {
backgroundColor: 'blue'
},
refreshed: {
backgroundColor: 'green'
},
willRefresh: {
backgroundColor: 'red'
}
})

export default (props, state, children) => {
const p = Math.atan(state.y / props.max)
return [
<div
key='pull'
className={css(
styles.comp,
state.refreshing && styles.refreshing,
state.refreshed && styles.refreshed,
state.willRefresh && styles.willRefresh
)}
style={{
height: Math.max(p * props.max, 0)
}}
>
{ state.refreshing && 'refreshing :' }
{ state.refreshed && 'refreshed :' }
{ state.willRefresh && 'willRefresh :' }
{ parseInt(state.y, 10) }
</div>,
children
]
}


42 changes: 25 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class PullRefresh extends Component {
super(props)
this.state = {
y: 0,
willRefresh: false,
yMax: 0,
refreshing: false,
refreshed: false
}
Expand All @@ -24,17 +24,25 @@ export default class PullRefresh extends Component {
this._py = ey
}
async onUp(evt) {
const { refreshed, refreshing, willRefresh } = this.state
const { y, refreshed, refreshing } = this.state
const { max, onRefresh } = this.props
if(refreshed || refreshing) return
this._down = false
if(willRefresh) {
if(y >= max) {
this._willRefresh = true
this._spring.endValue = max
await sleep(400)
this._spring.pause()
this.setState({ willRefresh: false, refreshing: true })
this._willRefresh = false
this.setState({
refreshing: true
})
await onRefresh()
this.setState({ refreshed: true, refreshing: false })
this.setState({
yMax: 0,
refreshed: true,
refreshing: false
})
this._spring.resume()
}
if(this._y !== 0) {
Expand All @@ -53,23 +61,21 @@ export default class PullRefresh extends Component {
this._py = ey
}
onSpringUpdate(spring) {
const { willRefresh, refreshing, refreshed } = this.state
const { max } = this.props
const { yMax, refreshed } = this.state
const y = spring.currentValue
this.setState({ y })
this.setState({
y,
yMax: this._willRefresh ? Math.max(y, yMax) : y
})
if(refreshed && y === 0) this.setState({ refreshed: false })
if(!refreshed && !refreshing) {
const refresh = y >= max
if(refresh !== willRefresh) this.setState({ willRefresh: refresh })
}
}
componentDidMount() {
this._y = 0
this._spring = new Spring(60, 10)
this._spring.onUpdate = ::this.onSpringUpdate
}
render() {
const { onRefresh, disabled, as, children, ...props } = this.props
const { bgColor, color, onRefresh, disabled, as, children, ...props } = this.props
const Container = as
return (
<Container
Expand All @@ -92,9 +98,10 @@ PullRefresh.propTypes = {
onRefresh: PropTypes.func,
max: PropTypes.number,
style: PropTypes.object,
disabled: PropTypes.bool
disabled: PropTypes.bool,
color: PropTypes.string,
bgColor: PropTypes.string,
// offset: PropTypes.number,
// color: PropTypes.string,
// size: PropTypes.number,
// waitingComponent: PropTypes.oneOfType([ PropTypes.func, PropTypes.bool ]),
// pullingComponent: PropTypes.oneOfType([ PropTypes.func, PropTypes.bool ]),
Expand All @@ -106,8 +113,9 @@ PullRefresh.defaultProps = {
as: 'div',
max: 100,
style: {},
disabled: false
// color: '#000000',
disabled: false,
color: '#787878',
bgColor: '#fff',
// offset: 0,
// size: 40,
// waitingComponent: undefined,
Expand Down

0 comments on commit 20b58b9

Please sign in to comment.