-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8ce4484
commit 58045a0
Showing
11 changed files
with
542 additions
and
74 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
93 changes: 93 additions & 0 deletions
93
assets/src/edit-story/components/colorPicker/editableHexPreview.js
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,93 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
import PropTypes from 'prop-types'; | ||
import styled from 'styled-components'; | ||
import { EditableInput } from 'react-color/lib/components/common'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useCallback, useLayoutEffect, useState } from '@wordpress/element'; | ||
|
||
const Preview = styled.button` | ||
padding: 0; | ||
margin: 0; | ||
border: none; | ||
background: ${({ theme }) => theme.colors.bg.v7}; | ||
color: ${({ theme }) => theme.colors.fg.v1}; | ||
`; | ||
|
||
const inputStyles = { | ||
/* stylelint-disable-next-line rule-empty-line-before */ | ||
input: { | ||
fontFamily: 'monospace', | ||
width: '60px', | ||
}, | ||
}; | ||
|
||
function EditableHexPreview({ hex, onChange }) { | ||
const [isEditing, setIsEditing] = useState(false); | ||
|
||
// Handle ESC keypress to toggle input field. | ||
const handleKeyPress = useCallback( | ||
(evt) => { | ||
if ('Escape' === evt.key && isEditing) { | ||
evt.stopPropagation(); | ||
evt.preventDefault(); | ||
setIsEditing(false); | ||
} | ||
}, | ||
[isEditing] | ||
); | ||
|
||
useLayoutEffect(() => { | ||
document.addEventListener('keydown', handleKeyPress); | ||
|
||
return () => document.removeEventListener('keydown', handleKeyPress); | ||
}, [handleKeyPress]); | ||
|
||
const handleOnBlur = (evt) => { | ||
if (!evt.currentTarget.contains(document.activeElement)) { | ||
setIsEditing(false); | ||
} | ||
}; | ||
|
||
if (!isEditing) { | ||
return <Preview onClick={() => setIsEditing(true)}>{hex}</Preview>; | ||
} | ||
|
||
return ( | ||
<div tabIndex={-1} onBlur={handleOnBlur}> | ||
<EditableInput | ||
value={hex} | ||
onChange={onChange} | ||
onChangeComplete={() => setIsEditing(false)} | ||
style={inputStyles} | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
EditableHexPreview.propTypes = { | ||
hex: PropTypes.string, | ||
onChange: PropTypes.func.isRequired, | ||
}; | ||
|
||
export default EditableHexPreview; |
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,211 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
import PropTypes from 'prop-types'; | ||
import styled from 'styled-components'; | ||
import { CustomPicker } from 'react-color'; | ||
import { Saturation, Hue, Alpha } from 'react-color/lib/components/common'; | ||
import { rgba } from 'polished'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { Close, Eyedropper } from '../button'; | ||
import Pointer from './pointer'; | ||
import EditableHexPreview from './editableHexPreview'; | ||
|
||
const CONTAINER_PADDING = 15; | ||
const EYEDROPPER_ICON_SIZE = 15; | ||
const HEADER_FOOTER_HEIGHT = 50; | ||
const BODY_HEIGHT = 140; | ||
const CONTROLS_WIDTH = 12; | ||
const CONTROLS_BORDER_RADIUS = 6; | ||
|
||
const Container = styled.div` | ||
border-radius: 4px; | ||
background: ${({ theme }) => theme.colors.bg.v7}; | ||
color: ${({ theme }) => theme.colors.fg.v1}; | ||
width: 240px; | ||
font-family: ${({ theme }) => theme.fonts.body1.family}; | ||
font-style: normal; | ||
font-weight: normal; | ||
font-size: 12px; | ||
user-select: none; | ||
`; | ||
|
||
const Header = styled.div` | ||
height: ${HEADER_FOOTER_HEIGHT}px; | ||
padding: ${CONTAINER_PADDING}px; | ||
border-bottom: 1px solid ${({ theme }) => rgba(theme.colors.fg.v2, 0.2)}; | ||
position: relative; | ||
`; | ||
|
||
const CloseButton = styled(Close)` | ||
opacity: 1; | ||
font-size: 15px; | ||
line-height: 20px; | ||
position: absolute; | ||
right: ${CONTAINER_PADDING}px; | ||
top: ${CONTAINER_PADDING}px; | ||
`; | ||
|
||
const Body = styled.div` | ||
padding: ${CONTAINER_PADDING}px; | ||
padding-bottom: 0; | ||
display: grid; | ||
grid: 'saturation hue alpha' ${BODY_HEIGHT}px / 1fr ${CONTROLS_WIDTH}px ${CONTROLS_WIDTH}px; | ||
grid-gap: 10px; | ||
`; | ||
|
||
const SaturationWrapper = styled.div` | ||
position: relative; | ||
width: 167px; | ||
height: ${BODY_HEIGHT}px; | ||
grid-area: saturation; | ||
`; | ||
|
||
const HueWrapper = styled.div` | ||
position: relative; | ||
height: ${BODY_HEIGHT}px; | ||
width: ${CONTROLS_WIDTH}px; | ||
grid-area: hue; | ||
`; | ||
|
||
const AlphaWrapper = styled.div` | ||
position: relative; | ||
height: ${BODY_HEIGHT}px; | ||
width: ${CONTROLS_WIDTH}px; | ||
background: #fff; | ||
border-radius: ${CONTROLS_BORDER_RADIUS}px; | ||
grid-area: alpha; | ||
`; | ||
|
||
const Footer = styled.div` | ||
padding: ${CONTAINER_PADDING}px; | ||
height: ${HEADER_FOOTER_HEIGHT}px; | ||
font-size: ${CONTROLS_WIDTH}px; | ||
line-height: 19px; | ||
position: relative; | ||
`; | ||
|
||
const EyedropperWrapper = styled.div` | ||
position: absolute; | ||
left: ${CONTAINER_PADDING}px; | ||
bottom: ${CONTAINER_PADDING}px; | ||
`; | ||
|
||
const EyedropperButton = styled(Eyedropper)` | ||
line-height: ${EYEDROPPER_ICON_SIZE}px; | ||
`; | ||
|
||
const CurrentWrapper = styled.div` | ||
position: absolute; | ||
left: 0; | ||
right: 0; | ||
text-align: center; | ||
bottom: ${CONTAINER_PADDING}px; | ||
`; | ||
|
||
const CurrentAlphaWrapper = styled.div` | ||
position: absolute; | ||
right: ${CONTAINER_PADDING}px; | ||
bottom: ${CONTAINER_PADDING}px; | ||
`; | ||
|
||
function ColorPicker({ rgb, hsl, hsv, hex, onChange, onClose }) { | ||
const alphaPercentage = Math.round(rgb.a * 100); | ||
|
||
return ( | ||
<Container> | ||
<Header> | ||
<CloseButton | ||
width={10} | ||
height={10} | ||
aria-label={__('Close', 'web-stories')} | ||
onClick={onClose} | ||
/> | ||
</Header> | ||
<Body> | ||
<SaturationWrapper> | ||
<Saturation | ||
radius={`${CONTROLS_BORDER_RADIUS}px`} | ||
pointer={() => <Pointer offset={-6} currentColor={rgb} />} | ||
hsl={hsl} | ||
hsv={hsv} | ||
onChange={onChange} | ||
/> | ||
</SaturationWrapper> | ||
<HueWrapper> | ||
<Hue | ||
direction="vertical" | ||
width={`${CONTROLS_WIDTH}px`} | ||
height={`${BODY_HEIGHT}px`} | ||
radius={`${CONTROLS_BORDER_RADIUS}px`} | ||
pointer={() => <Pointer offset={0} currentColor={rgb} />} | ||
hsl={hsl} | ||
onChange={onChange} | ||
/> | ||
</HueWrapper> | ||
<AlphaWrapper> | ||
<Alpha | ||
direction="vertical" | ||
width={`${CONTROLS_WIDTH}px`} | ||
height={`${BODY_HEIGHT}px`} | ||
radius={`${CONTROLS_BORDER_RADIUS}px`} | ||
pointer={() => <Pointer offset={-3} currentColor={rgb} withAlpha />} | ||
rgb={rgb} | ||
hsl={hsl} | ||
onChange={onChange} | ||
/> | ||
</AlphaWrapper> | ||
</Body> | ||
<Footer> | ||
{/* TODO: implement (see https://github.com/google/web-stories-wp/issues/262) */} | ||
<EyedropperWrapper> | ||
<EyedropperButton | ||
width={EYEDROPPER_ICON_SIZE} | ||
height={EYEDROPPER_ICON_SIZE} | ||
aria-label={__('Select color', 'web-stories')} | ||
isDisabled | ||
/> | ||
</EyedropperWrapper> | ||
<CurrentWrapper> | ||
<EditableHexPreview hex={hex} onChange={onChange} /> | ||
</CurrentWrapper> | ||
<CurrentAlphaWrapper>{alphaPercentage + '%'}</CurrentAlphaWrapper> | ||
</Footer> | ||
</Container> | ||
); | ||
} | ||
|
||
ColorPicker.propTypes = { | ||
onChange: PropTypes.func.isRequired, | ||
onClose: PropTypes.func, | ||
rgb: PropTypes.object, | ||
hex: PropTypes.string, | ||
hsl: PropTypes.object, | ||
hsv: PropTypes.object, | ||
}; | ||
|
||
export default CustomPicker(ColorPicker); |
Oops, something went wrong.