a tool for shared writing and social publishing
1"use client";
2
3import {
4 ColorPicker as SpectrumColorPicker,
5 parseColor,
6 Color,
7 ColorArea,
8 ColorThumb,
9 ColorSlider,
10 Input,
11 ColorField,
12 SliderTrack,
13 ColorSwatch,
14} from "react-aria-components";
15import { pickers } from "../ThemeSetter";
16import { Separator } from "components/Layout";
17import { onMouseDown } from "src/utils/iosInputMouseDown";
18
19export let thumbStyle =
20 "w-4 h-4 rounded-full border-2 border-white shadow-[0_0_0_1px_#8C8C8C,inset_0_0_0_1px_#8C8C8C]";
21
22export const ColorPicker = (props: {
23 label?: string;
24 helpText?: string;
25 value: Color | undefined;
26 alpha?: boolean;
27 image?: boolean;
28 setValue: (c: Color) => void;
29 openPicker: pickers;
30 thisPicker: pickers;
31 setOpenPicker: (thisPicker: pickers) => void;
32 closePicker: () => void;
33 disabled?: boolean;
34 children?: React.ReactNode;
35}) => {
36 return (
37 <SpectrumColorPicker value={props.value} onChange={props.setValue}>
38 <div className="flex flex-col w-full gap-2">
39 <div className="colorPickerLabel flex gap-2 items-center ">
40 <button
41 disabled={props.disabled}
42 className="flex gap-2 items-center disabled:text-tertiary"
43 onClick={() => {
44 if (props.openPicker === props.thisPicker) {
45 props.setOpenPicker("null");
46 } else {
47 props.setOpenPicker(props.thisPicker);
48 }
49 }}
50 >
51 <ColorSwatch
52 color={props.value}
53 className={`w-6 h-6 rounded-full border-2 border-white shadow-[0_0_0_1px_#8C8C8C] ${props.disabled ? "opacity-50" : ""}`}
54 style={{
55 backgroundSize: "cover",
56 }}
57 />
58 <strong className="w-max">{props.label}</strong>
59 </button>
60
61 <div className="flex gap-1">
62 {props.value === undefined ? (
63 <div>default</div>
64 ) : props.disabled ? (
65 <div className="text-tertiary italic">hidden</div>
66 ) : (
67 <ColorField className="w-fit gap-1">
68 <Input
69 onMouseDown={onMouseDown}
70 onFocus={(e) => {
71 e.currentTarget.setSelectionRange(
72 1,
73 e.currentTarget.value.length,
74 );
75 }}
76 onKeyDown={(e) => {
77 if (e.key === "Enter") {
78 e.currentTarget.blur();
79 } else return;
80 }}
81 onBlur={(e) => {
82 props.setValue(parseColor(e.currentTarget.value));
83 }}
84 className="w-[72px] bg-transparent outline-hidden disabled:text-tertiary"
85 />
86 </ColorField>
87 )}
88 {props.alpha && !props.disabled && (
89 <>
90 <Separator classname="my-1" />
91 <ColorField
92 className={`w-[48px] pl-[6px] ${props.disabled ? "opacity-50" : ""}`}
93 channel="alpha"
94 >
95 <Input
96 disabled={props.disabled}
97 onMouseDown={onMouseDown}
98 onFocus={(e) => {
99 e.currentTarget.setSelectionRange(
100 0,
101 e.currentTarget.value.length - 1,
102 );
103 }}
104 onKeyDown={(e) => {
105 if (e.key === "Enter") {
106 e.currentTarget.blur();
107 } else return;
108 }}
109 className="w-[72px] bg-transparent outline-hidden "
110 />
111 </ColorField>
112 </>
113 )}
114 </div>
115 </div>
116 {props.openPicker === props.thisPicker && (
117 <div className="w-full flex flex-col gap-2 px-1 pb-2">
118 {
119 <>
120 {props.helpText && (
121 <div className="text-sm leading-tight text-tertiary pl-7 -mt-2.5">
122 {props.helpText}
123 </div>
124 )}
125 <ColorArea
126 className="w-full h-[128px] rounded-md"
127 colorSpace="hsb"
128 xChannel="saturation"
129 yChannel="brightness"
130 >
131 <ColorThumb className={thumbStyle} />
132 </ColorArea>
133 <ColorSlider colorSpace="hsb" className="w-full" channel="hue">
134 <SliderTrack className="h-2 w-full rounded-md">
135 <ColorThumb className={`${thumbStyle} mt-[4px]`} />
136 </SliderTrack>
137 </ColorSlider>
138 {props.alpha && (
139 <ColorSlider
140 colorSpace="hsb"
141 className="w-full mt-1 rounded-full"
142 style={{
143 backgroundImage: `url(/transparent-bg.png)`,
144 backgroundRepeat: "repeat",
145 backgroundSize: "8px",
146 }}
147 channel="alpha"
148 >
149 <SliderTrack className="h-2 w-full rounded-md">
150 <ColorThumb className={`${thumbStyle} mt-[4px]`} />
151 </SliderTrack>
152 </ColorSlider>
153 )}
154 {props.children}
155 </>
156 }
157 </div>
158 )}
159 </div>
160 </SpectrumColorPicker>
161 );
162};