-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(controls): Add react version of annotations controls (#1291)
- Loading branch information
Showing
31 changed files
with
517 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
src/lib/viewers/controls/annotations/AnnotationsButton.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@import '~box-ui-elements/es/styles/variables'; | ||
@import '../styles'; | ||
|
||
.bp-AnnotationsButton { | ||
@include bp-ControlButton; | ||
|
||
svg { | ||
width: 34px; | ||
height: 32px; | ||
padding: 4px 5px; | ||
border-radius: 4px; | ||
fill: $white; | ||
} | ||
|
||
&.bp-is-active { | ||
svg { | ||
background-color: $white; | ||
fill: $black; | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/lib/viewers/controls/annotations/AnnotationsButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React, { ButtonHTMLAttributes } from 'react'; | ||
import classNames from 'classnames'; | ||
import noop from 'lodash/noop'; | ||
import { AnnotationMode } from './types'; | ||
import './AnnotationsButton.scss'; | ||
|
||
export type Props = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> & { | ||
children?: React.ReactNode; | ||
className?: string; | ||
isActive?: boolean; | ||
isEnabled?: boolean; | ||
mode: AnnotationMode; | ||
onClick?: (mode: AnnotationMode) => void; | ||
}; | ||
|
||
export default function AnnotationsButton({ | ||
children, | ||
className, | ||
isActive = false, | ||
isEnabled = true, | ||
mode, | ||
onClick = noop, | ||
...rest | ||
}: Props): JSX.Element | null { | ||
if (!isEnabled) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<button | ||
className={classNames('bp-AnnotationsButton', className, { | ||
'bp-is-active': isActive, | ||
})} | ||
onClick={(): void => onClick(mode)} | ||
type="button" | ||
{...rest} | ||
> | ||
{children} | ||
</button> | ||
); | ||
} |
9 changes: 9 additions & 0 deletions
9
src/lib/viewers/controls/annotations/AnnotationsControls.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
@import '~box-ui-elements/es/styles/variables'; | ||
@import '../styles'; | ||
|
||
.bp-AnnotationsControls { | ||
@include bp-ControlGroup; | ||
|
||
padding-left: 4px; | ||
border-left: 1px solid $twos; | ||
} |
87 changes: 87 additions & 0 deletions
87
src/lib/viewers/controls/annotations/AnnotationsControls.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React from 'react'; | ||
import noop from 'lodash/noop'; | ||
import AnnotationsButton from './AnnotationsButton'; | ||
import IconHighlightText16 from '../icons/IconHighlightText16'; | ||
import IconRegion24 from '../icons/IconRegion24'; | ||
import useFullscreen from '../hooks/useFullscreen'; | ||
import { AnnotationMode } from './types'; | ||
import './AnnotationsControls.scss'; | ||
|
||
export type Props = { | ||
annotationMode?: AnnotationMode; | ||
hasHighlight?: boolean; | ||
hasRegion?: boolean; | ||
onAnnotationModeClick?: ({ mode }: { mode: AnnotationMode }) => void; | ||
onAnnotationModeEscape?: () => void; | ||
}; | ||
|
||
export default function AnnotationsControls({ | ||
annotationMode = AnnotationMode.NONE, | ||
hasHighlight = false, | ||
hasRegion = false, | ||
onAnnotationModeClick = noop, | ||
onAnnotationModeEscape = noop, | ||
}: Props): JSX.Element | null { | ||
const isFullscreen = useFullscreen(); | ||
const showHighlight = !isFullscreen && hasHighlight; | ||
const showRegion = !isFullscreen && hasRegion; | ||
|
||
// Component event handlers | ||
const handleModeClick = (mode: AnnotationMode): void => { | ||
onAnnotationModeClick({ mode: annotationMode === mode ? AnnotationMode.NONE : mode }); | ||
}; | ||
|
||
// Global event handlers | ||
React.useEffect(() => { | ||
const handleKeyDown = (event: KeyboardEvent): void => { | ||
if (event.key !== 'Escape') { | ||
return; | ||
} | ||
|
||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
onAnnotationModeEscape(); | ||
}; | ||
|
||
if (annotationMode !== AnnotationMode.NONE) { | ||
document.addEventListener('keydown', handleKeyDown); | ||
} | ||
|
||
return (): void => { | ||
document.removeEventListener('keydown', handleKeyDown); | ||
}; | ||
}, [annotationMode, onAnnotationModeEscape]); | ||
|
||
// Prevent empty group from being displayed | ||
if (!showHighlight && !showRegion) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className="bp-AnnotationsControls"> | ||
<AnnotationsButton | ||
data-resin-target="highlightRegion" | ||
data-testid="bp-AnnotationsControls-regionBtn" | ||
isActive={annotationMode === AnnotationMode.REGION} | ||
isEnabled={showRegion} | ||
mode={AnnotationMode.REGION} | ||
onClick={handleModeClick} | ||
title={__('region_comment')} | ||
> | ||
<IconRegion24 /> | ||
</AnnotationsButton> | ||
<AnnotationsButton | ||
data-resin-target="highlightText" | ||
data-testid="bp-AnnotationsControls-highlightBtn" | ||
isActive={annotationMode === AnnotationMode.HIGHLIGHT} | ||
isEnabled={showHighlight} | ||
mode={AnnotationMode.HIGHLIGHT} | ||
onClick={handleModeClick} | ||
title={__('highlight_text')} | ||
> | ||
<IconHighlightText16 /> | ||
</AnnotationsButton> | ||
</div> | ||
); | ||
} |
40 changes: 40 additions & 0 deletions
40
src/lib/viewers/controls/annotations/__tests__/AnnotationsButton-test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React from 'react'; | ||
import { shallow, ShallowWrapper } from 'enzyme'; | ||
import AnnotationsButton from '../AnnotationsButton'; | ||
import { AnnotationMode } from '../types'; | ||
|
||
describe('AnnotationsButton', () => { | ||
const getWrapper = (props = {}): ShallowWrapper => | ||
shallow( | ||
<AnnotationsButton mode={AnnotationMode.REGION} onClick={jest.fn()} {...props}> | ||
Test | ||
</AnnotationsButton>, | ||
); | ||
|
||
describe('event handlers', () => { | ||
test('should call the onClick callback with the given mode', () => { | ||
const mode = AnnotationMode.HIGHLIGHT; | ||
const onClick = jest.fn(); | ||
const wrapper = getWrapper({ mode, onClick }); | ||
|
||
wrapper.simulate('click'); | ||
|
||
expect(onClick).toBeCalledWith(mode); | ||
}); | ||
}); | ||
|
||
describe('render', () => { | ||
test('should return nothing if not enabled', () => { | ||
const wrapper = getWrapper({ isEnabled: false }); | ||
expect(wrapper.isEmptyRender()).toBe(true); | ||
}); | ||
|
||
test('should return a valid wrapper', () => { | ||
const wrapper = getWrapper(); | ||
|
||
expect(wrapper.hasClass('bp-AnnotationsButton')).toBe(true); | ||
expect(wrapper.hasClass('bp-is-active')).toBe(false); // Default | ||
expect(wrapper.text()).toBe('Test'); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.