chore: merge master

This commit is contained in:
afc163 2025-01-17 11:39:45 +08:00
commit 8d935acb80
34 changed files with 763 additions and 299 deletions

View File

@ -20,6 +20,7 @@ interface ChangelogInfo {
version: string;
changelog: string;
refs: string[];
contributors: string[];
releaseDate: string;
}
@ -160,14 +161,30 @@ const ParseChangelog: React.FC<{ changelog: string }> = (props) => {
return <span>{parsedChangelog}</span>;
};
const RefLinks: React.FC<{ refs: string[] }> = ({ refs }) => {
const RefLinks: React.FC<{ refs: string[]; contributors: string[] }> = ({ refs, contributors }) => {
const { styles } = useStyle();
return (
<>
{refs?.map((ref) => (
<React.Fragment key={ref}>
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
#{ref.match(/[^/]+$/)?.[0]}
</a>
</React.Fragment>
))}
{contributors?.map((contributor) => (
<React.Fragment key={contributor}>
<a
className={styles.linkRef}
key={contributor}
href={`https://github.com/${contributor}`}
target="_blank"
rel="noreferrer"
>
@{contributor}
</a>
</React.Fragment>
))}
</>
);
@ -178,7 +195,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
const { styles } = useStyle();
const len = changelogList.length;
for (let i = 0; i < len; i += 1) {
const { refs, changelog } = changelogList[i];
const { refs, changelog, contributors } = changelogList[i];
// Check if the next line is an image link and append it to the current line
if (i + 1 < len && changelogList[i + 1].changelog.trim().startsWith('<img')) {
const imgDom = new DOMParser().parseFromString(changelogList[i + 1].changelog, 'text/html');
@ -186,7 +203,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
elements.push(
<li key={i}>
<ParseChangelog changelog={changelog} />
<RefLinks refs={refs} />
<RefLinks refs={refs} contributors={contributors} />
<br />
<img
src={imgElement?.getAttribute('src') || ''}
@ -200,7 +217,7 @@ const RenderChangelogList: React.FC<{ changelogList: ChangelogInfo[] }> = ({ cha
elements.push(
<li key={i}>
<ParseChangelog changelog={changelog} />
<RefLinks refs={refs} />
<RefLinks refs={refs} contributors={contributors} />
</li>,
);
}

View File

@ -5,7 +5,7 @@ on:
- cron: "0 0 * * *" # Run at 00:00 every day
permissions:
issues: write # Need write permission to modify issue assignees
issues: write
jobs:
reminder_job:
@ -19,12 +19,14 @@ jobs:
let page = 1;
const perPage = 100;
const reminderSignature = "This issue has been inactive for more than 14 days";
while (true) {
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
assignee: '*', // Filter assigned issues
assignee: '*',
per_page: perPage,
page: page,
});
@ -53,6 +55,19 @@ jobs:
);
if (daysInactive >= daysBeforeReminder && !hasLinkedPR) {
// get issue comments
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
});
// check if reminder has been sent
const hasReminder = comments.some(comment =>
comment.body.includes(reminderSignature)
);
if (!hasReminder) {
const assigneesMentions = issue.assignees
.map(user => `@${user.login}`)
.join(' ');
@ -65,6 +80,7 @@ jobs:
});
}
}
}
page += 1;
}

View File

@ -102,6 +102,20 @@ describe('Descriptions', () => {
expect(container.querySelectorAll('.ant-descriptions-item')[6]).toHaveAttribute('colSpan', '2');
});
it('when column=6, last item span should be 5', () => {
const { container } = render(
<Descriptions
column={6}
items={[
{ label: '0', children: '' },
{ label: '1', children: '', span: 2 },
]}
/>,
);
expect(container.querySelectorAll('.ant-descriptions-item')[0]).toHaveAttribute('colSpan', '1');
expect(container.querySelectorAll('.ant-descriptions-item')[1]).toHaveAttribute('colSpan', '5');
});
it('column is number', () => {
const wrapper = render(
<Descriptions column={3}>

View File

@ -53,7 +53,7 @@ function getCalcRows(
if (count < mergedColumn) {
// If the span of the last element in the current row is less than the column, then add its span to the remaining columns
const last = rows[rows.length - 1];
last.span = mergedColumn - count + 1;
last.span = mergedColumn - (count - (last.span || 1));
return rows;
}
return rows;

View File

@ -421,6 +421,7 @@ const genAllowClearStyle = (token: InputToken): CSSObject => {
// ========================= Input =========================
[`${componentCls}-clear-icon`]: {
margin: 0,
padding: 0,
lineHeight: 0,
color: token.colorTextQuaternary,
fontSize: token.fontSizeIcon,

View File

@ -1405,7 +1405,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx extend context correctly
>
<aside
class="ant-layout-sider ant-layout-sider-dark"
style="overflow: auto; height: 100vh; position: fixed; inset-inline-start: 0; top: 0px; bottom: 0px; flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;"
style="overflow: auto; height: 100vh; position: sticky; inset-inline-start: 0; top: 0px; bottom: 0px; flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;"
>
<div
class="ant-layout-sider-children"
@ -1836,7 +1836,6 @@ exports[`renders components/layout/demo/fixed-sider.tsx extend context correctly
</aside>
<div
class="ant-layout"
style="margin-inline-start: 200px;"
>
<header
class="ant-layout-header"

View File

@ -765,7 +765,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx correctly 1`] = `
>
<aside
class="ant-layout-sider ant-layout-sider-dark"
style="overflow:auto;height:100vh;position:fixed;inset-inline-start:0;top:0;bottom:0;scrollbar-width:thin;scrollbar-gutter:stable;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
style="overflow:auto;height:100vh;position:sticky;inset-inline-start:0;top:0;bottom:0;scrollbar-width:thin;scrollbar-gutter:stable;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
>
<div
class="ant-layout-sider-children"
@ -1044,7 +1044,6 @@ exports[`renders components/layout/demo/fixed-sider.tsx correctly 1`] = `
</aside>
<div
class="ant-layout"
style="margin-inline-start:200px"
>
<header
class="ant-layout-header"

View File

@ -4,4 +4,4 @@
## en-US
When dealing with long content, a fixed sider can provide a better user experience.
When dealing with long content, a sticky sider can provide a better user experience.

View File

@ -17,7 +17,7 @@ const { Header, Content, Footer, Sider } = Layout;
const siderStyle: React.CSSProperties = {
overflow: 'auto',
height: '100vh',
position: 'fixed',
position: 'sticky',
insetInlineStart: 0,
top: 0,
bottom: 0,
@ -51,7 +51,7 @@ const App: React.FC = () => {
<div className="demo-logo-vertical" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']} items={items} />
</Sider>
<Layout style={{ marginInlineStart: 200 }}>
<Layout>
<Header style={{ padding: 0, background: colorBgContainer }} />
<Content style={{ margin: '24px 16px 0', overflow: 'initial' }}>
<div

View File

@ -4,4 +4,4 @@
## en-US
Fixed Header is generally used to fix the top navigation to facilitate page switching.
Sticky Header is generally used to fix the top navigation to facilitate page switching.

View File

@ -126,6 +126,7 @@ const genMentionsStyle: GenerateStyle<MentionsToken> = (token) => {
insetBlockStart: calc(fontSize).mul(lineHeight).mul(0.5).add(paddingBlock).equal(),
transform: `translateY(-50%)`,
margin: 0,
padding: 0,
color: colorTextQuaternary,
fontSize: fontSizeIcon,
verticalAlign: -1,

View File

@ -1924,6 +1924,40 @@ exports[`renders components/menu/demo/extra-style.tsx extend context correctly 1
/>
</div>
</div>
<li
aria-disabled="true"
class="ant-menu-item ant-menu-item-disabled ant-menu-item-only-child"
data-menu-id="rc-menu-uuid-test-3"
role="menuitem"
style="padding-left: 48px;"
>
<span
class="ant-menu-title-content"
>
<a
href="https://www.baidu.com"
>
Link Option
</a>
</span>
</li>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
/>
</div>
</div>
</ul>
</div>
<ul
@ -2026,6 +2060,40 @@ exports[`renders components/menu/demo/extra-style.tsx extend context correctly 1
/>
</div>
</div>
<li
aria-disabled="true"
class="ant-menu-item ant-menu-item-disabled ant-menu-item-only-child"
data-menu-id="rc-menu-uuid-test-3"
role="menuitem"
style="padding-left: 48px;"
>
<span
class="ant-menu-title-content"
>
<a
href="https://www.baidu.com"
>
Link Option
</a>
</span>
</li>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-menu-inline-collapsed-tooltip ant-tooltip-placement-right"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
/>
</div>
</div>
</ul>
</li>
</ul>

View File

@ -911,6 +911,22 @@ exports[`renders components/menu/demo/extra-style.tsx correctly 1`] = `
</span>
</span>
</li>
<li
aria-disabled="true"
class="ant-menu-item ant-menu-item-disabled ant-menu-item-only-child"
role="menuitem"
style="padding-left:48px"
>
<span
class="ant-menu-title-content"
>
<a
href="https://www.baidu.com"
>
Link Option
</a>
</span>
</li>
</ul>
</li>
</ul>

View File

@ -1165,4 +1165,32 @@ describe('Menu', () => {
expect(container.querySelector('.ant-menu-title-content-with-extra')).toBeInTheDocument();
expect(container.querySelector('.ant-menu-item-extra')?.textContent).toBe(text);
});
it('should prevent click events when disabled MenuItem with link', () => {
const onClick = jest.fn();
const { container } = render(
<Menu
mode="vertical"
items={[
{
key: '1',
disabled: true,
label: (
<a href="https://ant.design" onClick={onClick}>
Disabled Link
</a>
),
},
]}
/>,
);
const link = container.querySelector('a')!;
expect(container.querySelector('.ant-menu-item')).toHaveClass('ant-menu-item-disabled');
expect(window.getComputedStyle(link).pointerEvents).toBe('none');
expect(link).toHaveStyle({
pointerEvents: 'none',
cursor: 'not-allowed',
});
});
});

View File

@ -25,6 +25,11 @@ const items1: MenuItem[] = [
label: 'Option 2',
extra: '⌘P',
},
{
key: '3',
label: <a href="https://www.baidu.com">Link Option</a>,
disabled: true,
},
],
},
];

View File

@ -474,6 +474,8 @@ const genMenuItemStyle = (token: MenuToken): CSSObject => {
a: {
color: 'inherit !important',
cursor: 'not-allowed',
pointerEvents: 'none',
},
[`> ${componentCls}-submenu-title`]: {

View File

@ -59,7 +59,7 @@ The properties of config are as follows:
| icon | Customized icon | ReactNode | - | - |
| key | The unique identifier of the Notification | string | - | - |
| message | The title of notification box (required) | ReactNode | - | - |
| placement | Position of Notification, can be one of `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | string | `topRight` | - |
| placement | Position of Notification, can be one of `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | string | `topRight` | - |
| style | Customized inline style | [CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - | - |
| role | The semantics of notification content recognized by screen readers. The default value is `alert`. When set as the default value, the screen reader will promptly interrupt any ongoing content reading and prioritize the notification content for immediate attention. | `alert \| status` | `alert` | 5.6.0 |
| onClick | Specify a function that will be called when the notification is clicked | function | - | - |
@ -75,7 +75,7 @@ The properties of config are as follows:
| bottom | Distance from the bottom of the viewport, when `placement` is `bottom` `bottomRight` or `bottomLeft` (unit: pixels) | number | 24 | |
| closeIcon | Custom close icon | ReactNode | true | 5.7.0: close button will be hidden when setting to null or false |
| getContainer | Return the mount node for Notification | () => HTMLNode | () => document.body | |
| placement | Position of Notification, can be one of `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | string | `topRight` | |
| placement | Position of Notification, can be one of `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | string | `topRight` | |
| showProgress | Show progress bar for auto-closing notification | boolean | | 5.18.0 |
| pauseOnHover | keep the timer running or not on hover | boolean | true | 5.18.0 |
| rtl | Whether to enable RTL mode | boolean | false | |

View File

@ -60,7 +60,7 @@ config 参数如下:
| icon | 自定义图标 | ReactNode | - | - |
| key | 当前通知唯一标志 | string | - | - |
| message | 通知提醒标题,必选 | ReactNode | - | - |
| placement | 弹出位置,可选 `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | string | `topRight` | - |
| placement | 弹出位置,可选 `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | string | `topRight` | - |
| style | 自定义内联样式 | [CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - | - |
| role | 供屏幕阅读器识别的通知内容语义,默认为 `alert`。此情况下屏幕阅读器会立即打断当前正在阅读的其他内容,转而阅读通知内容 | `alert \| status` | `alert` | 5.6.0 |
| onClick | 点击通知时触发的回调函数 | function | - | - |
@ -76,7 +76,7 @@ config 参数如下:
| bottom | 消息从底部弹出时,距离底部的位置,单位像素 | number | 24 | |
| closeIcon | 自定义关闭图标 | ReactNode | true | 5.7.0:设置为 null 或 false 时隐藏关闭按钮 |
| getContainer | 配置渲染节点的输出位置 | () => HTMLNode | () => document.body | |
| placement | 弹出位置,可选 `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | string | `topRight` | |
| placement | 弹出位置,可选 `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | string | `topRight` | |
| showProgress | 显示自动关闭通知框的进度条 | boolean | | 5.18.0 |
| pauseOnHover | 悬停时是否暂停计时器 | boolean | true | 5.18.0 |
| rtl | 是否开启 RTL 模式 | boolean | false | |

View File

@ -1149,7 +1149,31 @@ exports[`renders components/radio/demo/radiogroup.tsx extend context correctly 1
<span
class="ant-radio-label"
>
A
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="line-chart"
class="anticon anticon-line-chart"
role="img"
style="font-size: 18px;"
>
<svg
aria-hidden="true"
data-icon="line-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM305.8 637.7c3.1 3.1 8.1 3.1 11.3 0l138.3-137.6L583 628.5c3.1 3.1 8.2 3.1 11.3 0l275.4-275.3c3.1-3.1 3.1-8.2 0-11.3l-39.6-39.6a8.03 8.03 0 00-11.3 0l-230 229.9L461.4 404a8.03 8.03 0 00-11.3 0L266.3 586.7a8.03 8.03 0 000 11.3l39.5 39.7z"
/>
</svg>
</span>
LineChart
</div>
</span>
</label>
<label
@ -1171,7 +1195,31 @@ exports[`renders components/radio/demo/radiogroup.tsx extend context correctly 1
<span
class="ant-radio-label"
>
B
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="dot-chart"
class="anticon anticon-dot-chart"
role="img"
style="font-size: 18px;"
>
<svg
aria-hidden="true"
data-icon="dot-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM288 604a64 64 0 10128 0 64 64 0 10-128 0zm118-224a48 48 0 1096 0 48 48 0 10-96 0zm158 228a96 96 0 10192 0 96 96 0 10-192 0zm148-314a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
DotChart
</div>
</span>
</label>
<label
@ -1193,7 +1241,31 @@ exports[`renders components/radio/demo/radiogroup.tsx extend context correctly 1
<span
class="ant-radio-label"
>
C
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="bar-chart"
class="anticon anticon-bar-chart"
role="img"
style="font-size: 18px;"
>
<svg
aria-hidden="true"
data-icon="bar-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-600-80h56c4.4 0 8-3.6 8-8V560c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V384c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v320c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V462c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v242c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V304c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v400c0 4.4 3.6 8 8 8z"
/>
</svg>
</span>
BarChart
</div>
</span>
</label>
<label
@ -1215,7 +1287,31 @@ exports[`renders components/radio/demo/radiogroup.tsx extend context correctly 1
<span
class="ant-radio-label"
>
D
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="pie-chart"
class="anticon anticon-pie-chart"
role="img"
style="font-size: 18px;"
>
<svg
aria-hidden="true"
data-icon="pie-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M864 518H506V160c0-4.4-3.6-8-8-8h-26a398.46 398.46 0 00-282.8 117.1 398.19 398.19 0 00-85.7 127.1A397.61 397.61 0 0072 552a398.46 398.46 0 00117.1 282.8c36.7 36.7 79.5 65.6 127.1 85.7A397.61 397.61 0 00472 952a398.46 398.46 0 00282.8-117.1c36.7-36.7 65.6-79.5 85.7-127.1A397.61 397.61 0 00872 552v-26c0-4.4-3.6-8-8-8zM705.7 787.8A331.59 331.59 0 01470.4 884c-88.1-.4-170.9-34.9-233.2-97.2C174.5 724.1 140 640.7 140 552c0-88.7 34.5-172.1 97.2-234.8 54.6-54.6 124.9-87.9 200.8-95.5V586h364.3c-7.7 76.3-41.3 147-96.6 201.8zM952 462.4l-2.6-28.2c-8.5-92.1-49.4-179-115.2-244.6A399.4 399.4 0 00589 74.6L560.7 72c-4.7-.4-8.7 3.2-8.7 7.9V464c0 4.4 3.6 8 8 8l384-1c4.7 0 8.4-4 8-8.6zm-332.2-58.2V147.6a332.24 332.24 0 01166.4 89.8c45.7 45.6 77 103.6 90 166.1l-256.4.7z"
/>
</svg>
</span>
PieChart
</div>
</span>
</label>
</div>
@ -1448,12 +1544,7 @@ exports[`renders components/radio/demo/radiogroup-block.tsx extend context corre
exports[`renders components/radio/demo/radiogroup-more.tsx extend context correctly 1`] = `
<div
class="ant-radio-group ant-radio-group-outline"
>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
style="display: flex; flex-direction: column; gap: 8px;"
>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
@ -1478,10 +1569,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
Option A
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1504,10 +1591,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
Option B
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1530,10 +1613,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
Option C
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1557,8 +1636,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx extend context correc
</span>
</label>
</div>
</div>
</div>
`;
exports[`renders components/radio/demo/radiogroup-more.tsx extend context correctly 2`] = `[]`;

View File

@ -1135,7 +1135,31 @@ exports[`renders components/radio/demo/radiogroup.tsx correctly 1`] = `
<span
class="ant-radio-label"
>
A
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="line-chart"
class="anticon anticon-line-chart"
role="img"
style="font-size:18px"
>
<svg
aria-hidden="true"
data-icon="line-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM305.8 637.7c3.1 3.1 8.1 3.1 11.3 0l138.3-137.6L583 628.5c3.1 3.1 8.2 3.1 11.3 0l275.4-275.3c3.1-3.1 3.1-8.2 0-11.3l-39.6-39.6a8.03 8.03 0 00-11.3 0l-230 229.9L461.4 404a8.03 8.03 0 00-11.3 0L266.3 586.7a8.03 8.03 0 000 11.3l39.5 39.7z"
/>
</svg>
</span>
LineChart
</div>
</span>
</label>
<label
@ -1157,7 +1181,31 @@ exports[`renders components/radio/demo/radiogroup.tsx correctly 1`] = `
<span
class="ant-radio-label"
>
B
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="dot-chart"
class="anticon anticon-dot-chart"
role="img"
style="font-size:18px"
>
<svg
aria-hidden="true"
data-icon="dot-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM288 604a64 64 0 10128 0 64 64 0 10-128 0zm118-224a48 48 0 1096 0 48 48 0 10-96 0zm158 228a96 96 0 10192 0 96 96 0 10-192 0zm148-314a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
DotChart
</div>
</span>
</label>
<label
@ -1179,7 +1227,31 @@ exports[`renders components/radio/demo/radiogroup.tsx correctly 1`] = `
<span
class="ant-radio-label"
>
C
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="bar-chart"
class="anticon anticon-bar-chart"
role="img"
style="font-size:18px"
>
<svg
aria-hidden="true"
data-icon="bar-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm-600-80h56c4.4 0 8-3.6 8-8V560c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v144c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V384c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v320c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V462c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v242c0 4.4 3.6 8 8 8zm152 0h56c4.4 0 8-3.6 8-8V304c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v400c0 4.4 3.6 8 8 8z"
/>
</svg>
</span>
BarChart
</div>
</span>
</label>
<label
@ -1201,7 +1273,31 @@ exports[`renders components/radio/demo/radiogroup.tsx correctly 1`] = `
<span
class="ant-radio-label"
>
D
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center ant-flex-gap-small ant-flex-vertical"
>
<span
aria-label="pie-chart"
class="anticon anticon-pie-chart"
role="img"
style="font-size:18px"
>
<svg
aria-hidden="true"
data-icon="pie-chart"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M864 518H506V160c0-4.4-3.6-8-8-8h-26a398.46 398.46 0 00-282.8 117.1 398.19 398.19 0 00-85.7 127.1A397.61 397.61 0 0072 552a398.46 398.46 0 00117.1 282.8c36.7 36.7 79.5 65.6 127.1 85.7A397.61 397.61 0 00472 952a398.46 398.46 0 00282.8-117.1c36.7-36.7 65.6-79.5 85.7-127.1A397.61 397.61 0 00872 552v-26c0-4.4-3.6-8-8-8zM705.7 787.8A331.59 331.59 0 01470.4 884c-88.1-.4-170.9-34.9-233.2-97.2C174.5 724.1 140 640.7 140 552c0-88.7 34.5-172.1 97.2-234.8 54.6-54.6 124.9-87.9 200.8-95.5V586h364.3c-7.7 76.3-41.3 147-96.6 201.8zM952 462.4l-2.6-28.2c-8.5-92.1-49.4-179-115.2-244.6A399.4 399.4 0 00589 74.6L560.7 72c-4.7-.4-8.7 3.2-8.7 7.9V464c0 4.4 3.6 8 8 8l384-1c4.7 0 8.4-4 8-8.6zm-332.2-58.2V147.6a332.24 332.24 0 01166.4 89.8c45.7 45.6 77 103.6 90 166.1l-256.4.7z"
/>
</svg>
</span>
PieChart
</div>
</span>
</label>
</div>
@ -1430,12 +1526,7 @@ exports[`renders components/radio/demo/radiogroup-block.tsx correctly 1`] = `
exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
<div
class="ant-radio-group ant-radio-group-outline"
>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
style="display:flex;flex-direction:column;gap:8px"
>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
@ -1460,10 +1551,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
Option A
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1486,10 +1573,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
Option B
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1512,10 +1595,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
Option C
</span>
</label>
</div>
<div
class="ant-space-item"
>
<label
class="ant-radio-wrapper"
>
@ -1539,8 +1618,6 @@ exports[`renders components/radio/demo/radiogroup-more.tsx correctly 1`] = `
</span>
</label>
</div>
</div>
</div>
`;
exports[`renders components/radio/demo/radiogroup-options.tsx correctly 1`] = `

View File

@ -1,7 +1,8 @@
import React from 'react';
import { Flex, Radio } from 'antd';
import type { CheckboxGroupProps } from 'antd/es/checkbox';
const options = [
const options: CheckboxGroupProps<string>['options'] = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange' },

View File

@ -1,27 +1,46 @@
import React, { useState } from 'react';
import type { RadioChangeEvent } from 'antd';
import { Input, Radio, Space } from 'antd';
import { Input, Radio } from 'antd';
const style: React.CSSProperties = {
display: 'flex',
flexDirection: 'column',
gap: 8,
};
const App: React.FC = () => {
const [value, setValue] = useState(1);
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value);
setValue(e.target.value);
};
return (
<Radio.Group onChange={onChange} value={value}>
<Space direction="vertical">
<Radio value={1}>Option A</Radio>
<Radio value={2}>Option B</Radio>
<Radio value={3}>Option C</Radio>
<Radio value={4}>
<Radio.Group
style={style}
onChange={onChange}
value={value}
options={[
{ value: 1, label: 'Option A' },
{ value: 2, label: 'Option B' },
{ value: 3, label: 'Option C' },
{
value: 4,
label: (
<>
More...
{value === 4 ? <Input style={{ width: 100, marginInlineStart: 10 }} /> : null}
</Radio>
</Space>
</Radio.Group>
{value === 4 && (
<Input
variant="filled"
placeholder="please input"
style={{ width: 120, marginInlineStart: 12 }}
/>
)}
</>
),
},
]}
/>
);
};

View File

@ -1,14 +1,17 @@
import React, { useState } from 'react';
import type { RadioChangeEvent } from 'antd';
import { Radio } from 'antd';
import type { CheckboxGroupProps } from 'antd/es/checkbox';
const plainOptions = ['Apple', 'Pear', 'Orange'];
const options = [
const plainOptions: CheckboxGroupProps<string>['options'] = ['Apple', 'Pear', 'Orange'];
const options: CheckboxGroupProps<string>['options'] = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', title: 'Orange' },
];
const optionsWithDisabled = [
const optionsWithDisabled: CheckboxGroupProps<string>['options'] = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: true },

View File

@ -2,12 +2,16 @@ import React from 'react';
import { Radio } from 'antd';
const App: React.FC = () => (
<Radio.Group name="radiogroup" defaultValue={1}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
<Radio.Group
name="radiogroup"
defaultValue={1}
options={[
{ value: 1, label: 'A' },
{ value: 2, label: 'B' },
{ value: 3, label: 'C' },
{ value: 4, label: 'D' },
]}
/>
);
export default App;

View File

@ -1,22 +1,63 @@
import React, { useState } from 'react';
import {
BarChartOutlined,
DotChartOutlined,
LineChartOutlined,
PieChartOutlined,
} from '@ant-design/icons';
import type { RadioChangeEvent } from 'antd';
import { Radio } from 'antd';
import { Flex, Radio } from 'antd';
const App: React.FC = () => {
const [value, setValue] = useState(1);
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value);
setValue(e.target.value);
};
return (
<Radio.Group onChange={onChange} value={value}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
<Radio.Group
onChange={onChange}
value={value}
options={[
{
value: 1,
label: (
<Flex gap="small" justify="center" align="center" vertical>
<LineChartOutlined style={{ fontSize: 18 }} />
LineChart
</Flex>
),
},
{
value: 2,
label: (
<Flex gap="small" justify="center" align="center" vertical>
<DotChartOutlined style={{ fontSize: 18 }} />
DotChart
</Flex>
),
},
{
value: 3,
label: (
<Flex gap="small" justify="center" align="center" vertical>
<BarChartOutlined style={{ fontSize: 18 }} />
BarChart
</Flex>
),
},
{
value: 4,
label: (
<Flex gap="small" justify="center" align="center" vertical>
<PieChartOutlined style={{ fontSize: 18 }} />
PieChart
</Flex>
),
},
]}
/>
);
};

View File

@ -1,21 +1,19 @@
import React from 'react';
import { ConfigProvider, Radio } from 'antd';
import type { CheckboxGroupProps } from 'antd/es/checkbox';
const options: CheckboxGroupProps<string | number>['options'] = [
{ value: 1, label: 'A' },
{ value: 2, label: 'B' },
{ value: 3, label: 'C' },
{ value: 4, label: 'D' },
];
const App: React.FC = () => (
<ConfigProvider theme={{ token: { wireframe: true } }}>
<Radio.Group value={1}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
<Radio.Group value={1} options={options} />
<br />
<Radio.Group value={1} disabled>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
<Radio.Group value={1} options={options} disabled />
</ConfigProvider>
);

View File

@ -14,6 +14,29 @@ demo:
- Used to select a single state from multiple options.
- The difference from Select is that Radio is visible to the user and can facilitate the comparison of choice, which means there shouldn't be too many of them.
```tsx
// When use Radio.Group, recommended ✅
return (
<Radio.Group
value={value}
options={[
{ value: 1, label: "A" },
{ value: 2, label: "B"},
{ value: 3, label: "C" },
]}
/>
);
// No recommended 🙅🏻‍♀️
return (
<Radio.Group value={value}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
</Radio.Group>
);
```
## Examples
<!-- prettier-ignore-start -->

View File

@ -15,6 +15,29 @@ demo:
- 用于在多个备选项中选中单个状态。
- 和 Select 的区别是Radio 所有选项默认可见,方便用户在比较中选择,因此选项不宜过多。
```tsx
// 使用 Radio.Group 组件时,推荐的写法 ✅
return (
<Radio.Group
value={value}
options={[
{ value: 1, label: "A" },
{ value: 2, label: "B"},
{ value: 3, label: "C" },
]}
/>
);
// 不推荐的写法 🙅🏻‍♀️
return (
<Radio.Group value={value}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
</Radio.Group>
);
```
## 代码演示
<!-- prettier-ignore-start -->

View File

@ -172,6 +172,10 @@ const getRadioBasicStyle: GenerateStyle<RadioToken> = (token) => {
marginInlineEnd: wrapperMarginInlineEnd,
cursor: 'pointer',
'&:last-child': {
marginInlineEnd: 0,
},
// RTL
[`&${componentCls}-wrapper-rtl`]: {
direction: 'rtl',

View File

@ -5,7 +5,7 @@ import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
export type ComponentToken = {
export interface ComponentToken {
/**
* @desc
* @descEN Star color
@ -26,7 +26,7 @@ export type ComponentToken = {
* @descEN Star background color
*/
starBg: string;
};
}
interface RateToken extends FullToken<'Rate'> {}

View File

@ -4,7 +4,7 @@ import { Keyframes, unit } from '@ant-design/cssinjs';
import type { CSSUtil, FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
import { genStyleHooks, mergeToken } from '../../theme/internal';
export type ComponentToken = {
export interface ComponentToken {
/** @deprecated use gradientFromColor instead. */
color: string;
/** @deprecated use gradientToColor instead. */
@ -39,7 +39,7 @@ export type ComponentToken = {
* @descEN Line height of paragraph skeleton
*/
paragraphLiHeight: number;
};
}
const skeletonClsLoading = new Keyframes(`ant-skeleton-loading`, {
'0%': {

View File

@ -557,18 +557,18 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
const virtualProps: { listItemHeight?: number } = {};
const listItemHeight = React.useMemo(() => {
const { fontSize, lineHeight, padding, paddingXS, paddingSM } = token;
const { fontSize, lineHeight, lineWidth, padding, paddingXS, paddingSM } = token;
const fontHeight = Math.floor(fontSize * lineHeight);
switch (mergedSize) {
case 'large':
return padding * 2 + fontHeight;
case 'middle':
return paddingSM * 2 + fontHeight + lineWidth;
case 'small':
return paddingXS * 2 + fontHeight;
return paddingXS * 2 + fontHeight + lineWidth;
default:
return paddingSM * 2 + fontHeight;
return padding * 2 + fontHeight + lineWidth;
}
}, [token, mergedSize]);

View File

@ -61,6 +61,7 @@
"Amir M. Mohamadi",
"Amorites",
"Amour1688",
"Amumu",
"Anas Tawfeek",
"Andre Perunicic",
"Andre Zyczkowski",
@ -648,6 +649,7 @@
"Maximilian Meyer",
"Mayowa Sogbein",
"Md_ZubairAhmed",
"Mehmet Salih Yavuz",
"MeiLin",
"MengZhaoFly",
"Meow-z",
@ -698,6 +700,7 @@
"Muhammad Sameer",
"Muhammad Sohaib Raza",
"MuxinFeng",
"MyeongHyun Lew",
"Mykyta Velykanov",
"Mário Gonçalves",
"Nariman Movaffaghi",
@ -748,6 +751,8 @@
"Oren Kosto",
"Orkhan Huseynli",
"OuYancey",
"OweQian",
"Oyster Lee",
"PCCCCCCC",
"Pablo Recalde",
"Panjie Setiawan Wicaksono",
@ -822,6 +827,7 @@
"Rodrigo Ehlers",
"Rohan Bagchi",
"Rohan Malhotra",
"Roman Donchenko",
"Roman Soroka",
"Ron Šmeral",
"Rongjian Zhang",
@ -845,6 +851,7 @@
"Sam Lanning",
"Sam Marks",
"Sam Maxwell",
"SamLee",
"Samed Düzçay",
"Sami Mäkinen",
"Samuel Gaus",
@ -1557,7 +1564,6 @@
"yoshinyan",
"youmoo",
"youngz",
"yoyo837",
"yuanliu",
"yuche",
"yuezk",
@ -1681,6 +1687,7 @@
"栗康",
"梓安",
"沐霖",
"火尧",
"炒米粉",
"烽宁",
"爱but的苍蝇",

View File

@ -101,7 +101,13 @@ const miscKeys = [
// Changelog map
const componentChangelog: Record<
string,
{ version: string; changelog: string; refs: string[]; releaseDate: string }[]
{
version: string;
changelog: string;
refs: string[];
releaseDate: string;
contributors: string[];
}[]
> = {};
Object.keys(componentNameMap).forEach((name) => {
componentChangelog[name] = [];
@ -127,6 +133,20 @@ const miscKeys = [
lastReleaseDate = matchReleaseDate[1];
}
// Get Contributor name
const contributors: string[] = [];
const usernameMatches = line.match(/\[@([^\]]+)\]/g);
if (usernameMatches) {
usernameMatches.forEach((match) => {
const usernameMatch = match.match(/\[@([^\]]+)\]/);
if (usernameMatch) {
const username = usernameMatch[1];
contributors.push(username);
}
});
}
// Start when get version
if (!lastVersion) {
continue;
@ -184,6 +204,7 @@ const miscKeys = [
changelog: changelogLine,
refs,
releaseDate: lastReleaseDate,
contributors,
});
matched = true;
}