mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-04 06:31:13 +00:00
Replace react-color with custom HSL ColorPicker
Remove the react-color dependency and add a custom ColorPicker implementation. The new component uses HSL parsing and hex<->HSL conversion, provides SatLightPanel and HueSlider subcomponents with mouse/touch drag support, and integrates @heroui/input for inline HEX/HSL editing. The ColorPicker onChange now emits an "hsl(...)" string; theme config parsing was updated to convert that string into the existing "h s% l%" format. Also update package.json to drop react-color.
This commit is contained in:
parent
90e3936204
commit
0592f1a99a
@ -73,7 +73,6 @@
|
||||
"qrcode.react": "^4.2.0",
|
||||
"quill": "^2.0.3",
|
||||
"react": "^19.0.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-dropzone": "^14.3.5",
|
||||
"react-error-boundary": "^5.0.0",
|
||||
|
||||
@ -1,37 +1,409 @@
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover';
|
||||
import React from 'react';
|
||||
import { ColorResult, SketchPicker } from 'react-color';
|
||||
|
||||
// 假定 heroui 提供的 Popover组件
|
||||
import { Input } from "@heroui/input";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@heroui/popover";
|
||||
import React, { useCallback, useEffect, useRef, useState, memo } from "react";
|
||||
|
||||
interface ColorPickerProps {
|
||||
color: string;
|
||||
onChange: (color: ColorResult) => void;
|
||||
onChange: (color: string) => void;
|
||||
}
|
||||
|
||||
// 转换 HSL 字符串到对象
|
||||
const parseHsl = (hslStr: string) => {
|
||||
const match = hslStr.match(/hsl\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)%,\s*(\d+(?:\.\d+)?)%\)/);
|
||||
if (match) {
|
||||
return { h: parseFloat(match[1]), s: parseFloat(match[2]), l: parseFloat(match[3]) };
|
||||
}
|
||||
return { h: 0, s: 0, l: 0 };
|
||||
};
|
||||
|
||||
// 转换 HEX 到 HSL
|
||||
const hexToHsl = (hex: string) => {
|
||||
let r = 0, g = 0, b = 0;
|
||||
if (hex.length === 4) {
|
||||
r = parseInt("0x" + hex[1] + hex[1]);
|
||||
g = parseInt("0x" + hex[2] + hex[2]);
|
||||
b = parseInt("0x" + hex[3] + hex[3]);
|
||||
} else if (hex.length === 7) {
|
||||
r = parseInt("0x" + hex[1] + hex[2]);
|
||||
g = parseInt("0x" + hex[3] + hex[4]);
|
||||
b = parseInt("0x" + hex[5] + hex[6]);
|
||||
}
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
const cmin = Math.min(r, g, b),
|
||||
cmax = Math.max(r, g, b),
|
||||
delta = cmax - cmin;
|
||||
let h = 0,
|
||||
s = 0,
|
||||
l = 0;
|
||||
|
||||
if (delta === 0) h = 0;
|
||||
else if (cmax === r) h = ((g - b) / delta) % 6;
|
||||
else if (cmax === g) h = (b - r) / delta + 2;
|
||||
else h = (r - g) / delta + 4;
|
||||
|
||||
h = Math.round(h * 60);
|
||||
if (h < 0) h += 360;
|
||||
|
||||
l = (cmax + cmin) / 2;
|
||||
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
|
||||
s = +(s * 100).toFixed(1);
|
||||
l = +(l * 100).toFixed(1);
|
||||
|
||||
return { h, s, l };
|
||||
};
|
||||
|
||||
// 转换 HSL 到 HEX
|
||||
const hslToHex = (h: number, s: number, l: number) => {
|
||||
s /= 100;
|
||||
l /= 100;
|
||||
const c = (1 - Math.abs(2 * l - 1)) * s;
|
||||
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
||||
const m = l - c / 2;
|
||||
let r = 0, g = 0, b = 0;
|
||||
|
||||
if (0 <= h && h < 60) {
|
||||
r = c; g = x; b = 0;
|
||||
} else if (60 <= h && h < 120) {
|
||||
r = x; g = c; b = 0;
|
||||
} else if (120 <= h && h < 180) {
|
||||
r = 0; g = c; b = x;
|
||||
} else if (180 <= h && h < 240) {
|
||||
r = 0; g = x; b = c;
|
||||
} else if (240 <= h && h < 300) {
|
||||
r = x; g = 0; b = c;
|
||||
} else if (300 <= h && h < 360) {
|
||||
r = c; g = 0; b = x;
|
||||
}
|
||||
r = Math.round((r + m) * 255);
|
||||
g = Math.round((g + m) * 255);
|
||||
b = Math.round((b + m) * 255);
|
||||
|
||||
const toHex = (n: number) => {
|
||||
const hex = n.toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
};
|
||||
return "#" + toHex(r) + toHex(g) + toHex(b);
|
||||
};
|
||||
|
||||
interface PanelProps {
|
||||
hsl: { h: number, s: number, l: number; };
|
||||
onChange: (newHsl: { h: number, s: number, l: number; }) => void;
|
||||
}
|
||||
|
||||
// 饱和度/亮度面板
|
||||
const SatLightPanel = memo(({ hsl, onChange }: PanelProps) => {
|
||||
const panelRef = useRef<HTMLDivElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const hslRef = useRef(hsl);
|
||||
useEffect(() => { hslRef.current = hsl; }, [hsl]);
|
||||
|
||||
const updateColor = useCallback((clientX: number, clientY: number) => {
|
||||
if (!panelRef.current) return;
|
||||
const rect = panelRef.current.getBoundingClientRect();
|
||||
const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
||||
const y = Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
|
||||
|
||||
const s_hsv = x;
|
||||
const v_hsv = 1 - y;
|
||||
|
||||
let l_hsl = v_hsv * (1 - s_hsv / 2);
|
||||
let s_hsl = 0;
|
||||
if (l_hsl === 0 || l_hsl === 1) {
|
||||
s_hsl = 0;
|
||||
} else {
|
||||
s_hsl = (v_hsv - l_hsl) / Math.min(l_hsl, 1 - l_hsl);
|
||||
}
|
||||
|
||||
onChange({ h: hslRef.current.h, s: s_hsl * 100, l: l_hsl * 100 });
|
||||
}, [onChange]);
|
||||
|
||||
const handleStart = (clientX: number, clientY: number) => {
|
||||
setIsDragging(true);
|
||||
updateColor(clientX, clientY);
|
||||
};
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
handleStart(e.clientX, e.clientY);
|
||||
};
|
||||
|
||||
const handleTouchStart = (e: React.TouchEvent) => {
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
handleStart(touch.clientX, touch.clientY);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (isDragging) {
|
||||
e.preventDefault();
|
||||
updateColor(e.clientX, e.clientY);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchMove = (e: TouchEvent) => {
|
||||
if (isDragging) {
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
updateColor(touch.clientX, touch.clientY);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEnd = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
if (isDragging) {
|
||||
window.addEventListener("mousemove", handleMouseMove);
|
||||
window.addEventListener("mouseup", handleEnd);
|
||||
window.addEventListener("touchmove", handleTouchMove, { passive: false });
|
||||
window.addEventListener("touchend", handleEnd);
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener("mousemove", handleMouseMove);
|
||||
window.removeEventListener("mouseup", handleEnd);
|
||||
window.removeEventListener("touchmove", handleTouchMove);
|
||||
window.removeEventListener("touchend", handleEnd);
|
||||
};
|
||||
}, [isDragging, updateColor]);
|
||||
|
||||
const l_val = hsl.l / 100;
|
||||
const s_val = hsl.s / 100;
|
||||
const v_hsv = l_val + s_val * Math.min(l_val, 1 - l_val);
|
||||
const s_hsv = v_hsv === 0 ? 0 : 2 * (1 - l_val / v_hsv);
|
||||
|
||||
const markerX = s_hsv * 100;
|
||||
const markerY = (1 - v_hsv) * 100;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={panelRef}
|
||||
className="w-full h-40 rounded-lg relative cursor-crosshair overflow-hidden shadow-inner touch-none"
|
||||
style={{
|
||||
backgroundColor: "hsl(" + hsl.h + ", 100%, 50%)",
|
||||
backgroundImage: "linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)"
|
||||
}}
|
||||
onMouseDown={handleMouseDown}
|
||||
onTouchStart={handleTouchStart}
|
||||
>
|
||||
<div
|
||||
className="w-4 h-4 rounded-full border-2 border-white shadow-md absolute transform -translate-x-1/2 -translate-y-1/2 pointer-events-none"
|
||||
style={{
|
||||
left: markerX + "%",
|
||||
top: markerY + "%",
|
||||
backgroundColor: "hsl(" + hsl.h + ", " + hsl.s + "%, " + hsl.l + "%)"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
SatLightPanel.displayName = "SatLightPanel";
|
||||
|
||||
const HueSlider = memo(({ hsl, onChange }: PanelProps) => {
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const hslRef = useRef(hsl);
|
||||
useEffect(() => { hslRef.current = hsl; }, [hsl]);
|
||||
|
||||
const updateHue = useCallback((clientX: number) => {
|
||||
if (!sliderRef.current) return;
|
||||
const rect = sliderRef.current.getBoundingClientRect();
|
||||
let x = (clientX - rect.left) / rect.width;
|
||||
x = Math.max(0, Math.min(1, x));
|
||||
onChange({ ...hslRef.current, h: x * 360 });
|
||||
}, [onChange]);
|
||||
|
||||
const handleStart = (clientX: number) => {
|
||||
setIsDragging(true);
|
||||
updateHue(clientX);
|
||||
};
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
handleStart(e.clientX);
|
||||
};
|
||||
|
||||
const handleTouchStart = (e: React.TouchEvent) => {
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
handleStart(touch.clientX);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (isDragging) {
|
||||
e.preventDefault();
|
||||
updateHue(e.clientX);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchMove = (e: TouchEvent) => {
|
||||
if (isDragging) {
|
||||
e.preventDefault();
|
||||
const touch = e.touches[0];
|
||||
updateHue(touch.clientX);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEnd = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
if (isDragging) {
|
||||
window.addEventListener("mousemove", handleMouseMove);
|
||||
window.addEventListener("mouseup", handleEnd);
|
||||
window.addEventListener("touchmove", handleTouchMove, { passive: false });
|
||||
window.addEventListener("touchend", handleEnd);
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener("mousemove", handleMouseMove);
|
||||
window.removeEventListener("mouseup", handleEnd);
|
||||
window.removeEventListener("touchmove", handleTouchMove);
|
||||
window.removeEventListener("touchend", handleEnd);
|
||||
};
|
||||
}, [isDragging, updateHue]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={sliderRef}
|
||||
className="w-full h-4 rounded-full relative cursor-pointer mt-3 shadow-inner touch-none"
|
||||
style={{
|
||||
background: "linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)"
|
||||
}}
|
||||
onMouseDown={handleMouseDown}
|
||||
onTouchStart={handleTouchStart}
|
||||
>
|
||||
<div
|
||||
className="w-4 h-4 rounded-full border-2 border-white shadow-md absolute top-0 transform -translate-x-1/2 pointer-events-none bg-white"
|
||||
style={{ left: (hsl.h / 360) * 100 + "%" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
HueSlider.displayName = "HueSlider";
|
||||
|
||||
const ColorPicker: React.FC<ColorPickerProps> = ({ color, onChange }) => {
|
||||
const handleChange = (colorResult: ColorResult) => {
|
||||
onChange(colorResult);
|
||||
const [hsl, setHsl] = useState(parseHsl(color));
|
||||
const [hex, setHex] = useState(hslToHex(hsl.h, hsl.s, hsl.l));
|
||||
const isDraggingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDraggingRef.current) return;
|
||||
const newHsl = parseHsl(color);
|
||||
if (Math.abs(newHsl.h - hsl.h) > 0.1 || Math.abs(newHsl.s - hsl.s) > 0.1 || Math.abs(newHsl.l - hsl.l) > 0.1) {
|
||||
setHsl(newHsl);
|
||||
setHex(hslToHex(newHsl.h, newHsl.s, newHsl.l));
|
||||
}
|
||||
}, [color]);
|
||||
|
||||
const handleHslChange = useCallback((newHsl: { h: number, s: number, l: number; }) => {
|
||||
setHsl(newHsl);
|
||||
setHex(hslToHex(newHsl.h, newHsl.s, newHsl.l));
|
||||
onChange("hsl(" + Math.round(newHsl.h) + ", " + Math.round(newHsl.s) + "%, " + Math.round(newHsl.l) + "%)");
|
||||
}, [onChange]);
|
||||
|
||||
const handleHexChange = (value: string) => {
|
||||
setHex(value);
|
||||
if (/^#[0-9A-Fa-f]{6}$/.test(value)) {
|
||||
const newHsl = hexToHsl(value);
|
||||
handleHslChange(newHsl);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover triggerScaleOnOpen={false}>
|
||||
<Popover triggerScaleOnOpen={false} placement="bottom">
|
||||
<PopoverTrigger>
|
||||
<div
|
||||
className='w-36 h-8 rounded-md cursor-pointer border border-content4'
|
||||
style={{ background: color }}
|
||||
/>
|
||||
<div className="flex items-center gap-2 cursor-pointer group">
|
||||
<div
|
||||
className="w-10 h-10 rounded-lg shadow-sm border-2 border-default-200 transition-transform group-hover:scale-105"
|
||||
style={{ background: color }}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs font-mono text-default-500">{hex}</span>
|
||||
<span className="text-xs font-mono text-default-400">HSL({Math.round(hsl.h)}, {Math.round(hsl.s)}%, {Math.round(hsl.l)}%)</span>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
{/* 移除 PopoverContent 默认的事件阻止,允许鼠标拖动到外部 */}
|
||||
<PopoverContent className='pointer-events-auto'>
|
||||
<SketchPicker
|
||||
color={color}
|
||||
onChange={handleChange}
|
||||
className='!bg-transparent !shadow-none'
|
||||
/>
|
||||
<PopoverContent className="w-72 p-4 bg-background/80 backdrop-blur-xl border border-default-200 shadow-2xl rounded-2xl"
|
||||
onMouseDownCapture={() => { isDraggingRef.current = true; }}
|
||||
onMouseUpCapture={() => { isDraggingRef.current = false; }}
|
||||
onTouchStartCapture={() => { isDraggingRef.current = true; }}
|
||||
onTouchEndCapture={() => { isDraggingRef.current = false; }}
|
||||
>
|
||||
<div className="flex flex-col w-full gap-2">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm font-bold text-default-700">选择颜色</span>
|
||||
<div
|
||||
className="w-6 h-6 rounded-full border border-default-200 shadow-sm"
|
||||
style={{ background: color }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SatLightPanel hsl={hsl} onChange={handleHslChange} />
|
||||
<HueSlider hsl={hsl} onChange={handleHslChange} />
|
||||
|
||||
<div className="grid grid-cols-4 gap-2 mt-2 items-center">
|
||||
<span className="text-xs text-default-500 col-span-1">HEX</span>
|
||||
<Input
|
||||
size="sm"
|
||||
variant="flat"
|
||||
value={hex}
|
||||
onChange={(e) => handleHexChange(e.target.value)}
|
||||
className="col-span-3 font-mono"
|
||||
classNames={{
|
||||
input: "text-xs uppercase",
|
||||
inputWrapper: "h-8 min-h-8"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 gap-2 items-center">
|
||||
<span className="text-xs text-default-500 col-span-1">HSL</span>
|
||||
<div className="col-span-3 flex gap-1">
|
||||
<Input
|
||||
size="sm" variant="flat" type="number"
|
||||
value={Math.round(hsl.h).toString()}
|
||||
onChange={(e) => handleHslChange({ ...hsl, h: Number(e.target.value) })}
|
||||
endContent={<span className="text-xs text-default-400">H</span>}
|
||||
classNames={{ input: "text-xs", inputWrapper: "h-8 min-h-8 px-1" }}
|
||||
/>
|
||||
<Input
|
||||
size="sm" variant="flat" type="number"
|
||||
value={Math.round(hsl.s).toString()}
|
||||
onChange={(e) => handleHslChange({ ...hsl, s: Number(e.target.value) })}
|
||||
endContent={<span className="text-xs text-default-400">S</span>}
|
||||
classNames={{ input: "text-xs", inputWrapper: "h-8 min-h-8 px-1" }}
|
||||
/>
|
||||
<Input
|
||||
size="sm" variant="flat" type="number"
|
||||
value={Math.round(hsl.l).toString()}
|
||||
onChange={(e) => handleHslChange({ ...hsl, l: Number(e.target.value) })}
|
||||
endContent={<span className="text-xs text-default-400">L</span>}
|
||||
classNames={{ input: "text-xs", inputWrapper: "h-8 min-h-8 px-1" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1 mt-2 flex-wrap justify-between">
|
||||
{["#006FEE", "#17C964", "#F5A524", "#F31260", "#7828C8", "#000000", "#FFFFFF"].map((c) => (
|
||||
<button
|
||||
key={c}
|
||||
className="w-6 h-6 rounded-full border border-default-200 shadow-sm transition-transform hover:scale-110 active:scale-95"
|
||||
style={{ backgroundColor: c }}
|
||||
onClick={() => handleHexChange(c)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorPicker;
|
||||
export default ColorPicker;
|
||||
@ -500,10 +500,13 @@ const ThemeConfigCard = () => {
|
||||
return (
|
||||
<ColorPicker
|
||||
color={color}
|
||||
onChange={(result) => {
|
||||
onChange(
|
||||
`${result.hsl.h} ${result.hsl.s * 100}% ${result.hsl.l * 100}%`
|
||||
);
|
||||
onChange={(hslString) => {
|
||||
// ColorPicker returns hsl(h, s%, l%) string
|
||||
// We need to parse it and convert to "h s% l%" format for theme config
|
||||
const match = hslString.match(/hsl\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)%,\s*(\d+(?:\.\d+)?)%\)/);
|
||||
if (match) {
|
||||
onChange(`${match[1]} ${match[2]}% ${match[3]}%`);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -634,9 +634,6 @@ importers:
|
||||
react:
|
||||
specifier: ^19.0.0
|
||||
version: 19.2.0
|
||||
react-color:
|
||||
specifier: ^2.19.3
|
||||
version: 2.19.3(react@19.2.0)
|
||||
react-dom:
|
||||
specifier: ^19.0.0
|
||||
version: 19.2.0(react@19.2.0)
|
||||
@ -1859,11 +1856,6 @@ packages:
|
||||
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
||||
'@icons/material@0.2.4':
|
||||
resolution: {integrity: sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
'@img/colour@1.0.0':
|
||||
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -5154,9 +5146,6 @@ packages:
|
||||
markdown-table@3.0.4:
|
||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||
|
||||
material-colors@1.2.6:
|
||||
resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==}
|
||||
|
||||
math-intrinsics@1.1.0:
|
||||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -5859,11 +5848,6 @@ packages:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
||||
react-color@2.19.3:
|
||||
resolution: {integrity: sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
react-dom@19.2.0:
|
||||
resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==}
|
||||
peerDependencies:
|
||||
@ -5969,11 +5953,6 @@ packages:
|
||||
resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
reactcss@1.2.3:
|
||||
resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
read-cache@1.0.0:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
|
||||
@ -6488,9 +6467,6 @@ packages:
|
||||
tinybench@2.9.0:
|
||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||
|
||||
tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
|
||||
tinyexec@0.3.2:
|
||||
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
|
||||
|
||||
@ -8382,10 +8358,6 @@ snapshots:
|
||||
|
||||
'@humanwhocodes/retry@0.4.3': {}
|
||||
|
||||
'@icons/material@0.2.4(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
|
||||
'@img/colour@1.0.0': {}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.34.5':
|
||||
@ -12298,8 +12270,6 @@ snapshots:
|
||||
|
||||
markdown-table@3.0.4: {}
|
||||
|
||||
material-colors@1.2.6: {}
|
||||
|
||||
math-intrinsics@1.1.0: {}
|
||||
|
||||
mdast-util-find-and-replace@3.0.2:
|
||||
@ -13214,17 +13184,6 @@ snapshots:
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
|
||||
react-color@2.19.3(react@19.2.0):
|
||||
dependencies:
|
||||
'@icons/material': 0.2.4(react@19.2.0)
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
material-colors: 1.2.6
|
||||
prop-types: 15.8.1
|
||||
react: 19.2.0
|
||||
reactcss: 1.2.3(react@19.2.0)
|
||||
tinycolor2: 1.6.0
|
||||
|
||||
react-dom@19.2.0(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
@ -13329,11 +13288,6 @@ snapshots:
|
||||
|
||||
react@19.2.0: {}
|
||||
|
||||
reactcss@1.2.3(react@19.2.0):
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
react: 19.2.0
|
||||
|
||||
read-cache@1.0.0:
|
||||
dependencies:
|
||||
pify: 2.3.0
|
||||
@ -14023,8 +13977,6 @@ snapshots:
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
|
||||
tinycolor2@1.6.0: {}
|
||||
|
||||
tinyexec@0.3.2: {}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user