UNPKG

@carbon/react

Version:

React components for the Carbon Design System

138 lines (134 loc) 4.28 kB
/** * Copyright IBM Corp. 2016, 2023 * * 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 { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js'; import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { LayoutConstraint } from '../Layout/index.js'; import { useId } from '../../internal/useId.js'; import { usePrefix } from '../../internal/usePrefix.js'; import ContainedListItem from './ContainedListItem/ContainedListItem.js'; import Search from '../Search/Search.js'; import '../Search/Search.Skeleton.js'; const variants = ['on-page', 'disclosed']; function filterChildren(children) { if (Array.isArray(children)) { return children?.filter(child => !['Search', 'ExpandableSearch'].includes(child?.type?.displayName)); } if (children && !['Search', 'ExpandableSearch'].includes(children?.type?.displayName)) { return children; } return null; } function renderChildren(children) { if (Array.isArray(children)) { children.map((child, index) => { if (index === 0 && child.type === Search) { return child; } return child; }); } if (children && children.type === Search) { return children; } return children; } const ContainedList = ({ action, children, className, isInset, kind = variants[0], label, size, ...rest }) => { const labelId = `${useId('contained-list')}-header`; const prefix = usePrefix(); const classes = cx(`${prefix}--contained-list`, { [`${prefix}--contained-list--inset-rulers`]: isInset, [`${prefix}--contained-list--${size}`]: size, // TODO: V12 - Remove this class [`${prefix}--layout--size-${size}`]: size }, `${prefix}--contained-list--${kind}`, className); const filteredChildren = filterChildren(children); function isSearchAction(action) { if (! /*#__PURE__*/React.isValidElement(action)) { return false; } const actionTypes = ['Search', 'ExpandableSearch']; let actionType = ''; if (typeof action.type === 'string') { actionType = action.type; } else { actionType = action.type.displayName || ''; } return actionTypes.includes(actionType); } const isActionSearch = isSearchAction(action); const renderedChildren = renderChildren(children); return /*#__PURE__*/React.createElement("div", _extends({ className: classes }, rest), label && /*#__PURE__*/React.createElement("div", { className: `${prefix}--contained-list__header` }, /*#__PURE__*/React.createElement("div", { id: labelId, className: `${prefix}--contained-list__label` }, label), /*#__PURE__*/React.createElement(LayoutConstraint, { size: { min: 'sm', max: 'xl' }, className: `${prefix}--contained-list__action` }, action)), children && /*#__PURE__*/ /** * Webkit removes implicit "list" semantics when "list-style-type: none" is set. * Explicitly setting the "list" role ensures assistive technology in webkit * browsers correctly announce the semantics. * * Ref https://bugs.webkit.org/show_bug.cgi?id=170179#c1 */ // eslint-disable-next-line jsx-a11y/no-redundant-roles React.createElement("ul", { role: "list", "aria-labelledby": label ? labelId : undefined }, isActionSearch ? filteredChildren : renderedChildren)); }; ContainedList.propTypes = { /** * A slot for a possible interactive element to render. */ action: PropTypes.node, /** * A collection of ContainedListItems to be rendered in the ContainedList */ children: PropTypes.node, /** * Additional CSS class names. */ className: PropTypes.string, /** * Specify whether the dividing lines in between list items should be inset. */ isInset: PropTypes.bool, /** * The kind of ContainedList you want to display */ kind: PropTypes.oneOf(variants), /** * A label describing the contained list. */ label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), /** * Specify the size of the contained list. */ size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']) }; ContainedList.ContainedListItem = ContainedListItem; export { ContainedList as default };