Skip to content

refactor(3.x/button): use composition api #4291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/_util/hooks/useConfigInject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ export default (
form?: ComputedRef<{
requiredMark?: RequiredMark;
}>;
autoInsertSpaceInButton: ComputedRef<Boolean>;
} => {
const configProvider = inject<UnwrapRef<ConfigProviderProps>>(
'configProvider',
defaultConfigProvider,
);
const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls));
const direction = computed(() => configProvider.direction);
const autoInsertSpaceInButton = computed(() => configProvider.autoInsertSpaceInButton);
const space = computed(() => configProvider.space);
const pageHeader = computed(() => configProvider.pageHeader);
const form = computed(() => configProvider.form);
Expand All @@ -42,5 +44,6 @@ export default (
space,
pageHeader,
form,
autoInsertSpaceInButton,
};
};
8 changes: 4 additions & 4 deletions components/button/__tests__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`Button renders Chinese characters correctly 1`] = `

exports[`Button renders Chinese characters correctly 2`] = `
<button class="ant-btn" type="button">
<!----><span role="img" aria-label="search" class="anticon anticon-search"><svg class="" data-icon="search" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"></path></svg></span><span>按钮</span>
<!----><span role="img" aria-label="search" class="anticon anticon-search"><svg focusable="false" class="" data-icon="search" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"></path></svg></span><span>按钮</span>
</button>
`;

Expand All @@ -36,9 +36,9 @@ exports[`Button renders Chinese characters correctly 3`] = `
</button>
`;

exports[`Button renders Chinese characters correctly 4`] = `<button class="ant-btn ant-btn-loading" type="button"><span role="img" aria-label="loading" class="anticon anticon-loading"><svg class="anticon-spin" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024" focusable="false"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></span><span>按 钮</span></button>`;
exports[`Button renders Chinese characters correctly 4`] = `<button class="ant-btn ant-btn-loading" type="button"><span role="img" aria-label="loading" class="anticon anticon-loading"><svg focusable="false" class="anticon-spin" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></span><span>按 钮</span></button>`;

exports[`Button renders Chinese characters correctly 5`] = `<button class="ant-btn ant-btn-loading" type="button"><span role="img" aria-label="loading" class="anticon anticon-loading"><svg class="anticon-spin" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024" focusable="false"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></span><span>按 钮</span></button>`;
exports[`Button renders Chinese characters correctly 5`] = `<button class="ant-btn ant-btn-loading" type="button"><span role="img" aria-label="loading" class="anticon anticon-loading"><svg focusable="false" class="anticon-spin" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></span><span>按 钮</span></button>`;

exports[`Button renders Chinese characters correctly 6`] = `
<button class="ant-btn ant-btn-two-chinese-chars" type="button">
Expand All @@ -59,7 +59,7 @@ exports[`Button should not render as link button when href is undefined 1`] = `
`;

exports[`Button should support link button 1`] = `
<a target="_blank" class="ant-btn" href="http://ant.design">
<a class="ant-btn" href="http://ant.design" target="_blank">
<!----><span>link button</span>
</a>
`;
55 changes: 51 additions & 4 deletions components/button/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Button from '../index';
import SearchOutlined from '@ant-design/icons-vue/SearchOutlined';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { asyncExpect } from '@/tests/utils';
import { sleep } from '../../../tests/utils';
import mountTest from '../../../tests/shared/mountTest';
import { asyncExpect, sleep } from '@/tests/utils';
import mountTest from '@/tests/shared/mountTest';
import { resetWarned } from '../../_util/warning';

describe('Button', () => {
mountTest(Button);
Expand All @@ -27,7 +27,7 @@ describe('Button', () => {
expect(wrapper.find('.ant-btn-primary').exists()).toBe(true);
});

it('renders Chinese characters correctly', done => {
it('renders Chinese characters correctly', (done) => {
const wrapper = mount({
render() {
return <Button>按钮</Button>;
Expand Down Expand Up @@ -247,4 +247,51 @@ describe('Button', () => {
wrapper.unmount();
}).not.toThrow();
});

it('should warning when pass type=link and ghost=true', () => {
resetWarned();
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount({
render() {
return <Button type="link" ghost />;
},
});
expect(warnSpy).toHaveBeenCalledWith(
"Warning: [ant-design-vue: Button] `link` or `text` button can't be a `ghost` button.",
);
warnSpy.mockRestore();
});

it('should warning when pass type=text and ghost=true', () => {
resetWarned();
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount({
render() {
return <Button type="text" ghost />;
},
});
expect(warnSpy).toHaveBeenCalledWith(
"Warning: [ant-design-vue: Button] `link` or `text` button can't be a `ghost` button.",
);
warnSpy.mockRestore();
});

it('should not redirect when button is disabled', async () => {
const onClick = jest.fn();
const wrapper = mount({
render() {
return (
<Button href="https://ant.design" onClick={onClick} disabled>
click me
</Button>
);
},
});
await asyncExpect(() => {
wrapper.trigger('click');
});
await asyncExpect(() => {
expect(onClick).not.toHaveBeenCalled();
});
});
});
79 changes: 79 additions & 0 deletions components/button/__tests__/wave.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Button from '../index';
import { mount } from '@vue/test-utils';
import { asyncExpect, sleep } from '@/tests/utils';

describe('click wave effect', () => {
async function clickButton(wrapper) {
await asyncExpect(() => {
wrapper.find('.ant-btn').trigger('click');
});
wrapper.find('.ant-btn').element.dispatchEvent(new Event('transitionstart'));
await sleep(20);
wrapper.find('.ant-btn').element.dispatchEvent(new Event('animationend'));
await sleep(20);
}

it('should have click wave effect for primary button', async () => {
const wrapper = mount({
render() {
return <Button type="primary">button</Button>;
},
});
await clickButton(wrapper);
expect(wrapper.find('.ant-btn').attributes('ant-click-animating-without-extra-node')).toBe(
'true',
);
});

it('should have click wave effect for default button', async () => {
const wrapper = mount({
render() {
return <Button>button</Button>;
},
});
await clickButton(wrapper);
expect(wrapper.find('.ant-btn').attributes('ant-click-animating-without-extra-node')).toBe(
'true',
);
});

it('should not have click wave effect for link type button', async () => {
const wrapper = mount({
render() {
return <Button type="link">button</Button>;
},
});
await clickButton(wrapper);
expect(wrapper.find('.ant-btn').attributes('ant-click-animating-without-extra-node')).toBe(
undefined,
);
});

it('should not have click wave effect for text type button', async () => {
const wrapper = mount({
render() {
return <Button type="text">button</Button>;
},
});
await clickButton(wrapper);
expect(wrapper.find('.ant-btn').attributes('ant-click-animating-without-extra-node')).toBe(
undefined,
);
});

it('should handle transitionstart', async () => {
const wrapper = mount({
render() {
return <Button type="primary">button</Button>;
},
});
await clickButton(wrapper);
const buttonNode = wrapper.find('.ant-btn').element;
buttonNode.dispatchEvent(new Event('transitionstart'));
expect(wrapper.find('.ant-btn').attributes('ant-click-animating-without-extra-node')).toBe(
'true',
);
wrapper.unmount();
buttonNode.dispatchEvent(new Event('transitionstart'));
});
});
82 changes: 39 additions & 43 deletions components/button/button-group.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,49 @@
import { defineComponent, inject } from 'vue';
import { filterEmpty, getSlot } from '../_util/props-util';
import { defineComponent } from 'vue';
import { flattenChildren } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
import useConfigInject from '../_util/hooks/useConfigInject';

const ButtonGroupProps = {
import type { ExtractPropTypes, PropType } from 'vue';
import type { SizeType } from '../config-provider';

const buttonGroupProps = {
prefixCls: PropTypes.string,
size: PropTypes.oneOf(tuple('small', 'large', 'default')),
size: {
type: String as PropType<SizeType>,
},
};
export { ButtonGroupProps };
export { buttonGroupProps };

export type ButtonGroupProps = Partial<ExtractPropTypes<typeof buttonGroupProps>>;

export default defineComponent({
name: 'AButtonGroup',
props: ButtonGroupProps,
setup() {
const configProvider = inject('configProvider', defaultConfigProvider);
return {
configProvider,
};
},
data() {
return {
sizeMap: {
large: 'lg',
small: 'sm',
},
};
},
render() {
const { prefixCls: customizePrefixCls, size } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('btn-group', customizePrefixCls);
props: buttonGroupProps,
setup(props, { slots }) {
const { prefixCls, direction } = useConfigInject('btn-group', props);

return () => {
const { size } = props;

// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
break;
default:
break;
}
const classes = {
[`${prefixCls}`]: true,
[`${prefixCls}-${sizeCls}`]: sizeCls,
// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
break;
default:
break;
}
const classes = {
[`${prefixCls.value}`]: true,
[`${prefixCls.value}-${sizeCls}`]: sizeCls,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
};
return <div class={classes}>{flattenChildren(slots.default?.())}</div>;
};
return <div class={classes}>{filterEmpty(getSlot(this))}</div>;
},
});
Loading