UNPKG

@carbon/react

Version:

React components for the Carbon Design System

175 lines (168 loc) 6.61 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. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js'); var React = require('react'); var PropTypes = require('prop-types'); var cx = require('classnames'); var usePrefix = require('../../internal/usePrefix.js'); var TableContext = require('./TableContext.js'); var useEvent = require('../../internal/useEvent.js'); var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js'); var debounce = require('../../node_modules/es-toolkit/dist/compat/function/debounce.js'); const isElementWrappingContent = (element, context) => { if (element.children.length > 0) { return false; } const computedStyles = window.getComputedStyle(element); context.font = computedStyles.font ? computedStyles.font : `${computedStyles.fontSize}" "${computedStyles.fontFamily}`; const measuredText = context?.measureText(element.textContent ?? ''); let textWidth = measuredText.width ?? 0; // account for letter spacing const letterSpacing = computedStyles.letterSpacing?.split('px'); if (letterSpacing && letterSpacing.length && !isNaN(Number(letterSpacing[0]))) { textWidth += Number(letterSpacing[0]) * (element.textContent?.length ?? 0); } // account for padding const paddingLeft = computedStyles.paddingLeft?.split('px'); if (paddingLeft && paddingLeft.length && !isNaN(Number(paddingLeft[0]))) { textWidth += Number(paddingLeft[0]); } const paddingRight = computedStyles.paddingLeft?.split('px'); if (paddingRight && paddingRight.length && !isNaN(Number(paddingRight[0]))) { textWidth += Number(paddingRight[0]); } // if measured textWidth is larger than the cell's width, then the content is being wrapped if (textWidth > element.getBoundingClientRect().width) { return true; } return false; }; const Table = ({ className, children, useZebraStyles, size = 'lg', isSortable = false, useStaticWidth, stickyHeader, overflowMenuOnHover = true, experimentalAutoAlign = false, ...other }) => { const { titleId, descriptionId } = React.useContext(TableContext.TableContext); const prefix = usePrefix.usePrefix(); const tableRef = React.useRef(null); const componentClass = cx(`${prefix}--data-table`, className, { [`${prefix}--data-table--${size}`]: size, [`${prefix}--data-table--sort`]: isSortable, [`${prefix}--data-table--zebra`]: useZebraStyles, [`${prefix}--data-table--static`]: useStaticWidth, [`${prefix}--data-table--sticky-header`]: stickyHeader, [`${prefix}--data-table--visible-overflow-menu`]: !overflowMenuOnHover }); const toggleTableBodyAlignmentClass = React.useCallback((alignTop = false) => { if (alignTop) { tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-body`); } else { tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-body`); } }, [prefix]); const toggleTableHeaderAlignmentClass = React.useCallback((alignTop = false) => { if (alignTop) { tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-header`); } else { tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-header`); } }, [prefix]); const setTableAlignment = React.useCallback(() => { if (experimentalAutoAlign) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); if (tableRef.current && context) { const isBodyMultiline = Array.from(tableRef.current.querySelectorAll('td')).some(td => isElementWrappingContent(td, context)); const isHeaderMultiline = Array.from(tableRef.current.querySelectorAll('th')).some(th => { const label = th.querySelector(`.${prefix}--table-header-label`); return label && isElementWrappingContent(label, context); }); toggleTableBodyAlignmentClass(isBodyMultiline); toggleTableHeaderAlignmentClass(isHeaderMultiline); } } else { toggleTableBodyAlignmentClass(false); toggleTableHeaderAlignmentClass(false); } }, [experimentalAutoAlign, toggleTableBodyAlignmentClass, toggleTableHeaderAlignmentClass, prefix]); const debouncedSetTableAlignment = debounce.debounce(setTableAlignment, 100); useEvent.useWindowEvent('resize', debouncedSetTableAlignment); // recalculate table alignment once fonts have loaded if (typeof document !== 'undefined' && document?.fonts?.status && document.fonts.status !== 'loaded') { document.fonts.ready.then(() => { setTableAlignment(); }); } useIsomorphicEffect.default(() => { setTableAlignment(); }, [setTableAlignment, size]); const table = /*#__PURE__*/React.createElement("div", { className: `${prefix}--data-table-content` }, /*#__PURE__*/React.createElement("table", _rollupPluginBabelHelpers.extends({ "aria-labelledby": titleId, "aria-describedby": descriptionId }, other, { className: componentClass, ref: tableRef }), children)); return stickyHeader ? /*#__PURE__*/React.createElement("section", { className: `${prefix}--data-table_inner-container` }, table) : table; }; Table.propTypes = { /** * Pass in the children that will be rendered within the Table */ children: PropTypes.node, className: PropTypes.string, /** * Experimental property. Allows table to align cell contents to the top if there is text wrapping in the content. Might have performance issues, intended for smaller tables */ experimentalAutoAlign: PropTypes.bool, /** * `false` If true, will apply sorting styles */ isSortable: PropTypes.bool, /** * Specify whether the overflow menu (if it exists) should be shown always, or only on hover */ overflowMenuOnHover: PropTypes.bool, /** * Change the row height of table. Currently supports `xs`, `sm`, `md`, `lg`, and `xl`. */ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']), /** * `false` If true, will keep the header sticky (only data rows will scroll) */ stickyHeader: PropTypes.bool, /** * If `true`, sets the table width to `auto` instead of `100%`. */ useStaticWidth: PropTypes.bool, /** * `true` to add useZebraStyles striping. */ useZebraStyles: PropTypes.bool, /** * Specify the table tabIndex */ tabIndex: PropTypes.number }; exports.Table = Table; exports.default = Table;