UNPKG

@light-sheet/react

Version:

FortuneSheet is a drop-in javascript spreadsheet library that provides rich features like Excel and Google Sheets

638 lines (637 loc) 25.9 kB
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } import { clearFilter, locale, getFilterColumnValues, getFilterColumnColors, orderbydatafiler, saveFilter } from "@light-sheet/core"; import React, { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import _ from "lodash"; import produce from "immer"; import WorkbookContext from "../../context"; import Divider from "./Divider"; import Menu from "./Menu"; import SVGIcon from "../SVGIcon"; import { useAlert } from "../../hooks/useAlert"; import { useOutsideClick } from "../../hooks/useOutsideClick"; var SelectItem = function SelectItem(_ref) { var item = _ref.item, isChecked = _ref.isChecked, _onChange = _ref.onChange, isItemVisible = _ref.isItemVisible; var checked = useMemo(function () { return isChecked(item.key); }, [isChecked, item.key]); return isItemVisible(item) ? /*#__PURE__*/React.createElement("div", { className: "select-item" }, /*#__PURE__*/React.createElement("input", { className: "filter-checkbox", type: "checkbox", checked: checked, onChange: function onChange() { _onChange(item, !checked); } }), /*#__PURE__*/React.createElement("div", null, item.text), /*#__PURE__*/React.createElement("span", { className: "count" }, "( ".concat(item.rows.length, " )"))) : null; }; var DateSelectTreeItem = function DateSelectTreeItem(_ref2) { var item = _ref2.item, _ref2$depth = _ref2.depth, depth = _ref2$depth === void 0 ? 0 : _ref2$depth, initialExpand = _ref2.initialExpand, onExpand = _ref2.onExpand, isChecked = _ref2.isChecked, _onChange2 = _ref2.onChange, isItemVisible = _ref2.isItemVisible; var _useState = useState(initialExpand(item.key)), _useState2 = _slicedToArray(_useState, 2), expand = _useState2[0], setExpand = _useState2[1]; var checked = useMemo(function () { return isChecked(item.key); }, [isChecked, item.key]); return isItemVisible(item) ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { className: "select-item", style: { marginLeft: -2 + depth * 20 }, onClick: function onClick() { onExpand === null || onExpand === void 0 || onExpand(item.key, !expand); setExpand(!expand); }, tabIndex: 0 }, _.isEmpty(item.children) ? /*#__PURE__*/React.createElement("div", { style: { width: 10 } }) : /*#__PURE__*/React.createElement("div", { className: "filter-caret ".concat(expand ? "down" : "right"), style: { cursor: "pointer" } }), /*#__PURE__*/React.createElement("input", { className: "filter-checkbox", type: "checkbox", checked: checked, onChange: function onChange() { _onChange2(item, !checked); }, onClick: function onClick(e) { return e.stopPropagation(); }, tabIndex: 0 }), /*#__PURE__*/React.createElement("div", null, item.text), /*#__PURE__*/React.createElement("span", { className: "count" }, "( ".concat(item.rows.length, " )"))), expand && item.children.map(function (v) { return /*#__PURE__*/React.createElement(DateSelectTreeItem, { key: v.key, item: v, depth: depth + 1, initialExpand: initialExpand, onExpand: onExpand, isChecked: isChecked, onChange: _onChange2, isItemVisible: isItemVisible }); })) : null; }; var DateSelectTree = function DateSelectTree(_ref3) { var dates = _ref3.dates, initialExpand = _ref3.initialExpand, onExpand = _ref3.onExpand, isChecked = _ref3.isChecked, onChange = _ref3.onChange, isItemVisible = _ref3.isItemVisible; return /*#__PURE__*/React.createElement(React.Fragment, null, dates.map(function (v) { return /*#__PURE__*/React.createElement(DateSelectTreeItem, { key: v.key, item: v, initialExpand: initialExpand, onExpand: onExpand, isChecked: isChecked, onChange: onChange, isItemVisible: isItemVisible }); })); }; var FilterMenu = function FilterMenu() { var _settings$filterConte; var _useContext = useContext(WorkbookContext), context = _useContext.context, setContext = _useContext.setContext, settings = _useContext.settings, refs = _useContext.refs; var containerRef = useRef(null); var contextRef = useRef(context); var byColorMenuRef = useRef(null); var subMenuRef = useRef(null); var filterContextMenu = context.filterContextMenu; var _ref4 = filterContextMenu || { startRow: null, startCol: null, endRow: null, endCol: null, col: null, listBoxMaxHeight: 400 }, startRow = _ref4.startRow, startCol = _ref4.startCol, endRow = _ref4.endRow, endCol = _ref4.endCol, col = _ref4.col, listBoxMaxHeight = _ref4.listBoxMaxHeight; var _locale = locale(context), filter = _locale.filter; var _useState3 = useState({ dates: [], dateRowMap: {}, values: [], valueRowMap: {}, visibleRows: [], flattenValues: [] }), _useState4 = _slicedToArray(_useState3, 2), data = _useState4[0], setData = _useState4[1]; var _useState5 = useState([]), _useState6 = _slicedToArray(_useState5, 2), datesUncheck = _useState6[0], setDatesUncheck = _useState6[1]; var _useState7 = useState([]), _useState8 = _slicedToArray(_useState7, 2), valuesUncheck = _useState8[0], setValuesUncheck = _useState8[1]; var dateTreeExpandState = useRef({}); var hiddenRows = useRef([]); var _useState9 = useState([]), _useState10 = _slicedToArray(_useState9, 2), showValues = _useState10[0], setShowValues = _useState10[1]; var _useState11 = useState(""), _useState12 = _slicedToArray(_useState11, 2), searchText = _useState12[0], setSearchText = _useState12[1]; var _useState13 = useState(), _useState14 = _slicedToArray(_useState13, 2), subMenuPos = _useState14[0], setSubMenuPos = _useState14[1]; var _useState15 = useState({ bgColors: [], fcColors: [] }), _useState16 = _slicedToArray(_useState15, 2), filterColors = _useState16[0], setFilterColors = _useState16[1]; var _useState17 = useState(false), _useState18 = _slicedToArray(_useState17, 2), showSubMenu = _useState18[0], setShowSubMenu = _useState18[1]; var _useAlert = useAlert(), showAlert = _useAlert.showAlert; var mouseHoverSubMenu = useRef(false); contextRef.current = context; // 点击其他区域的时候关闭FilterMenu var close = useCallback(function () { setContext(function (ctx) { ctx.filterContextMenu = undefined; }); }, [setContext]); useOutsideClick(containerRef, close, [close]); var initialExpand = useCallback(function (key) { var expand = dateTreeExpandState.current[key]; if (expand == null) { dateTreeExpandState.current[key] = true; return true; } return expand; }, []); var onExpand = useCallback(function (key, expand) { dateTreeExpandState.current[key] = expand; }, []); var searchValues = useMemo(function () { return _.debounce(function (text) { setShowValues(_.filter(data.flattenValues, function (v) { return v.toLowerCase().indexOf(text.toLowerCase()) > -1; })); }, 300); }, [data.flattenValues]); var selectAll = useCallback(function () { setDatesUncheck([]); setValuesUncheck([]); hiddenRows.current = []; }, []); var clearAll = useCallback(function () { setDatesUncheck(_.keys(data.dateRowMap)); setValuesUncheck(_.keys(data.valueRowMap)); hiddenRows.current = data.visibleRows; }, [data.dateRowMap, data.valueRowMap, data.visibleRows]); var inverseSelect = useCallback(function () { setDatesUncheck(produce(function (draft) { return _.xor(draft, _.keys(data.dateRowMap)); })); setValuesUncheck(produce(function (draft) { return _.xor(draft, _.keys(data.valueRowMap)); })); hiddenRows.current = _.xor(hiddenRows.current, data.visibleRows); }, [data.dateRowMap, data.valueRowMap, data.visibleRows]); var onColorSelectChange = useCallback(function (key, color, checked) { setFilterColors(produce(function (draft) { var colorData = _.find(_.get(draft, key), function (v) { return v.color === color; }); colorData.checked = checked; })); }, []); var delayHideSubMenu = useMemo(function () { return _.debounce(function () { if (mouseHoverSubMenu.current) return; setShowSubMenu(false); }, 200); }, []); var sortData = useCallback(function (asc) { if (col == null) return; setContext(function (draftCtx) { var errMsg = orderbydatafiler(draftCtx, startRow, startCol, endRow, endCol, col, asc); if (errMsg != null) showAlert(errMsg); }); }, [col, setContext, startRow, startCol, endRow, endCol, showAlert]); var renderColorList = useCallback(function (key, title, colors, onSelectChange) { return colors.length > 1 ? /*#__PURE__*/React.createElement("div", { key: key }, /*#__PURE__*/React.createElement("div", { className: "title" }, title), /*#__PURE__*/React.createElement("div", { className: "color-list" }, colors.map(function (v) { return /*#__PURE__*/React.createElement("div", { key: v.color, className: "item", onClick: function onClick() { return onSelectChange(key, v.color, !v.checked); }, tabIndex: 0 }, /*#__PURE__*/React.createElement("div", { className: "color-label", style: { backgroundColor: v.color } }), /*#__PURE__*/React.createElement("input", { className: "luckysheet-mousedown-cancel", type: "checkbox", checked: v.checked, onChange: function onChange() {} })); }))) : null; }, []); useLayoutEffect(function () { var _refs$workbookContain; // re-position the filterContextMenu if it overflows the window if (!containerRef.current || !filterContextMenu) { return; } var winH = window.innerHeight; var winW = window.innerWidth; var rect = containerRef.current.getBoundingClientRect(); var workbookRect = (_refs$workbookContain = refs.workbookContainer.current) === null || _refs$workbookContain === void 0 ? void 0 : _refs$workbookContain.getBoundingClientRect(); if (!workbookRect) { return; } var menuW = rect.width; // menu最小高度 var menuH = 350; var top = filterContextMenu.y; var left = filterContextMenu.x; var hasOverflow = false; if (workbookRect.left + left + menuW > winW) { left -= menuW; hasOverflow = true; } if (workbookRect.top + top + menuH > winH) { top -= menuH; hasOverflow = true; } if (top < 0) { top = 0; hasOverflow = true; } // 适配小屏 var containerH = winH - rect.top - 350; if (containerH < 0) { containerH = 100; } // 防止Maximum update depth exceeded错误,如果当前值和前一个filterContextMenu值一样则不进行赋值 if (filterContextMenu.x === left && filterContextMenu.y === top && filterContextMenu.listBoxMaxHeight === containerH) { return; } setContext(function (draftCtx) { if (hasOverflow) { _.set(draftCtx, "filterContextMenu.x", left); _.set(draftCtx, "filterContextMenu.y", top); } _.set(draftCtx, "filterContextMenu.listBoxMaxHeight", containerH); }); }, [filterContextMenu, refs.workbookContainer, setContext]); useLayoutEffect(function () { var _byColorMenuRef$curre, _subMenuRef$current; if (!subMenuPos) return; // re-position the subMenu if it overflows the window var rect = (_byColorMenuRef$curre = byColorMenuRef.current) === null || _byColorMenuRef$curre === void 0 ? void 0 : _byColorMenuRef$curre.getBoundingClientRect(); var subMenuRect = (_subMenuRef$current = subMenuRef.current) === null || _subMenuRef$current === void 0 ? void 0 : _subMenuRef$current.getBoundingClientRect(); if (rect == null || subMenuRect == null) return; var winW = window.innerWidth; var pos = _.cloneDeep(subMenuPos); if (subMenuRect.left + subMenuRect.width > winW) { pos.left -= subMenuRect.width; setSubMenuPos(pos); } }, [subMenuPos]); useEffect(function () { if (col == null) return; setSearchText(""); setShowSubMenu(false); dateTreeExpandState.current = {}; hiddenRows.current = (filterContextMenu === null || filterContextMenu === void 0 ? void 0 : filterContextMenu.hiddenRows) || []; var res = getFilterColumnValues(contextRef.current, col, startRow, endRow, startCol); setData(_.omit(res, ["datesUncheck", "valuesUncheck"])); setDatesUncheck(res.datesUncheck); setValuesUncheck(res.valuesUncheck); setShowValues(res.flattenValues); }, [col, endRow, startRow, startCol, hiddenRows, filterContextMenu === null || filterContextMenu === void 0 ? void 0 : filterContextMenu.hiddenRows]); useEffect(function () { if (col == null) return; setFilterColors(getFilterColumnColors(contextRef.current, col, startRow, endRow)); }, [col, endRow, startRow]); if (filterContextMenu == null) return null; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { className: "fortune-context-menu luckysheet-cols-menu fortune-filter-menu", id: "luckysheet-\\${menuid}-menu", ref: containerRef, style: { left: filterContextMenu.x, top: filterContextMenu.y } }, (_settings$filterConte = settings.filterContextMenu) === null || _settings$filterConte === void 0 ? void 0 : _settings$filterConte.map(function (cellItem, i) { if (Array.isArray(cellItem)) { return cellItem.map(function (item) { return /*#__PURE__*/React.createElement(Menu, { key: item.label, onClick: function onClick() { item.onClick(); setContext(function (draftCtx) { draftCtx.contextMenu = {}; }); } }, item.label); }); } if (cellItem === "|") { return /*#__PURE__*/React.createElement(Divider, { key: "divider-".concat(i) }); } if (cellItem === "sort-by-asc") { return /*#__PURE__*/React.createElement(Menu, { key: cellItem, onClick: function onClick() { return sortData(true); } }, filter.sortByAsc); } if (cellItem === "sort-by-desc") { return /*#__PURE__*/React.createElement(Menu, { key: cellItem, onClick: function onClick() { return sortData(false); } }, filter.sortByDesc); } if (cellItem === "filter-by-color") { return /*#__PURE__*/React.createElement("div", { key: cellItem, ref: byColorMenuRef, onMouseEnter: function onMouseEnter() { var _byColorMenuRef$curre2; if (!containerRef.current || !filterContextMenu) { return; } setShowSubMenu(true); var rect = (_byColorMenuRef$curre2 = byColorMenuRef.current) === null || _byColorMenuRef$curre2 === void 0 ? void 0 : _byColorMenuRef$curre2.getBoundingClientRect(); if (rect == null) return; setSubMenuPos({ top: rect.top - 5, left: rect.right }); }, onMouseLeave: delayHideSubMenu }, /*#__PURE__*/React.createElement(Menu, { onClick: function onClick() {} }, /*#__PURE__*/React.createElement("div", { className: "filter-bycolor-container" }, filter.filterByColor, /*#__PURE__*/React.createElement("div", { className: "filter-caret right" })))); } if (cellItem === "filter-by-condition") { return /*#__PURE__*/React.createElement("div", { key: "cellItem" }, /*#__PURE__*/React.createElement(Menu, { onClick: function onClick() {} }, /*#__PURE__*/React.createElement("div", { className: "filter-caret right" }), filter.filterByCondition), /*#__PURE__*/React.createElement("div", { className: "luckysheet-\\${menuid}-bycondition", style: { display: "none" } }, /*#__PURE__*/React.createElement("div", { className: "luckysheet-flat-menu-button luckysheet-mousedown-cancel", id: "luckysheet-\\${menuid}-selected" }, /*#__PURE__*/React.createElement("span", { className: "luckysheet-mousedown-cancel", "data-value": "null", "data-type": "0" }, filter.filiterInputNone), /*#__PURE__*/React.createElement("div", { className: "luckysheet-mousedown-cancel" }, /*#__PURE__*/React.createElement("i", { className: "fa fa-sort", "aria-hidden": "true" }))))); } if (cellItem === "filter-by-value") { return /*#__PURE__*/React.createElement("div", { key: cellItem }, /*#__PURE__*/React.createElement(Menu, { onClick: function onClick() {} }, /*#__PURE__*/React.createElement("div", { className: "filter-caret right" }), filter.filterByValues), /*#__PURE__*/React.createElement("div", { className: "luckysheet-filter-byvalue" }, /*#__PURE__*/React.createElement("div", { className: "fortune-menuitem-row byvalue-btn-row" }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("span", { className: "fortune-byvalue-btn", onClick: selectAll, tabIndex: 0 }, filter.filterValueByAllBtn), " - ", /*#__PURE__*/React.createElement("span", { className: "fortune-byvalue-btn", onClick: clearAll, tabIndex: 0 }, filter.filterValueByClearBtn), " - ", /*#__PURE__*/React.createElement("span", { className: "fortune-byvalue-btn", onClick: inverseSelect, tabIndex: 0 }, filter.filterValueByInverseBtn)), /*#__PURE__*/React.createElement("div", { className: "byvalue-filter-icon" }, /*#__PURE__*/React.createElement(SVGIcon, { name: "filter-fill", style: { width: 20, height: 20 } }))), /*#__PURE__*/React.createElement("div", { className: "filtermenu-input-container" }, /*#__PURE__*/React.createElement("input", { type: "text", onKeyDown: function onKeyDown(e) { return e.stopPropagation(); }, placeholder: filter.filterValueByTip, className: "luckysheet-mousedown-cancel", id: "luckysheet-\\${menuid}-byvalue-input", value: searchText, onChange: function onChange(e) { setSearchText(e.target.value); searchValues(e.target.value); } })), /*#__PURE__*/React.createElement("div", { id: "luckysheet-filter-byvalue-select", style: { maxHeight: listBoxMaxHeight } }, /*#__PURE__*/React.createElement(DateSelectTree, { dates: data.dates, onExpand: onExpand, initialExpand: initialExpand, isChecked: function isChecked(key) { return _.find(datesUncheck, function (v) { return v.match(key) != null; }) == null; }, onChange: function onChange(item, checked) { var rows = hiddenRows.current; hiddenRows.current = checked ? _.without.apply(_, [rows].concat(_toConsumableArray(item.rows))) : _.union(rows, item.rows); setDatesUncheck(produce(function (draft) { return checked ? _.without.apply(_, [draft].concat(_toConsumableArray(item.dateValues))) : _.union(draft, item.dateValues); })); }, isItemVisible: function isItemVisible(item) { return showValues.length === data.flattenValues.length ? true : _.findIndex(showValues, function (v) { return v.match(item.key) != null; }) > -1; } }), data.values.map(function (v) { return /*#__PURE__*/React.createElement(SelectItem, { key: v.key, item: v, isChecked: function isChecked(key) { return !_.includes(valuesUncheck, key); }, onChange: function onChange(item, checked) { var rows = hiddenRows.current; hiddenRows.current = checked ? _.without.apply(_, [rows].concat(_toConsumableArray(item.rows))) : _.concat(rows, item.rows); setValuesUncheck(produce(function (draft) { if (checked) { _.pull(draft, item.key); } else { draft.push(item.key); } })); }, isItemVisible: function isItemVisible(item) { return showValues.length === data.flattenValues.length ? true : _.includes(showValues, item.text); } }); })))); } return null; }), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement("div", { className: "fortune-menuitem-row" }, /*#__PURE__*/React.createElement("div", { className: "button-basic button-primary", onClick: function onClick() { if (col == null) return; setContext(function (draftCtx) { var rowHidden = _.reduce(hiddenRows.current, function (pre, curr) { pre[curr] = 0; return pre; }, {}); saveFilter(draftCtx, hiddenRows.current.length > 0, rowHidden, {}, startRow, endRow, col, startCol, endCol); hiddenRows.current = []; draftCtx.filterContextMenu = undefined; }); }, tabIndex: 0 }, filter.filterConform), /*#__PURE__*/React.createElement("div", { className: "button-basic button-default", onClick: function onClick() { setContext(function (draftCtx) { draftCtx.filterContextMenu = undefined; }); }, tabIndex: 0 }, filter.filterCancel), /*#__PURE__*/React.createElement("div", { className: "button-basic button-danger", onClick: function onClick() { setContext(function (draftCtx) { clearFilter(draftCtx); }); }, tabIndex: 0 }, filter.clearFilter))), showSubMenu && /*#__PURE__*/React.createElement("div", { ref: subMenuRef, className: "luckysheet-filter-bycolor-submenu", style: subMenuPos, onMouseEnter: function onMouseEnter() { mouseHoverSubMenu.current = true; }, onMouseLeave: function onMouseLeave() { mouseHoverSubMenu.current = false; setShowSubMenu(false); } }, filterColors.bgColors.length < 2 && filterColors.fcColors.length < 2 ? /*#__PURE__*/React.createElement("div", { className: "one-color-tip" }, filter.filterContainerOneColorTip) : /*#__PURE__*/React.createElement(React.Fragment, null, [{ key: "bgColors", title: filter.filiterByColorTip, colors: filterColors.bgColors }, { key: "fcColors", title: filter.filiterByTextColorTip, colors: filterColors.fcColors }].map(function (v) { return renderColorList(v.key, v.title, v.colors, onColorSelectChange); }), /*#__PURE__*/React.createElement("div", { className: "button-basic button-primary", onClick: function onClick() { if (col == null) return; setContext(function (draftCtx) { var rowHidden = _.reduce(_(filterColors).values().flatten().map(function (v) { return v.checked ? [] : v.rows; }).flatten().valueOf(), function (pre, curr) { pre[curr] = 0; return pre; }, {}); saveFilter(draftCtx, !_.isEmpty(rowHidden), rowHidden, {}, startRow, endRow, col, startCol, endCol); hiddenRows.current = []; draftCtx.filterContextMenu = undefined; }); }, tabIndex: 0 }, filter.filterConform)))); }; export default FilterMenu;