refactor: breadcrumb button by ts

This commit is contained in:
tanjinzhou 2020-10-13 18:04:02 +08:00
parent 1503364d6b
commit d7426e11d4
16 changed files with 104 additions and 78 deletions

View File

@ -1,10 +1,17 @@
import { inject, cloneVNode } from 'vue';
import { inject, cloneVNode, defineComponent, PropType } from 'vue';
import PropTypes from '../_util/vue-types';
import { filterEmpty, getComponent, getSlot } from '../_util/props-util';
import warning from '../_util/warning';
import { defaultConfigProvider } from '../config-provider';
import BreadcrumbItem from './BreadcrumbItem';
import Menu from '../menu';
import { Omit, VueNode } from '../_util/type';
export interface Route {
path: string;
breadcrumbName: string;
children?: Omit<Route, 'children'>[];
}
const Route = PropTypes.shape({
path: PropTypes.string,
@ -14,13 +21,20 @@ const Route = PropTypes.shape({
const BreadcrumbProps = {
prefixCls: PropTypes.string,
routes: PropTypes.arrayOf(Route),
routes: {type: Array as PropType<Route[]>},
params: PropTypes.any,
separator: PropTypes.any,
itemRender: PropTypes.func,
separator: PropTypes.VNodeChild,
itemRender: {
type: Function as PropType<(
route: Route,
params: any,
routes: Array<Route>,
paths: Array<string>,
) => VueNode>
},
};
function getBreadcrumbName(route, params) {
function getBreadcrumbName(route: Route, params: any) {
if (!route.breadcrumbName) {
return null;
}
@ -31,8 +45,14 @@ function getBreadcrumbName(route, params) {
);
return name;
}
function defaultItemRender(opt: {route: Route, params: any, routes: Route[], paths: string[]}): VueNode {
const { route, params, routes, paths } = opt
const isLastItem = routes.indexOf(route) === routes.length - 1;
const name = getBreadcrumbName(route, params);
return isLastItem ? <span>{name}</span> : <a href={`#/${paths.join('/')}`}>{name}</a>;
}
export default {
export default defineComponent({
name: 'ABreadcrumb',
props: BreadcrumbProps,
setup() {
@ -41,12 +61,7 @@ export default {
};
},
methods: {
defaultItemRender({ route, params, routes, paths }) {
const isLastItem = routes.indexOf(route) === routes.length - 1;
const name = getBreadcrumbName(route, params);
return isLastItem ? <span>{name}</span> : <a href={`#/${paths.join('/')}`}>{name}</a>;
},
getPath(path, params) {
getPath(path: string, params: any) {
path = (path || '').replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key]);
@ -54,7 +69,7 @@ export default {
return path;
},
addChildPath(paths, childPath, params) {
addChildPath(paths: string[], childPath: string = '', params: any) {
const originalPaths = [...paths];
const path = this.getPath(childPath, params);
if (path) {
@ -63,9 +78,9 @@ export default {
return originalPaths;
},
genForRoutes({ routes = [], params = {}, separator, itemRender = this.defaultItemRender }) {
genForRoutes({ routes = [], params = {}, separator, itemRender = defaultItemRender }: any) {
const paths = [];
return routes.map(route => {
return routes.map((route: Route) => {
const path = this.getPath(route.path, params);
if (path) {
@ -104,14 +119,14 @@ export default {
},
},
render() {
let crumbs;
let crumbs: VueNode[];
const { prefixCls: customizePrefixCls, routes, params = {}, $slots } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
const children = filterEmpty(getSlot(this));
const separator = getComponent(this, 'separator');
const itemRender = this.itemRender || $slots.itemRender || this.defaultItemRender;
const itemRender = this.itemRender || $slots.itemRender || defaultItemRender;
if (routes && routes.length > 0) {
// generated by route
crumbs = this.genForRoutes({
@ -133,4 +148,4 @@ export default {
}
return <div class={prefixCls}>{crumbs}</div>;
},
};
});

View File

@ -1,18 +1,18 @@
import { inject } from 'vue';
import { defineComponent, inject } from 'vue';
import PropTypes from '../_util/vue-types';
import { hasProp, getComponent, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import DropDown from '../dropdown/dropdown';
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
export default {
export default defineComponent({
name: 'ABreadcrumbItem',
__ANT_BREADCRUMB_ITEM: true,
props: {
prefixCls: PropTypes.string,
href: PropTypes.string,
separator: PropTypes.any.def('/'),
overlay: PropTypes.any,
separator: PropTypes.VNodeChild.def('/'),
overlay: PropTypes.VNodeChild,
},
setup() {
return {
@ -24,7 +24,7 @@ export default {
* if overlay is have
* Wrap a DropDown
*/
renderBreadcrumbNode(breadcrumbItem, prefixCls) {
renderBreadcrumbNode(breadcrumbItem: any, prefixCls: string) {
const overlay = getComponent(this, 'overlay');
if (overlay) {
return (
@ -65,4 +65,4 @@ export default {
}
return null;
},
};
});

View File

@ -1,9 +1,9 @@
import { inject } from 'vue';
import { defineComponent, inject } from 'vue';
import { defaultConfigProvider } from '../config-provider';
import PropTypes from '../_util/vue-types';
import { getSlot } from '../_util/props-util';
export default {
export default defineComponent({
name: 'ABreadcrumbSeparator',
__ANT_BREADCRUMB_SEPARATOR: true,
props: {
@ -22,4 +22,4 @@ export default {
const children = getSlot(this);
return <span class={`${prefixCls}-separator`}>{children || '/'}</span>;
},
};
});

View File

@ -1,3 +1,4 @@
import { App } from 'vue';
import Breadcrumb from './Breadcrumb';
import BreadcrumbItem from './BreadcrumbItem';
import BreadcrumbSeparator from './BreadcrumbSeparator';
@ -6,7 +7,7 @@ Breadcrumb.Item = BreadcrumbItem;
Breadcrumb.Separator = BreadcrumbSeparator;
/* istanbul ignore next */
Breadcrumb.install = function(app) {
Breadcrumb.install = function(app: App) {
app.component(Breadcrumb.name, Breadcrumb);
app.component(BreadcrumbItem.name, BreadcrumbItem);
app.component(BreadcrumbSeparator.name, BreadcrumbSeparator);

View File

@ -1,18 +1,15 @@
import { inject } from 'vue';
import { defineComponent, inject } from 'vue';
import { filterEmpty, getSlot } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
const ButtonGroupProps = {
prefixCls: PropTypes.string,
size: {
validator(value) {
return ['small', 'large', 'default'].includes(value);
},
},
size: PropTypes.oneOf(tuple('small', 'large', 'default')),
};
export { ButtonGroupProps };
export default {
export default defineComponent({
name: 'AButtonGroup',
props: ButtonGroupProps,
setup() {
@ -53,4 +50,4 @@ export default {
};
return <div class={classes}>{filterEmpty(getSlot(this))}</div>;
},
};
});

View File

@ -1,4 +1,4 @@
import { inject, Text } from 'vue';
import { defineComponent, inject, Text, VNode } from 'vue';
import Wave from '../_util/wave';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import buttonTypes from './buttonTypes';
@ -8,7 +8,7 @@ import { defaultConfigProvider } from '../config-provider';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
const props = buttonTypes();
export default {
export default defineComponent({
name: 'AButton',
inheritAttrs: false,
__ANT_BUTTON: true,
@ -16,11 +16,12 @@ export default {
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
children: [],
iconCom: undefined,
delayTimeout: undefined
};
},
data() {
this.children = [];
this.iconCom = undefined;
return {
sizeMap: {
large: 'lg',
@ -67,7 +68,7 @@ export default {
ghost,
block,
$attrs,
} = this;
} = this
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('btn', customizePrefixCls);
const autoInsertSpace = this.configProvider.autoInsertSpaceInButton !== false;
@ -87,7 +88,7 @@ export default {
}
const iconType = sLoading ? 'loading' : this.iconCom;
return {
[$attrs.class]: $attrs.class,
[$attrs.class as string]: $attrs.class,
[`${prefixCls}`]: true,
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-${shape}`]: shape,
@ -101,7 +102,7 @@ export default {
},
fixTwoCNChar() {
// Fix for HOC usage like <FormatMessage />
const node = this.$refs.buttonNode;
const node = this.$refs.buttonNode as HTMLElement;
if (!node) {
return;
}
@ -114,17 +115,17 @@ export default {
this.hasTwoCNChar = false;
}
},
handleClick(event) {
handleClick(event: Event) {
const { sLoading } = this.$data;
if (sLoading) {
return;
}
this.$emit('click', event);
},
insertSpace(child, needInserted) {
insertSpace(child: VNode, needInserted: boolean) {
const SPACE = needInserted ? ' ' : '';
if (child.type === Text) {
let text = child.children.trim();
let text = (child.children as string).trim();
if (isTwoCNChar(text)) {
text = text.split('').join(SPACE);
}
@ -179,4 +180,4 @@ export default {
return <Wave ref="wave">{buttonNode}</Wave>;
},
};
});

View File

@ -1,15 +0,0 @@
import PropTypes, { withUndefined } from '../_util/vue-types';
export default () => ({
prefixCls: PropTypes.string,
type: PropTypes.string,
htmlType: PropTypes.oneOf(['button', 'submit', 'reset']).def('button'),
// icon: PropTypes.string,
shape: PropTypes.oneOf(['circle', 'circle-outline', 'round']),
size: PropTypes.oneOf(['small', 'large', 'default']).def('default'),
loading: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object])),
disabled: PropTypes.looseBool,
ghost: PropTypes.looseBool,
block: PropTypes.looseBool,
icon: PropTypes.any,
onClick: PropTypes.func,
});

View File

@ -0,0 +1,26 @@
import { tuple } from '../_util/type';
import PropTypes, { withUndefined } from '../_util/vue-types';
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'danger', 'link');
export type ButtonType = typeof ButtonTypes[number];
const ButtonShapes = tuple('circle', 'circle-outline', 'round');
export type ButtonShape = typeof ButtonShapes[number];
const ButtonSizes = tuple('large', 'default', 'small');
export type ButtonSize = typeof ButtonSizes[number];
const ButtonHTMLTypes = tuple('submit', 'button', 'reset');
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];
export default () => ({
prefixCls: PropTypes.string,
type: PropTypes.oneOf(ButtonTypes),
htmlType: PropTypes.oneOf(ButtonHTMLTypes).def('button'),
// icon: PropTypes.string,
shape: PropTypes.oneOf(ButtonShapes),
size: PropTypes.oneOf(ButtonSizes).def('default'),
loading: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object])),
disabled: PropTypes.looseBool,
ghost: PropTypes.looseBool,
block: PropTypes.looseBool,
icon: PropTypes.VNodeChild,
onClick: PropTypes.func,
});

View File

@ -1,10 +1,11 @@
import { App } from 'vue';
import Button from './button';
import ButtonGroup from './button-group';
Button.Group = ButtonGroup;
/* istanbul ignore next */
Button.install = function(app) {
Button.install = function(app: App) {
app.component(Button.name, Button);
app.component(ButtonGroup.name, ButtonGroup);
};

View File

@ -142,7 +142,7 @@ const ConfigProvider = defineComponent({
const renderProvider = (legacyLocale: Locale) => {
return (
<LocaleProvider locale={props.locale || legacyLocale} _ANT_MARK__={ANT_MARK}>
<LocaleProvider locale={props.locale || legacyLocale} ANT_MARK__={ANT_MARK}>
{slots.default?.()}
</LocaleProvider>
);

View File

@ -1,4 +1,4 @@
import { provide, inject, cloneVNode } from 'vue';
import { provide, inject, cloneVNode, defineComponent } from 'vue';
import RcDropdown from '../vc-dropdown/src/index';
import DropdownButton from './dropdown-button';
import PropTypes from '../_util/vue-types';
@ -16,7 +16,7 @@ import { defaultConfigProvider } from '../config-provider';
import RightOutlined from '@ant-design/icons-vue/RightOutlined';
const DropdownProps = getDropdownProps();
const Dropdown = {
const Dropdown = defineComponent({
name: 'ADropdown',
inheritAttrs: false,
props: {
@ -107,7 +107,7 @@ const Dropdown = {
};
return <RcDropdown {...dropdownProps}>{dropdownTrigger}</RcDropdown>;
},
};
});
Dropdown.Button = DropdownButton;
export default Dropdown;

View File

@ -22,7 +22,7 @@ export interface Locale {
export interface LocaleProviderProps {
locale: Locale;
children?: VNode | VNode[];
_ANT_MARK__?: string;
ANT_MARK__?: string;
}
export const ANT_MARK = 'internalMark';
@ -41,11 +41,11 @@ const LocaleProvider = defineComponent({
locale: {
type: Object,
},
_ANT_MARK__: PropTypes.string,
ANT_MARK__: PropTypes.string,
},
data() {
warning(
this._ANT_MARK__ === ANT_MARK,
this.ANT_MARK__ === ANT_MARK,
'LocaleProvider',
'`LocaleProvider` is deprecated. Please use `locale` with `ConfigProvider` instead',
);
@ -58,7 +58,7 @@ const LocaleProvider = defineComponent({
},
setup(props) {
warning(
props._ANT_MARK__ === ANT_MARK,
props.ANT_MARK__ === ANT_MARK,
'LocaleProvider',
'`LocaleProvider` is deprecated. Please use `locale` with `ConfigProvider` instead',
);
@ -67,7 +67,7 @@ const LocaleProvider = defineComponent({
...props.locale,
exist: true,
},
_ANT_MARK__: ANT_MARK,
ANT_MARK__: ANT_MARK,
};
provide('localeData', data);
return data;

View File

@ -1,9 +1,9 @@
import { inject } from 'vue';
import { defineComponent, inject } from 'vue';
import { Item, itemProps } from '../vc-menu';
import { getOptionProps, getSlot } from '../_util/props-util';
import Tooltip from '../tooltip';
function noop() {}
export default {
export default defineComponent({
name: 'MenuItem',
inheritAttrs: false,
props: itemProps,
@ -56,4 +56,4 @@ export default {
const item = <Item {...itemProps}>{children}</Item>;
return <Tooltip {...toolTipProps}>{item}</Tooltip>;
},
};
});

View File

@ -1,4 +1,4 @@
import { inject, provide, toRef } from 'vue';
import { defineComponent, inject, provide, toRef } from 'vue';
import omit from 'omit.js';
import VcMenu, { Divider, ItemGroup } from '../vc-menu';
import SubMenu from './SubMenu';
@ -47,7 +47,7 @@ export const menuProps = {
'onUpdate:openKeys': PropTypes.func,
};
const Menu = {
const Menu = defineComponent({
name: 'AMenu',
inheritAttrs: false,
props: menuProps,
@ -294,7 +294,7 @@ const Menu = {
return <VcMenu {...menuProps} class={menuClassName} />;
},
};
});
/* istanbul ignore next */
Menu.install = function(app) {