/
kan64
/
spreadsheet-lab
Обзор
Документация
Войти
/
kan64
/
spreadsheet-lab
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
client/src/components/ColorPicker.tsx
125 строк
4 KB
Anton Kravchenkov
first_commit
18 фев 2026, 23:41
18 фев 2026, 23:41
42314b2
Код
Авторство
О чём код?
import React, { useState, useRef, useEffect } from 'react'; const PALETTE: string[][] = [ ['#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#d9d9d9', '#efefef', '#f3f3f3', '#ffffff'], ['#980000', '#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#4a86e8', '#0000ff', '#9900ff', '#ff00ff'], ['#e6b8af', '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3', '#c9daf8', '#cfe2f3', '#d9d2e9', '#ead1dc'], ['#dd7e6b', '#ea9999', '#f9cb9c', '#ffe599', '#b6d7a8', '#a2c4c9', '#a4c2f4', '#9fc5e8', '#b4a7d6', '#d5a6bd'], ['#cc4125', '#e06666', '#f6b26b', '#ffd966', '#93c47d', '#76a5af', '#6d9eeb', '#6fa8dc', '#8e7cc3', '#c27ba0'], ['#a61c00', '#cc0000', '#e69138', '#f1c232', '#6aa84f', '#45818e', '#3c78d8', '#3d85c6', '#674ea7', '#a64d79'], ['#85200c', '#990000', '#b45f06', '#bf9000', '#38761d', '#134f5c', '#1155cc', '#0b5394', '#351c75', '#741b47'], ['#5b0f00', '#660000', '#783f04', '#7f6000', '#274e13', '#0c343d', '#1c4587', '#073763', '#20124d', '#4c1130'], ]; interface ColorPickerProps { currentColor: string | undefined; defaultColor: string; onColorChange: (color: string) => void; onReset?: () => void; disabled?: boolean; icon: React.ReactNode; title: string; resetLabel?: string; } export const ColorPicker: React.FC<ColorPickerProps> = ({ currentColor, defaultColor, onColorChange, onReset, disabled, icon, title, resetLabel = 'Сбросить', }) => { const [open, setOpen] = useState(false); const wrapperRef = useRef<HTMLDivElement>(null); useEffect(() => { if (!open) return; const handleClickOutside = (e: MouseEvent) => { if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) { setOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [open]); return ( <div className="color-picker-wrapper" ref={wrapperRef}> <button className="toolbar-btn color-picker-trigger" onClick={() => setOpen(!open)} disabled={disabled} title={title} > {icon} <div className="color-indicator" style={{ backgroundColor: currentColor || defaultColor }} /> <svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor" className="color-picker-arrow" > <path d="M1 2.5 L4 5.5 L7 2.5" /> </svg> </button> {open && ( <div className="color-picker-dropdown"> {onReset && ( <> <button className="color-picker-reset" onClick={() => { onReset(); setOpen(false); }} > <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"> <line x1="4" y1="4" x2="20" y2="20" /> <line x1="20" y1="4" x2="4" y2="20" /> </svg> {resetLabel} </button> <div className="color-picker-sep" /> </> )} <div className="color-picker-grid"> {PALETTE.map((row, ri) => ( <div key={ri} className="color-picker-row"> {row.map((color) => ( <button key={color} className={`color-picker-swatch ${currentColor === color ? 'active' : ''}`} style={{ backgroundColor: color }} title={color} onClick={() => { onColorChange(color); setOpen(false); }} /> ))} </div> ))} </div> <div className="color-picker-sep" /> <label className="color-picker-custom"> <span>Другой цвет...</span> <input type="color" value={currentColor || defaultColor} onChange={(e) => { onColorChange(e.target.value); setOpen(false); }} className="color-input" /> </label> </div> )} </div> ); };