From bd0def8c1d53954beb29d694299acf99d67578a9 Mon Sep 17 00:00:00 2001 From: Rafael Caferati Date: Mon, 19 Feb 2018 10:52:52 +0000 Subject: [PATCH] add customiser initial version --- src/components/AwesomeButton/index.js | 13 +- src/components/AwesomeButtonProgress/index.js | 44 +++-- src/demo/components/customiser.js | 178 ++++++++++++++++++ src/demo/components/theme-test.js | 33 ++-- src/demo/demo.scss | 29 +++ src/demo/theme/demo.js | 4 +- src/helpers/components.js | 4 +- .../custom-properties.scss | 3 + .../base/with-custom-properties/main.scss | 57 +++--- .../base/with-custom-properties/progress.scss | 97 ++++++++++ .../themes/theme-blue/config/lists.scss | 12 +- 11 files changed, 390 insertions(+), 84 deletions(-) create mode 100644 src/demo/components/customiser.js diff --git a/src/components/AwesomeButton/index.js b/src/components/AwesomeButton/index.js index 979386e..988bee9 100644 --- a/src/components/AwesomeButton/index.js +++ b/src/components/AwesomeButton/index.js @@ -269,18 +269,13 @@ export default class AwesomeButton extends React.Component { > { this.button = button; }} - className={getClassName(`${this.rootElement}__container`, cssModule)} + className={getClassName(`${this.rootElement}__wrapper`, cssModule)} > { this.wrapper = wrapper; }} - className={getClassName(`${this.rootElement}__wrapper`, cssModule)} + ref={(content) => { this.content = content; }} + className={getClassName(`${this.rootElement}__content`, cssModule)} > - { this.content = content; }} - className={getClassName(`${this.rootElement}__content`, cssModule)} - > - {children} - + { this.child = child; }}>{children} diff --git a/src/components/AwesomeButtonProgress/index.js b/src/components/AwesomeButtonProgress/index.js index 0e97496..f770a8f 100644 --- a/src/components/AwesomeButtonProgress/index.js +++ b/src/components/AwesomeButtonProgress/index.js @@ -34,8 +34,8 @@ export default class AwesomeProgress extends React.Component { super(props); this.rootElement = props.rootElement || ROOTELM; this.animationStage = 0; + this.loading = false; this.state = { - loading: false, loadingEnd: false, loadingStart: false, blocked: false, @@ -61,36 +61,48 @@ export default class AwesomeProgress extends React.Component { return className.join(' ').trim().replace(/[\s]+/ig, ' '); } endLoading() { - this.setState({ loadingEnd: true }); + this.setState({ + loadingEnd: true, + }); this.animationStage = 1; } startLoading() { + this.loading = true; this.setState({ - loading: true, - loadingStart: true, blocked: true, active: true, + }, () => { + /* + To avoid the button eventual flickering I've changed the display strategy + for that to work in a controlled way we need to set the loadingStart + at least one painting cycle ahead + */ + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + this.setState({ + loadingStart: true, + }); + }); + }); }); } - clearLoading() { + clearLoading(callback) { + this.loading = false; this.setState({ - loading: false, loadingStart: false, loadingEnd: false, - }); + active: false, + }, callback); } clearStagedWrapperAnimation() { if (this.animationStage !== 0) { if (this.animationStage === LOADING_ANIMATION_STEPS) { this.animationStage = 0; - // hold life for 350ms before releasing the button; + // hold life for 500ms before releasing the button; setTimeout(() => { if (typeof window !== 'undefined') { window.requestAnimationFrame(() => { - this.clearLoading(); - this.setState({ - active: false, - }, () => { + this.clearLoading(() => { setTimeout(() => { this.setState({ blocked: false, @@ -118,19 +130,17 @@ export default class AwesomeProgress extends React.Component { const events = { onMouseDown: (event) => { if (this.state.disabled === true || - this.state.loading === true || + this.loading === true || this.state.blocked === true || (event && event.nativeEvent.which !== 1) ) { return; } - this.setState({ - loading: true, - }); + this.loading = true; }, onMouseUp: (event) => { if (this.state.disabled === true || - this.state.loading === true || + this.loading === true || this.state.blocked === true) { event.preventDefault(); event.stopPropagation(); diff --git a/src/demo/components/customiser.js b/src/demo/components/customiser.js new file mode 100644 index 0000000..c0afb53 --- /dev/null +++ b/src/demo/components/customiser.js @@ -0,0 +1,178 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const PROPERTIES = [ + { + name: 'button-color-primary', + type: 'color', + }, + { + name: 'button-color-primary-dark', + type: 'color', + }, + { + name: 'button-color-primary-light', + type: 'color', + }, + { + name: 'button-color-primary-border', + type: 'color', + }, + { + name: 'button-color-secondary', + type: 'color', + }, + { + name: 'button-color-secondary-dark', + type: 'color', + }, + { + name: 'button-color-secondary-light', + type: 'color', + }, + { + name: 'button-color-secondary-border', + type: 'color', + }, + { + name: 'button-default-height', + type: 'range', + max: 100, + min: 30, + suffix: 'px', + }, + { + name: 'button-default-font-size', + type: 'range', + max: 25, + min: 10, + suffix: 'px', + }, + { + name: 'button-default-border-radius', + type: 'range', + max: 25, + suffix: 'px', + }, + { + name: 'button-horizontal-padding', + type: 'range', + max: 50, + suffix: 'px', + }, + { + name: 'button-raise-level', + type: 'range', + max: 10, + suffix: 'px', + }, + { + name: 'button-hover-pressure', + type: 'range', + max: 4, + step: 0.5, + }, +]; + +function applyStyles(buttons, { property, value }) { + buttons.forEach((button) => { + button.style.setProperty(property, value); + }); +} + +class Customiser extends React.Component { + static propTypes = { + styles: PropTypes.object.isRequired, + theme: PropTypes.string.isRequired, + }; + constructor(props) { + super(props); + this.state = { + buttonSample: null, + '--button-color-primary': null, + }; + } + + componentDidMount() { + this.setState({ + buttonSample: document.querySelector('button'), + allButtons: document.querySelectorAll('button'), + }); + } + + handleChange = () => { + console.log('change-made'); + } + + renderInputs() { + return PROPERTIES.map((cssProperty) => { + const { name, type } = cssProperty; + const buttonName = `--${name}`; + + if (!this.state[buttonName] && this.state.buttonSample) { + const state = {}; + let style = getComputedStyle(this.state.buttonSample).getPropertyValue(buttonName); + if (style.match(/(#)([a-z0-9]{3})($)/)) { + style = style.replace(/(#)([a-z0-9]{3})/, '$1$2$2'); + } + if (style.match(/px|em/)) { + style = style.replace(/px|em/ig, '') + } + state[buttonName] = style; + this.setState(state); + } + + const extraProps = {}; + extraProps.type = type; + + if (type === 'range') { + extraProps.type = type; + extraProps.min = cssProperty.min || 0; + extraProps.max = cssProperty.max || 10; + extraProps.step = cssProperty.step || 1; + } + + return ( +
  • + + { + const state = {}; + let { value } = event.target; + state[buttonName] = value; + this.setState(state); + if (cssProperty.suffix) { + value = `${value}${cssProperty.suffix}`; + } + applyStyles(this.state.allButtons, { + property: buttonName, + value, + }); + }} + {... extraProps} + /> +
  • + ); + }); + } + + render() { + const { + styles, + } = this.props; + + return ( +
    + +
    + ); + } +} + +export default Customiser; diff --git a/src/demo/components/theme-test.js b/src/demo/components/theme-test.js index 6d22c49..5f9c483 100644 --- a/src/demo/components/theme-test.js +++ b/src/demo/components/theme-test.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { AwesomeButton, AwesomeButtonSocial } from '../../index'; +import { AwesomeButton, AwesomeButtonSocial, AwesomeButtonProgress } from '../../index'; import Modules from '../../helpers/modules'; class Test extends React.Component { @@ -28,32 +28,32 @@ class Test extends React.Component {
    Primary +
    +
    - Secondary + Secondary
    - { setTimeout(() => { + // debugger; next(); - }, 1000); + }, 750); }} > Progress - +
    - ← Set Placeholder Data + ← Set Data
    @@ -110,6 +110,8 @@ class Test extends React.Component { > Share +
    +
    Share - - Share - +
    +
    +
    +
    ); } diff --git a/src/helpers/components.js b/src/helpers/components.js index 07fc4da..fdde519 100644 --- a/src/helpers/components.js +++ b/src/helpers/components.js @@ -83,7 +83,9 @@ export function createBubbleEffect({ bubble.style.height = `${size}px`; setCssEndEvent(bubble, 'animation', () => { - content.removeChild(bubble); + window.requestAnimationFrame(() => { + content.removeChild(bubble); + }); }); window.requestAnimationFrame(() => { content.appendChild(bubble); diff --git a/src/styles/base/with-custom-properties/custom-properties.scss b/src/styles/base/with-custom-properties/custom-properties.scss index 17ca059..11256f1 100644 --- a/src/styles/base/with-custom-properties/custom-properties.scss +++ b/src/styles/base/with-custom-properties/custom-properties.scss @@ -25,9 +25,12 @@ --button-color-primary: $button-color-primary; --button-color-primary-dark: darken($button-color-primary, 15%); --button-color-primary-light: lighten($button-color-primary, 50%); + --button-color-primary-hover: darken($button-color-primary, 5%); + --button-color-primary-border: none; --button-color-secondary: $button-color-secondary; --button-color-secondary-dark: darken($button-color-secondary, 15%); --button-color-secondary-light: lighten($button-color-secondary, 50%); + --button-color-secondary-hover: darken($button-color-secondary, 5%); --button-color-secondary-border: 2px solid var(--button-color-primary); --button-color-disabled: $button-color-disabled; --button-color-disabled-dark: darken($button-color-disabled, 15%); diff --git a/src/styles/base/with-custom-properties/main.scss b/src/styles/base/with-custom-properties/main.scss index 845b610..683b42f 100644 --- a/src/styles/base/with-custom-properties/main.scss +++ b/src/styles/base/with-custom-properties/main.scss @@ -11,17 +11,19 @@ @if(length($color) > 4) { border: nth($color, 5); } - @if(length($color) > 6) { - > span:nth-child(1) { - &:before { - background-color: nth($color, 7) - } + } + @if(length($color) > 5) { + &:hover { + .#{$button-root}__content { + background: nth($color, 6); } } } - .#{$button-root}__bubble { - @if(length($color) > 5) { - background-color: nth($color, 6); + @if(length($color) > 6) { + &.#{$button-root}--active { + .#{$button-root}__content { + background: nth($color, 7); + } } } } @@ -107,12 +109,7 @@ transition: opacity .1s ease-out; border: none; opacity: 0; - z-index: 5; -webkit-font-smoothing: antialiased; - .#{$button-root}__container { - display: block; - height: 100%; - } .#{$button-root}__wrapper { position: relative; font-family: var(--button-font-family); @@ -151,28 +148,28 @@ z-index: 3; overflow: hidden; padding: 0 var(--button-horizontal-padding); + backface-visibility: hidden; + transform-style: flat; + transform: + skew(0) + translate3d(0, 0, 0); transition: border var(--transform-speed) ease-out, transform var(--transform-speed) ease-out, background var(--transform-speed) ease-out, color var(--transform-speed) ease-out; - &:before{ - @extend %fill-parent; + &:after { + // content: " "; + // background-color: rgba(0, 0, 0, $button-hover-darken-opacity); + // transition: opacity calc(var(--transform-speed) * 2) ease-out; + // opacity: 0; } &:after{ @extend %fill-parent; } > span:nth-child(1) { display: block; - &:before { - content: " "; - @extend %fill-parent; - background-color: rgba(0, 0, 0, $button-hover-darken-opacity); - transition: opacity calc(var(--transform-speed) * 2) ease-out; - opacity: 0; - z-index: -1; - } - > span, > svg, > img { + > svg, > img > span { vertical-align: middle; } } @@ -180,13 +177,6 @@ &:focus { @extend %clear-focus; } - &:hover { - .#{$button-root}__content { - > span:before { - opacity: 1; - } - } - } &:before { content: " "; background-color: rgba(0, 0, 0, 0.3); @@ -197,6 +187,9 @@ position: absolute; border-radius: var(--button-default-border-radius); z-index: 1; + transform: + skewY(0) + translate3d(0, 0, 0); transition: transform calc(var(--transform-speed) * 0.8) ease-out, background calc(var(--transform-speed) * 0.8) ease-out; } @include getColors($button-colors); @@ -284,7 +277,7 @@ span.#{$button-root}__bubble { height: 0px; border-radius: 50%; background: rgba(0, 0, 0, 0.1); - z-index: -1; + z-index: 10; opacity: 0; transform: scale(0.1); animation: ping calc(var(--transform-speed) * 3.5) cubic-bezier(0.5, 0, 0.6, 0.4) 0.05s forwards; diff --git a/src/styles/base/with-custom-properties/progress.scss b/src/styles/base/with-custom-properties/progress.scss index e69de29..1b3baf0 100644 --- a/src/styles/base/with-custom-properties/progress.scss +++ b/src/styles/base/with-custom-properties/progress.scss @@ -0,0 +1,97 @@ +.#{$button-root} { + &--progress { + .#{$button-root}__progress { + position: relative; + display: flex; + flex: 1; + align-items: center; + justify-content: center; + border-radius: $button-default-border-radius; + text-indent: 0; + z-index: 3; + overflow: hidden; + padding: 0 $button-horizontal-padding; + transition: + border $transform-speed ease-out, + transform $transform-speed ease-out, + background $transform-speed ease-out, + color $transform-speed ease-out; + > span { + transition: opacity $transform-speed * 0.50 ease-out $transform-speed * 0.75; + } + &:before, &:after { + @extend %fill-parent; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255,255,255, 0.65); + opacity: 0; + transition: transform $transform-speed ease-out 0.05s, opacity $transform-speed * 0.75 ease-out 0.05s; + } + &:before { + content: attr(data-loading); + display: none; + transform: translate3d(0, 50%, 0); + } + &:after { + content: attr(data-status); + display: none; + transform: translate3d(0, -50%, 0); + } + } + &.#{$button-root}--active { + .#{$button-root}__progress { + > span { + opacity: 0.075; + } + } + .#{$button-root}__progress:after, + .#{$button-root}__progress:before, + .#{$button-root}__content:after { + display: block; + } + } + .#{$button-root}__content { + &:after { + @extend %fill-parent; + content: " "; + background-color: rgba(0,0,0,0.15); + transform: translate3d(-100%, 0, 0); + width: 100%; + display: none; + } + } + } + &--start { + .#{$button-root}__progress { + &:before { + opacity: 1; + transform: translate3d(0, 0, 0); + } + } + .#{$button-root}__content { + &:after { + transition: transform $loading-transition-speed ease-out; + transform: translate3d(-15%, 0, 0); + } + } + } + &--end { + .#{$button-root}__content { + &:after { + transition: transform $loading-transition-speed/20 ease-out; + transform: translate3d(0, 0, 0); + } + } + .#{$button-root}__progress { + &:after { + opacity: 1; + transform: translate3d(0, 0, 0); + } + &:before { + transform: translate3d(0, 50%, 0); + opacity: 0; + } + } + } +} diff --git a/src/styles/themes/theme-blue/config/lists.scss b/src/styles/themes/theme-blue/config/lists.scss index 7414d43..842a964 100644 --- a/src/styles/themes/theme-blue/config/lists.scss +++ b/src/styles/themes/theme-blue/config/lists.scss @@ -15,6 +15,7 @@ $button-colors: var(--button-color-primary-dark), var(--button-color-primary-light), var(--button-color-primary-border), + var(--button-color-primary-hover), var(--button-color-primary-dark), ), ( @@ -23,6 +24,7 @@ $button-colors: var(--button-color-primary-dark), var(--button-color-primary), var(--button-color-secondary-border), + var(--button-color-secondary-hover), var(--button-color-secondary-dark), ), ( @@ -31,15 +33,15 @@ $button-colors: var(--button-color-disabled-dark), var(--button-color-disabled-dark), var(--button-color-disabled-border), - transparent, - transparent, + var(--button-color-disabled), + var(--button-color-disabled), ), ( "placeholder", var(--button-color-placeholder), var(--button-color-placeholder-dark), var(--button-color-placeholder-light), - none, - transparent, - transparent, + var(--button-color-placeholder-border), + var(--button-color-placeholder), + var(--button-color-placeholder), );