Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,23 @@ export type BreadcrumbSlots = {
// @public
export type BreadcrumbState = ComponentState<BreadcrumbSlots> & Required<Pick<BreadcrumbProps, 'appearance' | 'iconPosition' | 'size' | 'dividerType'>>;

// @public (undocumented)
export type PartitionBreadcrumbItems<T> = {
startDisplayedItems: readonly T[];
overflowItems?: readonly T[];
endDisplayedItems?: readonly T[];
};

// @public
export const partitionBreadcrumbItems: <T>(options: PartitionBreadcrumbItemsOptions<T>) => PartitionBreadcrumbItems<T>;

// @public (undocumented)
export type PartitionBreadcrumbItemsOptions<T> = {
items: readonly T[];
maxDisplayedItems?: number;
overflowIndex?: number;
};

// @public
export const renderBreadcrumb_unstable: (state: BreadcrumbState, contextValues: BreadcrumbContextValues) => JSX.Element;

Expand Down
2 changes: 2 additions & 0 deletions packages/react-components/react-breadcrumb/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export {
useBreadcrumbItem_unstable,
} from './BreadcrumbItem';
export type { BreadcrumbItemProps, BreadcrumbItemSlots, BreadcrumbItemState } from './BreadcrumbItem';
export { partitionBreadcrumbItems } from './utils/index';
export type { PartitionBreadcrumbItemsOptions, PartitionBreadcrumbItems } from './utils/index';
export {
BreadcrumbButton,
breadcrumbButtonClassNames,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { partitionBreadcrumbItems } from './partitionBreadcrumbItems';
export type { PartitionBreadcrumbItems, PartitionBreadcrumbItemsOptions } from './partitionBreadcrumbItems';
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { partitionBreadcrumbItems, PartitionBreadcrumbItemsOptions } from './partitionBreadcrumbItems';
const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const testData = [
[
{ items, overflowIndex: 2, maxDisplayedItems: 3 },
{ startDisplayedItems: [0, 1], overflowItems: [2, 3, 4, 5, 6, 7, 8, 9], endDisplayedItems: [10] },
],
[
{ items, maxDisplayedItems: 8, overflowIndex: 7 },
{ startDisplayedItems: [0, 1, 2, 3, 4, 5, 6], overflowItems: [7, 8, 9], endDisplayedItems: [10] },
],
[
{ items, maxDisplayedItems: 2, overflowIndex: 2 },
{ startDisplayedItems: [0], overflowItems: [1, 2, 3, 4, 5, 6, 7, 8, 9], endDisplayedItems: [10] },
],
[
{ items, maxDisplayedItems: 3, overflowIndex: 3 },
{ startDisplayedItems: [0, 1], overflowItems: [2, 3, 4, 5, 6, 7, 8, 9], endDisplayedItems: [10] },
],
[
{ items, maxDisplayedItems: 7, overflowIndex: 7 },
{ startDisplayedItems: [0, 1, 2, 3, 4, 5], overflowItems: [6, 7, 8, 9], endDisplayedItems: [10] },
],
[
{ items, maxDisplayedItems: 9, overflowIndex: 9 },
{ startDisplayedItems: [0, 1, 2, 3, 4, 5, 6, 7], overflowItems: [8, 9], endDisplayedItems: [10] },
],
];

const maxDisplayedItemsData = [
[
{ items, maxDisplayedItems: 3 },
{ startDisplayedItems: [0], overflowItems: [1, 2, 3, 4, 5, 6, 7, 8], endDisplayedItems: [9, 10] },
],
[
{ items, maxDisplayedItems: 2 },
{ startDisplayedItems: [0], overflowItems: [1, 2, 3, 4, 5, 6, 7, 8, 9], endDisplayedItems: [10] },
],
];
const overflowIndexData = [
[
{ items, overflowIndex: 2 },
{ startDisplayedItems: [0, 1], overflowItems: [2, 3, 4, 5, 6], endDisplayedItems: [7, 8, 9, 10] },
],
[
{ items, overflowIndex: 0 },
{ startDisplayedItems: [], overflowItems: [0, 1, 2, 3, 4], endDisplayedItems: [5, 6, 7, 8, 9, 10] },
],
];

describe('partitionBreadcrumbItems method', () => {
it.each(testData)("splits items correctly '%s'", (testItems, expected) => {
expect(partitionBreadcrumbItems(testItems as PartitionBreadcrumbItemsOptions<number>)).toStrictEqual(expected);
});
it.each(maxDisplayedItemsData)(
"splits items correctly if maxDisplayedItems are passed '%s'",
(testItems, expected) => {
expect(partitionBreadcrumbItems(testItems as PartitionBreadcrumbItemsOptions<number>)).toStrictEqual(expected);
},
);
it.each(overflowIndexData)("splits items correctly if overflowINdex is passed '%s'", (testItems, expected) => {
expect(partitionBreadcrumbItems(testItems as PartitionBreadcrumbItemsOptions<number>)).toStrictEqual(expected);
});
expect(partitionBreadcrumbItems({ items } as PartitionBreadcrumbItemsOptions<number>)).toStrictEqual({
startDisplayedItems: [0],
overflowItems: [1, 2, 3, 4, 5],
endDisplayedItems: [6, 7, 8, 9, 10],
});
expect(partitionBreadcrumbItems({} as PartitionBreadcrumbItemsOptions<number>)).toStrictEqual({
startDisplayedItems: [],
overflowItems: undefined,
endDisplayedItems: undefined,
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const DEFAULT_OVERFLOW_INDEX = 1;
const DEFAULT_MAX_DISPLAYED_ITEMS = 6;

export type PartitionBreadcrumbItemsOptions<T> = {
items: readonly T[];
maxDisplayedItems?: number;
overflowIndex?: number;
};

export type PartitionBreadcrumbItems<T> = {
startDisplayedItems: readonly T[];
overflowItems?: readonly T[];
endDisplayedItems?: readonly T[];
};

/**
* Get the displayed items and overflowing items based on the array of BreadcrumbItems needed for Breadcrumb.
*
* @param options - Configure the partition options
*
* @returns Three arrays split into displayed items and overflow items based on maxDisplayedItems.
*/
export const partitionBreadcrumbItems = <T>(
options: PartitionBreadcrumbItemsOptions<T>,
): PartitionBreadcrumbItems<T> => {
let startDisplayedItems;
let overflowItems;
let endDisplayedItems;

const { items = [] } = options;
const itemsCount = items.length;
const maxDisplayedItems = getMaxDisplayedItems(options.maxDisplayedItems);
let overflowIndex = options.overflowIndex ?? DEFAULT_OVERFLOW_INDEX;
startDisplayedItems = items.slice(0, overflowIndex);

const numberItemsToHide = itemsCount - maxDisplayedItems;

if (numberItemsToHide > 0) {
overflowIndex = overflowIndex === maxDisplayedItems ? overflowIndex - 1 : overflowIndex;
const menuLastItemIdx = overflowIndex + numberItemsToHide;

startDisplayedItems = startDisplayedItems.slice(0, overflowIndex);
overflowItems = items.slice(overflowIndex, menuLastItemIdx);
endDisplayedItems = items.slice(menuLastItemIdx, itemsCount);
}

return {
startDisplayedItems,
overflowItems,
endDisplayedItems,
};
};

function getMaxDisplayedItems(maxDisplayedItems: number | undefined) {
return maxDisplayedItems && maxDisplayedItems >= 0 ? maxDisplayedItems : DEFAULT_MAX_DISPLAYED_ITEMS;
}
Loading