import * as React from 'react'; import { Button, Component, Styles, Text, Types, UserInterface, View } from 'reactxp'; import { colors } from '../../config.json'; import styles from './AppButtonStyles'; import ImageView from './ImageView'; const ButtonContext = React.createContext({ textAdjustment: 0, textRef: React.createRef(), }); interface ILabelProps { children?: React.ReactText; } interface IPrivateLabelProps { textAdjustment: number; children?: React.ReactText; } class PrivateLabel extends Component { public render() { const { textAdjustment, children } = this.props; const textAdjustmentStyle = Styles.createViewStyle( { paddingRight: textAdjustment > 0 ? textAdjustment : 0, paddingLeft: textAdjustment < 0 ? Math.abs(textAdjustment) : 0, }, false, ); return ( {children} ); } } export class Label extends Component { public render() { return ( {(context) => ( {this.props.children} )} ); } } interface IIconProps { source: string; width?: number; height?: number; } export class Icon extends Component { public render() { return ( ); } } interface IProps { children?: React.ReactNode; style?: Types.ButtonStyleRuleSet; disabled?: boolean; onPress?: () => void; } interface IState { hovered: boolean; textAdjustment: number; } class BaseButton extends Component { public state: IState = { hovered: false, textAdjustment: 0, }; private containerRef = React.createRef(); private textViewRef = React.createRef(); public componentDidMount() { this.forceUpdateTextAdjustment(); } public render() { const { children, style, ...otherProps } = this.props; return ( ); } protected backgroundStyle = (): Types.ButtonStyleRuleSet => { throw new Error('Implement backgroundStyle in subclasses.'); }; protected onHoverStart = () => (!this.props.disabled ? this.setState({ hovered: true }) : null); protected onHoverEnd = () => (!this.props.disabled ? this.setState({ hovered: false }) : null); private async forceUpdateTextAdjustment() { const containerView = this.containerRef.current; if (containerView) { const containerLayout = await UserInterface.measureLayoutRelativeToAncestor( containerView, this, ); this.updateTextAdjustment(containerLayout); } } private async updateTextAdjustment(containerLayout: Types.LayoutInfo) { const labelView = this.textViewRef.current; if (labelView) { // calculate the title layout frame const labelLayout = await UserInterface.measureLayoutRelativeToAncestor(labelView, this); // calculate the remaining space at the right hand side const trailingSpace = containerLayout.width - (labelLayout.x + labelLayout.width); // calculate text adjustment const textAdjustment = labelLayout.x - trailingSpace; // re-render the view with the new text adjustment if it changed if (this.state.textAdjustment !== textAdjustment) { this.setState({ textAdjustment }); } } } private onLayout = async (containerLayout: Types.ViewOnLayoutEvent) => { this.updateTextAdjustment(containerLayout); }; } export class RedButton extends BaseButton { protected backgroundStyle = () => (this.state.hovered ? styles.redHover : styles.red); } export class GreenButton extends BaseButton { protected backgroundStyle = () => (this.state.hovered ? styles.greenHover : styles.green); } export class BlueButton extends BaseButton { protected backgroundStyle = () => (this.state.hovered ? styles.blueHover : styles.blue); } export class TransparentButton extends BaseButton { protected backgroundStyle = () => this.state.hovered ? styles.transparentHover : styles.transparent; } export class RedTransparentButton extends BaseButton { protected backgroundStyle = () => this.state.hovered ? styles.redTransparentHover : styles.redTransparent; }