Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
ad20c5f2
Commit
ad20c5f2
authored
Feb 09, 2022
by
Lyza Danger Gardner
Committed by
Lyza Gardner
Feb 11, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate annotator `Buckets` to modern styles, components, tailwind
parent
3a5aa936
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
269 additions
and
301 deletions
+269
-301
Buckets.js
src/annotator/components/Buckets.js
+99
-97
Buckets-test.js
src/annotator/components/test/Buckets-test.js
+63
-23
Buckets.scss
src/styles/annotator/components/Buckets.scss
+96
-41
buttons.scss
src/styles/mixins/buttons.scss
+0
-140
tailwind.config.mjs
tailwind.config.mjs
+11
-0
No files found.
src/annotator/components/Buckets.js
View file @
ad20c5f2
import
{
LabeledButton
}
from
'@hypothesis/frontend-shared'
;
import
classnames
from
'classnames'
;
import
classnames
from
'classnames'
;
/**
/**
* @typedef {import('../util/buckets').Bucket} Bucket
* @typedef {import('../util/buckets').Bucket} Bucket
* @typedef {import("preact").ComponentChildren} Children
*/
*/
/**
/**
*
A left-pointing indicator button that, when hovered or clicked, highlights
*
Render a set of buckets in a vertical channel positioned along the edge of
*
or selects associated annotations
.
*
the sidebar
.
*
*
* @param {object} props
* @param {object} props
* @param {Bucket} props.bucket
* @prop {Children} props.children
* @param {(tags: string[]) => void} props.onFocusAnnotations
* @param {(tags: string[], toggle: boolean) => void} props.onSelectAnnotations
*/
*/
function
BucketButton
({
bucket
,
onFocusAnnotations
,
onSelectAnnotations
})
{
function
BucketList
({
children
})
{
const
buttonTitle
=
`Select nearby annotations (
${
bucket
.
tags
.
size
}
)`
;
function
selectAnnotations
(
event
)
{
onSelectAnnotations
([...
bucket
.
tags
],
event
.
metaKey
||
event
.
ctrlKey
);
}
/** @param {boolean} hasFocus */
function
setFocus
(
hasFocus
)
{
if
(
hasFocus
)
{
onFocusAnnotations
([...
bucket
.
tags
]);
}
else
{
onFocusAnnotations
([]);
}
}
return
(
return
(
<
button
<
ul
className
=
"Buckets__button Buckets__button--left"
className
=
{
classnames
(
onClick
=
{
event
=>
selectAnnotations
(
event
)}
// 2020-11-20: Making bucket bar one pixel wider (23px vs 22px) is an
onBlur
=
{()
=>
setFocus
(
false
)}
// interim and pragmatic solution for an apparent glitch on
onFocus
=
{()
=>
setFocus
(
true
)}
// Safari and Chrome. Adding one pixel resolves this issue:
onMouseEnter
=
{()
=>
setFocus
(
true
)}
// https://github.com/hypothesis/client/pull/2750
onMouseOut
=
{()
=>
setFocus
(
false
)}
'absolute w-[23px] left-[-22px] h-full'
,
title
=
{
buttonTitle
}
// The background is set to low opacity when the sidebar is collapsed.
aria
-
label
=
{
buttonTitle
}
'bg-grey-2 annotator-collapsed:bg-black/[.08]'
,
// Disable pointer events along the sidebar itself; re-enable them in
// bucket indicator buttons
'pointer-events-none'
)}
>
>
{
bucket
.
tags
.
size
}
{
children
}
<
/
button
>
<
/
ul
>
);
);
}
}
/**
/**
* An up- or down-pointing button that will scroll to the next closest bucket
* Render a vertically-positioned bucket-list item.
* of annotations in the given direction.
*
*
* @param {object} props
* @param {object} props
* @param {Bucket} props.bucket
* @prop {Children} props.children
* @param {'down'|'up'} props.direction
* @prop {number} props.topPosition - The vertical top position, in pixels,
* @param {(tags: string[]) => void} props.onFocusAnnotations
* for this bucket item relative to the top of the containing BucketList
* @param {(tags: string[], direction: 'down'|'up') => void} props.onScrollToClosestOffScreenAnchor
*/
*/
function
NavigationBucketButton
({
function
BucketItem
({
children
,
topPosition
})
{
bucket
,
direction
,
onFocusAnnotations
,
onScrollToClosestOffScreenAnchor
,
})
{
const
buttonTitle
=
`Go
${
direction
}
to next annotations (
${
bucket
.
tags
.
size
}
)`
;
/** @param {boolean} hasFocus */
function
setFocus
(
hasFocus
)
{
if
(
hasFocus
)
{
onFocusAnnotations
([...
bucket
.
tags
]);
}
else
{
onFocusAnnotations
([]);
}
}
return
(
return
(
<
button
<
li
className
=
{
classnames
(
'Buckets__button'
,
`Buckets__button--
${
direction
}
`
)}
className
=
{
classnames
(
onClick
=
{()
=>
'absolute right-0'
,
onScrollToClosestOffScreenAnchor
([...
bucket
.
tags
],
direction
)
// Re-enable pointer events, which are disabled on the containing list
}
'pointer-events-auto'
onBlur
=
{()
=>
setFocus
(
false
)}
)}
onFocus
=
{()
=>
setFocus
(
true
)}
style
=
{{
top
:
topPosition
}}
onMouseEnter
=
{()
=>
setFocus
(
true
)}
onMouseOut
=
{()
=>
setFocus
(
false
)}
title
=
{
buttonTitle
}
aria
-
label
=
{
buttonTitle
}
>
>
{
bucket
.
tags
.
size
}
{
children
}
<
/
button
>
<
/
li
>
);
);
}
}
...
@@ -114,40 +81,75 @@ export default function Buckets({
...
@@ -114,40 +81,75 @@ export default function Buckets({
const
showDownNavigation
=
below
.
tags
.
size
>
0
;
const
showDownNavigation
=
below
.
tags
.
size
>
0
;
return
(
return
(
<
ul
className
=
"Buckets__list"
>
<
BucketList
>
{
showUpNavigation
&&
(
{
showUpNavigation
&&
(
<
li
className
=
"Buckets__bucket"
style
=
{{
top
:
above
.
position
}}
>
<
BucketItem
topPosition
=
{
above
.
position
}
>
<
NavigationBucketButton
<
LabeledButton
bucket
=
{
above
}
className
=
{
classnames
(
direction
=
"up"
'BucketButton UpBucketButton'
,
onFocusAnnotations
=
{
onFocusAnnotations
}
// Center the button vertically at `above.position` by pulling
onScrollToClosestOffScreenAnchor
=
{
onScrollToClosestOffScreenAnchor
}
// its top margin up by about half the button's height.
/
>
// This puts it nearer the toolbar's other buttons above the
<
/li
>
// bucket list.
'right-0 mt-[-11px]'
)}
data
-
testid
=
"up-navigation-button"
onClick
=
{()
=>
onScrollToClosestOffScreenAnchor
([...
above
.
tags
],
'up'
)
}
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
above
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
above
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Go up to next annotations (
${
above
.
tags
.
size
}
)`
}
>
{
above
.
tags
.
size
}
<
/LabeledButton
>
<
/BucketItem
>
)}
)}
{
buckets
.
map
((
bucket
,
index
)
=>
(
{
buckets
.
map
((
bucket
,
index
)
=>
(
<
li
<
BucketItem
topPosition
=
{
bucket
.
position
}
key
=
{
index
}
>
className
=
"Buckets__bucket"
<
LabeledButton
style
=
{{
top
:
bucket
.
position
}}
className
=
{
classnames
(
key
=
{
index
}
'BucketButton LeftBucketButton'
,
// Center the bucket indicator button vertically on `bucket.position`
// by pulling it by half the height of the button
'right-0 mt-[-8px]'
)}
onClick
=
{
event
=>
onSelectAnnotations
(
[...
bucket
.
tags
],
event
.
metaKey
||
event
.
ctrlKey
)
}
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
bucket
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
bucket
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Select nearby annotations (
${
bucket
.
tags
.
size
}
)`
}
>
>
<
BucketButton
{
bucket
.
tags
.
size
}
bucket
=
{
bucket
}
<
/LabeledButton
>
onFocusAnnotations
=
{
onFocusAnnotations
}
<
/BucketItem
>
onSelectAnnotations
=
{
onSelectAnnotations
}
/
>
<
/li
>
))}
))}
{
showDownNavigation
&&
(
{
showDownNavigation
&&
(
<
li
className
=
"Buckets__bucket"
style
=
{{
top
:
below
.
position
}}
>
<
BucketItem
topPosition
=
{
below
.
position
}
>
<
NavigationBucketButton
<
LabeledButton
bucket
=
{
below
}
className
=
"BucketButton DownBucketButton right-0"
direction
=
"down"
data
-
testid
=
"down-navigation-button"
onFocusAnnotations
=
{
onFocusAnnotations
}
onClick
=
{()
=>
onScrollToClosestOffScreenAnchor
=
{
onScrollToClosestOffScreenAnchor
}
onScrollToClosestOffScreenAnchor
([...
below
.
tags
],
'down'
)
/
>
}
<
/li
>
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
below
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
below
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Go up to next annotations (
${
below
.
tags
.
size
}
)`
}
>
{
below
.
tags
.
size
}
<
/LabeledButton
>
<
/BucketItem
>
)}
)}
<
/
ul
>
<
/
BucketList
>
);
);
}
}
src/annotator/components/test/Buckets-test.js
View file @
ad20c5f2
...
@@ -45,37 +45,76 @@ describe('Buckets', () => {
...
@@ -45,37 +45,76 @@ describe('Buckets', () => {
);
);
describe
(
'up and down navigation'
,
()
=>
{
describe
(
'up and down navigation'
,
()
=>
{
it
(
'focuses associated anchors when mouse enters the element'
,
()
=>
{
const
upButtonSelector
=
'[data-testid="up-navigation-button"] button'
;
const
downButtonSelector
=
'[data-testid="down-navigation-button"] button'
;
it
(
'focuses associated anchors above the screen when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'mouseenter'
);
wrapper
.
find
(
upButtonSelector
).
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
});
});
it
(
'removes focus on associated anchors when mouse leaves the element'
,
()
=>
{
it
(
'focuses associated anchors below the screen when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
downButtonSelector
).
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'b1'
,
'b2'
]);
});
it
(
'removes focus on associated anchors above screen when mouse leaves the element'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'mouseout'
);
wrapper
.
find
(
upButtonSelector
).
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
});
it
(
'
focuses associated anchors when the element is focused
'
,
()
=>
{
it
(
'
removes focus on associated anchors below screen when mouse leaves the element
'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
().
simulate
(
'focus'
);
wrapper
.
find
(
downButtonSelector
).
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
it
(
'focuses associated anchors above screen when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
upButtonSelector
).
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
});
});
it
(
'removes focus on associated anchors when element is blurred'
,
()
=>
{
it
(
'focuses associated anchors below screen when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
downButtonSelector
).
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'b1'
,
'b2'
]);
});
it
(
'removes focus on associated anchors above screen when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
upButtonSelector
).
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
it
(
'removes focus on associated anchors below screen when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'blur'
);
wrapper
.
find
(
downButtonSelector
).
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
@@ -83,9 +122,9 @@ describe('Buckets', () => {
...
@@ -83,9 +122,9 @@ describe('Buckets', () => {
it
(
'renders an up navigation button if there are above-screen anchors'
,
()
=>
{
it
(
'renders an up navigation button if there are above-screen anchors'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
const
upButton
=
wrapper
.
find
(
'.Buckets__button--up'
);
const
upButton
=
wrapper
.
find
(
upButtonSelector
);
// The list item element wrapping the button
// The list item element wrapping the button
const
bucketItem
=
wrapper
.
find
(
'
.Buckets__bucket
'
).
first
();
const
bucketItem
=
wrapper
.
find
(
'
BucketItem
'
).
first
();
assert
.
isTrue
(
upButton
.
exists
());
assert
.
isTrue
(
upButton
.
exists
());
assert
.
equal
(
assert
.
equal
(
...
@@ -97,15 +136,15 @@ describe('Buckets', () => {
...
@@ -97,15 +136,15 @@ describe('Buckets', () => {
it
(
'does not render an up navigation button if there are no above-screen anchors'
,
()
=>
{
it
(
'does not render an up navigation button if there are no above-screen anchors'
,
()
=>
{
fakeAbove
=
{
tags
:
new
Set
(),
position
:
150
};
fakeAbove
=
{
tags
:
new
Set
(),
position
:
150
};
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
assert
.
isFalse
(
wrapper
.
find
(
'.Buckets__button--up'
).
exists
());
assert
.
isFalse
(
wrapper
.
find
(
upButtonSelector
).
exists
());
});
});
it
(
'renders a down navigation button if there are below-screen anchors'
,
()
=>
{
it
(
'renders a down navigation button if there are below-screen anchors'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
const
downButton
=
wrapper
.
find
(
'.Buckets__button--down'
);
const
downButton
=
wrapper
.
find
(
downButtonSelector
);
// The list item element wrapping the button
// The list item element wrapping the button
const
bucketItem
=
wrapper
.
find
(
'
.Buckets__bucket
'
).
last
();
const
bucketItem
=
wrapper
.
find
(
'
BucketItem
'
).
last
();
assert
.
isTrue
(
downButton
.
exists
());
assert
.
isTrue
(
downButton
.
exists
());
assert
.
equal
(
assert
.
equal
(
...
@@ -117,12 +156,12 @@ describe('Buckets', () => {
...
@@ -117,12 +156,12 @@ describe('Buckets', () => {
it
(
'does not render a down navigation button if there are no below-screen anchors'
,
()
=>
{
it
(
'does not render a down navigation button if there are no below-screen anchors'
,
()
=>
{
fakeBelow
=
{
tags
:
new
Set
(),
position
:
550
};
fakeBelow
=
{
tags
:
new
Set
(),
position
:
550
};
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
assert
.
isFalse
(
wrapper
.
find
(
'.Buckets__button--down'
).
exists
());
assert
.
isFalse
(
wrapper
.
find
(
downButtonSelector
).
exists
());
});
});
it
(
'scrolls to anchors above when up navigation button is pressed'
,
()
=>
{
it
(
'scrolls to anchors above when up navigation button is pressed'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
const
upButton
=
wrapper
.
find
(
'.Buckets__button--up'
);
const
upButton
=
wrapper
.
find
(
upButtonSelector
);
upButton
.
simulate
(
'click'
);
upButton
.
simulate
(
'click'
);
...
@@ -135,7 +174,7 @@ describe('Buckets', () => {
...
@@ -135,7 +174,7 @@ describe('Buckets', () => {
it
(
'scrolls to anchors below when down navigation button is pressed'
,
()
=>
{
it
(
'scrolls to anchors below when down navigation button is pressed'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
const
downButton
=
wrapper
.
find
(
'.Buckets__button--down'
);
const
downButton
=
wrapper
.
find
(
downButtonSelector
);
downButton
.
simulate
(
'click'
);
downButton
.
simulate
(
'click'
);
...
@@ -148,16 +187,17 @@ describe('Buckets', () => {
...
@@ -148,16 +187,17 @@ describe('Buckets', () => {
});
});
describe
(
'on-screen buckets'
,
()
=>
{
describe
(
'on-screen buckets'
,
()
=>
{
const
bucketButtonSelector
=
'button[title^="Select nearby annotations"]'
;
it
(
'renders a bucket button for each bucket'
,
()
=>
{
it
(
'renders a bucket button for each bucket'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
assert
.
equal
(
wrapper
.
find
(
'.Buckets__button--left'
).
length
,
2
);
assert
.
equal
(
wrapper
.
find
(
bucketButtonSelector
).
length
,
2
);
});
});
it
(
'focuses on associated annotations when mouse enters the element'
,
()
=>
{
it
(
'focuses on associated annotations when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'mouseenter'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
...
@@ -166,7 +206,7 @@ describe('Buckets', () => {
...
@@ -166,7 +206,7 @@ describe('Buckets', () => {
it
(
'removes focus on associated anchors when mouse leaves the element'
,
()
=>
{
it
(
'removes focus on associated anchors when mouse leaves the element'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'mouseout'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
@@ -175,7 +215,7 @@ describe('Buckets', () => {
...
@@ -175,7 +215,7 @@ describe('Buckets', () => {
it
(
'focuses associated anchors when the element is focused'
,
()
=>
{
it
(
'focuses associated anchors when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'focus'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
...
@@ -184,7 +224,7 @@ describe('Buckets', () => {
...
@@ -184,7 +224,7 @@ describe('Buckets', () => {
it
(
'removes focus on associated annotations when element is blurred'
,
()
=>
{
it
(
'removes focus on associated annotations when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'blur'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
@@ -194,7 +234,7 @@ describe('Buckets', () => {
...
@@ -194,7 +234,7 @@ describe('Buckets', () => {
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
wrapper
.
find
(
'.Buckets__button--left'
)
.
find
(
bucketButtonSelector
)
.
first
()
.
first
()
.
simulate
(
'click'
,
{
metaKey
:
false
,
ctrlKey
:
false
});
.
simulate
(
'click'
,
{
metaKey
:
false
,
ctrlKey
:
false
});
...
@@ -208,7 +248,7 @@ describe('Buckets', () => {
...
@@ -208,7 +248,7 @@ describe('Buckets', () => {
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
wrapper
.
find
(
'.Buckets__button--left'
)
.
find
(
bucketButtonSelector
)
.
first
()
.
first
()
.
simulate
(
'click'
,
{
metaKey
:
true
,
ctrlKey
:
false
});
.
simulate
(
'click'
,
{
metaKey
:
true
,
ctrlKey
:
false
});
...
...
src/styles/annotator/components/Buckets.scss
View file @
ad20c5f2
@use
'../mixins/buttons'
;
/**
@use
'../variables'
as
var
;
* These classes style buttons to appear as lozenges with an integrated arrow
* pointing left, up or down (right doesn't exist yet but could easily be added).
$bucket-bar-width
:
22px
;
* *
* The arrow-points are created by the combination of borders and positioning.
.Buckets__list
{
* See https://css-tricks.com/snippets/css/css-triangle/ for a few examples
background
:
var
.
$grey-2
;
// When sidebar is unfolded, remove the background transparency
*
pointer-events
:
none
;
*/
position
:
absolute
;
height
:
100%
;
// 2020-11-20: interim and pragmatic solution for an apparent glitch on Safari and Chrome.
// Adding one pixel resolve this issue: https://github.com/hypothesis/client/pull/2750
width
:
$bucket-bar-width
+
1
;
left
:
-
(
$bucket-bar-width
);
}
// When the sidebar is collapsed, make the background semi-transparent so the
@layer
components
{
// text is visible throughout (useful for pages with tight margins)
// Base styling for a button with a numerical badge that points either up,
.annotator-collapsed
.Buckets__list
{
// down or left. On its own, it will be lozenge-shaped. Compose with one
background
:
rgba
(
0
,
0
,
0
,
0
.08
);
// of the directional classes below to style a button fully, e.g.
}
// `classname="BucketButton LeftBucketButton`
.BucketButton
{
// A lozenge-shaped element with very small text
@apply
w-
[
26px
]
h-
[
16px
]
absolute
border
bg-white
shadow
rounded
;
@apply
font-sans
text-center
text-tiny
font-bold
text-color-text-light
leading-none
;
.Buckets__bucket
{
// Establish :before and :after content for later manipulation into
position
:
absolute
;
// different pointer shapes and directions
right
:
0
;
&
:
:
before
,
}
&::
after
{
@apply
content-
[
""
]
absolute
border-transparent
;
}
}
.Buckets__button
{
// Style a `BucketButton` to point left
// Need pointer events again. Necessary because of `pointer-events` rule
.LeftBucketButton
{
// in `.Buckets__list`
@apply
rounded-r
rounded-l-sm
;
pointer-events
:
all
;
}
.Buckets__button--left
{
// Position to the left of the button and centered vertically
// Center the indicator vertically (the element is 16px tall)
&
:
:
before
,
margin-top
:
-8px
;
&::
after
{
@include
buttons
.
indicator--left
;
@apply
right-full
top-1
/
2
;
}
}
.Buckets__button--up
{
// Create a grey wedge to the left of the button
@include
buttons
.
indicator--up
;
// This will appear as the border around the pointy side
// Vertically center the element (which is 22px high)
&
:
:
before
{
margin-top
:
-11px
;
@apply
mt-
[
-8px
]
border-8
;
}
@apply
border-r-
[
5px
]
border-r-grey-3
;
}
// Create a white wedge to the left of the button, 1px smaller than
// grey wedge. This will composite on top of the grey wedge and serve as
// the white fill of the pointy side
&
:
:
after
{
@apply
mt-
[
-7px
]
border-
[
7px
]
;
@apply
border-r-
[
4px
]
border-r-white
;
}
}
// Style a `BucketButton` to point up
.UpBucketButton
{
// Z-index assures that left-pointing buttons will scroll behind this
@apply
z-1
rounded-t-sm
rounded-b
;
// Position above the button and horizontally centered
&
:
:
before
,
&::
after
{
@apply
top-auto
left-1
/
2
bottom-full
;
}
// Create a grey wedge at the top of the button
// This will appear as the border around the pointy side
&
:
:
before
{
@apply
ml-
[
-13px
]
border-
[
13px
]
;
@apply
border-b-
[
6px
]
border-b-grey-3
;
}
// Create a white wedge 1px smaller than the grey wedge, as "fill"
&
:
:
after
{
@apply
ml-
[
-12px
]
border-
[
12px
]
;
@apply
border-b-
[
5px
]
border-b-white
;
}
}
// Style a `BucketButton` to point down
.DownBucketButton
{
// Z-index assures that left-pointing buttons will scroll behind this
@apply
z-1
rounded-t
rounded-b-sm
;
// Position below the button and horizontally centered
&
:
:
before
,
&::
after
{
@apply
top-full
left-1
/
2
;
}
// Create a grey wedge at the bottom of the button
// This will appear as the border around the pointy side
&
:
:
before
{
@apply
ml-
[
-13px
]
border-
[
13px
]
;
@apply
border-t-
[
6px
]
border-t-grey-3
;
}
.Buckets__button--down
{
// Create a white wedge 1px smaller than the grey wedge, as "fill"
@include
buttons
.
indicator--down
;
&
:
:
after
{
@apply
ml-
[
-12px
]
border-
[
12px
]
;
@apply
border-t-
[
5px
]
border-t-white
;
}
}
}
}
src/styles/mixins/buttons.scss
View file @
ad20c5f2
...
@@ -17,7 +17,6 @@
...
@@ -17,7 +17,6 @@
*
*
* And pass 'my-component-button' as the `className` prop to `Button`.
* And pass 'my-component-button' as the `className` prop to `Button`.
*/
*/
@use
'sass:math'
;
@use
'@hypothesis/frontend-shared/styles/mixins/focus'
;
@use
'@hypothesis/frontend-shared/styles/mixins/focus'
;
...
@@ -139,142 +138,3 @@
...
@@ -139,142 +138,3 @@
color
:
var
.
$grey-semi
;
color
:
var
.
$grey-semi
;
}
}
}
}
/**
* Mixins that style buttons to appear as lozenges with an integrated arrow
* pointing left, up or down (right doesn't exist yet but could easily be added).
* These indicators are used, e.g., in the bucket bar.
*
* These button or button-like elements consist of styles applied to the
* element itself, which create a rounded-rectangle lozenge with small-sized
* label text, as well as composited ::before and ::after pseudo-elements to
* create an arrow-pointer effect.
*
* The arrow-points are created by the combination of borders and positioning.
* See https://css-tricks.com/snippets/css/css-triangle/ for a few examples
*
*/
$indicator-width
:
26px
;
$indicator-height
:
16px
;
// How far the arrow-pointer "sticks out" from the main body of the lozenge
$indicator-horizontal-offset
:
5px
;
$indicator-vertical-offset
:
6px
;
@mixin
indicator-base
{
@include
reset-native-btn-styles
;
@include
utils
.
border
;
position
:
absolute
;
right
:
0
;
background-color
:
var
.
$color-background
;
width
:
$indicator-width
;
height
:
$indicator-height
;
// Font/text
text-align
:
center
;
color
:
var
.
$color-text--light
;
font-weight
:
bold
;
font-family
:
var
.
$sans-font-family
;
font-size
:
var
.
$annotator-bucket-bar-font-size
;
line-height
:
1
;
&
:
:
before
,
&::
after
{
content
:
''
;
position
:
absolute
;
// NB: use of 'inset' here fixes jagged diagonals in FF
// https://github.com/zurb/foundation/issues/2230
border
:
inset
transparent
;
}
}
@mixin
indicator-vertical-base
{
@include
indicator-base
;
@include
utils
.
shadow
;
z-index
:
1
;
&
:
:
before
,
&::
after
{
left
:
50%
;
}
}
@mixin
indicator--left
{
@include
indicator-base
;
border-radius
:
2px
4px
4px
2px
;
&
:
:
before
,
&::
after
{
right
:
100%
;
top
:
50%
;
}
// This creates a left-pointing "wedge" in grey
// offset to the left of the element
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-height
,
2
);
border-right
:
$indicator-horizontal-offset
solid
var
.
$grey-3
;
margin-top
:
-1
*
math
.
div
(
$indicator-height
,
2
);
}
// This creates a left-pointing "wedge" in white, on top
// of the grey wedge and one pixel narrower so that the
// grey wedge appears as a border around it
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-height
,
2
)
-
1
;
border-right
:
(
$indicator-horizontal-offset
-
1
)
solid
var
.
$color-background
;
margin-top
:
-1
*
(
math
.
div
(
$indicator-height
,
2
)
-
1
);
}
}
@mixin
indicator--up
{
@include
indicator-vertical-base
;
border-radius
:
2px
2px
4px
4px
;
&
:
:
before
,
&::
after
{
top
:
auto
;
bottom
:
100%
;
}
// Grey (border) arrow pointing up
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-width
,
2
);
border-bottom
:
$indicator-vertical-offset
solid
var
.
$grey-3
;
margin-left
:
-1
*
math
.
div
(
$indicator-width
,
2
);
}
// White (fill) arrow pointing up
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-width
,
2
)
-
1
;
border-bottom
:
(
$indicator-vertical-offset
-
1
)
solid
var
.
$color-background
;
margin-left
:
-1
*
(
math
.
div
(
$indicator-width
,
2
)
-
1
);
}
}
@mixin
indicator--down
{
@include
indicator-vertical-base
;
margin-top
:
0
;
border-radius
:
4px
4px
2px
2px
;
&
:
:
before
,
&::
after
{
top
:
100%
;
}
// Grey (border) arrow, pointing down
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-width
,
2
);
border-top
:
$indicator-vertical-offset
solid
var
.
$grey-3
;
margin-left
:
-1
*
math
.
div
(
$indicator-width
,
2
);
}
// White (fill) arrow, pointing down
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-width
,
2
)
-
1
;
border-top
:
(
$indicator-vertical-offset
-
1
)
solid
var
.
$color-background
;
margin-left
:
-1
*
(
math
.
div
(
$indicator-width
,
2
)
-
1
);
}
}
tailwind.config.mjs
View file @
ad20c5f2
import
tailwindConfig
from
'@hypothesis/frontend-shared/lib/tailwind.preset.js'
;
import
tailwindConfig
from
'@hypothesis/frontend-shared/lib/tailwind.preset.js'
;
import
plugin
from
'tailwindcss/plugin.js'
;
export
default
{
export
default
{
presets
:
[
tailwindConfig
],
presets
:
[
tailwindConfig
],
...
@@ -81,8 +82,18 @@ export default {
...
@@ -81,8 +82,18 @@ export default {
},
},
},
},
zIndex
:
{
zIndex
:
{
1
:
'1'
,
2
:
'2'
,
2
:
'2'
,
},
},
},
},
},
},
plugins
:
[
plugin
(({
addVariant
})
=>
{
// Add a custom variant such that the `annotator-collapsed:` modifier
// is available. The `Sidebar` logic adds the `.annotator-collapsed`
// class to the sidebar frame when it's collapsed. This modifier allows
// sub-components to select for that state.
addVariant
(
'annotator-collapsed'
,
'.annotator-collapsed &'
);
}),
],
};
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment