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};