123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- import React, { useState } from "react";
- import {
- ColorPicker,
- Popover,
- Dropdown,
- Button,
- Space,
- Tooltip,
- InputNumber,
- Input,
- } from "antd";
- import type { ColorPickerProps } from "antd";
- import noColorImg from "@/assets/icon/no-color.png";
- import {
- ArrowRightOutlined,
- CaretDownOutlined,
- CheckOutlined,
- SwapOutlined,
- } from "@ant-design/icons";
- import morePng from "@/assets/icon/more-color.png";
- import insertCss from "insert-css";
- import { useModel } from "umi";
- // 系统色
- const presetColors1 = [
- "#EFECEB",
- "#F2F2F2",
- "#E7EBED",
- "#FADCDB",
- "#FBEADA",
- "#FCF9EA",
- "#E5F6DA",
- "#DBF5F5",
- "#D2D6F9",
- "#FADDED",
- "#DED9D7",
- "#D9D9D9",
- "#E0E0E0",
- "#F5B9B7",
- "#F8D5B5",
- "#F6EDC1",
- "#CAEDB4",
- "#B7EAEB",
- "#A6AEF3",
- "#F6BBDB",
- "#BEB3AF",
- "#BFBFBF",
- "#9E9E9E",
- "#F19594",
- "#F4C18F",
- "#F1E4A2",
- "#B0E38F",
- "#94E0E1",
- "#7985EC",
- "#F199C8",
- "#9D8C88",
- "#A6A6A6",
- "#616161",
- "#EC7270",
- "#F1AC6A",
- "#E9D66F",
- "#95DA69",
- "#70D5D7",
- "#5B79E8",
- "#ED77B6",
- "#5C4038",
- "#7F7F7F",
- "#262626",
- "#A23735",
- "#A66A30",
- "#A7932C",
- "#569230",
- "#358E90",
- "#314AA4",
- "#A23C73",
- ];
- // 莫兰迪
- const presetColors2 = [
- "#F1F1E8",
- "#ECECED",
- "#F3FAF9",
- "#F4F0EA",
- "#F9FAEE",
- "#F8F9F5",
- "#F5E9ED",
- "#FCE7EB",
- "#F9EEE1",
- "#FEF5EF",
- "#E3E2D1",
- "#D9DADB",
- "#E8F5F4",
- "#E9E1D5",
- "#F3F6DD",
- "#F0F3EC",
- "#EBD2DC",
- "#F9CFD7",
- "#F3DDC3",
- "#FDEBDF",
- "#D6D4BA",
- "#C5C7CA",
- "#DCEFEE",
- "#DDD1C1",
- "#EEF1CB",
- "#E9ECE2",
- "#E0BCCA",
- "#F6B6C4",
- "#EDCCA5",
- "#FCE2CF",
- "#C8C5A3",
- "#B2B5B8",
- "#D1EAE9",
- "#D2C2AC",
- "#E8EDBA",
- "#E1E6D9",
- "#D6A5B9",
- "#F39EB0",
- "#E7BB87",
- "#FBD8BF",
- "#959270",
- "#7F8285",
- "#9EB7B6",
- "#9F8F79",
- "#B5BA87",
- "#AEB3A6",
- "#A37286",
- "#C06B7D",
- "#B48854",
- "#C8A58C",
- ];
- // 中国风
- const presetColors3 = [
- "#866B50",
- "#705138",
- "#5A5645",
- "#5C3719",
- "#775550",
- "#5A1216",
- "#B0913E",
- "#964D22",
- "#E28342",
- "#C37940",
- "#2C2305",
- "#645822",
- "#6B5E4C",
- "#556980",
- "#70887D",
- "#5B8483",
- "#975F42",
- "#A2825E",
- "#DDAB4C",
- "#91A45A",
- "#4D5255",
- "#587D8C",
- "#737C7B",
- "#B1AD94",
- "#ADB4A9",
- "#467E7D",
- "#94B68E",
- "#894276",
- "#C36077",
- "#D59482",
- "#144A74",
- "#495C69",
- "#314656",
- "#134857",
- "#7E8489",
- "#8F927F",
- "#B2BBBE",
- "#67907C",
- "#539271",
- "#D2B116",
- "#322F3B",
- "#525288",
- "#8076A3",
- "#1A94BC",
- "#5D3131",
- "#314A43",
- "#C1651A",
- "#DE9E44",
- "#D2B116",
- "#D2D97A",
- ];
- // 潘通色
- const presetColors4 = [
- "#E3F0E1",
- "#EEE7F1",
- "#E4D5D8",
- "#FDF8DC",
- "#DFE3F5",
- "#FFF1D5",
- "#DFE5DB",
- "#E2EFF5",
- "#DEE6E6",
- "#F9DDD6",
- "#C7E1C3",
- "#DED0E4",
- "#CAAAB1",
- "#FBF1B8",
- "#BFC7EA",
- "#FEE2AB",
- "#BFCAB6",
- "#C6DFEA",
- "#BDCECD",
- "#F3BBAD",
- "#ABD1A6",
- "#CDB8D6",
- "#AF808A",
- "#F8EB95",
- "#9EAAE0",
- "#FED480",
- "#A0B092",
- "#A9CEE0",
- "#9DB5B5",
- "#ED9984",
- "#8FC288",
- "#BDA1C9",
- "#955563",
- "#F6E471",
- "#7E8ED5",
- "#FDC556",
- "#80956D",
- "#8DBED5",
- "#7C9D9C",
- "#E7775B",
- "#5C8F55",
- "#8A6E96",
- "#622230",
- "#C3B13E",
- "#4B5BA2",
- "#CA9223",
- "#4D623A",
- "#5A8BA2",
- "#496A69",
- "#B44428",
- ];
- const baseColor = [
- "#FFFFFF",
- "#7F8B98",
- "#000000",
- "#E74F4C",
- "#ED9745",
- "#E0C431",
- "#7BD144",
- "#4CCBCD",
- "#4669EA",
- "#E855A4",
- ];
- const colorTxts = ["系统色", "莫兰迪", "中国风", "潘通色"];
- const colors = [presetColors1, presetColors2, presetColors3, presetColors4];
- export default function CustomColorPicker(props: {
- onChange?: (color: string) => void;
- color?: string;
- pickerOption?: ColorPickerProps;
- children?: React.ReactNode;
- disabled?: boolean;
- otherPopoverAttr?: Partial<Parameters<typeof Popover>[0]>;
- }) {
- const { color } = props;
- const [colorSystem, setColorSystem] = useState(0);
- const [colorType, setColorType] = useState<"rgb" | "hex">("rgb");
- const [open, setOpen] = useState(false);
- const { historyColor, addHistoryCoolor } = useModel('appModel');
- // 修改值
- const onChange = (value: string) => {
- props.onChange?.(value);
- handleOpenChange(false);
- addHistoryCoolor(value);
- };
- insertCss(`
- .rgb .shalu-input-number-input {
- padding: 0 !important;
- }
- `);
- const handleSystemAbsorption = () => {
- // @ts-ignore 系统拾色
- const dropper = new EyeDropper();
- dropper.open().then((result: { sRGBHex: string }) => {
- onChange(result.sRGBHex);
- });
- };
- const handleChangeColorType = () => {
- setColorType(colorType === "rgb" ? "hex" : "rgb");
- };
- // hex转rgb
- const hexToRGB = (hex?: string) => {
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex || "");
- return result
- ? {
- r: parseInt(result[1], 16),
- g: parseInt(result[2], 16),
- b: parseInt(result[3], 16),
- }
- : {
- r: 255,
- g: 255,
- b: 255,
- };
- };
- const handleChangeRGB = (value: number | null, type: "r" | "g" | "b") => {
- const rgb = hexToRGB(color);
- const val = value?.toString(16);
- onChange(
- `${type === "r" ? val : rgb.r}${type === "g" ? val : rgb.g}${type === "b" ? val : rgb.b}`
- );
- };
- const handleOpenChange = (newOpen: boolean) => {
- setOpen(newOpen && !props.disabled);
- };
- const PopoverContent = () => {
- return (
- <div className="w-200px">
- <Dropdown
- menu={{
- items: colorTxts.map((item, index) => {
- return {
- key: index,
- label: (
- <span onClick={() => setColorSystem(index)}>
- <span className="inline-block w-24px">
- {colorSystem === index && <CheckOutlined />}
- </span>
- {item}
- </span>
- ),
- };
- }),
- }}
- >
- <div>
- {colorTxts[colorSystem]}
- <CaretDownOutlined />
- </div>
- </Dropdown>
- <Button
- size="small"
- className="block w-full my-8px"
- onClick={() => onChange("transparent")}
- >
- 无填充
- </Button>
- <Space wrap size={4} className="justify-between">
- {[...colors[colorSystem], ...baseColor].map((item, index) => {
- return (
- <Tooltip title={item} key={index}>
- <div
- className="w-14px h-14px border border-solid border-#00000000 border-radius-2px shadow hover:shadow-[0_0_4px_0_rgba(0,0,0,0.3)]"
- style={{ background: item }}
- onClick={() => onChange(item)}
- />
- </Tooltip>
- );
- })}
- </Space>
- <div className="text-12px text-#666666 my-8px">最近使用</div>
- <Space wrap size={4} className="justify-between">
- {[...historyColor].map((item, index) => {
- return (
- <Tooltip title={item} key={index}>
- <div
- className="w-14px h-14px border border-solid border-#00000000 border-radius-2px shadow hover:shadow-[0_0_4px_0_rgba(0,0,0,0.3)]"
- style={{ background: item }}
- onClick={() => onChange(item)}
- />
- </Tooltip>
- );
- })}
- </Space>
- <div className="flex items-center justify-center mt-8px">
- <Button
- type="text"
- size="small"
- icon={<i className="iconfont icon-xise" />}
- onClick={handleSystemAbsorption}
- />
- <Button type="text" size="small" onClick={handleChangeColorType}>
- {colorType === "rgb" ? "RGB" : "HEX"}
- <SwapOutlined />
- </Button>
- {colorType === "rgb" ? (
- <div className="flex rgb">
- <InputNumber
- size="small"
- max={255}
- min={0}
- precision={0}
- className="w-30px px-0"
- controls={false}
- value={hexToRGB(color).r}
- onChange={(value) => handleChangeRGB(value, "r")}
- />
- <InputNumber
- size="small"
- max={255}
- min={0}
- precision={0}
- className="w-30px"
- controls={false}
- value={hexToRGB(color).g}
- onChange={(value) => handleChangeRGB(value, "g")}
- />
- <InputNumber
- size="small"
- max={255}
- min={0}
- precision={0}
- className="w-30px"
- controls={false}
- value={hexToRGB(color).b}
- onChange={(value) => handleChangeRGB(value, "b")}
- />
- </div>
- ) : (
- <Input maxLength={6} pattern="[0-9a-fA-F]{6}" />
- )}
- <Tooltip title="当前颜色">
- <div
- className="ml-4px w-14px h-14px border border-solid border-#00000010 border-radius-2px"
- style={{ background: color || "#ffffff" }}
- />
- </Tooltip>
- </div>
- <div className="my-8px border border-transparent border-1px border-solid border-b-#e9edf2" />
- <ColorPicker
- value={color}
- disabledAlpha
- format="hex"
- onChange={(value) => onChange(value.toHexString())}
- className="w-0 h-0"
- >
- <Button
- type="text"
- className="w-full flex justify-between items-center"
- >
- <span className="flex-important items-center">
- <img className="w-16px h-16px mr-8px" src={morePng} alt="" />
- <span className="text-size-12px">更多颜色</span>
- </span>
- <ArrowRightOutlined />
- </Button>
- </ColorPicker>
- </div>
- );
- };
- const backgroundStyle =
- color === "transparent"
- ? { background: `url(${noColorImg})`, backgroundSize: "cover" }
- : { background: color };
- const popoverAttrs = props.otherPopoverAttr || {};
- return (
- <div className="inline-block">
- <Popover
- autoAdjustOverflow
- destroyTooltipOnHide
- content={<PopoverContent />}
- trigger="click"
- placement="bottom"
- arrow={false}
- open={open}
- onOpenChange={handleOpenChange}
- {...popoverAttrs}
- >
- {props.children ? (
- props.children
- ) : (
- <div
- className="w-30px h-24px border border-solid border-#435f7329 border-radius-2px"
- style={{
- ...backgroundStyle,
- opacity: props.disabled ? 0.5 : 1
- }}
- />
- )}
- </Popover>
- </div>
- );
- }
|