import * as classNames from "classnames"; import * as _ from "lodash"; import * as React from "react"; import { CSSTransition } from "react-transition-group"; import { Accordion } from "../Accordion"; import { Gallery } from "../Gallery"; import { Image, IImageProps } from "../Image"; import { Loading, LoadingType } from "../Loading"; export interface IImageLoadTrackerProps { mount: boolean; type: ImageLoadTrackerType; title: string; subtitle?: string; /** * For the "simple" and "preview" ImageLoadTrackerTypes, we show * some number of images. For detailed this uses a and for * preview it's just a single image. */ images?: IImageProps[]; /** * These 4 methods can be used to tap into the underlying * detail view */ onDetailOpen?: () => void; onDetailClose?: () => void; onDetailOpened?: () => void; onDetailClosed?: () => void; /** * This method is very incomplete. Currently, `onResize` is fired * when the gallery in the `Detailed` version goes from 2 rows to 1 */ onResize?: () => void; onEnter?: () => void; onExit?: () => void; onExited?: () => void; } export enum ImageLoadTrackerType { /** * A "simple" tracker type display a clean grey box with a spinner * and a provided title */ Simple = "Simple", Preview = "Preview", Detailed = "Detailed", } interface IImageLoadTrackerState { /** * We keep track of the mount in state * such that we can delay updating */ mount: boolean; } const defaultImageLoadTracker: IImageLoadTrackerState = { mount: null, } const UPDATE_MOUNT_THRESHOLD = 300; export class ImageLoadTracker extends React.Component { public state: IImageLoadTrackerState = defaultImageLoadTracker; private timer: any; public componentDidMount() { if (this.props.mount) { this.setState({ mount: true, }); } } public shouldComponentUpdate(nextProps: IImageLoadTrackerProps, nextState: IImageLoadTrackerState) { if (this.props.title !== nextProps.title) return true; if (this.props.subtitle !== nextProps.subtitle) return true; if (!_.isEqual(this.props.images, nextProps.images)) return true; if (this.props.mount !== nextProps.mount) return true; if (this.props.type !== nextProps.type) return true; if (this.state.mount !== nextState.mount) return true; return false; } public componentDidUpdate(prevProps: IImageLoadTrackerProps) { if (prevProps.mount !== this.props.mount) { this.handleChangeMountProps(this.props.mount); } } public render() { return (
{(this.props.type == ImageLoadTrackerType.Simple || this.props.type === ImageLoadTrackerType.Preview ) && (
{this.props.title}
{this.props.subtitle && (
{this.props.subtitle}
)}
)} {this.props.images && ( (this.props.type === ImageLoadTrackerType.Preview && (
)) || (this.props.type === ImageLoadTrackerType.Detailed && ( { return (
{this.props.title}
); }} renderSibling={() => { return (
{ // @ts-ignore const { sizes, ...imageWithoutSizes } = image || {}; return ( 0 && { renderOverlayContent: () => { return
+{remainder}
} }} {...image && { sizes: [_.first(image.sizes)] }} {...imageWithoutSizes } /> ); }} />
); }} renderContent={() => { return (
{ // @ts-ignore const { sizes, ...imageWithoutSizes } = image || {}; return ( 0 && { renderOverlayContent: () => { return
+{remainder}
} }} {...image && { sizes: [_.first(image.sizes)] }} {...imageWithoutSizes } /> ); }} />
); }} /> )) )}
); } private handleChangeMountProps(mount: boolean) { if (!_.isNil(this.timer)) { clearTimeout(this.timer); this.timer = null; } if (mount) { this.setState({ mount, }); } else { this.timer = setTimeout(() => { this.setState({ mount, }, () => { this.timer = null }); }, UPDATE_MOUNT_THRESHOLD); } } }