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