diff --git a/.dumi/pages/index/components/Theme/ColorPicker.tsx b/.dumi/pages/index/components/Theme/ColorPicker.tsx index b969d2b160..c9c6655b85 100644 --- a/.dumi/pages/index/components/Theme/ColorPicker.tsx +++ b/.dumi/pages/index/components/Theme/ColorPicker.tsx @@ -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 = ({ color, onChange }) => { +const DebouncedColorPicker: FC = ({ value: color, onChange, children }) => { const [value, setValue] = useState(color); useEffect(() => { @@ -52,23 +51,36 @@ const DebouncedColorPanel: FC = ({ color, onChange }) => { setValue(color); }, [color]); - return ; + return ( + + {children} + + ); }; 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 ( { onChange?.(event.target.value); }} @@ -126,17 +138,9 @@ export default function ColorPicker({ value, onChange }: RadiusPickerProps) { if (picker) { colorNode = ( - onChange?.(c)} /> - } - trigger="click" - arrow={false} - > + {colorNode} - + ); } diff --git a/.dumi/pages/index/components/Theme/colorUtil.ts b/.dumi/pages/index/components/Theme/colorUtil.ts index 0df5ea543a..0c3ebbccc0 100644 --- a/.dumi/pages/index/components/Theme/colorUtil.ts +++ b/.dumi/pages/index/components/Theme/colorUtil.ts @@ -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 + diff --git a/.dumi/pages/index/components/Theme/index.tsx b/.dumi/pages/index/components/Theme/index.tsx index 119b7f11a3..1fdd88bafb 100644 --- a/.dumi/pages/index/components/Theme/index.tsx +++ b/.dumi/pages/index/components/Theme/index.tsx @@ -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() { ) : ( {/* >>>>>> Background Image <<<<<< */} - + } > diff --git a/.dumi/theme/common/Color/ColorPaletteTool.tsx b/.dumi/theme/common/Color/ColorPaletteTool.tsx index d1cee01dce..25d55032b3 100644 --- a/.dumi/theme/common/Color/ColorPaletteTool.tsx +++ b/.dumi/theme/common/Color/ColorPaletteTool.tsx @@ -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('#1890ff'); - const [primaryColorInstance, setPrimaryColorInstance] = useState(null); - const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => { - const value = (e as ChangeEvent).target - ? (e as ChangeEvent).target.value - : e; - setPrimaryColor(value as string); + const [primaryColorInstance, setPrimaryColorInstance] = useState(null); + const handleChangeColor = (color: Color, hex: string) => { + setPrimaryColor(hex); setPrimaryColorInstance(color); }; const colorValidation = useMemo(() => { 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 {text.trim()}; @@ -41,7 +35,7 @@ const ColorPaletteTool: React.FC = () => {
{ColorPatterns({ color: primaryColor })}
- + {primaryColor} {colorValidation} diff --git a/.dumi/theme/common/Color/ColorPaletteToolDark.tsx b/.dumi/theme/common/Color/ColorPaletteToolDark.tsx index b6e13e2d0b..cdeb725033 100644 --- a/.dumi/theme/common/Color/ColorPaletteToolDark.tsx +++ b/.dumi/theme/common/Color/ColorPaletteToolDark.tsx @@ -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('#141414'); const [primaryColorInstance, setPrimaryColorInstance] = useState(null); - const handleChangeColor = (e: string | ChangeEvent, color: { hex: string }) => { - const value = (e as ChangeEvent).target - ? (e as ChangeEvent).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).target - ? (e as ChangeEvent).target.value - : e; - setBackgroundColor(value as string); + const handleChangeBackgroundColor = (_, hex: string) => { + setBackgroundColor(hex); }; const colorValidation = useMemo(() => { 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 = () => { - + {primaryColor} @@ -78,7 +67,7 @@ const ColorPaletteTool: React.FC = () => { - + {backgroundColor} diff --git a/.dumi/theme/common/Color/ColorPicker.tsx b/.dumi/theme/common/Color/ColorPicker.tsx deleted file mode 100644 index 6870ca18c3..0000000000 --- a/.dumi/theme/common/Color/ColorPicker.tsx +++ /dev/null @@ -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 = (props) => { - const { - small, - position = 'bottom', - presetColors, - onChange = noop, - onChangeComplete = noop, - } = props; - - const [color, setColor] = useState(props.color); - const [displayColorPicker, setDisplayColorPicker] = useState(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 = { - 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 = ( -
-
-
- ); - - const picker: React.ReactNode = displayColorPicker ? ( -
-
-
- -
-
- ) : null; - - return position === 'top' ? ( -
- {picker} - {swatch} -
- ) : ( -
- {swatch} - {picker} -
- ); -}; - -export default ColorPicker; diff --git a/components/config-provider/demo/theme.tsx b/components/config-provider/demo/theme.tsx index 599240b6af..76a8fb6601 100644 --- a/components/config-provider/demo/theme.tsx +++ b/components/config-provider/demo/theme.tsx @@ -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 }} > - + diff --git a/components/watermark/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/watermark/__tests__/__snapshots__/demo-extend.test.ts.snap index 776c72adfd..50e78ec725 100644 --- a/components/watermark/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/watermark/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -119,14 +119,19 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1 class="ant-form-item-control-input-content" >
+ class="ant-color-picker-color-block" + > +
+