1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import classNames from "classnames";
|
18 | import * as React from "react";
|
19 | import { polyfill } from "react-lifecycles-compat";
|
20 |
|
21 | import { AbstractPureComponent2, Boundary, Classes, Props, Position, removeNonHTMLProps } from "../../common";
|
22 | import { Menu } from "../menu/menu";
|
23 | import { MenuItem } from "../menu/menuItem";
|
24 | import { OverflowListProps, OverflowList } from "../overflow-list/overflowList";
|
25 | import { IPopoverProps, Popover } from "../popover/popover";
|
26 | import { Breadcrumb, BreadcrumbProps } from "./breadcrumb";
|
27 |
|
28 |
|
29 | export type BreadcrumbsProps = IBreadcrumbsProps;
|
30 |
|
31 | export interface IBreadcrumbsProps extends Props {
|
32 | |
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | breadcrumbRenderer?: (props: BreadcrumbProps) => JSX.Element;
|
40 |
|
41 | |
42 |
|
43 |
|
44 |
|
45 |
|
46 | collapseFrom?: Boundary;
|
47 |
|
48 | |
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | currentBreadcrumbRenderer?: (props: BreadcrumbProps) => JSX.Element;
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 | items: BreadcrumbProps[];
|
62 |
|
63 | |
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | minVisibleItems?: number;
|
70 |
|
71 | |
72 |
|
73 |
|
74 |
|
75 | overflowListProps?: Partial<OverflowListProps<BreadcrumbProps>>;
|
76 |
|
77 | |
78 |
|
79 |
|
80 | popoverProps?: IPopoverProps;
|
81 | }
|
82 |
|
83 | @polyfill
|
84 | export class Breadcrumbs extends AbstractPureComponent2<BreadcrumbsProps> {
|
85 | public static defaultProps: Partial<BreadcrumbsProps> = {
|
86 | collapseFrom: Boundary.START,
|
87 | };
|
88 |
|
89 | public render() {
|
90 | const { className, collapseFrom, items, minVisibleItems, overflowListProps = {} } = this.props;
|
91 | return (
|
92 | <OverflowList
|
93 | collapseFrom={collapseFrom}
|
94 | minVisibleItems={minVisibleItems}
|
95 | tagName="ul"
|
96 | {...overflowListProps}
|
97 | className={classNames(Classes.BREADCRUMBS, overflowListProps.className, className)}
|
98 | items={items}
|
99 | overflowRenderer={this.renderOverflow}
|
100 | visibleItemRenderer={this.renderBreadcrumbWrapper}
|
101 | />
|
102 | );
|
103 | }
|
104 |
|
105 | private renderOverflow = (items: BreadcrumbProps[]) => {
|
106 | const { collapseFrom } = this.props;
|
107 | const position = collapseFrom === Boundary.END ? Position.BOTTOM_RIGHT : Position.BOTTOM_LEFT;
|
108 | let orderedItems = items;
|
109 | if (collapseFrom === Boundary.START) {
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | orderedItems = items.slice().reverse();
|
115 | }
|
116 |
|
117 |
|
118 | return (
|
119 | <li>
|
120 | <Popover
|
121 | position={position}
|
122 | disabled={orderedItems.length === 0}
|
123 | content={<Menu>{orderedItems.map(this.renderOverflowBreadcrumb)}</Menu>}
|
124 | {...this.props.popoverProps}
|
125 | >
|
126 | <span className={Classes.BREADCRUMBS_COLLAPSED} />
|
127 | </Popover>
|
128 | </li>
|
129 | );
|
130 |
|
131 | };
|
132 |
|
133 | private renderOverflowBreadcrumb = (props: BreadcrumbProps, index: number) => {
|
134 | const isClickable = props.href != null || props.onClick != null;
|
135 | const htmlProps = removeNonHTMLProps(props);
|
136 | return <MenuItem disabled={!isClickable} {...htmlProps} text={props.text} key={index} />;
|
137 | };
|
138 |
|
139 | private renderBreadcrumbWrapper = (props: BreadcrumbProps, index: number) => {
|
140 | const isCurrent = this.props.items[this.props.items.length - 1] === props;
|
141 | return <li key={index}>{this.renderBreadcrumb(props, isCurrent)}</li>;
|
142 | };
|
143 |
|
144 | private renderBreadcrumb(props: BreadcrumbProps, isCurrent: boolean) {
|
145 | if (isCurrent && this.props.currentBreadcrumbRenderer != null) {
|
146 | return this.props.currentBreadcrumbRenderer(props);
|
147 | } else if (this.props.breadcrumbRenderer != null) {
|
148 | return this.props.breadcrumbRenderer(props);
|
149 | } else {
|
150 |
|
151 | return <Breadcrumb current={isCurrent} {...props} />;
|
152 | }
|
153 | }
|
154 | }
|