UNPKG

@mskcc/carbon-react

Version:

Carbon react components for the MSKCC DSM

169 lines (160 loc) 7.05 kB
/** * MSKCC 2021, 2024 */ '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 debounce = require('lodash.debounce'); var usePrefix = require('../../internal/usePrefix.js'); var TableContext = require('./TableContext.js'); var useEvent = require('../../internal/useEvent.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes); var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx); var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce); 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 = _ref => { let { className, children, useZebraStyles, size = 'lg', isSortable = false, useStaticWidth, stickyHeader, overflowMenuOnHover = true, experimentalAutoAlign = false, ...other } = _ref; const { titleId, descriptionId } = React.useContext(TableContext.TableContext); const prefix = usePrefix.usePrefix(); const tableRef = React.useRef(null); const componentClass = cx__default["default"](`${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(function () { let alignTop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; alignTop ? tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-body`) : tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-body`); }, [prefix]); const toggleTableHeaderAlignmentClass = React.useCallback(function () { let alignTop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; alignTop ? tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-header`) : 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__default["default"](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(); }); } React.useLayoutEffect(() => { setTableAlignment(); }, [setTableAlignment, size]); const table = /*#__PURE__*/React__default["default"].createElement("div", { className: `${prefix}--data-table-content` }, /*#__PURE__*/React__default["default"].createElement("table", _rollupPluginBabelHelpers["extends"]({ "aria-labelledby": titleId, "aria-describedby": descriptionId }, other, { className: componentClass, ref: tableRef }), children)); return stickyHeader ? /*#__PURE__*/React__default["default"].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__default["default"].node, className: PropTypes__default["default"].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__default["default"].bool, /** * `false` If true, will apply sorting styles */ isSortable: PropTypes__default["default"].bool, /** * Specify whether the overflow menu (if it exists) should be shown always, or only on hover */ overflowMenuOnHover: PropTypes__default["default"].bool, /** * Change the row height of table. Currently supports `xs`, `sm`, `md`, `lg`, and `xl`. */ size: PropTypes__default["default"].oneOf(['xs', 'sm', 'md', 'lg', 'xl']), /** * `false` If true, will keep the header sticky (only data rows will scroll) */ stickyHeader: PropTypes__default["default"].bool, /** * `false` If true, will use a width of 'auto' instead of 100% */ useStaticWidth: PropTypes__default["default"].bool, /** * `true` to add useZebraStyles striping. */ useZebraStyles: PropTypes__default["default"].bool }; exports.Table = Table; exports["default"] = Table;