docs: replace react-color with color-picker (#42350)

* style: fix prettier problem

* docs: add presets label

* style: fix prettier problem

* style: fix prettier
This commit is contained in:
红果汁 2023-05-15 15:11:05 +08:00 committed by GitHub
parent 0a81a00771
commit aeabe74fbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 402 additions and 599 deletions

View File

@ -1,12 +1,11 @@
import { Input, Space, Popover } from 'antd';
import { css } from '@emotion/react';
import { ColorPicker, Input, Space } from 'antd';
import type { Color, ColorPickerProps } from 'antd/es/color-picker';
import { generateColor } from 'antd/es/color-picker/util';
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import { css } from '@emotion/react';
import { TinyColor } from '@ctrl/tinycolor';
import type { ColorPanelProps } from 'antd-token-previewer/es/ColorPanel';
import ColorPanel from 'antd-token-previewer/es/ColorPanel';
import { PRESET_COLORS } from './colorUtil';
import useSiteToken from '../../../../hooks/useSiteToken';
import { PRESET_COLORS } from './colorUtil';
const useStyle = () => {
const { token } = useSiteToken();
@ -38,7 +37,7 @@ const useStyle = () => {
};
};
const DebouncedColorPanel: FC<ColorPanelProps> = ({ color, onChange }) => {
const DebouncedColorPicker: FC<ColorPickerProps> = ({ value: color, onChange, children }) => {
const [value, setValue] = useState(color);
useEffect(() => {
@ -52,23 +51,36 @@ const DebouncedColorPanel: FC<ColorPanelProps> = ({ color, onChange }) => {
setValue(color);
}, [color]);
return <ColorPanel color={value} onChange={setValue} />;
return (
<ColorPicker
value={value}
onChange={setValue}
presets={[
{
label: 'PresetColors',
colors: PRESET_COLORS,
},
]}
>
{children}
</ColorPicker>
);
};
export interface RadiusPickerProps {
value?: string;
value?: string | Color;
onChange?: (value: string) => void;
}
export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
export default function ThemeColorPicker({ value, onChange }: RadiusPickerProps) {
const style = useStyle();
const matchColors = React.useMemo(() => {
const valueStr = new TinyColor(value).toRgbString();
const valueStr = generateColor(value).toRgbString();
let existActive = false;
const colors = PRESET_COLORS.map((color) => {
const colorStr = new TinyColor(color).toRgbString();
const colorStr = generateColor(color).toRgbString();
const active = colorStr === valueStr;
existActive = existActive || active;
@ -92,7 +104,7 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
return (
<Space size="large">
<Input
value={value}
value={typeof value === 'string' ? value : value.toHexString()}
onChange={(event) => {
onChange?.(event.target.value);
}}
@ -126,17 +138,9 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) {
if (picker) {
colorNode = (
<Popover
key={color}
overlayInnerStyle={{ padding: 0 }}
content={
<DebouncedColorPanel color={value || ''} onChange={(c) => onChange?.(c)} />
}
trigger="click"
arrow={false}
>
<DebouncedColorPicker value={value || ''} onChange={onChange}>
{colorNode}
</Popover>
</DebouncedColorPicker>
);
}

View File

@ -1,4 +1,4 @@
import { TinyColor } from '@ctrl/tinycolor';
import { generateColor } from 'antd/es/color-picker/util';
export const DEFAULT_COLOR = '#1677FF';
export const PINK_COLOR = '#ED4192';
@ -47,10 +47,10 @@ export function getClosetColor(colorPrimary?: string | null) {
return null;
}
const colorPrimaryRGB = new TinyColor(colorPrimary).toRgb();
const colorPrimaryRGB = generateColor(colorPrimary).toRgb();
const distance = COLOR_IMAGES.map(({ color }) => {
const colorObj = new TinyColor(color).toRgb();
const colorObj = generateColor(color).toRgb();
const dist = Math.sqrt(
(colorObj.r - colorPrimaryRGB.r) ** 2 +
(colorObj.g - colorPrimaryRGB.g) ** 2 +

View File

@ -1,12 +1,10 @@
import * as React from 'react';
import { css } from '@emotion/react';
import { TinyColor } from '@ctrl/tinycolor';
import {
BellOutlined,
FolderOutlined,
HomeOutlined,
QuestionCircleOutlined,
} from '@ant-design/icons';
import { css } from '@emotion/react';
import type { MenuProps } from 'antd';
import {
Breadcrumb,
@ -18,21 +16,24 @@ import {
Menu,
Radio,
Space,
theme,
Typography,
theme,
} from 'antd';
import type { Color } from 'antd/es/color-picker';
import { generateColor } from 'antd/es/color-picker/util';
import * as React from 'react';
import useLocale from '../../../../hooks/useLocale';
import useSiteToken from '../../../../hooks/useSiteToken';
import SiteContext from '../../../../theme/slots/SiteContext';
import Group from '../Group';
import { useCarouselStyle } from '../util';
import BackgroundImage from './BackgroundImage';
import ColorPicker from './ColorPicker';
import MobileCarousel from './MobileCarousel';
import RadiusPicker from './RadiusPicker';
import type { THEME } from './ThemePicker';
import ThemePicker from './ThemePicker';
import ColorPicker from './ColorPicker';
import RadiusPicker from './RadiusPicker';
import Group from '../Group';
import BackgroundImage from './BackgroundImage';
import { DEFAULT_COLOR, getAvatarURL, getClosetColor, PINK_COLOR } from './colorUtil';
import SiteContext from '../../../../theme/slots/SiteContext';
import { useCarouselStyle } from '../util';
import MobileCarousel from './MobileCarousel';
import { DEFAULT_COLOR, PINK_COLOR, getAvatarURL, getClosetColor } from './colorUtil';
const { Header, Content, Sider } = Layout;
@ -221,12 +222,12 @@ const sideMenuItems: MenuProps['items'] = [
// ============================= Theme =============================
function getTitleColor(colorPrimary: string, isLight?: boolean) {
function getTitleColor(colorPrimary: string | Color, isLight?: boolean) {
if (!isLight) {
return '#FFF';
}
const color = new TinyColor(colorPrimary);
const color = generateColor(colorPrimary);
const closestColor = getClosetColor(colorPrimary);
switch (closestColor) {
@ -236,13 +237,13 @@ function getTitleColor(colorPrimary: string, isLight?: boolean) {
return undefined;
default:
return color.toHsl().l < 0.7 ? '#FFF' : undefined;
return color.toHsb().b < 0.7 ? '#FFF' : undefined;
}
}
interface ThemeData {
themeType: THEME;
colorPrimary: string;
colorPrimary: string | Color;
borderRadius: number;
compact: 'default' | 'compact';
}
@ -280,10 +281,14 @@ export default function Theme() {
setThemeData(nextThemeData);
};
const { compact, themeType, ...themeToken } = themeData;
const { compact, themeType, colorPrimary, ...themeToken } = themeData;
const isLight = themeType !== 'dark';
const [form] = Form.useForm();
const { isMobile } = React.useContext(SiteContext);
const colorPrimaryValue = React.useMemo(
() => (typeof colorPrimary === 'string' ? colorPrimary : colorPrimary.toHexString()),
[colorPrimary],
);
// const algorithmFn = isLight ? theme.defaultAlgorithm : theme.darkAlgorithm;
const algorithmFn = React.useMemo(() => {
@ -309,14 +314,14 @@ export default function Theme() {
}, [themeType]);
// ================================ Tokens ================================
const closestColor = getClosetColor(themeData.colorPrimary);
const closestColor = getClosetColor(colorPrimaryValue);
const [backgroundColor, avatarColor] = React.useMemo(() => {
let bgColor = 'transparent';
const mapToken = theme.defaultAlgorithm({
...theme.defaultConfig.token,
colorPrimary: themeData.colorPrimary,
colorPrimary: colorPrimaryValue,
});
if (themeType === 'dark') {
@ -328,14 +333,14 @@ export default function Theme() {
}
return [bgColor, mapToken.colorPrimaryBgHover];
}, [themeType, closestColor, themeData.colorPrimary]);
}, [themeType, closestColor, colorPrimaryValue]);
const logoColor = React.useMemo(() => {
const hsl = new TinyColor(themeData.colorPrimary).toHsl();
hsl.l = Math.min(hsl.l, 0.7);
const hsb = generateColor(colorPrimaryValue).toHsb();
hsb.b = Math.min(hsb.b, 0.7);
return new TinyColor(hsl).toHexString();
}, [themeData.colorPrimary]);
return generateColor(hsb).toHexString();
}, [colorPrimaryValue]);
// ================================ Render ================================
const themeNode = (
@ -349,6 +354,7 @@ export default function Theme() {
// colorBgContainer: '#474C56',
// colorBorderSecondary: 'rgba(255,255,255,0.06)',
}),
colorPrimary: colorPrimaryValue,
},
hashed: true,
algorithm: algorithmFn,
@ -511,7 +517,7 @@ export default function Theme() {
) : (
<Group
title={locale.themeTitle}
titleColor={getTitleColor(themeData.colorPrimary, isLight)}
titleColor={getTitleColor(colorPrimaryValue, isLight)}
description={locale.themeDesc}
id="flexible"
background={backgroundColor}
@ -567,7 +573,7 @@ export default function Theme() {
</div>
{/* >>>>>> Background Image <<<<<< */}
<BackgroundImage isLight={isLight} colorPrimary={themeData.colorPrimary} />
<BackgroundImage isLight={isLight} colorPrimary={colorPrimaryValue} />
</>
}
>

View File

@ -1,7 +1,7 @@
import type { ChangeEvent } from 'react';
import React, { useMemo, useState } from 'react';
import { ColorPicker } from 'antd';
import type { Color } from 'antd/es/color-picker';
import { FormattedMessage } from 'dumi';
import ColorPicker from './ColorPicker';
import React, { useMemo, useState } from 'react';
import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; // 主色推荐最小饱和度
@ -9,26 +9,20 @@ const primaryMinBrightness = 70; // 主色推荐最小亮度
const ColorPaletteTool: React.FC = () => {
const [primaryColor, setPrimaryColor] = useState<string>('#1890ff');
const [primaryColorInstance, setPrimaryColorInstance] = useState(null);
const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => {
const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value
: e;
setPrimaryColor(value as string);
const [primaryColorInstance, setPrimaryColorInstance] = useState<Color>(null);
const handleChangeColor = (color: Color, hex: string) => {
setPrimaryColor(hex);
setPrimaryColorInstance(color);
};
const colorValidation = useMemo<React.ReactNode>(() => {
let text = '';
if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(
primaryColorInstance.hsv.s * 100
).toFixed(2)}`;
const { s, b } = primaryColorInstance.toHsb();
if (s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(s * 100).toFixed(2)}`;
}
if (primaryColorInstance.hsv.v * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(
primaryColorInstance.hsv.v * 100
).toFixed(2)}`;
if (b * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(b * 100).toFixed(2)}`;
}
}
return <span className="color-palette-picker-validation">{text.trim()}</span>;
@ -41,7 +35,7 @@ const ColorPaletteTool: React.FC = () => {
<div className="main-color">{ColorPatterns({ color: primaryColor })}</div>
<div className="color-palette-picker">
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<ColorPicker color={primaryColor} onChange={handleChangeColor} />
<ColorPicker value={primaryColor} onChange={handleChangeColor} />
</span>
<span className="color-palette-picker-value">{primaryColor}</span>
{colorValidation}

View File

@ -1,8 +1,6 @@
import React, { useMemo, useState } from 'react';
import type { ChangeEvent } from 'react';
import { Col, ColorPicker, Row } from 'antd';
import { FormattedMessage } from 'dumi';
import { Row, Col } from 'antd';
import ColorPicker from './ColorPicker';
import React, { useMemo, useState } from 'react';
import ColorPatterns from './ColorPatterns';
const primaryMinSaturation = 70; // 主色推荐最小饱和度
@ -13,33 +11,24 @@ const ColorPaletteTool: React.FC = () => {
const [backgroundColor, setBackgroundColor] = useState<string>('#141414');
const [primaryColorInstance, setPrimaryColorInstance] = useState(null);
const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => {
const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value
: e;
setPrimaryColor(value as string);
const handleChangeColor = (color: Color, hex: string) => {
setPrimaryColor(hex);
setPrimaryColorInstance(color);
};
const handleChangeBackgroundColor = (e: string | ChangeEvent) => {
const value = (e as ChangeEvent<HTMLInputElement>).target
? (e as ChangeEvent<HTMLInputElement>).target.value
: e;
setBackgroundColor(value as string);
const handleChangeBackgroundColor = (_, hex: string) => {
setBackgroundColor(hex);
};
const colorValidation = useMemo<React.ReactNode>(() => {
let text = '';
if (primaryColorInstance) {
if (primaryColorInstance.hsv.s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(
primaryColorInstance.hsv.s * 100
).toFixed(2)}`;
const { s, b } = primaryColorInstance.toHsb();
if (s * 100 < primaryMinSaturation) {
text += ` 饱和度建议不低于${primaryMinSaturation}(现在 ${(s * 100).toFixed(2)}`;
}
if (primaryColorInstance.hsv.v * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(
primaryColorInstance.hsv.v * 100
).toFixed(2)}`;
if (b * 100 < primaryMinBrightness) {
text += ` 亮度建议不低于${primaryMinBrightness}(现在 ${(b * 100).toFixed(2)}`;
}
}
return (
@ -63,7 +52,7 @@ const ColorPaletteTool: React.FC = () => {
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker color={primaryColor} onChange={handleChangeColor} />
<ColorPicker value={primaryColor} onChange={handleChangeColor} />
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{primaryColor}</span>
@ -78,7 +67,7 @@ const ColorPaletteTool: React.FC = () => {
<span style={{ display: 'inline-block', verticalAlign: 'middle' }}>
<Row>
<Col span={18}>
<ColorPicker color={backgroundColor} onChange={handleChangeBackgroundColor} />
<ColorPicker value={backgroundColor} onChange={handleChangeBackgroundColor} />
</Col>
<Col span={6}>
<span className="color-palette-pick-hex">{backgroundColor}</span>

View File

@ -1,116 +0,0 @@
import React, { useState } from 'react';
import { SketchPicker } from 'react-color';
const noop = () => {};
interface ColorPickerProps {
color?: string;
small?: boolean;
position?: string;
presetColors?: string[];
onChange?: (hex: string, color: { hex: string }) => void;
onChangeComplete?: (hex: string) => void;
}
const ColorPicker: React.FC<ColorPickerProps> = (props) => {
const {
small,
position = 'bottom',
presetColors,
onChange = noop,
onChangeComplete = noop,
} = props;
const [color, setColor] = useState<string>(props.color);
const [displayColorPicker, setDisplayColorPicker] = useState<boolean>(false);
const handleClick = () => {
setDisplayColorPicker((prev) => !prev);
};
const handleClose = () => {
setDisplayColorPicker(false);
};
const handleChange = (changeColor: { hex: string }) => {
setColor(changeColor.hex);
onChange(changeColor.hex, changeColor);
};
const handleChangeComplete = (completeColor: { hex: string }) => {
setColor(completeColor.hex);
onChangeComplete(completeColor.hex);
};
const width = small ? 80 : 120;
const styles: Record<PropertyKey, React.CSSProperties> = {
color: {
width: `${width}px`,
height: small ? '16px' : '24px',
borderRadius: '2px',
background: color,
},
swatch: {
padding: '4px',
background: '#fff',
borderRadius: '2px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'inline-block',
cursor: 'pointer',
},
popover: {
position: 'absolute',
zIndex: 10,
},
cover: {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
},
wrapper: {
position: 'inherit',
zIndex: 100,
},
};
if (position === 'top') {
styles.wrapper.transform = `translate(calc(-100% + ${width + 8}px), -100%)`;
styles.wrapper.paddingBottom = 8;
}
const swatch: React.ReactNode = (
<div style={styles.swatch} onClick={handleClick}>
<div style={styles.color} />
</div>
);
const picker: React.ReactNode = displayColorPicker ? (
<div style={styles.popover}>
<div style={styles.cover} onClick={handleClose} />
<div style={styles.wrapper}>
<SketchPicker
presetColors={presetColors}
color={color}
onChange={handleChange}
onChangeComplete={handleChangeComplete}
/>
</div>
</div>
) : null;
return position === 'top' ? (
<div>
{picker}
{swatch}
</div>
) : (
<div>
{swatch}
{picker}
</div>
);
};
export default ColorPicker;

View File

@ -1,6 +1,6 @@
import { Button, ConfigProvider, Form, InputNumber } from 'antd';
import { Button, ColorPicker, ConfigProvider, Form, InputNumber } from 'antd';
import type { Color } from 'antd/es/color-picker';
import React from 'react';
import { SketchPicker } from 'react-color';
type ThemeData = {
borderRadius: number;
@ -25,7 +25,7 @@ export default () => {
form={form}
onValuesChange={(changedValues, allValues) => {
const colorObj = changedValues?.colorPrimary
? { colorPrimary: allValues?.colorPrimary?.hex }
? { colorPrimary: (allValues?.colorPrimary as Color)?.toHexString() }
: {};
setData({
...allValues,
@ -38,7 +38,7 @@ export default () => {
wrapperCol={{ span: 20 }}
>
<Form.Item valuePropName="color" name="colorPrimary" label="Primary Color">
<SketchPicker />
<ColorPicker />
</Form.Item>
<Form.Item name="borderRadius" label="Border Radius">
<InputNumber />

View File

@ -119,14 +119,19 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
class="ant-form-item-control-input-content"
>
<div
style="padding: 4px; background: rgb(255, 255, 255); border-radius: 2px; border: 1px solid #dedede; display: inline-block; cursor: pointer;"
class="ant-color-picker-trigger"
>
<div
style="width: 36px; height: 14px; border-radius: 2px; background: rgba(0, 0, 0, 0.15);"
/>
class="ant-color-picker-color-block"
>
<div
class="ant-color-picker-color-block-inner"
style="background: rgba(0, 0, 0, 0.15);"
/>
</div>
</div>
<div
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-popover-placement-bottomLeft"
class="ant-popover ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big ant-color-picker ant-popover-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
@ -139,407 +144,352 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
<div
class="ant-popover-inner"
role="tooltip"
style="padding: 0px;"
>
<div
class="ant-popover-inner-content"
>
<div
class="sketch-picker "
style="width: 200px; padding: 10px 10px 0px; box-sizing: initial; background: rgb(255, 255, 255); border-radius: 4px; box-shadow: 0 0 0 1px rgba(0,0,0,.15), 0 8px 16px rgba(0,0,0,.15);"
class="ant-color-picker-panel"
>
<div
style="width: 100%; padding-bottom: 75%; position: relative; overflow: hidden;"
class="ant-color-picker-inner-panel"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; background: rgb(255, 0, 0);"
class="ant-color-picker-select"
>
<style>
.saturation-white {
background: -webkit-linear-gradient(to right, #fff, rgba(255,255,255,0));
background: linear-gradient(to right, #fff, rgba(255,255,255,0));
}
.saturation-black {
background: -webkit-linear-gradient(to top, #000, rgba(0,0,0,0));
background: linear-gradient(to top, #000, rgba(0,0,0,0));
}
</style>
<div
class="saturation-white"
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
class="ant-color-picker-palette"
style="position: relative;"
>
<div
class="saturation-black"
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
/>
<div
style="position: absolute; top: 100%; left: 0%; cursor: default;"
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
style="width: 4px; height: 4px; box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0,0,0,.3),
0 0 1px 2px rgba(0,0,0,.4); border-radius: 50%; cursor: hand; transform: translate(-2px, -2px);"
class="ant-color-picker-handler"
style="background-color: rgba(0, 0, 0, 0.15);"
/>
</div>
<div
class="ant-color-picker-saturation"
style="background-color: rgb(255, 0, 0);"
/>
</div>
</div>
</div>
<div
class="flexbox-fix"
style="display: flex;"
>
<div
style="padding: 4px 0px; flex: 1;"
class="ant-color-picker-slider-container"
>
<div
style="position: relative; height: 10px; overflow: hidden;"
class="ant-color-picker-slider-group"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
class="ant-color-picker-slider ant-color-picker-slider-hue"
>
<div
class="hue-horizontal"
style="padding: 0px 2px; position: relative; height: 100%;"
class="ant-color-picker-palette"
style="position: relative;"
>
<style>
.hue-horizontal {
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0
33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
background: -webkit-linear-gradient(to right, #f00 0%, #ff0
17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.hue-vertical {
background: linear-gradient(to top, #f00 0%, #ff0 17%, #0f0 33%,
#0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
background: -webkit-linear-gradient(to top, #f00 0%, #ff0 17%,
#0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
</style>
<div
style="position: absolute; left: 0%;"
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
style="margin-top: 1px; width: 4px; border-radius: 1px; height: 8px; box-shadow: 0 0 2px rgba(0, 0, 0, .6); background: rgb(255, 255, 255); transform: translateX(-2px);"
class="ant-color-picker-handler ant-color-picker-handler-sm"
style="background-color: rgb(255, 0, 0);"
/>
</div>
</div>
</div>
</div>
<div
style="position: relative; height: 10px; margin-top: 4px; overflow: hidden;"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; overflow: hidden;"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; background: url(data:image/png;base64,00) left;"
class="ant-color-picker-gradient"
style="position: absolute; inset: 0;"
/>
</div>
</div>
<div
class="ant-color-picker-slider ant-color-picker-slider-alpha"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"
/>
<div
style="position: relative; height: 100%; margin: 0px 3px;"
class="ant-color-picker-palette"
style="position: relative;"
>
<div
style="position: absolute; left: 15%;"
style="position: absolute; left: 0px; top: 0px; z-index: 1;"
>
<div
style="width: 4px; border-radius: 1px; height: 8px; box-shadow: 0 0 2px rgba(0, 0, 0, .6); background: rgb(255, 255, 255); margin-top: 1px; transform: translateX(-2px);"
class="ant-color-picker-handler ant-color-picker-handler-sm"
style="background-color: rgba(0, 0, 0, 0.15);"
/>
</div>
<div
class="ant-color-picker-gradient"
style="position: absolute; inset: 0;"
/>
</div>
</div>
</div>
</div>
<div
style="width: 24px; height: 24px; position: relative; margin-top: 4px; margin-left: 4px; border-radius: 3px;"
>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; background: url(data:image/png;base64,00) left;"
/>
<div
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; border-radius: 2px; background: rgba(0, 0, 0, 0.15); box-shadow: inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25);"
/>
</div>
</div>
<div
class="flexbox-fix"
style="display: flex; padding-top: 4px;"
>
<div
style="flex: 2;"
>
<div
style="position: relative;"
class="ant-color-picker-color-block"
>
<input
id="rc-editable-input-2"
spellcheck="false"
style="width: 80%; padding: 4px 10% 3px; box-shadow: inset 0 0 0 1px #ccc; font-size: 11px;"
value="000000"
<div
class="ant-color-picker-color-block-inner"
style="background: rgba(0, 0, 0, 0.15);"
/>
<label
for="rc-editable-input-2"
style="display: block; text-align: center; font-size: 11px; color: rgb(34, 34, 34); padding-top: 3px; padding-bottom: 4px; text-transform: capitalize;"
>
hex
</label>
</div>
</div>
<div
style="flex: 1; padding-left: 6px;"
class="ant-color-picker-input-container"
>
<div
style="position: relative;"
class="ant-select ant-select-sm ant-select-borderless ant-select-in-form-item ant-color-picker-format-select ant-select-single ant-select-show-arrow"
>
<input
id="rc-editable-input-4"
spellcheck="false"
style="width: 80%; padding: 4px 10% 3px; box-shadow: inset 0 0 0 1px #ccc; font-size: 11px;"
value="0"
/>
<label
for="rc-editable-input-4"
style="display: block; text-align: center; font-size: 11px; color: rgb(34, 34, 34); padding-top: 3px; padding-bottom: 4px; text-transform: capitalize; cursor: ew-resize;"
<div
class="ant-select-selector"
>
r
</label>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="HEX"
>
HEX
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomRight"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; width: 68px;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="HEX"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
hex
</div>
<div
aria-label="HSB"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
role="option"
>
hsb
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
title="HEX"
>
<div
class="ant-select-item-option-content"
>
HEX
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="HSB"
>
<div
class="ant-select-item-option-content"
>
HSB
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="RGB"
>
<div
class="ant-select-item-option-content"
>
RGB
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
style="flex: 1; padding-left: 6px;"
>
<div
style="position: relative;"
class="ant-color-picker-input"
>
<input
id="rc-editable-input-6"
spellcheck="false"
style="width: 80%; padding: 4px 10% 3px; box-shadow: inset 0 0 0 1px #ccc; font-size: 11px;"
value="0"
/>
<label
for="rc-editable-input-6"
style="display: block; text-align: center; font-size: 11px; color: rgb(34, 34, 34); padding-top: 3px; padding-bottom: 4px; text-transform: capitalize; cursor: ew-resize;"
<span
class="ant-input-affix-wrapper ant-color-picker-hex-input ant-input-affix-wrapper-sm"
>
g
</label>
<span
class="ant-input-prefix"
>
#
</span>
<input
class="ant-input ant-input-sm"
type="text"
value="000000"
/>
</span>
</div>
</div>
<div
style="flex: 1; padding-left: 6px;"
>
<div
style="position: relative;"
class="ant-input-number ant-input-number-sm ant-input-number-in-form-item ant-color-picker-steppers ant-color-picker-alpha-input"
>
<input
id="rc-editable-input-8"
spellcheck="false"
style="width: 80%; padding: 4px 10% 3px; box-shadow: inset 0 0 0 1px #ccc; font-size: 11px;"
value="0"
/>
<label
for="rc-editable-input-8"
style="display: block; text-align: center; font-size: 11px; color: rgb(34, 34, 34); padding-top: 3px; padding-bottom: 4px; text-transform: capitalize; cursor: ew-resize;"
<div
class="ant-input-number-handler-wrap"
>
b
</label>
</div>
</div>
<div
style="flex: 1; padding-left: 6px;"
>
<div
style="position: relative;"
>
<input
id="rc-editable-input-10"
spellcheck="false"
style="width: 80%; padding: 4px 10% 3px; box-shadow: inset 0 0 0 1px #ccc; font-size: 11px;"
value="15"
/>
<label
for="rc-editable-input-10"
style="display: block; text-align: center; font-size: 11px; color: rgb(34, 34, 34); padding-top: 3px; padding-bottom: 4px; text-transform: capitalize; cursor: ew-resize;"
<span
aria-disabled="false"
aria-label="Increase Value"
class="ant-input-number-handler ant-input-number-handler-up"
role="button"
unselectable="on"
>
<span
aria-label="up"
class="anticon anticon-up ant-input-number-handler-up-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="up"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
/>
</svg>
</span>
</span>
<span
aria-disabled="false"
aria-label="Decrease Value"
class="ant-input-number-handler ant-input-number-handler-down"
role="button"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-input-number-handler-down-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-input-number-input-wrap"
>
a
</label>
<input
aria-valuemax="100"
aria-valuemin="0"
aria-valuenow="15"
autocomplete="off"
class="ant-input-number-input"
role="spinbutton"
step="1"
value="15%"
/>
</div>
</div>
</div>
</div>
<div
class="flexbox-fix"
style="margin: 0px -10px; padding: 10px 0px 0px 10px; border-top: 1px solid #eee; display: flex; flex-wrap: wrap; position: relative;"
>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(208, 2, 27); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#D0021B"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(245, 166, 35); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#F5A623"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(248, 231, 28); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#F8E71C"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(139, 87, 42); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#8B572A"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(126, 211, 33); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#7ED321"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(65, 117, 5); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#417505"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(189, 16, 224); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#BD10E0"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(144, 19, 254); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#9013FE"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(74, 144, 226); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#4A90E2"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(80, 227, 194); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#50E3C2"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(184, 233, 134); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#B8E986"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(0, 0, 0); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#000000"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(74, 74, 74); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#4A4A4A"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(155, 155, 155); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#9B9B9B"
/>
</span>
</div>
<div
style="width: 16px; height: 16px; margin: 0px 10px 10px 0px;"
>
<span>
<div
style="background: rgb(255, 255, 255); height: 100%; width: 100%; cursor: pointer; position: relative; outline: none; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);"
tabindex="0"
title="#FFFFFF"
/>
</span>
</div>
</div>
</div>
</div>
</div>

View File

@ -113,11 +113,16 @@ exports[`renders components/watermark/demo/custom.tsx correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
style="padding:4px;background:#fff;border-radius:2px;border:1px solid #dedede;display:inline-block;cursor:pointer"
class="ant-color-picker-trigger"
>
<div
style="width:36px;height:14px;border-radius:2px;background:rgba(0, 0, 0, 0.15)"
/>
class="ant-color-picker-color-block"
>
<div
class="ant-color-picker-color-block-inner"
style="background:rgba(0, 0, 0, 0.15)"
/>
</div>
</div>
</div>
</div>

View File

@ -1,55 +1,28 @@
import { ColorPicker, Form, Input, InputNumber, Slider, Space, Typography, Watermark } from 'antd';
import type { Color } from 'antd/es/color-picker';
import React, { useMemo, useState } from 'react';
import { Watermark, Popover, Typography, Form, Input, Slider, Space, InputNumber } from 'antd';
import { SketchPicker } from 'react-color';
import type { RGBColor } from 'react-color';
const { Paragraph } = Typography;
interface ColorPickerProps {
value?: RGBColor;
onChange?: (value: RGBColor) => void;
interface WatermarkConfig {
content: string;
color: string | Color;
fontSize: number;
zIndex: number;
rotate: number;
gap: [number, number];
offset?: [number, number];
}
const ColorPicker: React.FC<ColorPickerProps> = ({ value, onChange }) => {
const switchStyle = {
padding: 4,
background: '#fff',
borderRadius: 2,
border: '1px solid #dedede',
display: 'inline-block',
cursor: 'pointer',
};
const colorStyle = {
width: 36,
height: 14,
borderRadius: 2,
background: `rgba(${value?.r}, ${value?.g}, ${value?.b}, ${value?.a})`,
};
return (
<Popover
trigger="click"
placement="bottomLeft"
overlayInnerStyle={{ padding: 0 }}
content={<SketchPicker color={value} onChange={(color) => onChange?.(color.rgb)} />}
>
<div style={switchStyle}>
<div style={colorStyle} />
</div>
</Popover>
);
};
const App: React.FC = () => {
const [form] = Form.useForm();
const [config, setConfig] = useState({
const [config, setConfig] = useState<WatermarkConfig>({
content: 'Ant Design',
color: { r: 0, g: 0, b: 0, a: 0.15 },
color: 'rgba(0, 0, 0, 0.15)',
fontSize: 16,
zIndex: 11,
rotate: -22,
gap: [100, 100] as [number, number],
gap: [100, 100],
offset: undefined,
});
const { content, color, fontSize, zIndex, rotate, gap, offset } = config;
@ -58,7 +31,7 @@ const App: React.FC = () => {
() => ({
content,
font: {
color: `rgba(${color.r},${color.g},${color.b},${color.a})`,
color: typeof color === 'string' ? color : color.toRgbString(),
fontSize,
},
zIndex,

View File

@ -195,7 +195,6 @@
"@types/puppeteer": "^7.0.4",
"@types/qs": "^6.9.7",
"@types/react": "^18.0.0",
"@types/react-color": "^3.0.1",
"@types/react-copy-to-clipboard": "^5.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-highlight-words": "^0.16.4",
@ -267,7 +266,6 @@
"rc-tween-one": "^3.0.3",
"rc-virtual-list": "^3.4.11",
"react": "^18.0.0",
"react-color": "^2.17.3",
"react-copy-to-clipboard": "^5.0.1",
"react-countup": "^6.4.0",
"react-dom": "^18.0.0",
@ -325,4 +323,4 @@
"*.{ts,tsx,js,jsx}": "rome format --write",
"*.{json,less,md}": "prettier --ignore-unknown --write"
}
}
}