@snack-uikit/breadcrumbs 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +1 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +1 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.js +2 -2
- package/dist/components/Collapse/Collapse.js +17 -13
- package/dist/components/Crumb/Crumb.js +1 -1
- package/dist/components/Crumb/styles.module.css +1 -1
- package/dist/components/CrumbsTypography/CrumbsTypography.js +1 -1
- package/dist/components/HiddenChain/HiddenChain.d.ts +1 -0
- package/dist/components/HiddenChain/HiddenChain.js +3 -3
- package/dist/components/Separator/styles.module.css +3 -3
- package/dist/utils/buildBreadcrumbsConfigs.d.ts +1 -1
- package/dist/utils/buildBreadcrumbsConfigs.js +6 -2
- package/package.json +4 -4
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +4 -0
- package/src/components/Collapse/Collapse.tsx +50 -26
- package/src/components/Crumb/Crumb.tsx +1 -1
- package/src/components/CrumbsTypography/CrumbsTypography.tsx +1 -1
- package/src/components/HiddenChain/HiddenChain.tsx +4 -2
- package/src/utils/buildBreadcrumbsConfigs.ts +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 0.7.1 (2024-01-23)
|
|
7
|
+
|
|
8
|
+
### Only dependencies have been changed
|
|
9
|
+
* [@snack-uikit/droplist@0.12.5](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/droplist/CHANGELOG.md)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# 0.7.0 (2023-12-28)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **FF-3960:** change local droplist ([98abced](https://github.com/cloud-ru-tech/snack-uikit/commit/98abced33632f10accbf8140f4cdd99357d3e1ec))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
6
26
|
## 0.6.2 (2023-12-25)
|
|
7
27
|
|
|
8
28
|
### Only dependencies have been changed
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
| size | enum Size: `"xs"`, `"s"` | s | Размер |
|
|
20
20
|
| firstItemIconOnly | `boolean` | false | Использовать иконку без лейбла в первом айтеме |
|
|
21
21
|
| inactiveLastItem | `boolean` | false | Делает некликабельным последний элемент, даже если для него переданы `href` или `onClick` |
|
|
22
|
+
| lastEmpty | `boolean` | - | |
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
[//]: DOCUMENTATION_SECTION_END
|
|
@@ -22,13 +22,13 @@ import { Wrapper } from '../Wrapper';
|
|
|
22
22
|
* Компонент хлебных крошек
|
|
23
23
|
*/
|
|
24
24
|
export const Breadcrumbs = memo(function Breadcrumbs(_a) {
|
|
25
|
-
var { items: itemsProps, size = SIZE.S, separator = SEPARATOR, className, firstItemIconOnly = false, inactiveLastItem = false } = _a, rest = __rest(_a, ["items", "size", "separator", "className", "firstItemIconOnly", "inactiveLastItem"]);
|
|
25
|
+
var { items: itemsProps, size = SIZE.S, separator = SEPARATOR, className, firstItemIconOnly = false, inactiveLastItem = false, lastEmpty = false } = _a, rest = __rest(_a, ["items", "size", "separator", "className", "firstItemIconOnly", "inactiveLastItem", "lastEmpty"]);
|
|
26
26
|
const containerRef = useRef(null);
|
|
27
27
|
const { setConfigs, currentConfig } = useBreadcrumbsLayout(containerRef);
|
|
28
28
|
const items = useMemo(() => inactiveLastItem
|
|
29
29
|
? itemsProps.map((item, index) => index === itemsProps.length - 1 ? Object.assign(Object.assign({}, item), { onClick: undefined, href: undefined }) : item)
|
|
30
30
|
: itemsProps, [inactiveLastItem, itemsProps]);
|
|
31
|
-
return (_jsxs(_Fragment, { children: [_jsx(HiddenChain, { items: items, size: size, separator: separator, onConfigsBuilt: setConfigs, firstItemIconOnly: firstItemIconOnly }), _jsx(Wrapper, Object.assign({}, rest, { ref: containerRef, hidden: false, size: size, separator: separator, className: className, children: currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.chain.map((block, index, array) => {
|
|
31
|
+
return (_jsxs(_Fragment, { children: [_jsx(HiddenChain, { items: items, size: size, separator: separator, onConfigsBuilt: setConfigs, firstItemIconOnly: firstItemIconOnly, lastEmpty: lastEmpty }), _jsx(Wrapper, Object.assign({}, rest, { ref: containerRef, hidden: false, size: size, separator: separator, className: className, children: currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.chain.map((block, index, array) => {
|
|
32
32
|
const isLastElement = index === array.length - 1;
|
|
33
33
|
switch (block.element) {
|
|
34
34
|
case ELEMENT_TYPE.Separator:
|
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { useContext } from 'react';
|
|
3
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext, useState } from 'react';
|
|
3
|
+
import { Droplist } from '@snack-uikit/droplist';
|
|
4
4
|
import { ELEMENT_TYPE, ITEM_RENDER_MODE } from '../../constants';
|
|
5
5
|
import { BreadcrumbsContext } from '../../context';
|
|
6
6
|
import { getTestId } from '../../utils';
|
|
7
|
-
import { Crumb } from '../Crumb';
|
|
8
7
|
import { CrumbsTypography } from '../CrumbsTypography';
|
|
9
|
-
import { Separator } from '../Separator';
|
|
10
8
|
import styles from './styles.module.css';
|
|
11
9
|
export function Collapse({ currentConfig, className }) {
|
|
12
10
|
const ctx = useContext(BreadcrumbsContext);
|
|
13
11
|
const { hidden, size, testId } = ctx;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return (_jsxs("div", { className: styles.collapsedRow, children: [_jsx(Crumb, { item: node.item, renderMode: ITEM_RENDER_MODE.Full }), _jsx(Separator, {})] }, id));
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
12
|
+
const [open, setDroplistOpen] = useState(false);
|
|
13
|
+
const { handleTriggerKeyDown, handleDroplistItemKeyDown, handleDroplistItemClick, firstElementRefCallback, triggerElementRef, handleDroplistFocusLeave, } = Droplist.useKeyboardNavigation({
|
|
14
|
+
setDroplistOpen,
|
|
20
15
|
});
|
|
21
|
-
const
|
|
22
|
-
|
|
16
|
+
const collapsedItems = currentConfig
|
|
17
|
+
.filter(node => node.element === ELEMENT_TYPE.Item && node.item.renderMode === ITEM_RENDER_MODE.Collapsed)
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
.map((node) => {
|
|
21
|
+
const { id, label, onClick } = node.item;
|
|
22
|
+
return (_jsx(Droplist.ItemSingle, { option: label, onKeyDown: handleDroplistItemKeyDown, onClick: (e) => {
|
|
23
|
+
handleDroplistItemClick(e, onClick);
|
|
24
|
+
} }, id));
|
|
25
|
+
});
|
|
26
|
+
return (_jsx("div", { className: className, "data-test-id": getTestId('collapse', testId), "data-element-type": ELEMENT_TYPE.Collapse, children: _jsx(BreadcrumbsContext.Provider, { value: Object.assign(Object.assign({}, ctx), { testId: `${testId}-collapsed` }), children: _jsx(Droplist, { trigger: 'hoverAndFocusVisible', size: 's', open: open, onOpenChange: setDroplistOpen, firstElementRefCallback: firstElementRefCallback, onFocusLeave: handleDroplistFocusLeave, useScroll: true, triggerRef: triggerElementRef, triggerElement: _jsx("button", { className: styles.collapse, tabIndex: hidden ? -1 : 0, onKeyDown: handleTriggerKeyDown, children: _jsx(CrumbsTypography, { size: size, children: "..." }) }), children: collapsedItems }) }) }));
|
|
23
27
|
}
|
|
@@ -33,7 +33,7 @@ export const Crumb = memo(function Crumb(_a) {
|
|
|
33
33
|
'data-size': size,
|
|
34
34
|
'data-id': id,
|
|
35
35
|
};
|
|
36
|
-
const content = (_jsxs(_Fragment, { children: [Icon && (_jsx("div", { className: styles.icon, children: _jsx(Icon, { size:
|
|
36
|
+
const content = (_jsxs(_Fragment, { children: [Icon && (_jsx("div", { className: styles.icon, children: _jsx(Icon, { size: 16 }) })), !useIconOnly && (_jsx(CrumbsTypography, { size: size, className: styles.label, children: renderMode === ITEM_RENDER_MODE.ShortLabel ? shortLabel : label }))] }));
|
|
37
37
|
const tabIndex = hidden ? { tabIndex: -1 } : {};
|
|
38
38
|
const title = renderMode === ITEM_RENDER_MODE.Ellipsis ? label : '';
|
|
39
39
|
let crumb = null;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
outline-color:var(--sys-available-complementary, #131313);
|
|
34
34
|
}
|
|
35
35
|
.crumb[data-size=xs], a.crumb[data-size=xs]{
|
|
36
|
-
height:var(--size-breadcrumbs-xs,
|
|
36
|
+
height:var(--size-breadcrumbs-xs, 16px);
|
|
37
37
|
gap:var(--space-breadcrumbs-crumb-xs-gap, 2px);
|
|
38
38
|
}
|
|
39
39
|
.crumb[data-size=s], a.crumb[data-size=s]{
|
|
@@ -2,5 +2,5 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Typography } from '@snack-uikit/typography';
|
|
3
3
|
import { SIZE } from '../../constants';
|
|
4
4
|
export function CrumbsTypography({ size, children, className }) {
|
|
5
|
-
return (_jsx(Typography, { className: className, size: size === SIZE.S ? '
|
|
5
|
+
return (_jsx(Typography, { className: className, size: size === SIZE.S ? 'm' : 's', tag: 'div', family: 'sans', purpose: 'body', children: children }));
|
|
6
6
|
}
|
|
@@ -5,7 +5,7 @@ import { Collapse } from '../Collapse';
|
|
|
5
5
|
import { Separator } from '../Separator';
|
|
6
6
|
import { Wrapper } from '../Wrapper';
|
|
7
7
|
import { useItemModesRender } from './hooks';
|
|
8
|
-
export const HiddenChain = memo(function HiddenChain({ size, separator, items, onConfigsBuilt, firstItemIconOnly = false, }) {
|
|
8
|
+
export const HiddenChain = memo(function HiddenChain({ size, separator, items, onConfigsBuilt, firstItemIconOnly = false, lastEmpty = false, }) {
|
|
9
9
|
const containerRef = useRef(null);
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
const container = containerRef.current;
|
|
@@ -13,7 +13,7 @@ export const HiddenChain = memo(function HiddenChain({ size, separator, items, o
|
|
|
13
13
|
const observer = new ResizeObserver(([{ target }]) => {
|
|
14
14
|
const sizeMap = buildSizeMap(target);
|
|
15
15
|
if (sizeMap) {
|
|
16
|
-
onConfigsBuilt(buildBreadcrumbsConfigs(items, sizeMap));
|
|
16
|
+
onConfigsBuilt(buildBreadcrumbsConfigs(items, sizeMap, lastEmpty));
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
observer.observe(container);
|
|
@@ -21,7 +21,7 @@ export const HiddenChain = memo(function HiddenChain({ size, separator, items, o
|
|
|
21
21
|
observer.disconnect();
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
}, [items, onConfigsBuilt]);
|
|
24
|
+
}, [items, lastEmpty, onConfigsBuilt]);
|
|
25
25
|
const renderItemModes = useItemModesRender({ firstItemIconOnly });
|
|
26
26
|
return (_jsxs(Wrapper, { size: size, hidden: true, ref: containerRef, separator: separator, "data-test-id": 'hidden-wrapper', children: [_jsx(Separator, {}), _jsx(Collapse, { currentConfig: [] }), items.map(renderItemModes)] }));
|
|
27
27
|
});
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
color:var(--sys-neutral-text-disabled, #9e9e9e);
|
|
5
5
|
}
|
|
6
6
|
.separator[data-size=xs]{
|
|
7
|
-
height:var(--size-breadcrumbs-xs,
|
|
8
|
-
padding-left:var(--space-breadcrumbs-separator-padding-xs,
|
|
9
|
-
padding-right:var(--space-breadcrumbs-separator-padding-xs,
|
|
7
|
+
height:var(--size-breadcrumbs-xs, 16px);
|
|
8
|
+
padding-left:var(--space-breadcrumbs-separator-padding-xs, 4px);
|
|
9
|
+
padding-right:var(--space-breadcrumbs-separator-padding-xs, 4px);
|
|
10
10
|
}
|
|
11
11
|
.separator[data-size=s]{
|
|
12
12
|
height:var(--size-breadcrumbs-s, 24px);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { BreadcrumbsConfig, Item, SizeMap } from '../types';
|
|
2
|
-
export declare function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap): BreadcrumbsConfig[];
|
|
2
|
+
export declare function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap, lastEmpty?: boolean): BreadcrumbsConfig[];
|
|
@@ -45,7 +45,7 @@ const collapseAllRest = (lastElementRenderMode, rest) => rest.map((element, inde
|
|
|
45
45
|
const lastItem = index === array.length - 1;
|
|
46
46
|
return Object.assign(Object.assign({}, element), { renderMode: lastItem ? lastElementRenderMode : ITEM_RENDER_MODE.Collapsed });
|
|
47
47
|
});
|
|
48
|
-
export function buildBreadcrumbsConfigs(items, sizeMap) {
|
|
48
|
+
export function buildBreadcrumbsConfigs(items, sizeMap, lastEmpty) {
|
|
49
49
|
const chains = [];
|
|
50
50
|
const [first, ...rest] = items.map(item => (Object.assign(Object.assign({}, item), { renderMode: ITEM_RENDER_MODE.Full })));
|
|
51
51
|
buildSubChain(rest, { useCollapse: true, useEllipse: true }).forEach(subset => {
|
|
@@ -57,7 +57,7 @@ export function buildBreadcrumbsConfigs(items, sizeMap) {
|
|
|
57
57
|
chains.push(startsWithEllipsis(first, collapseAllRest(ITEM_RENDER_MODE.Ellipsis, rest)));
|
|
58
58
|
chains.push(startsWithCollapsed(first, collapseAllRest(ITEM_RENDER_MODE.Full, rest)));
|
|
59
59
|
chains.push(startsWithCollapsed(first, collapseAllRest(ITEM_RENDER_MODE.Ellipsis, rest)));
|
|
60
|
-
return chains.map(chain => chain.reduce((acc, item, index) => {
|
|
60
|
+
return chains.map(chain => chain.reduce((acc, item, index, array) => {
|
|
61
61
|
const { renderMode } = item;
|
|
62
62
|
if (index && RENDER_MODE_WITH_WIDTH.includes(renderMode)) {
|
|
63
63
|
acc.width += sizeMap.separator;
|
|
@@ -76,6 +76,10 @@ export function buildBreadcrumbsConfigs(items, sizeMap) {
|
|
|
76
76
|
acc.weight += RENDER_MODE_WEIGHT[item.renderMode];
|
|
77
77
|
acc.width += width;
|
|
78
78
|
acc.chain.push({ element: ELEMENT_TYPE.Item, item, width });
|
|
79
|
+
if (index === array.length - 1 && lastEmpty) {
|
|
80
|
+
acc.width += sizeMap.separator;
|
|
81
|
+
acc.chain.push({ element: ELEMENT_TYPE.Separator, width: sizeMap.separator });
|
|
82
|
+
}
|
|
79
83
|
return acc;
|
|
80
84
|
}, { chain: [], weight: 0, width: 0, hasCollapsed: false }));
|
|
81
85
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Breadcrumbs",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.7.1",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"license": "Apache-2.0",
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@snack-uikit/
|
|
36
|
-
"@snack-uikit/typography": "0.6.
|
|
35
|
+
"@snack-uikit/droplist": "0.12.5",
|
|
36
|
+
"@snack-uikit/typography": "0.6.1",
|
|
37
37
|
"@snack-uikit/utils": "3.2.0",
|
|
38
38
|
"classnames": "2.3.2",
|
|
39
39
|
"lodash.debounce": "4.0.8"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "c292f4c45173928f57cc5c9f3cb02efb26887b64"
|
|
42
42
|
}
|
|
@@ -36,6 +36,8 @@ export type BreadcrumbsProps = WithSupportProps<{
|
|
|
36
36
|
* @default false
|
|
37
37
|
*/
|
|
38
38
|
inactiveLastItem?: boolean;
|
|
39
|
+
|
|
40
|
+
lastEmpty?: boolean;
|
|
39
41
|
}>;
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -48,6 +50,7 @@ export const Breadcrumbs = memo(function Breadcrumbs({
|
|
|
48
50
|
className,
|
|
49
51
|
firstItemIconOnly = false,
|
|
50
52
|
inactiveLastItem = false,
|
|
53
|
+
lastEmpty = false,
|
|
51
54
|
...rest
|
|
52
55
|
}: BreadcrumbsProps) {
|
|
53
56
|
const containerRef = useRef<HTMLUListElement>(null);
|
|
@@ -72,6 +75,7 @@ export const Breadcrumbs = memo(function Breadcrumbs({
|
|
|
72
75
|
separator={separator}
|
|
73
76
|
onConfigsBuilt={setConfigs}
|
|
74
77
|
firstItemIconOnly={firstItemIconOnly}
|
|
78
|
+
lastEmpty={lastEmpty}
|
|
75
79
|
/>
|
|
76
80
|
<Wrapper {...rest} ref={containerRef} hidden={false} size={size} separator={separator} className={className}>
|
|
77
81
|
{currentConfig?.chain.map((block, index, array) => {
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { useContext } from 'react';
|
|
1
|
+
import { MouseEvent, useContext, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Droplist } from '@snack-uikit/droplist';
|
|
4
4
|
|
|
5
5
|
import { ELEMENT_TYPE, ITEM_RENDER_MODE } from '../../constants';
|
|
6
6
|
import { BreadcrumbsContext } from '../../context';
|
|
7
|
-
import { BreadcrumbsConfigChain } from '../../types';
|
|
7
|
+
import { BreadcrumbsConfigChain, InnerItem } from '../../types';
|
|
8
8
|
import { getTestId } from '../../utils';
|
|
9
|
-
import { Crumb } from '../Crumb';
|
|
10
9
|
import { CrumbsTypography } from '../CrumbsTypography';
|
|
11
|
-
import { Separator } from '../Separator';
|
|
12
10
|
import styles from './styles.module.scss';
|
|
13
11
|
|
|
14
12
|
export type CollapseProps = {
|
|
@@ -20,33 +18,59 @@ export function Collapse({ currentConfig, className }: CollapseProps) {
|
|
|
20
18
|
const ctx = useContext(BreadcrumbsContext);
|
|
21
19
|
const { hidden, size, testId } = ctx;
|
|
22
20
|
|
|
23
|
-
const
|
|
24
|
-
if (node.element === ELEMENT_TYPE.Item && node.item.renderMode === ITEM_RENDER_MODE.Collapsed) {
|
|
25
|
-
const { id } = node.item;
|
|
21
|
+
const [open, setDroplistOpen] = useState<boolean>(false);
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
const {
|
|
24
|
+
handleTriggerKeyDown,
|
|
25
|
+
handleDroplistItemKeyDown,
|
|
26
|
+
handleDroplistItemClick,
|
|
27
|
+
firstElementRefCallback,
|
|
28
|
+
triggerElementRef,
|
|
29
|
+
handleDroplistFocusLeave,
|
|
30
|
+
} = Droplist.useKeyboardNavigation<HTMLButtonElement>({
|
|
31
|
+
setDroplistOpen,
|
|
35
32
|
});
|
|
36
33
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
const collapsedItems = currentConfig
|
|
35
|
+
.filter(node => node.element === ELEMENT_TYPE.Item && node.item.renderMode === ITEM_RENDER_MODE.Collapsed)
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
.map((node: { element: typeof ELEMENT_TYPE.Item; width: number; item: InnerItem }) => {
|
|
39
|
+
const { id, label, onClick } = node.item;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Droplist.ItemSingle
|
|
43
|
+
option={label}
|
|
44
|
+
key={id}
|
|
45
|
+
onKeyDown={handleDroplistItemKeyDown}
|
|
46
|
+
onClick={(e: MouseEvent) => {
|
|
47
|
+
handleDroplistItemClick(e, onClick);
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
});
|
|
42
52
|
|
|
43
53
|
return (
|
|
44
54
|
<div className={className} data-test-id={getTestId('collapse', testId)} data-element-type={ELEMENT_TYPE.Collapse}>
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
<BreadcrumbsContext.Provider value={{ ...ctx, testId: `${testId}-collapsed` }}>
|
|
56
|
+
<Droplist
|
|
57
|
+
trigger='hoverAndFocusVisible'
|
|
58
|
+
size='s'
|
|
59
|
+
open={open}
|
|
60
|
+
onOpenChange={setDroplistOpen}
|
|
61
|
+
firstElementRefCallback={firstElementRefCallback}
|
|
62
|
+
onFocusLeave={handleDroplistFocusLeave}
|
|
63
|
+
useScroll
|
|
64
|
+
triggerRef={triggerElementRef}
|
|
65
|
+
triggerElement={
|
|
66
|
+
<button className={styles.collapse} tabIndex={hidden ? -1 : 0} onKeyDown={handleTriggerKeyDown}>
|
|
67
|
+
<CrumbsTypography size={size}>...</CrumbsTypography>
|
|
68
|
+
</button>
|
|
69
|
+
}
|
|
70
|
+
>
|
|
71
|
+
{collapsedItems}
|
|
72
|
+
</Droplist>
|
|
73
|
+
</BreadcrumbsContext.Provider>
|
|
50
74
|
</div>
|
|
51
75
|
);
|
|
52
76
|
}
|
|
@@ -12,7 +12,7 @@ export type CrumbsTypographyProps = PropsWithChildren<{
|
|
|
12
12
|
|
|
13
13
|
export function CrumbsTypography({ size, children, className }: CrumbsTypographyProps) {
|
|
14
14
|
return (
|
|
15
|
-
<Typography className={className} size={size === SIZE.S ? '
|
|
15
|
+
<Typography className={className} size={size === SIZE.S ? 'm' : 's'} tag='div' family='sans' purpose='body'>
|
|
16
16
|
{children}
|
|
17
17
|
</Typography>
|
|
18
18
|
);
|
|
@@ -13,6 +13,7 @@ export type HiddenChainProps = {
|
|
|
13
13
|
size: Size;
|
|
14
14
|
onConfigsBuilt(config: BreadcrumbsConfig[]): void;
|
|
15
15
|
firstItemIconOnly?: boolean;
|
|
16
|
+
lastEmpty?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export const HiddenChain = memo(function HiddenChain({
|
|
@@ -21,6 +22,7 @@ export const HiddenChain = memo(function HiddenChain({
|
|
|
21
22
|
items,
|
|
22
23
|
onConfigsBuilt,
|
|
23
24
|
firstItemIconOnly = false,
|
|
25
|
+
lastEmpty = false,
|
|
24
26
|
}: HiddenChainProps) {
|
|
25
27
|
const containerRef = useRef<HTMLUListElement>(null);
|
|
26
28
|
|
|
@@ -30,7 +32,7 @@ export const HiddenChain = memo(function HiddenChain({
|
|
|
30
32
|
const observer = new ResizeObserver(([{ target }]) => {
|
|
31
33
|
const sizeMap = buildSizeMap(target);
|
|
32
34
|
if (sizeMap) {
|
|
33
|
-
onConfigsBuilt(buildBreadcrumbsConfigs(items, sizeMap));
|
|
35
|
+
onConfigsBuilt(buildBreadcrumbsConfigs(items, sizeMap, lastEmpty));
|
|
34
36
|
}
|
|
35
37
|
});
|
|
36
38
|
observer.observe(container);
|
|
@@ -39,7 +41,7 @@ export const HiddenChain = memo(function HiddenChain({
|
|
|
39
41
|
observer.disconnect();
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
|
-
}, [items, onConfigsBuilt]);
|
|
44
|
+
}, [items, lastEmpty, onConfigsBuilt]);
|
|
43
45
|
|
|
44
46
|
const renderItemModes = useItemModesRender({ firstItemIconOnly });
|
|
45
47
|
|
|
@@ -18,8 +18,7 @@ const RENDER_MODE_WITH_WIDTH = [
|
|
|
18
18
|
|
|
19
19
|
const startsWith =
|
|
20
20
|
(renderMode: ItemRenderMode) =>
|
|
21
|
-
(item: InnerItem, tail: Chain): Chain =>
|
|
22
|
-
[{ ...item, renderMode }, ...tail];
|
|
21
|
+
(item: InnerItem, tail: Chain): Chain => [{ ...item, renderMode }, ...tail];
|
|
23
22
|
const startsWithFull = startsWith(ITEM_RENDER_MODE.Full);
|
|
24
23
|
const startsWithShortLabel = startsWith(ITEM_RENDER_MODE.ShortLabel);
|
|
25
24
|
const startsWithEllipsis = startsWith(ITEM_RENDER_MODE.Ellipsis);
|
|
@@ -72,7 +71,7 @@ const collapseAllRest = (lastElementRenderMode: ItemRenderMode, rest: InnerItem[
|
|
|
72
71
|
return { ...element, renderMode: lastItem ? lastElementRenderMode : ITEM_RENDER_MODE.Collapsed };
|
|
73
72
|
});
|
|
74
73
|
|
|
75
|
-
export function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap): BreadcrumbsConfig[] {
|
|
74
|
+
export function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap, lastEmpty?: boolean): BreadcrumbsConfig[] {
|
|
76
75
|
const chains: InnerItem[][] = [];
|
|
77
76
|
const [first, ...rest] = items.map(item => ({ ...item, renderMode: ITEM_RENDER_MODE.Full }));
|
|
78
77
|
|
|
@@ -89,7 +88,7 @@ export function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap): Breadc
|
|
|
89
88
|
|
|
90
89
|
return chains.map(chain =>
|
|
91
90
|
chain.reduce<BreadcrumbsConfig>(
|
|
92
|
-
(acc, item, index) => {
|
|
91
|
+
(acc, item, index, array) => {
|
|
93
92
|
const { renderMode } = item;
|
|
94
93
|
|
|
95
94
|
if (index && RENDER_MODE_WITH_WIDTH.includes(renderMode)) {
|
|
@@ -112,6 +111,11 @@ export function buildBreadcrumbsConfigs(items: Item[], sizeMap: SizeMap): Breadc
|
|
|
112
111
|
acc.width += width;
|
|
113
112
|
acc.chain.push({ element: ELEMENT_TYPE.Item, item, width });
|
|
114
113
|
|
|
114
|
+
if (index === array.length - 1 && lastEmpty) {
|
|
115
|
+
acc.width += sizeMap.separator;
|
|
116
|
+
acc.chain.push({ element: ELEMENT_TYPE.Separator, width: sizeMap.separator });
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
return acc;
|
|
116
120
|
},
|
|
117
121
|
{ chain: [], weight: 0, width: 0, hasCollapsed: false },
|