chore: auto merge branches (#52448)
Some checks failed
Publish Any Commit / build (push) Has been cancelled
🔀 Sync mirror to Gitee / mirror (push) Has been cancelled
✅ test / lint (push) Has been cancelled
✅ test / test-react-legacy (16, 1/2) (push) Has been cancelled
✅ test / test-react-legacy (16, 2/2) (push) Has been cancelled
✅ test / test-react-legacy (17, 1/2) (push) Has been cancelled
✅ test / test-react-legacy (17, 2/2) (push) Has been cancelled
✅ test / test-node (push) Has been cancelled
✅ test / test-react-latest (dom, 1/2) (push) Has been cancelled
✅ test / test-react-latest (dom, 2/2) (push) Has been cancelled
✅ test / build (push) Has been cancelled
✅ test / test lib/es module (es, 1/2) (push) Has been cancelled
✅ test / test lib/es module (es, 2/2) (push) Has been cancelled
✅ test / test lib/es module (lib, 1/2) (push) Has been cancelled
✅ test / test lib/es module (lib, 2/2) (push) Has been cancelled
👁️ Visual Regression Persist Start / test image (push) Has been cancelled
✅ test / test-react-latest-dist (dist, 1/2) (push) Has been cancelled
✅ test / test-react-latest-dist (dist, 2/2) (push) Has been cancelled
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Has been cancelled
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Has been cancelled
✅ test / test-coverage (push) Has been cancelled

chore: sync master to feature
This commit is contained in:
github-actions[bot] 2025-01-17 05:52:10 +00:00 committed by GitHub
commit c0286f1de6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 768 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) => (
<a className={styles.linkRef} key={ref} href={ref} target="_blank" rel="noreferrer">
#{ref.match(/[^/]+$/)?.[0]}
</a>
<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,16 +55,30 @@ jobs:
);
if (daysInactive >= daysBeforeReminder && !hasLinkedPR) {
const assigneesMentions = issue.assignees
.map(user => `@${user.login}`)
.join(' ');
await github.rest.issues.createComment({
// get issue comments
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `${assigneesMentions} 这个 issue 已经超过 14 天没有更新或关联 PR。如果您仍在处理这个 issue请更新进度如果您无法继续处理请联系维护者重新分配。\n\nThis issue has been inactive for more than 14 days without any updates or linked PR. If you are still working on this issue, please provide a progress update. If you are unable to continue, please contact the maintainers for reassignment.`,
});
// 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(' ');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `${assigneesMentions} 这个 issue 已经超过 14 天没有更新或关联 PR。如果您仍在处理这个 issue请更新进度如果您无法继续处理请联系维护者重新分配。\n\nThis issue has been inactive for more than 14 days without any updates or linked PR. If you are still working on this issue, please provide a progress update. If you are unable to continue, please contact the maintainers for reassignment.`,
});
}
}
}

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,42 @@ exports[`renders components/menu/demo/extra-style.tsx extend context correctly 1
/>
</div>
</div>
<li
aria-describedby="test-id"
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"
id="test-id"
role="tooltip"
/>
</div>
</div>
</ul>
</div>
<ul
@ -2026,6 +2062,42 @@ exports[`renders components/menu/demo/extra-style.tsx extend context correctly 1
/>
</div>
</div>
<li
aria-describedby="test-id"
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"
id="test-id"
role="tooltip"
/>
</div>
</div>
</ul>
</li>
</ul>

View File

@ -911,6 +911,23 @@ exports[`renders components/menu/demo/extra-style.tsx correctly 1`] = `
</span>
</span>
</li>
<li
aria-describedby="test-id"
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,116 +1544,97 @@ 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"
style="display: flex; flex-direction: column; gap: 8px;"
>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<div
class="ant-space-item"
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="1"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option A
</span>
</label>
</div>
<div
class="ant-space-item"
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="1"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="2"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option B
</span>
</label>
</div>
<div
class="ant-space-item"
Option A
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="3"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option C
</span>
</label>
</div>
<div
class="ant-space-item"
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="2"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="4"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
More...
</span>
</label>
</div>
</div>
Option B
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="3"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option C
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="4"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
More...
</span>
</label>
</div>
`;

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,116 +1526,97 @@ 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"
style="display:flex;flex-direction:column;gap:8px"
>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<div
class="ant-space-item"
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="1"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option A
</span>
</label>
</div>
<div
class="ant-space-item"
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="1"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="2"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option B
</span>
</label>
</div>
<div
class="ant-space-item"
Option A
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="3"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option C
</span>
</label>
</div>
<div
class="ant-space-item"
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="2"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="4"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
More...
</span>
</label>
</div>
</div>
Option B
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="3"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Option C
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="4"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
More...
</span>
</label>
</div>
`;

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}>
More...
{value === 4 ? <Input style={{ width: 100, marginInlineStart: 10 }} /> : null}
</Radio>
</Space>
</Radio.Group>
<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
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;
}