UNPKG

@carbon/react

Version:

React components for the Carbon Design System

152 lines (150 loc) 5.54 kB
/** * Copyright IBM Corp. 2016, 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 { usePrefix } from "../../internal/usePrefix.js"; import { useId } from "../../internal/useId.js"; import { isComponentElement } from "../../internal/utils.js"; import { AILabel } from "../AILabel/index.js"; import { sortStates } from "./state/sortStates.js"; import classNames from "classnames"; import { cloneElement, forwardRef, useRef } from "react"; import PropTypes from "prop-types"; import { jsx, jsxs } from "react/jsx-runtime"; import { ArrowUp, ArrowsVertical } from "@carbon/icons-react"; //#region src/components/DataTable/TableHeader.tsx /** * Copyright IBM Corp. 2016, 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. */ const defaultScope = "col"; const translationIds = { "carbon.table.header.icon.description": "carbon.table.header.icon.description" }; const defaultTranslations = { [translationIds["carbon.table.header.icon.description"]]: "Click to sort rows by header in ascending order" }; const defaultTranslateWithId = (messageId, args) => { if (args && messageId === translationIds["carbon.table.header.icon.description"]) { if (args.isSortHeader && sortStates) { if (args.sortDirection === sortStates.NONE) return `Click to sort rows by ${args.header} header in ascending order`; if (args.sortDirection === sortStates.ASC) return `Click to sort rows by ${args.header} header in descending order`; return `Click to unsort rows by ${args.header} header`; } return `Click to sort rows by ${args.header} header in ascending order`; } return defaultTranslations[messageId]; }; const sortDirections = { [sortStates.NONE]: "none", [sortStates.ASC]: "ascending", [sortStates.DESC]: "descending" }; const TableHeader = forwardRef((props, ref) => { const { className: headerClassName, children, colSpan, decorator, isSortable = false, isSortHeader, onClick, scope = defaultScope, sortDirection, translateWithId: t = defaultTranslateWithId, slug, id, ...rest } = props; const prefix = usePrefix(); const uniqueId = useId("table-sort"); const AILableRef = useRef(null); const candidate = slug ?? decorator; const candidateIsAILabel = isComponentElement(candidate, AILabel); const colHasAILabel = candidateIsAILabel; const normalizedDecorator = candidateIsAILabel ? cloneElement(candidate, { size: "mini", ref: AILableRef }) : candidate; const headerLabelClassNames = classNames({ [`${prefix}--table-header-label`]: true, [`${prefix}--table-header-label--slug ${prefix}--table-header-label--ai-label`]: colHasAILabel, [`${prefix}--table-header-label--decorator`]: decorator }); if (!isSortable) return /* @__PURE__ */ jsx("th", { ...rest, id, className: headerClassName, scope, colSpan, ref, children: children ? /* @__PURE__ */ jsxs("div", { className: headerLabelClassNames, children: [children, /* @__PURE__ */ jsx("div", { className: `${prefix}--table-header-label--decorator-inner`, children: normalizedDecorator })] }) : null }); const className = classNames(headerClassName, { [`${prefix}--table-sort`]: true, [`${prefix}--table-sort--active`]: isSortHeader && sortDirection !== sortStates.NONE, [`${prefix}--table-sort--descending`]: isSortHeader && sortDirection === sortStates.DESC }); const ariaSort = !isSortHeader || !sortDirection ? "none" : sortDirections[sortDirection]; const sortDescription = t && t("carbon.table.header.icon.description", { header: children, sortDirection, isSortHeader, sortStates }); const headerClasses = classNames(headerClassName, `${prefix}--table-sort__header`, { [`${prefix}--table-sort__header--ai-label`]: colHasAILabel, [`${prefix}--table-sort__header--decorator`]: decorator }); const handleClick = (evt) => { if (colHasAILabel && AILableRef.current && AILableRef.current.contains(evt.target)) return; else if (onClick) return onClick(evt); }; return /* @__PURE__ */ jsxs("th", { id, "aria-sort": ariaSort, className: headerClasses, colSpan, ref, scope, children: [/* @__PURE__ */ jsx("div", { className: `${prefix}--table-sort__description`, id: uniqueId, children: sortDescription }), /* @__PURE__ */ jsx("button", { type: "button", "aria-describedby": uniqueId, className, onClick: handleClick, ...rest, children: /* @__PURE__ */ jsxs("span", { className: `${prefix}--table-sort__flex`, children: [ /* @__PURE__ */ jsx("div", { className: `${prefix}--table-header-label`, children }), /* @__PURE__ */ jsx(ArrowUp, { size: 20, className: `${prefix}--table-sort__icon` }), /* @__PURE__ */ jsx(ArrowsVertical, { size: 20, className: `${prefix}--table-sort__icon-unsorted` }), /* @__PURE__ */ jsx("div", { className: `${prefix}--table-header-label--decorator-inner`, children: normalizedDecorator }) ] }) })] }); }); TableHeader.propTypes = { children: PropTypes.node, className: PropTypes.string, colSpan: PropTypes.number, id: PropTypes.string, isSortHeader: PropTypes.bool, isSortable: PropTypes.bool, onClick: PropTypes.func, scope: PropTypes.string, sortDirection: PropTypes.oneOf(Object.values(sortStates)), translateWithId: PropTypes.func }; TableHeader.displayName = "TableHeader"; //#endregion export { TableHeader as default };