UNPKG

dis-gui

Version:

An extensible, styleable, & React-based controller library inspired by the venerable dat-gui.

141 lines (125 loc) 3.73 kB
'use strict'; import PropTypes from 'prop-types'; import React from 'react'; import merge from 'lodash.merge'; import {Row, Control} from './components'; let defaultStyle = { labelWidth: 96, controlWidth: 192, paddingY: 3, paddingX: 3, highlight: '#0FA', lowlight: '#444', lowlighterr: '#822', font: '11px Arial', backgroundColor: '#1A1A1A', separator: '1px solid #333', label: { fontColor: '#FFF', fontWeight: 'normal', }, }; export default class GUI extends React.PureComponent { constructor(props) { super(props); this.style = merge(JSON.parse(JSON.stringify(defaultStyle)), this.props.style); this.style.computed = {}; this.style.computed.fontHeight = calculateFontHeight(this.style.font); this.style.computed.itemHeight = this.style.computed.fontHeight + this.style.paddingY * 2; this.style.computed.minRowHeight = this.style.computed.itemHeight + this.style.paddingY * 2; this.state = { expanded: this.props.expanded } } componentWillReceiveProps(nextProps) { if (nextProps.expanded !== this.props.expanded) { if (nextProps.expanded !== this.state.expanded) { this.setState({expanded: nextProps.expanded || nextProps.alwaysOpen}); } } } render() { let noSelect = { WebkitUserSelect: 'none', MozUserSelect: 'none', msUserSelect: 'none', userSelect: 'none', MozAppearance: 'none', } let style = { position: 'fixed', }; if (this.style.right !== undefined) { style.right = this.style.right; } else if (this.style.left !== undefined) { style.left = this.style.left; } else { style.right = '8px'; } if (this.style.top !== undefined) { style.top = this.style.top; } else if (this.style.bottom !== undefined) { style.bottom = this.style.bottom; } else { style.top = '0px'; } const expandText = this.state.expanded ? 'Close Controls' : 'Open Controls' return ( <div style={style} className={this.props.className}> <div style={{display: this.state.expanded ? 'block' : 'none'}}> {this.props.children} </div> {!this.props.alwaysOpen && <Row> <div onClick={this.handleCloseControls.bind(this)} style={{ font: this.style.font, color: this.style.label.fontColor, textAlign: 'center', width: this.style.labelWidth + this.style.controlWidth + 2 * this.style.paddingX, cursor: 'pointer', }} > <span style={noSelect}>{expandText}</span> </div> </Row> } </div> ) } getChildContext() { return { style: this.style, } } handleCloseControls() { this.setState({ expanded: !this.state.expanded }); } } GUI.propTypes = { style: PropTypes.object, expanded: PropTypes.bool, alwaysOpen: PropTypes.bool, className: PropTypes.string }; GUI.defaultProps = { expanded: true, alwaysOpen: false } GUI.childContextTypes = { style: PropTypes.object, }; function calculateFontHeight(font) { let div = document.createElement('div'); div.style.font = font; div.style.overflow = 'hidden'; div.style.whiteSpace = 'nowrap'; div.innerHTML = '~!@#$%^&*()_+`1234567890-=QWERTYUIOP{}|qwertyuiop[]\\ASDFGHJKL:"asdfghjkl;\'ZXCVBNM<>?zxcvbnm,./'; document.body.appendChild(div); let height = div.clientHeight; document.body.removeChild(div); return height; }