react-font-style
Version:
React font style editor
207 lines (192 loc) • 6.46 kB
JavaScript
// @flow
import * as React from 'react';
import ButtonGroup from './ui/ButtonGroup';
import IconButton from './ui/IconButton';
import Dropdown from './ui/Dropdown';
import FontFamilyDropdown from './ui/FontFamilyDropdown';
import Palette from './Palette';
import {generateConfig, generateConfigState, stateToStyle} from './config';
type toobacConfigType = {
type: string,
label: string,
style: Object
}
type Props = {
defaultStyle?: Object,
customConfig?: Object,
text?: string,
customizedPlugin?: React.Element<*>,
textComponent?: React.Element<*>,
onChange: (style: Object) => void
};
type State = {
showPalette: false | 'highlight' | 'font',
activeInlineStyle: Object,
activeFontSize: number,
activeColor: string,
activeBackgroundColor: string,
activeLineHeight: number,
activeAlign: string,
activeFontFamily: string,
config: {
ALIGN_DROPDOWN: Array<toobacConfigType>,
FONT_FAMILY_DROPDOWN: Array<toobacConfigType>,
FONT_SIZE_DROPDOWN: Array<toobacConfigType>,
INLINE_STYLE_BUTTONS: Array<toobacConfigType>,
LINE_HEIGHT_DROPDOWN: Array<toobacConfigType>,
alignObj: Object,
display: Array<string>,
fontFamiltyObj: Object,
fontSizeObj: Object,
inlineStyleObj: Object,
lineHeightObj: Object
},
fontStyle: Object
};
export default class ReactFontStyle extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
const config = generateConfig(props.customConfig);
const state = generateConfigState(config, props.defaultStyle);
this.state = {
...state,
showPalette: false,
config,
fontStyle: stateToStyle({...state, config})
};
}
static defaultProps = {
defaultStyle: {},
text: 'ABCD'
}
togglePalette = (show: false | 'highlight' | 'font') => {
const {showPalette} = this.state;
let newShowPalette;
if (show === showPalette) {
newShowPalette = false;
} else {
newShowPalette = show;
}
this.setState({showPalette: newShowPalette});
}
handleInlineStyleChange = (type: string) => {
const {activeInlineStyle} = this.state;
activeInlineStyle[type] = !activeInlineStyle[type];
this.onChange(activeInlineStyle);
}
handleChangeFontSize = (label: number) => {
this.onChange({activeFontSize: label});
}
handleChangeFontFamily = (label: number) => {
this.onChange({activeFontFamily: label});
}
handleLineHeight = (label: number) => {
this.onChange({activeLineHeight: label});
}
handleAlign = (label: string) => {
this.onChange({activeAlign: label});
}
handleColorChange = (color: {hex: string, rgba: Object}) => {
const {showPalette} = this.state;
const {hex} = color;
if (showPalette === 'font') {
this.onChange({activeColor: hex});
} else if (showPalette === 'highlight') {
this.onChange({activeBackgroundColor: hex});
}
}
onChange = (updated: Object) => {
const newState = {...this.state, ...updated};
const fontStyle = stateToStyle(newState);
this.setState({...newState, fontStyle});
if (this.props.onChange) {
this.props.onChange(fontStyle);
}
}
render() {
const {
activeInlineStyle,
activeFontSize,
activeColor,
activeBackgroundColor,
activeLineHeight,
activeAlign,
activeFontFamily,
showPalette,
config,
fontStyle
} = this.state;
const {text, customizedPlugin, textComponent} = this.props;
return (
<div>
{config.display.includes('INLINE_STYLE_BUTTONS') ?
<ButtonGroup>
{config.INLINE_STYLE_BUTTONS.map((item: toobacConfigType) => (
<IconButton key={item.type}
iconName={item.type}
isActive={activeInlineStyle[item.type]}
onMouseDown={() => this.handleInlineStyleChange(item.type)} />
))}
</ButtonGroup>
: null}
{config.display.includes('FONT_COLOR_BUTTON') || config.display.includes('FONT_HIGHLIGHT_BUTTON')?
<ButtonGroup>
{config.display.includes('FONT_HIGHLIGHT_BUTTON') ?
<IconButton iconName="mark"
onMouseDown={() => this.togglePalette('highlight')}
isActive={showPalette === 'highlight'}/>
: null}
{config.display.includes('FONT_COLOR_BUTTON') ?
<IconButton iconName="color"
onMouseDown={() => this.togglePalette('font')}
isActive={showPalette === 'font'}/>
: null}
</ButtonGroup>
: null}
{config.display.includes('FONT_SIZE_DROPDOWN') ?
<Dropdown choices={config.FONT_SIZE_DROPDOWN}
selectedKey={activeFontSize}
onChange={this.handleChangeFontSize}
icon='font'
/>
: null}
{config.display.includes('FONT_FAMILY_DROPDOWN') ?
<FontFamilyDropdown choices={config.FONT_FAMILY_DROPDOWN}
selectedKey={activeFontFamily}
onChange={this.handleChangeFontFamily}
icon='font'
/>
: null}
{config.display.includes('LINE_HEIGHT_DROPDOWN') ?
<Dropdown choices={config.LINE_HEIGHT_DROPDOWN}
selectedKey={activeLineHeight}
icon='lineheight'
onChange={this.handleLineHeight}
/>
: null}
{config.display.includes('ALIGN_DROPDOWN') ?
<Dropdown choices={config.ALIGN_DROPDOWN}
selectedKey={activeAlign}
icon={
activeAlign === 'Align Left' ? 'align-left' :
activeAlign === 'Align Center' ? 'align-center' : 'align-right'
}
onChange={this.handleAlign}
/>
: null}
{customizedPlugin ? customizedPlugin : null}
{showPalette ?
<Palette color={showPalette === 'font' ? activeColor : activeBackgroundColor}
onChange={this.handleColorChange}/>
: null}
{textComponent ? textComponent
: <div style={{padding: '20px 10px', backgroundColor: '#eee'}}>
<div style={fontStyle}>
{text}
</div>
</div>
}
</div>
);
}
}