import * as React from 'react'; import { ActionLink, distance, Flyout, Icon, styled, themed, Tooltip, StandardProps, AnchorProps } from 'precise-ui'; import { PageViewMode } from '../types/Page'; import { toCamel } from '../utils/hacks'; const Toolbar = styled.ul` background-color: ${themed(({ theme = {} }: StandardProps) => theme.ui5)}; color: ${themed(({ theme = {} }: StandardProps) => theme.text4)}; padding: 0 ${distance.medium}; display: flex; flex-direction: row; list-style: none; margin: 0; border-radius: 2px; align-items: center; position: relative; `; const ToolbarWrapper = styled.div` position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: center; `; const ToolbarItem = styled.li` display: list-item; padding: ${distance.medium} ${distance.xxsmall}; height: 25px; display: flex; align-items: center; & div { display: flex; } `; const ToolbarSeparator = styled.li` margin: ${distance.small} ${distance.medium}; width: 1px; overflow: hidden; background-color: ${themed(({ theme = {} }: StandardProps) => theme.ui4)}; height: 25px; `; const ToolbarTextField = styled.input` border: 0; padding: 0; height: 21px; width: 3em; `; const ToolbarDropdownListItem = styled.div` padding: ${distance.small} ${distance.medium}; background-color: ${themed(({ theme = {} }: StandardProps) => theme.ui5)}; white-space: nowrap; `; const ToolbarTooltip = styled(Tooltip)` font-size: 0.8em; white-space: nowrap; `; const ToolbarActionLink = styled(ActionLink)` color: ${themed(({ theme = {}, disabled }: StandardProps & AnchorProps) => (disabled ? theme.text3 : theme.text4))}; display: flex; align-items: center; height: 16px; :hover, :visited, :focus { color: ${themed(({ theme = {}, disabled }: StandardProps & AnchorProps) => (disabled ? theme.text3 : theme.text4))}; } `; const defaultLabels = { exitFullscreen: 'Exit Fullscreen', enterFullscreen: 'Enter Fullscreen', viewModeFitToHeight: 'Fit to Height', viewModeFitToWidth: 'Fit to Width', nextPage: 'Next', prevPage: 'Previous', zoomIn: 'Zoom In', zoomOut: 'Zoom Out', pagesOf: (current, total) => `Page ${current} of ${total}`, page: 'Page', }; export type ToolbarLabelProps = { exitFullscreen?: string; enterFullscreen?: string; viewModeFitToWidth?: string; viewModeFitToHeight?: string; viewModeDefault?: string; nextPage?: string; prevPage?: string; zoomIn?: string; zoomOut?: string; /** * Function that receives the current and total pages and returns a string with translations for number of pages * Example: 'Page 5 of 9' where 5 is the current page and 9 is the total. * * @param currentPage * @param totalPages */ pagesOf?(currentPage: number, totalPages: number): string; /** * Used as a prefix when editing the current page. * Example: 'Page ____.' * */ page?: string; }; export interface PDFViewerToolbarProps { currentPage: number; currentViewMode: PageViewMode; numPages: number; currentScale: number; fullscreen: boolean; onPageChange(pageNum: number): void; onScaleChange(pageNum: number): void; onViewModeChange(viewMode: PageViewMode): void; onFullscreenChange(): void; labels?: ToolbarLabelProps; } /** * The `Document` is a wrapper to load PDFs and render all the pages */ export const PDFViewerToolbar: React.FC = props => { const { labels = defaultLabels, fullscreen, onFullscreenChange, currentPage, currentScale } = props; const pageInputRef = React.useRef(); const [editingPageNumber, SetEditingPageNumber] = React.useState(); const [editingViewMode, SetEditingViewMode] = React.useState(false); /** * Returns the next view mode text to be used as tooltip */ function getViewModeText() { return labels[`viewMode${toCamel(PageViewMode[props.currentViewMode >= 3 ? 0 : props.currentViewMode])}`]; } /** * Returns the next view mode text to be used as tooltip */ function getViewModeIcon() { switch (props.currentViewMode) { case PageViewMode.FIT_TO_WIDTH: return 'FitToWidth'; case PageViewMode.FIT_TO_HEIGHT: return 'FitToHeight'; case PageViewMode.DEFAULT: return 'Page'; } } /** * Event triggered when the page number is clicked, thus entering page enter mode */ function onPageNumberFocused() { SetEditingPageNumber(true); } React.useEffect(() => { if (pageInputRef.current) { pageInputRef.current.focus(); } }, [pageInputRef, editingPageNumber]); /** * Event triggered when the page number field is blurred / changed */ function onPageNumberDefocused() { SetEditingPageNumber(false); // Now let's check the value if (pageInputRef.current && pageInputRef.current.value !== '') { const inputPage = Number(pageInputRef.current.value); if (!isNaN(inputPage)) { props.onPageChange(inputPage); } } } function onViewModeChange(viewMode: PageViewMode) { SetEditingViewMode(false); props.onViewModeChange(viewMode); } return ( props.onPageChange(currentPage - 1)} disabled={currentPage <= 1}> {editingPageNumber ? ( <> {labels.page}   e.key === 'Enter' && onPageNumberDefocused()} /> ) : ( {labels.pagesOf(currentPage, props.numPages)} )} props.onPageChange(currentPage + 1)} disabled={currentPage >= props.numPages}> { const scaleToPrev = Math.round((currentScale % 0.1) * 100) / 100; props.onScaleChange(currentScale - (scaleToPrev === 0 ? 0.1 : scaleToPrev)); }} disabled={currentScale <= 0.5}> {Math.round(currentScale * 100)}% { const scaleToPrev = Math.round((currentScale % 0.1) * 100) / 100; props.onScaleChange(currentScale + 0.1 - (scaleToPrev === 0.1 ? 0 : scaleToPrev)); }} disabled={currentScale >= 2.5}> theme.ui5) } }} content={ <> onViewModeChange(PageViewMode.FIT_TO_WIDTH)}> {labels.viewModeFitToWidth} onViewModeChange(PageViewMode.FIT_TO_HEIGHT)}> {labels.viewModeFitToHeight} }> SetEditingViewMode(!editingViewMode)}> {getViewModeText()} ); };