chore: auto merge branches (#49609)

chore: sync master to feature
This commit is contained in:
github-actions[bot] 2024-06-26 10:10:48 +00:00 committed by GitHub
commit 1b9706f22d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 195 additions and 51 deletions

View File

@ -181,6 +181,26 @@ const RoutesPlugin = (api: IApi) => {
// exclude dynamic route path, to avoid deploy failed by `:id` directory
.filter((f) => !f.path.includes(':'))
.map((file) => {
let globalStyles = '';
// Debug for file content: uncomment this if need check raw out
// const tmpFileName = `_${file.path.replace(/\//g, '-')}`;
// const tmpFilePath = path.join(api.paths.absOutputPath, tmpFileName);
// fs.writeFileSync(tmpFilePath, file.content, 'utf8');
// extract all emotion style tags from body
file.content = file.content.replace(
/<style (data-emotion|data-sandpack)[\S\s]+?<\/style>/g,
(s) => {
globalStyles += s;
return '';
},
);
// insert emotion style tags to head
file.content = file.content.replace('</head>', `${globalStyles}</head>`);
// 1. 提取 antd-style 样式
const styles = extractEmotionStyle(file.content);
@ -197,6 +217,30 @@ const RoutesPlugin = (api: IApi) => {
file.content = addLinkStyle(file.content, cssFile);
});
// Insert antd style to head
const matchRegex = /<style data-type="antd-cssinjs">([\S\s]+?)<\/style>/;
const matchList = file.content.match(matchRegex) || [];
// Init to order the `@layer`
let antdStyle = '@layer global, antd;';
matchList.forEach((text) => {
file.content = file.content.replace(text, '');
antdStyle += text.replace(matchRegex, '$1');
});
const cssFile = writeCSSFile('antd', antdStyle, antdStyle);
file.content = addLinkStyle(file.content, cssFile, true);
// Insert antd cssVar to head
const cssVarMatchRegex = /<style data-type="antd-css-var"[\S\s]+?<\/style>/;
const cssVarMatchList = file.content.match(cssVarMatchRegex) || [];
cssVarMatchList.forEach((text) => {
file.content = file.content.replace(text, '');
file.content = file.content.replace('<head>', `<head>${text}`);
});
return file;
}),
);

View File

@ -30,16 +30,7 @@ const locales = {
// ============================= Style =============================
const useStyle = createStyles(({ token }) => {
const {
antCls,
iconCls,
fontFamily,
fontSize,
headerHeight,
menuItemBorder,
colorPrimary,
colorText,
} = token;
const { antCls, iconCls, fontFamily, fontSize, headerHeight, colorPrimary } = token;
return {
nav: css`
@ -57,25 +48,6 @@ const useStyle = createStyles(({ token }) => {
padding-inline-end: ${token.paddingSM}px;
padding-inline-start: ${token.paddingSM}px;
line-height: ${headerHeight}px;
&::after {
top: 0;
right: 12px;
bottom: auto;
left: 12px;
border-width: ${menuItemBorder}px;
}
a {
color: ${colorText};
}
a:before {
position: absolute;
inset: 0;
background-color: transparent;
content: '';
}
}
& ${antCls}-menu-submenu-title ${iconCls} {

View File

@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- uses: oven-sh/setup-bun@v2
- name: size-limit
uses: ant-design/size-limit-action@master
with:

View File

@ -7,6 +7,7 @@ import { Button, InputNumber, Select } from '../..';
import { resetWarned } from '../../_util/warning';
import { render } from '../../../tests/utils';
import theme from '../../theme';
import type { GlobalToken } from '../../theme';
import { useToken } from '../../theme/internal';
const { defaultAlgorithm, darkAlgorithm, compactAlgorithm } = theme;
@ -32,13 +33,13 @@ describe('ConfigProvider.Theme', () => {
},
});
const styles: any[] = Array.from(document.querySelectorAll('style'));
const styles = Array.from(document.querySelectorAll<HTMLStyleElement>('style'));
const themeStyle = styles.find((style) =>
style.getAttribute('rc-util-key').includes('-dynamic-theme'),
style.getAttribute('rc-util-key')?.includes('-dynamic-theme'),
);
expect(themeStyle).toBeTruthy();
expect(themeStyle.innerHTML).toContain(`--bamboo-${kebabCase(colorName)}: rgb(0, 0, 255)`);
expect(themeStyle?.innerHTML).toContain(`--bamboo-${kebabCase(colorName)}: rgb(0, 0, 255)`);
});
});
@ -62,7 +63,7 @@ describe('ConfigProvider.Theme', () => {
});
it('algorithm should work', () => {
let tokenRef: any;
let tokenRef: Partial<GlobalToken> = {};
const Demo = () => {
const [, token] = useToken();
tokenRef = token;
@ -77,7 +78,7 @@ describe('ConfigProvider.Theme', () => {
});
it('compactAlgorithm should work', () => {
let tokenRef: any;
let tokenRef: Partial<GlobalToken> = {};
const Demo = () => {
const [, token] = useToken();
tokenRef = token;
@ -104,7 +105,7 @@ describe('ConfigProvider.Theme', () => {
});
it('should support algorithm array', () => {
let tokenRef: any;
let tokenRef: Partial<GlobalToken> = {};
const Demo = () => {
const [, token] = useToken();
tokenRef = token;
@ -126,9 +127,9 @@ describe('ConfigProvider.Theme', () => {
<InputNumber />
</ConfigProvider>,
);
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]')).map(
(item) => item?.innerHTML ?? '',
);
const dynamicStyles = Array.from(
document.querySelectorAll<HTMLStyleElement>('style[data-css-hash]'),
).map((item) => item?.innerHTML ?? '');
expect(
dynamicStyles.some(
(style) => style.includes('.ant-input-number') && style.includes('width:50.1234px'),
@ -159,7 +160,7 @@ describe('ConfigProvider.Theme', () => {
});
it('The order does not affect the result', () => {
const tokens = {
const tokens: Record<'a' | 'b', Partial<GlobalToken>> = {
a: {},
b: {},
};
@ -182,7 +183,7 @@ describe('ConfigProvider.Theme', () => {
});
it('theme separated should work', () => {
let tokenRef: any;
let tokenRef: Partial<GlobalToken> = {};
const Demo = () => {
const [, token] = useToken();
tokenRef = token;
@ -200,7 +201,7 @@ describe('ConfigProvider.Theme', () => {
it('theme inherit should not affect hashed and cssVar', () => {
let hashId = 'hashId';
let cssVar;
let cssVar: any;
const Demo = () => {
const [, , hash, , cssVarConfig] = useToken();

View File

@ -4,8 +4,17 @@ import type { ConfigConsumerProps } from '.';
import { ConfigContext } from '.';
import Empty from '../empty';
type ComponentName =
| 'Table'
| 'List'
| 'Select'
| 'TreeSelect'
| 'Cascader'
| 'Transfer'
| 'Mentions';
interface EmptyProps {
componentName?: string;
componentName?: ComponentName;
}
const DefaultRenderEmpty: React.FC<EmptyProps> = (props) => {
@ -29,6 +38,6 @@ const DefaultRenderEmpty: React.FC<EmptyProps> = (props) => {
}
};
export type RenderEmptyHandler = (componentName?: string) => React.ReactNode;
export type RenderEmptyHandler = (componentName?: ComponentName) => React.ReactNode;
export default DefaultRenderEmpty;

View File

@ -59,6 +59,7 @@ const localeValues: Locale = {
selectCurrent: 'เลือกทั้งหมดในหน้านี้',
removeCurrent: 'นำออกทั้งหมดในหน้านี้',
selectAll: 'เลือกข้อมูลทั้งหมด',
deselectAll: 'ยกเลิกการเลือกทั้งหมด',
removeAll: 'นำข้อมูลออกทั้งหมด',
selectInvert: 'กลับสถานะการเลือกในหน้านี้',
},
@ -80,6 +81,7 @@ const localeValues: Locale = {
copy: 'คัดลอก',
copied: 'คัดลอกแล้ว',
expand: 'ขยาย',
collapse: 'ย่อ',
},
Form: {
optional: '(ไม่จำเป็น)',
@ -137,6 +139,10 @@ const localeValues: Locale = {
QRCode: {
expired: 'คิวอาร์โค้ดหมดอายุ',
refresh: 'รีเฟรช',
scanned: 'สแกนแล้ว',
},
ColorPicker: {
presetEmpty: 'ไม่มีข้อมูล',
},
};

View File

@ -547,9 +547,10 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
const mergedStyle: React.CSSProperties = { ...table?.style, ...style };
const emptyText = locale?.emptyText || renderEmpty?.('Table') || (
<DefaultRenderEmpty componentName="Table" />
);
const emptyText =
typeof locale?.emptyText !== 'undefined'
? locale.emptyText
: renderEmpty?.('Table') || <DefaultRenderEmpty componentName="Table" />;
// ========================== Render ==========================
const TableComponent = virtual ? RcVirtualTable : RcTable;

View File

@ -147,6 +147,104 @@ exports[`Table renders empty table 1`] = `
</div>
`;
exports[`Table renders empty table when emptyText is null 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table ant-table-empty"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
scope="col"
>
Column 1
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 2
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 3
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 4
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 5
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 6
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 7
</th>
<th
class="ant-table-cell"
scope="col"
>
Column 8
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-placeholder"
>
<td
class="ant-table-cell"
colspan="8"
/>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Table renders empty table with custom emptyText 1`] = `
<div
class="ant-table-wrapper"

View File

@ -89,6 +89,18 @@ describe('Table', () => {
});
});
it('renders empty table when emptyText is null', () => {
const { container, asFragment } = render(
<Table dataSource={[]} columns={columns} pagination={false} locale={{ emptyText: null }} />,
);
expect(container.querySelector('.ant-table-placeholder>.ant-table-cell')?.hasChildNodes()).toBe(
false,
);
expect(asFragment().firstChild).toMatchSnapshot();
});
it('renders empty table with custom emptyText', () => {
const { asFragment } = render(
<Table

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
import { DndContext, PointerSensor, closestCenter, useSensor } from '@dnd-kit/core';
import {
arrayMove,
horizontalListSortingStrategy,
@ -69,7 +69,7 @@ const App: React.FC = () => {
<Tabs
items={items}
renderTabBar={(tabBarProps, DefaultTabBar) => (
<DndContext sensors={[sensor]} onDragEnd={onDragEnd}>
<DndContext sensors={[sensor]} onDragEnd={onDragEnd} collisionDetection={closestCenter}>
<SortableContext items={items.map((i) => i.key)} strategy={horizontalListSortingStrategy}>
<DefaultTabBar {...tabBarProps}>
{(node) => (

View File

@ -63,11 +63,12 @@ const InternalUploadList: React.ForwardRefRenderFunction<UploadListRef, UploadLi
typeof window === 'undefined' ||
!(window as any).FileReader ||
!(window as any).File ||
!(file.originFileObj instanceof File || file.originFileObj) ||
!(file.originFileObj instanceof File || (file.originFileObj as any) instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
file.thumbUrl = '';
if (previewFile) {
previewFile(file.originFileObj as File).then((previewDataUrl: string) => {
// Need append '' to avoid dead loop

View File

@ -25,7 +25,7 @@ $ cd demo
$ npm run dev
```
此时访问浏览器 http://localhost:3000看到 `Rsbuild with React` 的界面就算成功了。
此时访问浏览器 http://localhost:3000 ,看到 `Rsbuild with React` 的界面就算成功了。
## 引入 antd