principles-ui-components
Version:
Supporting UI controller for Tizen TV web application, which developed base on React Framework.
255 lines (230 loc) • 9.87 kB
JavaScript
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { is, Map, fromJS } from 'immutable';
import { MAIN_TEXT_FONT, TextItemFamily, AnimationEffect, KEY } from './common/CommonDefine';
import './css/Tooltip.css';
import CommonAPI from './common/CommonAPI';
import ScrollText from './common/ScrollText';
import Image from './common/Image';
const tailResource = {
normal: {
bg: 'url(./images/tooltip/c_tooltip_white_bubble_bg_9patch.png) 24 14 fill stretch',
top: 'url(./images/tooltip/c_tooltip_white_bubble_arrow_top.png)',
bottom: 'url(./images/tooltip/c_tooltip_white_bubble_arrow_bottom.png)',
left: 'url(./images/tooltip/c_tooltip_white_bubble_arrow_left.png)',
right: 'url(./images/tooltip/c_tooltip_white_bubble_arrow_right.png)',
},
highContrast: {
bg: 'url(./images/tooltip/c_tooltip_highcontrast_bubble_bg_9patch.png) 24 14 fill stretch',
top: 'url(./images/tooltip/c_tooltip_highcontrast_bubble_arrow_top.png)',
bottom: 'url(./images/tooltip/c_tooltip_highcontrast_bubble_arrow_bottom.png)',
left: 'url(./images/tooltip/c_tooltip_highcontrast_bubble_arrow_left.png)',
right: 'url(./images/tooltip/c_tooltip_highcontrast_bubble_arrow_right.png)',
},
};
const patchT = 24;
const patchL = 14;
const TOOLTIP_MIN_LENGTH = 132;
const TOOLTIP_MAX_LENGTH = 902;
export default class Tooltip extends Component {
constructor(props) {
super(props);
this.balloonTextFont = MAIN_TEXT_FONT;
this.balloonTextSize = TextItemFamily.TITLE2_TEXT_SIZE;
this.bodyGap = TextItemFamily.BODY_TEXT_GAP;
}
componentWillMount() {
}
componentWillReceiveProps(nextProps) {
}
shouldComponentUpdate(nextProps, nextState) { // return true -->render()
return (JSON.stringify(nextProps) !== JSON.stringify(this.props));
}
componentDidUpdate(prevProps, prevState) {
}
componentWillUnmount() {
}
process() {
const { OSD, showFlag, tailDirection, tailPostion, highContrast, enlarge, tailW, tailH } = this.props;
const BalloonStyle = {};
BalloonStyle.position = 'relative';
BalloonStyle.left = OSD.layout.l;
BalloonStyle.top = OSD.layout.t;
BalloonStyle.height = OSD.layout.h;
if (OSD.layout.w < TOOLTIP_MIN_LENGTH) { // TOOLTIP_MIN_LENGTH is min width
BalloonStyle.width = TOOLTIP_MIN_LENGTH;
} else if (OSD.layout.w > TOOLTIP_MAX_LENGTH) { // TOOLTIP_MAX_LENGTH is max width
BalloonStyle.width = TOOLTIP_MAX_LENGTH;
} else {
BalloonStyle.width = OSD.layout.w;
}
if (showFlag) {
BalloonStyle.animationName = 'Appear';
BalloonStyle.animationFillMode = 'forwards';
BalloonStyle.animationDuration = '1.10s';
BalloonStyle.animationTimingFunction = AnimationEffect.Elastic;
} else {
BalloonStyle.animationName = 'Disappear';
BalloonStyle.animationFillMode = 'forwards';
BalloonStyle.animationDuration = '0.85s';
BalloonStyle.animationTimingFunction = AnimationEffect.Out;
}
// calculate tail position
const ArrowStyle = {};
ArrowStyle.position = 'absolute';
ArrowStyle.width = tailW;
ArrowStyle.height = tailH;
if (tailPostion === 'center') {
if (tailDirection === 'top') {
ArrowStyle.left = (BalloonStyle.width - this.props.tailW) / 2;
ArrowStyle.top = 0;
} else if (tailDirection === 'bottom') {
ArrowStyle.left = (BalloonStyle.width - this.props.tailW) / 2;
ArrowStyle.top = BalloonStyle.height - patchT;
} else if (tailDirection === 'left') {
ArrowStyle.left = -this.props.tailW + patchL;
ArrowStyle.top = (BalloonStyle.height - this.props.tailH) / 2;
} else if (tailDirection === 'right') {
ArrowStyle.left = BalloonStyle.width - patchL;
ArrowStyle.top = (BalloonStyle.height - this.props.tailH) / 2;
}
} else if (tailPostion === 'start') {
ArrowStyle.left = this.props.tailOffset;
if (tailDirection === 'top') {
ArrowStyle.top = 0;
} else if (tailDirection === 'bottom') {
ArrowStyle.top = BalloonStyle.height - patchT;
} else {
ArrowStyle.top = 0;
}
} else if (tailPostion === 'end') {
ArrowStyle.left = BalloonStyle.width - this.props.tailOffset - this.props.tailW;
if (tailDirection === 'top') {
ArrowStyle.top = 0;
} else if (tailDirection === 'bottom') {
ArrowStyle.top = BalloonStyle.height - patchT;
} else {
ArrowStyle.top = 0;
}
}
if (highContrast) {
ArrowStyle.backgroundImage = tailResource.highContrast[tailDirection];
} else {
ArrowStyle.backgroundImage = tailResource.normal[tailDirection];
}
const TextBGStyle = {};
TextBGStyle.position = 'absolute';
TextBGStyle.height = OSD.layout.h;
TextBGStyle.width = OSD.layout.w;
TextBGStyle.left = 0;
TextBGStyle.borderStyle = 'solid';
TextBGStyle.borderWidth = '24px 14px';
TextBGStyle.borderImage = highContrast ? tailResource.highContrast.bg : tailResource.normal.bg;
if (tailDirection === 'top') {
TextBGStyle.top = this.props.tailH - patchT;
} else if (tailDirection === 'bottom') {
TextBGStyle.top = 0;
} else {
TextBGStyle.top = 0;
}
// icon compotent
let iconComponentList = null;
if (typeof OSD.icon !== 'undefined') {
iconComponentList = (<Image key={'icon'} OSD={OSD.icon} />);
}
// text compotent
const textComponentList = [];
const TextStyle = {};
if (typeof OSD.icon !== 'undefined') {
TextStyle.left = 14 + OSD.icon.w + 6;
TextStyle.width = BalloonStyle.width - 25 - 28 - 6 - OSD.icon.w;
} else {
TextStyle.left = 11;
TextStyle.width = BalloonStyle.width - 50;
}
const len = OSD.text.length; // OSD.text marked required
if (len === 1) {
TextStyle.height = TextItemFamily.TITLE2_TEXT_HEIGHT;
TextStyle.lineHeight = TextItemFamily.TITLE2_TEXT_HEIGHT;
} else {
TextStyle.height = TextItemFamily.TITLE_TEXT_HEIGHT;
TextStyle.lineHeight = TextItemFamily.TITLE_TEXT_HEIGHT;
}
const aligntext = (len === 1 && typeof OSD.icon === 'undefined') ? 'center' : 'left';
for (let idx = 0; idx < len; idx++) {
TextStyle.top = ((OSD.layout.h - (2 * patchT) - (len * TextStyle.height)) / 2) + (idx * TextStyle.height);
// console.log(`TextStyle.top: ${TextStyle.top} idx: ${idx}`);
textComponentList.push(
<ScrollText
key={`text${idx}`}
scroll={len === 1}
fontSize={enlarge ? (this.balloonTextSize * 1.2) : this.balloonTextSize}
fontFamily={this.balloonTextFont}
textGap={this.bodyGap}
width={TextStyle.width}
height={TextStyle.height}
top={TextStyle.top}
left={TextStyle.left}
lineHeight={`${TextStyle.lineHeight}px`}
textAlign={aligntext}
>
{OSD.text[idx]}
</ScrollText>);
}
return (
<div style={BalloonStyle}>
<div style={ArrowStyle} />
<div style={TextBGStyle}>
{textComponentList}
{iconComponentList}
</div>
</div>
);
}
render() {
return this.process();
}
}
Tooltip.defaultProps = {
showFlag: true,
tailW: 42,
tailH: 30,
tailOffset: 22,
highContrast: false,
enlarge: false,
OSD: {
layout: {
l: 0,
t: 0,
w: 414,
h: 116,
},
icon: null,
},
};
Tooltip.propTypes = {
showFlag: PropTypes.bool,
tailDirection: PropTypes.oneOf(['top', 'bottom', 'left', 'right']).isRequired, // tailDirection:top/bottom/left/right
tailPostion: PropTypes.oneOf(['start', 'center', 'end']).isRequired, // tailPostion: start/center/end
tailW: PropTypes.number, // tail width
tailH: PropTypes.number, // tail height
tailOffset: PropTypes.number, // The tail's offset distance relative to popup balloon's edge.
highContrast: PropTypes.bool,
enlarge: PropTypes.bool,
OSD: PropTypes.shape({ // UI content
layout: PropTypes.shape({
l: PropTypes.number, // tooltip left value
t: PropTypes.number, // tooltip top value
w: PropTypes.number, // tooltip width value
h: PropTypes.number, //tooltip height value
}),
icon: PropTypes.shape({
l: PropTypes.number,
t: PropTypes.number,
w: PropTypes.number,
h: PropTypes.number,
url: PropTypes.string,
}),
text: PropTypes.array.isRequired,
}),
};