mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 22:36:31 +08:00
commit
f8629ac588
39
.circleci/config.yml
Normal file
39
.circleci/config.yml
Normal file
@ -0,0 +1,39 @@
|
||||
# Use the latest 2.1 version of CircleCI pipeline process engine.
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference
|
||||
version: 2.1
|
||||
|
||||
# Define a job to be invoked later in a workflow.
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
||||
jobs:
|
||||
test-argos-ci:
|
||||
docker:
|
||||
- image: circleci/node:16-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install node_modules
|
||||
command: npm i
|
||||
- run:
|
||||
name: Install argos cli
|
||||
command: npm i fast-glob lodash @argos-ci/core
|
||||
- run:
|
||||
name: Install puppeteer
|
||||
command: node node_modules/puppeteer/install.js
|
||||
- run:
|
||||
name: Build dist file
|
||||
command: npm run dist
|
||||
- run:
|
||||
name: Run image screenshot tests
|
||||
command: npm run test-image
|
||||
- run:
|
||||
name: Upload screenshots to Argos CI
|
||||
command: npm run argos
|
||||
# The resource_class feature allows configuring CPU and RAM resources for each job. Different resource classes are available for different executors. https://circleci.com/docs/2.0/configuration-reference/#resourceclass
|
||||
resource_class: large
|
||||
|
||||
# Invoke jobs via workflows
|
||||
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||
workflows:
|
||||
test-argos-ci-workflow:
|
||||
jobs:
|
||||
- test-argos-ci
|
63
.github/workflows/ui-upload.yml
vendored
63
.github/workflows/ui-upload.yml
vendored
@ -1,63 +0,0 @@
|
||||
# Upload 📷 UI snapshots to argos server, help visual regression testing.
|
||||
name: 📷 UI Upload
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["📷 UI"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
upload-ui:
|
||||
permissions:
|
||||
actions: read # for dawidd6/action-download-artifact to query and download artifacts
|
||||
pull-requests: read # for dawidd6/action-download-artifact to query commit hash
|
||||
name: deploy preview
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
github.repository == 'ant-design/ant-design' &&
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download commit artifact
|
||||
uses: dawidd6/action-download-artifact@v2.23.0
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: commit
|
||||
|
||||
- name: Save commit id
|
||||
id: commit
|
||||
run: echo "::set-output name=id::$(<commit.txt)"
|
||||
|
||||
- name: Download branch artifact
|
||||
uses: dawidd6/action-download-artifact@v2.23.0
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: branch
|
||||
|
||||
- name: Save branch id
|
||||
id: branch
|
||||
run: echo "::set-output name=id::$(<branch.txt)"
|
||||
|
||||
- name: Download snapshots artifact
|
||||
uses: dawidd6/action-download-artifact@v2.23.0
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
workflow_conclusion: success
|
||||
name: snapshots
|
||||
path: imageSnapshots
|
||||
|
||||
- name: Install
|
||||
run: npm i fast-glob lodash @argos-ci/core
|
||||
|
||||
- name: Upload on Argos
|
||||
id: deploy
|
||||
run: npm run argos
|
||||
env:
|
||||
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
|
||||
ARGOS_PARALLEL_NONCE: ${{ github.run_id }}
|
93
.github/workflows/ui.yml
vendored
93
.github/workflows/ui.yml
vendored
@ -1,93 +0,0 @@
|
||||
name: 📷 UI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
push:
|
||||
|
||||
# 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:
|
||||
imagesnapshot:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: cache package-lock.json
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: package-temp-dir
|
||||
key: lock-${{ github.sha }}
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
|
||||
- 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
|
||||
|
||||
- name: test
|
||||
run: npm run test-image
|
||||
|
||||
- name: upload snapshots artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: snapshots
|
||||
path: imageSnapshots/
|
||||
retention-days: 3
|
||||
|
||||
- name: Save commit
|
||||
if: github.event_name == 'pull_request' && github.base_ref == 'master'
|
||||
run: echo ${{ github.event.pull_request.head.sha }} > ./commit.txt
|
||||
|
||||
- name: Save commit
|
||||
if: github.event_name == 'push'
|
||||
run: echo ${{ github.sha }} > ./commit.txt
|
||||
|
||||
- name: Upload commit
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: commit
|
||||
path: ./commit.txt
|
||||
|
||||
- name: Save branch
|
||||
if: github.event_name == 'pull_request' && github.base_ref == 'master'
|
||||
run: echo pull/${{ github.event.pull_request.number }}/merge > ./branch.txt
|
||||
|
||||
- name: Save branch
|
||||
if: github.event_name == 'push'
|
||||
run: echo ${GITHUB_REF##*/} > ./branch.txt
|
||||
|
||||
- name: Upload branch
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: branch
|
||||
path: ./branch.txt
|
@ -1,6 +0,0 @@
|
||||
FROM buildkite/puppeteer:10.0.0
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
COPY package.json ./
|
||||
ENV PATH="${PATH}:/app/node_modules/.bin"
|
||||
COPY . .
|
@ -35,10 +35,10 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
|
||||
|
||||
const sharpMatcherRegx = /#([\S ]+)$/;
|
||||
|
||||
type Section = {
|
||||
interface Section {
|
||||
link: string;
|
||||
top: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AnchorProps {
|
||||
prefixCls?: string;
|
||||
@ -89,11 +89,6 @@ export interface AntAnchor {
|
||||
}
|
||||
|
||||
class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigConsumerProps> {
|
||||
static defaultProps = {
|
||||
affix: true,
|
||||
showInkInFixed: false,
|
||||
};
|
||||
|
||||
static contextType = ConfigContext;
|
||||
|
||||
state = {
|
||||
@ -111,20 +106,20 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
|
||||
private links: string[] = [];
|
||||
|
||||
private scrollEvent: any;
|
||||
private scrollEvent: ReturnType<typeof addEventListener>;
|
||||
|
||||
private animating: boolean;
|
||||
|
||||
private prefixCls?: string;
|
||||
|
||||
// Context
|
||||
registerLink = (link: string) => {
|
||||
registerLink: AntAnchor['registerLink'] = link => {
|
||||
if (!this.links.includes(link)) {
|
||||
this.links.push(link);
|
||||
}
|
||||
};
|
||||
|
||||
unregisterLink = (link: string) => {
|
||||
unregisterLink: AntAnchor['unregisterLink'] = link => {
|
||||
const index = this.links.indexOf(link);
|
||||
if (index !== -1) {
|
||||
this.links.splice(index, 1);
|
||||
@ -174,7 +169,7 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
const linkSections: Array<Section> = [];
|
||||
const container = this.getContainer();
|
||||
this.links.forEach(link => {
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link?.toString());
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
@ -182,10 +177,7 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
if (target) {
|
||||
const top = getOffsetTop(target, container);
|
||||
if (top < offsetTop + bounds) {
|
||||
linkSections.push({
|
||||
link,
|
||||
top,
|
||||
});
|
||||
linkSections.push({ link, top });
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -259,10 +251,9 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
updateInk = () => {
|
||||
const { prefixCls, wrapperRef } = this;
|
||||
const anchorNode = wrapperRef.current;
|
||||
const linkNode = anchorNode?.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
|
||||
|
||||
const linkNode = anchorNode?.querySelector<HTMLElement>(`.${prefixCls}-link-title-active`);
|
||||
if (linkNode) {
|
||||
this.inkNode.style.top = `${(linkNode as any).offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
|
||||
this.inkNode.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
|
||||
}
|
||||
};
|
||||
|
||||
@ -283,8 +274,8 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
className = '',
|
||||
style,
|
||||
offsetTop,
|
||||
affix,
|
||||
showInkInFixed,
|
||||
affix = true,
|
||||
showInkInFixed = false,
|
||||
children,
|
||||
onClick,
|
||||
} = this.props;
|
||||
@ -311,7 +302,7 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
[`${prefixCls}-fixed`]: !affix && !showInkInFixed,
|
||||
});
|
||||
|
||||
const wrapperStyle = {
|
||||
const wrapperStyle: React.CSSProperties = {
|
||||
maxHeight: offsetTop ? `calc(100vh - ${offsetTop}px)` : '100vh',
|
||||
...style,
|
||||
};
|
||||
@ -331,33 +322,26 @@ class Anchor extends React.Component<InternalAnchorProps, AnchorState, ConfigCon
|
||||
|
||||
return (
|
||||
<AnchorContext.Provider value={contextValue}>
|
||||
{!affix ? (
|
||||
anchorContent
|
||||
) : (
|
||||
{affix ? (
|
||||
<Affix offsetTop={offsetTop} target={this.getContainer}>
|
||||
{anchorContent}
|
||||
</Affix>
|
||||
) : (
|
||||
anchorContent
|
||||
)}
|
||||
</AnchorContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// just use in test
|
||||
export type InternalAnchorClass = Anchor;
|
||||
|
||||
const AnchorFC = React.forwardRef<Anchor, AnchorProps>((props, ref) => {
|
||||
const { prefixCls: customizePrefixCls } = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const anchorPrefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
|
||||
const anchorProps: InternalAnchorProps = {
|
||||
...props,
|
||||
|
||||
anchorPrefixCls,
|
||||
};
|
||||
|
||||
return <Anchor {...anchorProps} ref={ref} />;
|
||||
return <Anchor {...props} ref={ref} anchorPrefixCls={anchorPrefixCls} />;
|
||||
});
|
||||
|
||||
export default AnchorFC;
|
||||
|
@ -14,49 +14,33 @@ export interface AnchorLinkProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
class AnchorLink extends React.Component<AnchorLinkProps, any, AntAnchor> {
|
||||
static defaultProps = {
|
||||
href: '#',
|
||||
const AnchorLink: React.FC<AnchorLinkProps> = props => {
|
||||
const { href = '#', title, prefixCls: customizePrefixCls, children, className, target } = props;
|
||||
|
||||
const context = React.useContext<AntAnchor | undefined>(AnchorContext);
|
||||
|
||||
const { registerLink, unregisterLink, scrollTo, onClick, activeLink } = context || {};
|
||||
|
||||
React.useEffect(() => {
|
||||
registerLink?.(href);
|
||||
return () => {
|
||||
unregisterLink?.(href);
|
||||
};
|
||||
}, [href]);
|
||||
|
||||
static contextType = AnchorContext;
|
||||
|
||||
context: AntAnchor;
|
||||
|
||||
componentDidMount() {
|
||||
this.context.registerLink(this.props.href);
|
||||
}
|
||||
|
||||
componentDidUpdate({ href: prevHref }: AnchorLinkProps) {
|
||||
const { href } = this.props;
|
||||
if (prevHref !== href) {
|
||||
this.context.unregisterLink(prevHref);
|
||||
this.context.registerLink(href);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.context.unregisterLink(this.props.href);
|
||||
}
|
||||
|
||||
handleClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||
const { scrollTo, onClick } = this.context;
|
||||
const { href, title } = this.props;
|
||||
const handleClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||
onClick?.(e, { title, href });
|
||||
scrollTo(href);
|
||||
scrollTo?.(href);
|
||||
};
|
||||
|
||||
renderAnchorLink = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, href, title, children, className, target } = this.props;
|
||||
return (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
|
||||
const active = this.context.activeLink === href;
|
||||
const wrapperClassName = classNames(
|
||||
`${prefixCls}-link`,
|
||||
{
|
||||
const active = activeLink === href;
|
||||
const wrapperClassName = classNames(`${prefixCls}-link`, className, {
|
||||
[`${prefixCls}-link-active`]: active,
|
||||
},
|
||||
className,
|
||||
);
|
||||
});
|
||||
const titleClassName = classNames(`${prefixCls}-link-title`, {
|
||||
[`${prefixCls}-link-title-active`]: active,
|
||||
});
|
||||
@ -67,18 +51,16 @@ class AnchorLink extends React.Component<AnchorLinkProps, any, AntAnchor> {
|
||||
href={href}
|
||||
title={typeof title === 'string' ? title : ''}
|
||||
target={target}
|
||||
onClick={this.handleClick}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{title}
|
||||
</a>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</ConfigConsumer>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderAnchorLink}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
export default AnchorLink;
|
||||
|
@ -41,11 +41,17 @@ describe('Anchor Render', () => {
|
||||
getClientRectsMock.mockReturnValue({ length: 1 } as DOMRectList);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
getBoundingClientRectMock.mockRestore();
|
||||
getClientRectsMock.mockRestore();
|
||||
@ -69,7 +75,7 @@ describe('Anchor Render', () => {
|
||||
expect(anchorInstance!.state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', () => {
|
||||
it('Anchor render perfectly for complete href - click', async () => {
|
||||
const hash = getHashUrl();
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
@ -82,6 +88,7 @@ describe('Anchor Render', () => {
|
||||
</Anchor>,
|
||||
);
|
||||
fireEvent.click(container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!);
|
||||
await waitFakeTimer();
|
||||
expect(anchorInstance!.state!.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
@ -100,13 +107,12 @@ describe('Anchor Render', () => {
|
||||
</Anchor>,
|
||||
);
|
||||
anchorInstance!.handleScrollTo('/#/faq?locale=en#Q1');
|
||||
expect(anchorInstance!.state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await waitFakeTimer();
|
||||
expect(anchorInstance!.state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
it('Anchor render perfectly for complete href - scroll', async () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
render(<div id={hash}>Hello</div>, { container: root });
|
||||
@ -121,6 +127,7 @@ describe('Anchor Render', () => {
|
||||
</Anchor>,
|
||||
);
|
||||
anchorInstance!.handleScroll();
|
||||
await waitFakeTimer();
|
||||
expect(anchorInstance!.state!.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
@ -141,10 +148,10 @@ describe('Anchor Render', () => {
|
||||
);
|
||||
|
||||
anchorInstance!.handleScrollTo(`##${hash}`);
|
||||
await waitFakeTimer();
|
||||
expect(anchorInstance!.state.activeLink).toBe(`##${hash}`);
|
||||
const calls = scrollToSpy.mock.calls.length;
|
||||
await waitFakeTimer();
|
||||
expect(scrollToSpy.mock.calls.length).toBeGreaterThan(calls);
|
||||
expect(scrollToSpy.mock.calls.length).toBe(calls);
|
||||
});
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
@ -373,7 +380,7 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('Anchor targetOffset prop', async () => {
|
||||
const hash = getHashUrl();
|
||||
let dateNowMock;
|
||||
let dateNowMock: jest.SpyInstance;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
@ -438,7 +445,7 @@ describe('Anchor Render', () => {
|
||||
// https://github.com/ant-design/ant-design/issues/31941
|
||||
it('Anchor targetOffset prop when contain spaces', async () => {
|
||||
const hash = `${getHashUrl()} s p a c e s`;
|
||||
let dateNowMock;
|
||||
let dateNowMock: jest.SpyInstance;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
@ -543,13 +550,9 @@ describe('Anchor Render', () => {
|
||||
});
|
||||
|
||||
it('test edge case when getBoundingClientRect return zero size', async () => {
|
||||
getBoundingClientRectMock.mockReturnValue({
|
||||
width: 0,
|
||||
height: 0,
|
||||
top: 1000,
|
||||
} as DOMRect);
|
||||
getBoundingClientRectMock.mockReturnValue({ width: 0, height: 0, top: 1000 } as DOMRect);
|
||||
const hash = getHashUrl();
|
||||
let dateNowMock;
|
||||
let dateNowMock: jest.SpyInstance;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
@ -615,7 +618,7 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('test edge case when container is not windows', async () => {
|
||||
const hash = getHashUrl();
|
||||
let dateNowMock;
|
||||
let dateNowMock: jest.SpyInstance;
|
||||
|
||||
function dataNowMockFn() {
|
||||
let start = 0;
|
||||
@ -758,5 +761,15 @@ describe('Anchor Render', () => {
|
||||
rerender(<Demo current={hash2} />);
|
||||
expect(container.querySelector(`.ant-anchor-link-title-active`)?.textContent).toBe(hash2);
|
||||
});
|
||||
it('should correct render when href is null', () => {
|
||||
expect(() => {
|
||||
render(
|
||||
<Anchor>
|
||||
<Link href={null as unknown as string} title="test" />
|
||||
</Anchor>,
|
||||
);
|
||||
fireEvent.scroll(window || document);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import type { AntAnchor } from './Anchor';
|
||||
|
||||
const AnchorContext = React.createContext<AntAnchor>(null as any);
|
||||
const AnchorContext = React.createContext<AntAnchor | undefined>(undefined);
|
||||
|
||||
export default AnchorContext;
|
||||
|
@ -619,37 +619,48 @@ describe('Form', () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const shouldNotRender = jest.fn();
|
||||
const StaticInput: React.FC = () => {
|
||||
const StaticInput: React.FC<React.InputHTMLAttributes<HTMLInputElement>> = ({
|
||||
id,
|
||||
value = '',
|
||||
}) => {
|
||||
shouldNotRender();
|
||||
return <Input />;
|
||||
return <input id={id} value={value} />;
|
||||
};
|
||||
|
||||
const shouldRender = jest.fn();
|
||||
const DynamicInput: React.FC = () => {
|
||||
const DynamicInput: React.FC<React.InputHTMLAttributes<HTMLInputElement>> = ({
|
||||
value = '',
|
||||
id,
|
||||
}) => {
|
||||
shouldRender();
|
||||
return <Input />;
|
||||
return <input id={id} value={value} />;
|
||||
};
|
||||
|
||||
const formRef = React.createRef<FormInstance>();
|
||||
|
||||
pureRender(
|
||||
const { container } = pureRender(
|
||||
<Form ref={formRef}>
|
||||
<Form.Item>
|
||||
<StaticInput />
|
||||
</Form.Item>
|
||||
<Form.Item name="light">
|
||||
<DynamicInput />
|
||||
<DynamicInput id="changed" />
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(container.querySelector<HTMLInputElement>('#changed')!.value).toEqual('');
|
||||
expect(shouldNotRender).toHaveBeenCalledTimes(1);
|
||||
expect(shouldRender).toHaveBeenCalledTimes(1);
|
||||
|
||||
formRef.current?.setFieldsValue({ light: 'bamboo' });
|
||||
formRef.current!.setFieldsValue({ light: 'bamboo' });
|
||||
await waitFakeTimer(100, 100);
|
||||
|
||||
await waitFakeTimer();
|
||||
expect(formRef.current!.getFieldsValue()).toEqual({ light: 'bamboo' });
|
||||
|
||||
expect(container.querySelector<HTMLInputElement>('#changed')!.value).toEqual('bamboo');
|
||||
expect(shouldNotRender).toHaveBeenCalledTimes(1);
|
||||
expect(shouldRender).toHaveBeenCalledTimes(2);
|
||||
|
||||
|
@ -18,7 +18,8 @@ const localeValues: Locale = {
|
||||
filterConfirm: 'OK',
|
||||
filterReset: 'Réinitialiser',
|
||||
filterEmptyText: 'Aucun filtre',
|
||||
filterCheckall: 'Sélectionner la page actuelle',
|
||||
filterCheckall: 'Tout sélectionner',
|
||||
filterSearchPlaceholder: 'Chercher dans les filtres',
|
||||
emptyText: 'Aucune donnée',
|
||||
selectAll: 'Sélectionner la page actuelle',
|
||||
selectInvert: 'Inverser la sélection de la page actuelle',
|
||||
|
@ -146,7 +146,7 @@ One of the Table `columns` prop for describing the table's columns, Column has t
|
||||
| showSorterTooltip | If header show next sorter direction tooltip, override `showSorterTooltip` in table | boolean \| [Tooltip props](/components/tooltip/) | true | |
|
||||
| sortDirections | Supported sort way, override `sortDirections` in `Table`, could be `ascend`, `descend` | Array | \[`ascend`, `descend`] | |
|
||||
| sorter | Sort function for local sort, see [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)'s compareFunction. If you need sort buttons only, set to `true` | function \| boolean | - | |
|
||||
| sortOrder | Order of sorted values: `'ascend'` `'descend'` `false` | boolean \| string | - | |
|
||||
| sortOrder | Order of sorted values: `ascend` `descend` `null` | `ascend` \| `descend` \| null | - | |
|
||||
| title | Title of this column | ReactNode \| ({ sortOrder, sortColumn, filters }) => ReactNode | - | |
|
||||
| width | Width of this column ([width not working?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string \| number | - | |
|
||||
| onCell | Set props on per cell | function(record, rowIndex) | - | |
|
||||
|
@ -147,7 +147,7 @@ const columns = [
|
||||
| showSorterTooltip | 表头显示下一次排序的 tooltip 提示, 覆盖 table 中 `showSorterTooltip` | boolean \| [Tooltip props](/components/tooltip/#API) | true | |
|
||||
| sortDirections | 支持的排序方式,覆盖 `Table` 中 `sortDirections`, 取值为 `ascend` `descend` | Array | \[`ascend`, `descend`] | |
|
||||
| sorter | 排序函数,本地排序使用一个函数(参考 [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 的 compareFunction),需要服务端排序可设为 true | function \| boolean | - | |
|
||||
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `ascend` `descend` false | boolean \| string | - | |
|
||||
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `ascend` `descend` `null` | `ascend` \| `descend` \| null | - | |
|
||||
| title | 列头显示文字(函数用法 `3.10.0` 后支持) | ReactNode \| ({ sortOrder, sortColumn, filters }) => ReactNode | - | |
|
||||
| width | 列宽度([指定了也不生效?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string \| number | - | |
|
||||
| onCell | 设置单元格属性 | function(record, rowIndex) | - | |
|
||||
|
@ -111,7 +111,7 @@ File icon realize by using switcherIcon. You can overwrite the style to hide it:
|
||||
|
||||
### Why defaultExpandAll not working on ajax data?
|
||||
|
||||
`default` prefix prop only works when inited. So `defaultExpandAll` has already executed when ajax load data. You can control `expandedKeys` or render Tree when data loaded to realize expanded all.
|
||||
`default` prefix prop only works when initializing. So `defaultExpandAll` has already executed when ajax load data. You can control `expandedKeys` or render Tree when data loaded to realize expanded all.
|
||||
|
||||
### Virtual scroll limitation
|
||||
|
||||
|
@ -4,7 +4,9 @@
|
||||
@select-tree-prefix-cls: ~'@{ant-prefix}-select-tree';
|
||||
@tree-motion: ~'@{ant-prefix}-motion-collapse';
|
||||
@tree-node-padding: (@padding-xs / 2);
|
||||
// @deprecated: kept for customization usages, recommend using @tree-node-highlight-color instead.
|
||||
@tree-node-hightlight-color: inherit;
|
||||
@tree-node-highlight-color: @tree-node-hightlight-color;
|
||||
|
||||
.antTreeSwitcherIcon(@type: 'tree-default-open-icon') {
|
||||
.@{tree-prefix-cls}-switcher-icon,
|
||||
@ -114,7 +116,7 @@
|
||||
}
|
||||
|
||||
&:not(&-disabled).filter-node .@{custom-tree-prefix-cls}-title {
|
||||
color: @tree-node-hightlight-color;
|
||||
color: @tree-node-highlight-color;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,13 @@ const WALKING = 2;
|
||||
const DONE_WITH_ELLIPSIS = 3;
|
||||
const DONE_WITHOUT_ELLIPSIS = 4;
|
||||
|
||||
type WalkingState =
|
||||
| typeof NONE
|
||||
| typeof PREPARE
|
||||
| typeof WALKING
|
||||
| typeof DONE_WITH_ELLIPSIS
|
||||
| typeof DONE_WITHOUT_ELLIPSIS;
|
||||
|
||||
const Ellipsis = ({
|
||||
enabledMeasure,
|
||||
children,
|
||||
@ -76,20 +83,15 @@ const Ellipsis = ({
|
||||
rows,
|
||||
onEllipsis,
|
||||
}: EllipsisProps) => {
|
||||
const [cutLength, setCutLength] = React.useState<[number, number, number]>([0, 0, 0]);
|
||||
const [walkingState, setWalkingState] = React.useState<
|
||||
| typeof NONE
|
||||
| typeof PREPARE
|
||||
| typeof WALKING
|
||||
| typeof DONE_WITH_ELLIPSIS
|
||||
| typeof DONE_WITHOUT_ELLIPSIS
|
||||
>(NONE);
|
||||
const [startLen, midLen, endLen] = cutLength;
|
||||
const [[startLen, midLen, endLen], setCutLength] = React.useState<
|
||||
[startLen: number, midLen: number, endLen: number]
|
||||
>([0, 0, 0]);
|
||||
const [walkingState, setWalkingState] = React.useState<WalkingState>(NONE);
|
||||
|
||||
const [singleRowHeight, setSingleRowHeight] = React.useState(0);
|
||||
|
||||
const singleRowRef = React.useRef<HTMLSpanElement>(null);
|
||||
const midRowRef = React.useRef<HTMLSpanElement>(null);
|
||||
const singleRowRef = React.useRef<HTMLElement>(null);
|
||||
const midRowRef = React.useRef<HTMLElement>(null);
|
||||
|
||||
const nodeList = React.useMemo(() => toArray(text), [text]);
|
||||
const totalLen = React.useMemo(() => getNodesLen(nodeList), [nodeList]);
|
||||
@ -167,7 +169,7 @@ const Ellipsis = ({
|
||||
|
||||
const renderMeasure = (
|
||||
content: React.ReactNode,
|
||||
ref: React.Ref<HTMLSpanElement>,
|
||||
ref: React.Ref<HTMLElement>,
|
||||
style: React.CSSProperties,
|
||||
) => (
|
||||
<span
|
||||
@ -189,7 +191,7 @@ const Ellipsis = ({
|
||||
</span>
|
||||
);
|
||||
|
||||
const renderMeasureSlice = (len: number, ref: React.Ref<HTMLSpanElement>) => {
|
||||
const renderMeasureSlice = (len: number, ref: React.Ref<HTMLElement>) => {
|
||||
const sliceNodeList = sliceNodes(nodeList, len);
|
||||
|
||||
return renderMeasure(children(sliceNodeList, true), ref, measureStyle);
|
||||
|
@ -60,7 +60,8 @@ export interface EllipsisConfig {
|
||||
tooltip?: React.ReactNode | TooltipProps;
|
||||
}
|
||||
|
||||
export interface BlockProps extends TypographyProps {
|
||||
export interface BlockProps<C extends keyof JSX.IntrinsicElements = keyof JSX.IntrinsicElements>
|
||||
extends TypographyProps<C> {
|
||||
title?: string;
|
||||
editable?: boolean | EditConfig;
|
||||
copyable?: boolean | CopyConfig;
|
||||
@ -114,13 +115,9 @@ function toList<T extends any>(val: T | T[]): T[] {
|
||||
return Array.isArray(val) ? val : [val];
|
||||
}
|
||||
|
||||
interface InternalBlockProps extends BlockProps {
|
||||
component: string;
|
||||
}
|
||||
|
||||
const ELLIPSIS_STR = '...';
|
||||
|
||||
const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
const Base = React.forwardRef<HTMLElement, BlockProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
@ -152,7 +149,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
'strong',
|
||||
'keyboard',
|
||||
'italic',
|
||||
]) as any;
|
||||
]);
|
||||
|
||||
// ========================== Editable ==========================
|
||||
const [enableEdit, editConfig] = useMergedConfig<EditConfig>(editable);
|
||||
@ -176,7 +173,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
}
|
||||
}, [editing]);
|
||||
|
||||
const onEditClick = (e?: React.MouseEvent<HTMLDivElement>) => {
|
||||
const onEditClick = (e?: React.MouseEvent<HTMLElement>) => {
|
||||
e?.preventDefault();
|
||||
triggerEdit(true);
|
||||
};
|
||||
@ -194,7 +191,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
// ========================== Copyable ==========================
|
||||
const [enableCopy, copyConfig] = useMergedConfig<CopyConfig>(copyable);
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
const copyIdRef = React.useRef<NodeJS.Timeout>();
|
||||
const copyIdRef = React.useRef<number>();
|
||||
|
||||
const copyOptions: Pick<CopyConfig, 'format'> = {};
|
||||
if (copyConfig.format) {
|
||||
@ -202,7 +199,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
}
|
||||
|
||||
const cleanCopyId = () => {
|
||||
clearTimeout(copyIdRef.current!);
|
||||
window.clearTimeout(copyIdRef.current!);
|
||||
};
|
||||
|
||||
const onCopyClick = (e?: React.MouseEvent<HTMLDivElement>) => {
|
||||
@ -215,7 +212,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
|
||||
// Trigger tips update
|
||||
cleanCopyId();
|
||||
copyIdRef.current = setTimeout(() => {
|
||||
copyIdRef.current = window.setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 3000);
|
||||
|
||||
@ -352,7 +349,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
tooltipProps = { title: ellipsisConfig.tooltip };
|
||||
}
|
||||
const topAriaLabel = React.useMemo(() => {
|
||||
const isValid = (val: any) => ['string', 'number'].includes(typeof val);
|
||||
const isValid = (val: any): val is string | number => ['string', 'number'].includes(typeof val);
|
||||
|
||||
if (!enableEllipsis || cssEllipsis) {
|
||||
return undefined;
|
||||
@ -495,7 +492,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
|
||||
return (
|
||||
<ResizeObserver onResize={onResize} disabled={!mergedEnableEllipsis || cssEllipsis}>
|
||||
{resizeRef => (
|
||||
{(resizeRef: React.RefObject<HTMLElement>) => (
|
||||
<EllipsisTooltip
|
||||
tooltipProps={tooltipProps}
|
||||
enabledEllipsis={mergedEnableEllipsis}
|
||||
@ -520,8 +517,8 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
|
||||
component={component}
|
||||
ref={composeRef(resizeRef, typographyRef, ref)}
|
||||
direction={direction}
|
||||
onClick={triggerType.includes('text') ? onEditClick : null}
|
||||
aria-label={topAriaLabel}
|
||||
onClick={triggerType.includes('text') ? onEditClick : undefined}
|
||||
aria-label={topAriaLabel?.toString()}
|
||||
title={title}
|
||||
{...textProps}
|
||||
>
|
||||
|
@ -4,15 +4,12 @@ import type { BlockProps } from './Base';
|
||||
import Base from './Base';
|
||||
|
||||
export interface LinkProps
|
||||
extends BlockProps,
|
||||
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'type'> {
|
||||
extends BlockProps<'a'>,
|
||||
Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'type' | keyof BlockProps<'a'>> {
|
||||
ellipsis?: boolean;
|
||||
}
|
||||
|
||||
const Link: React.ForwardRefRenderFunction<HTMLElement, LinkProps> = (
|
||||
{ ellipsis, rel, ...restProps },
|
||||
ref,
|
||||
) => {
|
||||
const Link = React.forwardRef<HTMLElement, LinkProps>(({ ellipsis, rel, ...restProps }, ref) => {
|
||||
warning(
|
||||
typeof ellipsis !== 'object',
|
||||
'Typography.Link',
|
||||
@ -28,11 +25,10 @@ const Link: React.ForwardRefRenderFunction<HTMLElement, LinkProps> = (
|
||||
rel: rel === undefined && restProps.target === '_blank' ? 'noopener noreferrer' : rel,
|
||||
};
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/26622
|
||||
// @ts-ignore
|
||||
// @ts-expect-error: https://github.com/ant-design/ant-design/issues/26622
|
||||
delete mergedProps.navigate;
|
||||
|
||||
return <Base {...mergedProps} ref={baseRef} ellipsis={!!ellipsis} component="a" />;
|
||||
};
|
||||
});
|
||||
|
||||
export default React.forwardRef(Link);
|
||||
export default Link;
|
||||
|
@ -2,12 +2,12 @@ import * as React from 'react';
|
||||
import type { BlockProps } from './Base';
|
||||
import Base from './Base';
|
||||
|
||||
export interface ParagraphProps extends BlockProps {
|
||||
onClick?: (e?: React.MouseEvent<HTMLDivElement>) => void;
|
||||
}
|
||||
export interface ParagraphProps
|
||||
extends BlockProps<'div'>,
|
||||
Omit<React.HTMLAttributes<HTMLDivElement>, 'type' | keyof BlockProps<'div'>> {}
|
||||
|
||||
const Paragraph: React.ForwardRefRenderFunction<HTMLDivElement, ParagraphProps> = (props, ref) => (
|
||||
const Paragraph = React.forwardRef<HTMLElement, ParagraphProps>((props, ref) => (
|
||||
<Base ref={ref} {...props} component="div" />
|
||||
);
|
||||
));
|
||||
|
||||
export default React.forwardRef(Paragraph);
|
||||
export default Paragraph;
|
||||
|
@ -4,9 +4,10 @@ import warning from '../_util/warning';
|
||||
import type { BlockProps, EllipsisConfig } from './Base';
|
||||
import Base from './Base';
|
||||
|
||||
export interface TextProps extends BlockProps {
|
||||
export interface TextProps
|
||||
extends BlockProps<'span'>,
|
||||
Omit<React.HTMLAttributes<HTMLSpanElement>, 'type' | keyof BlockProps<'span'>> {
|
||||
ellipsis?: boolean | Omit<EllipsisConfig, 'expandable' | 'rows' | 'onExpand'>;
|
||||
onClick?: (e?: React.MouseEvent<HTMLDivElement>) => void;
|
||||
}
|
||||
|
||||
const Text: React.ForwardRefRenderFunction<HTMLSpanElement, TextProps> = (
|
||||
|
@ -6,17 +6,18 @@ import Base from './Base';
|
||||
|
||||
const TITLE_ELE_LIST = tupleNum(1, 2, 3, 4, 5);
|
||||
|
||||
export type TitleProps = Omit<
|
||||
BlockProps & {
|
||||
export interface TitleProps
|
||||
extends Omit<BlockProps<'h1' | 'h2' | 'h3' | 'h4' | 'h5'>, 'strong'>,
|
||||
Omit<
|
||||
React.HTMLAttributes<HTMLHeadElement>,
|
||||
'type' | keyof BlockProps<'h1' | 'h2' | 'h3' | 'h4' | 'h5'>
|
||||
> {
|
||||
level?: typeof TITLE_ELE_LIST[number];
|
||||
onClick?: (e?: React.MouseEvent<HTMLDivElement>) => void;
|
||||
},
|
||||
'strong'
|
||||
>;
|
||||
}
|
||||
|
||||
const Title: React.ForwardRefRenderFunction<HTMLHeadingElement, TitleProps> = (props, ref) => {
|
||||
const Title = React.forwardRef<HTMLElement, TitleProps>((props, ref) => {
|
||||
const { level = 1, ...restProps } = props;
|
||||
let component: string;
|
||||
let component: keyof JSX.IntrinsicElements;
|
||||
|
||||
if (TITLE_ELE_LIST.indexOf(level) !== -1) {
|
||||
component = `h${level}`;
|
||||
@ -30,6 +31,6 @@ const Title: React.ForwardRefRenderFunction<HTMLHeadingElement, TitleProps> = (p
|
||||
}
|
||||
|
||||
return <Base ref={ref} {...restProps} component={component} />;
|
||||
};
|
||||
});
|
||||
|
||||
export default React.forwardRef(Title);
|
||||
export default Title;
|
||||
|
@ -1,37 +1,48 @@
|
||||
import classNames from 'classnames';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
import * as React from 'react';
|
||||
import type { DirectionType } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import warning from '../_util/warning';
|
||||
|
||||
export interface TypographyProps {
|
||||
export interface TypographyProps<C extends keyof JSX.IntrinsicElements>
|
||||
extends React.HTMLAttributes<HTMLElement> {
|
||||
id?: string;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
/** @internal */
|
||||
component?: C;
|
||||
['aria-label']?: string;
|
||||
direction?: DirectionType;
|
||||
}
|
||||
|
||||
interface InternalTypographyProps extends TypographyProps {
|
||||
component?: string;
|
||||
interface InternalTypographyProps<C extends keyof JSX.IntrinsicElements>
|
||||
extends TypographyProps<C> {
|
||||
/** @deprecated Use `ref` directly if using React 16 */
|
||||
setContentRef?: (node: HTMLElement) => void;
|
||||
}
|
||||
|
||||
const Typography: React.ForwardRefRenderFunction<{}, InternalTypographyProps> = (
|
||||
const Typography = React.forwardRef<
|
||||
HTMLElement,
|
||||
InternalTypographyProps<keyof JSX.IntrinsicElements>
|
||||
>(
|
||||
(
|
||||
{
|
||||
prefixCls: customizePrefixCls,
|
||||
component = 'article',
|
||||
component: Component = 'article',
|
||||
className,
|
||||
'aria-label': ariaLabel,
|
||||
setContentRef,
|
||||
children,
|
||||
direction: typographyDirection,
|
||||
...restProps
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const { getPrefixCls, direction: contextDirection } = React.useContext(ConfigContext);
|
||||
|
||||
const direction = typographyDirection ?? contextDirection;
|
||||
|
||||
let mergedRef = ref;
|
||||
if (setContentRef) {
|
||||
@ -39,7 +50,6 @@ const Typography: React.ForwardRefRenderFunction<{}, InternalTypographyProps> =
|
||||
mergedRef = composeRef(ref, setContentRef);
|
||||
}
|
||||
|
||||
const Component = component as any;
|
||||
const prefixCls = getPrefixCls('typography', customizePrefixCls);
|
||||
const componentClassName = classNames(
|
||||
prefixCls,
|
||||
@ -48,19 +58,19 @@ const Typography: React.ForwardRefRenderFunction<{}, InternalTypographyProps> =
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<Component className={componentClassName} aria-label={ariaLabel} ref={mergedRef} {...restProps}>
|
||||
// @ts-expect-error: Expression produces a union type that is too complex to represent.
|
||||
<Component className={componentClassName} ref={mergedRef} {...restProps}>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const RefTypography = React.forwardRef(Typography);
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
RefTypography.displayName = 'Typography';
|
||||
Typography.displayName = 'Typography';
|
||||
}
|
||||
|
||||
// es default export should use const instead of let
|
||||
const ExportTypography = RefTypography as unknown as React.FC<TypographyProps>;
|
||||
|
||||
export default ExportTypography;
|
||||
export default Typography;
|
||||
|
@ -3,27 +3,23 @@
|
||||
exports[`Typography rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<div
|
||||
class="ant-typography ant-typography-rtl"
|
||||
direction="rtl"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Typography rtl render component should be rendered correctly in RTL direction 2`] = `
|
||||
<article
|
||||
class="ant-typography ant-typography-rtl"
|
||||
direction="rtl"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Typography rtl render component should be rendered correctly in RTL direction 3`] = `
|
||||
<h1
|
||||
class="ant-typography ant-typography-rtl"
|
||||
direction="rtl"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Typography rtl render component should be rendered correctly in RTL direction 4`] = `
|
||||
<a
|
||||
class="ant-typography ant-typography-rtl"
|
||||
direction="rtl"
|
||||
/>
|
||||
`;
|
||||
|
@ -382,21 +382,14 @@ describe('Typography.Ellipsis', () => {
|
||||
|
||||
it('js ellipsis should show aria-label', () => {
|
||||
const { container: titleWrapper } = render(
|
||||
<Base
|
||||
component={undefined as unknown as string}
|
||||
title="bamboo"
|
||||
ellipsis={{ expandable: true }}
|
||||
/>,
|
||||
<Base component={undefined} title="bamboo" ellipsis={{ expandable: true }} />,
|
||||
);
|
||||
expect(titleWrapper.querySelector('.ant-typography')?.getAttribute('aria-label')).toEqual(
|
||||
'bamboo',
|
||||
);
|
||||
|
||||
const { container: tooltipWrapper } = render(
|
||||
<Base
|
||||
component={undefined as unknown as string}
|
||||
ellipsis={{ expandable: true, tooltip: 'little' }}
|
||||
/>,
|
||||
<Base component={undefined} ellipsis={{ expandable: true, tooltip: 'little' }} />,
|
||||
);
|
||||
expect(tooltipWrapper.querySelector('.ant-typography')?.getAttribute('aria-label')).toEqual(
|
||||
'little',
|
||||
@ -426,11 +419,7 @@ describe('Typography.Ellipsis', () => {
|
||||
|
||||
const ref = React.createRef<any>();
|
||||
const { container, baseElement } = render(
|
||||
<Base
|
||||
component={undefined as unknown as string}
|
||||
ellipsis={{ tooltip: 'This is tooltip', rows: 2 }}
|
||||
ref={ref}
|
||||
>
|
||||
<Base component={undefined} ellipsis={{ tooltip: 'This is tooltip', rows: 2 }} ref={ref}>
|
||||
Ant Design, a design language for background applications, is refined by Ant UED Team.
|
||||
</Base>,
|
||||
);
|
||||
|
@ -1,17 +0,0 @@
|
||||
version: '3'
|
||||
services:
|
||||
tests:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.ui-test
|
||||
volumes:
|
||||
- './node_modules:/app/node_modules'
|
||||
- './components:/app/components'
|
||||
- './tests:/app/tests'
|
||||
- './jest-stare:/app/jest-stare'
|
||||
- './dist:/app/dist'
|
||||
- '.jest.image.js:/app/.jest.image.js'
|
||||
- './jest-puppeteer.config.js:/app/jest-puppeteer.config.js'
|
||||
- './imageSnapshots:/app/imageSnapshots'
|
||||
- './imageDiffSnapshots:/app/imageDiffSnapshots'
|
||||
entrypoint: "npm run test-image:docker"
|
@ -98,8 +98,7 @@
|
||||
"test-node": "jest --config .jest.node.js --cache=false",
|
||||
"tsc": "tsc --noEmit",
|
||||
"site:test": "jest --config .jest.site.js --cache=false --force-exit",
|
||||
"test-image": "npm run dist && docker-compose run tests",
|
||||
"test-image:docker": "node node_modules/puppeteer/install.js && jest --config .jest.image.js --no-cache -i",
|
||||
"test-image": "npm run dist && jest --config .jest.image.js --no-cache -i -u",
|
||||
"argos": "node ./scripts/argos-upload.js",
|
||||
"version": "node ./scripts/generate-version",
|
||||
"install-react-16": "npm i --no-save --legacy-peer-deps react@16 react-dom@16",
|
||||
@ -191,7 +190,7 @@
|
||||
"@types/warning": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"antd-img-crop": "4.2.5",
|
||||
"antd-img-crop": "^4.2.8",
|
||||
"array-move": "^4.0.0",
|
||||
"babel-plugin-add-react-displayname": "^0.0.5",
|
||||
"bisheng": "^3.7.0-alpha.4",
|
||||
|
@ -47,7 +47,7 @@ async function run() {
|
||||
token: process.env.ARGOS_TOKEN,
|
||||
parallel: {
|
||||
total: chunks.length,
|
||||
nonce: process.env.ARGOS_PARALLEL_NONCE,
|
||||
nonce: process.env.ARGOS_PARALLEL_NONCE || process.env.CIRCLE_BUILD_NUM,
|
||||
},
|
||||
});
|
||||
// eslint-disable-next-line no-console -- pipe stdout
|
||||
|
Loading…
Reference in New Issue
Block a user