import { Button, Classes, Dialog } from '@blueprintjs/core'; import * as React from 'react'; import { positionForRect } from '../../utils/position-for-rect'; export interface TourScriptStep { name: string; selector: string; title: string; content: JSX.Element; getButtons?: (handlers: TourStepGetButtonParams) => Array; } interface TourProps { tour: Set; onStop: () => void; } interface TourState { tour: IterableIterator>; step: TourScriptStep | null; i: number; } export interface TourStepGetButtonParams { stop: () => void; advance: () => void; } export class Tour extends React.Component { private resizeHandle = 0; constructor(props: TourProps) { super(props); this.advance = this.advance.bind(this); this.stop = this.stop.bind(this); this.onResize = this.onResize.bind(this); this.state = { tour: props.tour.entries(), step: null, i: 0, }; } /** * Handles a resize of the window. */ public onResize() { if (!this.resizeHandle) { this.resizeHandle = window.setTimeout(() => { this.forceUpdate(); this.resizeHandle = 0; }, 100); } } /** * Component was mounted: Sign up for the window's "resize" * event and move to the first step of the tour. */ public componentDidMount() { this.advance(); window.addEventListener('resize', this.onResize); } public componentWillUnmount() { window.removeEventListener('resize', this.onResize); } /** * Moves the tour to the next step */ public advance() { const { done, value } = this.state.tour.next(); const step = done ? null : value[0]; this.setState({ step, i: this.state.i + 1 }); } /** * Stops the tour */ public stop() { this.props.onStop(); } public render() { const { step } = this.state; if (!step) return null; return
{this.getStep(step)}
; } /** * Return buttons for the dialog for the current step * of the tour. By default, we just return a continue/stop * combo * * @param {TourScriptStep} { getButtons } * @returns {Array} */ private getButtons({ getButtons }: TourScriptStep): Array { // Did the step bring its own buttons? if (getButtons) { return getButtons({ stop: this.stop, advance: this.advance, }); } // No? Fine! Are we at the end of the tour? return this.props.tour.size === this.state.i ? [