diff --git a/.dumi/pages/index/components/PreviewBanner/index.tsx b/.dumi/pages/index/components/PreviewBanner/index.tsx index 25ed675aa561..dd8835c03c8c 100644 --- a/.dumi/pages/index/components/PreviewBanner/index.tsx +++ b/.dumi/pages/index/components/PreviewBanner/index.tsx @@ -23,62 +23,64 @@ const locales = { }, }; -const useStyle = createStyles(({ token, css }) => { - const textShadow = `0 0 3px ${token.colorBgContainer}`; +const useStyle = () => { const { direction } = React.useContext(ConfigProvider.ConfigContext); const isRTL = direction === 'rtl'; - return { - holder: css` - height: 520px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - overflow: hidden; - perspective: 800px; - row-gap: ${token.marginXL}px; - `, - - typography: css` - text-align: center; - position: relative; - z-index: 1; - padding-inline: ${token.paddingXL}px; - text-shadow: ${new Array(5) - .fill(null) - .map(() => textShadow) - .join(', ')}; - - h1 { - font-family: AliPuHui, ${token.fontFamily} !important; - font-weight: 900 !important; - font-size: ${token.fontSizeHeading2 * 2}px !important; - line-height: ${token.lineHeightHeading2} !important; - } - - p { - font-size: ${token.fontSizeLG}px !important; - font-weight: normal !important; - margin-bottom: 0; - } - `, - - block: css` - position: absolute; - inset-inline-end: 0; - top: -38px; - transform: ${isRTL ? 'rotate3d(24, 83, -45, 57deg)' : 'rotate3d(24, -83, 45, 57deg)'}; - `, - - child: css` - position: relative; - z-index: 1; - `, - }; -}); - + return createStyles(({ token, css }) => { + const textShadow = `0 0 3px ${token.colorBgContainer}`; + + return { + holder: css` + height: 520px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; + perspective: 800px; + row-gap: ${token.marginXL}px; + `, + + typography: css` + text-align: center; + position: relative; + z-index: 1; + padding-inline: ${token.paddingXL}px; + text-shadow: ${new Array(5) + .fill(null) + .map(() => textShadow) + .join(', ')}; + + h1 { + font-family: AliPuHui, ${token.fontFamily} !important; + font-weight: 900 !important; + font-size: ${token.fontSizeHeading2 * 2}px !important; + line-height: ${token.lineHeightHeading2} !important; + } + + p { + font-size: ${token.fontSizeLG}px !important; + font-weight: normal !important; + margin-bottom: 0; + } + `, + + block: css` + position: absolute; + inset-inline-end: 0; + top: -38px; + transform: ${isRTL ? 'rotate3d(24, 83, -45, 57deg)' : 'rotate3d(24, -83, 45, 57deg)'}; + `, + + child: css` + position: relative; + z-index: 1; + `, + }; + })(); +}; export interface PreviewBannerProps { children?: React.ReactNode; } diff --git a/.dumi/pages/index/components/Theme/ThemePicker.tsx b/.dumi/pages/index/components/Theme/ThemePicker.tsx index e99b1cd13872..790a553fc498 100644 --- a/.dumi/pages/index/components/Theme/ThemePicker.tsx +++ b/.dumi/pages/index/components/Theme/ThemePicker.tsx @@ -43,6 +43,7 @@ const useStyle = createStyles(({ token, css }) => ({ width: 0; height: 0; opacity: 0; + position: absolute; } img { diff --git a/.dumi/theme/builtins/Previewer/CodePreviewer.tsx b/.dumi/theme/builtins/Previewer/CodePreviewer.tsx index 66033bec7dde..60024d8afcef 100644 --- a/.dumi/theme/builtins/Previewer/CodePreviewer.tsx +++ b/.dumi/theme/builtins/Previewer/CodePreviewer.tsx @@ -1,17 +1,21 @@ +/* eslint-disable jsx-a11y/no-noninteractive-tabindex */ +import React, { useContext, useEffect, useRef, useState } from 'react'; import { CheckOutlined, LinkOutlined, SnippetsOutlined, ThunderboltOutlined, + UpOutlined, } from '@ant-design/icons'; import type { Project } from '@stackblitz/sdk'; import stackblitzSdk from '@stackblitz/sdk'; +import { Alert, Badge, Space, Tooltip } from 'antd'; +import { createStyles, css } from 'antd-style'; import classNames from 'classnames'; import { FormattedMessage, useSiteData } from 'dumi'; import LZString from 'lz-string'; -import React, { useContext, useEffect, useRef, useState } from 'react'; import CopyToClipboard from 'react-copy-to-clipboard'; -import { Alert, Badge, Space, Tooltip } from 'antd'; + import type { AntdPreviewerProps } from '.'; import useLocation from '../../../hooks/useLocation'; import BrowserFrame from '../../common/BrowserFrame'; @@ -63,6 +67,31 @@ function useShowRiddleButton() { return showRiddleButton; } +const useStyle = createStyles(({ token }) => { + const { borderRadius } = token; + return { + codeHideBtn: css` + width: 100%; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 0 0 ${borderRadius}px ${borderRadius}px; + border-top: 1px solid ${token.colorSplit}; + color: ${token.colorTextSecondary}; + transition: all 0.2s ease-in-out; + background-color: ${token.colorBgElevated}; + cursor: pointer; + &:hover { + color: ${token.colorPrimary}; + } + span { + margin-right: ${token.marginXXS}px; + } + `, + }; +}); + const CodePreviewer: React.FC = (props) => { const { asset, @@ -86,6 +115,8 @@ const CodePreviewer: React.FC = (props) => { const { pkg } = useSiteData(); const location = useLocation(); + const { styles } = useStyle(); + const entryCode = asset.dependencies['index.tsx'].value; const showRiddleButton = useShowRiddleButton(); @@ -509,8 +540,12 @@ createRoot(document.getElementById('container')).render(); sourceCode={entryCode} jsxCode={jsx} styleCode={style} - onCodeTypeChange={(type) => setCodeType(type)} + onCodeTypeChange={setCodeType} /> +
setCodeExpand(false)}> + + +
)} diff --git a/.dumi/theme/common/CodePreview.tsx b/.dumi/theme/common/CodePreview.tsx index b69303dae1fe..827630fcc014 100644 --- a/.dumi/theme/common/CodePreview.tsx +++ b/.dumi/theme/common/CodePreview.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useMemo } from 'react'; -import Prism from 'prismjs'; +import { Tabs } from 'antd'; import toReactElement from 'jsonml-to-react-element'; import JsonML from 'jsonml.js/lib/utils'; -import { Tabs } from 'antd'; +import Prism from 'prismjs'; const LANGS = { tsx: 'TypeScript', @@ -17,22 +17,16 @@ interface CodePreviewProps { onCodeTypeChange?: (activeKey: string) => void; } -function toReactComponent(jsonML: any) { +function toReactComponent(jsonML: any[]) { return toReactElement(jsonML, [ [ (node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'pre', - (node: any, index: any) => { - // ref: https://github.com/benjycui/bisheng/blob/master/packages/bisheng/src/bisheng-plugin-highlight/lib/browser.js#L7 + (node: any, index: number) => { const attr = JsonML.getAttributes(node); - return React.createElement( - 'pre', - { - key: index, - className: `language-${attr.lang}`, - }, - React.createElement('code', { - dangerouslySetInnerHTML: { __html: attr.highlighted }, - }), + return ( +
+            
+          
); }, ], diff --git a/.dumi/theme/common/styles/Demo.tsx b/.dumi/theme/common/styles/Demo.tsx index c7b9b6fc5c75..9b0d8c1faa96 100644 --- a/.dumi/theme/common/styles/Demo.tsx +++ b/.dumi/theme/common/styles/Demo.tsx @@ -1,5 +1,5 @@ -import { css, Global } from '@emotion/react'; import React from 'react'; +import { css, Global } from '@emotion/react'; import { useTheme } from 'antd-style'; const GlobalDemoStyles: React.FC = () => { diff --git a/.dumi/theme/locales/en-US.json b/.dumi/theme/locales/en-US.json index 7a9f792abbd9..6ca8a49d35ef 100644 --- a/.dumi/theme/locales/en-US.json +++ b/.dumi/theme/locales/en-US.json @@ -31,6 +31,7 @@ "app.demo.copied": "Copied!", "app.demo.code.show": "Show code", "app.demo.code.hide": "Hide code", + "app.demo.code.hide.simplify": "Hide", "app.demo.codepen": "Open in CodePen", "app.demo.codesandbox": "Open in CodeSandbox", "app.demo.stackblitz": "Open in Stackblitz", diff --git a/.dumi/theme/locales/zh-CN.json b/.dumi/theme/locales/zh-CN.json index 3618d9dabbd6..2a37d63e3ea7 100644 --- a/.dumi/theme/locales/zh-CN.json +++ b/.dumi/theme/locales/zh-CN.json @@ -31,6 +31,7 @@ "app.demo.copied": "复制成功", "app.demo.code.show": "显示代码", "app.demo.code.hide": "收起代码", + "app.demo.code.hide.simplify": "收起", "app.demo.codepen": "在 CodePen 中打开", "app.demo.codesandbox": "在 CodeSandbox 中打开", "app.demo.stackblitz": "在 Stackblitz 中打开", diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 12e8f7c4c226..c57025a57aa3 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -16,6 +16,24 @@ tag: vVERSION --- +## 5.8.5 + +`2023-08-28` + +- 🛠 Refactor Badge style logic and take Ribbon style out to reduce SSR inline style size. [#44451](https://github.com/ant-design/ant-design/pull/44451) +- 🐞 Fix the issue of abnormal icon styling when using `@ant-design/icons`` within App. [#41208](https://github.com/ant-design/ant-design/pull/41208) [@Wxh16144](https://github.com/Wxh16144) +- 🐞 Fix the issue of vertical dragging malfunction in Carousel. [#44460](https://github.com/ant-design/ant-design/pull/44460) [@RedJue](https://github.com/RedJue) +- 🐞 Fix Tour panel use wrong design token. [#44428](https://github.com/ant-design/ant-design/pull/44428) +- 🐞 Fix Form `wrapperCol` with responsive `xs` config not working. [#44388](https://github.com/ant-design/ant-design/pull/44388) +- 🐞 Fix ColorPicker duplicate `key` issue. [#44370](https://github.com/ant-design/ant-design/pull/44370) [@xr0master](https://github.com/xr0master) +- 🐞 Fix Radio that not work in Tree title. [#44380](https://github.com/ant-design/ant-design/pull/44380) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix Table that would crash when `filterDropdown` does not support `ref`. [#44357](https://github.com/ant-design/ant-design/pull/44357) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix Form `inline` layout show extra bottom margin when validation failed. [#44360](https://github.com/ant-design/ant-design/pull/44360) +- 🐞 Fix DatePicker `showTime` working error when `format` is Array. [#44306](https://github.com/ant-design/ant-design/pull/44306) [@Zian502](https://github.com/Zian502) +- 🐞 Fix Watermark can not be fully shown when `content` is too long. [#44321](https://github.com/ant-design/ant-design/pull/44321) +- TypeScript + - 🤖 Fix the type error with align property in Dropdown component. [#44423](https://github.com/ant-design/ant-design/pull/44423) [@LeTuongKhanh](https://github.com/LeTuongKhanh) + ## 5.8.4 `2023-08-18` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 9eab1234e88a..d680fda23212 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -16,6 +16,24 @@ tag: vVERSION --- +## 5.8.5 + +`2023-08-28` + +- 🛠 重构 Badge 样式逻辑将 Ribbon 样式抽离以降低 SSR 内联样式尺寸。[#44451](https://github.com/ant-design/ant-design/pull/44451) +- 🐞 修复 App 组件下使用 `@ant-design/icons` 的图标样式异常的问题。[#41208](https://github.com/ant-design/ant-design/pull/41208) [@Wxh16144](https://github.com/Wxh16144) +- 🐞 修复 Carousel 组件垂直方向拖动失效的问题。[#44460](https://github.com/ant-design/ant-design/pull/44460) [@RedJue](https://github.com/RedJue) +- 🐞 修复 Tour 面板使用的 design token 错误的问题。[#44428](https://github.com/ant-design/ant-design/pull/44428) +- 🐞 修复 Form `wrapperCol` 配置响应式 `xs` 属性无效的问题。[#44388](https://github.com/ant-design/ant-design/pull/44388) +- 🐞 修复 ColorPicker 中重复 `key` 的问题。[#44370](https://github.com/ant-design/ant-design/pull/44370) [@xr0master](https://github.com/xr0master) +- 🐞 修复 Radio 组件组合 Tree 组件后失效的问题。[#44380](https://github.com/ant-design/ant-design/pull/44380) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Table 组件 `filterDropdown` 不支持 `ref` 时报错的问题。[#44357](https://github.com/ant-design/ant-design/pull/44357) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Form `inline` 布局在校验失败时出现额外空行的问题。[#44360](https://github.com/ant-design/ant-design/pull/44360) +- 🐞 修复 DatePicker 中 `showTime` 为 true 且 `format` 为数组时,组件报错。[#44306](https://github.com/ant-design/ant-design/pull/44306) [@Zian502](https://github.com/Zian502) +- 🐞 修复 Watermark 中 `content` 内容过长时无法完整显示的问题。[#44321](https://github.com/ant-design/ant-design/pull/44321) +- TypeScript + - 🤖 修复 Dropdown 组件中 `align` 属性的类型错误。[#44423](https://github.com/ant-design/ant-design/pull/44423) [@LeTuongKhanh](https://github.com/LeTuongKhanh) + ## 5.8.4 `2023-08-18` diff --git a/components/app/__tests__/index.test.tsx b/components/app/__tests__/index.test.tsx index 7cfccbdc93e5..c67fed6ce686 100644 --- a/components/app/__tests__/index.test.tsx +++ b/components/app/__tests__/index.test.tsx @@ -1,3 +1,4 @@ +import { SmileOutlined } from '@ant-design/icons'; import React, { useEffect } from 'react'; import type { NotificationConfig } from 'antd/es/notification/interface'; import App from '..'; @@ -181,4 +182,30 @@ describe('App', () => { ); expect(container.querySelector('.ant-app')).toHaveStyle('color: blue;'); }); + + // https://github.com/ant-design/ant-design/issues/41197#issuecomment-1465803061 + describe('restIcon style', () => { + beforeEach(() => { + Array.from(document.querySelectorAll('style')).forEach((style) => { + style.parentNode?.removeChild(style); + }); + }); + + it('should work by default', () => { + const { container } = render( + + + , + ); + + expect(container.querySelector('.anticon')).toBeTruthy(); + const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]')); + expect( + dynamicStyles.some((style) => { + const { innerHTML } = style; + return innerHTML.startsWith('.anticon'); + }), + ).toBeTruthy(); + }); + }); }); diff --git a/components/badge/Ribbon.tsx b/components/badge/Ribbon.tsx index 6fdf1aff02af..d8585dc61728 100644 --- a/components/badge/Ribbon.tsx +++ b/components/badge/Ribbon.tsx @@ -1,10 +1,11 @@ -import classNames from 'classnames'; import * as React from 'react'; +import classNames from 'classnames'; + import type { PresetColorType } from '../_util/colors'; import { isPresetColor } from '../_util/colors'; import type { LiteralUnion } from '../_util/type'; import { ConfigContext } from '../config-provider'; -import useStyle from './style'; +import useStyle from './style/ribbon'; type RibbonPlacement = 'start' | 'end'; diff --git a/components/badge/index.en-US.md b/components/badge/index.en-US.md index 13e5e401bbc2..87da9a7c3e23 100644 --- a/components/badge/index.en-US.md +++ b/components/badge/index.en-US.md @@ -49,13 +49,13 @@ Common props ref:[Common props](/docs/react/common-props) | offset | Set offset of the badge dot | \[number, number] | - | | | overflowCount | Max count to show | number | 99 | | | showZero | Whether to show badge when `count` is zero | boolean | false | | -| size | If `count` is set, `size` sets the size of badge | `default` \| `small` | - | 4.6.0 | +| size | If `count` is set, `size` sets the size of badge | `default` \| `small` | - | - | | status | Set Badge as a status dot | `success` \| `processing` \| `default` \| `error` \| `warning` | - | | | styles | Semantic DOM style | Record | - | 5.7.0 | | text | If `status` is set, `text` sets the display text of the status `dot` | ReactNode | - | | | title | Text to show when hovering over the badge | string | - | | -### Badge.Ribbon (4.5.0+) +### Badge.Ribbon | Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | diff --git a/components/badge/index.zh-CN.md b/components/badge/index.zh-CN.md index bd1866bf75f3..54b5b4b44416 100644 --- a/components/badge/index.zh-CN.md +++ b/components/badge/index.zh-CN.md @@ -50,13 +50,13 @@ group: 数据展示 | offset | 设置状态点的位置偏移 | \[number, number] | - | | | overflowCount | 展示封顶的数字值 | number | 99 | | | showZero | 当数值为 0 时,是否展示 Badge | boolean | false | | -| size | 在设置了 `count` 的前提下有效,设置小圆点的大小 | `default` \| `small` | - | 4.6.0 | +| size | 在设置了 `count` 的前提下有效,设置小圆点的大小 | `default` \| `small` | - | - | | status | 设置 Badge 为状态点 | `success` \| `processing` \| `default` \| `error` \| `warning` | - | | | styles | 语义化结构 style | Record | - | 5.7.0 | | text | 在设置了 `status` 的前提下有效,设置状态点的文本 | ReactNode | - | | | title | 设置鼠标放在状态点上时显示的文字 | string | - | | -### Badge.Ribbon (4.5.0+) +### Badge.Ribbon | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | diff --git a/components/badge/style/index.ts b/components/badge/style/index.ts index 9486be69895d..690628844d0f 100644 --- a/components/badge/style/index.ts +++ b/components/badge/style/index.ts @@ -1,8 +1,11 @@ import type { CSSObject } from '@ant-design/cssinjs'; import { Keyframes } from '@ant-design/cssinjs'; + import { resetComponent } from '../../style'; +import type { GlobalToken } from '../../theme'; import type { FullToken, GenerateStyle } from '../../theme/internal'; import { genComponentStyleHook, genPresetColor, mergeToken } from '../../theme/internal'; +import type { GenStyleFn } from '../../theme/util/genComponentStyleHook'; /** Component only token. Which will handle additional calculation of alias token */ export interface ComponentToken { @@ -49,7 +52,7 @@ export interface ComponentToken { statusSize: number; } -interface BadgeToken extends FullToken<'Badge'> { +export interface BadgeToken extends FullToken<'Badge'> { badgeFontHeight: number; badgeTextColor: string; badgeColor: string; @@ -98,7 +101,6 @@ const genSharedBadgeStyle: GenerateStyle = (token: BadgeToken): CSSO componentCls, iconCls, antCls, - badgeFontHeight, badgeShadowSize, motionDurationSlow, textFontSize, @@ -109,11 +111,8 @@ const genSharedBadgeStyle: GenerateStyle = (token: BadgeToken): CSSO indicatorHeight, indicatorHeightSM, marginXS, - badgeRibbonOffset, } = token; const numberPrefixCls = `${antCls}-scroll-number`; - const ribbonPrefixCls = `${antCls}-ribbon`; - const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`; const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({ [`&${componentCls} ${componentCls}-color-${colorKey}`]: { @@ -124,13 +123,6 @@ const genSharedBadgeStyle: GenerateStyle = (token: BadgeToken): CSSO }, })); - const statusRibbonPreset = genPresetColor(token, (colorKey, { darkColor }) => ({ - [`&${ribbonPrefixCls}-color-${colorKey}`]: { - background: darkColor, - color: darkColor, - }, - })); - return { [componentCls]: { ...resetComponent(token), @@ -328,98 +320,58 @@ const genSharedBadgeStyle: GenerateStyle = (token: BadgeToken): CSSO }, }, }, - [`${ribbonWrapperPrefixCls}`]: { position: 'relative' }, - [`${ribbonPrefixCls}`]: { - ...resetComponent(token), - position: 'absolute', - top: marginXS, - padding: `0 ${token.paddingXS}px`, - color: token.colorPrimary, - lineHeight: `${badgeFontHeight}px`, - whiteSpace: 'nowrap', - backgroundColor: token.colorPrimary, - borderRadius: token.borderRadiusSM, - [`${ribbonPrefixCls}-text`]: { color: token.colorTextLightSolid }, - [`${ribbonPrefixCls}-corner`]: { - position: 'absolute', - top: '100%', - width: badgeRibbonOffset, - height: badgeRibbonOffset, - color: 'currentcolor', - border: `${badgeRibbonOffset / 2}px solid`, - transform: token.badgeRibbonCornerTransform, - transformOrigin: 'top', - filter: token.badgeRibbonCornerFilter, - }, - ...statusRibbonPreset, - [`&${ribbonPrefixCls}-placement-end`]: { - insetInlineEnd: -badgeRibbonOffset, - borderEndEndRadius: 0, - [`${ribbonPrefixCls}-corner`]: { - insetInlineEnd: 0, - borderInlineEndColor: 'transparent', - borderBlockEndColor: 'transparent', - }, - }, - [`&${ribbonPrefixCls}-placement-start`]: { - insetInlineStart: -badgeRibbonOffset, - borderEndStartRadius: 0, - [`${ribbonPrefixCls}-corner`]: { - insetInlineStart: 0, - borderBlockEndColor: 'transparent', - borderInlineStartColor: 'transparent', - }, - }, - - // ====================== RTL ======================= - '&-rtl': { - direction: 'rtl', - }, - }, }; }; // ============================== Export ============================== +export const prepareToken: (token: Parameters>[0]) => BadgeToken = (token) => { + const { fontSize, lineHeight, lineWidth, marginXS, colorBorderBg } = token; + + const badgeFontHeight = Math.round(fontSize * lineHeight); + const badgeShadowSize = lineWidth; + const badgeTextColor = token.colorBgContainer; + const badgeColor = token.colorError; + const badgeColorHover = token.colorErrorHover; + + const badgeToken = mergeToken(token, { + badgeFontHeight, + badgeShadowSize, + badgeTextColor, + badgeColor, + badgeColorHover, + badgeShadowColor: colorBorderBg, + badgeProcessingDuration: '1.2s', + badgeRibbonOffset: marginXS, + + // Follow token just by Design. Not related with token + badgeRibbonCornerTransform: 'scaleY(0.75)', + badgeRibbonCornerFilter: `brightness(75%)`, + }); + + return badgeToken; +}; + +export const prepareComponentToken = (token: GlobalToken) => { + const { fontSize, lineHeight, fontSizeSM, lineWidth } = token; + + return { + indicatorZIndex: 'auto', + indicatorHeight: Math.round(fontSize * lineHeight) - 2 * lineWidth, + indicatorHeightSM: fontSize, + dotSize: fontSizeSM / 2, + textFontSize: fontSizeSM, + textFontSizeSM: fontSizeSM, + textFontWeight: 'normal', + statusSize: fontSizeSM / 2, + }; +}; + export default genComponentStyleHook( 'Badge', (token) => { - const { fontSize, lineHeight, lineWidth, marginXS, colorBorderBg } = token; - - const badgeFontHeight = Math.round(fontSize * lineHeight); - const badgeShadowSize = lineWidth; - const badgeTextColor = token.colorBgContainer; - const badgeColor = token.colorError; - const badgeColorHover = token.colorErrorHover; - - const badgeToken = mergeToken(token, { - badgeFontHeight, - badgeShadowSize, - badgeTextColor, - badgeColor, - badgeColorHover, - badgeShadowColor: colorBorderBg, - badgeProcessingDuration: '1.2s', - badgeRibbonOffset: marginXS, - - // Follow token just by Design. Not related with token - badgeRibbonCornerTransform: 'scaleY(0.75)', - badgeRibbonCornerFilter: `brightness(75%)`, - }); + const badgeToken = prepareToken(token); return [genSharedBadgeStyle(badgeToken)]; }, - (token) => { - const { fontSize, lineHeight, fontSizeSM, lineWidth } = token; - - return { - indicatorZIndex: 'auto', - indicatorHeight: Math.round(fontSize * lineHeight) - 2 * lineWidth, - indicatorHeightSM: fontSize, - dotSize: fontSizeSM / 2, - textFontSize: fontSizeSM, - textFontSizeSM: fontSizeSM, - textFontWeight: 'normal', - statusSize: fontSizeSM / 2, - }; - }, + prepareComponentToken, ); diff --git a/components/badge/style/ribbon.ts b/components/badge/style/ribbon.ts new file mode 100644 index 000000000000..d8a2a27f4da6 --- /dev/null +++ b/components/badge/style/ribbon.ts @@ -0,0 +1,82 @@ +import type { CSSObject } from '@ant-design/cssinjs'; + +import { prepareComponentToken, prepareToken, type BadgeToken } from '.'; +import { resetComponent } from '../../style'; +import type { GenerateStyle } from '../../theme/internal'; +import { genComponentStyleHook, genPresetColor } from '../../theme/internal'; + +// ============================== Ribbon ============================== +const genRibbonStyle: GenerateStyle = (token: BadgeToken): CSSObject => { + const { antCls, badgeFontHeight, marginXS, badgeRibbonOffset } = token; + const ribbonPrefixCls = `${antCls}-ribbon`; + const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`; + + const statusRibbonPreset = genPresetColor(token, (colorKey, { darkColor }) => ({ + [`&${ribbonPrefixCls}-color-${colorKey}`]: { + background: darkColor, + color: darkColor, + }, + })); + + return { + [`${ribbonWrapperPrefixCls}`]: { position: 'relative' }, + [`${ribbonPrefixCls}`]: { + ...resetComponent(token), + position: 'absolute', + top: marginXS, + padding: `0 ${token.paddingXS}px`, + color: token.colorPrimary, + lineHeight: `${badgeFontHeight}px`, + whiteSpace: 'nowrap', + backgroundColor: token.colorPrimary, + borderRadius: token.borderRadiusSM, + [`${ribbonPrefixCls}-text`]: { color: token.colorTextLightSolid }, + [`${ribbonPrefixCls}-corner`]: { + position: 'absolute', + top: '100%', + width: badgeRibbonOffset, + height: badgeRibbonOffset, + color: 'currentcolor', + border: `${badgeRibbonOffset / 2}px solid`, + transform: token.badgeRibbonCornerTransform, + transformOrigin: 'top', + filter: token.badgeRibbonCornerFilter, + }, + ...statusRibbonPreset, + [`&${ribbonPrefixCls}-placement-end`]: { + insetInlineEnd: -badgeRibbonOffset, + borderEndEndRadius: 0, + [`${ribbonPrefixCls}-corner`]: { + insetInlineEnd: 0, + borderInlineEndColor: 'transparent', + borderBlockEndColor: 'transparent', + }, + }, + [`&${ribbonPrefixCls}-placement-start`]: { + insetInlineStart: -badgeRibbonOffset, + borderEndStartRadius: 0, + [`${ribbonPrefixCls}-corner`]: { + insetInlineStart: 0, + borderBlockEndColor: 'transparent', + borderInlineStartColor: 'transparent', + }, + }, + + // ====================== RTL ======================= + '&-rtl': { + direction: 'rtl', + }, + }, + }; +}; + +// ============================== Export ============================== +export default genComponentStyleHook( + ['Badge', 'Ribbon'], + (token) => { + const badgeToken = prepareToken(token); + + return [genRibbonStyle(badgeToken)]; + }, + prepareComponentToken, +); diff --git a/components/button/button.tsx b/components/button/button.tsx index 64bdc20e413d..47c8b2bf50c4 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -1,7 +1,4 @@ /* eslint-disable react/button-has-type */ -import classNames from 'classnames'; -import omit from 'rc-util/lib/omit'; -import { composeRef } from 'rc-util/lib/ref'; import React, { Children, createRef, @@ -11,19 +8,24 @@ import React, { useMemo, useState, } from 'react'; +import classNames from 'classnames'; +import omit from 'rc-util/lib/omit'; +import { composeRef } from 'rc-util/lib/ref'; + import warning from '../_util/warning'; import Wave from '../_util/wave'; import { ConfigContext } from '../config-provider'; import DisabledContext from '../config-provider/DisabledContext'; -import type { SizeType } from '../config-provider/SizeContext'; import useSize from '../config-provider/hooks/useSize'; +import type { SizeType } from '../config-provider/SizeContext'; import { useCompactItemContext } from '../space/Compact'; -import IconWrapper from './IconWrapper'; -import LoadingIcon from './LoadingIcon'; import Group, { GroupSizeContext } from './button-group'; import type { ButtonHTMLType, ButtonShape, ButtonType } from './buttonHelpers'; import { isTwoCNChar, isUnBorderedButtonType, spaceChildren } from './buttonHelpers'; +import IconWrapper from './IconWrapper'; +import LoadingIcon from './LoadingIcon'; import useStyle from './style'; +import CompactStyle from './style/compactCmp'; export type LegacyButtonType = ButtonType | 'danger'; @@ -285,6 +287,9 @@ const InternalButton: React.ForwardRefRenderFunction< > {iconNode} {kids} + + {/* Styles: compact */} + {compactItemClassnames && } ); diff --git a/components/button/style/compactCmp.ts b/components/button/style/compactCmp.ts new file mode 100644 index 000000000000..77ed41f2ca7c --- /dev/null +++ b/components/button/style/compactCmp.ts @@ -0,0 +1,20 @@ +// Style as inline component +import { prepareComponentToken, prepareToken } from '.'; +import { genCompactItemStyle } from '../../style/compact-item'; +import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical'; +import { genSubStyleComponent } from '../../theme/internal'; + +// ============================== Export ============================== +export default genSubStyleComponent( + ['Button', 'compact'], + (token) => { + const buttonToken = prepareToken(token); + + return [ + // Space Compact + genCompactItemStyle(buttonToken), + genCompactItemVerticalStyle(buttonToken), + ]; + }, + prepareComponentToken, +); diff --git a/components/button/style/index.ts b/components/button/style/index.ts index 1ad770149b9a..674fb950e29a 100644 --- a/components/button/style/index.ts +++ b/components/button/style/index.ts @@ -1,10 +1,11 @@ -import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs'; import type { CSSProperties } from 'react'; +import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs'; + import { genFocusStyle } from '../../style'; -import { genCompactItemStyle } from '../../style/compact-item'; -import { genCompactItemVerticalStyle } from '../../style/compact-item-vertical'; +import type { GlobalToken } from '../../theme'; import type { FullToken, GenerateStyle } from '../../theme/internal'; import { genComponentStyleHook, mergeToken } from '../../theme/internal'; +import type { GenStyleFn } from '../../theme/util/genComponentStyleHook'; import genGroupStyle from './group'; /** Component only token. Which will handle additional calculation of alias token */ @@ -657,15 +658,52 @@ const genBlockButtonStyle: GenerateStyle = (token) => { }; // ============================== Export ============================== +export const prepareToken: (token: Parameters>[0]) => ButtonToken = ( + token, +) => { + const { paddingInline, onlyIconSize } = token; + + const buttonToken = mergeToken(token, { + buttonPaddingHorizontal: paddingInline, + buttonIconOnlyFontSize: onlyIconSize, + }); + + return buttonToken; +}; + +export const prepareComponentToken = (token: GlobalToken) => ({ + fontWeight: 400, + defaultShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`, + primaryShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`, + dangerShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`, + primaryColor: token.colorTextLightSolid, + dangerColor: token.colorTextLightSolid, + borderColorDisabled: token.colorBorder, + defaultGhostColor: token.colorBgContainer, + ghostBg: 'transparent', + defaultGhostBorderColor: token.colorBgContainer, + paddingInline: token.paddingContentHorizontal - token.lineWidth, + paddingInlineLG: token.paddingContentHorizontal - token.lineWidth, + paddingInlineSM: 8 - token.lineWidth, + onlyIconSize: token.fontSizeLG, + onlyIconSizeSM: token.fontSizeLG - 2, + onlyIconSizeLG: token.fontSizeLG + 2, + groupBorderColor: token.colorPrimaryHover, + linkHoverBg: 'transparent', + textHoverBg: token.colorBgTextHover, + defaultColor: token.colorText, + defaultBg: token.colorBgContainer, + defaultBorderColor: token.colorBorder, + defaultBorderColorDisabled: token.colorBorder, + contentFontSize: token.fontSize, + contentFontSizeSM: token.fontSize, + contentFontSizeLG: token.fontSizeLG, +}); + export default genComponentStyleHook( 'Button', (token) => { - const { paddingInline, onlyIconSize } = token; - - const buttonToken = mergeToken(token, { - buttonPaddingHorizontal: paddingInline, - buttonIconOnlyFontSize: onlyIconSize, - }); + const buttonToken = prepareToken(token); return [ // Shared @@ -684,38 +722,7 @@ export default genComponentStyleHook( // Button Group genGroupStyle(buttonToken), - - // Space Compact - genCompactItemStyle(token), - genCompactItemVerticalStyle(token), ]; }, - (token) => ({ - fontWeight: 400, - defaultShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`, - primaryShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`, - dangerShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`, - primaryColor: token.colorTextLightSolid, - dangerColor: token.colorTextLightSolid, - borderColorDisabled: token.colorBorder, - defaultGhostColor: token.colorBgContainer, - ghostBg: 'transparent', - defaultGhostBorderColor: token.colorBgContainer, - paddingInline: token.paddingContentHorizontal - token.lineWidth, - paddingInlineLG: token.paddingContentHorizontal - token.lineWidth, - paddingInlineSM: 8 - token.lineWidth, - onlyIconSize: token.fontSizeLG, - onlyIconSizeSM: token.fontSizeLG - 2, - onlyIconSizeLG: token.fontSizeLG + 2, - groupBorderColor: token.colorPrimaryHover, - linkHoverBg: 'transparent', - textHoverBg: token.colorBgTextHover, - defaultColor: token.colorText, - defaultBg: token.colorBgContainer, - defaultBorderColor: token.colorBorder, - defaultBorderColorDisabled: token.colorBorder, - contentFontSize: token.fontSize, - contentFontSizeSM: token.fontSize, - contentFontSizeLG: token.fontSizeLG, - }), + prepareComponentToken, ); diff --git a/components/carousel/index.tsx b/components/carousel/index.tsx index 451a95bf8649..7b5ddb0c470a 100644 --- a/components/carousel/index.tsx +++ b/components/carousel/index.tsx @@ -1,9 +1,10 @@ 'use client'; +import * as React from 'react'; import type { Settings } from '@ant-design/react-slick'; import SlickCarousel from '@ant-design/react-slick'; import classNames from 'classnames'; -import * as React from 'react'; + import { ConfigContext } from '../config-provider'; import useStyle from './style'; @@ -116,6 +117,7 @@ const Carousel = React.forwardRef((props, ref) => { dotsClass={dsClass} arrows={arrows} draggable={draggable} + verticalSwiping={vertical} waitForAnimate={waitForAnimate} /> , diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 67e1a3f2a178..d5a966a0b3aa 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -1,5 +1,6 @@ 'use client'; +import * as React from 'react'; import LeftOutlined from '@ant-design/icons/LeftOutlined'; import LoadingOutlined from '@ant-design/icons/LoadingOutlined'; import RightOutlined from '@ant-design/icons/RightOutlined'; @@ -15,18 +16,18 @@ import type { import RcCascader from 'rc-cascader'; import type { Placement } from 'rc-select/lib/BaseSelect'; import omit from 'rc-util/lib/omit'; -import * as React from 'react'; -import genPurePanel from '../_util/PurePanel'; + import type { SelectCommonPlacement } from '../_util/motion'; import { getTransitionName } from '../_util/motion'; +import genPurePanel from '../_util/PurePanel'; import type { InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils'; import warning from '../_util/warning'; import { ConfigContext } from '../config-provider'; -import DisabledContext from '../config-provider/DisabledContext'; -import type { SizeType } from '../config-provider/SizeContext'; import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty'; +import DisabledContext from '../config-provider/DisabledContext'; import useSize from '../config-provider/hooks/useSize'; +import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext } from '../form/context'; import useSelectStyle from '../select/style'; import useBuiltinPlacements from '../select/useBuiltinPlacements'; @@ -40,7 +41,7 @@ import useStyle from './style'; // - Hover opacity style // - Search filter match case -export { BaseOptionType, DefaultOptionType }; +export type { BaseOptionType, DefaultOptionType }; export type FieldNamesType = FieldNames; diff --git a/components/color-picker/ColorPicker.tsx b/components/color-picker/ColorPicker.tsx index abdc869311fd..7b9eab1e51c9 100644 --- a/components/color-picker/ColorPicker.tsx +++ b/components/color-picker/ColorPicker.tsx @@ -1,6 +1,5 @@ import type { CSSProperties, FC } from 'react'; import React, { useContext, useMemo, useRef, useState } from 'react'; - import type { HsbaColorType, ColorPickerProps as RcColorPickerProps, @@ -11,16 +10,16 @@ import useMergedState from 'rc-util/lib/hooks/useMergedState'; import genPurePanel from '../_util/PurePanel'; import { getStatusClassNames } from '../_util/statusUtils'; import warning from '../_util/warning'; -import type { SizeType } from '../config-provider/SizeContext'; import type { ConfigConsumerProps } from '../config-provider/context'; import { ConfigContext } from '../config-provider/context'; import useSize from '../config-provider/hooks/useSize'; +import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext, NoFormStyle } from '../form/context'; import type { PopoverProps } from '../popover'; import Popover from '../popover'; import theme from '../theme'; -import ColorPickerPanel from './ColorPickerPanel'; import type { Color } from './color'; +import ColorPickerPanel from './ColorPickerPanel'; import ColorTrigger from './components/ColorTrigger'; import useColorState from './hooks/useColorState'; import type { @@ -229,7 +228,7 @@ const ColorPicker: CompoundedComponent = (props) => { style={styles?.popup} overlayInnerStyle={styles?.popupOverlayInner} onOpenChange={(visible) => { - if (popupAllowCloseRef.current) { + if (popupAllowCloseRef.current && !disabled) { setPopupOpen(visible); } }} diff --git a/components/color-picker/__tests__/index.test.tsx b/components/color-picker/__tests__/index.test.tsx index a005aefb84a2..4c6763a0d21e 100644 --- a/components/color-picker/__tests__/index.test.tsx +++ b/components/color-picker/__tests__/index.test.tsx @@ -1,16 +1,18 @@ +import React, { useMemo, useState } from 'react'; import { createEvent, fireEvent, render } from '@testing-library/react'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; -import React, { useMemo, useState } from 'react'; + +import { resetWarned } from '../../_util/warning'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { waitFakeTimer } from '../../../tests/utils'; -import { resetWarned } from '../../_util/warning'; +import Button from '../../button'; import ConfigProvider from '../../config-provider'; import Form from '../../form'; import theme from '../../theme'; +import type { Color } from '../color'; import type { ColorPickerProps } from '../ColorPicker'; import ColorPicker from '../ColorPicker'; -import type { Color } from '../color'; function doMouseMove( container: HTMLElement, @@ -518,4 +520,41 @@ describe('ColorPicker', () => { render(); expect(errorSpy).not.toHaveBeenCalled(); }); + + it('Should not show popup when disabled', async () => { + const Demo = () => { + const [disabled, setDisabled] = useState(false); + return ( +
+ +
+ + +
+
+ ); + }; + const { container } = render(); + fireEvent.click(container.querySelector('.disabled-btn')!); + fireEvent.click(container.querySelector('.ant-color-picker-trigger')!); + await waitFakeTimer(); + fireEvent.click(container.querySelector('.active-btn')!); + expect(document.body.querySelector('.ant-popover')).toBeFalsy(); + }); }); diff --git a/components/config-provider/style/index.ts b/components/config-provider/style/index.ts index 87514c6073f1..23c40cb76c27 100644 --- a/components/config-provider/style/index.ts +++ b/components/config-provider/style/index.ts @@ -1,31 +1,2 @@ -import { useStyleRegister } from '@ant-design/cssinjs'; -import type { CSPConfig } from '..'; -import { resetIcon } from '../../style'; -import { useToken } from '../../theme/internal'; - -const useStyle = (iconPrefixCls: string, csp?: CSPConfig) => { - const [theme, token] = useToken(); - - // Generate style for icons - return useStyleRegister( - { - theme, - token, - hashId: '', - path: ['ant-design-icons', iconPrefixCls], - nonce: () => csp?.nonce!, - }, - () => [ - { - [`.${iconPrefixCls}`]: { - ...resetIcon(), - [`.${iconPrefixCls} .${iconPrefixCls}-icon`]: { - display: 'block', - }, - }, - }, - ], - ); -}; - -export default useStyle; +// eslint-disable-next-line no-restricted-exports +export { useResetIconStyle as default } from '../../theme/internal'; diff --git a/components/image/index.tsx b/components/image/index.tsx index fb87bacd55ca..e844cc069ccd 100644 --- a/components/image/index.tsx +++ b/components/image/index.tsx @@ -1,9 +1,11 @@ 'use client'; +import * as React from 'react'; import EyeOutlined from '@ant-design/icons/EyeOutlined'; import classNames from 'classnames'; -import RcImage, { type ImageProps } from 'rc-image'; -import * as React from 'react'; +import RcImage from 'rc-image'; +import type { ImageProps } from 'rc-image'; + import { getTransitionName } from '../_util/motion'; import { ConfigContext } from '../config-provider'; import defaultLocale from '../locale/en_US'; @@ -77,7 +79,7 @@ const Image: CompositionImage = (props) => { ); }; -export { ImageProps }; +export type { ImageProps }; Image.PreviewGroup = PreviewGroup; diff --git a/components/message/index.tsx b/components/message/index.tsx index 7d2f1fdf201a..d3216af7fccc 100755 --- a/components/message/index.tsx +++ b/components/message/index.tsx @@ -16,7 +16,7 @@ import PurePanel from './PurePanel'; import useMessage, { useInternalMessage } from './useMessage'; import { wrapPromiseFn } from './util'; -export { ArgsProps }; +export type { ArgsProps }; let message: GlobalMessage | null = null; diff --git a/components/select/index.zh-CN.md b/components/select/index.zh-CN.md index 1850ac83b685..981c1c00f816 100644 --- a/components/select/index.zh-CN.md +++ b/components/select/index.zh-CN.md @@ -15,6 +15,7 @@ demo: - 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。 - 当选项少时(少于 5 项),建议直接将选项平铺,使用 [Radio](/components/radio-cn/) 是更好的选择。 +- 如果你在寻找一个可输可选的输入框,那你可能需要 [AutoComplete](/components/autocomplete-cn/)。 ## 代码演示 diff --git a/components/tabs/TabPane.ts b/components/tabs/TabPane.ts index 6583651e32cf..d75078d0045a 100644 --- a/components/tabs/TabPane.ts +++ b/components/tabs/TabPane.ts @@ -7,6 +7,6 @@ if (process.env.NODE_ENV !== 'production') { TabPane.displayName = 'DeprecatedTabPane'; } -export { TabPaneProps }; +export type { TabPaneProps }; export default TabPane; diff --git a/components/theme/internal.ts b/components/theme/internal.ts index 66c2fb55e5fd..23bf38fc7748 100644 --- a/components/theme/internal.ts +++ b/components/theme/internal.ts @@ -1,4 +1,5 @@ import { useStyleRegister } from '@ant-design/cssinjs'; + import type { AliasToken, GenerateStyle, @@ -10,18 +11,21 @@ import type { import { PresetColors } from './interface'; import useToken from './useToken'; import type { FullToken } from './util/genComponentStyleHook'; -import genComponentStyleHook from './util/genComponentStyleHook'; +import genComponentStyleHook, { genSubStyleComponent } from './util/genComponentStyleHook'; import genPresetColor from './util/genPresetColor'; import statisticToken, { merge as mergeToken } from './util/statistic'; +import useResetIconStyle from './util/useResetIconStyle'; export { DesignTokenContext, defaultConfig } from './context'; export { PresetColors, genComponentStyleHook, + genSubStyleComponent, genPresetColor, mergeToken, statisticToken, // hooks + useResetIconStyle, useStyleRegister, useToken, }; diff --git a/components/theme/util/genComponentStyleHook.ts b/components/theme/util/genComponentStyleHook.ts index 4e3838417d4e..f729e8682fd6 100644 --- a/components/theme/util/genComponentStyleHook.ts +++ b/components/theme/util/genComponentStyleHook.ts @@ -1,8 +1,9 @@ /* eslint-disable no-redeclare */ +import { useContext, type ComponentType } from 'react'; import type { CSSInterpolation } from '@ant-design/cssinjs'; import { useStyleRegister } from '@ant-design/cssinjs'; import { warning } from 'rc-util'; -import { useContext } from 'react'; + import { ConfigContext } from '../../config-provider/context'; import { genCommonStyle, genLinkStyle } from '../../style'; import type { @@ -13,6 +14,7 @@ import type { } from '../interface'; import useToken from '../useToken'; import statisticToken, { merge as mergeToken } from './statistic'; +import useResetIconStyle from './useResetIconStyle'; export type OverrideTokenWithoutDerivative = ComponentTokenMap; export type OverrideComponent = keyof OverrideTokenWithoutDerivative; @@ -48,9 +50,14 @@ export type FullToken = TokenWithCommon GlobalTokenWithComponent >; +export type GenStyleFn = ( + token: FullToken, + info: StyleInfo, +) => CSSInterpolation; + export default function genComponentStyleHook( - component: ComponentName, - styleFn: (token: FullToken, info: StyleInfo) => CSSInterpolation, + componentName: ComponentName | [ComponentName, string], + styleFn: GenStyleFn, getDefaultToken?: | OverrideTokenWithoutDerivative[ComponentName] | ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName]), @@ -64,6 +71,14 @@ export default function genComponentStyleHook { const [theme, token, hashId] = useToken(); const { getPrefixCls, iconPrefixCls, csp } = useContext(ConfigContext); @@ -92,64 +107,85 @@ export default function genComponentStyleHook { - const { token: proxyToken, flush } = statisticToken(token); - - const customComponentToken = { ...(token[component] as ComponentToken) }; - if (options?.deprecatedTokens) { - const { deprecatedTokens } = options; - deprecatedTokens.forEach(([oldTokenKey, newTokenKey]) => { - if (process.env.NODE_ENV !== 'production') { - warning( - !customComponentToken?.[oldTokenKey], - `The token '${String(oldTokenKey)}' of ${component} had deprecated, use '${String( - newTokenKey, - )}' instead.`, - ); - } - - // Should wrap with `if` clause, or there will be `undefined` in object. - if (customComponentToken?.[oldTokenKey] || customComponentToken?.[newTokenKey]) { - customComponentToken[newTokenKey] ??= customComponentToken?.[oldTokenKey]; - } - }); - } - const defaultComponentToken = - typeof getDefaultToken === 'function' - ? getDefaultToken(mergeToken(proxyToken, customComponentToken ?? {})) - : getDefaultToken; - - const mergedComponentToken = { ...defaultComponentToken, ...customComponentToken }; - - const componentCls = `.${prefixCls}`; - const mergedToken = mergeToken< - TokenWithCommonCls> - >( - proxyToken, - { - componentCls, + useStyleRegister( + { ...sharedConfig, path: [concatComponent, prefixCls, iconPrefixCls] }, + () => { + const { token: proxyToken, flush } = statisticToken(token); + + const customComponentToken = { ...(token[component] as ComponentToken) }; + if (options?.deprecatedTokens) { + const { deprecatedTokens } = options; + deprecatedTokens.forEach(([oldTokenKey, newTokenKey]) => { + if (process.env.NODE_ENV !== 'production') { + warning( + !customComponentToken?.[oldTokenKey], + `The token '${String(oldTokenKey)}' of ${component} had deprecated, use '${String( + newTokenKey, + )}' instead.`, + ); + } + + // Should wrap with `if` clause, or there will be `undefined` in object. + if (customComponentToken?.[oldTokenKey] || customComponentToken?.[newTokenKey]) { + customComponentToken[newTokenKey] ??= customComponentToken?.[oldTokenKey]; + } + }); + } + const defaultComponentToken = + typeof getDefaultToken === 'function' + ? getDefaultToken(mergeToken(proxyToken, customComponentToken ?? {})) + : getDefaultToken; + + const mergedComponentToken = { ...defaultComponentToken, ...customComponentToken }; + + const componentCls = `.${prefixCls}`; + const mergedToken = mergeToken< + TokenWithCommonCls> + >( + proxyToken, + { + componentCls, + prefixCls, + iconCls: `.${iconPrefixCls}`, + antCls: `.${rootPrefixCls}`, + }, + mergedComponentToken, + ); + + const styleInterpolation = styleFn(mergedToken as unknown as FullToken, { + hashId, prefixCls, - iconCls: `.${iconPrefixCls}`, - antCls: `.${rootPrefixCls}`, - }, - mergedComponentToken, - ); - - const styleInterpolation = styleFn(mergedToken as unknown as FullToken, { - hashId, - prefixCls, - rootPrefixCls, - iconPrefixCls, - overrideComponentToken: customComponentToken as any, - }); - flush(component, mergedComponentToken); - return [ - options?.resetStyle === false ? null : genCommonStyle(token, prefixCls), - styleInterpolation, - ]; - }), + rootPrefixCls, + iconPrefixCls, + overrideComponentToken: customComponentToken as any, + }); + flush(component, mergedComponentToken); + return [ + options?.resetStyle === false ? null : genCommonStyle(token, prefixCls), + styleInterpolation, + ]; + }, + ), hashId, ]; }; } + +export interface SubStyleComponentProps { + prefixCls: string; +} + +export function genSubStyleComponent( + ...args: Parameters> +): ComponentType { + const useStyle = genComponentStyleHook(...args); + + return ({ prefixCls }: SubStyleComponentProps) => { + useStyle(prefixCls); + return null; + }; +} diff --git a/components/theme/util/statistic.ts b/components/theme/util/statistic.ts index 7a9458c5e6ba..affc8022b184 100644 --- a/components/theme/util/statistic.ts +++ b/components/theme/util/statistic.ts @@ -67,7 +67,13 @@ export default function statisticToken(token: T) { }); flush = (componentName, componentToken) => { - statistic[componentName] = { global: Array.from(tokenKeys!), component: componentToken }; + statistic[componentName] = { + global: Array.from(tokenKeys!), + component: { + ...statistic[componentName]?.component, + ...componentToken, + }, + }; }; } diff --git a/components/theme/util/useResetIconStyle.ts b/components/theme/util/useResetIconStyle.ts new file mode 100644 index 000000000000..f31204f49ba0 --- /dev/null +++ b/components/theme/util/useResetIconStyle.ts @@ -0,0 +1,31 @@ +import { useStyleRegister } from '@ant-design/cssinjs'; +import { resetIcon } from '../../style'; +import type { CSPConfig } from '../../config-provider'; +import useToken from '../useToken'; + +const useResetIconStyle = (iconPrefixCls: string, csp?: CSPConfig) => { + const [theme, token] = useToken(); + + // Generate style for icons + return useStyleRegister( + { + theme, + token, + hashId: '', + path: ['ant-design-icons', iconPrefixCls], + nonce: () => csp?.nonce!, + }, + () => [ + { + [`.${iconPrefixCls}`]: { + ...resetIcon(), + [`.${iconPrefixCls} .${iconPrefixCls}-icon`]: { + display: 'block', + }, + }, + }, + ], + ); +}; + +export default useResetIconStyle; diff --git a/components/upload/index.en-US.md b/components/upload/index.en-US.md index 49a2c7d48c64..08928a434239 100644 --- a/components/upload/index.en-US.md +++ b/components/upload/index.en-US.md @@ -87,7 +87,7 @@ Extends File with additional props. | crossOrigin | CORS settings attributes | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.20.0 | | name | File name | string | - | - | | percent | Upload progress percent | number | - | - | -| status | Upload status. Show different style when configured | `error` \| `success` \| `done` \| `uploading` \| `removed` | - | - | +| status | Upload status. Show different style when configured | `error` \| `done` \| `uploading` \| `removed` | - | - | | thumbUrl | Thumb image url | string | - | - | | uid | unique id. Will auto-generate when not provided | string | - | - | | url | Download url | string | - | - | diff --git a/components/upload/index.zh-CN.md b/components/upload/index.zh-CN.md index d3685cce05e5..8d42a0ae82fe 100644 --- a/components/upload/index.zh-CN.md +++ b/components/upload/index.zh-CN.md @@ -88,7 +88,7 @@ demo: | crossOrigin | CORS 属性设置 | `'anonymous'` \| `'use-credentials'` \| `''` | - | 4.20.0 | | name | 文件名 | string | - | - | | percent | 上传进度 | number | - | - | -| status | 上传状态,不同状态展示颜色也会有所不同 | `error` \| `success` \| `done` \| `uploading` \| `removed` | - | - | +| status | 上传状态,不同状态展示颜色也会有所不同 | `error` \| `done` \| `uploading` \| `removed` | - | - | | thumbUrl | 缩略图地址 | string | - | - | | uid | 唯一标识符,不设置时会自动生成 | string | - | - | | url | 下载地址 | string | - | - | diff --git a/components/upload/interface.ts b/components/upload/interface.ts index 7bb671165656..ed11b0c3d9ba 100755 --- a/components/upload/interface.ts +++ b/components/upload/interface.ts @@ -1,16 +1,17 @@ +import type * as React from 'react'; import type { RcFile as OriRcFile, UploadRequestOption as RcCustomRequestOptions, UploadProps as RcUploadProps, } from 'rc-upload/lib/interface'; -import type * as React from 'react'; + import type { ProgressAriaProps, ProgressProps } from '../progress'; export interface RcFile extends OriRcFile { readonly lastModifiedDate: Date; } -export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed'; +export type UploadFileStatus = 'error' | 'done' | 'uploading' | 'removed'; export interface HttpRequestHeader { [key: string]: string; diff --git a/package.json b/package.json index 9d385d4ec7f9..66d67e444d80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "5.8.4", + "version": "5.8.5", "packageManager": "^npm@9.0.0", "description": "An enterprise-class UI design language and React components implementation", "title": "Ant Design", @@ -300,8 +300,8 @@ "sylvanas": "^0.6.1", "terser": "^5.16.1", "ts-node": "^10.8.2", - "typedoc": "^0.24.8", - "typescript": "~5.1.3", + "typedoc": "^0.25.0", + "typescript": "~5.2.2", "vanilla-jsoneditor": "^0.18.0", "webpack-bundle-analyzer": "^4.1.0", "xhr-mock": "^2.4.1" diff --git a/scripts/generate-token-meta.ts b/scripts/generate-token-meta.ts index 39dca5c685c3..ae864c85b337 100644 --- a/scripts/generate-token-meta.ts +++ b/scripts/generate-token-meta.ts @@ -2,12 +2,12 @@ import fs from 'fs-extra'; import type { DeclarationReflection } from 'typedoc'; import { Application, TSConfigReader, TypeDocReader } from 'typedoc'; -type TokenMeta = { +interface TokenMeta { seed: ReturnType; map: ReturnType; alias: ReturnType; components: Record>; -}; +} function getTokenList(list?: DeclarationReflection[], source?: string) { return (list || []) @@ -40,20 +40,17 @@ function getTokenList(list?: DeclarationReflection[], source?: string) { })); } -const main = () => { - const app = new Application(); - - // If you want TypeDoc to load tsconfig.json / typedoc.json files - app.options.addReader(new TSConfigReader()); - app.options.addReader(new TypeDocReader()); - - app.bootstrap({ - // typedoc options here - entryPoints: ['components/theme/interface/index.ts', 'components/*/style/index.{ts,tsx}'], - skipErrorChecking: true, - }); +const main = async () => { + const app = await (Application as any).bootstrap( + { + // typedoc options here + entryPoints: ['components/theme/interface/index.ts', 'components/*/style/index.{ts,tsx}'], + skipErrorChecking: true, + }, + [new TSConfigReader(), new TypeDocReader()], + ); - const project = app.convert(); + const project = await app.convert(); if (project) { // Project may not have converted correctly @@ -66,11 +63,11 @@ const main = () => { }; // eslint-disable-next-line no-restricted-syntax - project?.children?.forEach((file) => { + project?.children?.forEach((file: any) => { // Global Token if (file.name === 'theme/interface') { let presetColors: string[] = []; - file.children?.forEach((type) => { + file.children?.forEach((type: any) => { if (type.name === 'SeedToken') { tokenMeta.seed = getTokenList(type.children, 'seed'); } else if (type.name === 'MapToken') { @@ -102,8 +99,8 @@ const main = () => { } else { const component = file.name .slice(0, file.name.indexOf('/')) - .replace(/(^(.)|-(.))/g, (match) => match.replace('-', '').toUpperCase()); - const componentToken = file.children?.find((item) => item.name === `ComponentToken`); + .replace(/(^(.)|-(.))/g, (match: string) => match.replace('-', '').toUpperCase()); + const componentToken = file.children?.find((item: any) => item?.name === 'ComponentToken'); if (componentToken) { tokenMeta.components[component] = getTokenList(componentToken.children, component); }