Skip to content

Commit aad46fe

Browse files
committed
add tooltips
1 parent d8736c8 commit aad46fe

File tree

13 files changed

+236
-104
lines changed

13 files changed

+236
-104
lines changed

src/PdfReader/ScrollPage.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type ScrollPageProps = {
1212
onLoadSuccess: (page: PageProps) => void;
1313
placeholderHeight: number;
1414
placeholderWidth: number;
15+
allowInView?: boolean;
1516
onInView?: (pageNumber: number, ratio: number) => void;
1617
fitMode: FitMode;
1718
};
@@ -40,28 +41,27 @@ const ScrollPage: FC<ScrollPageProps> = ({
4041
onLoadSuccess,
4142
placeholderHeight,
4243
placeholderWidth,
44+
allowInView,
4345
onInView,
4446
fitMode,
4547
}) => {
4648
const { ref, inView, entry } = useInView({
4749
threshold: Array.from({ length: 11 }, (_, i) => i * 0.1),
4850
triggerOnce: false,
4951
});
50-
const [hasLoaded, setHasLoaded] = React.useState(false);
5152

5253
const handleLoadSuccess = React.useCallback(
5354
(page: PageProps) => {
54-
setHasLoaded(true);
5555
onLoadSuccess(page);
5656
},
5757
[onLoadSuccess]
5858
);
5959

6060
React.useEffect(() => {
61-
if (onInView && entry && hasLoaded) {
61+
if (onInView && entry && allowInView) {
6262
onInView(pageNumber, entry.intersectionRatio || 0);
6363
}
64-
}, [entry, onInView, pageNumber, hasLoaded]);
64+
}, [allowInView, entry, onInView, pageNumber]);
6565

6666
return (
6767
<div ref={ref}>

src/PdfReader/index.tsx

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import 'react-pdf/dist/Page/TextLayer.css';
1111
import {
1212
DEFAULT_HEIGHT,
1313
DEFAULT_SHOULD_GROW_WHEN_SCROLLING,
14-
FOOTER_HEIGHT,
15-
HEADER_HEIGHT,
1614
MAIN_CONTENT_ID,
1715
} from '../constants';
1816
import LoadingSkeleton from '../ui/LoadingSkeleton';
@@ -69,6 +67,7 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
6967
const isFetching = !state.resource;
7068
const isParsed = typeof state.numPages === 'number';
7169
const [containerRef, containerSize] = useMeasure<HTMLDivElement>();
70+
const [pageHeight, setPageHeight] = React.useState<number>(0);
7271

7372
// dispatch action when arguments change
7473
React.useEffect(() => {
@@ -154,6 +153,24 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
154153
resizePage(containerSize, state.fitMode);
155154
}, [containerSize, resizePage, state.fitMode]);
156155

156+
const setInitialPageHeight = React.useCallback(() => {
157+
if (
158+
pageHeight === 0 &&
159+
state.pdfWidth &&
160+
state.pdfHeight &&
161+
containerSize.width
162+
) {
163+
const margin = 16;
164+
const aspectRatio = state.pdfHeight / state.pdfWidth;
165+
const initialPageHeight = (containerSize.width - margin) * aspectRatio;
166+
setPageHeight(initialPageHeight);
167+
}
168+
}, [pageHeight, state.pdfWidth, state.pdfHeight, containerSize.width]);
169+
170+
React.useEffect(() => {
171+
setInitialPageHeight();
172+
}, [setInitialPageHeight]);
173+
157174
/**
158175
* Update the atStart/atEnd state to tell the UI whether to show the prev/next buttons
159176
* Whether to have the next/prev buttons enabled. We disable them:
@@ -252,7 +269,7 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
252269
const intersectionRatios = React.useRef<{ [page: number]: number }>({});
253270
const lastMostVisiblePage = React.useRef<number>(state.pageNumber);
254271

255-
const handlePageInView = React.useCallback(
272+
const onInView = React.useCallback(
256273
(pageNum: number, ratio: number) => {
257274
if (!state.settings?.isScrolling) return;
258275
intersectionRatios.current[pageNum] = ratio;
@@ -363,9 +380,6 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
363380
}
364381
}
365382

366-
const shouldGrow = state.settings?.isScrolling && growWhenScrolling;
367-
const finalHeight = shouldGrow ? 'initial' : height;
368-
369383
// the reader is active but loading a page
370384
return {
371385
type: 'PDF',
@@ -380,18 +394,15 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
380394
tabIndex={-1}
381395
id={MAIN_CONTENT_ID}
382396
ref={containerRef}
383-
height={finalHeight}
397+
height={pageHeight}
398+
sx={{
399+
'.react-pdf__Document': {
400+
height: `${pageHeight}px`,
401+
overflowX: 'hidden',
402+
overflowY: 'auto',
403+
},
404+
}}
384405
>
385-
{/* FIXME: POC, update this with more a react proach. chakra.factory throws memory leak error.*/}
386-
<style>
387-
{`
388-
.react-pdf__Document {
389-
height: calc(100vh - ${HEADER_HEIGHT + FOOTER_HEIGHT}px);
390-
overflow-x: hidden;
391-
overflow-y: auto;
392-
}
393-
`}
394-
</style>
395406
<Document
396407
file={state.resource}
397408
onLoadSuccess={onDocumentLoadSuccess}
@@ -403,14 +414,15 @@ export default function usePdfReader(args: PdfReaderArguments): ReaderReturn {
403414
Array.from(new Array(state.numPages), (_, index) => (
404415
<ScrollPage
405416
key={`page_${index + 1}`}
406-
width={containerSize.width}
417+
width={containerSize.width - 16}
407418
height={state.pageHeight}
408419
placeholderHeight={state.pdfHeight}
409420
placeholderWidth={state.pdfWidth}
410421
scale={state.scale}
411422
pageNumber={index + 1}
412423
onLoadSuccess={onRenderSuccess}
413-
onInView={handlePageInView}
424+
allowInView={!isFetching}
425+
onInView={onInView}
414426
fitMode={state.fitMode}
415427
/>
416428
))}

src/PdfReader/pdfReader.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
.react-pdf__Document {
2+
scrollbar-color: #8d8d8d #424242;
3+
display: flex;
4+
flex-direction: column;
5+
background: #252525;
6+
gap: 8px;
7+
28
> div {
39
background: #252525;
410
}

src/constants.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ export const IS_DEV = process.env.NODE_ENV === 'development';
66

77
// we have to set a constant height to make this work with R2D2BC
88
export const HEADER_HEIGHT = 48;
9-
export const FOOTER_HEIGHT = 48;
10-
export const CHROME_HEIGHT = HEADER_HEIGHT + FOOTER_HEIGHT;
9+
export const CHROME_HEIGHT = HEADER_HEIGHT;
1110

1211
export const DEFAULT_HEIGHT = `calc(100vh - ${CHROME_HEIGHT}px)`;
1312
export const DEFAULT_SHOULD_GROW_WHEN_SCROLLING = true;

src/ui/Button.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,13 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
2525
ring: '2px',
2626
ringInset: 'inset',
2727
},
28+
padding: 1,
29+
height: '2rem',
30+
width: '2rem',
2831
}
2932
: {};
3033

31-
return (
32-
<ChakraButton
33-
h={8}
34-
w={8}
35-
p={1}
36-
ref={ref}
37-
variant="solid"
38-
{...iconProps}
39-
{...props}
40-
/>
41-
);
34+
return <ChakraButton ref={ref} variant="solid" {...iconProps} {...props} />;
4235
}
4336
);
4437

src/ui/Header.tsx

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import PdfZoomControls from './PdfZoomControls';
1818
import SettingsCard from './SettingsButton';
1919
import SkipNavigation from './SkipNavigation';
2020
import TableOfContent from './TableOfContent';
21+
import Tooltip from './Tooltip';
2122

2223
export default function Header(
2324
props: ActiveReader & {
@@ -111,31 +112,39 @@ export default function Header(
111112
readerState={props.state}
112113
/>
113114
)}
114-
<Button
115-
isIcon
116-
onClick={toggleFitMode}
117-
aria-label={fitMode === 'width' ? 'Fit to width' : 'Fit to height'}
115+
<Tooltip
116+
content={fitMode === 'width' ? 'Fit to height' : 'Fit to width'}
118117
>
119-
<Icon
120-
as={FitHeightWidth}
121-
fitMode={fitMode === 'width' ? 'width' : 'height'}
122-
w={6}
123-
h={6}
124-
/>
125-
</Button>
126-
<Button isIcon onClick={navigator.resetSettings}>
127-
<Icon as={Reset} w={6} h={6} />
128-
</Button>
118+
<Button
119+
isIcon
120+
onClick={toggleFitMode}
121+
aria-label={fitMode === 'width' ? 'Fit to height' : 'Fit to width'}
122+
>
123+
<Icon
124+
as={FitHeightWidth}
125+
fitMode={fitMode === 'width' ? 'width' : 'height'}
126+
w={6}
127+
h={6}
128+
/>
129+
</Button>
130+
</Tooltip>
131+
<Tooltip content="Reset settings">
132+
<Button isIcon onClick={navigator.resetSettings}>
133+
<Icon as={Reset} w={6} h={6} />
134+
</Button>
135+
</Tooltip>
129136
</HStack>
130137
<HStack mx="auto" spacing={2}>
131-
<Button
132-
onClick={pageUp}
133-
aria-label="Previous Page"
134-
isDisabled={currentPage <= 1}
135-
isIcon
136-
>
137-
<Icon as={PageUp} w={6} h={6} />
138-
</Button>
138+
<Tooltip content="Previous page">
139+
<Button
140+
onClick={pageUp}
141+
aria-label="Previous page"
142+
isDisabled={currentPage <= 1}
143+
isIcon
144+
>
145+
<Icon as={PageUp} w={6} h={6} />
146+
</Button>
147+
</Tooltip>
139148
<HStack color="ui.white" spacing={2} fontSize="sm" alignItems="center">
140149
<Input
141150
aria-label="Current page number"
@@ -158,38 +167,50 @@ export default function Header(
158167
<Text>/</Text>
159168
<Text>{totalPages}</Text>
160169
</HStack>
161-
<Button
162-
onClick={pageDown}
163-
aria-label="Next Page"
164-
isDisabled={currentPage >= totalPages}
165-
isIcon
166-
>
167-
<Icon as={PageDown} w={6} h={6} />
168-
</Button>
170+
<Tooltip content="Next page">
171+
<Button
172+
onClick={pageDown}
173+
aria-label="Next page"
174+
isDisabled={currentPage >= totalPages}
175+
isIcon
176+
>
177+
<Icon as={PageDown} w={6} h={6} />
178+
</Button>
179+
</Tooltip>
169180
</HStack>
170181
<HStack ml="auto" spacing={2}>
171-
<Button isIcon>
172-
<Icon as={Search} w={6} h={6} />
173-
</Button>
182+
<Tooltip content="Search inside">
183+
<Button isIcon>
184+
<Icon as={Search} w={6} h={6} />
185+
</Button>
186+
</Tooltip>
174187
<TableOfContent
175188
containerRef={containerRef}
176189
navigator={navigator}
177190
manifest={manifest}
178191
/>
179-
<Button
180-
aria-expanded={isFullscreen}
181-
aria-label="Toggle full screen"
182-
border="none"
183-
bgColor={mainBgColor}
184-
onClick={toggleFullScreen}
185-
isIcon
192+
<Tooltip
193+
content={
194+
isFullscreen ? 'Exit full screen mode' : 'Enter full screen mode'
195+
}
186196
>
187-
<Icon
188-
as={isFullscreen ? ToggleFullScreenExit : ToggleFullScreen}
189-
w={6}
190-
h={6}
191-
/>
192-
</Button>
197+
<Button
198+
aria-expanded={isFullscreen}
199+
aria-label={
200+
isFullscreen ? 'Exit full screen mode' : 'Enter full screen mode'
201+
}
202+
border="none"
203+
bgColor={mainBgColor}
204+
onClick={toggleFullScreen}
205+
isIcon
206+
>
207+
<Icon
208+
as={isFullscreen ? ToggleFullScreenExit : ToggleFullScreen}
209+
w={6}
210+
h={6}
211+
/>
212+
</Button>
213+
</Tooltip>
193214
{type === 'HTML' && <SettingsCard {...props} />}
194215
</HStack>
195216
</HeaderWrapper>

src/ui/HtmlFontSizeControls.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import { HtmlNavigator, ReaderState } from '../types';
44
import Button from './Button';
55
import { ZoomIn, ZoomOut } from './icons';
6+
import Tooltip from './Tooltip';
67

78
export type HtmlFontSizeControlsProps = {
89
navigator: HtmlNavigator;
@@ -21,12 +22,24 @@ export default function HtmlFontSizeControls(
2122

2223
return (
2324
<ButtonGroup display="flex" spacing={2}>
24-
<Button aria-label="Increase font size" onClick={increaseFontSize} isIcon>
25-
<Icon as={ZoomIn} w={6} h={6} />
26-
</Button>
27-
<Button aria-label="Decrease font size" onClick={decreaseFontSize} isIcon>
28-
<Icon as={ZoomOut} w={6} h={6} />
29-
</Button>
25+
<Tooltip content="Increase font size">
26+
<Button
27+
aria-label="Increase font size"
28+
onClick={increaseFontSize}
29+
isIcon
30+
>
31+
<Icon as={ZoomIn} w={6} h={6} />
32+
</Button>
33+
</Tooltip>
34+
<Tooltip content="Decrease font size">
35+
<Button
36+
aria-label="Decrease font size"
37+
onClick={decreaseFontSize}
38+
isIcon
39+
>
40+
<Icon as={ZoomOut} w={6} h={6} />
41+
</Button>
42+
</Tooltip>
3043
</ButtonGroup>
3144
);
3245
}

0 commit comments

Comments
 (0)