Commit d674e11b authored by Lyza Danger Gardner's avatar Lyza Danger Gardner Committed by Lyza Gardner

Convert `Buckets` to TS

Perform an internal refactor to reduce the number of internal components
parent 0facdc30
import { LabeledButton } from '@hypothesis/frontend-shared'; import { LabeledButton } from '@hypothesis/frontend-shared';
import classnames from 'classnames'; import classnames from 'classnames';
/** import type { Bucket } from '../util/buckets';
* @typedef {import('../util/buckets').Bucket} Bucket
* @typedef {import("preact").ComponentChildren} Children export type BucketsProps = {
/**
* Bucket containing the $tags of any annotations that are offscreen above
* the current viewport. If the set of $tags is non-empty, up navigation
* will be rendered.
*/ */
above: Bucket;
/** /**
* Render a set of buckets in a vertical channel positioned along the edge of * Bucket containing the $tags of any annotations that are offscreen below
* the sidebar. * the current viewport. If the set of $tags is non-empty, down navigation
* * will be rendered.
* @param {object} props
* @param {Children} props.children
*/ */
function BucketList({ children }) { below: Bucket;
return (
<ul
className={classnames(
// 2020-11-20: Making bucket bar one pixel wider (23px vs 22px) is an
// interim and pragmatic solution for an apparent glitch on
// Safari and Chrome. Adding one pixel resolves this issue:
// https://github.com/hypothesis/client/pull/2750
'absolute w-[23px] left-[-22px] h-full',
// The background is set to low opacity when the sidebar is collapsed.
'bg-grey-2 sidebar-collapsed:bg-black/[.08]',
// Disable pointer events along the sidebar itself; re-enable them in
// bucket indicator buttons
'pointer-events-none'
)}
>
{children}
</ul>
);
}
/** /**
* Render a vertically-positioned bucket-list item. * A list of buckets visible on-screen. A left-pointing arrow will be
* * rendered for each bucket.
* @param {object} props
* @param {Children} props.children
* @param {number} props.topPosition - The vertical top position, in pixels,
* for this bucket item relative to the top of the containing BucketList
*/ */
function BucketItem({ children, topPosition }) { buckets: Bucket[];
return ( onFocusAnnotations: ($tags: string[]) => void;
<li onScrollToClosestOffScreenAnchor: (
className={classnames( $tags: string[],
'absolute right-0', direction: 'down' | 'up'
// Re-enable pointer events, which are disabled on the containing list ) => void;
'pointer-events-auto' onSelectAnnotations: ($tags: string[], toggle: boolean) => void;
)} };
style={{ top: topPosition }}
>
{children}
</li>
);
}
/** /**
* A list of buckets, including up and down navigation (when applicable) and * A list of buckets, including up and down navigation (when applicable) and
...@@ -64,14 +38,6 @@ function BucketItem({ children, topPosition }) { ...@@ -64,14 +38,6 @@ function BucketItem({ children, topPosition }) {
* This component and its buttons are sized with absolute units such that they * This component and its buttons are sized with absolute units such that they
* don't scale with changes to the host page's root font size. They will still * don't scale with changes to the host page's root font size. They will still
* properly scale with user/browser zooming. * properly scale with user/browser zooming.
*
* @param {object} props
* @param {Bucket} props.above
* @param {Bucket} props.below
* @param {Bucket[]} props.buckets
* @param {(tags: string[]) => void} props.onFocusAnnotations
* @param {(tags: string[], direction: 'down'|'up') => void} props.onScrollToClosestOffScreenAnchor
* @param {(tags: string[], toggle: boolean) => void} props.onSelectAnnotations
*/ */
export default function Buckets({ export default function Buckets({
above, above,
...@@ -80,14 +46,30 @@ export default function Buckets({ ...@@ -80,14 +46,30 @@ export default function Buckets({
onFocusAnnotations, onFocusAnnotations,
onScrollToClosestOffScreenAnchor, onScrollToClosestOffScreenAnchor,
onSelectAnnotations, onSelectAnnotations,
}) { }: BucketsProps) {
const showUpNavigation = above.tags.size > 0; const showUpNavigation = above.tags.size > 0;
const showDownNavigation = below.tags.size > 0; const showDownNavigation = below.tags.size > 0;
return ( return (
<BucketList> <ul
className={classnames(
// 2020-11-20: Making bucket bar one pixel wider (23px vs 22px) is an
// interim and pragmatic solution for an apparent glitch on
// Safari and Chrome. Adding one pixel resolves this issue:
// https://github.com/hypothesis/client/pull/2750
'absolute w-[23px] left-[-22px] h-full',
// The background is set to low opacity when the sidebar is collapsed.
'bg-grey-2 sidebar-collapsed:bg-black/[.08]',
// Disable pointer events along the sidebar itself; re-enable them in
// bucket indicator buttons
'pointer-events-none'
)}
>
{showUpNavigation && ( {showUpNavigation && (
<BucketItem topPosition={above.position}> <li
className="absolute right-0 pointer-events-auto"
style={{ top: above.position }}
>
<LabeledButton <LabeledButton
className={classnames( className={classnames(
'BucketButton UpBucketButton', 'BucketButton UpBucketButton',
...@@ -109,10 +91,14 @@ export default function Buckets({ ...@@ -109,10 +91,14 @@ export default function Buckets({
> >
{above.tags.size} {above.tags.size}
</LabeledButton> </LabeledButton>
</BucketItem> </li>
)} )}
{buckets.map((bucket, index) => ( {buckets.map((bucket, index) => (
<BucketItem topPosition={bucket.position} key={index}> <li
className="absolute right-0 pointer-events-auto"
key={index}
style={{ top: bucket.position }}
>
<LabeledButton <LabeledButton
className={classnames( className={classnames(
'BucketButton LeftBucketButton', 'BucketButton LeftBucketButton',
...@@ -134,10 +120,13 @@ export default function Buckets({ ...@@ -134,10 +120,13 @@ export default function Buckets({
> >
{bucket.tags.size} {bucket.tags.size}
</LabeledButton> </LabeledButton>
</BucketItem> </li>
))} ))}
{showDownNavigation && ( {showDownNavigation && (
<BucketItem topPosition={below.position}> <li
className="absolute right-0 pointer-events-auto"
style={{ top: below.position }}
>
<LabeledButton <LabeledButton
className="BucketButton DownBucketButton right-0" className="BucketButton DownBucketButton right-0"
data-testid="down-navigation-button" data-testid="down-navigation-button"
...@@ -152,8 +141,8 @@ export default function Buckets({ ...@@ -152,8 +141,8 @@ export default function Buckets({
> >
{below.tags.size} {below.tags.size}
</LabeledButton> </LabeledButton>
</BucketItem> </li>
)} )}
</BucketList> </ul>
); );
} }
...@@ -124,7 +124,7 @@ describe('Buckets', () => { ...@@ -124,7 +124,7 @@ describe('Buckets', () => {
const wrapper = createComponent(); const wrapper = createComponent();
const upButton = wrapper.find(upButtonSelector); const upButton = wrapper.find(upButtonSelector);
// The list item element wrapping the button // The list item element wrapping the button
const bucketItem = wrapper.find('BucketItem').first(); const bucketItem = wrapper.find('li').first();
assert.isTrue(upButton.exists()); assert.isTrue(upButton.exists());
assert.equal( assert.equal(
...@@ -144,7 +144,7 @@ describe('Buckets', () => { ...@@ -144,7 +144,7 @@ describe('Buckets', () => {
const downButton = wrapper.find(downButtonSelector); const downButton = wrapper.find(downButtonSelector);
// The list item element wrapping the button // The list item element wrapping the button
const bucketItem = wrapper.find('BucketItem').last(); const bucketItem = wrapper.find('li').last();
assert.isTrue(downButton.exists()); assert.isTrue(downButton.exists());
assert.equal( assert.equal(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment