Skip to content

feat: add "active" state to highlight on PdfViewer - #259

Merged
fukudasjp merged 13 commits into
masterfrom
feat/active-pdf-highlight
Jan 21, 2022
Merged

feat: add "active" state to highlight on PdfViewer#259
fukudasjp merged 13 commits into
masterfrom
feat/active-pdf-highlight

Conversation

@fukudasjp

@fukudasjp fukudasjp commented Jan 11, 2022

Copy link
Copy Markdown
Contributor

What do these changes do/fix?

Add "active" state to highlights on PdfViewer. When you set a highlight as active,

  • the highlight is displayed in darker color, and
  • PdfViewer reveals the highlight by changing current page and scrolling

How do you test/verify these changes?

We can use Storybook (DocumentPreview > components > PdfViewerWithHighlight > default). In the story's Knobs tab, you can set Highlights and Active highlight index to the component.

Have you documented your changes (if necessary)?

Are there any breaking changes included in this pull request?

no

@fukudasjp fukudasjp changed the title feat: add active (selected) highlight feature to PdfViewer feat: add active highlight to PdfViewer Jan 11, 2022
@fukudasjp fukudasjp changed the title feat: add active highlight to PdfViewer feat: add focused highlight to PdfViewer Jan 12, 2022
@fukudasjp fukudasjp changed the title feat: add focused highlight to PdfViewer feat: add "active" state to highlight on PdfViewer Jan 12, 2022
@jhpedemonte

Copy link
Copy Markdown
Member

Functionality is good, but I'm concerned about the "active" color not meeting accessibility standards. It's hard to gauge since it's an overlay with opacity, but I used the Digital Color Meter app from the MacOS Developer Tools to measure both the overlay color and the text color (since the overlay changes the color of the underlying text):

Screen Shot 2022-01-19 at 4 02 35 PM
Screen Shot 2022-01-19 at 4 02 18 PM

I then ran those numbers through the Contrast Checker:

Screen Shot 2022-01-19 at 4 02 49 PM

If this were true system-level text highlighting, then the text would be true black, which easily passes all of the contrast checks. But since the overlay changes the text color, one test fails. We'll need to find a different color to use.

Or we can find a different way to denote "active"; for example, with a "focus" rectangle around it.

@jhpedemonte

jhpedemonte commented Jan 19, 2022

Copy link
Copy Markdown
Member

If using the "Active highlight index" knob, should setting it to 2 force the PDF viewer to load the 3rd page, which contains this highlight index?

Update: Oh, after refreshing Storybook, it worked. But then going back to 1 and 0 did nothing.

@jhpedemonte jhpedemonte left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep getting confused between PdfViewerHighlight.tsx and PdfViewerWithHighlight.tsx. I think one of those should be renamed, at least, to make things clearer.

const active = shape?.highlightId ? activeIds?.includes(shape.highlightId) : false;
return (
<Highlight
key={shape?.highlightId || `highlight_${hlIndex}`}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often will the "else" case resolve here? We shouldn't use array index for the React key -- that can easily lead to bugs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shape.highlightId is currently optional, but I refactor the code to make the highlightId required.

Comment on lines +100 to +108
function getPositionStyle(bbox: Bbox, scale: number, padding: number = 0) {
const [left, top, right, bottom] = bbox;
return {
left: `${(left - padding) * scale}px`,
top: `${(top - padding) * scale}px`,
width: `${(right - left + padding) * scale}px`,
height: `${(bottom - top + padding) * scale}px`
};
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this function outside of the component, since it's standalone. No sense in redefining it each time the component renders.

return (
<div className={cx(`${settings.prefix}--document-preview-pdf-viewer-highlight`, className)}>
{highlightBoxes.map((hl, hlIndex) => {
<div key={highlightId} data-highlight-id={highlightId}>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here with key.

})}
</React.Fragment>
<div
key={`hlId_${index}`}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.


function useScrollIntoActiveHighlight(
highlightDivRef: React.MutableRefObject<HTMLDivElement | null>,
shapes: (HighlightShape | undefined)[],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shapes can be an array of undefined?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no. I fixed the code

`[data-highlight-id=${activeShape.highlightId}]`
);
highlightElm?.firstElementChild?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
}, 50);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 50 for the timeout? I don't like having arbitrary timeout values, since they may work on your computer, but may fail on a slower computer.

Using zero is fine since that's useful to make some code asynchronous. But it would be better to key off of something else rather than a random timeout, if possible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was to push a new task to the javascript runtime. So I use the value 0.

);
highlightElm?.firstElementChild?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
}, 50);
return () => clearTimeout(timer);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this right, this is meant to be the cleanup function for the useEffect, right? If so, please comment.

Or better yet, do it like they show in the docs:

return function cleanup() {
  clearTimeout(timer);
}

const [highlightPage, setHighlightPage] = useState<number | undefined>();

useEffect(() => {
const pages = activeHighlightPages.filter(nonEmpty);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to move this into useActiveHighlightPages?

setHighlightPage(newPage);
}, [page, activeHighlightPages]);

const [currentPage, setCurrentPage] = useState(page);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function would read better if this were moved to the top and it referenced currentPage instead of page in the rest of the code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the currentPage useState to the top, revised the code and added comments.

fieldText = documentFieldArray?.[index ?? 0];
}
if (!fieldText || !span) {
if (typeof fieldText?.['table_text'] === 'string') {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Highlighting went wrong when there is table field in a document because it contains an object instead of text. Also, there is text_mappings for between bboxes and text in table fields. That code is to specially handles the table field to get field text referred in the text_mappings.

As the code is not clear, I updated the code and added a comment.

@fukudasjp

fukudasjp commented Jan 20, 2022

Copy link
Copy Markdown
Contributor Author

@jhpedemonte thanks for heading up the contrast issue! I updated the highlight style (8cb9c3f) to use smaller opacity value for the style not to affect the original text color. That passes the test.

image

@fukudasjp

Copy link
Copy Markdown
Contributor Author

Oh, after refreshing Storybook, it worked. But then going back to 1 and 0 did nothing.

This issue came from the Storybook code and fixed it.

@lgtm-com

lgtm-com Bot commented Jan 20, 2022

Copy link
Copy Markdown
Contributor

This pull request introduces 1 alert when merging 01d4ff7 into 5026722 - view on LGTM.com

new alerts:

  • 1 for Unneeded defensive code

@fukudasjp

Copy link
Copy Markdown
Contributor Author

I keep getting confused between PdfViewerHighlight.tsx and PdfViewerWithHighlight.tsx. I think one of those should be renamed, at least, to make things clearer.

I agree. Just renaming PdfViewerHighlight to PdfHighlight makes the situation much better and it's the first step, I think. I drafted #275 on top of this PR.

@fukudasjp
fukudasjp merged commit 35c473a into master Jan 21, 2022
@fukudasjp
fukudasjp deleted the feat/active-pdf-highlight branch January 21, 2022 04:15
jhpedemonte added a commit that referenced this pull request Jan 31, 2022
* origin/master:
  fix: add missing prop to doc provider interface (#283)
  chore: publish v1.5.0-beta.15 [ci skip]
  fix: fix PDFViewer rendering issue (#267)
  chore: publish v1.5.0-beta.14 [ci skip]
  feat: update preview toolbar design for PDF viewer (#251)
  chore: publish v1.5.0-beta.13 [ci skip]
  fix: Fix PdfView alignment in DocumentPreview (#256)
  chore: publish v1.5.0-beta.12 [ci skip]
  refactor: rename PdfViewerHighlight to PdfHighlight (#275)
  chore: publish v1.5.0-beta.11 [ci skip]
  feat: add "active" state to highlight on PdfViewer (#259)
  chore: update lockfile
  chore: update CODEOWNERS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants