mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 16:06:28 +08:00
commit
bb8705a38c
@ -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;
|
||||
`,
|
||||
return createStyles(({ token, css }) => {
|
||||
const textShadow = `0 0 3px ${token.colorBgContainer}`;
|
||||
|
||||
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(', ')};
|
||||
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;
|
||||
`,
|
||||
|
||||
h1 {
|
||||
font-family: AliPuHui, ${token.fontFamily} !important;
|
||||
font-weight: 900 !important;
|
||||
font-size: ${token.fontSizeHeading2 * 2}px !important;
|
||||
line-height: ${token.lineHeightHeading2} !important;
|
||||
}
|
||||
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(', ')};
|
||||
|
||||
p {
|
||||
font-size: ${token.fontSizeLG}px !important;
|
||||
font-weight: normal !important;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`,
|
||||
h1 {
|
||||
font-family: AliPuHui, ${token.fontFamily} !important;
|
||||
font-weight: 900 !important;
|
||||
font-size: ${token.fontSizeHeading2 * 2}px !important;
|
||||
line-height: ${token.lineHeightHeading2} !important;
|
||||
}
|
||||
|
||||
block: css`
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
top: -38px;
|
||||
transform: ${isRTL ? 'rotate3d(24, 83, -45, 57deg)' : 'rotate3d(24, -83, 45, 57deg)'};
|
||||
`,
|
||||
p {
|
||||
font-size: ${token.fontSizeLG}px !important;
|
||||
font-weight: normal !important;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`,
|
||||
|
||||
child: css`
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
`,
|
||||
};
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ const useStyle = createStyles(({ token, css }) => ({
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -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<AntdPreviewerProps> = (props) => {
|
||||
const {
|
||||
asset,
|
||||
@ -86,6 +115,8 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (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(<Demo />);
|
||||
sourceCode={entryCode}
|
||||
jsxCode={jsx}
|
||||
styleCode={style}
|
||||
onCodeTypeChange={(type) => setCodeType(type)}
|
||||
onCodeTypeChange={setCodeType}
|
||||
/>
|
||||
<div tabIndex={0} className={styles.codeHideBtn} onClick={() => setCodeExpand(false)}>
|
||||
<UpOutlined />
|
||||
<FormattedMessage id="app.demo.code.hide.simplify" />
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</section>
|
||||
|
@ -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 (
|
||||
<pre key={index} className={`language-${attr.lang}`}>
|
||||
<code dangerouslySetInnerHTML={{ __html: attr.highlighted }} />
|
||||
</pre>
|
||||
);
|
||||
},
|
||||
],
|
||||
|
@ -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 = () => {
|
||||
|
@ -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",
|
||||
|
@ -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 中打开",
|
||||
|
@ -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`
|
||||
|
@ -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`
|
||||
|
@ -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<HTMLDivElement>('.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(
|
||||
<App>
|
||||
<SmileOutlined />
|
||||
</App>,
|
||||
);
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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<SemanticDOM, CSSProperties> | - | 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 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
@ -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<SemanticDOM, CSSProperties> | - | 5.7.0 |
|
||||
| text | 在设置了 `status` 的前提下有效,设置状态点的文本 | ReactNode | - | |
|
||||
| title | 设置鼠标放在状态点上时显示的文字 | string | - | |
|
||||
|
||||
### Badge.Ribbon (4.5.0+)
|
||||
### Badge.Ribbon
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
@ -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<BadgeToken> = (token: BadgeToken): CSSO
|
||||
componentCls,
|
||||
iconCls,
|
||||
antCls,
|
||||
badgeFontHeight,
|
||||
badgeShadowSize,
|
||||
motionDurationSlow,
|
||||
textFontSize,
|
||||
@ -109,11 +111,8 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (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<BadgeToken> = (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<BadgeToken> = (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<GenStyleFn<'Badge'>>[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<BadgeToken>(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<BadgeToken>(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,
|
||||
);
|
||||
|
82
components/badge/style/ribbon.ts
Normal file
82
components/badge/style/ribbon.ts
Normal file
@ -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<BadgeToken> = (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,
|
||||
);
|
@ -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 && <CompactStyle prefixCls={prefixCls} />}
|
||||
</button>
|
||||
);
|
||||
|
||||
|
20
components/button/style/compactCmp.ts
Normal file
20
components/button/style/compactCmp.ts
Normal file
@ -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,
|
||||
);
|
@ -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<ButtonToken> = (token) => {
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export const prepareToken: (token: Parameters<GenStyleFn<'Button'>>[0]) => ButtonToken = (
|
||||
token,
|
||||
) => {
|
||||
const { paddingInline, onlyIconSize } = token;
|
||||
|
||||
const buttonToken = mergeToken<ButtonToken>(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<ButtonToken>(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,
|
||||
);
|
||||
|
@ -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<CarouselRef, CarouselProps>((props, ref) => {
|
||||
dotsClass={dsClass}
|
||||
arrows={arrows}
|
||||
draggable={draggable}
|
||||
verticalSwiping={vertical}
|
||||
waitForAnimate={waitForAnimate}
|
||||
/>
|
||||
</div>,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}}
|
||||
|
@ -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(<ColorPicker disabledAlpha value="#1677ff" />);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should not show popup when disabled', async () => {
|
||||
const Demo = () => {
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
return (
|
||||
<div className="App">
|
||||
<ColorPicker disabled={disabled} />
|
||||
<div className="buttons">
|
||||
<Button
|
||||
className="disabled-btn"
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
setDisabled(true);
|
||||
}}
|
||||
>
|
||||
禁用
|
||||
</Button>
|
||||
<Button
|
||||
className="active-btn"
|
||||
disabled={!disabled}
|
||||
onClick={() => {
|
||||
setDisabled(false);
|
||||
}}
|
||||
>
|
||||
启用
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const { container } = render(<Demo />);
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
@ -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';
|
||||
|
@ -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<ImageProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export { ImageProps };
|
||||
export type { ImageProps };
|
||||
|
||||
Image.PreviewGroup = PreviewGroup;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -15,6 +15,7 @@ demo:
|
||||
|
||||
- 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。
|
||||
- 当选项少时(少于 5 项),建议直接将选项平铺,使用 [Radio](/components/radio-cn/) 是更好的选择。
|
||||
- 如果你在寻找一个可输可选的输入框,那你可能需要 [AutoComplete](/components/autocomplete-cn/)。
|
||||
|
||||
## 代码演示
|
||||
|
||||
|
@ -7,6 +7,6 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
TabPane.displayName = 'DeprecatedTabPane';
|
||||
}
|
||||
|
||||
export { TabPaneProps };
|
||||
export type { TabPaneProps };
|
||||
|
||||
export default TabPane;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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<ComponentName extends OverrideComponent> = TokenWithCommon
|
||||
GlobalTokenWithComponent<ComponentName>
|
||||
>;
|
||||
|
||||
export type GenStyleFn<ComponentName extends OverrideComponent> = (
|
||||
token: FullToken<ComponentName>,
|
||||
info: StyleInfo<ComponentName>,
|
||||
) => CSSInterpolation;
|
||||
|
||||
export default function genComponentStyleHook<ComponentName extends OverrideComponent>(
|
||||
component: ComponentName,
|
||||
styleFn: (token: FullToken<ComponentName>, info: StyleInfo<ComponentName>) => CSSInterpolation,
|
||||
componentName: ComponentName | [ComponentName, string],
|
||||
styleFn: GenStyleFn<ComponentName>,
|
||||
getDefaultToken?:
|
||||
| OverrideTokenWithoutDerivative[ComponentName]
|
||||
| ((token: GlobalToken) => OverrideTokenWithoutDerivative[ComponentName]),
|
||||
@ -64,6 +71,14 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
|
||||
clientOnly?: boolean;
|
||||
},
|
||||
) {
|
||||
const cells = (Array.isArray(componentName) ? componentName : [componentName, componentName]) as [
|
||||
ComponentName,
|
||||
string,
|
||||
];
|
||||
|
||||
const [component] = cells;
|
||||
const concatComponent = cells.join('-');
|
||||
|
||||
return (prefixCls: string): UseComponentStyleResult => {
|
||||
const [theme, token, hashId] = useToken();
|
||||
const { getPrefixCls, iconPrefixCls, csp } = useContext(ConfigContext);
|
||||
@ -92,64 +107,85 @@ export default function genComponentStyleHook<ComponentName extends OverrideComp
|
||||
],
|
||||
);
|
||||
|
||||
// Generate style for icons
|
||||
useResetIconStyle(iconPrefixCls);
|
||||
|
||||
return [
|
||||
useStyleRegister({ ...sharedConfig, path: [component, prefixCls, iconPrefixCls] }, () => {
|
||||
const { token: proxyToken, flush } = statisticToken(token);
|
||||
useStyleRegister(
|
||||
{ ...sharedConfig, path: [concatComponent, prefixCls, iconPrefixCls] },
|
||||
() => {
|
||||
const { token: proxyToken, flush } = statisticToken(token);
|
||||
|
||||
const customComponentToken = { ...(token[component] as ComponentToken<ComponentName>) };
|
||||
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.`,
|
||||
);
|
||||
}
|
||||
const customComponentToken = { ...(token[component] as ComponentToken<ComponentName>) };
|
||||
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;
|
||||
// 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 mergedComponentToken = { ...defaultComponentToken, ...customComponentToken };
|
||||
|
||||
const componentCls = `.${prefixCls}`;
|
||||
const mergedToken = mergeToken<
|
||||
TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>
|
||||
>(
|
||||
proxyToken,
|
||||
{
|
||||
componentCls,
|
||||
const componentCls = `.${prefixCls}`;
|
||||
const mergedToken = mergeToken<
|
||||
TokenWithCommonCls<GlobalTokenWithComponent<OverrideComponent>>
|
||||
>(
|
||||
proxyToken,
|
||||
{
|
||||
componentCls,
|
||||
prefixCls,
|
||||
iconCls: `.${iconPrefixCls}`,
|
||||
antCls: `.${rootPrefixCls}`,
|
||||
},
|
||||
mergedComponentToken,
|
||||
);
|
||||
|
||||
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
|
||||
hashId,
|
||||
prefixCls,
|
||||
iconCls: `.${iconPrefixCls}`,
|
||||
antCls: `.${rootPrefixCls}`,
|
||||
},
|
||||
mergedComponentToken,
|
||||
);
|
||||
|
||||
const styleInterpolation = styleFn(mergedToken as unknown as FullToken<ComponentName>, {
|
||||
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<ComponentName extends OverrideComponent>(
|
||||
...args: Parameters<typeof genComponentStyleHook<ComponentName>>
|
||||
): ComponentType<SubStyleComponentProps> {
|
||||
const useStyle = genComponentStyleHook(...args);
|
||||
|
||||
return ({ prefixCls }: SubStyleComponentProps) => {
|
||||
useStyle(prefixCls);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
@ -67,7 +67,13 @@ export default function statisticToken<T extends object>(token: T) {
|
||||
});
|
||||
|
||||
flush = (componentName, componentToken) => {
|
||||
statistic[componentName] = { global: Array.from(tokenKeys!), component: componentToken };
|
||||
statistic[componentName] = {
|
||||
global: Array.from(tokenKeys!),
|
||||
component: {
|
||||
...statistic[componentName]?.component,
|
||||
...componentToken,
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
31
components/theme/util/useResetIconStyle.ts
Normal file
31
components/theme/util/useResetIconStyle.ts
Normal file
@ -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;
|
@ -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 | - | - |
|
||||
|
@ -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 | - | - |
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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<typeof getTokenList>;
|
||||
map: ReturnType<typeof getTokenList>;
|
||||
alias: ReturnType<typeof getTokenList>;
|
||||
components: Record<string, ReturnType<typeof getTokenList>>;
|
||||
};
|
||||
}
|
||||
|
||||
function getTokenList(list?: DeclarationReflection[], source?: string) {
|
||||
return (list || [])
|
||||
@ -40,20 +40,17 @@ function getTokenList(list?: DeclarationReflection[], source?: string) {
|
||||
}));
|
||||
}
|
||||
|
||||
const main = () => {
|
||||
const app = new Application();
|
||||
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()],
|
||||
);
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user