UNPKG

principles-ui-components

Version:

Supporting UI controller for Tizen TV web application, which developed base on React Framework.

450 lines (391 loc) 15.6 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { is, Map, fromJS } from 'immutable'; import { MAIN_TEXT_FONT, TextItemFamily, AnimationEffect } from './common/CommonDefine'; import './css/Button.css'; import CommonAPI from './common/CommonAPI'; import ScrollText from './common/ScrollText'; import Image from './common/Image'; import TTS from './common/TTS'; export const DROPDOWN_TYPE = { ICON: 'icon', TEXT: 'text', }; export const ARROW_TYPE = { UP: 'up', DOWN: 'down', }; const STATUS = { NORMAL: 0, FOCUSED: 1, SELECTED: 2, DISABLED: 3, }; const BtnResource = { NORMAL: 'url(./images/btn/c_basic_button_white_bg_normal_9patch.png) 5 4 fill stretch', FOCUS: 'url(./images/btn/r_highlight_bg_focus_9patch.png) 20 14 fill stretch', HCNORMAL: 'url(./images/btn/c_basic_button_highcontrast_bg_normal_9patch.png) 6 5 fill stretch', HCFOCUS: 'url(./images/btn/r_highlight_bg_focus_9patch.png) 20 14 fill stretch', SELECTED: 'url(./images/btn/c_basic_button_white_bg_select_9patch.png) 5 4 fill stretch', BAR: 'images/btn/c_buttondropdown_bar.png', ARROWUP_N: 'images/btn/c_buttondropdown_arrow_up.png', ARROWDOWN_N: 'images/btn/c_buttondropdown_arrow_down.png', ARROWUP_F: 'images/btn/c_buttondropdown_arrow_up_focus.png', ARROWDOWN_F: 'images/btn/c_buttondropdown_arrow_down_focus.png', }; const TEXT_LEFT_BORDER = 21; export default class DropdownButton extends Component { constructor(props) { super(props); this.state = { refresh: false, }; this.status = STATUS.NORMAL; this.AnimationName = ''; this.selectIdx = 1; this.animationDone = this.animationDone.bind(this); this.bodyGap = TextItemFamily.BODY_TEXT_GAP; } componentWillMount() { const { buttonScale, refname } = this.props; this.style = document.createElement('style'); this.style.type = 'text/css'; const keyFrames = `@keyframes FocusIn${refname} { 0% {transform: scale(1.00) translateZ(100px);} 100% {transform: scale(${buttonScale}) translateZ(100px);} } @keyframes FocusOut${refname} { 0% {transform: scale(${buttonScale}) translateZ(100px);} 100% {transform: scale(1.00) translateZ(100px);} } @keyframes SelectedIn${refname} { 0% {transform: scale(${buttonScale}) translateZ(100px);} 100% {transform: scale(1.00) translateZ(100px);} } @keyframes SelectedOut${refname} { 0% {transform: scale(1.00) translateZ(100px);} 100% {transform: scale(${buttonScale}) translateZ(100px);} } `; this.style.innerHTML = keyFrames; document.getElementsByTagName('head')[0].appendChild(this.style); } componentDidMount() { this.motionContent.addEventListener('animationend', this.animationDone, false); } componentWillReceiveProps(nextProps) { if (this.props.buttonScale !== nextProps.buttonScale) { this.removeStyleFromHeader(); this.style = document.createElement('style'); this.style.type = 'text/css'; const keyFrames = `@keyframes FocusIn${nextProps.refname} { 0% {transform: scale(1.00) translateZ(100px);} 100% {transform: scale(${nextProps.buttonScale}) translateZ(100px);} } @keyframes FocusOut${nextProps.refname} { 0% {transform: scale(${nextProps.buttonScale}) translateZ(100px);} 100% {transform: scale(1.00) translateZ(100px);} } @keyframes SelectedIn${nextProps.refname} { 0% {transform: scale(${nextProps.buttonScale}) translateZ(100px);} 100% {transform: scale(1.00) translateZ(100px);} } @keyframes SelectedOut${nextProps.refname} { 0% {transform: scale(1.00) translateZ(100px);} 100% {transform: scale(${nextProps.buttonScale}) translateZ(100px);} } `; this.style.innerHTML = keyFrames; document.getElementsByTagName('head')[0].appendChild(this.style); } } shouldComponentUpdate(nextProps, nextState) { return (JSON.stringify(nextProps) !== JSON.stringify(this.props)) || (JSON.stringify(nextState) !== JSON.stringify(this.state)); } componentWillUnmount() { this.removeStyleFromHeader(); this.motionContent.removeEventListener('animationend', this.animationDone, false); } getButtonStyle() { const { layout, highContrast, refname } = this.props; const ButtonStyle = {}; ButtonStyle.position = 'absolute'; ButtonStyle.left = layout.l; ButtonStyle.top = layout.t; ButtonStyle.width = layout.w; ButtonStyle.height = layout.h; // ButtonStyle.border = '2px solid rgb(255,255,255)'; if (this.status === STATUS.FOCUSED) { ButtonStyle.borderImage = highContrast ? BtnResource.HCFOCUS : BtnResource.FOCUS; } else if (this.status === STATUS.SELECTED) { ButtonStyle.borderImage = BtnResource.SELECTED; } else { // NORMAL and DISABLED ButtonStyle.borderImage = highContrast ? BtnResource.HCNORMAL : BtnResource.NORMAL; } ButtonStyle.animationName = this.AnimationName; ButtonStyle.animationFillMode = 'forwards'; if (this.AnimationName === `FocusIn${refname}`) { ButtonStyle.animationDuration = '1.10s'; ButtonStyle.animationTimingFunction = AnimationEffect.Elastic; } else if (this.AnimationName === `FocusOut${refname}`) { ButtonStyle.animationDuration = '0.85s'; ButtonStyle.animationTimingFunction = AnimationEffect.Out; } else if (this.AnimationName === `SelectedIn${refname}`) { ButtonStyle.animationDuration = '0.85s'; ButtonStyle.animationTimingFunction = AnimationEffect.Out; } else if (this.AnimationName === `SelectedOut${refname}`) { ButtonStyle.animationDuration = '1.10s'; ButtonStyle.animationTimingFunction = AnimationEffect.Elastic; } else { ButtonStyle.animationDuration = '0s'; ButtonStyle.animationTimingFunction = ''; } return ButtonStyle; } getDimStyle() { const { layout } = this.props; const dimAnimation = {}; dimAnimation.position = 'absolute'; dimAnimation.width = layout.w; // if have border, need to sub 2* borderwidth dimAnimation.height = layout.h; // if have border, need to sub 2* borderwidth dimAnimation.name = this.AnimationName; if (this.AnimationName === 'DimIn' || this.AnimationName === 'DimOut') { dimAnimation.animationDuration = '0.333s'; dimAnimation.animationTimingFunction = AnimationEffect.Basic; } else { dimAnimation.animationDuration = '0s'; dimAnimation.animationTimingFunction = ''; } return dimAnimation; } getIcon() { const { iconOSD } = this.props; const imageOSD = { l: iconOSD.l, t: iconOSD.t, w: iconOSD.w, h: iconOSD.h, url: iconOSD.url_n, }; if (this.status === STATUS.FOCUSED && typeof iconOSD.url_f !== 'undefined') { imageOSD.url = iconOSD.url_f; } return (<Image OSD={imageOSD} opacity={0} />); } getTextAndBar() { const { layout, text, enlarge, textFont, textSize } = this.props; const barOsd = { l: layout.w - 76, t: (layout.h - 64) / 2, w: 2, h: 64, url: BtnResource.BAR, }; return (<div> <ScrollText left={TEXT_LEFT_BORDER} top={TEXT_LEFT_BORDER} scroll={true} fontSize={enlarge ? (textSize * 1.2) : textSize} fontFamily={textFont} textGap={this.bodyGap} width={layout.w - (TEXT_LEFT_BORDER * 2)} height={layout.h - (TEXT_LEFT_BORDER * 2)} lineHeight={`${layout.h - (TEXT_LEFT_BORDER * 2)}px`} textAlign={'center'} > {text} </ScrollText> <Image OSD={barOsd} /> </div> ); } getArrow() { const { arrowType, layout, buttonType } = this.props; const arrowOsd = {}; arrowOsd.w = 17; arrowOsd.h = 17; arrowOsd.l = layout.w - arrowOsd.w - (buttonType === DROPDOWN_TYPE.ICON ? 11 : 30); arrowOsd.t = (layout.h - arrowOsd.h) / 2; if (arrowType === ARROW_TYPE.UP) { if (this.status === STATUS.FOCUSED) { arrowOsd.url = BtnResource.ARROWUP_F; } else if (this.status === STATUS.SELECTED) { arrowOsd.url = BtnResource.ARROWDOWN_F; } else { arrowOsd.url = BtnResource.ARROWUP_N; } } else if (arrowType === ARROW_TYPE.DOWN) { if (this.status === STATUS.FOCUSED) { arrowOsd.url = BtnResource.ARROWDOWN_F; } else if (this.status === STATUS.SELECTED) { arrowOsd.url = BtnResource.ARROWUP_F; } else { arrowOsd.url = BtnResource.ARROWDOWN_N; } } return (<Image OSD={arrowOsd} />); } SelectButton(flag) { if (this.status === STATUS.DISABLED) { console.log('Button disabled!'); return; } if (flag && this.status === STATUS.FOCUSED) { this.AnimationName = `SelectedIn${this.props.refname}`; this.status = STATUS.SELECTED; } else if (!flag && this.status === STATUS.SELECTED) { this.AnimationName = `SelectedOut${this.props.refname}`; this.status = STATUS.FOCUSED; } else { return; } this.setState({ refresh: !this.state.refresh }); // render and refresh the button } DisableButton(flag) { if (flag && this.status !== STATUS.DISABLED) { this.AnimationName = 'DimIn'; this.status = STATUS.DISABLED; } else if (!flag && this.status === STATUS.DISABLED) { this.AnimationName = 'DimOut'; this.status = STATUS.NORMAL; } else { return; } this.setState({ refresh: !this.state.refresh }); // render and refresh the button } playTTS() { if (this.props.ttsEnable) { console.log('drop down button play TTS'); this.TTSnode.playTTS(); } } SetFocus(flag) { if (this.status === STATUS.DISABLED) { console.log('Button disabled!'); return; } if (flag && this.status === STATUS.NORMAL) { this.AnimationName = `FocusIn${this.props.refname}`; this.status = STATUS.FOCUSED; this.playTTS(); } else if (!flag && this.status === STATUS.FOCUSED) { this.AnimationName = `FocusOut${this.props.refname}`; this.status = STATUS.NORMAL; } else { return; } this.setState({ refresh: !this.state.refresh }); // render and refresh the button } animationDone(e) { e.preventDefault(); const target = e.target; if (target === e.currentTarget) { if (e.type === 'animationend') { if (e.animationName === `SelectedIn${this.props.refname}`) { if (this.props.selectCB && typeof this.props.selectCB === 'function') { this.props.selectCB(); } } else if (e.animationName === `SelectedOut${this.props.refname}`) { if (this.props.unselectCB && typeof this.props.unselectCB === 'function') { this.props.unselectCB(); } } } } } removeStyleFromHeader() { if (this.style) { document.getElementsByTagName('head')[0].removeChild(this.style); this.style = null; } } render() { const { buttonType, ttsEnable, ttsText } = this.props; let contentComponent = null; if (buttonType === DROPDOWN_TYPE.ICON) { contentComponent = this.getIcon(); } else if (buttonType === DROPDOWN_TYPE.TEXT) { contentComponent = this.getTextAndBar(); } const arrowComponent = this.getArrow(); let TTSComponent = null; if (ttsEnable) { TTSComponent = <TTS ref={(TTSnode) => { this.TTSnode = TTSnode; }} ttsEnable={ttsEnable} ttsText={ttsText} />; } const ButtonStyle = this.getButtonStyle(); const dimAnimation = this.getDimStyle(); return (<div ref={(motionContent) => { this.motionContent = motionContent; }} style={ButtonStyle}> <div style={dimAnimation}> {contentComponent} {arrowComponent} </div> {TTSComponent} </div> ); } } DropdownButton.defaultProps = { layout: { l: 0, t: 0, w: 414, h: 84, }, highContrast: false, enlarge: false, ttsEnable: false, ttsText: '', selectCB: null, unselectCB: null, buttonScale: 1.08, refname: '', text: '', textFont: MAIN_TEXT_FONT, textSize: TextItemFamily.TITLE2_TEXT_SIZE, iconOSD: { l: 14, t: 23, w: 38, h: 38, url_n: '', url_f: '', }, }; DropdownButton.propTypes = { buttonType: PropTypes.oneOf(['icon', 'text']).isRequired, // The type of button, "ICON" means only icon, "TEXT means only text arrowType: PropTypes.oneOf(['up', 'down']).isRequired, layout: PropTypes.shape({ l: PropTypes.number, t: PropTypes.number, w: PropTypes.number, h: PropTypes.number, }), selectCB: PropTypes.func, unselectCB: PropTypes.func, highContrast: PropTypes.bool, enlarge: PropTypes.bool, ttsEnable: PropTypes.bool, ttsText: PropTypes.string, buttonScale: PropTypes.number, refname: PropTypes.string, text: PropTypes.string, // message of button show textFont: PropTypes.string, textSize: PropTypes.number, iconOSD: PropTypes.shape({ l: PropTypes.number, t: PropTypes.number, w: PropTypes.number, h: PropTypes.number, url_n: PropTypes.string, url_f: PropTypes.string, }), };