@animech-public/chonky
Version:
A File Browser component for React
1,317 lines (1,306 loc) • 207 kB
JavaScript
import merge from 'deepmerge';
import React, { useRef, useState, useEffect, useCallback, createContext, useMemo, useContext, useImperativeHandle } from 'react';
import { DndContext, useDrop, useDrag, useDragLayer, DndProvider } from 'react-dnd';
import { HTML5Backend, getEmptyImage } from 'react-dnd-html5-backend';
import { useIntl, IntlProvider } from 'react-intl';
import { createUseStyles, ThemeProvider } from 'react-jss';
import { useSelector, useDispatch, useStore, Provider } from 'react-redux';
import { nanoid } from 'nanoid';
import { createTheme, StyledEngineProvider, ThemeProvider as ThemeProvider$1 } from '@mui/material/styles';
import { createSelector, createSlice, configureStore } from '@reduxjs/toolkit';
import { sort } from 'fast-sort';
import FuzzySearch from 'fuzzy-search';
import watch from 'redux-watch';
import { filesize } from 'filesize';
import ExactTrie from 'exact-trie';
import useMediaQuery from '@mui/material/useMediaQuery';
import classnames from 'classnames';
import Box from '@mui/material/Box';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import hotkeys from 'hotkeys-js';
import Breadcrumbs from '@mui/material/Breadcrumbs';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import MenuItem from '@mui/material/MenuItem';
import Typography from '@mui/material/Typography';
import InputAdornment from '@mui/material/InputAdornment';
import TextField from '@mui/material/TextField';
import AutoSizer from 'react-virtualized-auto-sizer';
import { VariableSizeGrid, FixedSizeList } from 'react-window';
import ListSubheader from '@mui/material/ListSubheader';
function _regeneratorRuntime() {
_regeneratorRuntime = function () {
return e;
};
var t,
e = {},
r = Object.prototype,
n = r.hasOwnProperty,
o = Object.defineProperty || function (t, e, r) {
t[e] = r.value;
},
i = "function" == typeof Symbol ? Symbol : {},
a = i.iterator || "@@iterator",
c = i.asyncIterator || "@@asyncIterator",
u = i.toStringTag || "@@toStringTag";
function define(t, e, r) {
return Object.defineProperty(t, e, {
value: r,
enumerable: !0,
configurable: !0,
writable: !0
}), t[e];
}
try {
define({}, "");
} catch (t) {
define = function (t, e, r) {
return t[e] = r;
};
}
function wrap(t, e, r, n) {
var i = e && e.prototype instanceof Generator ? e : Generator,
a = Object.create(i.prototype),
c = new Context(n || []);
return o(a, "_invoke", {
value: makeInvokeMethod(t, r, c)
}), a;
}
function tryCatch(t, e, r) {
try {
return {
type: "normal",
arg: t.call(e, r)
};
} catch (t) {
return {
type: "throw",
arg: t
};
}
}
e.wrap = wrap;
var h = "suspendedStart",
l = "suspendedYield",
f = "executing",
s = "completed",
y = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
var p = {};
define(p, a, function () {
return this;
});
var d = Object.getPrototypeOf,
v = d && d(d(values([])));
v && v !== r && n.call(v, a) && (p = v);
var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
function defineIteratorMethods(t) {
["next", "throw", "return"].forEach(function (e) {
define(t, e, function (t) {
return this._invoke(e, t);
});
});
}
function AsyncIterator(t, e) {
function invoke(r, o, i, a) {
var c = tryCatch(t[r], t, o);
if ("throw" !== c.type) {
var u = c.arg,
h = u.value;
return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
invoke("next", t, i, a);
}, function (t) {
invoke("throw", t, i, a);
}) : e.resolve(h).then(function (t) {
u.value = t, i(u);
}, function (t) {
return invoke("throw", t, i, a);
});
}
a(c.arg);
}
var r;
o(this, "_invoke", {
value: function (t, n) {
function callInvokeWithMethodAndArg() {
return new e(function (e, r) {
invoke(t, n, e, r);
});
}
return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
}
});
}
function makeInvokeMethod(e, r, n) {
var o = h;
return function (i, a) {
if (o === f) throw new Error("Generator is already running");
if (o === s) {
if ("throw" === i) throw a;
return {
value: t,
done: !0
};
}
for (n.method = i, n.arg = a;;) {
var c = n.delegate;
if (c) {
var u = maybeInvokeDelegate(c, n);
if (u) {
if (u === y) continue;
return u;
}
}
if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
if (o === h) throw o = s, n.arg;
n.dispatchException(n.arg);
} else "return" === n.method && n.abrupt("return", n.arg);
o = f;
var p = tryCatch(e, r, n);
if ("normal" === p.type) {
if (o = n.done ? s : l, p.arg === y) continue;
return {
value: p.arg,
done: n.done
};
}
"throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
}
};
}
function maybeInvokeDelegate(e, r) {
var n = r.method,
o = e.iterator[n];
if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
var i = tryCatch(o, e.iterator, r.arg);
if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
var a = i.arg;
return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
}
function pushTryEntry(t) {
var e = {
tryLoc: t[0]
};
1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
}
function resetTryEntry(t) {
var e = t.completion || {};
e.type = "normal", delete e.arg, t.completion = e;
}
function Context(t) {
this.tryEntries = [{
tryLoc: "root"
}], t.forEach(pushTryEntry, this), this.reset(!0);
}
function values(e) {
if (e || "" === e) {
var r = e[a];
if (r) return r.call(e);
if ("function" == typeof e.next) return e;
if (!isNaN(e.length)) {
var o = -1,
i = function next() {
for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
return next.value = t, next.done = !0, next;
};
return i.next = i;
}
}
throw new TypeError(typeof e + " is not iterable");
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
value: GeneratorFunctionPrototype,
configurable: !0
}), o(GeneratorFunctionPrototype, "constructor", {
value: GeneratorFunction,
configurable: !0
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
var e = "function" == typeof t && t.constructor;
return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
}, e.mark = function (t) {
return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
}, e.awrap = function (t) {
return {
__await: t
};
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
return this;
}), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
void 0 === i && (i = Promise);
var a = new AsyncIterator(wrap(t, r, n, o), i);
return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
return t.done ? t.value : a.next();
});
}, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
return this;
}), define(g, "toString", function () {
return "[object Generator]";
}), e.keys = function (t) {
var e = Object(t),
r = [];
for (var n in e) r.push(n);
return r.reverse(), function next() {
for (; r.length;) {
var t = r.pop();
if (t in e) return next.value = t, next.done = !1, next;
}
return next.done = !0, next;
};
}, e.values = values, Context.prototype = {
constructor: Context,
reset: function (e) {
if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
},
stop: function () {
this.done = !0;
var t = this.tryEntries[0].completion;
if ("throw" === t.type) throw t.arg;
return this.rval;
},
dispatchException: function (e) {
if (this.done) throw e;
var r = this;
function handle(n, o) {
return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
}
for (var o = this.tryEntries.length - 1; o >= 0; --o) {
var i = this.tryEntries[o],
a = i.completion;
if ("root" === i.tryLoc) return handle("end");
if (i.tryLoc <= this.prev) {
var c = n.call(i, "catchLoc"),
u = n.call(i, "finallyLoc");
if (c && u) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
} else if (c) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
} else {
if (!u) throw new Error("try statement without catch or finally");
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
}
}
}
},
abrupt: function (t, e) {
for (var r = this.tryEntries.length - 1; r >= 0; --r) {
var o = this.tryEntries[r];
if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
var i = o;
break;
}
}
i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
var a = i ? i.completion : {};
return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
},
complete: function (t, e) {
if ("throw" === t.type) throw t.arg;
return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
},
finish: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
}
},
catch: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.tryLoc === t) {
var n = r.completion;
if ("throw" === n.type) {
var o = n.arg;
resetTryEntry(r);
}
return o;
}
}
throw new Error("illegal catch attempt");
},
delegateYield: function (e, r, n) {
return this.delegate = {
iterator: values(e),
resultName: r,
nextLoc: n
}, "next" === this.method && (this.arg = t), y;
}
}, e;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
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 _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var useDebounce = function useDebounce(value, delay) {
var _useState = useState(value),
debouncedValue = _useState[0],
setDebouncedValue = _useState[1];
useEffect(function () {
var handler = setTimeout(function () {
setDebouncedValue(value);
}, delay);
return function () {
clearTimeout(handler);
};
}, [value, delay]);
return [debouncedValue, setDebouncedValue];
};
var UNINITIALIZED_SENTINEL = {};
var useStaticValue = function useStaticValue(factory) {
var valueRef = useRef(UNINITIALIZED_SENTINEL);
if (valueRef.current === UNINITIALIZED_SENTINEL) valueRef.current = factory();
return valueRef.current;
};
var useInstanceVariable = function useInstanceVariable(value) {
var ref = useRef(value);
useEffect(function () {
ref.current = value;
}, [ref, value]);
return ref;
};
var Logger = /*#__PURE__*/function () {
function Logger() {}
Logger.error = function error() {
var _console;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
// eslint-disable-next-line no-console
(_console = console).error.apply(_console, ['[Chonky runtime error]'].concat(args));
};
Logger.warn = function warn() {
var _console2;
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
// eslint-disable-next-line no-console
(_console2 = console).warn.apply(_console2, ['[Chonky runtime warning]'].concat(args));
};
Logger.debug = function debug() {
var _console3;
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
// eslint-disable-next-line no-console
(_console3 = console).debug.apply(_console3, ['[Chonky runtime debug]'].concat(args));
};
Logger.formatBullets = function formatBullets(bullets) {
return "\n- " + bullets.join('\n- ');
};
return Logger;
}();
var FileHelper = /*#__PURE__*/function () {
function FileHelper() {}
FileHelper.isDirectory = function isDirectory(file) {
// Not a directory by default
return !!file && file.isDir === true;
};
FileHelper.isHidden = function isHidden(file) {
// Not hidden by default
return !!file && file.isHidden === true;
};
FileHelper.isSymlink = function isSymlink(file) {
// Not a symlink by default
return !!file && file.isSymlink === true;
};
FileHelper.isEncrypted = function isEncrypted(file) {
// Not encrypted by default
return !!file && file.isEncrypted === true;
};
FileHelper.isClickable = function isClickable(file) {
// Clickable by default
return !!file;
};
FileHelper.isOpenable = function isOpenable(file) {
// Openable by default
return !!file && file.openable !== false;
};
FileHelper.isSelectable = function isSelectable(file) {
// Selectable by default
return !!file && file.selectable !== false;
};
FileHelper.isRenamable = function isRenamable(file) {
// Renamable by default
return !!file && file.renamable !== false;
};
FileHelper.isDraggable = function isDraggable(file) {
// File & folders are draggable by default, `null` is not
return !!file && file.draggable !== false;
};
FileHelper.isDroppable = function isDroppable(file) {
// Folders are droppable by default, files are not
if (!file) return false;
if (file.isDir && file.droppable !== false) return true;
return file.droppable === true;
};
FileHelper.isDndOpenable = function isDndOpenable(file) {
// Folders are DnD openable by default, files are not
if (!FileHelper.isOpenable(file)) return false;
if (file.isDir && file.dndOpenable !== false) return true;
return file.dndOpenable === true;
};
FileHelper.getModDate = function getModDate(file) {
if (!file || file.modDate === null || file.modDate === undefined) return null;
return FileHelper.parseDate(file.modDate);
};
FileHelper.parseDate = function parseDate(maybeDate) {
if (typeof maybeDate === 'string' || typeof maybeDate === 'number') {
// We allow users to provide string and numerical representations of dates.
try {
return new Date(maybeDate);
} catch (error) {
var err = error;
Logger.error("Could not convert provided string/number into a date: " + err.message + " ", 'Invalid value:', maybeDate);
}
}
if (maybeDate instanceof Date && !isNaN(maybeDate.getTime())) {
// We only allow valid dates objects
return maybeDate;
}
// If we have an invalid date representation, we just return null.
Logger.warn('Unsupported date representation:', maybeDate);
return null;
};
FileHelper.getChildrenCount = function getChildrenCount(file) {
if (!file || typeof file.childrenCount !== 'number') return null;
return file.childrenCount;
};
return FileHelper;
}();
var sanitizeInputArray = function sanitizeInputArray(mode, rawArray) {
var sanitizedFiles = [];
var errorMessages = [];
if ((mode === 'folderChain' || mode === 'fileActions') && !rawArray) ; else if (!Array.isArray(rawArray)) {
errorMessages.push("Expected \"" + mode + "\" prop to be an array, got \"" + typeof rawArray + "\" instead.");
} else {
var nonObjectFileCount = 0;
var missingFieldFileCount = 0;
var seenIds = new Set();
var duplicateIds = new Set();
for (var i = 0; i < rawArray.length; ++i) {
var item = rawArray[i];
if (!item) {
if (mode === 'fileActions') nonObjectFileCount++;else sanitizedFiles.push(null);
} else if (typeof item !== 'object') {
nonObjectFileCount++;
} else {
if (!item.id || mode !== 'fileActions' && !item.name) {
missingFieldFileCount++;
} else if (seenIds.has(item.id)) {
duplicateIds.add(item.id);
} else {
seenIds.add(item.id);
sanitizedFiles.push(item);
}
}
}
if (nonObjectFileCount) {
errorMessages.push("Detected " + nonObjectFileCount + " file(s) of invalid type. Remember " + "that \"files\" array should contain either objects or nulls.");
}
if (missingFieldFileCount) {
errorMessages.push("Detected " + missingFieldFileCount + " file(s) that are missing the " + "required fields. Remember that file object should define an " + "\"id\" and a \"name\".");
}
if (duplicateIds.size > 0) {
var repeatedIdsString = '"' + Array.from(duplicateIds).join('", "') + '"';
errorMessages.push("Detected " + duplicateIds.size + " file IDs that are used multiple " + "times. Remember that each file should have a unique IDs. The " + ("following IDs were seen multiple times: " + repeatedIdsString));
}
}
if (errorMessages.length > 0) {
var errorMessageString = '\n- ' + errorMessages.join('\n- ');
var arrayString;
var itemString;
if (mode === 'folderChain') {
arrayString = 'folder chain';
itemString = 'files';
} else if (mode === 'fileActions') {
arrayString = 'file actions';
itemString = 'file actions';
} else {
// mode === 'files'
arrayString = 'files';
itemString = 'files';
}
Logger.error("Errors were detected when sanitizing the " + arrayString + " array. " + ("Offending " + itemString + " were removed from the array. Summary of ") + ("validation errors: " + errorMessageString));
}
return {
sanitizedArray: sanitizedFiles,
errorMessages: errorMessages
};
};
/**
* We have option IDs in a separate file to avoid circular deps...
*/
var OptionIds = {
ShowHiddenFiles: 'show_hidden_files',
ShowFoldersFirst: 'show_folders_first',
DarkMode: 'dark_mode'
};
var SortOrder;
(function (SortOrder) {
SortOrder["ASC"] = "asc";
SortOrder["DESC"] = "desc";
})(SortOrder || (SortOrder = {}));
// Raw selectors
var selectInstanceId = function selectInstanceId(state) {
return state.instanceId;
};
var selectExternalFileActionHandler = function selectExternalFileActionHandler(state) {
return state.externalFileActionHandler;
};
var selectFileActionMap = function selectFileActionMap(state) {
return state.fileActionMap;
};
var selectFileActionIds = function selectFileActionIds(state) {
return state.fileActionIds;
};
var selectFileActionData = function selectFileActionData(fileActionId) {
return function (state) {
return selectFileActionMap(state)[fileActionId];
};
};
var selectToolbarItems = function selectToolbarItems(state) {
return state.toolbarItems;
};
var selectContextMenuItems = function selectContextMenuItems(state) {
return state.contextMenuItems;
};
var selectFolderChain = function selectFolderChain(state) {
return state.folderChain;
};
var selectCurrentFolder = function selectCurrentFolder(state) {
var folderChain = selectFolderChain(state);
var currentFolder = folderChain.length > 0 ? folderChain[folderChain.length - 1] : null;
return currentFolder;
};
var selectParentFolder = function selectParentFolder(state) {
var folderChain = selectFolderChain(state);
var parentFolder = folderChain.length > 1 ? folderChain[folderChain.length - 2] : null;
return parentFolder;
};
var selectRawFiles = function selectRawFiles(state) {
return state.rawFiles;
};
var selectFileMap = function selectFileMap(state) {
return state.fileMap;
};
var selectCleanFileIds = function selectCleanFileIds(state) {
return state.cleanFileIds;
};
var selectFileData = function selectFileData(fileId) {
return function (state) {
return fileId ? selectFileMap(state)[fileId] : null;
};
};
var selectHiddenFileIdMap = function selectHiddenFileIdMap(state) {
return state.hiddenFileIdMap;
};
var selectHiddenFileCount = function selectHiddenFileCount(state) {
return Object.keys(selectHiddenFileIdMap(state)).length;
};
var selectFocusSearchInput = function selectFocusSearchInput(state) {
return state.focusSearchInput;
};
var selectSearchString = function selectSearchString(state) {
return state.searchString;
};
var selectOnSearchInput = function selectOnSearchInput(state) {
return state.onSearchInput;
};
var selectOnCancelSearch = function selectOnCancelSearch(state) {
return state.onCancelSearch;
};
var selectSelectionMap = function selectSelectionMap(state) {
return state.selectionMap;
};
var selectSelectedFileIds = function selectSelectedFileIds(state) {
return Object.keys(selectSelectionMap(state));
};
var selectSelectionSize = function selectSelectionSize(state) {
return selectSelectedFileIds(state).length;
};
var selectIsFileSelected = function selectIsFileSelected(fileId) {
return function (state) {
return !!fileId && !!selectSelectionMap(state)[fileId];
};
};
var selectSelectedFiles = function selectSelectedFiles(state) {
var fileMap = selectFileMap(state);
return Object.keys(selectSelectionMap(state)).map(function (id) {
return fileMap[id];
});
};
var selectSelectedFilesForAction = function selectSelectedFilesForAction(fileActionId) {
return function (state) {
var fileActionMap = state.fileActionMap;
var action = fileActionMap[fileActionId];
if (!action || !action.requiresSelection) return undefined;
return getSelectedFiles(state, action.fileFilter);
};
};
var selectSelectedFilesForActionCount = function selectSelectedFilesForActionCount(fileActionId) {
return function (state) {
var _getSelectedFilesForA;
return (_getSelectedFilesForA = getSelectedFilesForAction(state, fileActionId)) == null ? void 0 : _getSelectedFilesForA.length;
};
};
var selectDisableSelection = function selectDisableSelection(state) {
return state.disableSelection;
};
var selectDisableSimpleDeselection = function selectDisableSimpleDeselection(state) {
return state.disableSimpleDeselection;
};
var selectForceEnableOpenParent = function selectForceEnableOpenParent(state) {
return state.forceEnableOpenParent;
};
var selectHideToolbarInfo = function selectHideToolbarInfo(state) {
return state.hideToolbarInfo;
};
var selectFileViewConfig = function selectFileViewConfig(state) {
return state.fileViewConfig;
};
var selectSortActionId = function selectSortActionId(state) {
return state.sortActionId;
};
var selectSortOrder = function selectSortOrder(state) {
return state.sortOrder;
};
var selectOptionMap = function selectOptionMap(state) {
return state.optionMap;
};
var selectOptionValue = function selectOptionValue(optionId) {
return function (state) {
return selectOptionMap(state)[optionId];
};
};
var selectDoubleClickDelay = function selectDoubleClickDelay(state) {
return state.doubleClickDelay;
};
var selectIsDnDDisabled = function selectIsDnDDisabled(state) {
return state.disableDragAndDrop;
};
var selectClearSelectionOnOutsideClick = function selectClearSelectionOnOutsideClick(state) {
return state.clearSelectionOnOutsideClick;
};
var selectContextMenuMounted = function selectContextMenuMounted(state) {
return state.contextMenuMounted;
};
var selectContextMenuConfig = function selectContextMenuConfig(state) {
return state.contextMenuConfig;
};
var selectContextMenuTriggerFile = function selectContextMenuTriggerFile(state) {
var _fileMap$config$trigg;
var config = selectContextMenuConfig(state);
if (!config || !config.triggerFileId) return null;
var fileMap = selectFileMap(state);
return (_fileMap$config$trigg = fileMap[config.triggerFileId]) != null ? _fileMap$config$trigg : null;
};
var selectRenamingFileId = function selectRenamingFileId(state) {
return state.renamingFileId;
};
var selectIsFileRenaming = function selectIsFileRenaming(fileId) {
return function (state) {
return !!fileId && selectRenamingFileId(state) === fileId;
};
};
var selectRenamingSanitizer = function selectRenamingSanitizer(state) {
return state.renamingSanitizer;
};
// Raw selectors
var getFileActionMap = function getFileActionMap(state) {
return state.fileActionMap;
};
var getOptionMap = function getOptionMap(state) {
return state.optionMap;
};
var getFileMap = function getFileMap(state) {
return state.fileMap;
};
var getFileIds = function getFileIds(state) {
return state.fileIds;
};
var getCleanFileIds = function getCleanFileIds(state) {
return state.cleanFileIds;
};
var getSortActionId = function getSortActionId(state) {
return state.sortActionId;
};
var getSortOrder = function getSortOrder(state) {
return state.sortOrder;
};
var getSearchString = function getSearchString(state) {
return state.searchString;
};
var _getLastClick = function _getLastClick(state) {
return state.lastClick;
};
var getSortCollator = function getSortCollator(state) {
return state.sortCollator;
};
var getSearchPredicate = function getSearchPredicate(state) {
return state.searchPredicate;
};
// Memoized selectors
var makeGetAction = function makeGetAction(fileActionSelector) {
return createSelector([getFileActionMap, fileActionSelector], function (fileActionMap, fileActionId) {
return fileActionId && fileActionMap[fileActionId] ? fileActionMap[fileActionId] : null;
});
};
var makeGetOptionValue = function makeGetOptionValue(optionId, defaultValue) {
if (defaultValue === void 0) {
defaultValue = undefined;
}
return createSelector([getOptionMap], function (optionMap) {
var value = optionMap[optionId];
if (value === undefined) {
return defaultValue;
}
return value;
});
};
var makeGetFiles = function makeGetFiles(fileIdsSelector) {
return createSelector([getFileMap, fileIdsSelector], function (fileMap, fileIds) {
return fileIds.map(function (fileId) {
return fileId && fileMap[fileId] ? fileMap[fileId] : null;
});
});
};
var getSortedFileIds = /*#__PURE__*/createSelector([getFileIds, getSortOrder, getSortCollator, /*#__PURE__*/makeGetFiles(getFileIds), /*#__PURE__*/makeGetAction(getSortActionId), /*#__PURE__*/makeGetOptionValue(OptionIds.ShowFoldersFirst, false)], function (fileIds, sortOrder, sortCollator, files, sortAction, showFolderFirst) {
if (!sortAction) {
// We allow users to set the sort action ID to `null` if they want to use their
// own sorting mechanisms instead of relying on Chonky built-in sort.
return fileIds;
}
var prepareSortKeySelector = function prepareSortKeySelector(selector) {
return function (file) {
return selector(file);
};
};
var sortFunctions = [];
if (showFolderFirst) {
// If option is undefined (relevant actions is not enabled), we don't show
// folders first.
sortFunctions.push({
desc: prepareSortKeySelector(FileHelper.isDirectory)
});
}
if (sortAction.sortKeySelector) {
var _sortFunctions$push;
var configKeyName = sortOrder === SortOrder.ASC ? 'asc' : 'desc';
sortFunctions.push((_sortFunctions$push = {}, _sortFunctions$push[configKeyName] = prepareSortKeySelector(sortAction.sortKeySelector), _sortFunctions$push.comparer = sortCollator == null ? void 0 : sortCollator.compare, _sortFunctions$push));
}
if (sortFunctions.length === 0) return fileIds;
// We copy the array because `fast-sort` mutates it
var sortedFileIds = sort([].concat(files)).by(sortFunctions).map(function (file) {
return file ? file.id : null;
});
return sortedFileIds;
});
var getSearcher = /*#__PURE__*/createSelector([/*#__PURE__*/makeGetFiles(getCleanFileIds), getSearchPredicate], function (cleanFiles, searchPredicate) {
var files = cleanFiles;
return searchPredicate ? {
search: function search(needle) {
return files.filter(function (file) {
return searchPredicate(needle, file);
});
}
} : new FuzzySearch(files, ['name'], {
caseSensitive: false
});
});
var getSearchFilteredFileIds = /*#__PURE__*/createSelector([getCleanFileIds, getSearchString, getSearcher], function (cleanFileIds, searchString, searcher) {
return searchString ? searcher.search(searchString).map(function (f) {
return f.id;
}) : cleanFileIds;
});
var getHiddenFileIdMap = /*#__PURE__*/createSelector([getSearchFilteredFileIds, /*#__PURE__*/makeGetFiles(getCleanFileIds), /*#__PURE__*/makeGetOptionValue(OptionIds.ShowHiddenFiles)], function (searchFilteredFileIds, cleanFiles, showHiddenFiles) {
var searchFilteredFileIdsSet = new Set(searchFilteredFileIds);
var hiddenFileIdMap = {};
cleanFiles.forEach(function (file) {
if (!file) return;else if (!searchFilteredFileIdsSet.has(file.id)) {
// Hidden by seach
hiddenFileIdMap[file.id] = true;
} else if (!showHiddenFiles && FileHelper.isHidden(file)) {
// Hidden by options
hiddenFileIdMap[file.id] = true;
}
});
return hiddenFileIdMap;
});
var getDisplayFileIds = /*#__PURE__*/createSelector([getSortedFileIds, getHiddenFileIdMap], /** Returns files that will actually be shown to the user. */
function (sortedFileIds, hiddenFileIdMap) {
return sortedFileIds.filter(function (id) {
return !id || !hiddenFileIdMap[id];
});
});
var getLastClick = /*#__PURE__*/createSelector([_getLastClick, getDisplayFileIds], /** Returns the last click index after ensuring it is actually still valid. */
function (lastClick, displayFileIds) {
if (!lastClick || lastClick.index > displayFileIds.length - 1 || lastClick.fileId != displayFileIds[lastClick.index]) {
return null;
}
return lastClick;
});
var selectors = {
// Raw selectors
getFileActionMap: getFileActionMap,
getOptionMap: getOptionMap,
getFileMap: getFileMap,
getFileIds: getFileIds,
getCleanFileIds: getCleanFileIds,
getSortActionId: getSortActionId,
getSortOrder: getSortOrder,
getSearchString: getSearchString,
_getLastClick: _getLastClick,
// Memoized selectors
getSortedFileIds: getSortedFileIds,
getSearcher: getSearcher,
getSearchFilteredFileIds: getSearchFilteredFileIds,
getHiddenFileIdMap: getHiddenFileIdMap,
getDisplayFileIds: getDisplayFileIds,
getLastClick: getLastClick,
// Parametrized selectors
makeGetAction: makeGetAction,
makeGetOptionValue: makeGetOptionValue,
makeGetFiles: makeGetFiles
};
// Selectors meant to be used outside of Redux code
var getFileData = function getFileData(state, fileId) {
return fileId ? selectFileMap(state)[fileId] : null;
};
var getIsFileSelected = function getIsFileSelected(state, file) {
// !!! We deliberately don't use `FileHelper.isSelectable` here as we want to
// reflect the state of Redux store accurately.
return !!selectSelectionMap(state)[file.id];
};
var getSelectedFiles = function getSelectedFiles(state) {
var fileMap = state.fileMap,
selectionMap = state.selectionMap;
var selectedFiles = Object.keys(selectionMap).map(function (id) {
return fileMap[id];
});
for (var _len = arguments.length, filters = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
filters[_key - 1] = arguments[_key];
}
var filteredSelectedFiles = filters.reduce(function (prevFiles, filter) {
return filter ? prevFiles.filter(filter) : prevFiles;
}, selectedFiles);
return filteredSelectedFiles;
};
var getSelectedFilesForAction = function getSelectedFilesForAction(state, fileActionId) {
return selectSelectedFilesForAction(fileActionId)(state);
};
var ChonkyIconName;
(function (ChonkyIconName) {
// Misc
ChonkyIconName["loading"] = "loading";
ChonkyIconName["dropdown"] = "dropdown";
ChonkyIconName["placeholder"] = "placeholder";
// File Actions: Drag & drop
ChonkyIconName["dndDragging"] = "dndDragging";
ChonkyIconName["dndCanDrop"] = "dndCanDrop";
ChonkyIconName["dndCannotDrop"] = "dndCannotDrop";
// File Actions: File operations
ChonkyIconName["openFiles"] = "openFiles";
ChonkyIconName["openParentFolder"] = "openParentFolder";
ChonkyIconName["copy"] = "copy";
ChonkyIconName["paste"] = "paste";
ChonkyIconName["share"] = "share";
ChonkyIconName["search"] = "search";
ChonkyIconName["selectAllFiles"] = "selectAllFiles";
ChonkyIconName["clearSelection"] = "clearSelection";
// File Actions: Sorting & options
ChonkyIconName["sortAsc"] = "sortAsc";
ChonkyIconName["sortDesc"] = "sortDesc";
ChonkyIconName["toggleOn"] = "toggleOn";
ChonkyIconName["toggleOff"] = "toggleOff";
// File Actions: File Views
ChonkyIconName["list"] = "list";
ChonkyIconName["compact"] = "compact";
ChonkyIconName["smallThumbnail"] = "smallThumbnail";
ChonkyIconName["largeThumbnail"] = "largeThumbnail";
// File Actions: Unsorted
ChonkyIconName["folder"] = "folder";
ChonkyIconName["folderCreate"] = "folderCreate";
ChonkyIconName["folderOpen"] = "folderOpen";
ChonkyIconName["folderChainSeparator"] = "folderChainSeparator";
ChonkyIconName["download"] = "download";
ChonkyIconName["upload"] = "upload";
ChonkyIconName["trash"] = "trash";
ChonkyIconName["fallbackIcon"] = "fallbackIcon";
// File modifiers
ChonkyIconName["symlink"] = "symlink";
ChonkyIconName["hidden"] = "hidden";
// Generic file types
ChonkyIconName["file"] = "file";
ChonkyIconName["license"] = "license";
ChonkyIconName["code"] = "code";
ChonkyIconName["config"] = "config";
ChonkyIconName["model"] = "model";
ChonkyIconName["database"] = "database";
ChonkyIconName["text"] = "text";
ChonkyIconName["archive"] = "archive";
ChonkyIconName["image"] = "image";
ChonkyIconName["video"] = "video";
ChonkyIconName["info"] = "info";
ChonkyIconName["key"] = "key";
ChonkyIconName["lock"] = "lock";
ChonkyIconName["music"] = "music";
ChonkyIconName["terminal"] = "terminal";
ChonkyIconName["users"] = "users";
// OS file types
ChonkyIconName["linux"] = "linux";
ChonkyIconName["ubuntu"] = "ubuntu";
ChonkyIconName["windows"] = "windows";
// Programming language file types
ChonkyIconName["rust"] = "rust";
ChonkyIconName["python"] = "python";
ChonkyIconName["nodejs"] = "nodejs";
ChonkyIconName["php"] = "php";
// Development tools file types
ChonkyIconName["git"] = "git";
// Other program file types
ChonkyIconName["pdf"] = "pdf";
ChonkyIconName["excel"] = "excel";
ChonkyIconName["word"] = "word";
ChonkyIconName["flash"] = "flash";
})(ChonkyIconName || (ChonkyIconName = {}));
/**
* Merges multiple file action arrays into one while removing duplicates
*/
var mergeFileActionsArrays = function mergeFileActionsArrays() {
var _Array;
var seenActionIds = new Set();
var addToSeen = function addToSeen(a) {
return !!seenActionIds.add(a.id);
};
var wasNotSeen = function wasNotSeen(a) {
return !seenActionIds.has(a.id);
};
for (var _len = arguments.length, fileActionArrays = new Array(_len), _key = 0; _key < _len; _key++) {
fileActionArrays[_key] = arguments[_key];
}
var duplicateFreeArrays = fileActionArrays.map(function (arr) {
var duplicateFreeArray = arr.filter(wasNotSeen);
duplicateFreeArray.map(addToSeen);
return duplicateFreeArray;
});
return (_Array = new Array()).concat.apply(_Array, duplicateFreeArrays);
};
var thunkUpdateRawFileActions = function thunkUpdateRawFileActions(rawFileActions, disableDefaultFileActions) {
return function (dispatch) {
var _sanitizeInputArray = sanitizeInputArray('fileActions', rawFileActions),
sanitizedArray = _sanitizeInputArray.sanitizedArray,
errorMessages = _sanitizeInputArray.errorMessages;
// Add default actions unless user disabled them
var defaultActionsToAdd;
if (Array.isArray(disableDefaultFileActions)) {
var disabledActionIds = new Set(disableDefaultFileActions);
defaultActionsToAdd = DefaultFileActions.filter(function (action) {
return !disabledActionIds.has(action.id);
});
} else if (disableDefaultFileActions) {
defaultActionsToAdd = [];
} else {
defaultActionsToAdd = DefaultFileActions;
}
var fileActions = mergeFileActionsArrays(sanitizedArray, EssentialFileActions, defaultActionsToAdd);
var optionDefaults = {};
fileActions.map(function (a) {
return a.option ? optionDefaults[a.option.id] = a.option.defaultValue : null;
});
dispatch(reduxActions.setRawFileActions(rawFileActions));
dispatch(reduxActions.setFileActionsErrorMessages(errorMessages));
dispatch(reduxActions.setFileActions(fileActions));
dispatch(reduxActions.setOptionDefaults(optionDefaults));
dispatch(thunkUpdateToolbarNContextMenuItems(fileActions));
};
};
var thunkUpdateToolbarNContextMenuItems = function thunkUpdateToolbarNContextMenuItems(fileActions) {
return function (dispatch) {
var excludedToolbarFileActionIds = new Set([
// TODO: Move decision to exclude actions somewhere else, as users' custom
// components might not give these actions special treatment like Chonky does.
ChonkyActions.OpenParentFolder.id]);
// TODO: Move decision to set icons somewhere else, as users' custom
// components might not give these group names special treatment.
var groupIcons = {
Actions: ChonkyIconName.dropdown,
Options: ChonkyIconName.config
};
var groupSortOrder = {
Options: 0,
Actions: 1
};
var toolbarItems = [];
var toolbarGroupItems = [];
var seenToolbarGroups = {};
var contextMenuItems = [];
var seenContextMenuGroups = {};
var getGroup = function getGroup(itemArray, seenMap, groupName) {
if (seenMap[groupName]) return seenMap[groupName];
var group = {
name: groupName,
icon: groupIcons[groupName] || null,
sortOrder: groupSortOrder[groupName] || -1,
fileActionIds: []
};
itemArray.push(group);
seenMap[groupName] = group;
return group;
};
for (var _iterator = _createForOfIteratorHelperLoose(fileActions), _step; !(_step = _iterator()).done;) {
var action = _step.value;
var button = action.button;
if (!button) continue;
if (button.toolbar && !excludedToolbarFileActionIds.has(action.id)) {
if (button.group) {
var group = getGroup(toolbarGroupItems, seenToolbarGroups, button.group);
group.fileActionIds.push(action.id);
} else {
toolbarItems.push(action.id);
}
}
if (button.contextMenu) {
if (button.group) {
var _group = getGroup(contextMenuItems, seenContextMenuGroups, button.group);
_group.fileActionIds.push(action.id);
} else {
contextMenuItems.push(action.id);
}
}
}
toolbarGroupItems.sort(function (a, b) {
return a.sortOrder - b.sortOrder;
});
dispatch(reduxActions.updateFileActionMenuItems([[].concat(toolbarItems, toolbarGroupItems), contextMenuItems]));
};
};
var thunkUpdateDefaultFileViewActionId = function thunkUpdateDefaultFileViewActionId(fileActionId) {
return function (dispatch, getState) {
var _getState = getState(),
fileActionMap = _getState.fileActionMap;
var action = fileActionId ? fileActionMap[fileActionId] : null;
if (action && action.fileViewConfig) {
dispatch(reduxActions.setFileViewConfig(action.fileViewConfig));
}
};
};
var thunkActivateSortAction = function thunkActivateSortAction(fileActionId) {
return function (dispatch, getState) {
if (!fileActionId) return;
var _getState2 = getState(),
oldActionId = _getState2.sortActionId,
oldOrder = _getState2.sortOrder,
fileActionMap = _getState2.fileActionMap;
var action = fileActionMap[fileActionId];
if (!action || !action.sortKeySelector) return;
var order = oldOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
if (oldActionId !== fileActionId) {
order = SortOrder.ASC;
}
dispatch(reduxActions.setSort({
actionId: fileActionId,
order: order
}));
};
};
var thunkApplySelectionTransform = function thunkApplySelectionTransform(action) {
return function (dispatch, getState) {
var selectionTransform = action.selectionTransform;
if (!selectionTransform) return;
var state = getState();
var prevSelection = new Set(Object.keys(selectSelectionMap(state)));
var hiddenFileIds = new Set(Object.keys(selectors.getHiddenFileIdMap(state)));
var newSelection = selectionTransform({
prevSelection: prevSelection,
fileIds: selectCleanFileIds(state),
fileMap: selectFileMap(state),
hiddenFileIds: hiddenFileIds
});
if (!newSelection) return;
if (newSelection.size === 0) {
dispatch(reduxActions.clearSelection());
} else {
dispatch(reduxActions.selectFiles({
fileIds: Array.from(newSelection),
reset: true
}));
}
};
};
/**
* Thunk that dispatches actions to the external (user-provided) action handler.
*/
var thunkDispatchFileAction = function thunkDispatchFileAction(data) {
return function (_dispatch, getState) {
Logger.debug("FILE ACTION DISPATCH: [" + data.id + "]", 'data:', data);
var state = getState();
var action = selectFileActionMap(state)[data.id];
var externalFileActionHandler = selectExternalFileActionHandler(state);
if (action) {
if (externalFileActionHandler) {
Promise.resolve(externalFileActionHandler(data))["catch"](function (error) {
return Logger.error("User-defined file action handler threw an error: " + error.message);
});
}
} else {
Logger.warn("Internal components dispatched the \"" + data.id + "\" file action, but such " + "action was not registered.");
}
};
};
/**
* Thunk that is used by internal components (and potentially the user) to "request"
* actions. When action is requested, Chonky "prepares" the action data by extracting it
* from Redux state. Once action data is ready, Chonky executes some side effect and/or
* dispatches the action to the external action handler.
*/
var thunkRequestFileAction = function thunkRequestFileAction(action, payload) {
return function (dispatch, getState) {
Logger.debug("FILE ACTION REQUEST: [" + action.id + "]", 'action:', action, 'payload:', payload);
var state = getState();
var instanceId = selectInstanceId(state);
if (!selectFileActionMap(state)[action.id]) {
Logger.warn("The action \"" + action.id + "\" was requested, but it is not registered. The " + "action will still be dispatched, but this might indicate a bug in " + "the code. Please register your actions by passing them to " + "\"fileActions\" prop.");
}
// Determine files for the action if action requires selection
var selectedFiles = selectSelectedFiles(state);
var selectedFilesForAction = action.fileFilter ? selectedFiles.filter(action.fileFilter) : selectedFiles;
if (action.requiresSelection && selectedFilesForAction.length === 0) {
Logger.warn("Internal components requested the \"" + action.id + "\" file " + "action, but the selection for this action was empty. This " + "might a bug in the code of the presentational components.");
return;
}
var contextMenuTriggerFile = selectContextMenuTriggerFile(state);
var actionState = {
instanceId: instanceId,
selectedFiles: selectedFiles,
selectedFilesForAction: selectedFilesForAction,
contextMenuTriggerFile: contextMenuTriggerFile
};
// === Update sort state if necessary
var sortKeySelector = action.sortKeySelector;
if (sortKeySelector) dispatch(thunkActivateSortAction(action.id));
// === Update file view state if necessary
var fileViewConfig = action.fileViewConfig;
if (fileViewConfig) dispatch(reduxActions.setFileViewConfig(fileViewConfig));
// === Update option state if necessary
var option = action.option;
if (option) dispatch(reduxActions.toggleOption(option.id));
// === Apply selection transform if necessary
var selectionTransform = action.selectionTransform;
if (selectionTransform) dispatch(thunkApplySelectionTransform(action));
// Apply the effect
var effect = action.effect;
var maybeEffectPromise = undefined;
if (effect) {
try {
maybeEffectPromise = effect({
action: action,
payload: payload,
state: actionState,
reduxDispatch: dispatch,
getReduxState: getState
});
} catch (err) {
var error = err;
Logger.error("User-defined effect function for action " + action.id + " threw an " + ("error: " + error.message));
}
}
// Dispatch the action to user code. Deliberately call it after all other
// operations are over.
return Promise.resolve(maybeEffectPromise).then(function (effectResult) {
var data = {
id: action.id,
action: action,
payload: payload,
state: actionState
};
triggerDispatchAfterEffect(dispatch, data, effectResult);
})["catch"](function (error) {
Logger.error("User-defined effect function for action " + action.id + " returned a " + ("promise that was rejected: " + error.message));
var data = {
id: action.id,
action: action,
payload: payload,
state: actionState
};
triggerDispatchAfterEffect(dispatch, data, undefined);
});
};
};
var triggerDispatchAfterEffect = function triggerDispatchAfterEffect(dispatch, data, effectResult) {
var preventDispatch = effectResult === true;
if (!preventDis