UNPKG

lucid-ui

Version:

A UI component library from Xandr.

730 lines 29.4 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Th = void 0; var lodash_1 = __importStar(require("lodash")); var react_1 = __importDefault(require("react")); var prop_types_1 = __importDefault(require("prop-types")); var style_helpers_1 = require("../../util/style-helpers"); var component_types_1 = require("../../util/component-types"); var ArrowIcon_1 = __importDefault(require("../Icon/ArrowIcon/ArrowIcon")); var DragCaptureZone_1 = __importDefault(require("../DragCaptureZone/DragCaptureZone")); var cx = style_helpers_1.lucidClassNames.bind('&-Table'); var any = prop_types_1.default.any, bool = prop_types_1.default.bool, func = prop_types_1.default.func, node = prop_types_1.default.node, number = prop_types_1.default.number, object = prop_types_1.default.object, string = prop_types_1.default.string, oneOf = prop_types_1.default.oneOf, oneOfType = prop_types_1.default.oneOfType; var Thead = function (props) { var children = props.children, className = props.className, passThroughs = __rest(props, ["children", "className"]); return (react_1.default.createElement("thead", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'className', 'children', 'initialState', 'callbackId', ]), { className: cx('&-Thead', className) }), renderRowsWithIdentifiedEdges((0, component_types_1.filterTypes)(children, Tr), Th))); }; Thead.displayName = 'Table.Thead'; Thead.peek = { description: "\n\t\t`Thead` renders <thead>.\n\t", }; Thead.propTypes = { /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** any valid React children */ children: node, }; var Tbody = function (props) { var children = props.children, className = props.className, passThroughs = __rest(props, ["children", "className"]); return (react_1.default.createElement("tbody", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'className', 'children', 'initialState', 'callbackId', ]), { className: cx('&-Tbody', className) }), renderRowsWithIdentifiedEdges((0, component_types_1.filterTypes)(children, Tr), Td))); }; Tbody.displayName = 'Table.Tbody'; Tbody.peek = { description: "\n\t\t`Tbody` renders <tbody>.\n\t", }; Tbody.propTypes = { /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** any valid React children */ children: node, }; var Tr = function (props) { var className = props.className, children = props.children, isDisabled = props.isDisabled, isSelected = props.isSelected, isActive = props.isActive, passThroughs = __rest(props, ["className", "children", "isDisabled", "isSelected", "isActive"]); return (react_1.default.createElement("tr", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'children', 'className', 'isDisabled', 'isSelected', 'isActive', 'isActionable', 'initialState', 'callbackId', ]), { className: cx('&-Tr', { '&-is-disabled': isDisabled, '&-is-selected': isSelected, '&-is-active': isActive, }, className) }), children)); }; Tr.defaultProps = { isDisabled: false, isSelected: false, isActive: false, }; Tr.displayName = 'Table.Tr'; Tr.peek = { description: "\n\t\t`Tr` renders <tr>.\n\t", }; Tr.propTypes = { /** any valid React children */ children: node, /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** Applies disabled styles to the row. */ isDisabled: bool, /** Applies styles to the row for when the row is selected, usually by a checkbox. */ isSelected: bool, /** Applies active styles to the row, usually when the row has been clicked. */ isActive: bool, }; var Th = /** @class */ (function (_super) { __extends(Th, _super); function Th() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.rootRef = react_1.default.createRef(); _this.state = { // Represents the actively changing width as the cell is resized. activeWidth: _this.props.width || null, // Indicates if a `width` prop was explicitly provided. hasSetWidth: !!_this.props.width, // Indicates whether the cell is currently being resized. isResizing: false, // Indicates a mouse drag is in progress isDragging: false, // Represents the width when the cell is not actively being resized. passiveWidth: _this.props.width || null, }; _this.getWidth = function () { var styleWidth = lodash_1.default.get(_this.rootRef, 'style.width'); if (lodash_1.default.endsWith(styleWidth, 'px')) { return parseInt(styleWidth); } if (_this.rootRef.current) { return _this.rootRef.current.getBoundingClientRect().width; } return null; }; _this.handleClickCapture = function (event) { if (_this.state.isDragging) { event.stopPropagation(); _this.setState({ isDragging: false, }); } }; _this.handleMouseEnter = function () { _this.setState({ isDragging: _this.state.isResizing, }); }; _this.handleMouseUp = function () { _this.setState({ isDragging: _this.state.isResizing, }); }; _this.handleDragEnded = function (coordinates, _a) { var event = _a.event; _this.setState({ isResizing: false, passiveWidth: _this.state.activeWidth, }); window.document.body.style.cursor = ''; if (_this.props.onResize) { _this.props.onResize(_this.state.activeWidth, { event: event, props: _this.props, }); } }; _this.handleDragged = function (coordinates, _a) { var event = _a.event, props = _a.props; var passiveWidth = _this.state.passiveWidth; var minWidth = _this.props.minWidth !== null && lodash_1.default.isString(_this.props.minWidth) ? parseInt(_this.props.minWidth) : _this.props.minWidth; if (passiveWidth === null) { return; } else if (lodash_1.default.isString(passiveWidth)) { passiveWidth = parseInt(passiveWidth); } var activeWidth = (minWidth && passiveWidth + coordinates.dX > minWidth) || !minWidth ? passiveWidth + coordinates.dX : minWidth; _this.setState({ activeWidth: activeWidth }); if (_this.props.onResize) { _this.props.onResize(activeWidth, { event: event, props: _this.props, }); } }; _this.handleDragStarted = function (coordinates, _a) { var event = _a.event, props = _a.props; var startingWidth = _this.getWidth(); _this.setState({ activeWidth: startingWidth, hasSetWidth: true, isResizing: true, isDragging: true, passiveWidth: startingWidth, }); window.document.body.style.cursor = 'ew-resize'; if (_this.props.onResize) { _this.props.onResize(startingWidth, { event: event, props: _this.props, }); } }; return _this; } Th.prototype.UNSAFE_componentWillReceiveProps = function (_a) { var width = _a.width; if (!lodash_1.default.isNil(width) && width !== this.props.width) { this.setState({ hasSetWidth: true, passiveWidth: width, }); } }; Th.prototype.render = function () { var _a = this.props, children = _a.children, className = _a.className, hasBorderRight = _a.hasBorderRight, hasBorderLeft = _a.hasBorderLeft, isFirstRow = _a.isFirstRow, isLastRow = _a.isLastRow, isFirstCol = _a.isFirstCol, isFirstSingle = _a.isFirstSingle, isLastCol = _a.isLastCol, align = _a.align, isResizable = _a.isResizable, isSortable = _a.isSortable, isSorted = _a.isSorted, sortDirection = _a.sortDirection, style = _a.style, truncateContent = _a.truncateContent, passThroughs = __rest(_a, ["children", "className", "hasBorderRight", "hasBorderLeft", "isFirstRow", "isLastRow", "isFirstCol", "isFirstSingle", "isLastCol", "align", "isResizable", "isSortable", "isSorted", "sortDirection", "style", "truncateContent"]); var _b = this.state, activeWidth = _b.activeWidth, hasSetWidth = _b.hasSetWidth, isResizing = _b.isResizing, passiveWidth = _b.passiveWidth; return (react_1.default.createElement("th", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'className', 'children', 'style', 'align', 'hasBorderRight', 'hasBorderLeft', 'isResizable', 'isSortable', 'isSorted', 'onResize', 'sortDirection', 'width', 'minWidth', 'isFirstRow', 'isLastRow', 'isFirstCol', 'isLastCol', 'isFirstSingle', 'field', 'truncateContent', 'initialState', 'callbackId', ]), { className: cx('&-Th', { '&-is-first-row': isFirstRow, '&-is-last-row': isLastRow, '&-is-first-col': isFirstCol, '&-is-first-single': isFirstSingle, '&-is-last-col': isLastCol, '&-align-left': align === 'left', '&-align-center': align === 'center', '&-align-right': align === 'right', '&-is-resizable': isResizable, '&-is-resizing': isResizing, '&-is-sortable': isSortable === false ? isSortable : isSorted || isSortable, '&-is-sorted': isSorted, '&-has-border-right': hasBorderRight, '&-has-border-left': hasBorderLeft, '&-truncate-content': truncateContent, }, className), ref: this.rootRef, onClickCapture: this.handleClickCapture, onMouseEnter: this.handleMouseEnter, onMouseUp: this.handleMouseUp, style: hasSetWidth ? lodash_1.default.assign({}, style, { width: isResizing ? activeWidth : passiveWidth, }) : style }), react_1.default.createElement("div", { className: cx('&-Th-inner') }, react_1.default.createElement("div", { className: cx('&-Th-inner-content') }, children), isSorted || isSortable ? (react_1.default.createElement("div", { className: cx('&-Th-inner-caret') }, react_1.default.createElement(ArrowIcon_1.default, { className: cx('&-sort-icon'), direction: sortDirection, size: 10 }))) : null, isResizable ? (react_1.default.createElement(DragCaptureZone_1.default, { className: cx('&-Th-inner-resize'), onDrag: this.handleDragged, onDragEnd: this.handleDragEnded, onDragStart: this.handleDragStarted })) : null))); }; Th.displayName = 'Table.Th'; Th.defaultProps = { align: 'left', isResizable: false, isSorted: false, sortDirection: 'up', rowSpan: 1, }; Th.peek = { description: "\n\t\t\t`Th` renders <th>.\n\t\t", }; Th.propTypes = { /** Aligns the content of a cell. Can be \`left\`, \`center\`, or \`right\`. */ align: string, /** any valid React children */ children: node, /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** Should be \`true\` to render a right border. */ hasBorderRight: bool, /** Should be \`true\` to render a left border. */ hasBorderLeft: bool, /** Styles the cell to indicate it should be resizable and sets up drag- related events to enable this resizing functionality. */ isResizable: bool, /** Styles the cell to allow column sorting. */ isSortable: bool, /** Renders a caret icon to show that the column is sorted. */ isSorted: bool, /** Called as the user drags the resize handle to resize the column atop which this table header cell sits. */ onResize: func, /** Sets the direction of the caret icon when \`isSorted\` is also set. */ sortDirection: oneOf(['left', 'up', 'right', 'down', undefined]), /** Styles that are passed through to root element. */ style: object, /** Sets the width of the cell. */ width: oneOfType([number, string]), /** Sets the min width of the cell. */ minWidth: oneOfType([number, string]), /** Define the cell as being in the first row. */ isFirstRow: bool, /** Define the cell as being in the last row. */ isLastRow: bool, /** Define the cell as being in the first column. */ isFirstCol: bool, /** Define the cell as being in the last column. */ isLastCol: bool, /** Define the cell as being the first 1-height cell in the row. */ isFirstSingle: bool, /** Sets the field value for the cell. */ field: string, /** Truncates `Table.Td` content with ellipses, must be used with `hasFixedHeader` */ /** Truncates header and adds ellipses. */ truncateContent: bool, }; return Th; }(react_1.default.Component)); exports.Th = Th; var Td = function (props) { var className = props.className, isFirstRow = props.isFirstRow, isLastRow = props.isLastRow, isFirstCol = props.isFirstCol, isLastCol = props.isLastCol, isFirstSingle = props.isFirstSingle, align = props.align, hasBorderRight = props.hasBorderRight, hasBorderLeft = props.hasBorderLeft, truncateContent = props.truncateContent, passThroughs = __rest(props, ["className", "isFirstRow", "isLastRow", "isFirstCol", "isLastCol", "isFirstSingle", "align", "hasBorderRight", "hasBorderLeft", "truncateContent"]); return (react_1.default.createElement("td", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'className', 'align', 'hasBorderRight', 'hasBorderLeft', 'isFirstRow', 'isLastRow', 'isFirstCol', 'isLastCol', 'isFirstSingle', 'isEmpty', 'truncateContent', 'initialState', 'callbackId', 'sortDirection', ]), { className: cx('&-Td', { '&-is-first-row': isFirstRow, '&-is-last-row': isLastRow, '&-is-first-col': isFirstCol, '&-is-last-col': isLastCol, '&-is-first-single': isFirstSingle, '&-align-left': align === 'left', '&-align-center': align === 'center', '&-align-right': align === 'right', '&-has-border-right': hasBorderRight, '&-has-border-left': hasBorderLeft, '&-truncate-content': truncateContent, }, className) }))); }; Td.displayName = 'Table.Td'; Td.defaultProps = { align: 'left', hasBorderRight: false, hasBorderLeft: false, rowSpan: 1, }; Td.peek = { description: "\n\t\t`Td` renders <td>.\n\t", categories: [], madeFrom: [], }; Td.propTypes = { /** Aligns the content of a cell. Can be \`left\`, \`center\`, or \`right\`. */ align: oneOf(['left', 'center', 'right']), /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** Should be \`true\` to render a right border. */ hasBorderRight: bool, /** Should be \`true\` to render a left border. */ hasBorderLeft: bool, /** Define the cell as being in the first row. */ isFirstRow: bool, /** Define the cell as being in the last row. */ isLastRow: bool, /** Define the cell as being in the first column. */ isFirstCol: bool, /** Define the cell as being in the last column. */ isLastCol: bool, /** Define the cell as being the first 1-height cell in the row. */ isFirstSingle: bool, /** Indicates if the cell has any data or not. */ isEmpty: bool, /** Truncates \`Table.Td\` content with ellipses, must be used with \`hasFixedHeader\` */ truncateContent: bool, }; var Table = function (props) { var className = props.className, hasBorder = props.hasBorder, density = props.density, hasWordWrap = props.hasWordWrap, hasLightHeader = props.hasLightHeader, hasHover = props.hasHover, style = props.style, passThroughs = __rest(props, ["className", "hasBorder", "density", "hasWordWrap", "hasLightHeader", "hasHover", "style"]); return (react_1.default.createElement("table", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'density', 'hasLightHeader', 'hasBorder', 'hasWordWrap', 'hasHover', 'initialState', 'callbackId', ]), { style: style, className: cx('&', { '&-density-extended': density === 'extended', '&-density-compressed': density === 'compressed', '&-has-border': hasBorder, '&-has-word-wrap': hasWordWrap, '&-has-light-header': hasLightHeader, '&-no-hover': !hasHover, }, className) }))); }; Table.displayName = 'Table'; Table.defaultProps = { density: 'extended', hasBorder: false, hasWordWrap: true, hasLightHeader: true, hasHover: true, }; Table.peek = { description: "`Table` provides the most basic components to create a lucid table. It is recommended to create a wrapper around this component rather than using it directly in an app.", categories: ['table'], madeFrom: ['ArrowIcon', 'DragCaptureZone'], }; Table.propTypes = { /** Styles that are passed through to the root container. */ style: object, /** Class names that are appended to the defaults. */ className: string, /** Adjusts the row density of the table to have more or less spacing. */ density: oneOf(['compressed', 'extended']), /** Allows light header. */ hasLightHeader: bool, /** Render the table with borders on the outer edge. */ hasBorder: bool, /** Enables word wrapping in tables cells. */ hasWordWrap: bool, /** Applies a row hover to rows. Defaults to true. */ hasHover: bool, }; /** ChildComponents */ Table.Thead = Thead; Table.Th = Th; Table.Tbody = Tbody; Table.Tr = Tr; Table.Td = Td; function mapToGrid(trList, cellType, mapFn) { if (cellType === void 0) { cellType = Td; } if (mapFn === void 0) { mapFn = lodash_1.default.property('element'); } var cellRowList = lodash_1.default.map(trList, function (trElement) { return lodash_1.default.map((0, component_types_1.filterTypes)(trElement.props.children, cellType)); }); var grid = []; if (lodash_1.default.isEmpty(cellRowList)) { return []; } // iterate over each row for (var rowIndex = 0; rowIndex < cellRowList.length; rowIndex++) { var cellRow = cellRowList[rowIndex]; if (lodash_1.default.isNil(grid[rowIndex])) { grid[rowIndex] = []; } var canonicalRow = rowIndex; // build out each horizonal duplicates of each cell for (var cellElementIndex = 0; cellElementIndex < cellRow.length; cellElementIndex++) { var cellElement = cellRow[cellElementIndex]; var colSpan = 1; var isCellIncluded = false; if (lodash_1.default.isNumber(cellElement.props.colSpan)) { colSpan = cellElement.props.colSpan; } var nilCellIndex = lodash_1.default.findIndex(grid[canonicalRow], lodash_1.default.isNil); var originCol = nilCellIndex !== -1 ? nilCellIndex : grid[canonicalRow].length; for (var currentColSpan = 0; currentColSpan < colSpan; currentColSpan++) { grid[canonicalRow][originCol + currentColSpan] = { element: cellElement, canonicalPosition: { row: canonicalRow, col: originCol, }, isOriginal: !isCellIncluded, }; isCellIncluded = true; } } // build out each vertial duplicates of each cell using the new row in the full grid for (var colIndex = 0; colIndex < grid[canonicalRow].length; colIndex++) { var gridCell = grid[canonicalRow][colIndex]; if (gridCell.isOriginal) { var cellElement = lodash_1.default.get(gridCell, 'element'); var rowSpan = 1; if (lodash_1.default.isNumber(lodash_1.default.get(cellElement, 'props.rowSpan'))) { rowSpan = lodash_1.default.get(cellElement, 'props.rowSpan'); } for (var currentRowSpan = 1; currentRowSpan < rowSpan; currentRowSpan++) { if (lodash_1.default.isNil(grid[canonicalRow + currentRowSpan])) { grid[canonicalRow + currentRowSpan] = []; } grid[canonicalRow + currentRowSpan][colIndex] = lodash_1.default.assign({}, grid[canonicalRow + currentRowSpan - 1][colIndex], { isOriginal: false }); } } } } // map new values to each cell in the final grid var finalGrid = []; for (var rowIndex = 0; rowIndex < grid.length; rowIndex++) { finalGrid[rowIndex] = []; for (var colIndex = 0; colIndex < grid[rowIndex].length; colIndex++) { finalGrid[rowIndex][colIndex] = mapFn(grid[rowIndex][colIndex], { row: rowIndex, col: colIndex }, finalGrid); } } return finalGrid; } /** * renderRowsWithIdentifiedEdges * * Returns an equivalent list of Tr's where each cell on the perimeter has props set for: `isFirstRow`, `isLastRow`, `isFirstCol`, `isLastCol`, and `isFirstSingle` */ function renderRowsWithIdentifiedEdges(trList, cellType) { if (cellType === void 0) { cellType = Td; } var duplicateReferences = []; var fullCellGrid = mapToGrid(trList, cellType, function (_a, currentPos, grid) { var props = _a.element.props, isOriginal = _a.isOriginal, canonicalPosition = _a.canonicalPosition; if (!isOriginal) { // if cell spans multiple positions // store current position and return original cell props reference duplicateReferences.push(currentPos); return grid[canonicalPosition.row][canonicalPosition.col]; } return lodash_1.default.assign({}, props); // return a new props object based on old cell }); if (lodash_1.default.isEmpty(fullCellGrid)) { return []; } var firstRow = lodash_1.default.first(fullCellGrid); if (lodash_1.default.isUndefined(firstRow)) { return []; } var firstRowIndex = 0; var lastRowIndex = fullCellGrid.length - 1; var firstColIndex = 0; var lastColIndex = firstRow.length - 1; var firstSingleLookup = {}; // decorate the props of each cell with props that indicate its role in the table lodash_1.default.forEach(fullCellGrid, function (cellList, rowIndex) { return lodash_1.default.forEach(cellList, function (cellProps, colIndex) { if (!lodash_1.default.isNull(cellProps)) { if (rowIndex === firstRowIndex) { cellProps.isFirstRow = true; } if (rowIndex === lastRowIndex) { cellProps.isLastRow = true; } if (colIndex === firstColIndex) { cellProps.isFirstCol = true; } if (colIndex === lastColIndex) { cellProps.isLastCol = true; } if (!lodash_1.default.has(firstSingleLookup, rowIndex)) { lodash_1.default.set(firstSingleLookup, rowIndex, false); } if (!lodash_1.default.get(firstSingleLookup, rowIndex) && lodash_1.default.get(cellProps, 'rowSpan', 1) === 1) { lodash_1.default.set(firstSingleLookup, rowIndex, true); cellProps.isFirstSingle = true; } } }); }); lodash_1.default.forEach(duplicateReferences, function (_a) { var row = _a.row, col = _a.col; fullCellGrid[row][col] = null; // remove duplicate references from grid }); // render the grid back to elements using the updated cell props return lodash_1.default.map(trList, function (trElement, rowIndex) { return (react_1.default.createElement(Tr, __assign({}, trElement.props, { key: rowIndex }), lodash_1.default.reduce(fullCellGrid[rowIndex], function (rowChildren, cellProps, colIndex) { return rowChildren.concat(!lodash_1.default.isNull(cellProps) ? [ react_1.default.createElement(cellType, lodash_1.default.assign({}, cellProps, { key: colIndex })), ] : []); }, []))); }); } exports.default = Table; //# sourceMappingURL=Table.js.map