11 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Color Values
36 |
37 |
38 | HEX
39 | {colorState.hex}
40 |
41 |
42 | RGB
43 |
44 | {colorState.rgb.r}, {colorState.rgb.g}, {colorState.rgb.b}
45 |
46 |
47 |
48 | HSL
49 |
50 | {colorState.hsl.h}°, {colorState.hsl.s}%, {colorState.hsl.l}%
51 |
52 |
53 |
54 | HSV
55 |
56 | {colorState.hsv.h}°, {colorState.hsv.s}%, {colorState.hsv.v}%
57 |
58 |
59 |
60 | Alpha
61 | {Math.round(colorState.alpha * 100)}%
62 |
63 |
64 |
65 |
66 |
67 |
\')',
74 | backgroundSize: '16px 16px',
75 | }),
76 | }}
77 | />
78 |
79 |
80 |
81 | );
82 | }
83 |
84 | export function HueExample() {
85 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hex', value: '#ff6b9d' });
86 |
87 | return (
88 |
89 |
90 |
Hue Selector
91 |
96 |
97 |
98 |
99 |
Current Hue: {Math.round(colorState.hsv.h)}°
100 |
101 | Color: {colorState.hex}
102 |
103 |
104 |
105 |
106 | );
107 | }
108 |
109 | export function SaturationExample() {
110 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hex', value: '#ff6b9d' });
111 |
112 | return (
113 |
114 |
115 |
Saturation Selector
116 |
121 |
122 |
123 |
124 |
125 |
Current Saturation: {Math.round(colorState.hsv.s)}%
126 |
Current Brightness: {Math.round(colorState.hsv.v)}%
127 |
128 | Color: {colorState.hex}
129 |
130 |
131 |
132 |
133 |
134 | );
135 | }
136 |
137 | export function AlphaExample() {
138 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hex', value: '#ff6b9d' });
139 |
140 | return (
141 |
142 |
143 |
Alpha Selector
144 |
149 |
150 |
151 |
152 |
Current Alpha: {Math.round(colorState.alpha * 100)}%
153 |
154 |
155 |
156 | );
157 | }
158 |
159 | export function EyeDropperExample() {
160 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hex', value: '#ff6b9d' });
161 |
162 | return (
163 |
164 |
165 |
Eye Dropper
166 | Selected Color: {colorState.hex}
167 |
168 |
169 |
174 |
175 |
179 |
180 |
181 |
182 |
190 |
191 |
192 | );
193 | }
194 |
--------------------------------------------------------------------------------
/docs/content/docs/utils.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Color Utilities
3 | description: Public utility functions for color conversion and manipulation
4 | ---
5 |
6 | import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
7 |
8 | ## Overview
9 |
10 | React Beautiful Color provides a comprehensive set of utility functions for color conversion and manipulation. These utilities are available for public use and can help you work with colors in your applications.
11 |
12 | ## Color Conversion
13 |
14 | ### Hex Conversions
15 |
16 |
17 |
18 | ```tsx
19 | import { hexToRgb } from 'react-beautiful-color';
20 |
21 | const rgb = hexToRgb('#ff6b9d');
22 | // { r: 255, g: 107, b: 157 }
23 | ```
24 |
25 |
26 |
27 |
28 | ```tsx
29 | import { hexToHsv } from 'react-beautiful-color';
30 |
31 | const hsv = hexToHsv('#ff6b9d');
32 | // { h: 334, s: 58, v: 100 }
33 | ```
34 |
35 |
36 |
37 |
38 | ```tsx
39 | import { hexToHsl } from 'react-beautiful-color';
40 |
41 | const hsl = hexToHsl('#ff6b9d');
42 | // { h: 334, s: 100, l: 71 }
43 | ```
44 |
45 |
46 |
47 |
48 | ### RGB Conversions
49 |
50 |
51 |
52 | ```tsx
53 | import { rgbToHex } from 'react-beautiful-color';
54 |
55 | const hex = rgbToHex({ r: 255, g: 107, b: 157 });
56 | // "#ff6b9d"
57 | ```
58 |
59 |
60 |
61 |
62 | ```tsx
63 | import { rgbToHsv } from 'react-beautiful-color';
64 |
65 | const hsv = rgbToHsv({ r: 255, g: 107, b: 157 });
66 | // { h: 334, s: 58, v: 100 }
67 | ```
68 |
69 |
70 |
71 |
72 | ```tsx
73 | import { rgbToHsl } from 'react-beautiful-color';
74 |
75 | const hsl = rgbToHsl({ r: 255, g: 107, b: 157 });
76 | // { h: 334, s: 100, l: 71 }
77 | ```
78 |
79 |
80 |
81 |
82 | ### HSV Conversions
83 |
84 |
85 |
86 | ```tsx
87 | import { hsvToRgb } from 'react-beautiful-color';
88 |
89 | const rgb = hsvToRgb({ h: 334, s: 58, v: 100 });
90 | // { r: 255, g: 107, b: 157 }
91 | ```
92 |
93 |
94 |
95 |
96 | ```tsx
97 | import { hsvToHex } from 'react-beautiful-color';
98 |
99 | const hex = hsvToHex({ h: 334, s: 58, v: 100 });
100 | // "#ff6b9d"
101 | ```
102 |
103 |
104 |
105 |
106 | ```tsx
107 | import { hsvToHsl } from 'react-beautiful-color';
108 |
109 | const hsl = hsvToHsl({ h: 334, s: 58, v: 100 });
110 | // { h: 334, s: 100, l: 71 }
111 | ```
112 |
113 |
114 |
115 |
116 | ### HSL Conversions
117 |
118 |
119 |
120 | ```tsx
121 | import { hslToRgb } from 'react-beautiful-color';
122 |
123 | const rgb = hslToRgb({ h: 334, s: 100, l: 71 });
124 | // { r: 255, g: 107, b: 157 }
125 | ```
126 |
127 |
128 |
129 |
130 | ```tsx
131 | import { hslToHex } from 'react-beautiful-color';
132 |
133 | const hex = hslToHex({ h: 334, s: 100, l: 71 });
134 | // "#ff6b9d"
135 | ```
136 |
137 |
138 |
139 |
140 | ```tsx
141 | import { hslToHsv } from 'react-beautiful-color';
142 |
143 | const hsv = hslToHsv({ h: 334, s: 100, l: 71 });
144 | // { h: 334, s: 58, v: 100 }
145 | ```
146 |
147 |
148 |
149 |
150 | ## Utility Functions
151 |
152 | ### getContrastColor
153 |
154 | Returns the best contrast color (black or white) for accessibility.
155 |
156 | ```tsx
157 | import { getContrastColor } from 'react-beautiful-color';
158 |
159 | const textColor = getContrastColor('#ff6b9d');
160 | // "#000000" (black for light backgrounds)
161 |
162 | const textColor2 = getContrastColor('#1a1a1a');
163 | // "#ffffff" (white for dark backgrounds)
164 | ```
165 |
166 | ### randomHex
167 |
168 | Generates a random hex color.
169 |
170 | ```tsx
171 | import { randomHex } from 'react-beautiful-color';
172 |
173 | const color = randomHex();
174 | // "#a1b2c3" (random hex color)
175 | ```
176 |
177 | ### formatColorString
178 |
179 | Formats a ColorState object into a CSS color string.
180 |
181 | ```tsx
182 | import { formatColorString, useColorState } from 'react-beautiful-color';
183 |
184 | const [{ colorState }] = useColorState({ type: 'hex', value: '#ff6b9d' });
185 |
186 | const hex = formatColorString(colorState, 'hex'); // "#ff6b9d"
187 | const rgb = formatColorString(colorState, 'rgb'); // "rgb(255, 107, 157)"
188 | const rgba = formatColorString(colorState, 'rgba'); // "rgba(255, 107, 157, 1)"
189 | const hsl = formatColorString(colorState, 'hsl'); // "hsl(334, 100%, 71%)"
190 | const hsla = formatColorString(colorState, 'hsla'); // "hsla(334, 100%, 71%, 1)"
191 | ```
192 |
193 | ## Color Class
194 |
195 | The `Color` class provides an object-oriented interface for working with colors. It encapsulates color data and provides methods for conversion and formatting.
196 |
197 | ### Creating an Instance
198 |
199 | ```tsx
200 | import { Color } from 'react-beautiful-color';
201 |
202 | // Create from hex
203 | const color = new Color({ type: 'hex', value: '#ff6b9d' });
204 |
205 | // Create from RGB
206 | const color2 = new Color({ type: 'rgb', r: 255, g: 107, b: 157 });
207 |
208 | // Create from HSL
209 | const color3 = new Color({ type: 'hsl', h: 334, s: 100, l: 71 });
210 |
211 | // Create from HSV
212 | const color4 = new Color({ type: 'hsv', h: 334, s: 58, v: 100 });
213 | ```
214 |
215 | ### Color Conversion
216 |
217 |
218 |
219 | Returns the RGB representation of the color.
220 |
221 | ```tsx
222 | const color = new Color({ type: 'hex', value: '#ff6b9d' });
223 | const rgb = color.getRgb();
224 | // { r: 255, g: 107, b: 157 }
225 | ```
226 |
227 |
228 |
229 |
230 | Returns the HSV representation of the color.
231 |
232 | ```tsx
233 | const hsv = color.getHsv();
234 | // { h: 334, s: 58, v: 100 }
235 | ```
236 |
237 |
238 |
239 |
240 | Returns the HSL representation of the color.
241 |
242 | ```tsx
243 | const hsl = color.getHsl();
244 | // { h: 334, s: 100, l: 71 }
245 | ```
246 |
247 |
248 |
249 |
250 | Returns the hex representation of the color.
251 |
252 | ```tsx
253 | const hex = color.getHex();
254 | // "#ff6b9d"
255 | ```
256 |
257 |
258 |
259 |
260 | Returns the RGBA representation of the color.
261 |
262 | ```tsx
263 | const rgba = color.getRgba();
264 | // { r: 255, g: 107, b: 157, a: 1 }
265 | ```
266 |
267 |
268 |
269 |
270 | Returns the HSLA representation of the color.
271 |
272 | ```tsx
273 | const hsla = color.getHsla();
274 | // { h: 334, s: 100, l: 71, a: 1 }
275 | ```
276 |
277 |
278 |
279 |
280 | Returns the HSVA representation of the color.
281 |
282 | ```tsx
283 | const hsva = color.getHsva();
284 | // { h: 334, s: 58, v: 100, a: 1 }
285 | ```
286 |
287 |
288 |
289 |
290 | ### Formatting Methods
291 |
292 | #### format()
293 |
294 | Formats the color as a CSS color string. Supports all formats except HSV/HSVA.
295 |
296 | ```tsx
297 | const color = new Color({ type: 'hex', value: '#ff6b9d' });
298 |
299 | const hex = color.format('hex'); // "#ff6b9d"
300 | const rgb = color.format('rgb'); // "rgb(255, 107, 157)"
301 | const rgba = color.format('rgba'); // "rgba(255, 107, 157, 1)"
302 | const hsl = color.format('hsl'); // "hsl(334, 100%, 71%)"
303 | const hsla = color.format('hsla'); // "hsla(334, 100%, 71%, 1)"
304 |
305 | // Default format is hex
306 | const defaultFormat = color.format(); // "#ff6b9d"
307 | ```
308 |
309 | #### getContrastingColor()
310 |
311 | Returns a new Color instance with the best contrast color (black or white) for accessibility.
312 |
313 | ```tsx
314 | const color = new Color({ type: 'hex', value: '#ff6b9d' });
315 | const contrastColor = color.getContrastingColor();
316 | const contrastHex = contrastColor.getHex(); // "#000000" (black for light backgrounds)
317 |
318 | const darkColor = new Color({ type: 'hex', value: '#1a1a1a' });
319 | const darkContrast = darkColor.getContrastingColor();
320 | const darkContrastHex = darkContrast.getHex(); // "#ffffff" (white for dark backgrounds)
321 | ```
322 |
323 | ### Complete Example
324 |
325 | ```tsx
326 | import { Color } from 'react-beautiful-color';
327 |
328 | // Create a color instance
329 | const color = new Color({ type: 'hex', value: '#ff6b9d' });
330 |
331 | // Convert to different formats
332 | const rgb = color.getRgb(); // { r: 255, g: 107, b: 157 }
333 | const hsv = color.getHsv(); // { h: 334, s: 58, v: 100 }
334 | const hsl = color.getHsl(); // { h: 334, s: 100, l: 71 }
335 |
336 | // Format as CSS strings
337 | const hexString = color.format('hex'); // "#ff6b9d"
338 | const rgbString = color.format('rgb'); // "rgb(255, 107, 157)"
339 | const hslString = color.format('hsl'); // "hsl(334, 100%, 71%)"
340 |
341 | // Get contrasting color for accessibility
342 | const contrastColor = color.getContrastingColor();
343 | const contrastHex = contrastColor.getHex(); // "#000000"
344 | ```
--------------------------------------------------------------------------------
/src/utils/public.ts:
--------------------------------------------------------------------------------
1 | import type { ColorFormat, ColorInput, HexColor, HslaColor, HslColor, HsvaColor, HsvColor, RgbaColor, RgbColor } from '../types';
2 | import { Color } from '../types';
3 | import { assertUnreachable } from './internal';
4 |
5 | const clamp = (num: number, min: number, max: number): number => Math.min(Math.max(num, min), max);
6 | const round = (num: number): number => Math.round(clamp(num, 0, 255));
7 |
8 | /**
9 | * Convert hex color to RGB values
10 | * @param hex - Hex color string (e.g., "#ff6b9d")
11 | * @returns RGB color object with r, g, b values (0-255)
12 | */
13 | export const hexToRgb = (hex: string): RgbColor => {
14 | const h = hex.replace('#', '');
15 | const bigint = parseInt(h, 16);
16 | return {
17 | r: (bigint >> 16) & 255,
18 | g: (bigint >> 8) & 255,
19 | b: bigint & 255,
20 | };
21 | };
22 |
23 | /**
24 | * Convert RGB values to hex color
25 | * @param rgb - RGB color object with r, g, b values (0-255)
26 | * @returns Hex color string (e.g., "#ff6b9d")
27 | */
28 | export const rgbToHex = ({ r, g, b }: RgbColor): string => {
29 | const toHex = (c: number) => round(c).toString(16).padStart(2, '0');
30 | return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
31 | };
32 |
33 | /**
34 | * Convert HSV color to RGB values
35 | * @param hsv - HSV color object with h (0-360), s (0-100), v (0-100)
36 | * @returns RGB color object with r, g, b values (0-255)
37 | */
38 | export const hsvToRgb = ({ h, s, v }: HsvColor): RgbColor => {
39 | h = h / 360;
40 | s = s / 100;
41 | v = v / 100;
42 |
43 | const i = Math.floor(h * 6);
44 | const f = h * 6 - i;
45 | const p = v * (1 - s);
46 | const q = v * (1 - f * s);
47 | const t = v * (1 - (1 - f) * s);
48 |
49 | let r: number, g: number, b: number;
50 |
51 | switch (i % 6) {
52 | case 0:
53 | r = v;
54 | g = t;
55 | b = p;
56 | break;
57 | case 1:
58 | r = q;
59 | g = v;
60 | b = p;
61 | break;
62 | case 2:
63 | r = p;
64 | g = v;
65 | b = t;
66 | break;
67 | case 3:
68 | r = p;
69 | g = q;
70 | b = v;
71 | break;
72 | case 4:
73 | r = t;
74 | g = p;
75 | b = v;
76 | break;
77 | case 5:
78 | r = v;
79 | g = p;
80 | b = q;
81 | break;
82 | default:
83 | r = g = b = 0;
84 | }
85 |
86 | return {
87 | r: round(r * 255),
88 | g: round(g * 255),
89 | b: round(b * 255),
90 | };
91 | };
92 |
93 | /**
94 | * Convert RGB values to HSV color
95 | * @param rgb - RGB color object with r, g, b values (0-255)
96 | * @returns HSV color object with h (0-360), s (0-100), v (0-100)
97 | */
98 | export const rgbToHsv = ({ r, g, b }: RgbColor): HsvColor => {
99 | r /= 255;
100 | g /= 255;
101 | b /= 255;
102 |
103 | const max = Math.max(r, g, b);
104 | const min = Math.min(r, g, b);
105 | const diff = max - min;
106 |
107 | let h = 0;
108 | const s = max === 0 ? 0 : diff / max;
109 | const v = max;
110 |
111 | if (diff !== 0) {
112 | switch (max) {
113 | case r:
114 | h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
115 | break;
116 | case g:
117 | h = ((b - r) / diff + 2) / 6;
118 | break;
119 | case b:
120 | h = ((r - g) / diff + 4) / 6;
121 | break;
122 | }
123 | }
124 |
125 | return {
126 | h: Math.round(h * 360),
127 | s: Math.round(s * 100),
128 | v: Math.round(v * 100),
129 | };
130 | };
131 |
132 | /**
133 | * Convert HSV color to hex string
134 | * @param hsv - HSV color object with h (0-360), s (0-100), v (0-100)
135 | * @returns Hex color string (e.g., "#ff6b9d")
136 | */
137 | export const hsvToHex = (hsv: HsvColor): string => rgbToHex(hsvToRgb(hsv));
138 |
139 | /**
140 | * Convert hex color to HSV values
141 | * @param hex - Hex color string (e.g., "#ff6b9d")
142 | * @returns HSV color object with h (0-360), s (0-100), v (0-100)
143 | */
144 | export const hexToHsv = (hex: string): HsvColor => rgbToHsv(hexToRgb(hex));
145 |
146 | /**
147 | * Convert RGB values to HSL color
148 | * @param rgb - RGB color object with r, g, b values (0-255)
149 | * @returns HSL color object with h (0-360), s (0-100), l (0-100)
150 | */
151 | export const rgbToHsl = ({ r, g, b }: RgbColor): HslColor => {
152 | r /= 255;
153 | g /= 255;
154 | b /= 255;
155 |
156 | const max = Math.max(r, g, b);
157 | const min = Math.min(r, g, b);
158 | const diff = max - min;
159 |
160 | let h = 0;
161 | let s = 0;
162 | const l = (max + min) / 2;
163 |
164 | if (diff !== 0) {
165 | s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
166 |
167 | switch (max) {
168 | case r:
169 | h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
170 | break;
171 | case g:
172 | h = ((b - r) / diff + 2) / 6;
173 | break;
174 | case b:
175 | h = ((r - g) / diff + 4) / 6;
176 | break;
177 | }
178 | }
179 |
180 | return {
181 | h: Math.round(h * 360),
182 | s: Math.round(s * 100),
183 | l: Math.round(l * 100),
184 | };
185 | };
186 |
187 | /**
188 | * Convert HSL color to RGB values
189 | * @param hsl - HSL color object with h (0-360), s (0-100), l (0-100)
190 | * @returns RGB color object with r, g, b values (0-255)
191 | */
192 | export const hslToRgb = ({ h, s, l }: HslColor): RgbColor => {
193 | h /= 360;
194 | s /= 100;
195 | l /= 100;
196 |
197 | const hue2rgb = (p: number, q: number, t: number): number => {
198 | if (t < 0) t += 1;
199 | if (t > 1) t -= 1;
200 | if (t < 1 / 6) return p + (q - p) * 6 * t;
201 | if (t < 1 / 2) return q;
202 | if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
203 | return p;
204 | };
205 |
206 | let r: number, g: number, b: number;
207 |
208 | if (s === 0) {
209 | r = g = b = l;
210 | } else {
211 | const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
212 | const p = 2 * l - q;
213 | r = hue2rgb(p, q, h + 1 / 3);
214 | g = hue2rgb(p, q, h);
215 | b = hue2rgb(p, q, h - 1 / 3);
216 | }
217 |
218 | return {
219 | r: Math.round(r * 255),
220 | g: Math.round(g * 255),
221 | b: Math.round(b * 255),
222 | };
223 | };
224 |
225 | /**
226 | * Convert HSL color to hex string
227 | * @param hsl - HSL color object with h (0-360), s (0-100), l (0-100)
228 | * @returns Hex color string (e.g., "#ff6b9d")
229 | */
230 | export const hslToHex = (hsl: HslColor): string => rgbToHex(hslToRgb(hsl));
231 |
232 | /**
233 | * Convert hex color to HSL values
234 | * @param hex - Hex color string (e.g., "#ff6b9d")
235 | * @returns HSL color object with h (0-360), s (0-100), l (0-100)
236 | */
237 | export const hexToHsl = (hex: string): HslColor => rgbToHsl(hexToRgb(hex));
238 |
239 | /**
240 | * Convert HSV color to HSL color
241 | * @param hsv - HSV color object with h (0-360), s (0-100), v (0-100)
242 | * @returns HSL color object with h (0-360), s (0-100), l (0-100)
243 | */
244 | export const hsvToHsl = ({ h, s, v }: HsvColor): HslColor => {
245 | const l = (v * (2 - s / 100)) / 2;
246 | const sL = l !== 0 && l !== 100 ? ((v - l) / Math.min(l, 100 - l)) * 100 : 0;
247 |
248 | return {
249 | h,
250 | s: Math.round(sL),
251 | l: Math.round(l),
252 | };
253 | };
254 |
255 | /**
256 | * Convert HSL color to HSV color
257 | * @param hsl - HSL color object with h (0-360), s (0-100), l (0-100)
258 | * @returns HSV color object with h (0-360), s (0-100), v (0-100)
259 | */
260 | export const hslToHsv = ({ h, s, l }: HslColor): HsvColor => {
261 | const v = l + (s * Math.min(l, 100 - l)) / 100;
262 | const sV = v === 0 ? 0 : 2 * (1 - l / v) * 100;
263 |
264 | return {
265 | h,
266 | s: Math.round(sV),
267 | v: Math.round(v),
268 | };
269 | };
270 |
271 | /**
272 | * Get the contrast color (black or white) for a given hex color
273 | * @param hex - Hex color string (e.g., "#ff6b9d")
274 | * @returns "#000000" for light colors, "#ffffff" for dark colors
275 | */
276 | export const getContrastColor = (hex: string): string => {
277 | const { r, g, b } = hexToRgb(hex);
278 | const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
279 | return luminance > 0.5 ? '#000000' : '#ffffff';
280 | };
281 |
282 | /**
283 | * Generate a random hex color
284 | * @returns Random hex color string (e.g., "#a1b2c3")
285 | */
286 | export const randomHex = (): string => {
287 | return `#${Math.floor(Math.random() * 16777215)
288 | .toString(16)
289 | .padStart(6, '0')}`;
290 | };
291 |
292 | /**
293 | * Format a ColorState object into a CSS color string
294 | * @param color - ColorState object
295 | * @param format - Output format: 'hex', 'rgb', 'rgba', 'hsl', 'hsla'
296 | * @returns Formatted color string
297 | */
298 | export const formatColorString = (color: Color, format: Exclude
= 'hex'): string => {
299 | switch (format) {
300 | case 'hex':
301 | return color.getHex();
302 | case 'rgb':
303 | const rgb = color.getRgb();
304 | return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
305 | case 'rgba':
306 | const rgba = color.getRgba();
307 | return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
308 | case 'hsl':
309 | const hsl = color.getHsl();
310 | return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
311 | case 'hsla':
312 | const hsla = color.getHsla();
313 | return `hsla(${hsla.h}, ${hsla.s}%, ${hsla.l}%, ${hsla.a})`;
314 | default:
315 | assertUnreachable(format);
316 | }
317 | };
318 |
319 | function toHsva(color: ColorInput): HsvaColor {
320 | switch (color.type) {
321 | case 'hex':
322 | return { ...hexToHsv(color.value), a: 1 };
323 | case 'rgb':
324 | return { ...rgbToHsv(color), a: 1 };
325 | case 'rgba':
326 | return { ...rgbToHsv(color), a: color.a };
327 | case 'hsl':
328 | return { ...hslToHsv(color), a: 1 };
329 | case 'hsla':
330 | return { ...hslToHsv(color), a: 1 };
331 | case 'hsv':
332 | return { ...color, a: 1 };
333 | case 'hsva':
334 | return { ...color };
335 | default:
336 | assertUnreachable(color);
337 | }
338 | }
339 |
340 | export function convertColor(color: ColorInput, format: 'hex'): HexColor;
341 | export function convertColor(color: ColorInput, format: 'rgb'): RgbColor;
342 | export function convertColor(color: ColorInput, format: 'rgba'): RgbaColor;
343 | export function convertColor(color: ColorInput, format: 'hsl'): HslColor;
344 | export function convertColor(color: ColorInput, format: 'hsla'): HslaColor;
345 | export function convertColor(color: ColorInput, format: 'hsv'): HsvColor;
346 | export function convertColor(color: ColorInput, format: 'hsva'): HsvaColor;
347 | export function convertColor(color: ColorInput, format: ColorFormat): HexColor | RgbColor | RgbaColor | HslColor | HslaColor | HsvColor | HsvaColor {
348 | const hsva = toHsva(color);
349 | switch (format) {
350 | case 'hex':
351 | return hsvToHex(hsva);
352 | case 'rgb':
353 | return hsvToRgb(hsva);
354 | case 'rgba':
355 | return { ...hsvToRgb(hsva), a: hsva.a };
356 | case 'hsl':
357 | return hsvToHsl(hsva);
358 | case 'hsla':
359 | return { ...hsvToHsl(hsva), a: hsva.a };
360 | case 'hsv':
361 | return { h: hsva.h, s: hsva.s, v: hsva.v };
362 | case 'hsva':
363 | return hsva;
364 | default:
365 | assertUnreachable(format);
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/docs/content/docs/components/color-picker.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: ColorPicker
3 | description: A complete color picker component with hue, saturation, and alpha controls
4 | ---
5 |
6 | import { BasicColorPickerExample
7 | } from '../../../components/ColorPickerExample';
8 | import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
9 |
10 | ## Features
11 |
12 | - **Compound Components**: Modular design with sub-components
13 | - **Eye Dropper**: Built-in screen color picker (where supported)
14 | - **Touch & Mouse Support**: Works on all devices
15 | - **Color Formats**: Supports hex, rgb, rgba, hsl, hsla, hsv, hsva
16 |
17 | ## Basic Usage
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```tsx
26 | import { ColorPicker, useColorState } from 'react-beautiful-color';
27 | import { Pipette } from 'lucide-react';
28 |
29 | export function BasicColorPickerExample() {
30 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hex', value: '#ff6b9d' });
31 |
32 | return (
33 |
34 |
39 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
Color Values
57 |
58 |
59 | HEX
60 | {colorState.hex}
61 |
62 |
63 | RGB
64 |
65 | {colorState.rgb.r}, {colorState.rgb.g}, {colorState.rgb.b}
66 |
67 |
68 |
69 | HSL
70 |
71 | {colorState.hsl.h}°, {colorState.hsl.s}%, {colorState.hsl.l}%
72 |
73 |
74 |
75 | HSV
76 |
77 | {colorState.hsv.h}°, {colorState.hsv.s}%, {colorState.hsv.v}%
78 |
79 |
80 |
81 | Alpha
82 | {Math.round(colorState.alpha * 100)}%
83 |
84 |
85 |
86 |
87 |
88 |
\')',
95 | backgroundSize: '16px 16px',
96 | }),
97 | }}
98 | />
99 |
100 |
101 |
102 | );
103 | }
104 | ```
105 |
106 |
107 |
108 | ```tsx
109 | import { ColorPicker, Color } from 'react-beautiful-color';
110 | import { Pipette } from 'lucide-react';
111 |
112 | export function BasicColorPickerExampleUseState() {
113 | const [color, setColor] = useState(new Color({ type: 'hex', value: '#ff6b9d' }));
114 |
115 | const rgba = color.getRgba();
116 | const hex = color.getHex();
117 | const hsl = color.getHsl();
118 | const hsv = color.getHsv();
119 |
120 | return (
121 |
122 |
127 |
128 |
129 |
130 |
131 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
Color Values
147 |
148 |
149 | HEX
150 | {hex}
151 |
152 |
153 | RGB
154 |
155 | {rgba.r}, {rgba.g}, {rgba.b}
156 |
157 |
158 |
159 | HSL
160 |
161 | {hsl.h}°, {hsl.s}%, {hsl.l}%
162 |
163 |
164 |
165 | HSV
166 |
167 | {hsv.h}°, {hsv.s}%, {hsv.v}%
168 |
169 |
170 |
171 | Alpha
172 | {Math.round(rgba.a * 100)}%
173 |
174 |
175 |
176 |
177 |
178 |
\')',
185 | backgroundSize: '16px 16px',
186 | }),
187 | }}
188 | />
189 |
190 |
191 |
192 | );
193 | }
194 | ```
195 |
196 |
197 |
198 | ## Props
199 |
200 | | Prop | Type | Default | Description |
201 | |------|------|---------|-------------|
202 | | `defaultColor` | [ColorInput](/docs/components/color-picker#color-input-format) \| [Color](/docs/utils#color-class) | - | Initial color value |
203 | | `color` | [ColorInput](/docs/components/color-picker#color-input-format) \| [Color](/docs/utils#color-class) | - | Color value |
204 | | `onChange` | `(color: Color) => void` | - | Callback fired when color changes |
205 | | `className` | `string` | - | Additional CSS classes |
206 |
207 | ## Color Input Format
208 |
209 | The `ColorInput` type supports multiple color formats:
210 |
211 |
212 |
213 | ```tsx
214 | // Hex color input
215 | const hexColor = { type: 'hex', value: '#ff6b9d' };
216 | ```
217 |
218 |
219 |
220 | ```tsx
221 | // RGB color input
222 | const rgbColor = { type: 'rgb', r: 255, g: 107, b: 157 };
223 |
224 | // RGBA color input (with alpha)
225 | const rgbaColor = { type: 'rgba', r: 255, g: 107, b: 157, a: 0.8 };
226 | ```
227 |
228 |
229 |
230 | ```tsx
231 | // HSL color input
232 | const hslColor = { type: 'hsl', h: 334, s: 100, l: 71 };
233 |
234 | // HSLA color input (with alpha)
235 | const hslaColor = { type: 'hsla', h: 334, s: 100, l: 71, a: 0.8 };
236 | ```
237 |
238 |
239 |
240 | ```tsx
241 | // HSV color input
242 | const hsvColor = { type: 'hsv', h: 334, s: 58, v: 100 };
243 |
244 | // HSVA color input (with alpha)
245 | const hsvaColor = { type: 'hsva', h: 334, s: 58, v: 100, a: 0.8 };
246 | ```
247 |
248 |
249 |
250 | ## Sub-Components
251 |
252 | ### ColorPicker.Saturation
253 |
254 | The saturation and brightness selection area.
255 |
256 | ```tsx
257 |
258 | ```
259 |
260 | ### ColorPicker.Hue
261 |
262 | The hue selection slider.
263 |
264 | ```tsx
265 |
266 | ```
267 |
268 | ### ColorPicker.Alpha
269 |
270 | The alpha/transparency selection slider.
271 |
272 | ```tsx
273 |
274 | ```
275 |
276 | ### ColorPicker.EyeDropper
277 |
278 | Button to activate the browser's eye dropper tool. The button is not rendered if the user's browser doesn't support it.
279 |
280 | ```tsx
281 |
282 | {/* Icon content */}
283 |
284 | ```
285 |
--------------------------------------------------------------------------------
/docs/app/(home)/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Link from 'next/link';
4 | import { Palette, Zap, Code, Sparkles, Pipette, Github, Package, Coffee, Heart } from 'lucide-react';
5 | import { ColorPicker, useColorState } from 'react-beautiful-color';
6 | import { cn } from 'fumadocs-ui/utils/cn';
7 |
8 | export default function HomePage() {
9 | const [{ colorInput, colorState }, setColor] = useColorState({ type: 'hsva', h: 334, s: 100, v: 100, a: 0.5 });
10 |
11 | return (
12 |
13 | {/* Hero Section */}
14 |
15 |
16 | {/* Badge */}
17 |
18 |
19 | Beautiful • Flexible • Type-Safe
20 |
21 |
22 | {/* Hero Title */}
23 |
24 |
25 | react-
26 |
30 | beautiful
31 |
32 | -color
33 |
34 |
35 |
The most flexible and beautiful color picker for React
36 |
37 |
38 |
39 | {/* Social Links */}
40 |
76 |
77 |
78 |
79 | {/* Hero Subtitle */}
80 |
81 |
82 |
87 |
88 |
89 |
90 |
91 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | {/* Made with love */}
106 |
107 |
108 |
Made with
109 |
113 |
for
114 |
115 |
127 |
React
128 |
129 |
by
130 |
134 | Özer Gökalpsezer
135 |
136 |
137 |
143 |
147 | Buy me a coffee
148 |
149 |
150 |
151 |
152 |
153 | {/* Features Section */}
154 |
155 |
156 |
157 |
Why Choose React Beautiful Color?
158 |
159 | Built for developers who care about flexibility, performance, and beautiful user experiences.
160 |
161 |
162 |
163 |
164 | {/* Feature 1 */}
165 |
166 |
167 |
168 |
169 |
Compound Components
170 |
Compose your own layout with flexible compound components. No rigid UI constraints.
171 |
172 |
173 | {/* Feature 2 */}
174 |
175 |
178 |
Beautiful Design
179 |
Clean, modern UI that fits any design system. Built with Tailwind CSS for easy customization.
180 |
181 |
182 | {/* Feature 3 */}
183 |
184 |
185 |
186 |
187 |
Powerful Hook
188 |
useColorState hook with all color formats instantly available and complete type safety.
189 |
190 |
191 | {/* Feature 4 */}
192 |
193 |
194 |
195 |
196 |
Lightweight
197 |
Pure Tailwind CSS with no external dependencies. Small bundle size, maximum performance.
198 |
199 |
200 | {/* Feature 5 */}
201 |
202 |
203 |
204 |
205 |
Type-Safe
206 |
Full TypeScript support with discriminated unions for color inputs and complete type safety.
207 |
208 |
209 | {/* Feature 6 */}
210 |
211 |
214 |
Eye Dropper
215 |
Built-in eye dropper support for picking colors from anywhere on the screen.
216 |
217 |
218 |
219 |
220 |
221 | );
222 | }
223 |
--------------------------------------------------------------------------------