mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor(console): improve color picker (#3648)
This commit is contained in:
parent
1c431e7a59
commit
6773a3ae35
5 changed files with 119 additions and 44 deletions
|
@ -44,6 +44,7 @@
|
|||
"@types/mdx": "^2.0.1",
|
||||
"@types/mdx-js__react": "^1.5.5",
|
||||
"@types/react": "^18.0.31",
|
||||
"@types/react-color": "^3.0.6",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/react-helmet": "^6.1.6",
|
||||
"@types/react-modal": "^3.13.1",
|
||||
|
@ -76,6 +77,7 @@
|
|||
"prop-types": "^15.8.1",
|
||||
"react": "^18.0.0",
|
||||
"react-animate-height": "^3.0.4",
|
||||
"react-color": "^2.19.3",
|
||||
"react-dnd": "^16.0.0",
|
||||
"react-dnd-html5-backend": "^16.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
|
|
|
@ -7,48 +7,24 @@
|
|||
transition-property: outline, border;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 0.2s;
|
||||
padding: _.unit(2) _.unit(3);
|
||||
padding: _.unit(1.5) _.unit(3);
|
||||
font: var(--font-body-2);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:focus-within {
|
||||
&:focus,
|
||||
&.highlight {
|
||||
border-color: var(--color-primary);
|
||||
outline-color: var(--color-focused-variant);
|
||||
}
|
||||
|
||||
input {
|
||||
.brick {
|
||||
flex-shrink: 0;
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--color-divider);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
&::-moz-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&::-moz-color-swatch {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
&::-webkit-color-swatch {
|
||||
border-style: none;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
flex: 1;
|
||||
margin-left: _.unit(2);
|
||||
margin-right: _.unit(2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,53 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useRef, useState } from 'react';
|
||||
import { ChromePicker } from 'react-color';
|
||||
|
||||
import { onKeyDownHandler } from '@/utils/a11y';
|
||||
|
||||
import Dropdown from '../Dropdown';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
function ColorPicker({ onChange, value = '#000000' }: Props) {
|
||||
const [id, setId] = useState(nanoid());
|
||||
|
||||
const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||
onChange?.(event.target.value);
|
||||
};
|
||||
const anchorRef = useRef<HTMLSpanElement>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<input type="color" id={id} value={value} onChange={handleChange} />
|
||||
<label htmlFor={id}>{value.toUpperCase()}</label>
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
className={classNames(styles.container, isOpen && styles.highlight)}
|
||||
onClick={() => {
|
||||
setIsOpen(true);
|
||||
}}
|
||||
onKeyDown={onKeyDownHandler(() => {
|
||||
setIsOpen(true);
|
||||
})}
|
||||
>
|
||||
<span ref={anchorRef} className={styles.brick} style={{ backgroundColor: value }} />
|
||||
<span>{value.toUpperCase()}</span>
|
||||
<Dropdown
|
||||
anchorRef={anchorRef}
|
||||
isOpen={isOpen}
|
||||
horizontalAlign="start"
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
<ChromePicker
|
||||
color={value}
|
||||
onChange={({ hex }) => {
|
||||
onChange(hex);
|
||||
}}
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ColorPicker;
|
||||
|
|
|
@ -79,7 +79,14 @@ function Dropdown({
|
|||
}}
|
||||
className={classNames(styles.content, positionState.verticalAlign === 'top' && styles.onTop)}
|
||||
overlayClassName={styles.overlay}
|
||||
onRequestClose={onClose}
|
||||
onRequestClose={(event) => {
|
||||
/**
|
||||
* Note:
|
||||
* we should stop propagation to prevent the event from bubbling up when we click on the overlay to close the dropdown.
|
||||
*/
|
||||
event.stopPropagation();
|
||||
onClose?.();
|
||||
}}
|
||||
onAfterOpen={mutate}
|
||||
>
|
||||
<div ref={overlayRef} className={styles.dropdownContainer}>
|
||||
|
|
|
@ -398,6 +398,9 @@ importers:
|
|||
'@types/react':
|
||||
specifier: ^18.0.31
|
||||
version: 18.0.31
|
||||
'@types/react-color':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
'@types/react-dom':
|
||||
specifier: ^18.0.0
|
||||
version: 18.0.6
|
||||
|
@ -494,6 +497,9 @@ importers:
|
|||
react-animate-height:
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4(react-dom@18.2.0)(react@18.2.0)
|
||||
react-color:
|
||||
specifier: ^2.19.3
|
||||
version: 2.19.3(react@18.2.0)
|
||||
react-dnd:
|
||||
specifier: ^16.0.0
|
||||
version: 16.0.0(@types/node@18.11.18)(@types/react@18.0.31)(react@18.2.0)
|
||||
|
@ -2542,6 +2548,14 @@ packages:
|
|||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||
dev: true
|
||||
|
||||
/@icons/material@0.2.4(react@18.2.0):
|
||||
resolution: {integrity: sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/@istanbuljs/load-nyc-config@1.1.0:
|
||||
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -5048,6 +5062,13 @@ packages:
|
|||
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
||||
dev: true
|
||||
|
||||
/@types/react-color@3.0.6:
|
||||
resolution: {integrity: sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.31
|
||||
'@types/reactcss': 1.2.6
|
||||
dev: true
|
||||
|
||||
/@types/react-dom@18.0.6:
|
||||
resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==}
|
||||
dependencies:
|
||||
|
@ -5095,6 +5116,12 @@ packages:
|
|||
csstype: 3.0.11
|
||||
dev: true
|
||||
|
||||
/@types/reactcss@1.2.6:
|
||||
resolution: {integrity: sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.31
|
||||
dev: true
|
||||
|
||||
/@types/retry@0.12.1:
|
||||
resolution: {integrity: sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==}
|
||||
dev: false
|
||||
|
@ -10632,6 +10659,10 @@ packages:
|
|||
p-locate: 6.0.0
|
||||
dev: false
|
||||
|
||||
/lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
dev: true
|
||||
|
||||
/lodash.camelcase@4.3.0:
|
||||
resolution: {integrity: sha1-soqmKIorn8ZRA1x3EfZathkDMaY=}
|
||||
dev: true
|
||||
|
@ -10798,6 +10829,10 @@ packages:
|
|||
resolution: {integrity: sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==}
|
||||
dev: true
|
||||
|
||||
/material-colors@1.2.6:
|
||||
resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==}
|
||||
dev: true
|
||||
|
||||
/mathml-tag-names@2.1.3:
|
||||
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
||||
dev: true
|
||||
|
@ -12810,6 +12845,21 @@ packages:
|
|||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: true
|
||||
|
||||
/react-color@2.19.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
dependencies:
|
||||
'@icons/material': 0.2.4(react@18.2.0)
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
material-colors: 1.2.6
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
reactcss: 1.2.3(react@18.2.0)
|
||||
tinycolor2: 1.6.0
|
||||
dev: true
|
||||
|
||||
/react-device-detect@2.2.2(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==}
|
||||
peerDependencies:
|
||||
|
@ -13140,6 +13190,15 @@ packages:
|
|||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
/reactcss@1.2.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/read-pkg-up@7.0.1:
|
||||
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -14576,6 +14635,10 @@ packages:
|
|||
globrex: 0.1.2
|
||||
dev: true
|
||||
|
||||
/tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
dev: true
|
||||
|
||||
/tmp@0.0.33:
|
||||
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
|
||||
engines: {node: '>=0.6.0'}
|
||||
|
|
Loading…
Reference in a new issue