Last active
October 29, 2017 20:00
-
-
Save wsmd/d022ebdd5d167745ab8bde3f696a4ee0 to your computer and use it in GitHub Desktop.
Revisions
-
wsmd revised this gist
Oct 29, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ import React, { Component } from 'react'; import classNames from 'classnames'; import './CounterButton.css'; @@ -13,7 +13,7 @@ const getComputedProperty = (node, property) => { return value; } class CounterButton extends Component { deferredUpdates = []; state = { -
wsmd renamed this gist
Oct 29, 2017 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
wsmd revised this gist
Oct 29, 2017 . 1 changed file with 7 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -20,7 +20,7 @@ class CounterButton extends React.Component { count: this.props.count, next: this.props.count + 1, prev: this.props.count - 1, animation: null, width: null, } @@ -40,7 +40,7 @@ class CounterButton extends React.Component { } componentWillReceiveProps(nextProps) { if (this.state.animation === null) { this.animateNumber(nextProps.count); } else { this.deferredUpdates.push(nextProps.count); @@ -49,12 +49,12 @@ class CounterButton extends React.Component { animateNumber(nextCount) { if (nextCount > this.state.count) { this.setState({ animation: 'inc', next: nextCount }, () => { this.setState({ width: this.getWidth(this.nextNode) }); this.updateCount(nextCount) }); } else { this.setState({ animation: 'dec', prev: nextCount }, () => { this.setState({ width: this.getWidth(this.prevNode) }); this.updateCount(nextCount) }); @@ -63,7 +63,7 @@ class CounterButton extends React.Component { updateCount(number) { setTimeout(() => { this.setState({ count: number, animation: null }, this.handleDeferredItems); }, this.ANIMATION_DURATION); } @@ -91,8 +91,8 @@ class CounterButton extends React.Component { get buttonClassName() { return classNames('counter', { incrementing: this.state.animation === 'inc', decrementing: this.state.animation === 'dec', }) } -
wsmd revised this gist
Oct 29, 2017 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ import React from 'react'; import classNames from 'classnames'; import './CounterButton.css'; const WIDTH_DIFF_THRESHOLD = 2.5; const PARSABLE_PROPERTIES = ['margin-left', 'animation-duration']; const getComputedProperty = (node, property) => { const value = window.getComputedStyle(node)[property]; @@ -80,7 +82,7 @@ class CounterButton extends React.Component { const totalWidth = this.counter.getBoundingClientRect().width; const currentWidth = this.currentNode.getBoundingClientRect().width; const nextWidth = nextNode.getBoundingClientRect().width; if (Math.abs(currentWidth - nextWidth) < WIDTH_DIFF_THRESHOLD) { return totalWidth; }; const newWidth = totalWidth - currentWidth + nextWidth; -
wsmd revised this gist
Oct 29, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -28,6 +28,7 @@ class CounterButton extends React.Component { this.setState({ width: (() => { // @todo I should probbarly avoid a second call here const margin = getComputedProperty(this.counterNode, 'margin-left'); const initial = this.counter.getBoundingClientRect().width; const current = this.currentNode.getBoundingClientRect().width; -
wsmd created this gist
Oct 29, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,24 @@ import React, { Component } from 'react'; import CounterButton from './CounterButton'; import TodoList from './TodoList'; // simple to do list with onCheck and onUncheck props // See live demo: // https://react-counter-button.herokuapp.com/ class App extends Component { state = { counter: 0, } // some logic to handle state.counter render() { return ( <div className="App"> <CounterButton count={this.state.counter}>Archive</CounterButton> </div> ); } } export default App; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,104 @@ .counter { color: white; background: #0076FF; box-shadow: 0 4px 8px -3px rgba(0, 118, 255, 0.5), 0 1px 1px rgba(0, 118, 255, 0.25); padding: 8px 12px; line-height: 16px; display: inline-block; border-radius: 4px; transition: all 0.15s ease; font-size: 14px; box-sizing: border-box; cursor: pointer; text-align: left; border: 0; } .counter-counts { margin-left: 8px; position: absolute; display: inline-block; text-align: center; opacity: 0.75; } .counter-count { transition: all .2s ease; display: inline-block; } .counter-count--active { transform: translateY(0px); } .counter-count--prev, .counter-count--next { position: absolute; left: 0; opacity: 0; } .counter-count--prev { transform: translateY(25px); } .counter-count--next { transform: translateY(-25px); } @keyframes incrementingNext { to { transform: translateY(0px); opacity: 1; } } @keyframes incrementingActive { 60% { opacity: 0; } to { transform: translateY(25px); opacity: 0; } } @keyframes decrementingPrev { to { transform: translateY(0px); opacity: 1; } } @keyframes decrementingActive { 60% { opacity: 0; } to { transform: translateY(-25px); opacity: 0; } } .counter-count { animation-duration: 300ms; animation-timing-function: ease; animation-fill-mode: forwards; animation-iteration-count: infinite; } .counter.incrementing .counter-count--next { animation-name: incrementingNext; } .counter.incrementing .counter-count--active { animation-name: incrementingActive; } .counter.decrementing .counter-count--prev { animation-name: decrementingPrev; } .counter.decrementing .counter-count--active { animation-name: decrementingActive; } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,129 @@ import React from 'react'; import classNames from 'classnames'; import './CounterButton.css'; const PARSABLE_PROPERTIES = ['margin-left', 'animation-duration']; const getComputedProperty = (node, property) => { const value = window.getComputedStyle(node)[property]; if (PARSABLE_PROPERTIES.includes(property)) { return parseFloat(value); } return value; } class CounterButton extends React.Component { deferredUpdates = []; state = { count: this.props.count, next: this.props.count + 1, prev: this.props.count - 1, state: null, width: null, } componentDidMount() { this.ANIMATION_DURATION = getComputedProperty(this.currentNode, 'animation-duration') * 1000; this.setState({ width: (() => { const margin = getComputedProperty(this.counterNode, 'margin-left'); const initial = this.counter.getBoundingClientRect().width; const current = this.currentNode.getBoundingClientRect().width; return initial + margin + current; })(), }) } componentWillReceiveProps(nextProps) { if (this.state.state === null) { this.animateNumber(nextProps.count); } else { this.deferredUpdates.push(nextProps.count); } } animateNumber(nextCount) { if (nextCount > this.state.count) { this.setState({ state: 'inc', next: nextCount }, () => { this.setState({ width: this.getWidth(this.nextNode) }); this.updateCount(nextCount) }); } else { this.setState({ state: 'dec', prev: nextCount }, () => { this.setState({ width: this.getWidth(this.prevNode) }); this.updateCount(nextCount) }); } } updateCount(number) { setTimeout(() => { this.setState({ count: number, state: null }, this.handleDeferredItems); }, this.ANIMATION_DURATION); } handleDeferredItems() { const deferredLength = this.deferredUpdates.length; if (deferredLength > 0) { const lastDeferredNumber = this.deferredUpdates[deferredLength - 1]; if (lastDeferredNumber !== this.state.count) { this.animateNumber(lastDeferredNumber); } this.deferredUpdates = []; } } getWidth(nextNode) { const totalWidth = this.counter.getBoundingClientRect().width; const currentWidth = this.currentNode.getBoundingClientRect().width; const nextWidth = nextNode.getBoundingClientRect().width; if (Math.abs(currentWidth - nextWidth) < 2.5) { return totalWidth; }; const newWidth = totalWidth - currentWidth + nextWidth; return newWidth; } get buttonClassName() { return classNames('counter', { incrementing: this.state.state === 'inc', decrementing: this.state.state === 'dec', }) } render() { return ( <button className={this.buttonClassName} ref={n => { this.counter = n; }} style={{ width: this.state.width }} > {this.props.children} <div className="counter-counts" ref={n => { this.counterNode = n; }} > <span className="counter-count counter-count--next" ref={n => { this.nextNode = n; }} children={this.state.next} /> <span className="counter-count counter-count--active" ref={n => { this.currentNode = n; }} children={this.state.count} /> <span className="counter-count counter-count--prev" ref={n => { this.prevNode = n; }} children={this.state.prev} /> </div> </button> ); } } export default CounterButton;