import * as React from 'react';
import { NavLink } from 'react-router-dom';
import { parseHash } from '../util/url';
/**
 * A horizontal bar that displays tab titles, which the user can click to switch to the tab.
 *
 * @template ID The type that includes all possible tab IDs (typically a union of string constants).
 * @template T The type that describes a tab.
 */
class TabBar extends React.PureComponent {
    render() {
        return (React.createElement("div", { className: `tab-bar ${this.props.tabs.length === 0 ? 'tab-bar--empty' : ''}` },
            this.props.tabs
                .filter(({ hidden }) => !hidden)
                .map((tab, i) => (React.createElement(this.props.tabComponent, { key: tab.id, tab: tab, className: `btn btn-link btn-sm tab-bar__tab ${!this.props.endFragment &&
                    'tab-bar__tab--flex-grow'} tab-bar__tab--${this.props.activeTab !== undefined && this.props.activeTab === tab.id
                    ? 'active'
                    : 'inactive'} ${this.props.tabClassName || ''}` }))),
            this.props.endFragment));
    }
}
/**
 * An element to pass to Tab's tabBarEndFragment prop to fill all width between the tabs (on the left) and the
 * other tabBarEndFragment elements (on the right).
 */
export const Spacer = () => React.createElement("span", { className: "tab-bar__spacer" });
/**
 * The class name to use for other elements injected via tabBarEndFragment that should have a bottom border.
 */
export const TabBorderClassName = 'tab-bar__end-fragment-other-element';
/**
 * A tabbed UI component, with a tab bar for switching between tabs and a content view that renders the active
 * tab's contents.
 *
 * Callers should use one of the TabsWithXyzViewStatePersistence components to handle view state persistence.
 */
class Tabs extends React.PureComponent {
    render() {
        let children;
        if (Array.isArray(this.props.children)) {
            children = this.props.children;
        }
        else if (this.props.children) {
            children = [this.props.children];
        }
        return (React.createElement("div", { id: this.props.id, className: `tabs ${this.props.className || ''}` },
            React.createElement(TabBar, { tabs: this.props.tabs, activeTab: this.props.activeTab, endFragment: this.props.tabBarEndFragment, tabClassName: this.props.tabClassName, tabComponent: this.props.tabComponent }),
            children && children.find(c => c && c.key === this.props.activeTab)));
    }
}
/**
 * A wrapper for Tabs that persists view state (the currently active tab) in localStorage.
 */
export class TabsWithLocalStorageViewStatePersistence extends React.PureComponent {
    constructor(props) {
        super(props);
        this.onSelectTab = (tab) => {
            if (this.props.onSelectTab) {
                this.props.onSelectTab(tab);
            }
            this.setState({ activeTab: tab }, () => TabsWithLocalStorageViewStatePersistence.saveToLocalStorage(this.props.storageKey, tab));
        };
        this.renderTab = ({ tab, className }) => (React.createElement("button", { type: "button", className: className, 
            // tslint:disable-next-line:jsx-no-lambda
            onClick: () => this.onSelectTab(tab.id) }, tab.label));
        this.state = {
            activeTab: TabsWithLocalStorageViewStatePersistence.readFromLocalStorage(this.props.storageKey, this.props.tabs),
        };
    }
    static readFromLocalStorage(storageKey, tabs) {
        const lastTabID = localStorage.getItem(storageKey);
        if (lastTabID !== null && tabs.find(tab => tab.id === lastTabID)) {
            return lastTabID;
        }
        if (tabs.length === 0) {
            return undefined;
        }
        return tabs[0].id; // default
    }
    static saveToLocalStorage(storageKey, lastTabID) {
        localStorage.setItem(storageKey, lastTabID);
    }
    render() {
        return (React.createElement(Tabs, Object.assign({}, this.props, { onSelectTab: this.onSelectTab, activeTab: this.state.activeTab, tabComponent: this.renderTab })));
    }
}
/**
 * A wrapper for Tabs that persists view state (the currently active tab) in the current page's URL.
 *
 * URL whose fragment (hash) ends with "$x" are considered to have active tab "x" (where "x" is the tab's ID).
 */
export class TabsWithURLViewStatePersistence extends React.PureComponent {
    constructor(props) {
        super(props);
        this.renderTab = ({ tab, className }) => (React.createElement(NavLink, { className: className, to: TabsWithURLViewStatePersistence.urlForTabID(this.props.location, tab.id), 
            // tslint:disable-next-line:jsx-no-lambda
            onClick: () => {
                if (this.props.onSelectTab) {
                    this.props.onSelectTab(tab.id);
                }
            } }, tab.label));
        this.state = {
            activeTab: this.readFromURL(props.location, props.tabs),
        };
    }
    /**
     * Returns the URL hash (which can be used as a relative URL) that specifies the given tab. If the URL hash
     * already contains a tab ID, it replaces it; otherwise it appends it to the current URL fragment. If the tabID
     * argument is null, then the tab ID is removed from the URL.
     */
    static urlForTabID(location, tabID) {
        const hash = new URLSearchParams(location.hash.slice('#'.length));
        if (tabID) {
            hash.set('tab', tabID);
        }
        else {
            hash.delete('tab');
        }
        return Object.assign({}, location, { hash: hash.toString().replace(/%3A/g, ':') });
    }
    readFromURL(location, tabs) {
        const urlTabID = parseHash(location.hash).viewState;
        if (urlTabID) {
            for (const tab of tabs) {
                if (tab.id === urlTabID) {
                    return tab.id;
                }
            }
        }
        if (tabs.length === 0) {
            return undefined;
        }
        return tabs[0].id; // default
    }
    componentWillReceiveProps(nextProps) {
        if (nextProps.location !== this.props.location || nextProps.tabs !== this.props.tabs) {
            this.setState({ activeTab: this.readFromURL(nextProps.location, nextProps.tabs) });
        }
    }
    render() {
        return React.createElement(Tabs, Object.assign({}, this.props, { activeTab: this.state.activeTab, tabComponent: this.renderTab }));
    }
}
//# sourceMappingURL=Tabs.js.map