UNPKG

react-awesome-button-namdaoduy

Version:

Performant, extendable, highly customisable, production ready React Component that renders an animated basic set of UI buttons

292 lines (271 loc) 8.08 kB
import React from 'react'; import PropTypes from 'prop-types'; import Styles from './customiser.scss'; import { AwesomeButton, AwesomeButtonSocial } from '../../../src/index'; import { rgba2hex } from '../../helpers/examples'; import { ColorPicker, BorderPicker } from '../index'; function applyStyles(elements, { property, value }) { elements.forEach((element) => { element.style.setProperty(property, value); }); } class Customiser extends React.Component { static propTypes = { repository: PropTypes.string.isRequired, module: PropTypes.object.isRequired, handlePopover: PropTypes.func.isRequired, theme: PropTypes.string.isRequired, componentClass: PropTypes.string.isRequired, properties: PropTypes.array.isRequired, }; constructor(props) { super(props); this.values = {}; this.state = { customized: false, popoverOpened: false, }; } state = { element: null, }; componentWillMount() { this.updateProperties(this.props); } componentDidMount() { this.updateElement(this.props.componentClass); this.updateAllValues(this.props); } componentWillReceiveProps(newProps) { this.values = {}; if (this.props.theme !== newProps.theme) { this.updateValues = true; } } componentDidUpdate() { if (this.updateValues === true) { this.updateValues = false; this.updateAllValues(this.props); } } getStylesText() { // this.element const text = ['<p><b>.aws-btn</b> {</p><ul>']; this.props.properties.forEach((section) => { section.props.forEach((prop) => { const name = `--${prop.name}`; text.push(`<li><b>${name}</b>: <em>${this.state[name]}${prop.suffix || ''}</em>;</li>`); }); }); text.push('</ul><p>}</p>'); return text.join(''); } updateAllValues(newProps) { const state = { customized: false, }; if (!this.element) { return false; } newProps.properties.forEach((section) => { section.props.forEach((prop) => { const name = `--${prop.name}`; let style = getComputedStyle(this.element).getPropertyValue(name).trim(); if (style.match(/(#)([a-z0-9]{3})($)/)) { style = style.replace(/(#)([a-z0-9]{3})/, '$1$2$2'); } if (style.match(/(px|em|s)$/)) { style = style.replace(/px|em|s/ig, ''); } if (style.match(/rgb/)) { style = rgba2hex(style); } state[name] = style; if (typeof window !== 'undefined') { applyStyles(document.querySelectorAll(`[data-role="customizable"] .${this.props.componentClass}`), { property: name, value: style + (prop.suffix || ''), }); } }); }); this.setState(state); return true; } updateProperties(newProps) { if (newProps.properties) { const state = {}; newProps.properties.forEach((section) => { section.props.forEach((prop) => { state[`--${prop.name}`] = null; }); }); this.setState(state); } } updateElement(className) { if (this.control) { this.element = this.control.querySelector(`.${className}`); } } resetStyles = () => { this.setState({ customized: false, }); this.updateAllValues(this.props); } exportStyles = () => { this.setState({ popoverOpened: true, }, () => { this.props.handlePopover({ popoverOpened: true, popoverText: this.getStylesText(), }); }); } updatePopoverText() { this.props.handlePopover({ popoverText: this.getStylesText(), }); } renderInputs(props) { return props.map((cssProperty) => { const { name, type } = cssProperty; const buttonName = `--${name}`; 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; } const onChange = (event) => { if (this.state.customized === false) { this.setState({ customized: true }); } const state = {}; let { value } = event.target; state[buttonName] = value; this.setState(state, () => { this.updatePopoverText(); }); if (typeof window !== 'undefined') { if (cssProperty.suffix) { value = `${value}${cssProperty.suffix}`; } applyStyles(document.querySelectorAll(`[data-role="customizable"] .${this.props.componentClass}`), { property: buttonName, value, }); } }; let input = null; switch (type) { case 'color': input = ( <ColorPicker value={this.state[buttonName] || this.values[buttonName] || ''} setTransparency={onChange} onChange={onChange} {... extraProps} /> ); break; case 'border': input = ( <BorderPicker value={this.state[buttonName] || this.values[buttonName] || ''} onChange={onChange} {... extraProps} /> ); break; default: input = ( <input value={this.state[buttonName] || this.values[buttonName] || ''} onChange={onChange} {... extraProps} /> ); } const buttonValue = this.state[buttonName] ? `${this.state[buttonName] || this.values[buttonName]}${cssProperty.suffix || ''}` || '' : ''; return ( <li key={buttonName}> <label> <code>{name}</code> </label> <div> {input} </div> <div> <span>{buttonValue}</span> </div> </li> ); }); } renderSection(section) { return ( <section key={section.name}> <h3>{section.name}</h3> <ul> {this.renderInputs(section.props)} </ul> </section> ); } renderSections(sections) { return sections.map(section => this.renderSection(section)); } render() { return ( <section className={Styles.container}> <header> <h2>Custom Properties</h2> <p>Basic customization through CSS custom-properties.</p> <div ref={(control) => { this.control = control; }} className={Styles.control} > <AwesomeButton size="medium" disabled={!this.state.customized} action={this.resetStyles} cssModule={this.props.module} > Reset Styles </AwesomeButton> <AwesomeButtonSocial size="medium" href={this.props.repository} target="_blank" type="github" cssModule={this.props.module} > Source </AwesomeButtonSocial> </div> </header> <ul> { this.renderSections(this.props.properties) } </ul> <footer> <div className={Styles.export}> <AwesomeButton size="medium" action={this.exportStyles} cssModule={this.props.module} > Export Styles </AwesomeButton> </div> <p>Access the source on <a target="_blank" href={this.props.repository}>github</a> to check all customisable options</p> </footer> </section> ); } } export default Customiser;