mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
commit
7c21018f4f
@ -1,8 +1,10 @@
|
||||
.demo-logo {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
height: 32px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 6px;
|
||||
margin-inline-end: 24px;
|
||||
}
|
||||
|
||||
.demo-logo-vertical {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import SourceCode from 'dumi/theme-default/builtins/SourceCode';
|
||||
import React from 'react';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { ConfigProvider, Tabs } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import SourceCode from 'dumi/theme-default/builtins/SourceCode';
|
||||
import type { Tab } from 'rc-tabs/lib/interface';
|
||||
|
||||
import NpmLogo from './npm';
|
||||
import PnpmLogo from './pnpm';
|
||||
import YarnLogo from './yarn';
|
||||
@ -13,68 +13,31 @@ interface InstallProps {
|
||||
pnpm?: string;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
packageManager: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
svg {
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const InstallDependencies: React.FC<InstallProps> = (props) => {
|
||||
const { npm, yarn, pnpm } = props;
|
||||
const { styles } = useStyle();
|
||||
|
||||
const items = React.useMemo<TabsProps['items']>(
|
||||
() =>
|
||||
[
|
||||
{
|
||||
key: 'npm',
|
||||
children: npm ? <SourceCode lang="bash">{npm}</SourceCode> : null,
|
||||
label: (
|
||||
<div className={styles.packageManager}>
|
||||
<NpmLogo />
|
||||
<span>npm</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'yarn',
|
||||
children: yarn ? <SourceCode lang="bash">{yarn}</SourceCode> : null,
|
||||
label: (
|
||||
<div className={styles.packageManager}>
|
||||
<YarnLogo />
|
||||
<span>yarn</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'pnpm',
|
||||
children: pnpm ? <SourceCode lang="bash">{pnpm}</SourceCode> : null,
|
||||
label: (
|
||||
<div className={styles.packageManager}>
|
||||
<PnpmLogo />
|
||||
<span>pnpm</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
].filter((item) => item.children),
|
||||
[npm, yarn, pnpm],
|
||||
);
|
||||
const items: Tab[] = [
|
||||
{
|
||||
key: 'npm',
|
||||
label: 'npm',
|
||||
children: npm ? <SourceCode lang="bash">{npm}</SourceCode> : null,
|
||||
icon: <NpmLogo />,
|
||||
},
|
||||
{
|
||||
key: 'yarn',
|
||||
label: 'yarn',
|
||||
children: yarn ? <SourceCode lang="bash">{yarn}</SourceCode> : null,
|
||||
icon: <YarnLogo />,
|
||||
},
|
||||
{
|
||||
key: 'pnpm',
|
||||
label: 'pnpm',
|
||||
children: pnpm ? <SourceCode lang="bash">{pnpm}</SourceCode> : null,
|
||||
icon: <PnpmLogo />,
|
||||
},
|
||||
].filter((item) => item.children);
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Tabs: {
|
||||
horizontalMargin: '0',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConfigProvider theme={{ components: { Tabs: { horizontalMargin: '0' } } }}>
|
||||
<Tabs className="markdown" size="small" defaultActiveKey="npm" items={items} />
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
@ -1,26 +1,39 @@
|
||||
import React from 'react';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
iconWrap: css`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
vertical-align: -0.125em;
|
||||
`,
|
||||
}));
|
||||
|
||||
const NpmIcon: React.FC<IconProps> = (props) => {
|
||||
const { className, style } = props;
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
style={style}
|
||||
fill="#E53E3E"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
stroke="#E53E3E"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 16 16"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M0 0v16h16v-16h-16zM13 13h-2v-8h-3v8h-5v-10h10v10z" />
|
||||
</svg>
|
||||
<span className={classNames(styles.iconWrap, className)} style={style}>
|
||||
<svg
|
||||
fill="#E53E3E"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
stroke="#E53E3E"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 16 16"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M0 0v16h16v-16h-16zM13 13h-2v-8h-3v8h-5v-10h10v10z" />
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,28 +1,41 @@
|
||||
import React from 'react';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
iconWrap: css`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
vertical-align: -0.125em;
|
||||
`,
|
||||
}));
|
||||
|
||||
const PnpmIcon: React.FC<IconProps> = (props) => {
|
||||
const { className, style } = props;
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
style={style}
|
||||
aria-hidden="true"
|
||||
fill="#F69220"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="img"
|
||||
stroke="#F69220"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" />
|
||||
</svg>
|
||||
<span className={classNames(styles.iconWrap, className)} style={style}>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="#F69220"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="img"
|
||||
stroke="#F69220"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" />
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,27 +1,40 @@
|
||||
import React from 'react';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
iconWrap: css`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
vertical-align: -0.125em;
|
||||
`,
|
||||
}));
|
||||
|
||||
const YarnIcon: React.FC<IconProps> = (props) => {
|
||||
const { className, style } = props;
|
||||
const { styles } = useStyle();
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
style={style}
|
||||
aria-hidden="true"
|
||||
fill="#2C8EBB"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
stroke="#2C8EBB"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 496 512"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M393.9 345.2c-39 9.3-48.4 32.1-104 47.4 0 0-2.7 4-10.4 5.8-13.4 3.3-63.9 6-68.5 6.1-12.4.1-19.9-3.2-22-8.2-6.4-15.3 9.2-22 9.2-22-8.1-5-9-9.9-9.8-8.1-2.4 5.8-3.6 20.1-10.1 26.5-8.8 8.9-25.5 5.9-35.3.8-10.8-5.7.8-19.2.8-19.2s-5.8 3.4-10.5-3.6c-6-9.3-17.1-37.3 11.5-62-1.3-10.1-4.6-53.7 40.6-85.6 0 0-20.6-22.8-12.9-43.3 5-13.4 7-13.3 8.6-13.9 5.7-2.2 11.3-4.6 15.4-9.1 20.6-22.2 46.8-18 46.8-18s12.4-37.8 23.9-30.4c3.5 2.3 16.3 30.6 16.3 30.6s13.6-7.9 15.1-5c8.2 16 9.2 46.5 5.6 65.1-6.1 30.6-21.4 47.1-27.6 57.5-1.4 2.4 16.5 10 27.8 41.3 10.4 28.6 1.1 52.7 2.8 55.3.8 1.4 13.7.8 36.4-13.2 12.8-7.9 28.1-16.9 45.4-17 16.7-.5 17.6 19.2 4.9 22.2zM496 256c0 136.9-111.1 248-248 248S0 392.9 0 256 111.1 8 248 8s248 111.1 248 248zm-79.3 75.2c-1.7-13.6-13.2-23-28-22.8-22 .3-40.5 11.7-52.8 19.2-4.8 3-8.9 5.2-12.4 6.8 3.1-44.5-22.5-73.1-28.7-79.4 7.8-11.3 18.4-27.8 23.4-53.2 4.3-21.7 3-55.5-6.9-74.5-1.6-3.1-7.4-11.2-21-7.4-9.7-20-13-22.1-15.6-23.8-1.1-.7-23.6-16.4-41.4 28-12.2.9-31.3 5.3-47.5 22.8-2 2.2-5.9 3.8-10.1 5.4h.1c-8.4 3-12.3 9.9-16.9 22.3-6.5 17.4.2 34.6 6.8 45.7-17.8 15.9-37 39.8-35.7 82.5-34 36-11.8 73-5.6 79.6-1.6 11.1 3.7 19.4 12 23.8 12.6 6.7 30.3 9.6 43.9 2.8 4.9 5.2 13.8 10.1 30 10.1 6.8 0 58-2.9 72.6-6.5 6.8-1.6 11.5-4.5 14.6-7.1 9.8-3.1 36.8-12.3 62.2-28.7 18-11.7 24.2-14.2 37.6-17.4 12.9-3.2 21-15.1 19.4-28.2z" />
|
||||
</svg>
|
||||
<span className={classNames(styles.iconWrap, className)} style={style}>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="#2C8EBB"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
stroke="#2C8EBB"
|
||||
strokeWidth="0"
|
||||
viewBox="0 0 496 512"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M393.9 345.2c-39 9.3-48.4 32.1-104 47.4 0 0-2.7 4-10.4 5.8-13.4 3.3-63.9 6-68.5 6.1-12.4.1-19.9-3.2-22-8.2-6.4-15.3 9.2-22 9.2-22-8.1-5-9-9.9-9.8-8.1-2.4 5.8-3.6 20.1-10.1 26.5-8.8 8.9-25.5 5.9-35.3.8-10.8-5.7.8-19.2.8-19.2s-5.8 3.4-10.5-3.6c-6-9.3-17.1-37.3 11.5-62-1.3-10.1-4.6-53.7 40.6-85.6 0 0-20.6-22.8-12.9-43.3 5-13.4 7-13.3 8.6-13.9 5.7-2.2 11.3-4.6 15.4-9.1 20.6-22.2 46.8-18 46.8-18s12.4-37.8 23.9-30.4c3.5 2.3 16.3 30.6 16.3 30.6s13.6-7.9 15.1-5c8.2 16 9.2 46.5 5.6 65.1-6.1 30.6-21.4 47.1-27.6 57.5-1.4 2.4 16.5 10 27.8 41.3 10.4 28.6 1.1 52.7 2.8 55.3.8 1.4 13.7.8 36.4-13.2 12.8-7.9 28.1-16.9 45.4-17 16.7-.5 17.6 19.2 4.9 22.2zM496 256c0 136.9-111.1 248-248 248S0 392.9 0 256 111.1 8 248 8s248 111.1 248 248zm-79.3 75.2c-1.7-13.6-13.2-23-28-22.8-22 .3-40.5 11.7-52.8 19.2-4.8 3-8.9 5.2-12.4 6.8 3.1-44.5-22.5-73.1-28.7-79.4 7.8-11.3 18.4-27.8 23.4-53.2 4.3-21.7 3-55.5-6.9-74.5-1.6-3.1-7.4-11.2-21-7.4-9.7-20-13-22.1-15.6-23.8-1.1-.7-23.6-16.4-41.4 28-12.2.9-31.3 5.3-47.5 22.8-2 2.2-5.9 3.8-10.1 5.4h.1c-8.4 3-12.3 9.9-16.9 22.3-6.5 17.4.2 34.6 6.8 45.7-17.8 15.9-37 39.8-35.7 82.5-34 36-11.8 73-5.6 79.6-1.6 11.1 3.7 19.4 12 23.8 12.6 6.7 30.3 9.6 43.9 2.8 4.9 5.2 13.8 10.1 30 10.1 6.8 0 58-2.9 72.6-6.5 6.8-1.6 11.5-4.5 14.6-7.1 9.8-3.1 36.8-12.3 62.2-28.7 18-11.7 24.2-14.2 37.6-17.4 12.9-3.2 21-15.1 19.4-28.2z" />
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -26,7 +26,7 @@ const GlobalDemoStyles: React.FC = () => {
|
||||
margin: 0 0 16px;
|
||||
background-color: ${token.colorBgContainer};
|
||||
border: 1px solid ${token.colorSplit};
|
||||
border-radius: ${token.borderRadius}px;
|
||||
border-radius: ${token.borderRadiusLG}px;
|
||||
transition: all 0.2s;
|
||||
|
||||
.code-box-title {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { CodeOutlined, SkinOutlined } from '@ant-design/icons';
|
||||
import { Tabs } from 'antd';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import type { IContentTabsProps } from 'dumi/theme-default/slots/ContentTabs';
|
||||
import type { TabsProps } from 'rc-tabs';
|
||||
import { Tabs } from 'antd';
|
||||
|
||||
const titleMap: Record<string, string> = {
|
||||
const titleMap: Record<string, ReactNode> = {
|
||||
design: '设计',
|
||||
};
|
||||
|
||||
@ -23,24 +23,17 @@ const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
label: (
|
||||
<span>
|
||||
<CodeOutlined />
|
||||
开发
|
||||
</span>
|
||||
),
|
||||
key: 'development',
|
||||
label: '开发',
|
||||
icon: <CodeOutlined />,
|
||||
},
|
||||
];
|
||||
|
||||
tabs?.forEach((tab) => {
|
||||
items.push({
|
||||
label: (
|
||||
<span>
|
||||
{iconMap[tab.key]}
|
||||
{titleMap[tab.key]}
|
||||
</span>
|
||||
),
|
||||
key: tab.key,
|
||||
label: titleMap[tab.key],
|
||||
icon: iconMap[tab.key],
|
||||
});
|
||||
});
|
||||
|
||||
@ -48,7 +41,7 @@ const ContentTabs: FC<IContentTabsProps> = ({ tabs, tabKey, onChange }) => {
|
||||
<Tabs
|
||||
items={items}
|
||||
activeKey={tabKey || 'development'}
|
||||
onChange={(key) => onChange(tabs.find((tab) => tab.key === key))}
|
||||
onChange={(key) => onChange(tabs?.find((tab) => tab.key === key))}
|
||||
style={{ margin: '32px 0 -16px' }}
|
||||
/>
|
||||
);
|
||||
|
111
.github/workflows/visual-regression-diff-build.yml
vendored
Normal file
111
.github/workflows/visual-regression-diff-build.yml
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
# Each PR will visual-regression diff that help to check code is work as expect.
|
||||
|
||||
name: 👀 Visual Regression Diff Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, feature]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
# Cancel prev CI if new commit come
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Prepare node modules. Reuse cache if available
|
||||
setup:
|
||||
name: prepare node_modules
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: create package-lock.json
|
||||
run: npm i --package-lock-only --ignore-scripts
|
||||
|
||||
- name: hack for single file
|
||||
run: |
|
||||
if [ ! -d "package-temp-dir" ]; then
|
||||
mkdir package-temp-dir
|
||||
fi
|
||||
cp package-lock.json package-temp-dir
|
||||
|
||||
- name: cache node_modules
|
||||
id: node_modules_cache_id
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
||||
- name: install
|
||||
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
|
||||
run: npm ci
|
||||
|
||||
visual-diff-report:
|
||||
name: visual-diff report
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: restore cache from package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- name: restore cache from node_modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules
|
||||
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}
|
||||
|
||||
- name: generate image snapshots
|
||||
id: test-image
|
||||
run: |
|
||||
node node_modules/puppeteer/install.mjs
|
||||
npm run version
|
||||
npm run test-image
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
|
||||
# Execute visual regression diff task and zip then
|
||||
# output as visualRegressionReport.tar.gz
|
||||
- name: visual regression diff
|
||||
run: |
|
||||
npm run visual-regression -- --pr-id=${{ github.event.number }}
|
||||
|
||||
# Upload report in `visualRegressionReport`
|
||||
- name: upload report artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: visual-regression-report
|
||||
path: visualRegressionReport.tar.gz
|
||||
|
||||
# Upload git ref for next workflow `visual-regression-diff-finish` use
|
||||
- name: Save persist key
|
||||
if: ${{ always() }}
|
||||
# should be pr id
|
||||
run: echo ${{ github.event.number }} > ./visual-regression-pr-id.txt
|
||||
|
||||
- name: Upload persist key
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: visual-regression-diff-ref
|
||||
path: ./visual-regression-pr-id.txt
|
131
.github/workflows/visual-regression-diff-finish.yml
vendored
Normal file
131
.github/workflows/visual-regression-diff-finish.yml
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
# Each PR will visual-regression diff that help to check code is work as expect.
|
||||
|
||||
name: 👀 Visual Regression Diff Finish
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["👀 Visual Regression Diff Build"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
upstream-workflow-summary:
|
||||
name: upstream workflow summary
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
jobs: ${{ steps.visual_diff_build_job_status.outputs.result }}
|
||||
build-success: ${{ steps.visual_diff_build_job_status.outputs.build-success }}
|
||||
build-failure: ${{ steps.visual_diff_build_job_status.outputs.build-failure }}
|
||||
steps:
|
||||
- name: summary jobs status
|
||||
uses: actions/github-script@v6
|
||||
id: visual_diff_build_job_status
|
||||
with:
|
||||
script: |
|
||||
const response = await github.rest.actions.listJobsForWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: ${{ github.event.workflow_run.id }},
|
||||
});
|
||||
|
||||
// { [name]: [conclusion] }, e.g. { 'test image': 'success' }
|
||||
const jobs = (response.data?.jobs ?? []).reduce((acc, job) => {
|
||||
if(job?.status === 'completed' && 'name' in job && 'conclusion' in job) {
|
||||
acc[job.name] = job.conclusion;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['visual-diff report']);
|
||||
|
||||
// set output
|
||||
core.setOutput('build-success', jobs['visual-diff report'] === 'success');
|
||||
core.setOutput('build-failure', jobs['visual-diff report'] === 'failure');
|
||||
return jobs;
|
||||
|
||||
download-visual-regression-report:
|
||||
name: download visual-regression report
|
||||
permissions:
|
||||
actions: read # for dawidd6/action-download-artifact to query and download artifacts
|
||||
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
|
||||
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
|
||||
runs-on: ubuntu-latest
|
||||
needs: [upstream-workflow-summary]
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# We need get persist-index first
|
||||
- name: download image snapshot artifact
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: visual-regression-diff-ref
|
||||
|
||||
# Save PR id to output
|
||||
- name: save PR id
|
||||
id: pr
|
||||
run: echo "id=$(<visual-regression-pr-id.txt)" >> $GITHUB_OUTPUT
|
||||
|
||||
# Download report artifact
|
||||
- name: download report artifact
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }}
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: visual-regression-report
|
||||
|
||||
# unzip report and then upload them to oss
|
||||
- name: upload visual-regression report
|
||||
id: report
|
||||
env:
|
||||
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
|
||||
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
|
||||
run: |
|
||||
mkdir ./visualRegressionReport
|
||||
tar -xzvf visualRegressionReport.tar.gz -C ./visualRegressionReport
|
||||
echo "✅ Uncompress Finished"
|
||||
|
||||
rm package.json
|
||||
npm i ali-oss --no-save
|
||||
echo "✅ Install `ali-oss` Finished"
|
||||
|
||||
echo "🤖 Uploading"
|
||||
node scripts/visual-regression/upload.js ./visualRegressionReport --ref=pr-${{ steps.pr.outputs.id }}
|
||||
echo "✅ Uploaded"
|
||||
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "content<<${delimiter}" >> "${GITHUB_OUTPUT}"
|
||||
echo "$(<visualRegressionReport/report.md)" >> "${GITHUB_OUTPUT}"
|
||||
echo "${delimiter}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: success comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
if: ${{ steps.report.outcome == 'success' }}
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
${{ steps.report.outputs.content }}
|
||||
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
|
||||
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
|
||||
number: ${{ steps.pr.outputs.id }}
|
||||
|
||||
- name: failed comment
|
||||
if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-failure) || steps.report.outcome == 'failure' || failure() }}
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
## Visual-Regression Diff Failed
|
||||
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
|
||||
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
|
||||
number: ${{ steps.pr.outputs.id }}
|
32
.github/workflows/visual-regression-diff-start.yml
vendored
Normal file
32
.github/workflows/visual-regression-diff-start.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# When `visual-regression-diff-build` start. Leave a message on the PR
|
||||
#
|
||||
# 🚨🚨🚨 Important 🚨🚨🚨
|
||||
# Never do any `checkout` or `npm install` action!
|
||||
# `pull_request_target` will enable PR to access the secrets!
|
||||
|
||||
name: 👀 Visual Regression Diff Start
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, feature]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
visual-regression-diff-start:
|
||||
permissions:
|
||||
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
|
||||
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
|
||||
name: start visual-regression diff
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: update status comment
|
||||
uses: actions-cool/maintain-one-comment@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
## Visual-Regression Diff Building...
|
||||
<!-- VISUAL_DIFF_REGRESSION_HOOK -->
|
||||
body-include: '<!-- VISUAL_DIFF_REGRESSION_HOOK -->'
|
@ -24,7 +24,6 @@ jobs:
|
||||
uses: actions/github-script@v6
|
||||
id: persist_start_job_status
|
||||
with:
|
||||
# todo: split it out as github actions
|
||||
script: |
|
||||
const response = await github.rest.actions.listJobsForWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
@ -43,7 +42,9 @@ jobs:
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}` in preview-build.yml
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['test image']);
|
||||
|
||||
// set output
|
||||
core.setOutput('build-success', jobs['test image'] === 'success');
|
||||
core.setOutput('build-failure', jobs['test image'] === 'failure');
|
||||
@ -69,7 +70,7 @@ jobs:
|
||||
|
||||
# Save visual-regression ref to output
|
||||
- name: Extra Visual Regression Ref
|
||||
id: visuall-regression
|
||||
id: visual_regression
|
||||
run: echo "id=$(<visual-regression-ref.txt)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download Visual-Regression Artifact
|
||||
@ -88,13 +89,13 @@ jobs:
|
||||
env:
|
||||
ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }}
|
||||
ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }}
|
||||
ALI_OSS_BUCKET: ${{ secrets.ALI_OSS_BUCKET }}
|
||||
run: |
|
||||
rm package.json
|
||||
npm i ali-oss --no-save
|
||||
echo "✅ Install `ali-oss` Finished"
|
||||
|
||||
echo "🤖 Uploading"
|
||||
node scripts/visual-regression-upload.js ./imageSnapshots.tar.gz --ref=${{ github.sha }}
|
||||
node scripts/visual-regression-upload.js ./visual-regression-ref.txt --ref=${{ github.ref_name }}
|
||||
node scripts/visual-regression/upload.js ./imageSnapshots.tar.gz --ref=${{ github.sha }}
|
||||
node scripts/visual-regression/upload.js ./visual-regression-ref.txt --ref=${{ github.ref_name }}
|
||||
|
||||
echo "✅ Uploaded"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -63,6 +63,7 @@ __image_snapshots__/
|
||||
/jest-stare
|
||||
/imageSnapshots*
|
||||
/imageDiffSnapshots
|
||||
/visualRegressionReport*
|
||||
|
||||
.devcontainer*
|
||||
.husky/prepare-commit-msg
|
||||
|
@ -16,6 +16,20 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.12.2
|
||||
|
||||
`2023-12-11`
|
||||
|
||||
- 🐞 MISC: Fix `useId` error when webpack build with React 17. [#46261](https://github.com/ant-design/ant-design/pull/46261)
|
||||
- Pagination
|
||||
- 🐞 Fix Pagination throws error in legacy browsers. [react-component/pagination#545](https://github.com/react-component/pagination/pull/545)
|
||||
- 🐞 Fix Pagination `current` not working in `simple` mode. [react-component/pagination#546](https://github.com/react-component/pagination/pull/546)
|
||||
- 🐞 Fix Table filter dropdown lost background color in CSS variables mode. [#46314](https://github.com/ant-design/ant-design/pull/46314)
|
||||
- 🐞 Prevent interaction when Spin component enable `fullscreen` prop. [#46303](https://github.com/ant-design/ant-design/pull/46303) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 Fix Form `hideRequiredMark` prop's priority compared with ConfigProvider `form` prop. [#46299](https://github.com/ant-design/ant-design/pull/46299) [@linhf123](https://github.com/linhf123)
|
||||
- TypeScript
|
||||
- 🤖 Fix Descriptions `id` type. [#46367](https://github.com/ant-design/ant-design/pull/46367) [@RSS1102](https://github.com/RSS1102)
|
||||
|
||||
## 5.12.1
|
||||
|
||||
`2023-12-04`
|
||||
|
@ -16,6 +16,20 @@ tag: vVERSION
|
||||
|
||||
---
|
||||
|
||||
## 5.12.2
|
||||
|
||||
`2023-12-11`
|
||||
|
||||
- 🐞 MISC: 修复 React 17 以下使用 webpack 构建时报错 `useId` 找不到的问题。[#46261](https://github.com/ant-design/ant-design/pull/46261)
|
||||
- Pagination
|
||||
- 🐞 修复 Pagination 在低版本浏览器上报错的问题。[react-component/pagination#545](https://github.com/react-component/pagination/pull/545)
|
||||
- 🐞 修复 Pagination `simple` 模式下 `current` 受控选中分页不生效的问题。[react-component/pagination#546](https://github.com/react-component/pagination/pull/546)
|
||||
- 🐞 修复 Table 筛选菜单在 CSS 变量模式下丢失背景色的问题。[#46314](https://github.com/ant-design/ant-design/pull/46314)
|
||||
- 🐞 优化 Spin 交互,全屏状态时禁止用户触发鼠标事件。[#46303](https://github.com/ant-design/ant-design/pull/46303) [@li-jia-nan](https://github.com/li-jia-nan)
|
||||
- 🐞 修复 Form `hideRequiredMark` 属性的优先级低于 ConfigProvider 的 form 配置的问题。[#46299](https://github.com/ant-design/ant-design/pull/46299) [@linhf123](https://github.com/linhf123)
|
||||
- TypeScript
|
||||
- 🤖 修复 Descriptions TS 定义不支持 `id` 属性的问题。[#46367](https://github.com/ant-design/ant-design/pull/46367) [@RSS1102](https://github.com/RSS1102)
|
||||
|
||||
## 5.12.1
|
||||
|
||||
`2023-12-04`
|
||||
|
@ -1,20 +1,29 @@
|
||||
<p align="center">
|
||||
<a href="https://ant.design">
|
||||
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
</a>
|
||||
</p>
|
||||
<div align="center"><a name="readme-top"></a>
|
||||
|
||||
<h1 align="center">Ant Design</h1>
|
||||
<img height="180" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
|
||||
<div align="center">
|
||||
<h1>Ant Design</h1>
|
||||
|
||||
一套企业级 UI 设计语言和 React 组件库。
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
[![CI status][github-action-image]][github-action-url]
|
||||
[![codecov][codecov-image]][codecov-url]
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url]
|
||||
[![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url]
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url]
|
||||
[![][issues-helper-image]][issues-helper-url]
|
||||
[![dumi][dumi-image]][dumi-url]
|
||||
[![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[Changelog](./CHANGELOG-zh-CN.md) · [Report Bug][github-issues-url] · [Request Feature][github-issues-url] · [English](./README.md) · 中文
|
||||
|
||||
![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@ -34,19 +43,29 @@
|
||||
[unpkg-js-url]: https://unpkg.com/browse/antd/dist/antd.min.js
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/antd?style=flat-square
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/antd
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-actions--cool-blue?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool
|
||||
[renovate-image]: https://img.shields.io/badge/renovate-enabled-brightgreen.svg?style=flat-square
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
[github-issues-url]: https://new-issue.ant.design
|
||||
|
||||
<!-- Copy-paste in your Readme.md file -->
|
||||
|
||||
<a href="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats?repo_id=34526884" target="_blank" style="display: block" align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=dark" width="655" height="auto">
|
||||
<img alt="Performance Stats of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-last-28-days-stats/thumbnail.png?repo_id=34526884&image_size=auto&color_scheme=light" width="655" height="auto">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
|
||||
|
||||
</div>
|
||||
|
||||
[![](https://user-images.githubusercontent.com/507615/209472919-6f7e8561-be8c-4b0b-9976-eb3c692aa20a.png)](https://ant.design)
|
||||
|
||||
[English](./README.md) | 中文
|
||||
|
||||
## ✨ 特性
|
||||
|
||||
- 🌈 提炼自企业级中后台产品的交互语言和视觉风格。
|
||||
@ -152,6 +171,19 @@ $ npm start
|
||||
|
||||
## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
|
||||
|
||||
ome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
|
||||
|
||||
<!-- Copy-paste in your Readme.md file -->
|
||||
|
||||
<a href="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors?repo_id=34526884&limit=30" target="_blank" style="display: block" align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=dark" width="655" height="auto">
|
||||
<img alt="Active Contributors of ant-design/ant-design - Last 28 days" src="https://next.ossinsight.io/widgets/official/compose-recent-active-contributors/thumbnail.png?repo_id=34526884&limit=30&image_size=auto&color_scheme=light" width="655" height="auto">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
<!-- Made with [OSS Insight](https://ossinsight.io/) -->
|
||||
|
||||
请参考[贡献指南](https://ant.design/docs/react/contributing-cn).
|
||||
|
||||
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。
|
||||
|
32
README.md
32
README.md
@ -1,20 +1,29 @@
|
||||
<p align="center">
|
||||
<a href="https://ant.design">
|
||||
<img width="200" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
</a>
|
||||
</p>
|
||||
<div align="center"><a name="readme-top"></a>
|
||||
|
||||
<h1 align="center">Ant Design</h1>
|
||||
<img height="180" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
|
||||
|
||||
<div align="center">
|
||||
<h1>Ant Design</h1>
|
||||
|
||||
An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![CI status][github-action-image]][github-action-url] [![codecov][codecov-image]][codecov-url] [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
[![CI status][github-action-image]][github-action-url]
|
||||
[![codecov][codecov-image]][codecov-url]
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![][bundlephobia-image]][bundlephobia-url] [![][bundlesize-js-image]][unpkg-js-url] [![FOSSA Status][fossa-image]][fossa-url]
|
||||
[![][bundlephobia-image]][bundlephobia-url]
|
||||
[![][bundlesize-js-image]][unpkg-js-url]
|
||||
[![FOSSA Status][fossa-image]][fossa-url]
|
||||
|
||||
[![Follow Twitter][twitter-image]][twitter-url] [![Renovate status][renovate-image]][renovate-dashboard-url] [![][issues-helper-image]][issues-helper-url] [![dumi][dumi-image]][dumi-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![Follow Twitter][twitter-image]][twitter-url]
|
||||
[![Renovate status][renovate-image]][renovate-dashboard-url]
|
||||
[![][issues-helper-image]][issues-helper-url]
|
||||
[![dumi][dumi-image]][dumi-url]
|
||||
[![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[更新日志](./CHANGELOG.en-US.md) · [报告问题][github-issues-url] · [特性需求][github-issues-url] · English | [中文](./README-zh_CN.md)
|
||||
|
||||
![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/antd.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/antd
|
||||
@ -40,6 +49,7 @@ An enterprise-class UI design language and React UI library.
|
||||
[renovate-dashboard-url]: https://github.com/ant-design/ant-design/issues/32498
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
[github-issues-url]: https://new-issue.ant.design
|
||||
|
||||
<!-- Copy-paste in your Readme.md file -->
|
||||
|
||||
@ -56,8 +66,6 @@ An enterprise-class UI design language and React UI library.
|
||||
|
||||
[![](https://user-images.githubusercontent.com/507615/209472919-6f7e8561-be8c-4b0b-9976-eb3c692aa20a.png)](https://ant.design)
|
||||
|
||||
English | [中文](./README-zh_CN.md)
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🌈 Enterprise-class UI designed for web applications.
|
||||
|
@ -1 +0,0 @@
|
||||
# antd-image-snapshots
|
@ -1,22 +1,15 @@
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import * as React from 'react';
|
||||
import ConfigProvider, { ConfigContext } from '../config-provider';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
|
||||
export function withPureRenderTheme(Component: any) {
|
||||
return function PureRenderThemeComponent(props: any) {
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
motion: false,
|
||||
zIndexPopupBase: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Component {...props} />
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
import ConfigProvider, { ConfigContext } from '../config-provider';
|
||||
import type { AnyObject } from './type';
|
||||
|
||||
export function withPureRenderTheme<T extends AnyObject = AnyObject>(Component: React.FC<T>) {
|
||||
return (props: T) => (
|
||||
<ConfigProvider theme={{ token: { motion: false, zIndexPopupBase: 0 } }}>
|
||||
<Component {...props} />
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export interface BaseProps {
|
||||
@ -25,15 +18,15 @@ export interface BaseProps {
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export default function genPurePanel<ComponentProps extends BaseProps>(
|
||||
const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
|
||||
Component: any,
|
||||
defaultPrefixCls?: string,
|
||||
getDropdownCls?: null | ((prefixCls: string) => string),
|
||||
postProps?: (props: ComponentProps) => ComponentProps,
|
||||
) {
|
||||
type WrapProps = Omit<ComponentProps, 'open' | 'visible'> & { open?: boolean };
|
||||
) => {
|
||||
type WrapProps = ComponentProps & AnyObject;
|
||||
|
||||
function PurePanel(props: WrapProps) {
|
||||
const PurePanel: React.FC<WrapProps> = (props) => {
|
||||
const { prefixCls: customizePrefixCls, style } = props;
|
||||
|
||||
const holderRef = React.useRef<HTMLDivElement>(null);
|
||||
@ -88,22 +81,21 @@ export default function genPurePanel<ComponentProps extends BaseProps>(
|
||||
};
|
||||
|
||||
if (postProps) {
|
||||
mergedProps = postProps(mergedProps as ComponentProps);
|
||||
mergedProps = postProps(mergedProps);
|
||||
}
|
||||
|
||||
const mergedStyle: React.CSSProperties = {
|
||||
paddingBottom: popupHeight,
|
||||
position: 'relative',
|
||||
minWidth: popupWidth,
|
||||
};
|
||||
return (
|
||||
<div
|
||||
ref={holderRef}
|
||||
style={{
|
||||
paddingBottom: popupHeight,
|
||||
position: 'relative',
|
||||
minWidth: popupWidth,
|
||||
}}
|
||||
>
|
||||
<div ref={holderRef} style={mergedStyle}>
|
||||
<Component {...mergedProps} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return withPureRenderTheme(PurePanel);
|
||||
}
|
||||
return withPureRenderTheme<AnyObject>(PurePanel);
|
||||
};
|
||||
|
||||
export default genPurePanel;
|
||||
|
@ -1,7 +1,7 @@
|
||||
type RecordType = Record<string, any>;
|
||||
import type { AnyObject } from './type';
|
||||
|
||||
function extendsObject<T extends RecordType>(...list: T[]) {
|
||||
const result: RecordType = { ...list[0] };
|
||||
const extendsObject = <T extends AnyObject = AnyObject>(...list: T[]) => {
|
||||
const result: AnyObject = { ...list[0] };
|
||||
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
const obj = list[i];
|
||||
@ -16,6 +16,6 @@ function extendsObject<T extends RecordType>(...list: T[]) {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export default extendsObject;
|
||||
|
@ -9,9 +9,5 @@ export const getRenderPropValue = (
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof propValue === 'function') {
|
||||
return propValue();
|
||||
}
|
||||
|
||||
return propValue;
|
||||
return typeof propValue === 'function' ? propValue() : propValue;
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| --- | --- | --- | --- | --- |
|
||||
| itemRender | Custom item renderer | (route, params, routes, paths) => ReactNode | - | |
|
||||
| params | Routing parameters | object | - | |
|
||||
| items | The routing stack information of router | [items\[\]](#ItemType) | - | 5.3.0 |
|
||||
| items | The routing stack information of router | [ItemType\[\]](#ItemType) | - | 5.3.0 |
|
||||
| separator | Custom separator | ReactNode | `/` | |
|
||||
|
||||
### ItemType
|
||||
|
@ -1,16 +1,19 @@
|
||||
import type { TriggerProps } from '@rc-component/trigger';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import 'dayjs/locale/mk'; // to test local in 'prop locale should works' test case
|
||||
|
||||
import React from 'react';
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
import MockDate from 'mockdate';
|
||||
import dayJsGenerateConfig from 'rc-picker/lib/generate/dayjs';
|
||||
import React from 'react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
|
||||
import DatePicker from '..';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../tests/utils';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import type { PickerLocale } from '../generatePicker';
|
||||
import { closeCircleByRole, expectCloseCircle } from './utils';
|
||||
|
||||
@ -124,6 +127,55 @@ describe('DatePicker', () => {
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showMinute: true, showSecond: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ showMinute: true, showSecond: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[0]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[1]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showHour: true, showMinute: true, showSecond: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ showHour: true, showMinute: true, showSecond: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(3);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[0]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(24);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[1]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[2]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showHour: true, showSecond: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
@ -146,27 +198,69 @@ describe('DatePicker', () => {
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showMinute: true, showSecond: true }}', () => {
|
||||
it('showTime={{ showSecond: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ showMinute: true, showSecond: true }}
|
||||
showTime={{ showSecond: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(1);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[0]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showMinute: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ showMinute: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(1);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[1]
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[0]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it('showTime={{ showHour: true }}', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ showHour: true }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(1);
|
||||
expect(
|
||||
container
|
||||
.querySelectorAll('.ant-picker-time-panel-column')?.[0]
|
||||
.querySelectorAll('.ant-picker-time-panel-cell').length,
|
||||
).toBe(24);
|
||||
});
|
||||
|
||||
it('showTime={{ }} (no true args)', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
defaultValue={dayjs()}
|
||||
showTime={{ }}
|
||||
format="YYYY-MM-DD"
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(0);
|
||||
});
|
||||
|
||||
it('showTime should work correctly when format is custom function', () => {
|
||||
const { container } = render(
|
||||
<DatePicker
|
||||
|
@ -56,6 +56,65 @@ describe('RangePicker', () => {
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('the left selection is before the right selection', () => {
|
||||
let rangePickerValue: dayjs.Dayjs[] = [];
|
||||
const Test: React.FC = () => {
|
||||
const [value, setValue] = useState<RangeValue<dayjs.Dayjs>>(null);
|
||||
return (
|
||||
<RangePicker
|
||||
value={value}
|
||||
mode={['month', 'month']}
|
||||
onPanelChange={(v) => {
|
||||
setValue(v);
|
||||
rangePickerValue = v as dayjs.Dayjs[];
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = render(<Test />);
|
||||
|
||||
openPicker(wrapper);
|
||||
selectCell(wrapper, 'Feb');
|
||||
openPicker(wrapper, 1);
|
||||
selectCell(wrapper, 'May');
|
||||
closePicker(wrapper, 1);
|
||||
|
||||
const [start, end] = rangePickerValue;
|
||||
|
||||
expect(start.isBefore(end, 'date')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('the left selection is after the right selection, no selection made', () => {
|
||||
let rangePickerValue: dayjs.Dayjs[] = [];
|
||||
const Test: React.FC = () => {
|
||||
const [value, setValue] = useState<RangeValue<dayjs.Dayjs>>(null);
|
||||
return (
|
||||
<RangePicker
|
||||
value={value}
|
||||
mode={['month', 'month']}
|
||||
onPanelChange={(v) => {
|
||||
setValue(v);
|
||||
rangePickerValue = v as dayjs.Dayjs[];
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = render(<Test />);
|
||||
|
||||
openPicker(wrapper);
|
||||
selectCell(wrapper, 'May');
|
||||
openPicker(wrapper, 1);
|
||||
selectCell(wrapper, 'Feb');
|
||||
closePicker(wrapper, 1);
|
||||
|
||||
const [start, end] = rangePickerValue;
|
||||
|
||||
expect(start).not.toBeNull();
|
||||
expect(end).toBeNull();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/13302
|
||||
describe('in "month" mode, when the left and right panels select the same month', () => {
|
||||
it('the cell status is correct', () => {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import BehaviorMap from '../../../.dumi/theme/common/BehaviorMap';
|
||||
|
||||
const BehaviorPattern = () => (
|
||||
const BehaviorPattern: React.FC = () => (
|
||||
<BehaviorMap
|
||||
data={{
|
||||
id: '200000004',
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { FC } from 'react';
|
||||
import React from 'react';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import { DatePicker } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classNames from 'classnames';
|
||||
import { DatePicker } from 'antd';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
|
||||
const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
|
||||
|
||||
@ -48,9 +48,9 @@ const useStyle = createStyles(({ token }) => ({
|
||||
}
|
||||
`,
|
||||
minus: css`
|
||||
color: #52C41A80;
|
||||
color: #52c41a80;
|
||||
.ant-picker-cell-in-view & {
|
||||
color: #52C41A;
|
||||
color: #52c41a;
|
||||
}
|
||||
.ant-picker-cell-selected & {
|
||||
color: #fff;
|
||||
|
@ -1,18 +1,17 @@
|
||||
import React from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import { DatePicker } from 'antd';
|
||||
import type { TimeRangePickerProps } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { _InternalRangePanelDoNotUseOrYouWillBeFired: PureRangePicker } = DatePicker;
|
||||
|
||||
const App: React.FC = () => (
|
||||
<PureRangePicker
|
||||
presets={[
|
||||
{ label: 'Last 7 Days', value: [dayjs().add(-7, 'd'), dayjs()] },
|
||||
{ label: 'Last 14 Days', value: [dayjs().add(-14, 'd'), dayjs()] },
|
||||
{ label: 'Last 30 Days', value: [dayjs().add(-30, 'd'), dayjs()] },
|
||||
{ label: 'Last 90 Days', value: [dayjs().add(-90, 'd'), dayjs()] },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
const rangePresets: TimeRangePickerProps['presets'] = [
|
||||
{ label: 'Last 7 Days', value: [dayjs().add(-7, 'd'), dayjs()] },
|
||||
{ label: 'Last 14 Days', value: [dayjs().add(-14, 'd'), dayjs()] },
|
||||
{ label: 'Last 30 Days', value: [dayjs().add(-30, 'd'), dayjs()] },
|
||||
{ label: 'Last 90 Days', value: [dayjs().add(-90, 'd'), dayjs()] },
|
||||
];
|
||||
|
||||
const App: React.FC = () => <PureRangePicker presets={rangePresets} />;
|
||||
|
||||
export default App;
|
||||
|
@ -58,8 +58,7 @@ If there are special needs (only modifying single component language), Please us
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
When use with Nextjs App Router, make sure to add `'use client'` before import locale file of dayjs.
|
||||
It's because all components of Ant Design only works in client, importing locale in RSC will not work.
|
||||
When use with Nextjs App Router, make sure to add `'use client'` before import locale file of dayjs. It's because all components of Ant Design only works in client, importing locale in RSC will not work.
|
||||
:::
|
||||
|
||||
```jsx
|
||||
|
@ -59,8 +59,7 @@ demo:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
在搭配 Nextjs 的 App Router 使用时,注意在引入 dayjs 的 locale 文件时加上 `'use client'`。
|
||||
这是由于 Ant Design 的组件都是客户端组件,在 RSC 中引入 dayjs 的 locale 文件将不会在客户端生效。
|
||||
在搭配 Nextjs 的 App Router 使用时,注意在引入 dayjs 的 locale 文件时加上 `'use client'`。这是由于 Ant Design 的组件都是客户端组件,在 RSC 中引入 dayjs 的 locale 文件将不会在客户端生效。
|
||||
:::
|
||||
|
||||
```jsx
|
||||
|
@ -188,6 +188,16 @@ describe('Descriptions', () => {
|
||||
expect(wrapper.container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('Descriptions support id', () => {
|
||||
const wrapper = render(
|
||||
<Descriptions id="descriptions">
|
||||
<Descriptions.Item>Cloud Database</Descriptions.Item>
|
||||
</Descriptions>,
|
||||
);
|
||||
const descriptionItemsElement = wrapper.container.querySelector('#descriptions');
|
||||
expect(descriptionItemsElement).not.toBeNull();
|
||||
});
|
||||
|
||||
it('keep key', () => {
|
||||
render(
|
||||
<Descriptions>
|
||||
|
@ -47,6 +47,7 @@ export interface DescriptionsProps {
|
||||
labelStyle?: React.CSSProperties;
|
||||
contentStyle?: React.CSSProperties;
|
||||
items?: DescriptionsItemType[];
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const Descriptions: React.FC<DescriptionsProps> & CompoundedComponent = (props) => {
|
||||
|
@ -297,7 +297,7 @@ exports[`renders components/flex/demo/combination.tsx extend context correctly 1
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
Get Start
|
||||
Get Started
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -293,7 +293,7 @@ exports[`renders components/flex/demo/combination.tsx correctly 1`] = `
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
Get Start
|
||||
Get Started
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -23,7 +23,7 @@ const App: React.FC = () => (
|
||||
“antd is an enterprise-class UI design language and React UI library.”
|
||||
</Typography.Title>
|
||||
<Button type="primary" href="https://ant.design" target="_blank">
|
||||
Get Start
|
||||
Get Started
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
@ -115,4 +115,9 @@ export default genStyleHooks(
|
||||
];
|
||||
},
|
||||
prepareComponentToken,
|
||||
{
|
||||
// Flex component don't apply extra font style
|
||||
// https://github.com/ant-design/ant-design/issues/46403
|
||||
resetStyle: false,
|
||||
},
|
||||
);
|
||||
|
@ -91,7 +91,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormInstance, FormProps> = (p
|
||||
if (hideRequiredMark) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (contextForm && contextForm.requiredMark !== undefined) {
|
||||
return contextForm.requiredMark;
|
||||
}
|
||||
|
@ -2,124 +2,47 @@
|
||||
|
||||
exports[`renders components/layout/demo/basic.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="row-gap: 48px; width: 100%;"
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
class="ant-layout"
|
||||
style="border-radius: 8px; overflow: hidden; width: calc(50% - 8px); max-width: calc(50% - 8px);"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 48px; line-height: 64px; background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 50px; line-height: 64px; background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(16, 142, 233);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(9, 88, 217);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
class="ant-layout"
|
||||
style="border-radius: 8px; overflow: hidden; width: calc(50% - 8px); max-width: calc(50% - 8px);"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 48px; line-height: 64px; background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 50px; line-height: 64px; background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(59, 160, 233); flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(16, 142, 233);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 50px; line-height: 64px; background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(16, 142, 233);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(59, 160, 233); flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(59, 160, 233); flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(22, 119, 255); flex: 0 0 25%; max-width: 25%; min-width: 25%; width: 25%;"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
@ -127,28 +50,92 @@ exports[`renders components/layout/demo/basic.tsx extend context correctly 1`] =
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(9, 88, 217);"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 50px; line-height: 64px; background-color: rgb(125, 188, 234);"
|
||||
Content
|
||||
</main>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-layout"
|
||||
style="border-radius: 8px; overflow: hidden; width: calc(50% - 8px); max-width: calc(50% - 8px);"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 48px; line-height: 64px; background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(9, 88, 217);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(22, 119, 255); flex: 0 0 25%; max-width: 25%; min-width: 25%; width: 25%;"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(16, 142, 233);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(125, 188, 234);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
style="border-radius: 8px; overflow: hidden; width: calc(50% - 8px); max-width: calc(50% - 8px);"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align: center; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(22, 119, 255); flex: 0 0 25%; max-width: 25%; min-width: 25%; width: 25%;"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align: center; color: rgb(255, 255, 255); height: 64px; padding-inline: 48px; line-height: 64px; background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align: center; min-height: 120px; line-height: 120px; color: rgb(255, 255, 255); background-color: rgb(9, 88, 217);"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align: center; color: rgb(255, 255, 255); background-color: rgb(64, 150, 255);"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1100,7 +1087,7 @@ exports[`renders components/layout/demo/component-token.tsx extend context corre
|
||||
</nav>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding: 24px; margin: 0px; min-height: 280px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; margin: 0px; min-height: 280px; background: rgb(245, 245, 245); border-radius: 8px;"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
@ -1380,7 +1367,7 @@ exports[`renders components/layout/demo/custom-trigger.tsx extend context correc
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="margin: 24px 16px; padding: 24px; min-height: 280px; background: rgb(255, 255, 255);"
|
||||
style="margin: 24px 16px; padding: 24px; min-height: 280px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
@ -1405,6 +1392,7 @@ exports[`renders components/layout/demo/fixed.tsx extend context correctly 1`] =
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex: 1; min-width: 0;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -1604,8 +1592,8 @@ exports[`renders components/layout/demo/fixed.tsx extend context correctly 1`] =
|
||||
</div>
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content site-layout"
|
||||
style="padding: 0px 50px;"
|
||||
class="ant-layout-content"
|
||||
style="padding: 0px 48px;"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -1648,7 +1636,7 @@ exports[`renders components/layout/demo/fixed.tsx extend context correctly 1`] =
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
style="padding: 24px; min-height: 380px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; min-height: 380px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
@ -2225,7 +2213,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx extend context correctly
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout site-layout"
|
||||
class="ant-layout"
|
||||
style="margin-left: 200px;"
|
||||
>
|
||||
<header
|
||||
@ -2237,7 +2225,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx extend context correctly
|
||||
style="margin: 24px 16px 0px; overflow: initial;"
|
||||
>
|
||||
<div
|
||||
style="padding: 24px; text-align: center; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; text-align: center; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
<p>
|
||||
long content
|
||||
@ -2799,7 +2787,7 @@ exports[`renders components/layout/demo/responsive.tsx extend context correctly
|
||||
style="margin: 24px 16px 0px;"
|
||||
>
|
||||
<div
|
||||
style="padding: 24px; min-height: 360px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; min-height: 360px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
content
|
||||
</div>
|
||||
@ -3451,7 +3439,7 @@ exports[`renders components/layout/demo/side.tsx extend context correctly 1`] =
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
style="padding: 24px; min-height: 360px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; min-height: 360px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
Bill is a cat.
|
||||
</div>
|
||||
@ -3474,7 +3462,7 @@ exports[`renders components/layout/demo/side.tsx extend context correctly 2`] =
|
||||
|
||||
exports[`renders components/layout/demo/top.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-layout layout"
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
@ -3487,6 +3475,7 @@ exports[`renders components/layout/demo/top.tsx extend context correctly 1`] = `
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex: 1; min-width: 0;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -4239,7 +4228,7 @@ exports[`renders components/layout/demo/top.tsx extend context correctly 1`] = `
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding: 0px 50px;"
|
||||
style="padding: 0px 48px;"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -4282,8 +4271,7 @@ exports[`renders components/layout/demo/top.tsx extend context correctly 1`] = `
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
class="site-layout-content"
|
||||
style="background: rgb(255, 255, 255);"
|
||||
style="background: rgb(255, 255, 255); min-height: 280px; padding: 24px; border-radius: 8px;"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
@ -4318,6 +4306,7 @@ exports[`renders components/layout/demo/top-side.tsx extend context correctly 1`
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex: 1; min-width: 0;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -4518,7 +4507,7 @@ exports[`renders components/layout/demo/top-side.tsx extend context correctly 1`
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding: 0px 50px;"
|
||||
style="padding: 0px 48px;"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -4562,7 +4551,7 @@ exports[`renders components/layout/demo/top-side.tsx extend context correctly 1`
|
||||
</nav>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
style="padding: 24px 0px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px 0px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
@ -5480,6 +5469,7 @@ exports[`renders components/layout/demo/top-side-2.tsx extend context correctly
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex: 1; min-width: 0;"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -6605,7 +6595,7 @@ exports[`renders components/layout/demo/top-side-2.tsx extend context correctly
|
||||
</nav>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding: 24px; margin: 0px; min-height: 280px; background: rgb(255, 255, 255);"
|
||||
style="padding: 24px; margin: 0px; min-height: 280px; background: rgb(255, 255, 255); border-radius: 8px;"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
|
@ -2,124 +2,47 @@
|
||||
|
||||
exports[`renders components/layout/demo/basic.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="row-gap:48px;width:100%"
|
||||
class="ant-flex ant-flex-wrap-wrap ant-flex-gap-middle"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
class="ant-layout"
|
||||
style="border-radius:8px;overflow:hidden;width:calc(50% - 8px);max-width:calc(50% - 8px)"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:48px;line-height:64px;background-color:#4096ff"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:50px;line-height:64px;background-color:#7dbcea"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#108ee9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#7dbcea"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#0958d9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#4096ff"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
class="ant-layout"
|
||||
style="border-radius:8px;overflow:hidden;width:calc(50% - 8px);max-width:calc(50% - 8px)"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:48px;line-height:64px;background-color:#4096ff"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:50px;line-height:64px;background-color:#7dbcea"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#3ba0e9;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#108ee9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#7dbcea"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:50px;line-height:64px;background-color:#7dbcea"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#108ee9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#3ba0e9;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#7dbcea"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#3ba0e9;flex:0 0 200px;max-width:200px;min-width:200px;width:200px"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#1677ff;flex:0 0 25%;max-width:25%;min-width:25%;width:25%"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
@ -127,28 +50,92 @@ exports[`renders components/layout/demo/basic.tsx correctly 1`] = `
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout"
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#0958d9"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:50px;line-height:64px;background-color:#7dbcea"
|
||||
Content
|
||||
</main>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#4096ff"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-layout"
|
||||
style="border-radius:8px;overflow:hidden;width:calc(50% - 8px);max-width:calc(50% - 8px)"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:48px;line-height:64px;background-color:#4096ff"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#0958d9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#1677ff;flex:0 0 25%;max-width:25%;min-width:25%;width:25%"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#108ee9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#7dbcea"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#4096ff"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
style="border-radius:8px;overflow:hidden;width:calc(50% - 8px);max-width:calc(50% - 8px)"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
style="text-align:center;line-height:120px;color:#fff;background-color:#1677ff;flex:0 0 25%;max-width:25%;min-width:25%;width:25%"
|
||||
>
|
||||
<div
|
||||
class="ant-layout-sider-children"
|
||||
>
|
||||
Sider
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
style="text-align:center;color:#fff;height:64px;padding-inline:48px;line-height:64px;background-color:#4096ff"
|
||||
>
|
||||
Header
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="text-align:center;min-height:120px;line-height:120px;color:#fff;background-color:#0958d9"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
<footer
|
||||
class="ant-layout-footer"
|
||||
style="text-align:center;color:#fff;background-color:#4096ff"
|
||||
>
|
||||
Footer
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -418,7 +405,7 @@ exports[`renders components/layout/demo/component-token.tsx correctly 1`] = `
|
||||
</nav>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding:24px;margin:0;min-height:280px;background:#ffffff"
|
||||
style="padding:24px;margin:0;min-height:280px;background:#f5f5f5;border-radius:8px"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
@ -586,7 +573,7 @@ exports[`renders components/layout/demo/custom-trigger.tsx correctly 1`] = `
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="margin:24px 16px;padding:24px;min-height:280px;background:#ffffff"
|
||||
style="margin:24px 16px;padding:24px;min-height:280px;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
@ -609,6 +596,7 @@ exports[`renders components/layout/demo/fixed.tsx correctly 1`] = `
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex:1;min-width:0"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -691,8 +679,8 @@ exports[`renders components/layout/demo/fixed.tsx correctly 1`] = `
|
||||
/>
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content site-layout"
|
||||
style="padding:0 50px"
|
||||
class="ant-layout-content"
|
||||
style="padding:0 48px"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -735,7 +723,7 @@ exports[`renders components/layout/demo/fixed.tsx correctly 1`] = `
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
style="padding:24px;min-height:380px;background:#ffffff"
|
||||
style="padding:24px;min-height:380px;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
@ -1025,7 +1013,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx correctly 1`] = `
|
||||
</div>
|
||||
</aside>
|
||||
<div
|
||||
class="ant-layout site-layout"
|
||||
class="ant-layout"
|
||||
style="margin-left:200px"
|
||||
>
|
||||
<header
|
||||
@ -1037,7 +1025,7 @@ exports[`renders components/layout/demo/fixed-sider.tsx correctly 1`] = `
|
||||
style="margin:24px 16px 0;overflow:initial"
|
||||
>
|
||||
<div
|
||||
style="padding:24px;text-align:center;background:#ffffff"
|
||||
style="padding:24px;text-align:center;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
<p>
|
||||
long content
|
||||
@ -1417,7 +1405,7 @@ exports[`renders components/layout/demo/responsive.tsx correctly 1`] = `
|
||||
style="margin:24px 16px 0"
|
||||
>
|
||||
<div
|
||||
style="padding:24px;min-height:360px;background:#ffffff"
|
||||
style="padding:24px;min-height:360px;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
content
|
||||
</div>
|
||||
@ -1698,7 +1686,7 @@ exports[`renders components/layout/demo/side.tsx correctly 1`] = `
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
style="padding:24px;min-height:360px;background:#ffffff"
|
||||
style="padding:24px;min-height:360px;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
Bill is a cat.
|
||||
</div>
|
||||
@ -1715,7 +1703,7 @@ exports[`renders components/layout/demo/side.tsx correctly 1`] = `
|
||||
|
||||
exports[`renders components/layout/demo/top.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-layout layout"
|
||||
class="ant-layout"
|
||||
>
|
||||
<header
|
||||
class="ant-layout-header"
|
||||
@ -1728,6 +1716,7 @@ exports[`renders components/layout/demo/top.tsx correctly 1`] = `
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex:1;min-width:0"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -1955,7 +1944,7 @@ exports[`renders components/layout/demo/top.tsx correctly 1`] = `
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding:0 50px"
|
||||
style="padding:0 48px"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -1998,8 +1987,7 @@ exports[`renders components/layout/demo/top.tsx correctly 1`] = `
|
||||
</ol>
|
||||
</nav>
|
||||
<div
|
||||
class="site-layout-content"
|
||||
style="background:#ffffff"
|
||||
style="background:#ffffff;min-height:280px;padding:24px;border-radius:8px"
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
@ -2028,6 +2016,7 @@ exports[`renders components/layout/demo/top-side.tsx correctly 1`] = `
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex:1;min-width:0"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -2111,7 +2100,7 @@ exports[`renders components/layout/demo/top-side.tsx correctly 1`] = `
|
||||
</header>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding:0 50px"
|
||||
style="padding:0 48px"
|
||||
>
|
||||
<nav
|
||||
class="ant-breadcrumb"
|
||||
@ -2155,7 +2144,7 @@ exports[`renders components/layout/demo/top-side.tsx correctly 1`] = `
|
||||
</nav>
|
||||
<div
|
||||
class="ant-layout ant-layout-has-sider"
|
||||
style="padding:24px 0;background:#ffffff"
|
||||
style="padding:24px 0;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
<aside
|
||||
class="ant-layout-sider ant-layout-sider-dark"
|
||||
@ -2387,6 +2376,7 @@ exports[`renders components/layout/demo/top-side-2.tsx correctly 1`] = `
|
||||
class="ant-menu-overflow ant-menu ant-menu-root ant-menu-horizontal ant-menu-dark"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
style="flex:1;min-width:0"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
@ -2715,7 +2705,7 @@ exports[`renders components/layout/demo/top-side-2.tsx correctly 1`] = `
|
||||
</nav>
|
||||
<main
|
||||
class="ant-layout-content"
|
||||
style="padding:24px;margin:0;min-height:280px;background:#ffffff"
|
||||
style="padding:24px;margin:0;min-height:280px;background:#ffffff;border-radius:8px"
|
||||
>
|
||||
Content
|
||||
</main>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Layout, Space } from 'antd';
|
||||
import { Layout, Flex } from 'antd';
|
||||
|
||||
const { Header, Footer, Sider, Content } = Layout;
|
||||
|
||||
@ -7,9 +7,9 @@ const headerStyle: React.CSSProperties = {
|
||||
textAlign: 'center',
|
||||
color: '#fff',
|
||||
height: 64,
|
||||
paddingInline: 50,
|
||||
paddingInline: 48,
|
||||
lineHeight: '64px',
|
||||
backgroundColor: '#7dbcea',
|
||||
backgroundColor: '#4096ff',
|
||||
};
|
||||
|
||||
const contentStyle: React.CSSProperties = {
|
||||
@ -17,54 +17,70 @@ const contentStyle: React.CSSProperties = {
|
||||
minHeight: 120,
|
||||
lineHeight: '120px',
|
||||
color: '#fff',
|
||||
backgroundColor: '#108ee9',
|
||||
backgroundColor: '#0958d9',
|
||||
};
|
||||
|
||||
const siderStyle: React.CSSProperties = {
|
||||
textAlign: 'center',
|
||||
lineHeight: '120px',
|
||||
color: '#fff',
|
||||
backgroundColor: '#3ba0e9',
|
||||
backgroundColor: '#1677ff',
|
||||
};
|
||||
|
||||
const footerStyle: React.CSSProperties = {
|
||||
textAlign: 'center',
|
||||
color: '#fff',
|
||||
backgroundColor: '#7dbcea',
|
||||
backgroundColor: '#4096ff',
|
||||
};
|
||||
|
||||
const layoutStyle = {
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
width: 'calc(50% - 8px)',
|
||||
maxWidth: 'calc(50% - 8px)',
|
||||
};
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={[0, 48]}>
|
||||
<Layout>
|
||||
<Flex gap="middle" wrap="wrap">
|
||||
<Layout style={layoutStyle}>
|
||||
<Header style={headerStyle}>Header</Header>
|
||||
<Content style={contentStyle}>Content</Content>
|
||||
<Footer style={footerStyle}>Footer</Footer>
|
||||
</Layout>
|
||||
<Layout>
|
||||
|
||||
<Layout style={layoutStyle}>
|
||||
<Header style={headerStyle}>Header</Header>
|
||||
<Layout hasSider>
|
||||
<Sider style={siderStyle}>Sider</Sider>
|
||||
<Layout>
|
||||
<Sider width="25%" style={siderStyle}>
|
||||
Sider
|
||||
</Sider>
|
||||
<Content style={contentStyle}>Content</Content>
|
||||
</Layout>
|
||||
<Footer style={footerStyle}>Footer</Footer>
|
||||
</Layout>
|
||||
<Layout>
|
||||
|
||||
<Layout style={layoutStyle}>
|
||||
<Header style={headerStyle}>Header</Header>
|
||||
<Layout hasSider>
|
||||
<Layout>
|
||||
<Content style={contentStyle}>Content</Content>
|
||||
<Sider style={siderStyle}>Sider</Sider>
|
||||
<Sider width="25%" style={siderStyle}>
|
||||
Sider
|
||||
</Sider>
|
||||
</Layout>
|
||||
<Footer style={footerStyle}>Footer</Footer>
|
||||
</Layout>
|
||||
<Layout>
|
||||
<Sider style={siderStyle}>Sider</Sider>
|
||||
|
||||
<Layout style={layoutStyle}>
|
||||
<Sider width="25%" style={siderStyle}>
|
||||
Sider
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Header style={headerStyle}>Header</Header>
|
||||
<Content style={contentStyle}>Content</Content>
|
||||
<Footer style={footerStyle}>Footer</Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Space>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -27,7 +27,7 @@ const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOu
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, colorBgLayout, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -39,8 +39,8 @@ const App: React.FC = () => {
|
||||
headerBg: '#1677ff',
|
||||
headerHeight: 64,
|
||||
headerPadding: `0 24px`,
|
||||
headerColor: '#fff',
|
||||
siderBg: '#fff',
|
||||
headerColor: colorBgContainer,
|
||||
siderBg: colorBgContainer,
|
||||
},
|
||||
},
|
||||
}}
|
||||
@ -71,7 +71,8 @@ const App: React.FC = () => {
|
||||
padding: 24,
|
||||
margin: 0,
|
||||
minHeight: 280,
|
||||
background: colorBgContainer,
|
||||
background: colorBgLayout,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
|
@ -67,7 +67,7 @@ const items: MenuProps['items'] = [
|
||||
const App: React.FC = () => {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -101,6 +101,7 @@ const App: React.FC = () => {
|
||||
padding: 24,
|
||||
minHeight: 280,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
|
@ -13,7 +13,7 @@ const { Header, Sider, Content } = Layout;
|
||||
const App: React.FC = () => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -62,6 +62,7 @@ const App: React.FC = () => {
|
||||
padding: 24,
|
||||
minHeight: 280,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
|
@ -31,7 +31,7 @@ const items: MenuProps['items'] = [
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -49,10 +49,17 @@ const App: React.FC = () => {
|
||||
<div className="demo-logo-vertical" />
|
||||
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']} items={items} />
|
||||
</Sider>
|
||||
<Layout className="site-layout" style={{ marginLeft: 200 }}>
|
||||
<Layout style={{ marginLeft: 200 }}>
|
||||
<Header style={{ padding: 0, background: colorBgContainer }} />
|
||||
<Content style={{ margin: '24px 16px 0', overflow: 'initial' }}>
|
||||
<div style={{ padding: 24, textAlign: 'center', background: colorBgContainer }}>
|
||||
<div
|
||||
style={{
|
||||
padding: 24,
|
||||
textAlign: 'center',
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
<p>long content</p>
|
||||
{
|
||||
// indicates very long content
|
||||
|
@ -3,9 +3,14 @@ import { Breadcrumb, Layout, Menu, theme } from 'antd';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
|
||||
const items = new Array(3).fill(null).map((_, index) => ({
|
||||
key: String(index + 1),
|
||||
label: `nav ${index + 1}`,
|
||||
}));
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -25,19 +30,26 @@ const App: React.FC = () => {
|
||||
theme="dark"
|
||||
mode="horizontal"
|
||||
defaultSelectedKeys={['2']}
|
||||
items={new Array(3).fill(null).map((_, index) => ({
|
||||
key: String(index + 1),
|
||||
label: `nav ${index + 1}`,
|
||||
}))}
|
||||
items={items}
|
||||
style={{ flex: 1, minWidth: 0 }}
|
||||
/>
|
||||
</Header>
|
||||
<Content className="site-layout" style={{ padding: '0 50px' }}>
|
||||
<Content style={{ padding: '0 48px' }}>
|
||||
<Breadcrumb style={{ margin: '16px 0' }}>
|
||||
<Breadcrumb.Item>Home</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>List</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>App</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div style={{ padding: 24, minHeight: 380, background: colorBgContainer }}>Content</div>
|
||||
<div
|
||||
style={{
|
||||
padding: 24,
|
||||
minHeight: 380,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
</Content>
|
||||
<Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
|
||||
</Layout>
|
||||
|
@ -4,9 +4,17 @@ import { Layout, Menu, theme } from 'antd';
|
||||
|
||||
const { Header, Content, Footer, Sider } = Layout;
|
||||
|
||||
const items = [UserOutlined, VideoCameraOutlined, UploadOutlined, UserOutlined].map(
|
||||
(icon, index) => ({
|
||||
key: String(index + 1),
|
||||
icon: React.createElement(icon),
|
||||
label: `nav ${index + 1}`,
|
||||
}),
|
||||
);
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -22,23 +30,21 @@ const App: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
<div className="demo-logo-vertical" />
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
defaultSelectedKeys={['4']}
|
||||
items={[UserOutlined, VideoCameraOutlined, UploadOutlined, UserOutlined].map(
|
||||
(icon, index) => ({
|
||||
key: String(index + 1),
|
||||
icon: React.createElement(icon),
|
||||
label: `nav ${index + 1}`,
|
||||
}),
|
||||
)}
|
||||
/>
|
||||
<Menu theme="dark" mode="inline" defaultSelectedKeys={['4']} items={items} />
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Header style={{ padding: 0, background: colorBgContainer }} />
|
||||
<Content style={{ margin: '24px 16px 0' }}>
|
||||
<div style={{ padding: 24, minHeight: 360, background: colorBgContainer }}>content</div>
|
||||
<div
|
||||
style={{
|
||||
padding: 24,
|
||||
minHeight: 360,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
content
|
||||
</div>
|
||||
</Content>
|
||||
<Footer style={{ textAlign: 'center' }}>Ant Design ©2023 Created by Ant UED</Footer>
|
||||
</Layout>
|
||||
|
@ -42,7 +42,7 @@ const items: MenuItem[] = [
|
||||
const App: React.FC = () => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
@ -58,7 +58,14 @@ const App: React.FC = () => {
|
||||
<Breadcrumb.Item>User</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Bill</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div style={{ padding: 24, minHeight: 360, background: colorBgContainer }}>
|
||||
<div
|
||||
style={{
|
||||
padding: 24,
|
||||
minHeight: 360,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Bill is a cat.
|
||||
</div>
|
||||
</Content>
|
||||
|
@ -32,14 +32,20 @@ const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOu
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Header style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<div className="demo-logo" />
|
||||
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="horizontal"
|
||||
defaultSelectedKeys={['2']}
|
||||
items={items1}
|
||||
style={{ flex: 1, minWidth: 0 }}
|
||||
/>
|
||||
</Header>
|
||||
<Layout>
|
||||
<Sider width={200} style={{ background: colorBgContainer }}>
|
||||
@ -63,6 +69,7 @@ const App: React.FC = () => {
|
||||
margin: 0,
|
||||
minHeight: 280,
|
||||
background: colorBgContainer,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
|
@ -32,22 +32,30 @@ const items2: MenuProps['items'] = [UserOutlined, LaptopOutlined, NotificationOu
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Header style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<div className="demo-logo" />
|
||||
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']} items={items1} />
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="horizontal"
|
||||
defaultSelectedKeys={['2']}
|
||||
items={items1}
|
||||
style={{ flex: 1, minWidth: 0 }}
|
||||
/>
|
||||
</Header>
|
||||
<Content style={{ padding: '0 50px' }}>
|
||||
<Content style={{ padding: '0 48px' }}>
|
||||
<Breadcrumb style={{ margin: '16px 0' }}>
|
||||
<Breadcrumb.Item>Home</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>List</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>App</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<Layout style={{ padding: '24px 0', background: colorBgContainer }}>
|
||||
<Layout
|
||||
style={{ padding: '24px 0', background: colorBgContainer, borderRadius: borderRadiusLG }}
|
||||
>
|
||||
<Sider style={{ background: colorBgContainer }} width={200}>
|
||||
<Menu
|
||||
mode="inline"
|
||||
|
@ -3,35 +3,42 @@ import { Breadcrumb, Layout, Menu, theme } from 'antd';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
|
||||
const items = new Array(15).fill(null).map((_, index) => ({
|
||||
key: index + 1,
|
||||
label: `nav ${index + 1}`,
|
||||
}));
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {
|
||||
token: { colorBgContainer },
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
<Layout className="layout">
|
||||
<Layout>
|
||||
<Header style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<div className="demo-logo" />
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="horizontal"
|
||||
defaultSelectedKeys={['2']}
|
||||
items={new Array(15).fill(null).map((_, index) => {
|
||||
const key = index + 1;
|
||||
return {
|
||||
key,
|
||||
label: `nav ${key}`,
|
||||
};
|
||||
})}
|
||||
items={items}
|
||||
style={{ flex: 1, minWidth: 0 }}
|
||||
/>
|
||||
</Header>
|
||||
<Content style={{ padding: '0 50px' }}>
|
||||
<Content style={{ padding: '0 48px' }}>
|
||||
<Breadcrumb style={{ margin: '16px 0' }}>
|
||||
<Breadcrumb.Item>Home</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>List</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>App</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="site-layout-content" style={{ background: colorBgContainer }}>
|
||||
<div
|
||||
style={{
|
||||
background: colorBgContainer,
|
||||
minHeight: 280,
|
||||
padding: 24,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
Content
|
||||
</div>
|
||||
</Content>
|
||||
|
@ -73,4 +73,10 @@ describe('Spin', () => {
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('right style when fullscreen', () => {
|
||||
const { container } = render(<Spin fullscreen spinning />);
|
||||
const element = container.querySelector<HTMLDivElement>('.ant-spin.ant-spin-fullscreen');
|
||||
expect(element).not.toHaveStyle({ pointerEvents: 'none' });
|
||||
});
|
||||
});
|
||||
|
@ -2787,9 +2787,7 @@ exports[`renders components/tabs/demo/icon.tsx correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Tab
|
||||
<!-- -->
|
||||
1
|
||||
Tab 1
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -2827,9 +2825,7 @@ exports[`renders components/tabs/demo/icon.tsx correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
Tab
|
||||
<!-- -->
|
||||
2
|
||||
Tab 2
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,8 +8,8 @@ const App: React.FC = () => (
|
||||
items={[AppleOutlined, AndroidOutlined].map((Icon, i) => {
|
||||
const id = String(i + 1);
|
||||
return {
|
||||
label: <span>Tab {id}</span>,
|
||||
key: id,
|
||||
label: `Tab ${id}`,
|
||||
children: `Tab ${id}`,
|
||||
icon: <Icon />,
|
||||
};
|
||||
|
@ -60,7 +60,6 @@ const App: React.FC = () => {
|
||||
<Option value="card">Child - card</Option>
|
||||
<Option value="editable-card">Parent - card edit</Option>
|
||||
</Select>
|
||||
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
tabPosition={parentPos}
|
||||
@ -77,7 +76,6 @@ const App: React.FC = () => {
|
||||
style={{ height: 300 }}
|
||||
items={new Array(20).fill(null).map((_, index) => {
|
||||
const key = String(index);
|
||||
|
||||
return {
|
||||
label: `Tab ${key}`,
|
||||
key,
|
||||
|
@ -25,9 +25,7 @@ To enable CSS variable mode, use the `cssVar` configuration in the `theme` prope
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
CSS variable mode requires a unique key for each theme to ensure style isolation.
|
||||
In React 18, we use `useId` to generate unique keys by default, so you don't have to worry about this issue in React 18.
|
||||
But in React 17 or 16, you need to manually set a unique key for each theme, otherwise the themes will be mixed up.
|
||||
CSS variable mode requires a unique key for each theme to ensure style isolation. In React 18, we use `useId` to generate unique keys by default, so you don't have to worry about this issue in React 18. But in React 17 or 16, you need to manually set a unique key for each theme, otherwise the themes will be mixed up.
|
||||
:::
|
||||
|
||||
```tsx
|
||||
|
@ -25,8 +25,7 @@ CSS 变量模式为 Ant Design 的样式能力带来了两个重要的提升:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
:::warning
|
||||
CSS 变量模式需要为每一个主题设置独特的 key 来保证样式隔离,在 React 18 中我们使用了 `useId` 来生成唯一的 key,所以在 React 18 中,你可以不用关心这个问题。
|
||||
但是在 React 17 或者 16 中,你需要手动为每一个主题设置一个唯一的 key,否则会导致主题混乱。
|
||||
CSS 变量模式需要为每一个主题设置独特的 key 来保证样式隔离,在 React 18 中我们使用了 `useId` 来生成唯一的 key,所以在 React 18 中,你可以不用关心这个问题。但是在 React 17 或者 16 中,你需要手动为每一个主题设置一个唯一的 key,否则会导致主题混乱。
|
||||
:::
|
||||
|
||||
```tsx
|
||||
|
29
package.json
29
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "5.12.1",
|
||||
"version": "5.12.2",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"keywords": [
|
||||
"ant",
|
||||
@ -99,6 +99,7 @@
|
||||
"token-meta": "tsx scripts/generate-token-meta.ts",
|
||||
"tsc": "tsc --noEmit",
|
||||
"version": "tsx scripts/generate-version.ts",
|
||||
"visual-regression": "tsx scripts/visual-regression/build.ts",
|
||||
"npm-install": "npm install"
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -113,7 +114,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.0.0",
|
||||
"@ant-design/cssinjs": "^1.18.0",
|
||||
"@ant-design/cssinjs": "^1.18.1",
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@ant-design/react-slick": "~1.0.2",
|
||||
"@babel/runtime": "^7.23.4",
|
||||
@ -140,7 +141,7 @@
|
||||
"rc-menu": "~9.12.4",
|
||||
"rc-motion": "^2.9.0",
|
||||
"rc-notification": "~5.3.0",
|
||||
"rc-pagination": "~4.0.1",
|
||||
"rc-pagination": "~4.0.3",
|
||||
"rc-picker": "~3.14.6",
|
||||
"rc-progress": "~3.5.1",
|
||||
"rc-rate": "~2.12.0",
|
||||
@ -199,6 +200,8 @@
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/pixelmatch": "^5.2.6",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/prismjs": "^1.26.3",
|
||||
"@types/progress": "^2.0.7",
|
||||
"@types/qs": "^6.9.10",
|
||||
@ -207,6 +210,7 @@
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@types/react-highlight-words": "^0.16.7",
|
||||
"@types/react-resizable": "^3.0.7",
|
||||
"@types/tar": "^6.1.10",
|
||||
"@types/throttle-debounce": "^5.0.2",
|
||||
"@types/warning": "^3.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
||||
@ -266,10 +270,14 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lunar-typescript": "^1.6.13",
|
||||
"lz-string": "^1.5.0",
|
||||
"minimist": "^1.2.8",
|
||||
"mockdate": "^3.0.5",
|
||||
"node-fetch": "^3.3.2",
|
||||
"node-notifier": "^10.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"open": "^9.1.0",
|
||||
"pixelmatch": "^5.3.0",
|
||||
"pngjs": "^7.0.0",
|
||||
"prettier": "^3.1.0",
|
||||
"prettier-plugin-jsdoc": "^1.1.1",
|
||||
"pretty-format": "^29.7.0",
|
||||
@ -294,23 +302,28 @@
|
||||
"regenerator-runtime": "^0.14.0",
|
||||
"remark": "^15.0.1",
|
||||
"remark-cli": "^12.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-html": "^16.0.1",
|
||||
"remark-lint": "^9.1.2",
|
||||
"remark-lint-no-undefined-references": "^4.2.1",
|
||||
"remark-preset-lint-recommended": "^6.1.3",
|
||||
"runes2": "^1.1.3",
|
||||
"semver": "^7.5.4",
|
||||
"sharp": "^0.33.0",
|
||||
"simple-git": "^3.21.0",
|
||||
"size-limit": "^11.0.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint": "^16.0.0",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-standard": "^34.0.0",
|
||||
"stylelint-prettier": "^4.1.0",
|
||||
"stylelint-config-standard": "^35.0.0",
|
||||
"stylelint-prettier": "^5.0.0",
|
||||
"sylvanas": "^0.6.1",
|
||||
"tar": "^6.2.0",
|
||||
"tar-fs": "^3.0.4",
|
||||
"terser": "^5.24.0",
|
||||
"tsx": "^4.6.0",
|
||||
"typedoc": "^0.25.4",
|
||||
"typescript": "~5.3.0",
|
||||
"vanilla-jsoneditor": "^0.19.0",
|
||||
"vanilla-jsoneditor": "^0.20.0",
|
||||
"vanilla-tilt": "^1.8.1",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
@ -328,7 +341,7 @@
|
||||
"dumi": "^2.3.0-alpha.4"
|
||||
}
|
||||
},
|
||||
"packageManager": "npm@10.2.4",
|
||||
"packageManager": "npm@10.2.5",
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "./dist/antd.min.js",
|
||||
|
22
scripts/tsconfig.json
Normal file
22
scripts/tsconfig.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"skipLibCheck": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"incremental": true,
|
||||
"sourceMap": false,
|
||||
"strict": false,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"noEmitOnError": false,
|
||||
"importHelpers": false,
|
||||
"typeRoots": ["../node_modules/@types"],
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["./"],
|
||||
"exclude": ["**/node_modules"]
|
||||
}
|
308
scripts/visual-regression/build.ts
Normal file
308
scripts/visual-regression/build.ts
Normal file
@ -0,0 +1,308 @@
|
||||
/* eslint-disable compat/compat */
|
||||
/* eslint-disable no-console, no-await-in-loop, import/no-extraneous-dependencies, lodash/import-scope, no-restricted-syntax */
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import { Readable } from 'stream';
|
||||
import { finished } from 'stream/promises';
|
||||
|
||||
import { remark } from 'remark';
|
||||
import remarkHtml from 'remark-html';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import minimist from 'minimist';
|
||||
import tar from 'tar';
|
||||
import fse from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import _ from 'lodash';
|
||||
import pixelmatch from 'pixelmatch';
|
||||
import { PNG } from 'pngjs';
|
||||
import sharp from 'sharp';
|
||||
import { assert } from 'console';
|
||||
|
||||
const ALI_OSS_BUCKET = 'antd-visual-diff';
|
||||
|
||||
const compareScreenshots = async (
|
||||
baseImgPath: string,
|
||||
currentImgPath: string,
|
||||
diffImagePath: string,
|
||||
): Promise<number> => {
|
||||
const baseImgBuf = await sharp(baseImgPath).toBuffer();
|
||||
const currentImgBuf = await sharp(currentImgPath).toBuffer();
|
||||
|
||||
const basePng = PNG.sync.read(baseImgBuf);
|
||||
const targetWidth = basePng.width;
|
||||
const targetHeight = basePng.height;
|
||||
|
||||
const comparePng = PNG.sync.read(
|
||||
await sharp(currentImgBuf)
|
||||
.resize({
|
||||
width: targetWidth,
|
||||
height: targetHeight,
|
||||
fit: sharp.fit.contain,
|
||||
background: { r: 255, g: 255, b: 255, alpha: 0 },
|
||||
})
|
||||
.png()
|
||||
.toBuffer(),
|
||||
);
|
||||
|
||||
const diffPng = new PNG({ width: targetWidth, height: targetHeight });
|
||||
|
||||
const mismatchedPixels = pixelmatch(
|
||||
basePng.data,
|
||||
comparePng.data,
|
||||
diffPng.data,
|
||||
targetWidth,
|
||||
targetHeight,
|
||||
{ threshold: 0.1, diffMask: false },
|
||||
);
|
||||
|
||||
// if mismatched then write diff image
|
||||
if (mismatchedPixels) {
|
||||
diffPng.pack().pipe(fs.createWriteStream(diffImagePath));
|
||||
}
|
||||
|
||||
return (mismatchedPixels / (targetWidth * targetHeight)) * 100;
|
||||
};
|
||||
|
||||
const readPngs = (dir: string) => fs.readdirSync(dir).filter((n) => n.endsWith('.png'));
|
||||
|
||||
const prettyList = (list: string[]) => list.map((i) => ` * ${i}`).join('\n');
|
||||
|
||||
const ossDomain = `https://${ALI_OSS_BUCKET}.oss-cn-shanghai.aliyuncs.com`;
|
||||
|
||||
async function downloadFile(url: string, destPath: string) {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok || response.status !== 200) {
|
||||
throw new Error(`Download file failed: ${new URL(url).pathname}`);
|
||||
}
|
||||
// @ts-ignore
|
||||
const body = Readable.fromWeb(response.body);
|
||||
await finished(body.pipe(fs.createWriteStream(destPath)));
|
||||
}
|
||||
|
||||
async function getBranchLatestRef(branchName: string) {
|
||||
const baseImageRefUrl = `${ossDomain}/${branchName}/visual-regression-ref.txt`;
|
||||
// get content from baseImageRefText
|
||||
const res = await fetch(baseImageRefUrl);
|
||||
const text = await res.text();
|
||||
const ref = text.trim();
|
||||
return ref;
|
||||
}
|
||||
|
||||
async function downloadBaseSnapshots(ref: string, targetDir: string) {
|
||||
// download imageSnapshotsUrl
|
||||
const imageSnapshotsUrl = `${ossDomain}/${ref}/imageSnapshots.tar.gz`;
|
||||
const targzPath = path.resolve(os.tmpdir(), `./${path.basename(targetDir)}.tar.gz`);
|
||||
await downloadFile(imageSnapshotsUrl, targzPath);
|
||||
// untar
|
||||
return tar.x({
|
||||
// remove top-level dir
|
||||
strip: 1,
|
||||
C: targetDir,
|
||||
file: targzPath,
|
||||
});
|
||||
}
|
||||
|
||||
interface IBadCase {
|
||||
type: 'removed' | 'changed';
|
||||
filename: string;
|
||||
}
|
||||
|
||||
function md2Html(md: string) {
|
||||
return remark().use(remarkGfm).use(remarkHtml).processSync(md).toString();
|
||||
}
|
||||
|
||||
function generateReport(
|
||||
badCases: IBadCase[],
|
||||
targetBranch: string,
|
||||
targetRef: string,
|
||||
): [string, string] {
|
||||
// parse args from -- --pr-id=123
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
const prId = argv['pr-id'];
|
||||
assert(prId, 'Missing --pr-id');
|
||||
const publicPath = `${ossDomain}/pr-${prId}`;
|
||||
|
||||
const commonHeader = `
|
||||
## Visual Regression Report for PR #${prId}
|
||||
> **Target branch:** ${targetBranch} (${targetRef})
|
||||
`.trim();
|
||||
|
||||
if (badCases.length === 0) {
|
||||
const mdStr = [
|
||||
commonHeader,
|
||||
'------------------------',
|
||||
'Congrats! No visual-regression diff found',
|
||||
].join('\n');
|
||||
|
||||
return [mdStr, md2Html(mdStr)];
|
||||
}
|
||||
|
||||
const htmlReportLink = `${publicPath}/visualRegressionReport/report.html`;
|
||||
|
||||
const addonFullReportDesc = `\n\nToo many visual-regression diffs found, please check [Full Report](${htmlReportLink}) for details`;
|
||||
|
||||
// github action pr comment has limit of 65536 4-byte unicode characters
|
||||
const limit = 65536 - addonFullReportDesc.length;
|
||||
|
||||
let reportMdStr = `
|
||||
${commonHeader}
|
||||
> [View Full Report](${htmlReportLink})\n
|
||||
------------------------
|
||||
| image name | expected | actual | diff |
|
||||
| --- | --- | --- | --- |
|
||||
`.trim();
|
||||
reportMdStr += '\n';
|
||||
|
||||
let fullVersionMd = reportMdStr;
|
||||
|
||||
let addonFullReportDescAdded = false;
|
||||
|
||||
for (const badCase of badCases) {
|
||||
const { filename, type } = badCase;
|
||||
let lineReportMdStr = '';
|
||||
if (type === 'changed') {
|
||||
lineReportMdStr += '| ';
|
||||
lineReportMdStr += [
|
||||
badCase.filename,
|
||||
`![${targetBranch}: ${targetRef}](${publicPath}/visualRegressionReport/images/base/${filename})`,
|
||||
`![current: pr-${prId}](${publicPath}/visualRegressionReport/images/current/${filename})`,
|
||||
`![diff](${publicPath}/visualRegressionReport/images/diff/${filename})`,
|
||||
].join(' | ');
|
||||
lineReportMdStr += ' |\n';
|
||||
} else if (type === 'removed') {
|
||||
lineReportMdStr += '| ';
|
||||
lineReportMdStr += [
|
||||
badCase.filename,
|
||||
`![${targetBranch}: ${targetRef}](${publicPath}/visualRegressionReport/images/base/${filename})`,
|
||||
`⛔️⛔️⛔️ Missing ⛔️⛔️⛔️`,
|
||||
`🚨🚨🚨 Removed 🚨🚨🚨`,
|
||||
].join(' | ');
|
||||
lineReportMdStr += ' |\n';
|
||||
}
|
||||
|
||||
if (lineReportMdStr) {
|
||||
if (reportMdStr.length + lineReportMdStr.length < limit) {
|
||||
reportMdStr += lineReportMdStr;
|
||||
} else if (!addonFullReportDescAdded) {
|
||||
reportMdStr += addonFullReportDesc;
|
||||
addonFullReportDescAdded = true;
|
||||
}
|
||||
fullVersionMd += lineReportMdStr;
|
||||
}
|
||||
}
|
||||
|
||||
// convert fullVersionMd to html
|
||||
return [reportMdStr, md2Html(fullVersionMd)];
|
||||
}
|
||||
|
||||
async function boot() {
|
||||
console.log(chalk.green('Preparing image snapshots from latest `master` branch\n'));
|
||||
const baseImgSourceDir = path.resolve(__dirname, '../../imageSnapshots-master');
|
||||
await fse.ensureDir(baseImgSourceDir);
|
||||
|
||||
const targetBranch = 'master';
|
||||
const targetRef = await getBranchLatestRef(targetBranch);
|
||||
assert(targetRef, `Missing ref from ${targetBranch}`);
|
||||
|
||||
await downloadBaseSnapshots(targetRef, baseImgSourceDir);
|
||||
|
||||
const currentImgSourceDir = path.resolve(__dirname, '../../imageSnapshots');
|
||||
|
||||
const reportDir = path.resolve(__dirname, '../../visualRegressionReport');
|
||||
// save diff images(x3) to reportDir
|
||||
const diffImgReportDir = path.resolve(reportDir, './images/diff');
|
||||
const baseImgReportDir = path.resolve(reportDir, './images/base');
|
||||
const currentImgReportDir = path.resolve(reportDir, './images/current');
|
||||
|
||||
await fse.ensureDir(diffImgReportDir);
|
||||
await fse.ensureDir(baseImgReportDir);
|
||||
await fse.ensureDir(currentImgReportDir);
|
||||
|
||||
console.log(chalk.blue('⛳ Checking image snapshots with branch %s'), targetBranch);
|
||||
console.log('\n');
|
||||
|
||||
const baseImgFileList = readPngs(baseImgSourceDir);
|
||||
const currentImgFileList = readPngs(currentImgSourceDir);
|
||||
|
||||
const deletedImgs = _.difference(baseImgFileList, currentImgFileList);
|
||||
if (deletedImgs.length) {
|
||||
console.log(chalk.red('⛔️ Missing images compare to master:\n'), prettyList(deletedImgs));
|
||||
console.log('\n');
|
||||
}
|
||||
// ignore new images
|
||||
const newImgs = _.difference(currentImgFileList, baseImgFileList);
|
||||
if (newImgs.length) {
|
||||
console.log(chalk.green('🆕 Added images:\n'), prettyList(newImgs));
|
||||
console.log('\n');
|
||||
}
|
||||
|
||||
const badCases: IBadCase[] = [];
|
||||
|
||||
for (const file of baseImgFileList) {
|
||||
const baseImgPath = path.join(baseImgSourceDir, file);
|
||||
const currentImgPath = path.join(currentImgSourceDir, file);
|
||||
const diffImgPath = path.join(diffImgReportDir, file);
|
||||
|
||||
const currentImgExists = await fse.exists(currentImgPath);
|
||||
if (!currentImgExists) {
|
||||
console.log(chalk.red(`⛔️ Missing image: ${file}\n`));
|
||||
badCases.push({
|
||||
type: 'removed',
|
||||
filename: file,
|
||||
});
|
||||
await fse.copy(baseImgPath, path.join(baseImgReportDir, file));
|
||||
continue;
|
||||
}
|
||||
|
||||
const mismatchedPxPercent = await compareScreenshots(baseImgPath, currentImgPath, diffImgPath);
|
||||
|
||||
if (mismatchedPxPercent > 0) {
|
||||
console.log(
|
||||
'Mismatched pixels for:',
|
||||
chalk.yellow(file),
|
||||
`${mismatchedPxPercent.toFixed(2)}%\n`,
|
||||
);
|
||||
// copy compare imgs(x2) to report dir
|
||||
await fse.copy(baseImgPath, path.join(baseImgReportDir, file));
|
||||
await fse.copy(currentImgPath, path.join(currentImgReportDir, file));
|
||||
|
||||
badCases.push({
|
||||
type: 'changed',
|
||||
filename: file,
|
||||
});
|
||||
} else {
|
||||
console.log('Passed for: %s\n', chalk.green(file));
|
||||
}
|
||||
}
|
||||
|
||||
if (badCases.length) {
|
||||
console.log(chalk.red('⛔️ Failed cases:\n'), prettyList(badCases.map((i) => i.filename)));
|
||||
console.log('\n');
|
||||
}
|
||||
|
||||
const jsonl = badCases.map((i) => JSON.stringify(i)).join('\n');
|
||||
// write jsonl and markdown report to diffImgDir
|
||||
await fse.writeFile(path.join(reportDir, './report.jsonl'), jsonl);
|
||||
const [reportMdStr, reportHtmlStr] = generateReport(badCases, targetBranch, targetRef);
|
||||
await fse.writeFile(path.join(reportDir, './report.md'), reportMdStr);
|
||||
const htmlTemplate = await fse.readFile(path.join(__dirname, './report-template.html'), 'utf8');
|
||||
|
||||
await fse.writeFile(
|
||||
path.join(reportDir, './report.html'),
|
||||
htmlTemplate.replace('{{reportContent}}', reportHtmlStr),
|
||||
'utf-8',
|
||||
);
|
||||
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
// ignore top-level dir(e.g. visualRegressionReport) and zip all files in it
|
||||
cwd: reportDir,
|
||||
file: `${path.basename(reportDir)}.tar.gz`,
|
||||
},
|
||||
await fse.readdir(reportDir),
|
||||
);
|
||||
}
|
||||
|
||||
boot();
|
74
scripts/visual-regression/report-template.html
Normal file
74
scripts/visual-regression/report-template.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
<link href="https://unpkg.com/antd@latest/dist/reset.css" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
/* Table Styles */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* Hover Effect */
|
||||
tr:hover {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
/* Responsive Table */
|
||||
@media screen and (max-width: 600px) and (min-width: 1px) {
|
||||
table {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
display: block;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{reportContent}}
|
||||
</body>
|
||||
</html>
|
@ -6,17 +6,19 @@
|
||||
const OSS = require('ali-oss');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { assert } = require('console');
|
||||
const assert = require('assert');
|
||||
|
||||
// node scripts/visual-regression-upload.js ./visualRegressionReport.tar.gz --ref=pr-id
|
||||
// node scripts/visual-regression-upload.js ./imageSnapshots.tar.gz --ref=master-commitId
|
||||
// node scripts/visual-regression/upload.js ./visualRegressionReport.tar.gz --ref=pr-id
|
||||
// node scripts/visual-regression/upload.js ./imageSnapshots.tar.gz --ref=master-commitId
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length < 2) {
|
||||
console.error('Usage: node scripts/visual-regression-upload.js <tarFilePath> --ref=<refValue>');
|
||||
console.error('Usage: node scripts/visual-regression/upload.js <tarFilePath> --ref=<refValue>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const ALI_OSS_BUCKET = 'antd-visual-diff';
|
||||
|
||||
/**
|
||||
* Extract the tar file path and ref value from the cli arguments
|
||||
* @param {string[]} cliArgs
|
||||
@ -99,7 +101,7 @@ async function boot() {
|
||||
endpoint: 'oss-cn-shanghai.aliyuncs.com',
|
||||
accessKeyId: process.env.ALI_OSS_AK_ID,
|
||||
accessKeySecret: process.env.ALI_OSS_AK_SECRET,
|
||||
bucket: process.env.ALI_OSS_BUCKET,
|
||||
bucket: ALI_OSS_BUCKET,
|
||||
});
|
||||
|
||||
// if is a file then upload it directly
|
@ -35,7 +35,7 @@ export default function imageTest(
|
||||
identifier: string,
|
||||
options: ImageTestOptions,
|
||||
) {
|
||||
function test(name: string, themedComponent: React.ReactElement) {
|
||||
function test(name: string, suffix: string, themedComponent: React.ReactElement) {
|
||||
it(name, async () => {
|
||||
await jestPuppeteer.resetPage();
|
||||
await page.setRequestInterception(true);
|
||||
@ -86,7 +86,7 @@ export default function imageTest(
|
||||
});
|
||||
|
||||
expect(image).toMatchImageSnapshot({
|
||||
customSnapshotIdentifier: `${identifier}-${name.replace(/\s/g, '-')}`,
|
||||
customSnapshotIdentifier: `${identifier}${suffix}`,
|
||||
});
|
||||
|
||||
MockDate.reset();
|
||||
@ -98,12 +98,14 @@ export default function imageTest(
|
||||
Object.entries(themes).forEach(([key, algorithm]) => {
|
||||
test(
|
||||
`component image screenshot should correct ${key}`,
|
||||
`-${key}`,
|
||||
<div style={{ background: key === 'dark' ? '#000' : '', padding: `24px 12px` }} key={key}>
|
||||
<ConfigProvider theme={{ algorithm }}>{component}</ConfigProvider>
|
||||
</div>,
|
||||
);
|
||||
test(
|
||||
`component image screenshot should correct ${key}.css-var`,
|
||||
`[CSS Var] component image screenshot should correct ${key}`,
|
||||
`-${key}.css-var`,
|
||||
<div style={{ background: key === 'dark' ? '#000' : '', padding: `24px 12px` }} key={key}>
|
||||
<div>CSS Var</div>
|
||||
<ConfigProvider theme={{ algorithm, cssVar: true }}>{component}</ConfigProvider>
|
||||
@ -113,6 +115,7 @@ export default function imageTest(
|
||||
} else {
|
||||
test(
|
||||
`component image screenshot should correct`,
|
||||
'',
|
||||
<>
|
||||
{Object.entries(themes).map(([key, algorithm]) => (
|
||||
<div style={{ background: key === 'dark' ? '#000' : '', padding: `24px 12px` }} key={key}>
|
||||
@ -122,7 +125,8 @@ export default function imageTest(
|
||||
</>,
|
||||
);
|
||||
test(
|
||||
`component image screenshot should correct.css-var`,
|
||||
`[CSS Var] component image screenshot should correct`,
|
||||
'.css-var',
|
||||
<>
|
||||
<div>CSS Var</div>
|
||||
{Object.entries(themes).map(([key, algorithm]) => (
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user