/** * See `@tdb/ui.test` for UI stories. * See: * https://github.com/xyc/react-inspector */ import { React, ReactDOM, css, GlamorValue } from '../common'; export interface IMeasureSizeStyle { width?: number; fontFamily?: string; fontSize?: string | number; fontWeight?: string | number; fontStyle?: string; lineHeight?: string | number; letterSpacing?: string | number; } export interface IMeasureSizeProps extends IMeasureSizeStyle { content?: React.ReactNode; style?: GlamorValue; } const HIDDEN = { position: 'absolute', left: -999999, top: -999999, }; /** * API for invisibly measuring text. */ class Measurer { public static create = (props: IMeasureSizeStyle) => { return { props, size: (content: React.ReactNode) => Measurer.measure({ ...props, content }), }; }; public static measure(props: IMeasureSizeProps) { const instance = new Measurer(props); const size = instance.size; instance.dispose(); return size; } public props: IMeasureSizeProps; private div: HTMLDivElement; private component: MeasureSize; public constructor(props: IMeasureSizeProps) { this.props = props; this.div = document.createElement('DIV') as HTMLDivElement; document.body.appendChild(this.div); const ref = (el: MeasureSize) => (this.component = el); ReactDOM.render( , this.div, ); } public dispose() { if (!this.isDisposed) { ReactDOM.unmountComponentAtNode(this.div); document.body.removeChild(this.div); } } public get isDisposed() { return !Boolean(this.component); } public get width() { return this.component ? this.component.width : -1; } public get height() { return this.component ? this.component.height : -1; } public get size() { const width = this.width; const height = this.height; return { width, height }; } } /** * Measures the length of the content accounting for font size and style. */ export class MeasureSize extends React.PureComponent { public static create = (props: IMeasureSizeStyle) => { return Measurer.create(props); }; public static measure(props: IMeasureSizeProps) { return Measurer.measure(props); } private el: HTMLDivElement; public componentDidMount() { const el = ReactDOM.findDOMNode(this as any) as HTMLElement; this.el = el.firstChild as HTMLDivElement; } public get width() { return this.el ? this.el.offsetWidth : -1; } public get height() { return this.el ? this.el.offsetHeight : -1; } public get size() { const width = this.width; const height = this.height; return { width, height }; } public render() { const { content, fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, width, } = this.props; const styles = { text: css({ display: 'inline-block', fontFamily, fontSize, fontWeight, fontStyle, lineHeight, letterSpacing, width, }), }; return (
{content}
); } }