Feat v4 floatbutton (#6294)

* feat: add float-button components

* fix type &  demo display

* fix components entry

* fix review bug

* fix bug

* fix .value
pull/6348/head
果冻橙 2023-03-02 10:59:44 +08:00 committed by GitHub
parent 41a455f881
commit 3f5f3ecabf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1989 additions and 4 deletions

View File

@ -76,6 +76,9 @@ export { default as Drawer } from './drawer';
export type { EmptyProps } from './empty';
export { default as Empty } from './empty';
export type { FloatButtonProps, FloatButtonGroupProps } from './float-button/interface';
export { default as FloatButton, FloatButtonGroup } from './float-button';
export type { FormProps, FormItemProps, FormInstance, FormItemInstance } from './form';
export { default as Form, FormItem, FormItemRest } from './form';

View File

@ -0,0 +1,143 @@
import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined';
import { getTransitionProps, Transition } from '../_util/transition';
import {
defineComponent,
nextTick,
onActivated,
onBeforeUnmount,
onMounted,
reactive,
ref,
watch,
onDeactivated,
} from 'vue';
import FloatButton from './FloatButton';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import getScroll from '../_util/getScroll';
import scrollTo from '../_util/scrollTo';
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
import { initDefaultProps } from '../_util/props-util';
import { backTopProps } from './interface';
import { floatButtonPrefixCls } from './FloatButton';
import useStyle from './style';
const BackTop = defineComponent({
compatConfig: { MODE: 3 },
name: 'ABackTop',
inheritAttrs: false,
props: initDefaultProps(backTopProps(), {
visibilityHeight: 400,
target: () => window,
duration: 450,
}),
// emits: ['click'],
setup(props, { slots, attrs, emit }) {
const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props);
const [wrapSSR] = useStyle(prefixCls);
const domRef = ref();
const state = reactive({
visible: false,
scrollEvent: null,
});
const getDefaultTarget = () =>
domRef.value && domRef.value.ownerDocument ? domRef.value.ownerDocument : window;
const scrollToTop = (e: Event) => {
const { target = getDefaultTarget, duration } = props;
scrollTo(0, {
getContainer: target,
duration,
});
emit('click', e);
};
const handleScroll = throttleByAnimationFrame((e: Event | { target: any }) => {
const { visibilityHeight } = props;
const scrollTop = getScroll(e.target, true);
state.visible = scrollTop >= visibilityHeight;
});
const bindScrollEvent = () => {
const { target } = props;
const getTarget = target || getDefaultTarget;
const container = getTarget();
handleScroll({ target: container });
container?.addEventListener('scroll', handleScroll);
};
const scrollRemove = () => {
const { target } = props;
const getTarget = target || getDefaultTarget;
const container = getTarget();
handleScroll.cancel();
container?.removeEventListener('scroll', handleScroll);
};
watch(
() => props.target,
() => {
scrollRemove();
nextTick(() => {
bindScrollEvent();
});
},
);
onMounted(() => {
nextTick(() => {
bindScrollEvent();
});
});
onActivated(() => {
nextTick(() => {
bindScrollEvent();
});
});
onDeactivated(() => {
scrollRemove();
});
onBeforeUnmount(() => {
scrollRemove();
});
return () => {
const defaultElement = (
<div class={`${prefixCls.value}-content`}>
<div class={`${prefixCls.value}-icon`}>
<VerticalAlignTopOutlined />
</div>
</div>
);
const divProps = {
...attrs,
onClick: scrollToTop,
class: {
[`${prefixCls.value}`]: true,
[`${attrs.class}`]: attrs.class,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
};
const transitionProps = getTransitionProps('fade');
return wrapSSR(
<Transition {...transitionProps}>
<FloatButton v-show={state.visible} {...divProps} ref={domRef}>
{{
icon: () => <VerticalAlignTopOutlined />,
default: () => slots.default?.() || defaultElement,
}}
</FloatButton>
</Transition>,
);
};
},
});
export default BackTop;

View File

@ -0,0 +1,121 @@
import classNames from '../_util/classNames';
import { defineComponent, computed, CSSProperties, ref } from 'vue';
import Tooltip from '../tooltip';
import Content from './FloatButtonContent';
import type { FloatButtonContentProps } from './interface';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import FloatButtonGroupContext from './context';
import warning from '../_util/warning';
import { initDefaultProps } from '../_util/props-util';
import { floatButtonProps } from './interface';
// import { useCompactItemContext } from '../space/Compact';
// CSSINJS
import useStyle from './style';
export const floatButtonPrefixCls = 'float-btn';
const FloatButton = defineComponent({
compatConfig: { MODE: 3 },
name: 'AFloatButton',
inheritAttrs: false,
props: initDefaultProps(floatButtonProps(), { type: 'default', shape: 'circle' }),
setup(props, { attrs, slots, expose }) {
const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props);
const [wrapSSR, hashId] = useStyle(prefixCls);
const { shape: groupShape } = FloatButtonGroupContext.useInject();
const floatButtonRef = ref(null);
const mergeShape = computed(() => {
return groupShape?.value || props.shape;
});
expose({
floatButtonEl: floatButtonRef,
});
return () => {
const {
prefixCls: customPrefixCls,
type = 'default',
shape = 'circle',
description,
tooltip,
...restProps
} = props;
const contentProps: FloatButtonContentProps = {
prefixCls: prefixCls.value,
description,
};
const classString = classNames(
prefixCls.value,
`${prefixCls.value}-${props.type}`,
`${prefixCls.value}-${mergeShape.value}`,
{
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
attrs.class,
hashId.value,
);
const buttonNode = (
<Tooltip placement="left">
{{
title:
slots.tooltip || tooltip
? () => (slots.tooltip && slots.tooltip()) || tooltip
: undefined,
default: () => (
<div class={`${prefixCls.value}-body`}>
<Content {...contentProps}>
{{
icon: slots.icon,
description: slots.description,
}}
</Content>
</div>
),
}}
</Tooltip>
);
if (process.env.NODE_ENV !== 'production') {
warning(
!(shape === 'circle' && description),
'FloatButton',
'supported only when `shape` is `square`. Due to narrow space for text, short sentence is recommended.',
);
}
return wrapSSR(
props.href ? (
<a
ref={floatButtonRef}
{...attrs}
{...(restProps as any)}
class={classString}
style={attrs.style as CSSProperties}
>
{buttonNode}
</a>
) : (
<button
ref={floatButtonRef}
{...attrs}
{...restProps}
class={classString}
style={attrs.style as CSSProperties}
type="button"
>
{buttonNode}
</button>
),
);
};
},
});
export default FloatButton;

View File

@ -0,0 +1,41 @@
import { defineComponent } from 'vue';
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
import classNames from '../_util/classNames';
import { floatButtonContentProps } from './interface';
const FloatButtonContent = defineComponent({
compatConfig: { MODE: 3 },
name: 'AFloatButtonContent',
inheritAttrs: false,
props: floatButtonContentProps(),
setup(props, { attrs, slots }) {
return () => {
const { description, prefixCls } = props;
const defaultElement = (
<div class={`${prefixCls}-icon`}>
<FileTextOutlined />
</div>
);
return (
<div {...attrs} class={classNames(attrs.class, `${prefixCls}-content`)}>
{slots.icon || description ? (
<>
{slots.icon && <div class={`${prefixCls}-icon`}>{slots.icon()}</div>}
{(slots.description || description) && (
<div class={`${prefixCls}-description`}>
{(slots.description && slots.description()) || description}
</div>
)}
</>
) : (
defaultElement
)}
</div>
);
};
},
});
export default FloatButtonContent;

View File

@ -0,0 +1,132 @@
import { defineComponent, ref, computed, watch } from 'vue';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
import classNames from '../_util/classNames';
import { getTransitionProps, Transition } from '../_util/transition';
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import FloatButtonGroupContext from './context';
import { initDefaultProps } from '../_util/props-util';
import { floatButtonGroupProps } from './interface';
import type { FloatButtonGroupProps } from './interface';
// CSSINJS
import useStyle from './style';
const FloatButtonGroup = defineComponent({
compatConfig: { MODE: 3 },
name: 'AFloatButtonGroup',
inheritAttrs: false,
props: initDefaultProps(floatButtonGroupProps(), {
type: 'default',
shape: 'circle',
} as FloatButtonGroupProps),
setup(props, { attrs, slots }) {
const { prefixCls, direction } = useConfigInject(floatButtonPrefixCls, props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const open = ref(props.open);
const floatButtonGroupRef = ref<HTMLDivElement>(null);
const floatButtonRef = ref<HTMLButtonElement | HTMLAnchorElement>(null);
FloatButtonGroupContext.useProvide({
shape: computed(() => props.shape),
});
const hoverAction = computed(() => {
const hoverTypeAction = {
onMouseenter() {
open.value = true;
props.onOpenChange?.(true);
},
onMouseleave() {
open.value = false;
props.onOpenChange?.(false);
},
};
return props.trigger === 'hover' ? hoverTypeAction : {};
});
const handleOpenChange = () => {
open.value = !open.value;
props.onOpenChange?.(!open.value);
};
const onClick = (e: MouseEvent) => {
if (floatButtonGroupRef.value?.contains(e.target as Node)) {
if ((floatButtonRef.value as any)?.floatButtonEl?.contains(e.target as Node)) {
handleOpenChange();
}
return;
}
open.value = false;
props.onOpenChange?.(false);
};
watch(
computed(() => props.trigger),
value => {
if (value === 'click') {
document.addEventListener('click', onClick);
return () => {
document.removeEventListener('click', onClick);
};
}
},
{ immediate: true },
);
return () => {
const { shape = 'circle', type = 'default', tooltip, description, trigger } = props;
const groupPrefixCls = `${prefixCls.value}-group`;
const groupCls = classNames(groupPrefixCls, hashId.value, attrs.class, {
[`${groupPrefixCls}-rtl`]: direction.value === 'rtl',
[`${groupPrefixCls}-${shape}`]: shape,
[`${groupPrefixCls}-${shape}-shadow`]: !trigger,
});
const wrapperCls = classNames(hashId.value, `${groupPrefixCls}-wrap`);
const transitionProps = getTransitionProps(`${groupPrefixCls}-wrap`);
return wrapSSR(
<div ref={floatButtonGroupRef} {...attrs} class={groupCls} {...hoverAction.value}>
{trigger && ['click', 'hover'].includes(trigger) ? (
<>
<Transition {...transitionProps}>
<div v-show={open.value} class={classNames(wrapperCls)}>
{slots.default && slots.default()}
</div>
</Transition>
<FloatButton
ref={floatButtonRef}
type={type}
shape={shape}
tooltip={tooltip}
description={description}
>
{{
icon: () =>
open.value
? (slots.closeIcon && slots.closeIcon()) || <CloseOutlined />
: (slots.icon && slots.icon()) || <FileTextOutlined />,
tooltip: slots.tooltip,
description: slots.description,
}}
</FloatButton>
</>
) : (
slots.default && slots.default()
)}
</div>,
);
};
},
});
export default FloatButtonGroup;

View File

@ -0,0 +1,256 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/button/demo/basic.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary Button</span>
</button>
<button class="ant-btn" type="button">
<!----><span>Default Button</span>
</button>
<button class="ant-btn ant-btn-dashed" type="button">
<!----><span>Dashed Button</span>
</button>
<button class="ant-btn ant-btn-text" type="button">
<!----><span>Text Button</span>
</button>
<button class="ant-btn ant-btn-link" type="button">
<!----><span>Link Button</span>
</button>
`;
exports[`renders ./components/button/demo/block.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary ant-btn-block" type="button">
<!----><span>Primary</span>
</button>
<button class="ant-btn ant-btn-block" type="button">
<!----><span>Default</span>
</button>
<button class="ant-btn ant-btn-dashed ant-btn-block" type="button">
<!----><span>Dashed</span>
</button>
<button class="ant-btn ant-btn-block ant-btn-dangerous" type="button">
<!----><span>Danger</span>
</button>
<button class="ant-btn ant-btn-link ant-btn-block" type="button">
<!----><span>Link</span>
</button>
`;
exports[`renders ./components/button/demo/button-group.vue correctly 1`] = `
<div id="components-button-demo-button-group">
<h4>Basic</h4>
<div class="ant-btn-group"><button class="ant-btn" type="button">
<!----><span>Cancel</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>OK</span>
</button></div>
<div class="ant-btn-group"><button disabled="" class="ant-btn" type="button">
<!----><span>L</span>
</button><button disabled="" class="ant-btn" type="button">
<!----><span>M</span>
</button><button disabled="" class="ant-btn" type="button">
<!----><span>R</span>
</button></div>
<div class="ant-btn-group"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>L</span>
</button><button class="ant-btn" type="button">
<!----><span>M</span>
</button><button class="ant-btn" type="button">
<!----><span>M</span>
</button><button class="ant-btn ant-btn-dashed" type="button">
<!----><span>R</span>
</button></div>
<h4>With Icon</h4>
<div class="ant-btn-group"><button class="ant-btn ant-btn-primary" type="button">
<!----><span role="img" aria-label="left" class="anticon anticon-left"><svg focusable="false" class="" data-icon="left" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"></path></svg></span><span>Go back</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Go forward</span><span role="img" aria-label="right" class="anticon anticon-right"><svg focusable="false" class="" data-icon="right" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"></path></svg></span>
</button></div>
<div class="ant-btn-group"><button class="ant-btn ant-btn-primary ant-btn-icon-only" type="button"><span role="img" aria-label="cloud" class="anticon anticon-cloud"><svg focusable="false" class="" data-icon="cloud" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M811.4 418.7C765.6 297.9 648.9 212 512.2 212S258.8 297.8 213 418.6C127.3 441.1 64 519.1 64 612c0 110.5 89.5 200 199.9 200h496.2C870.5 812 960 722.5 960 612c0-92.7-63.1-170.7-148.6-193.3zm36.3 281a123.07 123.07 0 01-87.6 36.3H263.9c-33.1 0-64.2-12.9-87.6-36.3A123.3 123.3 0 01140 612c0-28 9.1-54.3 26.2-76.3a125.7 125.7 0 0166.1-43.7l37.9-9.9 13.9-36.6c8.6-22.8 20.6-44.1 35.7-63.4a245.6 245.6 0 0152.4-49.9c41.1-28.9 89.5-44.2 140-44.2s98.9 15.3 140 44.2c19.9 14 37.5 30.8 52.4 49.9 15.1 19.3 27.1 40.7 35.7 63.4l13.8 36.5 37.8 10c54.3 14.5 92.1 63.8 92.1 120 0 33.1-12.9 64.3-36.3 87.7z"></path></svg></span></button><button class="ant-btn ant-btn-primary ant-btn-icon-only" type="button"><span role="img" aria-label="cloud-download" class="anticon anticon-cloud-download"><svg focusable="false" class="" data-icon="cloud-download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M624 706.3h-74.1V464c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v242.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.7a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9z"></path><path d="M811.4 366.7C765.6 245.9 648.9 160 512.2 160S258.8 245.8 213 366.6C127.3 389.1 64 467.2 64 560c0 110.5 89.5 200 199.9 200H304c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8h-40.1c-33.7 0-65.4-13.4-89-37.7-23.5-24.2-36-56.8-34.9-90.6.9-26.4 9.9-51.2 26.2-72.1 16.7-21.3 40.1-36.8 66.1-43.7l37.9-9.9 13.9-36.6c8.6-22.8 20.6-44.1 35.7-63.4a245.6 245.6 0 0152.4-49.9c41.1-28.9 89.5-44.2 140-44.2s98.9 15.3 140 44.2c19.9 14 37.5 30.8 52.4 49.9 15.1 19.3 27.1 40.7 35.7 63.4l13.8 36.5 37.8 10C846.1 454.5 884 503.8 884 560c0 33.1-12.9 64.3-36.3 87.7a123.07 123.07 0 01-87.6 36.3H720c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h40.1C870.5 760 960 670.5 960 560c0-92.7-63.1-170.7-148.6-193.3z"></path></svg></span></button></div>
</div>
`;
exports[`renders ./components/button/demo/danger.vue correctly 1`] = `
<div><button class="ant-btn ant-btn-primary ant-btn-dangerous" type="button">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-dangerous" type="button">
<!----><span>Default</span>
</button><button class="ant-btn ant-btn-dashed ant-btn-dangerous" type="button">
<!----><span>Dashed</span>
</button><button class="ant-btn ant-btn-text ant-btn-dangerous" type="button">
<!----><span>Text</span>
</button><button class="ant-btn ant-btn-link ant-btn-dangerous" type="button">
<!----><span>Link</span>
</button></div>
`;
exports[`renders ./components/button/demo/disabled.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button>
<button disabled="" class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary(disabled)</span>
</button>
<br>
<button class="ant-btn" type="button">
<!----><span>Default</span>
</button>
<button disabled="" class="ant-btn" type="button">
<!----><span>Default(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-dashed" type="button">
<!----><span>Dashed</span>
</button>
<button disabled="" class="ant-btn ant-btn-dashed" type="button">
<!----><span>Dashed(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-text" type="button">
<!----><span>Text</span>
</button>
<button disabled="" class="ant-btn ant-btn-text" type="button">
<!----><span>Text(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-link" type="button">
<!----><span>Link</span>
</button>
<button disabled="" class="ant-btn ant-btn-link" type="button">
<!----><span>Link(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-dangerous" type="button">
<!----><span>Danger Default</span>
</button>
<button disabled="" class="ant-btn ant-btn-dangerous" type="button">
<!----><span>Danger Default(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-text ant-btn-dangerous" type="button">
<!----><span>Danger Text</span>
</button>
<button disabled="" class="ant-btn ant-btn-text ant-btn-dangerous" type="button">
<!----><span>Danger Text(disabled)</span>
</button>
<br>
<button class="ant-btn ant-btn-link ant-btn-dangerous" type="button">
<!----><span>Danger Link</span>
</button>
<button disabled="" class="ant-btn ant-btn-link ant-btn-dangerous" type="button">
<!----><span>Danger Link(disabled)</span>
</button>
<br>
<div style="padding: 8px 8px 0px 8px; background: rgb(190, 200, 200);"><button class="ant-btn ant-btn-background-ghost" type="button">
<!----><span>Ghost</span>
</button><button disabled="" class="ant-btn ant-btn-background-ghost" type="button">
<!----><span>Ghost(disabled)</span>
</button></div>
`;
exports[`renders ./components/button/demo/ghost.vue correctly 1`] = `
<div style="background: rgb(190, 200, 200); padding: 26px 16px 16px;"><button class="ant-btn ant-btn-primary ant-btn-background-ghost" type="button">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-background-ghost" type="button">
<!----><span>Default</span>
</button><button class="ant-btn ant-btn-dashed ant-btn-background-ghost" type="button">
<!----><span>Dashed</span>
</button><button class="ant-btn ant-btn-primary ant-btn-background-ghost ant-btn-dangerous" type="button">
<!----><span>Danger</span>
</button></div>
`;
exports[`renders ./components/button/demo/icon.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary ant-btn-circle ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-primary ant-btn-circle" type="button">
<!----><span>A</span>
</button>
<button class="ant-btn ant-btn-primary" type="button"><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>Search</span></button>
<button class="ant-btn ant-btn-default ant-btn-circle ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn" type="button"><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>Search</span></button>
<button class="ant-btn ant-btn-default ant-btn-circle ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn" type="button"><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>Search</span></button>
<button class="ant-btn ant-btn-dashed ant-btn-circle ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-dashed" type="button"><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>Search</span></button>
<a class="ant-btn ant-btn-icon-only" href="https://www.google.com"><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></a>
<br>
<br>
<button class="ant-btn ant-btn-primary ant-btn-circle ant-btn-lg ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-primary ant-btn-circle ant-btn-lg" type="button">
<!----><span>A</span>
</button>
<button class="ant-btn ant-btn-primary ant-btn-lg" type="button"><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>Search</span></button>
<button class="ant-btn ant-btn-default ant-btn-circle ant-btn-lg ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-lg" type="button"><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>Search</span></button>
<br>
<button class="ant-btn ant-btn-default ant-btn-circle ant-btn-lg ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-lg" type="button"><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>Search</span></button>
<button class="ant-btn ant-btn-dashed ant-btn-circle ant-btn-lg ant-btn-icon-only" type="button"><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></button>
<button class="ant-btn ant-btn-dashed ant-btn-lg" type="button"><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>Search</span></button>
<a class="ant-btn ant-btn-lg ant-btn-icon-only" href="https://www.google.com"><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></a>
`;
exports[`renders ./components/button/demo/loading.vue correctly 1`] = `
<div class="ant-space ant-space-horizontal ant-space-align-center" style="width: 100%;">
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary ant-btn-loading" type="button"><span class="ant-btn-loading-icon"><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>Loading</span></button></div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-primary ant-btn-sm ant-btn-loading" type="button"><span class="ant-btn-loading-icon"><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>Loading</span></button></div>
<!---->
</div>
<div class="ant-space ant-space-horizontal ant-space-align-center" style="width: 100%;">
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>mouseenter me!</span>
</button></div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button"><span role="img" aria-label="poweroff" class="anticon anticon-poweroff"><svg focusable="false" class="" data-icon="poweroff" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M705.6 124.9a8 8 0 00-11.6 7.2v64.2c0 5.5 2.9 10.6 7.5 13.6a352.2 352.2 0 0162.2 49.8c32.7 32.8 58.4 70.9 76.3 113.3a355 355 0 0127.9 138.7c0 48.1-9.4 94.8-27.9 138.7a355.92 355.92 0 01-76.3 113.3 353.06 353.06 0 01-113.2 76.4c-43.8 18.6-90.5 28-138.5 28s-94.7-9.4-138.5-28a353.06 353.06 0 01-113.2-76.4A355.92 355.92 0 01184 650.4a355 355 0 01-27.9-138.7c0-48.1 9.4-94.8 27.9-138.7 17.9-42.4 43.6-80.5 76.3-113.3 19-19 39.8-35.6 62.2-49.8 4.7-2.9 7.5-8.1 7.5-13.6V132c0-6-6.3-9.8-11.6-7.2C178.5 195.2 82 339.3 80 506.3 77.2 745.1 272.5 943.5 511.2 944c239 .5 432.8-193.3 432.8-432.4 0-169.2-97-315.7-238.4-386.7zM480 560h64c4.4 0 8-3.6 8-8V88c0-4.4-3.6-8-8-8h-64c-4.4 0-8 3.6-8 8v464c0 4.4 3.6 8 8 8z"></path></svg></span><span>延迟1s</span></button></div>
<!---->
</div>
<div class="ant-space ant-space-horizontal ant-space-align-center" style="width: 100%;">
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary ant-btn-loading ant-btn-icon-only" type="button"><span class="ant-btn-loading-icon"><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></button></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary ant-btn-circle ant-btn-loading ant-btn-icon-only" type="button"><span class="ant-btn-loading-icon"><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></button></div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-default ant-btn-round ant-btn-loading ant-btn-dangerous ant-btn-icon-only" type="button"><span class="ant-btn-loading-icon"><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></button></div>
<!---->
</div>
`;
exports[`renders ./components/button/demo/multiple.vue correctly 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button>
<button class="ant-btn" type="button">
<!----><span>secondary</span>
</button>
<button class="ant-btn ant-dropdown-trigger" type="button">
<!----><span>Actions</span><span role="img" aria-label="down" class="anticon anticon-down"><svg focusable="false" class="" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></span>
</button>
`;
exports[`renders ./components/button/demo/size.vue correctly 1`] = `
<div class="ant-radio-group ant-radio-group-outline"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="large"><span class="ant-radio-button-inner"></span></span><span>Large</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="default"><span class="ant-radio-button-inner"></span></span><span>Default</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="small"><span class="ant-radio-button-inner"></span></span><span>Small</span></label></div>
<br>
<br>
<button class="ant-btn ant-btn-primary ant-btn-lg" type="button">
<!----><span>Primary</span>
</button>
<button class="ant-btn ant-btn-lg" type="button">
<!----><span>Normal</span>
</button>
<button class="ant-btn ant-btn-dashed ant-btn-lg" type="button">
<!----><span>Dashed</span>
</button>
<button class="ant-btn ant-btn-lg ant-btn-dangerous" type="button">
<!----><span>Danger</span>
</button>
<button class="ant-btn ant-btn-link ant-btn-lg" type="button">
<!----><span>Link</span>
</button>
<br>
<button class="ant-btn ant-btn-primary ant-btn-lg ant-btn-icon-only" type="button"><span role="img" aria-label="download" class="anticon anticon-download"><svg focusable="false" class="" data-icon="download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span></button>
<button class="ant-btn ant-btn-primary ant-btn-circle ant-btn-lg ant-btn-icon-only" type="button"><span role="img" aria-label="download" class="anticon anticon-download"><svg focusable="false" class="" data-icon="download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span></button>
<button class="ant-btn ant-btn-primary ant-btn-round ant-btn-lg" type="button"><span role="img" aria-label="download" class="anticon anticon-download"><svg focusable="false" class="" data-icon="download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Download</span></button>
<button class="ant-btn ant-btn-primary ant-btn-round ant-btn-lg ant-btn-icon-only" type="button"><span role="img" aria-label="download" class="anticon anticon-download"><svg focusable="false" class="" data-icon="download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span></button>
<button class="ant-btn ant-btn-primary ant-btn-lg" type="button"><span role="img" aria-label="download" class="anticon anticon-download"><svg focusable="false" class="" data-icon="download" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>Download</span></button>
<br>
`;

View File

@ -0,0 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button fixbug renders {0} , 0 and {false} 1`] = `
<button class="ant-btn" type="button">
<!----><span>0</span>
</button>
`;
exports[`Button fixbug renders {0} , 0 and {false} 2`] = `
<button class="ant-btn" type="button">
<!----><span>0</span>
</button>
`;
exports[`Button fixbug renders {0} , 0 and {false} 3`] = `
<button class="ant-btn" type="button">
<!---->
</button>
`;
exports[`Button renders Chinese characters correctly 1`] = `
<button class="ant-btn" type="button">
<!----><span>按 钮</span>
</button>
`;
exports[`Button renders Chinese characters correctly 2`] = `
<button class="ant-btn" type="button">
<!----><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>
`;
exports[`Button renders Chinese characters correctly 3`] = `
<button class="ant-btn" type="button">
<!----><span>按 钮</span>
</button>
`;
exports[`Button renders Chinese characters correctly 4`] = `<button class="ant-btn ant-btn-loading" type="button"><span class="ant-btn-loading-icon"><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>按 钮</span></button>`;
exports[`Button renders Chinese characters correctly 5`] = `<button class="ant-btn ant-btn-loading" type="button"><span class="ant-btn-loading-icon"><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>按 钮</span></button>`;
exports[`Button renders Chinese characters correctly 6`] = `
<button class="ant-btn ant-btn-two-chinese-chars" type="button">
<!----><span>按钮</span>
</button>
`;
exports[`Button renders correctly 1`] = `
<button class="ant-btn" type="button">
<!----><span>Follow</span>
</button>
`;
exports[`Button should not render as link button when href is undefined 1`] = `
<button class="ant-btn ant-btn-primary" type="button">
<!----><span>button</span>
</button>
`;
exports[`Button should support link button 1`] = `
<a class="ant-btn" href="http://ant.design" target="_blank">
<!----><span>link button</span>
</a>
`;

View File

@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('float-button');

View File

@ -0,0 +1,48 @@
import FloatButton from '../index';
import { mount } from '@vue/test-utils';
import mountTest from '../../../tests/shared/mountTest';
describe('FloatButton', () => {
mountTest(FloatButton);
mountTest(FloatButton.Group);
it('renders correctly', () => {
const wrapper = mount({
render() {
return <FloatButton></FloatButton>;
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('create primary button', () => {
const wrapper = mount({
render() {
return <FloatButton type="primary">按钮</FloatButton>;
},
});
expect(wrapper.find('.ant-float-btn-primary').exists()).toBe(true);
});
it('fixbug renders {0} , 0 and {false}', () => {
const wrapper = mount({
render() {
return <FloatButton>{0}</FloatButton>;
},
});
expect(wrapper.html()).toMatchSnapshot();
const wrapper1 = mount({
render() {
return <FloatButton>0</FloatButton>;
},
});
expect(wrapper1.html()).toMatchSnapshot();
const wrapper2 = mount({
render() {
return <FloatButton>{false}</FloatButton>;
},
});
expect(wrapper2.html()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,79 @@
import FloatButton from '../index';
import { mount } from '@vue/test-utils';
import { asyncExpect, sleep } from '../../../tests/utils';
describe('click wave effect', () => {
async function clickFloatButton(wrapper) {
await asyncExpect(() => {
wrapper.find('.ant-float-btn').trigger('click');
});
wrapper.find('.ant-float-btn').element.dispatchEvent(new Event('transitionstart'));
await sleep(20);
wrapper.find('.ant-float-btn').element.dispatchEvent(new Event('animationend'));
await sleep(20);
}
it('should have click wave effect for primary button', async () => {
const wrapper = mount({
render() {
return <FloatButton type="primary"></FloatButton>;
},
});
await clickFloatButton(wrapper);
expect(
wrapper.find('.ant-float-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 <FloatButton>button</FloatButton>;
},
});
await clickFloatButton(wrapper);
expect(
wrapper.find('.ant-float-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 <FloatButton type="link">button</FloatButton>;
},
});
await clickFloatButton(wrapper);
expect(
wrapper.find('.ant-float-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 <FloatButton type="text">button</FloatButton>;
},
});
await clickFloatButton(wrapper);
expect(
wrapper.find('.ant-float-btn').attributes('ant-click-animating-without-extra-node'),
).toBe(undefined);
});
it('should handle transitionstart', async () => {
const wrapper = mount({
render() {
return <FloatButton type="primary">button</FloatButton>;
},
});
await clickFloatButton(wrapper);
const buttonNode = wrapper.find('.ant-float-btn').element;
buttonNode.dispatchEvent(new Event('transitionstart'));
expect(
wrapper.find('.ant-float-btn').attributes('ant-click-animating-without-extra-node'),
).toBe('true');
wrapper.unmount();
buttonNode.dispatchEvent(new Event('transitionstart'));
});
});

View File

@ -0,0 +1,29 @@
import type { Ref } from 'vue';
import { inject, provide } from 'vue';
import type { FloatButtonShape } from './interface';
function createContext<T extends Record<string, any>>(defaultValue?: T) {
const contextKey = Symbol('floatButtonGroupContext');
const useProvide = (props: T) => {
provide(contextKey, props);
return props;
};
const useInject = () => {
return inject(contextKey, defaultValue as T) || ({} as T);
};
return {
useProvide,
useInject,
};
}
const FloatButtonGroupContext = createContext<{ shape: Ref<FloatButtonShape> } | undefined>(
undefined,
);
export default FloatButtonGroupContext;

View File

@ -0,0 +1,43 @@
<docs>
---
order: 7
iframe: 360
title:
zh-CN: 回到顶部
en-US: BackTop
---
## zh-CN
返回页面顶部的操作按钮
## en-US
`BackTop` makes it easy to go back to the top of the page.
</docs>
<template>
<div :style="{ height: '500vh', padding: '10px' }">
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<div>Scroll to bottom</div>
<a-back-top />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { FileTextOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { FileTextOutlined },
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,36 @@
<docs>
---
order: 0
iframe: 360
title:
zh-CN: 基本
en-US: Basic Usage
---
## zh-CN
最简单的用法
## en-US
The most basic usage.
</docs>
<template>
<a-float-button @click="handleClick" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
setup() {
const handleClick = () => console.log('click');
return {
handleClick,
};
},
});
</script>

View File

@ -0,0 +1,69 @@
<docs>
---
order: 3
iframe: 360
title:
zh-CN: 描述
en-US: Description
---
## zh-CN
可以通过 `description` 设置文字内容
> 仅当 `shape` 属性为 `square` 时支持由于空间较小推荐使用比较精简的双数文字
## en-US
Setting `description` prop to show FloatButton with description.
> supported only when `shape` is `square`. Due to narrow space for text, short sentence is recommended.
</docs>
<template>
<a-float-button
shape="square"
description="HELP INFO"
:style="{
right: '24px',
}"
>
<template #icon>
<FileTextOutlined />
</template>
</a-float-button>
<a-float-button
shape="square"
description="HELP INFO"
:style="{
right: '94px',
}"
></a-float-button>
<a-float-button
shape="square"
description="HELP"
:style="{
right: '164px',
}"
>
<template #icon>
<FileTextOutlined />
</template>
</a-float-button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { FileTextOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { FileTextOutlined },
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,56 @@
<docs>
---
order: 6
iframe: 360
title:
zh-CN: 菜单模式
en-US: Menu mode
---
## zh-CN
设置 `trigger` 属性即可开启菜单模式提供 `hover` `click` 两种触发方式
## en-US
Open menu mode with `trigger`, which could be `hover` or `click`.
</docs>
<template>
<a-float-button-group trigger="click" type="primary" :style="{ right: '24px' }">
<template #icon>
<CustomerServiceOutlined />
</template>
<a-float-button />
<a-float-button>
<template #icon>
<CommentOutlined />
</template>
</a-float-button>
</a-float-button-group>
<a-float-button-group trigger="hover" type="primary" :style="{ right: '94px' }">
<template #icon>
<CustomerServiceOutlined />
</template>
<a-float-button />
<a-float-button>
<template #icon>
<CommentOutlined />
</template>
</a-float-button>
</a-float-button-group>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { CustomerServiceOutlined, CommentOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { CustomerServiceOutlined, CommentOutlined },
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,57 @@
<docs>
---
order: 5
iframe: 360
title:
zh-CN: 浮动按钮组
en-US: FloatButton Group
---
## zh-CN
按钮组合使用时推荐使用 `<FloatButton.Group />`并通过设置 `shape` 属性改变悬浮按钮组的形状悬浮按钮组的 `shape` 会覆盖内部 FloatButton `shape` 属性
## en-US
When multiple buttons are used together, `<FloatButton.Group />` is recommended. By setting `shape` of FloatButton.Group, you can change the shape of group. `shape` of FloatButton.Group will override `shape` of FloatButton inside.
</docs>
<template>
<a-float-button-group shape="circle" :style="{ right: '24px' }">
<a-float-button>
<template #icon>
<QuestionCircleOutlined />
</template>
</a-float-button>
<a-float-button />
<a-back-top :visibilityHeight="0" />
</a-float-button-group>
<a-float-button-group shape="square" :style="{ right: '94px' }">
<a-float-button>
<template #icon>
<QuestionCircleOutlined />
</template>
</a-float-button>
<a-float-button />
<a-float-button>
<template #icon>
<SyncOutlined />
</template>
</a-float-button>
<a-back-top :visibilityHeight="0" />
</a-float-button-group>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { QuestionCircleOutlined, SyncOutlined },
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,86 @@
<template>
<template v-if="iframeName === 'basic-usage'">
<basic></basic>
</template>
<template v-else-if="iframeName === 'type'">
<type></type>
</template>
<template v-else-if="iframeName === 'shape'">
<shape></shape>
</template>
<template v-else-if="iframeName === 'description'">
<description></description>
</template>
<template v-else-if="iframeName === 'floatbutton-with-tooltip'">
<tooltip></tooltip>
</template>
<template v-else-if="iframeName === 'floatbutton-group'">
<group></group>
</template>
<template v-else-if="iframeName === 'menu-mode'">
<group-menu></group-menu>
</template>
<template v-else-if="iframeName === 'backtop'">
<back-top></back-top>
</template>
<demo-sort v-else>
<basic></basic>
<type></type>
<shape></shape>
<description></description>
<tooltip></tooltip>
<group></group>
<group-menu></group-menu>
<back-top></back-top>
</demo-sort>
</template>
<script lang="ts">
import Basic from './basic.vue';
import Type from './type.vue';
import Shape from './shape.vue';
import Description from './description.vue';
import Tooltip from './tooltip.vue';
import group from './group.vue';
import GroupMenu from './group-menu.vue';
import BackTop from './back-top.vue';
import { defineComponent, provide } from 'vue';
import US from '../index.en-US.md';
import CN from '../index.zh-CN.md';
export default defineComponent({
CN,
US,
components: {
Basic,
Type,
Shape,
Description,
Tooltip,
group,
GroupMenu,
BackTop,
},
props: {
iframeName: String,
},
setup(props) {
provide(
'iframeDemo',
!props.iframeName
? {
type: '/iframe/float-button/#type',
'basic-usage': '/iframe/float-button/#basic-usage',
shape: '/iframe/float-button/#shape',
description: '/iframe/float-button/#description',
'floatbutton-with-tooltip': '/iframe/float-button/#floatbutton-with-tooltip',
'floatbutton-group': '/iframe/float-button/#floatbutton-group',
'menu-mode': '/iframe/float-button/#menu-mode',
backtop: '/iframe/float-button/#backtop',
}
: {},
);
},
});
</script>

View File

@ -0,0 +1,62 @@
<docs>
---
order: 2
iframe: 360
title:
zh-CN: 形状
en-US: Shape
---
## zh-CN
最简单的用法
## en-US
The most basic usage.
</docs>
<template>
<a-float-button @click="handleClick" />
<a-float-button
shape="circle"
type="primary"
:style="{
right: '94px',
}"
>
<template #icon>
<CustomerServiceOutlined />
</template>
</a-float-button>
<a-float-button
shape="square"
type="primary"
:style="{
right: '24px',
}"
>
<template #icon>
<CustomerServiceOutlined />
</template>
</a-float-button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { CustomerServiceOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { CustomerServiceOutlined },
setup() {
const handleClick = () => console.log('click');
return {
handleClick,
};
},
});
</script>

View File

@ -0,0 +1,47 @@
<docs>
---
order: 4
iframe: 360
title:
zh-CN: 含有气泡卡片的悬浮按钮
en-US: FloatButton with tooltip
---
## zh-CN
设置 tooltip 属性即可开启气泡卡片
## en-US
Setting `tooltip` prop to show FloatButton with tooltip.
</docs>
<template>
<a-float-button
tooltip="HELP INFO"
:style="{
right: '24px',
}"
></a-float-button>
<a-float-button
:style="{
right: '94px',
}"
>
<template #tooltip>
<div>Documents</div>
</template>
</a-float-button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,54 @@
<docs>
---
order: 1
iframe: 360
title:
zh-CN: 类型
en-US: Type
---
## zh-CN
通过 `type` 改变悬浮按钮的类型
## en-US
Change the type of the FloatButton with `type`.
</docs>
<template>
<a-float-button
type="primary"
:style="{
right: '24px',
}"
>
<template #icon>
<QuestionCircleOutlined />
</template>
</a-float-button>
<a-float-button
type="default"
:style="{
right: '94px',
}"
>
<template #icon>
<QuestionCircleOutlined />
</template>
</a-float-button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components: { QuestionCircleOutlined },
setup() {
return {};
},
});
</script>

View File

@ -0,0 +1,48 @@
---
category: Components
type: Other
title: FloatButton
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAAAAAAAADrJ8AQ/original
---
FloatButton. Available since `4.0.0`.
## When To Use
- For global functionality on the site.
- Buttons that can be seen wherever you browse.
## API
> This component is available since `ant-design-vue@4.0.0`.
### common API
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| icon | Set the icon component of button | slot | - | |
| description | Text and other | string \| slot | - | |
| tooltip | The text shown in the tooltip | string \| slot | | |
| type | Setting button type | `default` \| `primary` | `default` | |
| shape | Setting button shape | `circle` \| `square` | `circle` | |
| onClick | Set the handler to handle `click` event | (event) => void | - | |
| href | The target of hyperlink | string | - | |
| target | Specifies where to display the linked URL | string | - | |
### FloatButton.Group
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| shape | Setting button shape of children | `circle` \| `square` | `circle` | |
| trigger | Which action can trigger menu open/close | `click` \| `hover` | - | |
| open | Whether the menu is visible or not | boolean | - | |
| onOpenChange | Callback executed when active menu is changed | (open: boolean) => void | - | |
### FloatButton.BackTop
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| duration | Time to return to topms | number | 450 | |
| target | Specifies the scrollable area dom node | () => HTMLElement | () => window | |
| visibilityHeight | The BackTop button will not show until the scroll height reaches this value | number | 400 | |
| onClick | A callback function, which can be executed when you click the button | () => void | - | |

View File

@ -0,0 +1,42 @@
import type { App, Plugin } from 'vue';
import FloatButton from './FloatButton';
import FloatButtonGroup from './FloatButtonGroup';
import BackTop from './BackTop';
import type {
FloatButtonProps,
FloatButtonShape,
FloatButtonType,
FloatButtonGroupProps,
BackTopProps,
} from './interface';
import type { SizeType as FloatButtonSize } from '../config-provider';
export type {
FloatButtonProps,
FloatButtonShape,
FloatButtonType,
FloatButtonGroupProps,
BackTopProps,
FloatButtonSize,
};
FloatButton.Group = FloatButtonGroup;
FloatButton.BackTop = BackTop;
/* istanbul ignore next */
FloatButton.install = function (app: App) {
app.component(FloatButton.name, FloatButton);
app.component(FloatButtonGroup.name, FloatButtonGroup);
app.component(BackTop.name, BackTop);
return app;
};
export { FloatButtonGroup };
export default FloatButton as typeof FloatButton &
Plugin & {
readonly Group: typeof FloatButtonGroup;
readonly BackTop: typeof BackTop;
};

View File

@ -0,0 +1,49 @@
---
category: Components
subtitle: 悬浮按钮
type: 其他
title: FloatButton
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAAAAAAAADrJ8AQ/original
---
悬浮按钮。自 `4.0.0` 版本开始提供该组件。
## 何时使用
- 用于网站上的全局功能;
- 无论浏览到何处都可以看见的按钮。
## API
> 自 `ant-design-vue@4.0.0` 版本开始提供该组件。
### 共同的 API
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| icon | 自定义图标 | slot | - | |
| description | 文字及其它内容 | string \| slot | - | |
| tooltip | 气泡卡片的内容 | string \| slot | - | |
| type | 设置按钮类型 | `default` \| `primary` | `default` | |
| shape | 设置按钮形状 | `circle` \| `square` | `circle` | |
| onClick | 点击按钮时的回调 | (event) => void | - | |
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | |
| target | 相当于 a 标签的 target 属性href 存在时生效 | string | - | |
### FloatButton.Group
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| ------------ | -------------------------------- | ----------------------- | -------- | ---- |
| shape | 设置包含的 FloatButton 按钮形状 | `circle` \| `square` | `circle` | |
| trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | |
| open | 受控展开 | boolean | - | |
| onOpenChange | 展开收起时的回调 | (open: boolean) => void | - | |
### FloatButton.BackTop
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| ---------------- | ---------------------------------- | ----------------- | ------------ | ---- |
| duration | 回到顶部所需时间ms | number | 450 | |
| target | 设置需要监听其滚动事件的元素 | () => HTMLElement | () => window | |
| visibilityHeight | 滚动高度达到此参数值才出现 BackTop | number | 400 | |
| onClick | 点击按钮的回调函数 | () => void | - | |

View File

@ -0,0 +1,66 @@
import type { ExtractPropTypes } from 'vue';
import PropTypes from '../_util/vue-types';
import type { MouseEventHandler } from '../_util/EventInterface';
import { stringType, booleanType, functionType } from '../_util/type';
export type FloatButtonType = 'default' | 'primary';
export type FloatButtonShape = 'circle' | 'square';
export type FloatButtonGroupTrigger = 'click' | 'hover';
export const floatButtonProps = () => {
return {
prefixCls: String,
description: PropTypes.any,
type: stringType<FloatButtonType>('default'),
shape: stringType<FloatButtonShape>('circle'),
tooltip: PropTypes.any,
href: String,
target: functionType<() => Window | HTMLElement | null>(),
onClick: functionType<MouseEventHandler>(),
};
};
export type FloatButtonProps = Partial<ExtractPropTypes<ReturnType<typeof floatButtonProps>>>;
export const floatButtonContentProps = () => {
return {
prefixCls: stringType<FloatButtonProps['prefixCls']>(),
description: PropTypes.any,
};
};
export type FloatButtonContentProps = Partial<
ExtractPropTypes<ReturnType<typeof floatButtonContentProps>>
>;
export const floatButtonGroupProps = () => {
return {
...floatButtonProps(),
// 包含的 Float Button
// 触发方式 (有触发方式为菜单模式)
trigger: stringType<FloatButtonGroupTrigger>(),
// 受控展开
open: booleanType(false),
// 展开收起的回调
onOpenChange: functionType<(open: boolean) => void>(),
};
};
export type FloatButtonGroupProps = Partial<
ExtractPropTypes<ReturnType<typeof floatButtonGroupProps>>
>;
export const backTopProps = () => {
return {
...floatButtonProps(),
prefixCls: String,
duration: Number,
target: functionType<() => HTMLElement | Window | Document>(),
visibilityHeight: Number,
onClick: functionType<MouseEventHandler>(),
};
};
export type BackTopProps = Partial<ExtractPropTypes<ReturnType<typeof backTopProps>>>;

View File

@ -0,0 +1,333 @@
import type { CSSObject } from '../../_util/cssinjs';
import { Keyframes } from '../../_util/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { initFadeMotion } from '../../style/motion/fade';
import { resetComponent } from '../../style';
import { initMotion } from '../../style/motion/motion';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
zIndexPopup: number;
}
type FloatButtonToken = FullToken<'FloatButton'> & {
floatButtonColor: string;
floatButtonBackgroundColor: string;
floatButtonHoverBackgroundColor: string;
floatButtonFontSize: number;
floatButtonSize: number;
floatButtonIconSize: number;
// Position
floatButtonInsetBlockEnd: number;
floatButtonInsetInlineEnd: number;
};
const initFloatButtonGroupMotion = (token: FloatButtonToken) => {
const { componentCls, floatButtonSize, motionDurationSlow, motionEaseInOutCirc } = token;
const groupPrefixCls = `${componentCls}-group`;
const moveDownIn = new Keyframes('antFloatButtonMoveDownIn', {
'0%': {
transform: `translate3d(0, ${floatButtonSize}px, 0)`,
transformOrigin: '0 0',
opacity: 0,
},
'100%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1,
},
});
const moveDownOut = new Keyframes('antFloatButtonMoveDownOut', {
'0%': {
transform: 'translate3d(0, 0, 0)',
transformOrigin: '0 0',
opacity: 1,
},
'100%': {
transform: `translate3d(0, ${floatButtonSize}px, 0)`,
transformOrigin: '0 0',
opacity: 0,
},
});
return [
{
[`${groupPrefixCls}-wrap`]: {
...initMotion(`${groupPrefixCls}-wrap`, moveDownIn, moveDownOut, motionDurationSlow, true),
},
},
{
[`${groupPrefixCls}-wrap`]: {
[`
&${groupPrefixCls}-wrap-enter,
&${groupPrefixCls}-wrap-appear
`]: {
opacity: 0,
animationTimingFunction: motionEaseInOutCirc,
},
[`&${groupPrefixCls}-wrap-leave`]: {
animationTimingFunction: motionEaseInOutCirc,
},
},
},
];
};
// ============================== Group ==============================
const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token => {
const { componentCls, floatButtonSize, margin, borderRadiusLG } = token;
const groupPrefixCls = `${componentCls}-group`;
return {
[groupPrefixCls]: {
...resetComponent(token),
zIndex: 99,
display: 'block',
border: 'none',
position: 'fixed',
width: floatButtonSize,
height: 'auto',
boxShadow: 'none',
minHeight: floatButtonSize,
insetInlineEnd: token.floatButtonInsetInlineEnd,
insetBlockEnd: token.floatButtonInsetBlockEnd,
borderRadius: borderRadiusLG,
[`${groupPrefixCls}-wrap`]: {
zIndex: -1,
display: 'block',
position: 'relative',
marginBottom: margin,
},
[`&${groupPrefixCls}-rtl`]: {
direction: 'rtl',
},
[componentCls]: {
position: 'static',
},
},
[`${groupPrefixCls}-circle`]: {
[`${componentCls}-circle:not(:last-child)`]: {
marginBottom: token.margin,
[`${componentCls}-body`]: {
width: floatButtonSize,
height: floatButtonSize,
},
},
},
[`${groupPrefixCls}-square`]: {
[`${componentCls}-square`]: {
borderRadius: 0,
padding: 0,
'&:first-child': {
borderStartStartRadius: borderRadiusLG,
borderStartEndRadius: borderRadiusLG,
},
'&:last-child': {
borderEndStartRadius: borderRadiusLG,
borderEndEndRadius: borderRadiusLG,
},
'&:not(:last-child)': {
borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorSplit}`,
},
},
[`${groupPrefixCls}-wrap`]: {
display: 'block',
borderRadius: borderRadiusLG,
boxShadow: token.boxShadowSecondary,
overflow: 'hidden',
[`${componentCls}-square`]: {
boxShadow: 'none',
marginTop: 0,
borderRadius: 0,
padding: token.paddingXXS,
'&:first-child': {
borderStartStartRadius: borderRadiusLG,
borderStartEndRadius: borderRadiusLG,
},
'&:last-child': {
borderEndStartRadius: borderRadiusLG,
borderEndEndRadius: borderRadiusLG,
},
'&:not(:last-child)': {
borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorSplit}`,
},
[`${componentCls}-body`]: {
width: floatButtonSize - token.paddingXXS * 2,
height: floatButtonSize - token.paddingXXS * 2,
},
},
},
},
[`${groupPrefixCls}-circle-shadow`]: {
boxShadow: 'none',
},
[`${groupPrefixCls}-square-shadow`]: {
boxShadow: token.boxShadowSecondary,
[`${componentCls}-square`]: {
boxShadow: 'none',
padding: token.paddingXXS,
[`${componentCls}-body`]: {
width: floatButtonSize - token.paddingXXS * 2,
height: floatButtonSize - token.paddingXXS * 2,
},
},
},
};
};
// ============================== Shared ==============================
const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token => {
const { componentCls, floatButtonIconSize, floatButtonSize, borderRadiusLG } = token;
return {
[componentCls]: {
...resetComponent(token),
border: 'none',
position: 'fixed',
cursor: 'pointer',
overflow: 'hidden',
zIndex: 99,
display: 'block',
justifyContent: 'center',
alignItems: 'center',
width: floatButtonSize,
height: floatButtonSize,
insetInlineEnd: token.floatButtonInsetInlineEnd,
insetBlockEnd: token.floatButtonInsetBlockEnd,
boxShadow: token.boxShadowSecondary,
// Pure Panel
'&-pure': {
position: 'relative',
inset: 'auto',
},
'&:empty': {
display: 'none',
},
[`${componentCls}-body`]: {
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: `all ${token.motionDurationMid}`,
[`${componentCls}-content`]: {
overflow: 'hidden',
textAlign: 'center',
minHeight: floatButtonSize,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: `2px 4px`,
[`${componentCls}-icon`]: {
textAlign: 'center',
margin: 'auto',
width: floatButtonIconSize,
fontSize: floatButtonIconSize,
lineHeight: 1,
},
},
},
},
[`${componentCls}-circle`]: {
height: floatButtonSize,
borderRadius: '50%',
[`${componentCls}-body`]: {
borderRadius: '50%',
},
},
[`${componentCls}-square`]: {
height: 'auto',
minHeight: floatButtonSize,
borderRadius: borderRadiusLG,
[`${componentCls}-body`]: {
height: 'auto',
borderRadius: token.borderRadiusSM,
},
},
[`${componentCls}-default`]: {
backgroundColor: token.floatButtonBackgroundColor,
transition: `background-color ${token.motionDurationMid}`,
[`${componentCls}-body`]: {
backgroundColor: token.floatButtonBackgroundColor,
transition: `background-color ${token.motionDurationMid}`,
'&:hover': {
backgroundColor: token.colorFillContent,
},
[`${componentCls}-content`]: {
[`${componentCls}-icon`]: {
color: token.colorText,
},
[`${componentCls}-description`]: {
display: 'flex',
alignItems: 'center',
lineHeight: `${token.fontSizeLG}px`,
color: token.colorText,
fontSize: token.fontSizeSM,
},
},
},
},
[`${componentCls}-primary`]: {
backgroundColor: token.colorPrimary,
[`${componentCls}-body`]: {
backgroundColor: token.colorPrimary,
transition: `background-color ${token.motionDurationMid}`,
'&:hover': {
backgroundColor: token.colorPrimaryHover,
},
[`${componentCls}-content`]: {
[`${componentCls}-icon`]: {
color: token.colorTextLightSolid,
},
[`${componentCls}-description`]: {
display: 'flex',
alignItems: 'center',
lineHeight: `${token.fontSizeLG}px`,
color: token.colorTextLightSolid,
fontSize: token.fontSizeSM,
},
},
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook<'FloatButton'>('FloatButton', token => {
const {
colorTextLightSolid,
colorBgElevated,
controlHeightLG,
marginXXL,
marginLG,
fontSize,
fontSizeIcon,
controlItemBgHover,
} = token;
const floatButtonToken = mergeToken<FloatButtonToken>(token, {
floatButtonBackgroundColor: colorBgElevated,
floatButtonColor: colorTextLightSolid,
floatButtonHoverBackgroundColor: controlItemBgHover,
floatButtonFontSize: fontSize,
floatButtonIconSize: fontSizeIcon * 1.5,
floatButtonSize: controlHeightLG,
floatButtonInsetBlockEnd: marginXXL,
floatButtonInsetInlineEnd: marginLG,
});
return [
floatButtonGroupStyle(floatButtonToken),
sharedFloatButtonStyle(floatButtonToken),
initFadeMotion(token),
initFloatButtonGroupMotion(floatButtonToken),
];
});

View File

@ -3,7 +3,7 @@ import type { ComponentToken as AnchorComponentToken } from '../../anchor/style'
import type { ComponentToken as AvatarComponentToken } from '../../avatar/style';
import type { ComponentToken as BackTopComponentToken } from '../../back-top/style';
import type { ComponentToken as ButtonComponentToken } from '../../button/style';
// import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style';
import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style';
import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
import type { ComponentToken as CardComponentToken } from '../../card/style';
import type { ComponentToken as CarouselComponentToken } from '../../carousel/style';
@ -71,7 +71,7 @@ export interface ComponentTokenMap {
Drawer?: DrawerComponentToken;
Dropdown?: DropdownComponentToken;
Empty?: EmptyComponentToken;
// FloatButton?: FloatButtonComponentToken;
FloatButton?: FloatButtonComponentToken;
Form?: {};
Grid?: {};
Image?: ImageComponentToken;

View File

@ -63,7 +63,7 @@
gtag('config', 'UA-151755889-1');
</script>
<script type="text/javascript" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
<div
<!-- <div
class="surveybyantdv"
data-sf-id="63ad5912f3e10066"
data-sf-mode="popover"
@ -81,7 +81,7 @@
data-sf-width="350px"
data-sf-height="450px"
data-sf-preload="true"
></div>
></div> -->
<script async src="//aliyuncdn.antdv.com/form/static/embed/v1.js"></script>
</body>
</html>

View File

@ -38,6 +38,23 @@ const routes = [
},
component: () => import('../../../components/layout/demo/index.vue'),
},
{
path: 'float-button:lang(.*)',
meta: {
category: 'Components',
subtitle: '悬浮按钮',
type: '悬浮按钮',
cols: 1,
title: 'FloatButton',
cover:
'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAAAAAAAADrJ8AQ/original',
},
props: route => {
const hash = route.hash.replace('#', '');
return { iframeName: hash };
},
component: () => import('../../../components/float-button/demo/index.vue'),
},
],
},
{