Skip to content

Commit 70d6dd5

Browse files
committed
feat(components): add Breadcrumb
1 parent a55dc0f commit 70d6dd5

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

src/components/breadcrumb/index.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as React from 'react';
2+
import { prefixClaName, classNames, getBEMElement } from 'mo/common/className';
3+
import { ComponentProps } from 'react';
4+
import { Icon } from '../icon';
5+
6+
export interface IBreadcrumbItem {
7+
id: string;
8+
href?: string;
9+
name?: string;
10+
icon?: typeof Icon;
11+
className?: string;
12+
render?(item: IBreadcrumbItem): ReactNode;
13+
}
14+
15+
export interface IBreadcrumb extends ComponentProps<'div'> {
16+
routes: IBreadcrumbItem[];
17+
separator?: typeof Icon;
18+
onClick?(event: React.MouseEvent, item?: IBreadcrumbItem): void;
19+
}
20+
21+
export const defaultBreadcrumbClassName = prefixClaName('breadcrumb');
22+
23+
export const breadcrumbItemClassName = getBEMElement(
24+
defaultBreadcrumbClassName,
25+
'item'
26+
);
27+
28+
export const breadcrumbLabelClassName = getBEMElement(
29+
defaultBreadcrumbClassName,
30+
'label'
31+
);
32+
33+
export function Breadcrumb(props: IBreadcrumb) {
34+
const { onClick, className, separator, routes = [], ...extra } = props;
35+
36+
const getEvents = (item: IBreadcrumbItem) => {
37+
return {
38+
onClick: function (e: React.MouseEvent) {
39+
onClick?.(e, item);
40+
},
41+
};
42+
};
43+
44+
const claNames = classNames(defaultBreadcrumbClassName, className);
45+
const len = routes.length;
46+
const sep = separator || <Icon type="chevron-right" />;
47+
return (
48+
<div className={claNames} {...extra}>
49+
{routes.map((route: IBreadcrumbItem, index: number) => (
50+
<a
51+
key={route.id}
52+
className={classNames(
53+
breadcrumbItemClassName,
54+
route.className
55+
)}
56+
href={route.href}
57+
{...getEvents(route)}
58+
>
59+
{route.icon}
60+
<span className={breadcrumbLabelClassName}>
61+
{route.render ? route.render(route) : route.name}
62+
</span>
63+
{len - index > 1 ? sep : null}
64+
</a>
65+
))}
66+
</div>
67+
);
68+
}

src/components/breadcrumb/style.scss

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@import 'mo/style/common';
2+
3+
#{$breadcrumb} {
4+
display: flex;
5+
6+
&__item {
7+
align-items: center;
8+
color: inherit;
9+
cursor: pointer;
10+
display: flex;
11+
justify-content: left;
12+
text-decoration: none;
13+
14+
&:hover {
15+
opacity: 0.8;
16+
}
17+
}
18+
19+
&__label {
20+
align-items: center;
21+
background-position: center center;
22+
background-repeat: no-repeat;
23+
background-size: 16px;
24+
display: flex;
25+
height: 100%;
26+
justify-content: center;
27+
text-decoration: none;
28+
width: 100%;
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import * as React from 'react';
2+
import { storiesOf } from '@storybook/react';
3+
import { withKnobs } from '@storybook/addon-knobs';
4+
import { propsTable } from '../common/propsTable';
5+
6+
import { Breadcrumb, IBreadcrumbItem } from 'mo/components/breadcrumb';
7+
8+
const stories = storiesOf('Breadcrumb', module);
9+
stories.addDecorator(withKnobs);
10+
11+
const propDefinitions = [
12+
{
13+
property: 'render',
14+
propType: '() => React.ReactNode',
15+
required: false,
16+
description: 'Default render content',
17+
defaultValue: null,
18+
},
19+
];
20+
21+
stories.add(
22+
'Basic Usage',
23+
() => {
24+
const click = (e, item) => {
25+
console.log('onClick breadcrumb item.', e, item);
26+
};
27+
28+
const data: IBreadcrumbItem[] = [
29+
{
30+
id: 'item1',
31+
name: 'item1',
32+
href: '#',
33+
},
34+
{
35+
id: 'item2',
36+
name: 'item1',
37+
href: '#',
38+
},
39+
{
40+
id: 'item3',
41+
name: 'item1',
42+
href: '#',
43+
},
44+
];
45+
46+
return (
47+
<div>
48+
<h2>简述</h2>
49+
<p>Breadcrumb component.</p>
50+
<h2>使用示例</h2>
51+
<div>
52+
<h3>Basic</h3>
53+
<Breadcrumb
54+
className="custom-list-1"
55+
onClick={click}
56+
routes={data}
57+
/>
58+
</div>
59+
</div>
60+
);
61+
},
62+
{
63+
info: {
64+
inline: true,
65+
TableComponent: () => propsTable({ propDefinitions }),
66+
// propTablesExclude: [],
67+
text: `
68+
代码示例:
69+
~~~js
70+
import { useContextView } from 'mo/components/contextview';
71+
72+
const contextView = useContextView();
73+
74+
const mouseMove = (event: React.MouseEvent): void => {
75+
contextView.show({
76+
x: event.clientX,
77+
y: event.clientY,
78+
}, () => {
79+
return (
80+
<h1>Hello World</h1>
81+
);
82+
});
83+
};
84+
85+
return (
86+
<div>
87+
<div id="topLeft"
88+
onMouseMove={mouseMove}
89+
style={
90+
{
91+
position: 'absolute',
92+
width: 200,
93+
height: 200,
94+
top: 0,
95+
left: 0,
96+
right: 0,
97+
bottom: 0,
98+
background: '#dddddd',
99+
}
100+
}>
101+
Hover me!
102+
</div>
103+
</div>
104+
);
105+
~~
106+
`,
107+
},
108+
}
109+
);

0 commit comments

Comments
 (0)