"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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __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