Skip to content

Commit 37b53a3

Browse files
committed
build: Add sandbox page for easier development
1 parent 31b2145 commit 37b53a3

16 files changed

+10461
-419
lines changed

.editorconfig

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 4
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
insert_final_newline = false
13+
trim_trailing_whitespace = false

.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PUBLIC_URL="/"

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ yarn-error.log*
1616
*.ntvs*
1717
*.njsproj
1818
*.sln
19+
20+
# local .eslintcache file
21+
.eslintcache

package.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"dist"
1010
],
1111
"scripts": {
12-
"build": "rollup -c",
13-
"start": "rollup -c -w"
12+
"start": "react-scripts start",
13+
"build": "rollup -c"
1414
},
1515
"dependencies": {
1616
"@radial-color-picker/color-wheel": "2.2.1",
@@ -23,16 +23,17 @@
2323
"@babel/preset-react": "7.9.4",
2424
"autoprefixer": "9.7.6",
2525
"postcss": "7.0.27",
26-
"react": "16.13.1",
27-
"react-dom": "16.13.1",
26+
"react": "17.0.1",
27+
"react-dom": "17.0.1",
28+
"react-scripts": "4.0.1",
2829
"rollup": "2.6.1",
2930
"rollup-plugin-babel": "4.4.0",
3031
"rollup-plugin-node-resolve": "5.2.0",
3132
"rollup-plugin-postcss": "2.6.4",
3233
"rollup-plugin-terser": "5.3.0"
3334
},
3435
"peerDependencies": {
35-
"react": "^16.7.0"
36+
"react": "^16.7.0 || ^17.0.0"
3637
},
3738
"homepage": "https://github.com/radial-color-picker/react-color-picker#readme",
3839
"repository": "[email protected]:radial-color-picker/react-color-picker.git",

prettier.config.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
printWidth: 120,
3+
singleQuote: true,
4+
tabWidth: 4,
5+
trailingComma: 'es5',
6+
arrowParens: 'avoid',
7+
};

public/favicon.ico

3.78 KB
Binary file not shown.

public/index.html

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
9+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
10+
<title>React Color Picker</title>
11+
</head>
12+
<body>
13+
<div id="root"></div>
14+
</body>
15+
</html>

public/logo192.png

5.22 KB
Loading

public/logo512.png

9.44 KB
Loading

public/manifest.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"short_name": "React Color Picker",
3+
"name": "React Color Picker Sandbox",
4+
"icons": [
5+
{
6+
"src": "favicon.ico",
7+
"sizes": "64x64 32x32 24x24 16x16",
8+
"type": "image/x-icon"
9+
},
10+
{
11+
"src": "logo192.png",
12+
"type": "image/png",
13+
"sizes": "192x192"
14+
},
15+
{
16+
"src": "logo512.png",
17+
"type": "image/png",
18+
"sizes": "512x512"
19+
}
20+
],
21+
"start_url": ".",
22+
"display": "standalone",
23+
"theme_color": "#000000",
24+
"background_color": "#ffffff"
25+
}

rollup.config.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import { terser } from 'rollup-plugin-terser';
44
import postcss from 'rollup-plugin-postcss';
55
import resolve from 'rollup-plugin-node-resolve';
66

7+
const input = 'src/ColorPicker/index.js';
78
const file = 'dist/react-color-picker';
89

910
export default [
1011
{
11-
input: 'src/index.js',
12+
input,
1213
output: [
1314
{ file: `${file}.cjs.js`, format: 'cjs' },
1415
{ file: `${file}.esm.js`, format: 'esm' }
@@ -24,7 +25,7 @@ export default [
2425
]
2526
},
2627
{
27-
input: 'src/index.js',
28+
input,
2829
output: {
2930
file: `${file}.umd.js`,
3031
format: 'umd',
@@ -47,7 +48,7 @@ export default [
4748
]
4849
},
4950
{
50-
input: 'src/index.js',
51+
input,
5152
output: {
5253
file: `${file}.umd.min.js`,
5354
format: 'umd',

src/App.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useState } from 'react';
2+
import ColorPicker from './ColorPicker';
3+
import './ColorPicker/style.css';
4+
5+
function App() {
6+
const [color, setColor] = useState({ hue: 90, saturation: 100, luminosity: 50, alpha: 1 });
7+
8+
const onInput = (hue) => {
9+
setColor((prev) => ({ ...prev, hue }));
10+
};
11+
12+
return (
13+
<div className="App">
14+
<ColorPicker {...color} onInput={onInput} />
15+
</div>
16+
);
17+
}
18+
19+
export default App;

src/ColorPicker/index.js

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import React from 'react';
2+
import fillColorWheel from '@radial-color-picker/color-wheel';
3+
import Rotator from '@radial-color-picker/rotator';
4+
5+
const noop = () => {};
6+
7+
export default class ColorPicker extends React.Component {
8+
paletteRef = React.createRef();
9+
rotatorRef = React.createRef();
10+
elRef = React.createRef();
11+
12+
rotator = null;
13+
14+
state = {
15+
isKnobIn: !this.props.initiallyCollapsed,
16+
isPaletteIn: !this.props.initiallyCollapsed,
17+
isPressed: false,
18+
isRippling: false,
19+
isDragging: false,
20+
};
21+
22+
static defaultProps = {
23+
hue: 0,
24+
saturation: 100,
25+
luminosity: 50,
26+
alpha: 1,
27+
step: 2,
28+
mouseScroll: false,
29+
variant: 'collapsible', // collapsible | persistent
30+
disabled: false,
31+
initiallyCollapsed: false,
32+
onInput: noop,
33+
onChange: noop,
34+
};
35+
36+
componentDidMount() {
37+
if (this.props.mouseScroll) {
38+
this.rotatorRef.current.addEventListener('wheel', this.onScroll);
39+
}
40+
41+
if (this.props.initiallyCollapsed && this.props.variant === 'persistent') {
42+
console.warn(`Incorrect config: using variant="persistent" and initiallyCollapsed={true} at the same time is not supported.`);
43+
}
44+
45+
const isConicGradientSupported = getComputedStyle(this.paletteRef.current)
46+
.backgroundImage
47+
.includes('conic');
48+
49+
if (!isConicGradientSupported) {
50+
fillColorWheel(
51+
this.paletteRef.current.firstElementChild,
52+
this.elRef.current.offsetWidth || 280
53+
);
54+
}
55+
56+
this.rotator = new Rotator(this.rotatorRef.current, {
57+
angle: this.props.hue,
58+
onRotate: this.updateColor,
59+
onDragStart: () => {
60+
this.setState({ isDragging: true });
61+
},
62+
onDragStop: () => {
63+
this.setState({ isDragging: false });
64+
},
65+
});
66+
}
67+
68+
componentDidUpdate(prevProps) {
69+
if (this.props.hue !== prevProps.hue) {
70+
this.rotator.angle = this.props.hue;
71+
}
72+
}
73+
74+
componentWillUnmount() {
75+
this.rotator.destroy();
76+
this.rotator = null;
77+
78+
if (this.props.mouseScroll) {
79+
this.rotatorRef.current.removeEventListener('wheel', this.onScroll);
80+
}
81+
}
82+
83+
onScroll = ev => {
84+
if (this.state.isPressed || !this.state.isKnobIn)
85+
return;
86+
87+
ev.preventDefault();
88+
89+
if (ev.deltaY > 0) {
90+
this.rotator.angle += this.props.step;
91+
} else {
92+
this.rotator.angle -= this.props.step;
93+
}
94+
95+
this.updateColor(this.rotator.angle);
96+
};
97+
98+
onKeyUp = ev => {
99+
if (ev.key === 'Enter') {
100+
this.selectColor();
101+
}
102+
};
103+
104+
onKeyDown = ev => {
105+
if (this.props.disabled || this.state.isPressed || !this.state.isKnobIn)
106+
return;
107+
108+
const isIncrementing = ev.key === 'ArrowUp' || ev.key === 'ArrowRight';
109+
const isDecrementing = ev.key === 'ArrowDown' || ev.key === 'ArrowLeft';
110+
111+
if (isIncrementing || isDecrementing) {
112+
ev.preventDefault();
113+
114+
let multiplier = isIncrementing ? 1 : -1;
115+
116+
if (ev.ctrlKey) {
117+
multiplier *= 6;
118+
} else if (ev.shiftKey) {
119+
multiplier *= 3;
120+
}
121+
122+
this.rotator.angle += this.props.step * multiplier;
123+
this.updateColor(this.rotator.angle);
124+
}
125+
};
126+
127+
updateColor = hue => {
128+
this.props.onInput(hue);
129+
};
130+
131+
rotateToMouse = ev => {
132+
if (this.state.isPressed || !this.state.isKnobIn || ev.target !== this.rotatorRef.current)
133+
return;
134+
135+
this.rotator.setAngleFromEvent(ev);
136+
};
137+
138+
selectColor = () => {
139+
this.setState({ isPressed: true });
140+
141+
if (this.state.isPaletteIn && this.state.isKnobIn) {
142+
this.props.onChange(this.props.hue);
143+
this.setState({ isRippling: true });
144+
} else {
145+
this.setState({ isPaletteIn: true });
146+
}
147+
};
148+
149+
togglePicker = () => {
150+
if (this.props.variant !== 'persistent') {
151+
if (this.state.isKnobIn) {
152+
this.setState({ isKnobIn: false });
153+
} else {
154+
this.setState({
155+
isKnobIn: true,
156+
isPaletteIn: true,
157+
});
158+
}
159+
}
160+
161+
this.setState({
162+
isRippling: false,
163+
isPressed: false,
164+
});
165+
};
166+
167+
hidePalette = () => {
168+
if (!this.state.isKnobIn) {
169+
this.setState({ isPaletteIn: false });
170+
}
171+
};
172+
173+
render() {
174+
const { disabled, hue, saturation, luminosity, alpha } = this.props;
175+
const { isDragging, isPressed, isPaletteIn, isKnobIn, isRippling } = this.state;
176+
177+
const color = `hsla(${hue}, ${saturation}%, ${luminosity}%, ${alpha})`;
178+
179+
return (
180+
<div
181+
ref={this.elRef}
182+
className={`rcp ${isDragging ? 'dragging' : ''} ${disabled ? 'disabled' : ''}`.trim()}
183+
tabIndex={disabled ? -1 : 0}
184+
onKeyUp={this.onKeyUp}
185+
onKeyDown={this.onKeyDown}
186+
>
187+
<div
188+
ref={this.paletteRef}
189+
className={`rcp__palette ${isPaletteIn ? 'in' : 'out'}`}
190+
>
191+
<canvas />
192+
</div>
193+
194+
<div
195+
ref={this.rotatorRef}
196+
className="rcp__rotator"
197+
style={{ pointerEvents: disabled || isPressed || !isKnobIn ? 'none' : null }}
198+
onDoubleClick={this.rotateToMouse}
199+
>
200+
<div
201+
className={`rcp__knob ${isKnobIn ? 'in' : 'out'}`}
202+
onTransitionEnd={this.hidePalette}
203+
/>
204+
</div>
205+
206+
<div
207+
className={`rcp__ripple ${isRippling ? 'rippling' : ''}`.trim()}
208+
style={{ borderColor: color }}
209+
/>
210+
211+
<button
212+
type="button"
213+
className={`rcp__well ${isPressed ? 'pressed' : ''}`.trim()}
214+
style={{ backgroundColor: color }}
215+
onClick={this.selectColor}
216+
onAnimationEnd={this.togglePicker}
217+
/>
218+
</div>
219+
);
220+
}
221+
}
File renamed without changes.

0 commit comments

Comments
 (0)