@carbon/ibm-products
Version:
Carbon for IBM Products
278 lines (276 loc) • 11.1 kB
JavaScript
/**
* Copyright IBM Corp. 2020, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { __toESM } from "../../_virtual/_rolldown/runtime.js";
import { require_classnames } from "../../node_modules/classnames/index.js";
import { pkg } from "../../settings.js";
import { TearsheetNarrow } from "../Tearsheet/TearsheetNarrow.js";
import { NotFoundEmptyState } from "../EmptyStates/NotFoundEmptyState/NotFoundEmptyState.js";
import { Tearsheet } from "../Tearsheet/Tearsheet.js";
import { AddSelectSidebar } from "./AddSelectSidebar.js";
import { AddSelectBreadcrumbs } from "./AddSelectBreadcrumbs.js";
import { AddSelectList } from "./AddSelectList.js";
import { AddSelectSort } from "./AddSelectSort.js";
import { getFilteredItems, sortItems } from "./add-select-utils.js";
import { useItemSort } from "./hooks/useItemSort.js";
import useParentSelect from "./hooks/useParentSelect.js";
import { AddSelectColumn } from "./AddSelectColumn.js";
import { AddSelectFilter } from "./AddSelectFilter.js";
import usePath from "./hooks/usePath.js";
import React, { forwardRef, useState } from "react";
import PropTypes from "prop-types";
import { Tag } from "@carbon/react";
//#region src/components/AddSelect/AddSelectBody.tsx
var import_classnames = /* @__PURE__ */ __toESM(require_classnames());
const blockClass = `${pkg.prefix}--add-select`;
const componentName = "AddSelectBody";
const AddSelectBody = forwardRef(({ className, clearFiltersText, closeIconDescription, columnInputPlaceholder, defaultModifiers, description, filterByLabel, globalFilterOpts, globalFiltersLabel, globalFiltersIconDescription, globalFiltersPlaceholderText, globalFiltersPrimaryButtonText, globalFiltersSecondaryButtonText, globalSearchLabel, globalSearchPlaceholder, globalSortBy, illustrationTheme, influencerTitle, items, itemsLabel, metaIconDescription, metaPanelTitle, multi, navIconDescription, noResultsDescription, noResultsTitle, noSelectionDescription, noSelectionTitle, noTearsheet = false, normalizedItems, onClose, onCloseButtonText, onSubmit, onSubmitButtonText, open, portalTarget, searchResultsTitle, sortByLabel, title, useNormalizedItems, ...rest }, ref) => {
const [singleSelection, setSingleSelection] = useState("");
const [multiSelection, setMultiSelection] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const [appliedGlobalFilters, setAppliedGlobalFilters] = useState({});
const [displayMetalPanel, setDisplayMetaPanel] = useState({});
const [appliedModifiers, setAppliedModifiers] = useState(defaultModifiers);
const { sortDirection, setSortDirection, sortAttribute, setSortAttribute } = useItemSort();
const { parentSelected, setParentSelected } = useParentSelect();
const { path, setPath, pathOnclick, resetPath } = usePath(itemsLabel);
const resetState = () => {
setSingleSelection("");
setMultiSelection([]);
setSearchTerm("");
setAppliedGlobalFilters({});
setDisplayMetaPanel({});
setAppliedModifiers(defaultModifiers);
setSortAttribute("");
setSortDirection("");
setParentSelected(null);
resetPath();
};
const onCloseHandler = () => {
resetState();
onClose?.();
};
const tearsheetClassnames = (0, import_classnames.default)(className, blockClass, {
[`${blockClass}__single`]: !multi,
[`${blockClass}__multi`]: multi
});
const globalFilterKeys = Object.keys(appliedGlobalFilters);
const globalFiltersApplied = globalFilterKeys.length > 0;
const handleSearch = (term) => {
setSearchTerm(term);
};
const handleFilter = (filters) => {
setAppliedGlobalFilters(filters);
};
const submitHandler = () => {
if (multi && appliedModifiers && appliedModifiers?.length > 0) {
const selections = multiSelection.map((item) => {
return appliedModifiers.find((mod) => mod.id === item);
});
onSubmit?.(selections);
} else if (multi && appliedModifiers?.length === 0) onSubmit?.(multiSelection);
else onSubmit?.(singleSelection);
onCloseHandler();
};
const setShowBreadsCrumbs = () => {
if (useNormalizedItems === false || searchTerm || globalFiltersApplied) return false;
return true;
};
const setShowTags = () => {
if (searchTerm) return true;
if (useNormalizedItems && multi) return false;
return true;
};
const parentSelectionHandler = (id, title, parentId) => {
setParentSelected(id);
setPath(id, title, parentId);
};
const itemsToDisplay = getFilteredItems(useNormalizedItems, normalizedItems, searchTerm, globalFiltersApplied, globalFilterKeys, appliedGlobalFilters, sortItems(sortAttribute, sortDirection), multi, items, path);
const hasResults = itemsToDisplay.length > 0;
const showBreadsCrumbs = setShowBreadsCrumbs();
const showSort = (searchTerm || globalFiltersApplied) && hasResults;
const showTags = setShowTags();
const commonListProps = {
displayMetalPanel,
metaIconDescription,
multi,
multiSelection,
navIconDescription,
path,
setMultiSelection,
setPath,
setSingleSelection,
singleSelection,
setDisplayMetaPanel,
parentId: path[0].id
};
const commonTearsheetProps = {
...rest,
className: tearsheetClassnames,
open,
title,
description,
actions: [{
label: onCloseButtonText,
kind: "secondary",
onClick: onCloseHandler
}, {
label: onSubmitButtonText,
kind: "primary",
onClick: submitHandler,
disabled: multi ? multiSelection.length === 0 : !singleSelection
}],
portalTarget,
ref
};
const sidebarProps = {
appliedModifiers,
closeIconDescription,
displayMetalPanel,
illustrationTheme,
influencerTitle,
items: useNormalizedItems ? normalizedItems : items?.entries,
metaPanelTitle,
modifiers: items?.modifiers,
multiSelection,
noSelectionDescription,
noSelectionTitle,
setDisplayMetaPanel
};
const displayColumnView = multi && useNormalizedItems && !searchTerm && !globalFiltersApplied;
const body = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
id: "add-select",
className: `${blockClass}__header`
}, /* @__PURE__ */ React.createElement(AddSelectFilter, {
inputLabel: globalSearchLabel,
inputPlaceholder: globalSearchPlaceholder,
searchTerm,
handleSearch,
multi,
filterOpts: globalFilterOpts,
filtersLabel: globalFiltersLabel,
handleFilter,
primaryButtonText: globalFiltersPrimaryButtonText,
secondaryButtonText: globalFiltersSecondaryButtonText,
placeholder: globalFiltersPlaceholderText,
iconDescription: globalFiltersIconDescription,
appliedFilters: appliedGlobalFilters,
hasFiltersApplied: globalFiltersApplied,
clearFiltersText
}), /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)(`${blockClass}__sub-header`, { [`${blockClass}__sub-header-multi`]: multi }) }, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__tags` }, showBreadsCrumbs ? /* @__PURE__ */ React.createElement(AddSelectBreadcrumbs, {
path,
onClick: pathOnclick,
multi
}) : /* @__PURE__ */ React.createElement("p", { className: `${blockClass}__tags-label` }, searchTerm ? searchResultsTitle : itemsLabel), showTags && /* @__PURE__ */ React.createElement(Tag, {
type: "gray",
size: "sm"
}, itemsToDisplay.length)), showSort && /* @__PURE__ */ React.createElement(AddSelectSort, {
setSortAttribute,
setSortDirection,
sortBy: globalSortBy
}))), displayColumnView ? /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__columns` }, /* @__PURE__ */ React.createElement(AddSelectColumn, {
...commonListProps,
items: itemsToDisplay,
columnInputPlaceholder,
header: path[0]?.title,
filterByLabel,
sortByLabel
})) : /* @__PURE__ */ React.createElement("div", null, hasResults ? /* @__PURE__ */ React.createElement(AddSelectList, {
...commonListProps,
filteredItems: itemsToDisplay,
modifiers: items?.modifiers,
appliedModifiers,
setAppliedModifiers,
setParentSelected: parentSelectionHandler,
parentSelected,
parentId: parentSelected || path[0].id
}) : /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__body` }, /* @__PURE__ */ React.createElement(NotFoundEmptyState, {
subtitle: noResultsDescription,
title: noResultsTitle,
illustrationTheme
}))));
if (noTearsheet) return body;
if (multi) return /* @__PURE__ */ React.createElement(Tearsheet, {
...commonTearsheetProps,
influencer: multi && /* @__PURE__ */ React.createElement(AddSelectSidebar, sidebarProps),
influencerPosition: "right"
}, body);
return /* @__PURE__ */ React.createElement(TearsheetNarrow, commonTearsheetProps, body);
});
AddSelectBody.propTypes = {
className: PropTypes.string,
clearFiltersText: PropTypes.string,
closeIconDescription: PropTypes.string,
columnInputPlaceholder: PropTypes.string,
defaultModifiers: PropTypes.array,
description: PropTypes.string,
filterByLabel: PropTypes.string,
globalFilterOpts: PropTypes.array,
globalFiltersIconDescription: PropTypes.string,
globalFiltersLabel: PropTypes.string,
globalFiltersPlaceholderText: PropTypes.string,
globalFiltersPrimaryButtonText: PropTypes.string,
globalFiltersSecondaryButtonText: PropTypes.string,
globalSearchLabel: PropTypes.string.isRequired,
globalSearchPlaceholder: PropTypes.string,
globalSortBy: PropTypes.array,
illustrationTheme: PropTypes.oneOf(["light", "dark"]),
influencerTitle: PropTypes.string,
/**@ts-ignore */
items: PropTypes.shape({
modifiers: PropTypes.shape({
id: PropTypes.string,
label: PropTypes.string,
options: PropTypes.array,
multiSelect: PropTypes.bool
}),
sortBy: PropTypes.array,
filterBy: PropTypes.array,
entries: PropTypes.arrayOf(PropTypes.shape({
avatar: PropTypes.shape({
alt: PropTypes.string,
icon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
src: PropTypes.string,
theme: PropTypes.oneOf(["light", "dark"])
}),
children: PropTypes.object,
icon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
id: PropTypes.string.isRequired,
meta: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
title: PropTypes.string,
value: PropTypes.string
})), PropTypes.node]),
subtitle: PropTypes.string,
title: PropTypes.string.isRequired,
value: PropTypes.string.isRequired
}))
}),
itemsLabel: PropTypes.string,
metaIconDescription: PropTypes.string,
metaPanelTitle: PropTypes.string,
multi: PropTypes.bool,
navIconDescription: PropTypes.string,
noResultsDescription: PropTypes.string,
noResultsTitle: PropTypes.string,
noSelectionDescription: PropTypes.string,
noSelectionTitle: PropTypes.string,
normalizedItems: PropTypes.object,
onClose: PropTypes.func,
onCloseButtonText: PropTypes.string,
onSubmit: PropTypes.func,
onSubmitButtonText: PropTypes.string,
open: PropTypes.bool,
/**@ts-ignore */
portalTarget: PropTypes.node,
searchResultsTitle: PropTypes.string,
sortByLabel: PropTypes.string,
title: PropTypes.string,
useNormalizedItems: PropTypes.bool
};
AddSelectBody.displayName = componentName;
//#endregion
export { AddSelectBody };