-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(drawing): add color picker component #1300
Changes from 31 commits
8a7294c
dd420a0
7001a2a
0c80c2a
b231a3f
817eb1d
16657da
0471d7f
83187a6
68394ec
fdf5cff
011df39
efc5e41
589d2d2
731eec9
2c90cdd
c9ed901
9799954
4084bc5
33fd6ee
333800d
05763d8
b64b1a7
8d549cb
261831e
53afaf1
8e5cedb
a2f2636
c487c4d
1e4b91b
dcb5829
e6017f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@import '../styles'; | ||
|
||
.bp-ColorPickerControl { | ||
position: relative; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
|
||
.bp-ColorPickerControl-button { | ||
@include bp-ControlButton; | ||
} | ||
|
||
.bp-ColorPickerControl-palette { | ||
$arrow-height: 12px; | ||
|
||
position: absolute; | ||
top: -#{$arrow-height}; | ||
left: 50%; | ||
z-index: 1; | ||
padding-bottom: 10px; | ||
transform: translate(-50%, -100%); | ||
|
||
&::after { | ||
position: absolute; | ||
left: 50%; | ||
display: block; | ||
border-top: $arrow-height solid $bp-controls-background; | ||
border-right: $arrow-height solid transparent; | ||
border-left: $arrow-height solid transparent; | ||
transform: translateX(-50%); | ||
content: ''; | ||
} | ||
} | ||
|
||
.bp-ColorPickerControl-swatch { | ||
width: 18px; | ||
height: 18px; | ||
background-color: $box-blue; | ||
border: 2px solid #fff; | ||
border-radius: 2px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React, { useState } from 'react'; | ||
import classNames from 'classnames'; | ||
import ColorPickerPalette from './ColorPickerPalette'; | ||
import { AnnotationMode } from '../annotations/types'; | ||
import './ColorPickerControl.scss'; | ||
|
||
export type Props = { | ||
annotationMode?: AnnotationMode; | ||
onAnnotationColorClick: (color: string) => void; | ||
isActive?: boolean; | ||
}; | ||
|
||
export default function ColorPickerControl({ | ||
annotationMode, | ||
isActive = false, | ||
onAnnotationColorClick, | ||
...rest | ||
}: Props): JSX.Element | null { | ||
const [isColorPickerToggled, setIsColorPickerToggled] = useState(false); | ||
|
||
if (annotationMode !== AnnotationMode.DRAWING) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this picker need to know about annotations at all? Could the rendering of this |
||
return null; | ||
} | ||
|
||
return ( | ||
<div className="bp-ColorPickerControl"> | ||
{isColorPickerToggled && ( | ||
<div className="bp-ColorPickerControl-palette"> | ||
<ColorPickerPalette | ||
onColorSelect={(color: string): void => { | ||
setIsColorPickerToggled(false); | ||
onAnnotationColorClick(color); | ||
}} | ||
/> | ||
</div> | ||
)} | ||
<button | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need a resin tag and/or testid attributes? Similarly for the |
||
className={classNames('bp-ColorPickerControl-button', { | ||
'bp-is-active': isActive, | ||
})} | ||
onClick={(): void => setIsColorPickerToggled(!isColorPickerToggled)} | ||
type="button" | ||
{...rest} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems a bit odd to spread the |
||
> | ||
<div className="bp-ColorPickerControl-swatch" /> | ||
</button> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
@import '../styles'; | ||
|
||
.bp-ColorPickerPalette { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
padding: 0 8px; | ||
background: $bp-controls-background; | ||
border-radius: 4px; | ||
} | ||
|
||
.bp-ColorPickerPalette-button { | ||
width: 20px; | ||
height: 20px; | ||
margin: 10px 2px; | ||
padding: 0; | ||
border: none; | ||
border-radius: 4px; | ||
cursor: pointer; | ||
|
||
&:focus, | ||
&:hover { | ||
ChenCodes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
outline: 0; | ||
box-shadow: 0 0 0 2px #fff; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
import './ColorPickerPalette.scss'; | ||
|
||
export type Props = { | ||
onColorSelect: (color: string) => void; | ||
}; | ||
|
||
export default function ColorPickerPalette({ onColorSelect }: Props): JSX.Element { | ||
const colors = ['#0061d5', '#26c281', '#ed3757', '#f5b31b', '#ffd700', '#4826c2']; | ||
ChenCodes marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these colors be moved outside of the function? |
||
|
||
return ( | ||
<div className="bp-ColorPickerPalette"> | ||
{colors.map(color => { | ||
return ( | ||
<button | ||
key={color} | ||
className="bp-ColorPickerPalette-button" | ||
onClick={(): void => onColorSelect(color)} | ||
style={{ | ||
backgroundColor: color, | ||
}} | ||
type="button" | ||
/> | ||
); | ||
})} | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import * as React from 'react'; | ||
import { shallow, ShallowWrapper } from 'enzyme'; | ||
import { AnnotationMode } from '../../annotations/types'; | ||
import ColorPickerControl from '../ColorPickerControl'; | ||
|
||
describe('ColorPickerControl', () => { | ||
const onAnnotationColorClick = jest.fn(); | ||
|
||
const getWrapper = (props = {}): ShallowWrapper => | ||
shallow(<ColorPickerControl onAnnotationColorClick={onAnnotationColorClick} {...props} />); | ||
|
||
const getToggleButton = (wrapper: ShallowWrapper): ShallowWrapper => wrapper.find('.bp-ColorPickerControl-button'); | ||
|
||
describe('render', () => { | ||
test('should render null if annotationMode is not AnnotationMode.DRAWING', () => { | ||
const wrapper = getWrapper({ annotationMode: AnnotationMode.REGION }); | ||
|
||
expect(wrapper.isEmptyRender()).toBe(true); | ||
}); | ||
|
||
test('should not render ColorPickerPalette when the component is first mounted', () => { | ||
const wrapper = getWrapper(); | ||
|
||
expect(wrapper.find('ColorPickerPalette').exists()).toBe(false); | ||
}); | ||
|
||
test('should render ColorPickerPalette when the toggle button is clicked', () => { | ||
const wrapper = getWrapper({ annotationMode: AnnotationMode.DRAWING }); | ||
|
||
getToggleButton(wrapper).simulate('click'); | ||
|
||
expect(wrapper.find('ColorPickerPalette').exists()).toBe(true); | ||
}); | ||
|
||
test('should render the toggle button with bp-is-active set to true if isActive is true', () => { | ||
const wrapper = getWrapper({ annotationMode: AnnotationMode.DRAWING, isActive: true }); | ||
|
||
expect(getToggleButton(wrapper).hasClass('bp-is-active')).toBe(true); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react'; | ||
import { shallow, ShallowWrapper } from 'enzyme'; | ||
import ColorPickerPalette from '../ColorPickerPalette'; | ||
|
||
describe('ColorPickerPalette', () => { | ||
const onColorSelect = jest.fn(); | ||
|
||
const getWrapper = (props = {}): ShallowWrapper => | ||
shallow(<ColorPickerPalette onColorSelect={onColorSelect} {...props} />); | ||
|
||
describe('render', () => { | ||
test('should render the six color swatches', () => { | ||
const wrapper = getWrapper(); | ||
|
||
expect(wrapper.find('button').length).toBe(6); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './ColorPickerControl'; | ||
export { default } from './ColorPickerControl'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,8 @@ | |
align-items: center; | ||
background: fade-out($black, .2); | ||
border-radius: 3px; | ||
|
||
& + & { | ||
margin-left: 6px; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import React from 'react'; | ||
import AnnotationsControls, { Props as AnnotationsControlsProps } from '../controls/annotations'; | ||
import ColorPickerControl, { Props as ColorPickerControlProps } from '../controls/color-picker'; | ||
import ControlsBar from '../controls/controls-bar'; | ||
import FindBarToggle, { Props as FindBarToggleProps } from '../controls/findbar'; | ||
import FullscreenToggle, { Props as FullscreenToggleProps } from '../controls/fullscreen'; | ||
|
@@ -8,6 +9,7 @@ import ThumbnailsToggle, { Props as ThumbnailsToggleProps } from '../controls/si | |
import ZoomControls, { Props as ZoomControlsProps } from '../controls/zoom'; | ||
|
||
export type Props = AnnotationsControlsProps & | ||
ColorPickerControlProps & | ||
FindBarToggleProps & | ||
FullscreenToggleProps & | ||
PageControlsProps & | ||
|
@@ -21,6 +23,7 @@ export default function DocControls({ | |
hasRegion, | ||
maxScale, | ||
minScale, | ||
onAnnotationColorClick, | ||
onAnnotationModeClick, | ||
onAnnotationModeEscape, | ||
onFindBarToggle, | ||
|
@@ -35,31 +38,36 @@ export default function DocControls({ | |
scale, | ||
}: Props): JSX.Element { | ||
return ( | ||
<ControlsBar> | ||
<ThumbnailsToggle onThumbnailsToggle={onThumbnailsToggle} /> | ||
<FindBarToggle onFindBarToggle={onFindBarToggle} /> | ||
<ZoomControls | ||
maxScale={maxScale} | ||
minScale={minScale} | ||
onZoomIn={onZoomIn} | ||
onZoomOut={onZoomOut} | ||
scale={scale} | ||
/> | ||
<PageControls | ||
onPageChange={onPageChange} | ||
onPageSubmit={onPageSubmit} | ||
pageCount={pageCount} | ||
pageNumber={pageNumber} | ||
/> | ||
<FullscreenToggle onFullscreenToggle={onFullscreenToggle} /> | ||
<AnnotationsControls | ||
annotationMode={annotationMode} | ||
hasDrawing={hasDrawing} | ||
hasHighlight={hasHighlight} | ||
hasRegion={hasRegion} | ||
onAnnotationModeClick={onAnnotationModeClick} | ||
onAnnotationModeEscape={onAnnotationModeEscape} | ||
/> | ||
</ControlsBar> | ||
<> | ||
<ControlsBar> | ||
<ThumbnailsToggle onThumbnailsToggle={onThumbnailsToggle} /> | ||
<FindBarToggle onFindBarToggle={onFindBarToggle} /> | ||
<ZoomControls | ||
maxScale={maxScale} | ||
minScale={minScale} | ||
onZoomIn={onZoomIn} | ||
onZoomOut={onZoomOut} | ||
scale={scale} | ||
/> | ||
<PageControls | ||
onPageChange={onPageChange} | ||
onPageSubmit={onPageSubmit} | ||
pageCount={pageCount} | ||
pageNumber={pageNumber} | ||
/> | ||
<FullscreenToggle onFullscreenToggle={onFullscreenToggle} /> | ||
<AnnotationsControls | ||
annotationMode={annotationMode} | ||
hasDrawing={hasDrawing} | ||
hasHighlight={hasHighlight} | ||
hasRegion={hasRegion} | ||
onAnnotationModeClick={onAnnotationModeClick} | ||
onAnnotationModeEscape={onAnnotationModeEscape} | ||
/> | ||
</ControlsBar> | ||
<ControlsBar> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be added to the |
||
<ColorPickerControl annotationMode={annotationMode} onAnnotationColorClick={onAnnotationColorClick} /> | ||
</ControlsBar> | ||
</> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 🔤