Skip to content

refactor: Breadcrumb #4175

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
44cd93e
chore: remove resize-observer-polyfill
tangjinzhou Apr 17, 2021
7315bfd
Merge remote-tracking branch 'origin/next' into v3
tangjinzhou May 10, 2021
184957e
refactor: align
tangjinzhou May 10, 2021
4d178de
refactor(v3/avatar): refactor using composition api (#4052)
John60676 May 10, 2021
7a2f28a
fix: avatar src scale not update
tangjinzhou May 10, 2021
11ffa8d
refactor: resizeObserver
tangjinzhou May 10, 2021
170a169
refactor: divider
tangjinzhou May 11, 2021
dbbd07d
refactor: localeProvider
tangjinzhou May 11, 2021
5bcca46
refactor(v3/back-top): use composition api (#4060)
sendya May 11, 2021
b96fc44
refactor: backtop
tangjinzhou May 11, 2021
3a13ef2
refactor: empty
tangjinzhou May 11, 2021
8f02b6d
refactor: transButton
tangjinzhou May 11, 2021
49ad768
Merge remote-tracking branch 'origin/next' into v3
tangjinzhou May 12, 2021
0984951
feat(v3/avatar): add avatar group (#4062)
John60676 May 12, 2021
4a5c4cd
refactor: avatar
tangjinzhou May 12, 2021
7acf577
refactor: avatar
tangjinzhou May 13, 2021
ea8ff66
style: rename useProvide
tangjinzhou May 13, 2021
67952ab
refactor: menu (#4110)
tangjinzhou May 23, 2021
7b494fd
fix: menu
tangjinzhou May 23, 2021
8179361
refactor: menu
tangjinzhou May 24, 2021
3d0edbc
refactor: remove rc-menu
tangjinzhou May 24, 2021
0c9951a
fix: menu rtl error
tangjinzhou May 24, 2021
1139aa5
style: lint
tangjinzhou May 24, 2021
1877d66
refactor(Anchor): use composition api (#4054)
sendya May 24, 2021
fbe3a48
refactor: anchor
tangjinzhou May 24, 2021
a6e30c2
refactor: anchor
tangjinzhou May 24, 2021
de4693c
refactor: anchor
tangjinzhou May 24, 2021
44ccaa1
feat: update
tangjinzhou May 25, 2021
69b9f80
fix: icon class lose
tangjinzhou May 25, 2021
372ac5c
refactor(v3/badge): use composition api (#4076)
sendya May 25, 2021
e442b0d
refactor: badge
tangjinzhou May 25, 2021
a01be5c
fix: badge inheritAttrs
tangjinzhou May 25, 2021
fe99051
refactor: grid
tangjinzhou May 25, 2021
3825c65
refactor: layout
tangjinzhou May 26, 2021
a049a66
fix: menu not close
tangjinzhou May 26, 2021
42916f5
refactor: space
tangjinzhou May 26, 2021
3b89f59
refactor: result
tangjinzhou May 26, 2021
e9854da
refactor: affix
tangjinzhou May 26, 2021
5ee3d30
refactor: comment
tangjinzhou May 26, 2021
2089961
refactor: form
tangjinzhou May 26, 2021
b53a91c
feat: spin add rtl
tangjinzhou May 26, 2021
ad2b447
feat: export spin type
tangjinzhou May 26, 2021
d2a1c42
refactor: pageHeader
tangjinzhou May 26, 2021
5096ee4
refactor: page-header
tangjinzhou May 27, 2021
c889882
refactor: skeleton
tangjinzhou May 28, 2021
b68bb81
refactor: typography
tangjinzhou May 28, 2021
2b78d2d
refactor(v3/rate): use composition api
sendya May 28, 2021
7ec594c
fix: add useRef hook
sendya May 28, 2021
c2bba2e
refactor: form
tangjinzhou May 28, 2021
0a2940e
fix: menu not update
tangjinzhou May 28, 2021
3d2a04d
refactor: form
tangjinzhou May 30, 2021
7214710
refactor: form
tangjinzhou May 31, 2021
f9ccbfd
fix: slide animate not work
tangjinzhou May 31, 2021
b8c52b3
fix: menu mode error
tangjinzhou May 31, 2021
6b2af5c
fix: menu icon
tangjinzhou May 31, 2021
3186b92
Merge branch 'refactor/v3/rate' of git://github.com/sendya/ant-design…
tangjinzhou Jun 1, 2021
836ae6d
Merge branch 'sendya-refactor/v3/rate' into v3
tangjinzhou Jun 1, 2021
bc85604
refactor: rate
tangjinzhou Jun 2, 2021
a58cb3c
perf: remove rate
tangjinzhou Jun 2, 2021
08a5ff3
feat: add vc-overflow
tangjinzhou Jun 2, 2021
1281e4a
refactor: menu
tangjinzhou Jun 7, 2021
2b0afda
fix: remove flex check (#4165)
zkwolf Jun 7, 2021
0d02391
Merge remote-tracking branch 'origin/next' into v3
tangjinzhou Jun 7, 2021
62ca3a9
fix: dist locale file lose #3684
tangjinzhou Jun 7, 2021
2cfc6cc
release 2.2.0-beta.1
tangjinzhou Jun 7, 2021
5cc10c6
dcos: update changelog
tangjinzhou Jun 7, 2021
dde7719
chore: update type
tangjinzhou Jun 7, 2021
772ac3c
docs: update changelog
tangjinzhou Jun 7, 2021
770e9cc
refactor: breadcrumb (#4137)
John60676 Jun 8, 2021
6ad0f9d
Merge remote-tracking branch 'origin/next' into v3
tangjinzhou Jun 8, 2021
0fa1581
refactor: breadcrumb
tangjinzhou Jun 8, 2021
3557e01
docs: update examples
tangjinzhou Jun 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 60 additions & 50 deletions components/breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import { inject, cloneVNode, defineComponent, PropType } from 'vue';
import { cloneVNode, defineComponent, PropType, ExtractPropTypes } from 'vue';
import PropTypes from '../_util/vue-types';
import { filterEmpty, getComponent, getSlot } from '../_util/props-util';
import { flattenChildren, getPropsSlot } 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';
import useConfigInject from '../_util/hooks/useConfigInject';

export interface Route {
path: string;
breadcrumbName: string;
children?: Omit<Route, 'children'>[];
}

const BreadcrumbProps = {
const breadcrumbProps = {
prefixCls: PropTypes.string,
routes: { type: Array as PropType<Route[]> },
params: PropTypes.any,
separator: PropTypes.VNodeChild,
separator: PropTypes.any,
itemRender: {
type: Function as PropType<
(opt: { route: Route; params: unknown; routes: Route[]; paths: string[] }) => VueNode
>,
},
};

export type BreadcrumbProps = Partial<ExtractPropTypes<typeof breadcrumbProps>>;

function getBreadcrumbName(route: Route, params: unknown) {
if (!route.breadcrumbName) {
return null;
Expand All @@ -50,34 +52,37 @@ function defaultItemRender(opt: {

export default defineComponent({
name: 'ABreadcrumb',
props: BreadcrumbProps,
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
methods: {
getPath(path: string, params: unknown) {
props: breadcrumbProps,
slots: ['separator', 'itemRender'],
setup(props, { slots }) {
const { prefixCls, direction } = useConfigInject('breadcrumb', props);

const getPath = (path: string, params: unknown) => {
path = (path || '').replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key]);
});
return path;
},
};

addChildPath(paths: string[], childPath = '', params: unknown) {
const addChildPath = (paths: string[], childPath = '', params: unknown) => {
const originalPaths = [...paths];
const path = this.getPath(childPath, params);
const path = getPath(childPath, params);
if (path) {
originalPaths.push(path);
}
return originalPaths;
},
};

genForRoutes({ routes = [], params = {}, separator, itemRender = defaultItemRender }: any) {
const genForRoutes = ({
routes = [],
params = {},
separator,
itemRender = defaultItemRender,
}: any) => {
const paths = [];
return routes.map((route: Route) => {
const path = this.getPath(route.path, params);
const path = getPath(route.path, params);

if (path) {
paths.push(path);
Expand All @@ -94,7 +99,7 @@ export default defineComponent({
route: child,
params,
routes,
paths: this.addChildPath(tempPaths, child.path, params),
paths: addChildPath(tempPaths, child.path, params),
})}
</Menu.Item>
))}
Expand All @@ -112,36 +117,41 @@ export default defineComponent({
</BreadcrumbItem>
);
});
},
},
render() {
let crumbs: VueNode[];
const { prefixCls: customizePrefixCls, routes, params = {}, $slots } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
};
return () => {
let crumbs: VueNode[];

const children = filterEmpty(getSlot(this));
const separator = getComponent(this, 'separator');
const itemRender = this.itemRender || $slots.itemRender || defaultItemRender;
if (routes && routes.length > 0) {
// generated by route
crumbs = this.genForRoutes({
routes,
params,
separator,
itemRender,
});
} else if (children.length) {
crumbs = children.map((element, index) => {
warning(
typeof element.type === 'object' &&
(element.type.__ANT_BREADCRUMB_ITEM || element.type.__ANT_BREADCRUMB_SEPARATOR),
'Breadcrumb',
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
);
return cloneVNode(element, { separator, key: index });
});
}
return <div class={prefixCls}>{crumbs}</div>;
const { routes, params = {} } = props;

const children = flattenChildren(getPropsSlot(slots, props));
const separator = getPropsSlot(slots, props, 'separator') ?? '/';

const itemRender = props.itemRender || slots.itemRender || defaultItemRender;
if (routes && routes.length > 0) {
// generated by route
crumbs = genForRoutes({
routes,
params,
separator,
itemRender,
});
} else if (children.length) {
crumbs = children.map((element, index) => {
warning(
typeof element.type === 'object' &&
(element.type.__ANT_BREADCRUMB_ITEM || element.type.__ANT_BREADCRUMB_SEPARATOR),
'Breadcrumb',
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
);
return cloneVNode(element, { separator, key: index });
});
}

const breadcrumbClassName = {
[prefixCls.value]: true,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
};
return <div class={breadcrumbClassName}>{crumbs}</div>;
};
},
});
85 changes: 41 additions & 44 deletions components/breadcrumb/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { defineComponent, inject } from 'vue';
import { defineComponent, ExtractPropTypes } from 'vue';
import PropTypes from '../_util/vue-types';
import { hasProp, getComponent, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import { getPropsSlot } from '../_util/props-util';
import DropDown from '../dropdown/dropdown';
import DownOutlined from '@ant-design/icons-vue/DownOutlined';
import useConfigInject from '../_util/hooks/useConfigInject';

const breadcrumbItemProps = {
prefixCls: PropTypes.string,
href: PropTypes.string,
separator: PropTypes.any,
overlay: PropTypes.any,
};

export type BreadcrumbItemProps = Partial<ExtractPropTypes<typeof breadcrumbItemProps>>;
export default defineComponent({
name: 'ABreadcrumbItem',
__ANT_BREADCRUMB_ITEM: true,
props: {
prefixCls: PropTypes.string,
href: PropTypes.string,
separator: PropTypes.VNodeChild.def('/'),
overlay: PropTypes.VNodeChild,
},
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
methods: {
props: breadcrumbItemProps,
slots: ['separator', 'overlay'],
setup(props, { slots }) {
const { prefixCls } = useConfigInject('breadcrumb', props);
/**
* if overlay is have
* Wrap a DropDown
*/
renderBreadcrumbNode(breadcrumbItem: JSX.Element, prefixCls: string) {
const overlay = getComponent(this, 'overlay');
const renderBreadcrumbNode = (breadcrumbItem: JSX.Element, prefixCls: string) => {
const overlay = getPropsSlot(slots, props, 'overlay');
if (overlay) {
return (
<DropDown overlay={overlay} placement="bottomCenter">
Expand All @@ -37,32 +37,29 @@ export default defineComponent({
);
}
return breadcrumbItem;
},
},
render() {
const { prefixCls: customizePrefixCls } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
const separator = getComponent(this, 'separator');
const children = getSlot(this);
let link: JSX.Element;
if (hasProp(this, 'href')) {
link = <a class={`${prefixCls}-link`}>{children}</a>;
} else {
link = <span class={`${prefixCls}-link`}>{children}</span>;
}
// wrap to dropDown
link = this.renderBreadcrumbNode(link, prefixCls);
if (children) {
return (
<span>
{link}
{separator && separator !== '' && (
<span class={`${prefixCls}-separator`}>{separator}</span>
)}
</span>
);
}
return null;
};

return () => {
const separator = getPropsSlot(slots, props, 'separator') ?? '/';
const children = getPropsSlot(slots, props);
let link: JSX.Element;

if (props.href !== undefined) {
link = <a class={`${prefixCls.value}-link`}>{children}</a>;
} else {
link = <span class={`${prefixCls.value}-link`}>{children}</span>;
}
// wrap to dropDown
link = renderBreadcrumbNode(link, prefixCls.value);
if (children) {
return (
<span>
{link}
{separator && <span class={`${prefixCls.value}-separator`}>{separator}</span>}
</span>
);
}
return null;
};
},
});
42 changes: 20 additions & 22 deletions components/breadcrumb/BreadcrumbSeparator.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import { defineComponent, inject } from 'vue';
import { defaultConfigProvider } from '../config-provider';
import { defineComponent, ExtractPropTypes } from 'vue';
import PropTypes from '../_util/vue-types';
import { getSlot } from '../_util/props-util';
import { flattenChildren } from '../_util/props-util';
import useConfigInject from '../_util/hooks/useConfigInject';

const breadcrumbSeparator = {
prefixCls: PropTypes.string,
};
export type BreadcrumbSeparator = Partial<ExtractPropTypes<typeof breadcrumbSeparator>>;

export default defineComponent({
name: 'ABreadcrumbSeparator',
__ANT_BREADCRUMB_SEPARATOR: true,
inheritAttrs: false,
props: {
prefixCls: PropTypes.string,
},
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
render() {
const { prefixCls: customizePrefixCls } = this;
const { separator, class: className, ...restAttrs } = this.$attrs;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
props: breadcrumbSeparator,
setup(props, { slots, attrs }) {
const { prefixCls } = useConfigInject('breadcrumb', props);

const children = getSlot(this);
return (
<span class={[`${prefixCls}-separator`, className]} {...restAttrs}>
{children.length > 0 ? children : '/'}
</span>
);
return () => {
const { separator, class: className, ...restAttrs } = attrs;
const children = flattenChildren(slots.default?.());
return (
<span class={[`${prefixCls.value}-separator`, className]} {...restAttrs}>
{children.length > 0 ? children : '/'}
</span>
);
};
},
});
21 changes: 21 additions & 0 deletions components/breadcrumb/__tests__/Breadcrumb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,25 @@ describe('Breadcrumb', () => {
});
expect(wrapper.html()).toMatchSnapshot();
});

// https://github.com/ant-design/ant-design/issues/25975
it('should support Breadcrumb.Item default separator', () => {
const MockComponent = () => (
<span>
<Breadcrumb.Item>Mock Node</Breadcrumb.Item>
</span>
);
const wrapper = mount({
render() {
return (
<Breadcrumb>
<Breadcrumb.Item>Location</Breadcrumb.Item>
<MockComponent />
<Breadcrumb.Item>Application Center</Breadcrumb.Item>
</Breadcrumb>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

exports[`Breadcrumb should allow Breadcrumb.Item is null or undefined 1`] = `<div class="ant-breadcrumb"><span><span class="ant-breadcrumb-link">Home</span><span class="ant-breadcrumb-separator">/</span></span></div>`;

exports[`Breadcrumb should not display Breadcrumb Item when its children is falsy 1`] = `<div class="ant-breadcrumb"><span><span class="ant-breadcrumb-link"></span><span class="ant-breadcrumb-separator">/</span></span><span><span class="ant-breadcrumb-link">xxx</span><span class="ant-breadcrumb-separator">/</span></span><span><span class="ant-breadcrumb-link">yyy</span><span class="ant-breadcrumb-separator">/</span></span></div>`;
exports[`Breadcrumb should not display Breadcrumb Item when its children is falsy 1`] = `
<div class="ant-breadcrumb">
<!----><span><span class="ant-breadcrumb-link">xxx</span><span class="ant-breadcrumb-separator">/</span></span><span><span class="ant-breadcrumb-link">yyy</span><span class="ant-breadcrumb-separator">/</span></span>
</div>
`;

exports[`Breadcrumb should render a menu 1`] = `<div class="ant-breadcrumb"><span><span class="ant-breadcrumb-link"><a href="#/index">home</a></span><span class="ant-breadcrumb-separator">/</span></span><span><!----><span class="ant-breadcrumb-overlay-link ant-dropdown-trigger"><span class="ant-breadcrumb-link"><a href="#/index/first">first</a></span><span role="img" aria-label="down" class="anticon anticon-down"><svg class="" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><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></span><span class="ant-breadcrumb-separator">/</span></span><span><span class="ant-breadcrumb-link"><span>second</span></span><span class="ant-breadcrumb-separator">/</span></span></div>`;

exports[`Breadcrumb should support Breadcrumb.Item default separator 1`] = `<div class="ant-breadcrumb"><span><span class="ant-breadcrumb-link">Location</span><span class="ant-breadcrumb-separator">/</span></span><span><span><span class="ant-breadcrumb-link">Mock Node</span><span class="ant-breadcrumb-separator">/</span></span></span><span><span class="ant-breadcrumb-link">Application Center</span><span class="ant-breadcrumb-separator">/</span></span></div>`;

exports[`Breadcrumb should support custom attribute 1`] = `<div class="ant-breadcrumb" data-custom="custom"><span data-custom="custom-item"><span class="ant-breadcrumb-link">xxx</span><span class="ant-breadcrumb-separator">/</span></span><span><span class="ant-breadcrumb-link">yyy</span><span class="ant-breadcrumb-separator">/</span></span></div>`;
4 changes: 4 additions & 0 deletions components/breadcrumb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import Breadcrumb from './Breadcrumb';
import BreadcrumbItem from './BreadcrumbItem';
import BreadcrumbSeparator from './BreadcrumbSeparator';

export { BreadcrumbProps } from './Breadcrumb';
export { BreadcrumbItemProps } from './BreadcrumbItem';
export { BreadcrumbSeparator } from './BreadcrumbSeparator';

Breadcrumb.Item = BreadcrumbItem;
Breadcrumb.Separator = BreadcrumbSeparator;

Expand Down
5 changes: 4 additions & 1 deletion components/breadcrumb/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
}

&-link {
> .@{iconfont-css-prefix} + span {
> .@{iconfont-css-prefix} + span,
> .@{iconfont-css-prefix} + a {
margin-left: 4px;
}
}
Expand All @@ -49,3 +50,5 @@
}
}
}

@import './rtl';
Loading