Skip to content

Commit

Permalink
feat(controls): add new onPageSubmit to handle input submit
Browse files Browse the repository at this point in the history
  • Loading branch information
cweeii committed Nov 16, 2020
1 parent 002b0b8 commit d1ad31e
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 185 deletions.
2 changes: 1 addition & 1 deletion src/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ export function loadScripts(urls, disableAMD = false) {
* Function to decode key down events into keys
*
* @public
* @param {Event} event - Keydown event
* @param {KeyboardEvent<Element>} event - Keydown event
* @return {string} Decoded keydown key
*/
export function decodeKeydown(event) {
Expand Down
11 changes: 3 additions & 8 deletions src/lib/viewers/controls/page/PageControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import PageControlsForm from './PageControlsForm';
import './PageControls.scss';

export type Props = {
getViewer: () => HTMLElement;
onPageChange: (newPageNumber: number) => void;
onPageSubmit: (newPageNumber: number) => void;
pageCount: number;
pageNumber: number;
};

export default function PageControls({ getViewer, onPageChange, pageCount, pageNumber }: Props): JSX.Element {
export default function PageControls({ onPageChange, onPageSubmit, pageCount, pageNumber }: Props): JSX.Element {
return (
<div className="bp-PageControls">
<button
Expand All @@ -24,12 +24,7 @@ export default function PageControls({ getViewer, onPageChange, pageCount, pageN
>
<IconArrowUp24 />
</button>
<PageControlsForm
getViewer={getViewer}
onPageChange={onPageChange}
pageCount={pageCount}
pageNumber={pageNumber}
/>
<PageControlsForm onPageSubmit={onPageSubmit} pageCount={pageCount} pageNumber={pageNumber} />
<button
className="bp-PageControls-button"
data-testid="bp-PageControls-next"
Expand Down
1 change: 1 addition & 0 deletions src/lib/viewers/controls/page/PageControlsForm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
padding: 7px 5px;
color: $white;
font-size: 14px;
white-space: nowrap;
background-color: $fours;
border-radius: 3px;
}
Expand Down
98 changes: 57 additions & 41 deletions src/lib/viewers/controls/page/PageControlsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,91 @@
import React from 'react';
import Browser from '../../../Browser';
import { BROWSERS } from '../../../constants';
import { decodeKeydown } from '../../../util';
import './PageControlsForm.scss';

export type Props = {
getViewer: () => HTMLElement;
onPageChange: (newPageNumber: number) => void;
onPageSubmit: (newPageNumber: number) => void;
pageNumber: number;
pageCount: number;
};

export default function PageControlsForm({ getViewer, onPageChange, pageNumber, pageCount }: Props): JSX.Element {
export const ENTER = 'Enter';
export const ESCAPE = 'Escape';

export default function PageControlsForm({ onPageSubmit, pageNumber, pageCount }: Props): JSX.Element {
const [isInputShown, setIsInputShown] = React.useState(false);
const [pageInputValue, setPageInputValue] = React.useState(pageNumber.toString());
const [inputValue, setInputValue] = React.useState(pageNumber.toString());
const [isButtonFocus, setIsButtonFocus] = React.useState(false);
const buttonElRef = React.useRef<HTMLButtonElement>(null);
const inputElRef = React.useRef<HTMLInputElement>(null);
const viewer = getViewer();

React.useEffect(() => {
if (inputElRef && inputElRef.current) {
setPageInputValue(pageNumber.toString());
inputElRef.current.focus();
const setPage = (allowRetry = false): void => {
const newPageNumber = parseInt(inputValue, 10);

if (
!Number.isNaN(newPageNumber) &&
newPageNumber >= 1 &&
newPageNumber <= pageCount &&
newPageNumber !== pageNumber
) {
onPageSubmit(newPageNumber);
} else {
setInputValue(pageNumber.toString()); // Reset the invalid input value to the current page

if (allowRetry) {
setIsButtonFocus(true);
}
}
}, [isInputShown, pageNumber]);

setIsInputShown(false);
};

const handleNumInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
setPageInputValue(event.target.value);
setInputValue(event.target.value);
};

const handleNumInputBlur = (): void => {
const newPageNumber = parseInt(pageInputValue, 10);

if (!Number.isNaN(newPageNumber)) {
onPageChange(newPageNumber);
}

setIsInputShown(false);
setPage();
};

const handleNumInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
const key = decodeKeydown((event as unknown) as Event);
const key = decodeKeydown(event);

switch (key) {
case 'Enter':
case 'Tab':
viewer.focus();
// The keycode of the 'next' key on Android Chrome is 9, which maps to 'Tab'.
// We normally trigger the blur handler by blurring the input
// field, but this doesn't work for IE in fullscreen. For IE,
// we blur the page behind the controls - this unfortunately
// is an IE-only solution that doesn't work with other browsers

if (Browser.getName() !== BROWSERS.INTERNET_EXPLORER) {
(event.target as HTMLInputElement).blur();
}

case ENTER:
event.stopPropagation();
event.preventDefault();
break;

case 'Escape':
setIsInputShown(false);
viewer.focus();

setPage(true);
break;
case ESCAPE:
event.stopPropagation();
event.preventDefault();

setIsInputShown(false);
setIsButtonFocus(true);
break;
default:
break;
}
};

React.useEffect(() => {
setInputValue(pageNumber.toString()); // Keep internal state in sync with prop as it changes
}, [pageNumber]);

React.useLayoutEffect(() => {
if (buttonElRef.current && isButtonFocus) {
buttonElRef.current.focus();
setIsButtonFocus(false);
}
}, [isButtonFocus]);

React.useLayoutEffect(() => {
if (inputElRef.current && isInputShown) {
inputElRef.current.select();
}
}, [isInputShown]);

return (
<div className="bp-PageControlsForm">
{isInputShown ? (
Expand All @@ -87,10 +102,11 @@ export default function PageControlsForm({ getViewer, onPageChange, pageNumber,
size={3}
title={__('enter_page_num')}
type="number"
value={pageInputValue}
value={inputValue}
/>
) : (
<button
ref={buttonElRef}
className="bp-PageControlsForm-button"
data-testid="bp-PageControlsForm-button"
onClick={(): void => setIsInputShown(true)}
Expand All @@ -99,7 +115,7 @@ export default function PageControlsForm({ getViewer, onPageChange, pageNumber,
>
<span
className="bp-PageControlsForm-button-label"
data-testid="bp-PageControlsForm-button-span"
data-testid="bp-PageControlsForm-button-label"
>{`${pageNumber} / ${pageCount}`}</span>
</button>
)}
Expand Down
10 changes: 1 addition & 9 deletions src/lib/viewers/controls/page/__tests__/PageControls-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,7 @@ import PageControlsForm from '../PageControlsForm';

describe('PageControls', () => {
const getWrapper = (props = {}): ShallowWrapper =>
shallow(
<PageControls
getViewer={(): HTMLElement => document.createElement('div')}
onPageChange={noop}
pageCount={3}
pageNumber={1}
{...props}
/>,
);
shallow(<PageControls onPageChange={noop} onPageSubmit={noop} pageCount={3} pageNumber={1} {...props} />);
const getPreviousPageButton = (wrapper: ShallowWrapper): ShallowWrapper =>
wrapper.find('[data-testid="bp-PageControls-previous"]');
const getNextPageButton = (wrapper: ShallowWrapper): ShallowWrapper =>
Expand Down
Loading

0 comments on commit d1ad31e

Please sign in to comment.