@snack-uikit/breadcrumbs 0.6.2-preview-00fa1de0.0 → 0.7.0

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 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.0 (2023-12-28)
7
+
8
+
9
+ ### Features
10
+
11
+ * **FF-3960:** change local droplist ([98abced](https://github.com/cloud-ru-tech/snack-uikit/commit/98abced33632f10accbf8140f4cdd99357d3e1ec))
12
+
13
+
14
+
15
+
16
+
17
+ ## 0.6.2 (2023-12-25)
18
+
19
+ ### Only dependencies have been changed
20
+ * [@snack-uikit/popover@0.6.2](https://github.com/cloud-ru-tech/snack-uikit/blob/master/packages/popover/CHANGELOG.md)
21
+
22
+
23
+
24
+
25
+
6
26
  ## 0.6.1 (2023-12-14)
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
@@ -26,6 +26,7 @@ export type BreadcrumbsProps = WithSupportProps<{
26
26
  * @default false
27
27
  */
28
28
  inactiveLastItem?: boolean;
29
+ lastEmpty?: boolean;
29
30
  }>;
30
31
  /**
31
32
  * Компонент хлебных крошек
@@ -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, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useContext } from 'react';
3
- import { Popover } from '@snack-uikit/popover';
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 collapsedItems = currentConfig.map(node => {
15
- if (node.element === ELEMENT_TYPE.Item && node.item.renderMode === ITEM_RENDER_MODE.Collapsed) {
16
- const { id } = node.item;
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 tip = (_jsx(BreadcrumbsContext.Provider, { value: Object.assign(Object.assign({}, ctx), { testId: `${testId}-collapsed` }), children: collapsedItems }));
22
- return (_jsx("div", { className: className, "data-test-id": getTestId('collapse', testId), "data-element-type": ELEMENT_TYPE.Collapse, children: _jsx(Popover, { tip: tip, trigger: 'hoverAndFocusVisible', placement: 'top', children: _jsx("button", { className: styles.collapse, tabIndex: hidden ? -1 : 0, children: _jsx(CrumbsTypography, { size: size, children: "..." }) }) }) }));
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: 24 }) })), !useIconOnly && (_jsx(CrumbsTypography, { size: size, className: styles.label, children: renderMode === ITEM_RENDER_MODE.ShortLabel ? shortLabel : label }))] }));
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, 24px);
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 ? 'l' : 'm', tag: 'div', family: 'sans', purpose: 'body', children: children }));
5
+ return (_jsx(Typography, { className: className, size: size === SIZE.S ? 'm' : 's', tag: 'div', family: 'sans', purpose: 'body', children: children }));
6
6
  }
@@ -6,5 +6,6 @@ export type HiddenChainProps = {
6
6
  size: Size;
7
7
  onConfigsBuilt(config: BreadcrumbsConfig[]): void;
8
8
  firstItemIconOnly?: boolean;
9
+ lastEmpty?: boolean;
9
10
  };
10
11
  export declare const HiddenChain: import("react").NamedExoticComponent<HiddenChainProps>;
@@ -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, 24px);
8
- padding-left:var(--space-breadcrumbs-separator-padding-xs, 8px);
9
- padding-right:var(--space-breadcrumbs-separator-padding-xs, 8px);
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.6.2-preview-00fa1de0.0",
7
+ "version": "0.7.0",
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/popover": "0.6.2-preview-00fa1de0.0",
36
- "@snack-uikit/typography": "0.6.0",
35
+ "@snack-uikit/droplist": "0.12.4",
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": "197debfa780364e989e8de7c27ebe15474429c57"
41
+ "gitHead": "57c597a3eebaf6528c0c61b6b27dd244753de1cf"
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 { Popover } from '@snack-uikit/popover';
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 collapsedItems = currentConfig.map(node => {
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
- return (
28
- <div key={id} className={styles.collapsedRow}>
29
- <Crumb item={node.item} renderMode={ITEM_RENDER_MODE.Full} />
30
- <Separator />
31
- </div>
32
- );
33
- }
34
- return null;
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 tip = (
38
- <BreadcrumbsContext.Provider value={{ ...ctx, testId: `${testId}-collapsed` }}>
39
- {collapsedItems}
40
- </BreadcrumbsContext.Provider>
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
- <Popover tip={tip} trigger='hoverAndFocusVisible' placement='top'>
46
- <button className={styles.collapse} tabIndex={hidden ? -1 : 0}>
47
- <CrumbsTypography size={size}>...</CrumbsTypography>
48
- </button>
49
- </Popover>
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
  }
@@ -50,7 +50,7 @@ export const Crumb = memo(function Crumb({
50
50
  <>
51
51
  {Icon && (
52
52
  <div className={styles.icon}>
53
- <Icon size={24} />
53
+ <Icon size={16} />
54
54
  </div>
55
55
  )}
56
56
  {!useIconOnly && (
@@ -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 ? 'l' : 'm'} tag='div' family='sans' purpose='body'>
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 },