@gravity-ui/uikit
Version:
Gravity UI base styling and components
154 lines (153 loc) • 7.13 kB
JavaScript
'use client';
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
import * as React from 'react';
import _throttle from "lodash/throttle.js";
import { block } from "../../utils/cn.js";
import { BreadcrumbsItem as Item } from "./BreadcrumbsItem.js";
import { BreadcrumbsMore } from "./BreadcrumbsMore.js";
import { BreadcrumbsSeparator } from "./BreadcrumbsSeparator.js";
import "./Breadcrumbs.css";
const RESIZE_THROTTLE = 200;
const MORE_ITEM_WIDTH = 34;
const DEFAULT_POPUP_PLACEMENT = ['bottom', 'top'];
const GAP_WIDTH = 4;
const b = block('breadcrumbs-legacy');
export var LastDisplayedItemsCount;
(function (LastDisplayedItemsCount) {
LastDisplayedItemsCount[LastDisplayedItemsCount["One"] = 1] = "One";
LastDisplayedItemsCount[LastDisplayedItemsCount["Two"] = 2] = "Two";
})(LastDisplayedItemsCount || (LastDisplayedItemsCount = {}));
export var FirstDisplayedItemsCount;
(function (FirstDisplayedItemsCount) {
FirstDisplayedItemsCount[FirstDisplayedItemsCount["Zero"] = 0] = "Zero";
FirstDisplayedItemsCount[FirstDisplayedItemsCount["One"] = 1] = "One";
})(FirstDisplayedItemsCount || (FirstDisplayedItemsCount = {}));
/**
* @deprecated
*/
export class Breadcrumbs extends React.Component {
static defaultProps = {
popupPlacement: DEFAULT_POPUP_PLACEMENT,
};
static prepareInitialState(props) {
const { firstDisplayedItemsCount } = props;
return {
calculated: false,
rootItem: firstDisplayedItemsCount ? props.items[0] : undefined,
visibleItems: props.items.slice(firstDisplayedItemsCount),
hiddenItems: [],
allItems: props.items,
};
}
static getDerivedStateFromProps(props, state) {
if (state.allItems !== props.items) {
return Breadcrumbs.prepareInitialState(props);
}
return null;
}
container;
resizeObserver;
constructor(props) {
super(props);
this.handleResize = _throttle(this.handleResize, RESIZE_THROTTLE);
if (typeof window !== 'undefined') {
this.resizeObserver = new ResizeObserver(this.handleResize);
}
this.container = React.createRef();
this.state = Breadcrumbs.prepareInitialState(props);
}
componentDidMount() {
this.recalculate();
this.resizeObserver?.observe(this.container.current);
}
componentDidUpdate(prevProps) {
if (prevProps.items !== this.state.allItems) {
this.recalculate();
}
}
componentWillUnmount() {
this.resizeObserver?.disconnect();
}
render() {
const { className, qa } = this.props;
const { calculated } = this.state;
return (_jsx("div", { className: b({ calculated: calculated ? 'yes' : 'no' }, className), "data-qa": qa, children: _jsxs("div", { className: b('inner'), ref: this.container, children: [this.renderRootItem(), this.renderMoreItem(), this.renderVisibleItems()] }) }));
}
renderItem(item, isCurrent, isPrevCurrent, renderItemContent) {
return (_jsx(Item, { item: item, isCurrent: isCurrent, isPrevCurrent: isPrevCurrent, renderItemContent: renderItemContent || this.props.renderItemContent, renderItem: this.props.renderItem }));
}
renderItemDivider() {
const { renderItemDivider } = this.props;
return _jsx(BreadcrumbsSeparator, { renderItemDivider: renderItemDivider });
}
renderRootItem() {
const { renderRootContent } = this.props;
const { rootItem, visibleItems } = this.state;
const isCurrent = visibleItems.length === 0;
if (!rootItem) {
return null;
}
return this.renderItem(rootItem, isCurrent, false, renderRootContent);
}
renderVisibleItems() {
const { visibleItems } = this.state;
return visibleItems.map((item, index, items) => {
const isCurrent = index === items.length - 1;
const isPrevCurrent = index === items.length - 2;
return (_jsxs(React.Fragment, { children: [this.renderItemDivider(), this.renderItem(item, isCurrent, isPrevCurrent)] }, index));
});
}
renderMoreItem() {
const { hiddenItems } = this.state;
if (hiddenItems.length === 0) {
return null;
}
const { popupStyle, popupPlacement, renderItemDivider } = this.props;
return (_jsxs(React.Fragment, { children: [_jsx(BreadcrumbsSeparator, { renderItemDivider: renderItemDivider }), _jsx(BreadcrumbsMore, { items: hiddenItems, popupPlacement: popupPlacement, popupStyle: popupStyle })] }));
}
recalculate() {
const { items: allItems, lastDisplayedItemsCount, firstDisplayedItemsCount } = this.props;
let availableWidth = this.container.current?.offsetWidth || 0;
if (this.container.current && availableWidth > 0) {
availableWidth += GAP_WIDTH;
const dividers = Array.from(this.container.current.querySelectorAll(`.${b('divider')}`));
const items = [
...Array.from(this.container.current.querySelectorAll(`.${b('switcher')}`)),
...Array.from(this.container.current.querySelectorAll(`.${b('item')}`)),
];
const itemsWidths = items.map((elem, i) => elem.scrollWidth + (i === items.length - 1 ? GAP_WIDTH : GAP_WIDTH * 2));
const dividersWidths = dividers.map((elem) => elem.offsetWidth);
const buttonsWidth = itemsWidths.reduce((total, width, index, widths) => {
const isLastItem = widths.length - 1 === index;
const isItemBeforeLast = lastDisplayedItemsCount === LastDisplayedItemsCount.Two &&
widths.length - 2 === index;
if (isLastItem || isItemBeforeLast) {
return total + Math.min(width, 200);
}
return total + width;
}, 0);
const dividersWidth = dividersWidths.reduce((total, width) => total + width, 0);
let totalWidth = buttonsWidth + dividersWidth;
let visibleItemsStartIndex = 1;
while (totalWidth > availableWidth &&
visibleItemsStartIndex < items.length - lastDisplayedItemsCount) {
if (visibleItemsStartIndex === 1) {
totalWidth += MORE_ITEM_WIDTH + dividersWidths[visibleItemsStartIndex];
}
totalWidth -=
itemsWidths[visibleItemsStartIndex] + dividersWidths[visibleItemsStartIndex];
visibleItemsStartIndex++;
}
this.setState({
calculated: true,
visibleItems: allItems.slice(visibleItemsStartIndex - (1 - firstDisplayedItemsCount)),
hiddenItems: allItems.slice(firstDisplayedItemsCount, visibleItemsStartIndex - (1 - firstDisplayedItemsCount)),
});
}
}
handleResize = () => {
const state = Breadcrumbs.prepareInitialState(this.props);
this.setState(state, this.recalculate);
};
}
//# sourceMappingURL=Breadcrumbs.js.map