50c7308ee7
Closes #4207
97 lines
3.2 KiB
JavaScript
97 lines
3.2 KiB
JavaScript
// @flow
|
|
import React, { useState, useCallback } from 'react';
|
|
import * as ICONS from 'constants/icons';
|
|
import Button from 'component/button';
|
|
|
|
// the maximum length of history to show per button
|
|
const MAX_HISTORY_SIZE = 12;
|
|
|
|
type Props = {
|
|
isBackward: boolean,
|
|
history: {
|
|
entries: Array<{ key: string, title: string, pathname: string }>,
|
|
go: number => void,
|
|
goBack: () => void,
|
|
goForward: () => void,
|
|
index: number,
|
|
length: number,
|
|
location: { pathname: string },
|
|
push: string => void,
|
|
},
|
|
};
|
|
|
|
// determines which slice of entries should make up the back or forward button drop-downs (isBackward vs !isBackward respectively)
|
|
const sliceEntries = (currentIndex, entries, historyLength, isBackward, maxSize) => {
|
|
let l = isBackward ? 0 : currentIndex + 1;
|
|
let r = isBackward ? currentIndex : historyLength;
|
|
const exceedsMax = maxSize < r - l;
|
|
if (!exceedsMax) {
|
|
return entries.slice(l, r);
|
|
} else if (isBackward) {
|
|
l = r - maxSize;
|
|
} else {
|
|
r = l + maxSize;
|
|
}
|
|
return entries.slice(l, r);
|
|
};
|
|
|
|
const NavigationButton = (props: Props) => {
|
|
const { isBackward, history } = props;
|
|
const { entries, go } = history;
|
|
const currentIndex = history.index;
|
|
const historyLength = history.length;
|
|
const [showHistory, setShowHistory] = useState(false);
|
|
|
|
// creates an <li> intended for the button's <ul>
|
|
const makeItem = useCallback(
|
|
(entry: { pathname: string, title: string, key: string }, index: number) => {
|
|
// difference between the current index and the index of the entry
|
|
const backwardDif = index - (currentIndex < MAX_HISTORY_SIZE ? currentIndex : MAX_HISTORY_SIZE);
|
|
const forwardDif = index + 1;
|
|
return (
|
|
<li
|
|
className="header__navigation-button"
|
|
role="link"
|
|
key={entry.key}
|
|
onMouseDown={() => {
|
|
setShowHistory(false);
|
|
go(isBackward ? backwardDif : forwardDif);
|
|
}}
|
|
>
|
|
<span>{entry.title}</span>
|
|
<span className="header__navigation-button-help">{entry.pathname === '/' ? __('Home') : entry.pathname}</span>
|
|
</li>
|
|
);
|
|
},
|
|
[currentIndex, isBackward, go]
|
|
);
|
|
const slicedEntries = sliceEntries(currentIndex, entries, historyLength, isBackward, MAX_HISTORY_SIZE);
|
|
return (
|
|
<div
|
|
// @if TARGET='app'
|
|
onDoubleClick={e => {
|
|
e.stopPropagation();
|
|
}}
|
|
// @endif
|
|
>
|
|
<Button
|
|
className={`header__navigation-item header__navigation-item--${isBackward ? 'back' : 'forward'}`}
|
|
description={isBackward ? __('Navigate back') : __('Navigate forward')}
|
|
onBlur={() => setShowHistory(false)}
|
|
onClick={() => (isBackward ? history.goBack() : history.goForward())}
|
|
onContextMenu={e => {
|
|
setShowHistory(!showHistory);
|
|
// the following three lines prevent the regular context menu (right click menu) from appearing
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return false;
|
|
}}
|
|
icon={isBackward ? ICONS.ARROW_LEFT : ICONS.ARROW_RIGHT}
|
|
iconSize={18}
|
|
disabled={slicedEntries.length === 0}
|
|
/>
|
|
{showHistory && <ul className={'header__navigation-dropdown'}>{slicedEntries.map(makeItem)}</ul>}
|
|
</div>
|
|
);
|
|
};
|
|
export default NavigationButton;
|