UNPKG

@sap-ux/ui-components

Version:
280 lines 14.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UIFlexibleTable = UIFlexibleTable; const react_1 = __importStar(require("react")); const react_movable_1 = require("react-movable"); const __1 = require(".."); const UIFlexibleTableRow_1 = require("./UIFlexibleTableRow"); const UIFlexibleTableRowNoData_1 = require("./UIFlexibleTableRowNoData"); const types_1 = require("./types"); require("./UIFlexibleTable.scss"); const utils_1 = require("./utils"); const RowActions_1 = require("./RowActions"); const RowData_1 = require("./RowData"); /** * UIFlexibleTable component. * * @exports * @param {UIFlexibleTableProps<T>} props * @returns {React.ReactElement} */ function UIFlexibleTable(props) { const [currentFocusedRowIndex, setCurrentFocusedRowIndex] = (0, react_1.useState)(); const [currentFocusedRowAction, setCurrentFocusedRowAction] = (0, react_1.useState)(''); const [isInRowLayout, setIsInRowLayout] = (0, react_1.useState)(props.layout === types_1.UIFlexibleTableLayout.InlineFlex); const [titleRowRightPadding, setTitleRowRightPadding] = (0, react_1.useState)(0); const [rowToNavigate, setRowToNavigate] = (0, react_1.useState)(); const scrollableElement = (0, react_1.useRef)(null); const tableRootElementRef = (0, react_1.useRef)(null); const contentElementRef = (0, react_1.useRef)(null); const tableBodyElementRef = (0, react_1.useRef)(null); const scrollTargetRef = (0, react_1.useRef)(null); const onResize = (element) => { setIsInRowLayout(props.layout === types_1.UIFlexibleTableLayout.InlineFlex && isRowFitsContainer(props.inRowLayoutMinWidth, tableRootElementRef)); const rootContainer = tableRootElementRef.current; if (element && props.onContentSizeChange && rootContainer) { props.onContentSizeChange({ height: rootContainer.clientHeight, width: rootContainer.clientWidth }); } }; const onScrollBarStateChange = () => { const content = contentElementRef .current; const scrollableContent = scrollableElement.current; const scrollBarSize = content && scrollableContent ? content.clientWidth - scrollableContent.clientWidth : 0; setTitleRowRightPadding(scrollBarSize); }; const [resizeObserver] = (0, react_1.useState)(new ResizeObserver(onResize)); const scrollBarObserver = (0, react_1.useRef)(new ResizeObserver(onScrollBarStateChange)); (0, react_1.useEffect)(() => { if (tableRootElementRef.current) { resizeObserver.observe(tableRootElementRef.current); onResize(); } }, [tableRootElementRef.current]); (0, react_1.useEffect)(() => { if (currentFocusedRowIndex !== undefined) { restoreFocus(currentFocusedRowAction, currentFocusedRowIndex, props.id); } if (!props.isContentLoading && scrollTargetRef.current) { scrollTargetRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); setRowToNavigate(undefined); } }, [props.isContentLoading, props.rows]); (0, react_1.useEffect)(() => { return () => { resizeObserver.disconnect(); }; }, []); (0, react_1.useEffect)(() => { onResize(); }, [props.layout, props.maxWidth]); const reorderTable = (oldIndex, newIndex) => { if (props.onTableReorder) { const result = props.onTableReorder({ oldIndex, newIndex }); if (typeof result === 'object' && result.isDropDisabled) { return; } setCurrentFocusedRowIndex(newIndex); } }; const addNewRow = () => { if (props.addRowButton?.onClick) { const result = props.addRowButton.onClick(); if (result instanceof Promise) { result.then((data) => setRowToNavigate(data?.scrollToRow)).catch(() => undefined); } else { setRowToNavigate(result?.scrollToRow); } } }; const onFocusRowAction = (rowIndex, actionName = '') => { setCurrentFocusedRowIndex(rowIndex); setCurrentFocusedRowAction(actionName); }; const renderRowActions = (rowIndex) => { return (react_1.default.createElement(RowActions_1.RowActions, { rowIndex: rowIndex, tableProps: props, onFocusRowAction: (actionName) => onFocusRowAction(rowIndex, actionName), onMoveDownClick: () => reorderTable(rowIndex, rowIndex + 1), onMoveUpClick: () => reorderTable(rowIndex, rowIndex - 1) })); }; const renderRowData = (params) => (react_1.default.createElement(RowData_1.RowDataCells, { key: params.index ?? 0, isInRowLayout: isInRowLayout, row: params.value, rowIndex: params.index ?? 0, tableProps: props })); /** * Renders row. * * @param {NodeDragAndDropSortingParams} params * @returns {React.ReactElement<UIFlexibleTableRowProps<T>, 'UIFlexibleTableRow'>} */ function renderRow(params) { const rowIndex = params.index; const { isDropWarning } = props.onRenderRowContainer ? props.onRenderRowContainer({ readonly: !!props.readonly, rowIndex, isDragged: params.isDragged }) : { isDropWarning: false }; return (react_1.default.createElement(UIFlexibleTableRow_1.UIFlexibleTableRow, { key: `row-${rowIndex}`, dragAndDropParams: params, rowActions: renderRowActions(rowIndex ?? 0), rowData: renderRowData(params), tableProps: props, rowRef: typeof rowToNavigate === 'number' && rowIndex === rowToNavigate ? scrollTargetRef : undefined, className: isDropWarning ? 'highlight-drop-warning' : '' })); } const renderTable = (params) => { const ulElement = params.props.ref?.current; let { children } = params; if (ulElement && scrollableElement.current !== ulElement) { scrollableElement.current = ulElement; scrollBarObserver.current.observe(ulElement); } if (props.rows.length === 0 && props.noDataText) { children = (react_1.default.createElement(UIFlexibleTableRowNoData_1.UIFlexibleTableRowNoData, { noRowBackground: props.noRowBackground, reverseBackground: props.reverseBackground }, props.noDataText)); } const getCursorStyle = () => { let cursorIcon = 'default'; if (props.onTableReorder) { cursorIcon = params.isDragged ? 'grabbing' : 'grab'; } return cursorIcon; }; return (react_1.default.createElement("ul", { ref: params.props.ref, className: `flexible-table-content-table${params.isDragged ? ' dragged' : ''}`, style: { cursor: getCursorStyle(), maxHeight: props.maxScrollableContentHeight ? `${props.maxScrollableContentHeight}px` : undefined } }, children)); }; const tableBody = getTableBody(props, renderTable, renderRow, reorderTable, tableBodyElementRef); const tableClasses = (0, utils_1.composeClassNames)('flexible-table', [ props.layout === types_1.UIFlexibleTableLayout.InlineFlex ? 'inline-layout' : 'wrapping-layout', props.readonly ? 'readonly' : '' ]); const showTitleRow = props.showColumnTitles && isInRowLayout && !props.showColumnTitlesInCells; const tableRootElementStyle = { maxWidth: props.maxWidth ? `${props.maxWidth}px` : '100%' }; const getCustomTableActions = (actionsGenerator) => { if (actionsGenerator) { const customActions = actionsGenerator({ readonly: !!props.readonly }); return customActions.map((actionElement) => (react_1.default.createElement(react_1.default.Fragment, { key: `table-action-${actionElement.key}` }, react_1.default.createElement("div", { className: "flexible-table-header-action" }, actionElement)))); } return []; }; const primaryTableActions = getCustomTableActions(props.onRenderPrimaryTableActions); const secondaryTableActions = getCustomTableActions(props.onRenderSecondaryTableActions); const isEmptyHeader = !props.addRowButton && primaryTableActions.length + secondaryTableActions.length === 0; const contentClasses = (0, utils_1.composeClassNames)('flexible-table-content', [ props.rows.length === 0 && !props.noDataText ? 'empty-table' : '', props.isContentLoading ? 'loading' : '', isEmptyHeader ? 'empty-table-header' : '' ]); return (react_1.default.createElement("div", { className: tableClasses, ref: tableRootElementRef, id: props.id, style: tableRootElementStyle, onBlur: () => { onFocusRowAction(); } }, isEmptyHeader ? (react_1.default.createElement(react_1.default.Fragment, null)) : (react_1.default.createElement("div", { className: "flexible-table-header" }, react_1.default.createElement("div", { className: "flexible-table-header-primary-actions" }, props.addRowButton && (react_1.default.createElement("div", { className: "flexible-table-header-action" }, react_1.default.createElement(__1.UIDefaultButton, { iconProps: { iconName: 'Add' }, className: "flexible-table-btn-add", id: (0, utils_1.getTableActionButtonId)(props.id, 'add-row'), primary: true, disabled: props.isAddItemDisabled || props.isContentLoading || props.readonly, onClick: addNewRow, title: props.addRowButton.title, "aria-label": props.addRowButton.ariaLabel ?? props.addRowButton.label }, props.addRowButton.label))), primaryTableActions), react_1.default.createElement("div", { className: "flexible-table-header-secondary-actions" }, secondaryTableActions))), react_1.default.createElement("div", { className: contentClasses, ref: contentElementRef }, showTitleRow && (0, UIFlexibleTableRow_1.renderTitleRow)(props, titleRowRightPadding), tableBody, props.isContentLoading && (react_1.default.createElement(__1.UILoader, { className: 'uiLoaderXLarge flexible-table-overlay-loader', blockDOM: true }))))); } /** * Gets table body. * * @param {UIFlexibleTableProps<T>} props * @param {(params: { children: React.ReactNode; isDragged: boolean; props: { ref?: React.RefObject<any>; }; }) => React.ReactNode} renderTable * @param {( params: NodeDragAndDropSortingParams) => React.ReactElement<UIFlexibleTableRowProps<T>, 'UIFlexibleTableRow'>} renderRow * @param { (oldIndex: number, newIndex: number) => void} reorderTable * @param {React.MutableRefObject<any>} tableBodyElementRef * @returns {React.ReactNode} */ function getTableBody(props, renderTable, renderRow, reorderTable, tableBodyElementRef) { let tableBody; const { rows } = props.onBeforeTableRender ? props.onBeforeTableRender({ rows: props.rows }) : { rows: props.rows }; if (rows.length > 0 && props.onTableReorder && !props.readonly) { tableBody = (react_1.default.createElement(react_movable_1.List, { values: rows, lockVertically: props.lockVertically, onChange: (params) => reorderTable(params.oldIndex, params.newIndex), renderList: (params) => renderTable(params), renderItem: (params) => renderRow(params), removableByMove: true, beforeDrag: props.onStartDragging })); } else { const children = props.rows.map((row, index) => { const rowProps = { key: index }; const dragAndDropParams = { index, isDragged: false, isOutOfBounds: false, isSelected: false, props: rowProps, value: row }; return renderRow(dragAndDropParams); }); tableBody = renderTable({ children, isDragged: false, props: { ...props, ref: tableBodyElementRef } }); } return tableBody; } /** * Restores focus. * * @param {string} currentFocusedRowAction * @param {number | undefined} currentFocusedRowIndex * @param {string} tableId */ function restoreFocus(currentFocusedRowAction, currentFocusedRowIndex, tableId) { if (currentFocusedRowAction) { let actionElement = document.getElementById((0, utils_1.getRowActionButtonId)(tableId, currentFocusedRowIndex, currentFocusedRowAction)); if (actionElement) { if (!actionElement.hasAttribute('disabled')) { actionElement.focus(); } else { if (currentFocusedRowAction === 'up') { actionElement = document.getElementById((0, utils_1.getRowActionButtonId)(tableId, currentFocusedRowIndex, 'down')); } else { actionElement = document.getElementById((0, utils_1.getRowActionButtonId)(tableId, currentFocusedRowIndex, 'up')); } if (actionElement) { actionElement.focus(); } } } } } /** * Check row fit container. * * @param {number | undefined} propThreshold * @param {React.MutableRefObject<HTMLDivElement | null>} containerRef * @returns {boolean} */ function isRowFitsContainer(propThreshold, containerRef) { let result = true; const inRowMinWidth = propThreshold ?? 600; const containerWidth = containerRef?.current?.clientWidth ?? 0; if (containerWidth) { result = containerWidth >= inRowMinWidth; } return result; } //# sourceMappingURL=UIFlexibleTable.js.map