@gravity-ui/uikit
Version: 
Gravity UI base styling and components
153 lines (152 loc) • 6.94 kB
JavaScript
'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import * as React from 'react';
import _get from "lodash/get.js";
import _memoize from "lodash/memoize.js";
import { createOnKeyDownHandler } from "../../../../hooks/useActionHandlers/useActionHandlers.js";
import { block } from "../../../utils/cn.js";
import { getComponentName } from "../../../utils/getComponentName.js";
import { Table } from "../../Table.js";
import { SortIndicator } from "./SortIndicator/SortIndicator.js";
import "./withTableSorting.css";
export const TableSortIndicator = SortIndicator;
const b = block('table');
export function withTableSorting(TableComponent) {
    const componentName = getComponentName(TableComponent);
    const displayName = `withTableSorting(${componentName})`;
    function defaultCompareFunction(itemA, itemB, columnId) {
        if (_get(itemA, columnId) === _get(itemB, columnId)) {
            return 0;
        }
        else {
            return _get(itemA, columnId) > _get(itemB, columnId) ? 1 : -1;
        }
    }
    return class extends React.Component {
        static displayName = displayName;
        state = {
            sort: this.props.defaultSortState ?? [],
        };
        render() {
            const { columns, ...restTableProps } = this.props;
            return (_jsx(TableComponent, { ...restTableProps, data: this.getSortedData(), columns: this.enhanceColumns(columns) }));
        }
        getSortedData() {
            const { data, columns, disableDataSorting = this.isControlledState() } = this.props;
            const sortState = this.getSortState();
            if (disableDataSorting || sortState.length === 0) {
                return data;
            }
            return data.slice().sort((itemA, itemB) => {
                let i = 0;
                while (i < sortState.length) {
                    const state = sortState[i++];
                    const column = columns.find((c) => c.id === state.column);
                    const compareFunction = column?.meta?.sort;
                    if (!compareFunction) {
                        continue;
                    }
                    const compareValue = typeof compareFunction === 'function'
                        ? compareFunction(itemA, itemB)
                        : defaultCompareFunction(itemA, itemB, state.column);
                    if (compareValue !== 0) {
                        return state.order === 'asc' ? compareValue : -compareValue;
                    }
                }
                return 0;
            });
        }
        // eslint-disable-next-line @typescript-eslint/member-ordering
        enhanceColumns = _memoize((columns) => {
            return columns.map((column) => {
                const meta = column.meta;
                if (meta && meta.sort) {
                    return {
                        ...column,
                        meta: {
                            ...column.meta,
                            _originalName: column.name,
                        },
                        name: () => {
                            const sortState = this.getSortState();
                            let sortOrder;
                            if (sortState.length > 0) {
                                const state = sortState.find((s) => s.column === column.id);
                                if (state) {
                                    sortOrder = state.order;
                                }
                            }
                            const originContent = Table.getHeadCellContent(column);
                            const content = [
                                _jsx("div", { className: b('sort-content'), children: originContent }, "content"),
                                _jsx("div", { className: b('sort-indicator'), children: _jsx(SortIndicator, { order: sortOrder }) }, "indicator"),
                            ];
                            if (column.align === 'right' || column.align === 'end') {
                                content.reverse();
                            }
                            const onClick = this.handleColumnSortClick.bind(this, column);
                            const onKeyDown = createOnKeyDownHandler(onClick);
                            return (_jsx("div", { role: "button", tabIndex: 0, className: b('sort', { active: Boolean(sortOrder) }), onClick: onClick, onKeyDown: onKeyDown, children: content }));
                        },
                    };
                }
                else {
                    return column;
                }
            });
        });
        handleColumnSortClick = (column, event) => {
            const sortState = this.getSortState();
            const currentStateIndex = sortState.findIndex((state) => state.column === column.id);
            const currentState = sortState[currentStateIndex];
            const nextColumnSort = this.getNextSortForColumn(column, currentState);
            if (!event.shiftKey) {
                this.handleSortStateChange(nextColumnSort);
                return;
            }
            if (currentState) {
                this.handleSortStateChange([
                    ...sortState.slice(0, currentStateIndex),
                    ...sortState.slice(currentStateIndex + 1),
                    ...nextColumnSort,
                ]);
            }
            else {
                this.handleSortStateChange([...sortState, ...nextColumnSort]);
            }
        };
        getSortState() {
            const { sortState } = this.props;
            const { sort } = this.state;
            return this.isControlledState() ? sortState : sort;
        }
        handleSortStateChange(newSortState) {
            const { onSortStateChange } = this.props;
            if (!this.isControlledState()) {
                this.setState({ sort: newSortState });
            }
            if (onSortStateChange) {
                onSortStateChange(newSortState);
            }
        }
        isControlledState() {
            const { sortState, onSortStateChange } = this.props;
            return Boolean(sortState && onSortStateChange);
        }
        getColumnDefaultSortOrder(column) {
            return column.meta?.defaultSortOrder || 'asc';
        }
        getNextSortForColumn(column, currentState) {
            const defaultOrder = this.getColumnDefaultSortOrder(column);
            const orderStack = defaultOrder === 'desc' ? ['desc', 'asc', undefined] : ['asc', 'desc', undefined];
            const currentIndex = orderStack.indexOf(currentState?.order);
            const nextIndex = (currentIndex + 1) % orderStack.length;
            const nextOrder = orderStack[nextIndex];
            if (!nextOrder) {
                return [];
            }
            return [{ column: column.id, order: nextOrder }];
        }
    };
}
//# sourceMappingURL=withTableSorting.js.map