mirror of
https://github.com/Choices-js/Choices.git
synced 2026-03-14 22:55:46 +01:00
Remove redux store in replace for hand-rolled replacement design for in-place updates of the state. Avoids a lot of data copying, and reduces bundle size
This commit is contained in:
parent
bc7be39b57
commit
88db9639b0
51 changed files with 1301 additions and 3686 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Choices.js [](https://github.com/jshjohnson/Choices/actions) [](https://github.com/jshjohnson/Choices/actions) [](https://www.npmjs.com/package/choices.js)
|
||||
|
||||
A vanilla, lightweight (~20.8kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.
|
||||
A vanilla, lightweight (~19.9kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.
|
||||
|
||||
[Demo](https://choices-js.github.io/Choices/)
|
||||
|
||||
|
|
|
|||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -9,8 +9,7 @@
|
|||
"version": "11.0.0-rc5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fuse.js": "^7.0.0",
|
||||
"redux": "^4.2.0"
|
||||
"fuse.js": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.24.8",
|
||||
|
|
@ -1887,6 +1886,7 @@
|
|||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
|
|
@ -12241,15 +12241,6 @@
|
|||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
|
|
@ -12274,6 +12265,7 @@
|
|||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/regenerator-transform": {
|
||||
|
|
|
|||
|
|
@ -131,8 +131,7 @@
|
|||
"vitest": "^2.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"fuse.js": "^7.0.0",
|
||||
"redux": "^4.2.0"
|
||||
"fuse.js": "^7.0.0"
|
||||
},
|
||||
"npmName": "choices.js",
|
||||
"npmFileMap": [
|
||||
|
|
|
|||
|
|
@ -105,14 +105,6 @@
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -240,9 +232,6 @@
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -980,447 +969,85 @@
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1429,36 +1056,41 @@
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1471,102 +1103,110 @@
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1636,10 +1276,10 @@
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1647,7 +1287,7 @@
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -3734,9 +3374,6 @@
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -3819,8 +3456,7 @@
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -3844,6 +3480,7 @@
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -4249,7 +3886,7 @@
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -4278,15 +3915,12 @@
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -4296,7 +3930,6 @@
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -5515,7 +5148,6 @@
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -5543,6 +5175,10 @@
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
2
public/assets/scripts/choices.min.js
vendored
2
public/assets/scripts/choices.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -99,14 +99,6 @@ var highlightItem = function (item, highlighted) { return ({
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -234,9 +226,6 @@ var dispatchEvent = function (element, type, customArgs) {
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -974,447 +963,85 @@ var DEFAULT_CONFIG = {
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1423,36 +1050,41 @@ function choices(state, action) {
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1465,102 +1097,110 @@ function choices(state, action) {
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1630,10 +1270,10 @@ var Store = /** @class */ (function () {
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1641,7 +1281,7 @@ var Store = /** @class */ (function () {
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -3728,9 +3368,6 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -3813,8 +3450,7 @@ var Choices = /** @class */ (function () {
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -3838,6 +3474,7 @@ var Choices = /** @class */ (function () {
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -4243,7 +3880,7 @@ var Choices = /** @class */ (function () {
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -4272,15 +3909,12 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -4290,7 +3924,6 @@ var Choices = /** @class */ (function () {
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -5509,7 +5142,6 @@ var Choices = /** @class */ (function () {
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -5537,6 +5169,10 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -105,14 +105,6 @@
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -240,9 +232,6 @@
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -980,447 +969,85 @@
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1429,36 +1056,41 @@
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1471,102 +1103,110 @@
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1636,10 +1276,10 @@
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1647,7 +1287,7 @@
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -3252,9 +2892,6 @@
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -3337,8 +2974,7 @@
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -3362,6 +2998,7 @@
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -3767,7 +3404,7 @@
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -3796,15 +3433,12 @@
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -3814,7 +3448,6 @@
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -5033,7 +4666,6 @@
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -5061,6 +4693,10 @@
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -99,14 +99,6 @@ var highlightItem = function (item, highlighted) { return ({
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -234,9 +226,6 @@ var dispatchEvent = function (element, type, customArgs) {
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -974,447 +963,85 @@ var DEFAULT_CONFIG = {
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1423,36 +1050,41 @@ function choices(state, action) {
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1465,102 +1097,110 @@ function choices(state, action) {
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1630,10 +1270,10 @@ var Store = /** @class */ (function () {
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1641,7 +1281,7 @@ var Store = /** @class */ (function () {
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -3246,9 +2886,6 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -3331,8 +2968,7 @@ var Choices = /** @class */ (function () {
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -3356,6 +2992,7 @@ var Choices = /** @class */ (function () {
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -3761,7 +3398,7 @@ var Choices = /** @class */ (function () {
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -3790,15 +3427,12 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -3808,7 +3442,6 @@ var Choices = /** @class */ (function () {
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -5027,7 +4660,6 @@ var Choices = /** @class */ (function () {
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -5055,6 +4687,10 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -105,14 +105,6 @@
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -240,9 +232,6 @@
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -980,447 +969,85 @@
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1429,36 +1056,41 @@
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1471,102 +1103,110 @@
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1636,10 +1276,10 @@
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1647,7 +1287,7 @@
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -2108,9 +1748,6 @@
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -2193,8 +1830,7 @@
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -2218,6 +1854,7 @@
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -2623,7 +2260,7 @@
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -2652,15 +2289,12 @@
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2670,7 +2304,6 @@
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -3889,7 +3522,6 @@
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -3917,6 +3549,10 @@
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -99,14 +99,6 @@ var highlightItem = function (item, highlighted) { return ({
|
|||
highlighted: highlighted,
|
||||
}); };
|
||||
|
||||
var clearAll = function () { return ({
|
||||
type: "CLEAR_ALL" /* ActionType.CLEAR_ALL */,
|
||||
}); };
|
||||
var setTxn = function (txn) { return ({
|
||||
type: "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */,
|
||||
txn: txn,
|
||||
}); };
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var getRandomNumber = function (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
|
|
@ -234,9 +226,6 @@ var dispatchEvent = function (element, type, customArgs) {
|
|||
});
|
||||
return element.dispatchEvent(event);
|
||||
};
|
||||
var cloneObject = function (obj) {
|
||||
return obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined;
|
||||
};
|
||||
/**
|
||||
* Returns an array of keys present on the first but missing on the second object
|
||||
*/
|
||||
|
|
@ -974,447 +963,85 @@ var DEFAULT_CONFIG = {
|
|||
|
||||
var ObjectsInConfig = ['fuseOptions', 'classNames'];
|
||||
|
||||
/**
|
||||
* Adapted from React: https://github.com/facebook/react/blob/master/packages/shared/formatProdErrorMessage.js
|
||||
*
|
||||
* Do not require this module directly! Use normal throw error calls. These messages will be replaced with error codes
|
||||
* during build.
|
||||
* @param {number} code
|
||||
*/
|
||||
function formatProdErrorMessage(code) {
|
||||
return "Minified Redux error #" + code + "; visit https://redux.js.org/Errors?code=" + code + " for the full message or " + 'use the non-minified dev environment for full errors. ';
|
||||
}
|
||||
|
||||
// Inlined version of the `symbol-observable` polyfill
|
||||
var $$observable = function () {
|
||||
return typeof Symbol === 'function' && Symbol.observable || '@@observable';
|
||||
}();
|
||||
|
||||
/**
|
||||
* These are private action types reserved by Redux.
|
||||
* For any unknown actions, you must return the current state.
|
||||
* If the current state is undefined, you must return the initial state.
|
||||
* Do not reference these action types directly in your code.
|
||||
*/
|
||||
var randomString = function randomString() {
|
||||
return Math.random().toString(36).substring(7).split('').join('.');
|
||||
};
|
||||
var ActionTypes = {
|
||||
INIT: "@@redux/INIT" + randomString(),
|
||||
REPLACE: "@@redux/REPLACE" + randomString(),
|
||||
PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
|
||||
return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) return false;
|
||||
var proto = obj;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(obj) === proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* **We recommend using the `configureStore` method
|
||||
* of the `@reduxjs/toolkit` package**, which replaces `createStore`.
|
||||
*
|
||||
* Redux Toolkit is our recommended approach for writing Redux logic today,
|
||||
* including store setup, reducers, data fetching, and more.
|
||||
*
|
||||
* **For more details, please read this Redux docs page:**
|
||||
* **https://redux.js.org/introduction/why-rtk-is-redux-today**
|
||||
*
|
||||
* `configureStore` from Redux Toolkit is an improved version of `createStore` that
|
||||
* simplifies setup and helps avoid common bugs.
|
||||
*
|
||||
* You should not be using the `redux` core package by itself today, except for learning purposes.
|
||||
* The `createStore` method from the core `redux` package will not be removed, but we encourage
|
||||
* all users to migrate to using Redux Toolkit for all Redux code.
|
||||
*
|
||||
* If you want to use `createStore` without this visual deprecation warning, use
|
||||
* the `legacy_createStore` import instead:
|
||||
*
|
||||
* `import { legacy_createStore as createStore} from 'redux'`
|
||||
*
|
||||
*/
|
||||
|
||||
function createStore(reducer, preloadedState, enhancer) {
|
||||
var _ref2;
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
|
||||
throw new Error(formatProdErrorMessage(0) );
|
||||
}
|
||||
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
|
||||
enhancer = preloadedState;
|
||||
preloadedState = undefined;
|
||||
}
|
||||
if (typeof enhancer !== 'undefined') {
|
||||
if (typeof enhancer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(1) );
|
||||
}
|
||||
return enhancer(createStore)(reducer, preloadedState);
|
||||
}
|
||||
if (typeof reducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(2) );
|
||||
}
|
||||
var currentReducer = reducer;
|
||||
var currentState = preloadedState;
|
||||
var currentListeners = [];
|
||||
var nextListeners = currentListeners;
|
||||
var isDispatching = false;
|
||||
/**
|
||||
* This makes a shallow copy of currentListeners so we can use
|
||||
* nextListeners as a temporary list while dispatching.
|
||||
*
|
||||
* This prevents any bugs around consumers calling
|
||||
* subscribe/unsubscribe in the middle of a dispatch.
|
||||
*/
|
||||
|
||||
function ensureCanMutateNextListeners() {
|
||||
if (nextListeners === currentListeners) {
|
||||
nextListeners = currentListeners.slice();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reads the state tree managed by the store.
|
||||
*
|
||||
* @returns {any} The current state tree of your application.
|
||||
*/
|
||||
|
||||
function getState() {
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(3) );
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
/**
|
||||
* Adds a change listener. It will be called any time an action is dispatched,
|
||||
* and some part of the state tree may potentially have changed. You may then
|
||||
* call `getState()` to read the current state tree inside the callback.
|
||||
*
|
||||
* You may call `dispatch()` from a change listener, with the following
|
||||
* caveats:
|
||||
*
|
||||
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
|
||||
* If you subscribe or unsubscribe while the listeners are being invoked, this
|
||||
* will not have any effect on the `dispatch()` that is currently in progress.
|
||||
* However, the next `dispatch()` call, whether nested or not, will use a more
|
||||
* recent snapshot of the subscription list.
|
||||
*
|
||||
* 2. The listener should not expect to see all state changes, as the state
|
||||
* might have been updated multiple times during a nested `dispatch()` before
|
||||
* the listener is called. It is, however, guaranteed that all subscribers
|
||||
* registered before the `dispatch()` started will be called with the latest
|
||||
* state by the time it exits.
|
||||
*
|
||||
* @param {Function} listener A callback to be invoked on every dispatch.
|
||||
* @returns {Function} A function to remove this change listener.
|
||||
*/
|
||||
|
||||
function subscribe(listener) {
|
||||
if (typeof listener !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(4) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(5) );
|
||||
}
|
||||
var isSubscribed = true;
|
||||
ensureCanMutateNextListeners();
|
||||
nextListeners.push(listener);
|
||||
return function unsubscribe() {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(6) );
|
||||
}
|
||||
isSubscribed = false;
|
||||
ensureCanMutateNextListeners();
|
||||
var index = nextListeners.indexOf(listener);
|
||||
nextListeners.splice(index, 1);
|
||||
currentListeners = null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Dispatches an action. It is the only way to trigger a state change.
|
||||
*
|
||||
* The `reducer` function, used to create the store, will be called with the
|
||||
* current state tree and the given `action`. Its return value will
|
||||
* be considered the **next** state of the tree, and the change listeners
|
||||
* will be notified.
|
||||
*
|
||||
* The base implementation only supports plain object actions. If you want to
|
||||
* dispatch a Promise, an Observable, a thunk, or something else, you need to
|
||||
* wrap your store creating function into the corresponding middleware. For
|
||||
* example, see the documentation for the `redux-thunk` package. Even the
|
||||
* middleware will eventually dispatch plain object actions using this method.
|
||||
*
|
||||
* @param {Object} action A plain object representing “what changed”. It is
|
||||
* a good idea to keep actions serializable so you can record and replay user
|
||||
* sessions, or use the time travelling `redux-devtools`. An action must have
|
||||
* a `type` property which may not be `undefined`. It is a good idea to use
|
||||
* string constants for action types.
|
||||
*
|
||||
* @returns {Object} For convenience, the same action object you dispatched.
|
||||
*
|
||||
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
|
||||
* return something else (for example, a Promise you can await).
|
||||
*/
|
||||
|
||||
function dispatch(action) {
|
||||
if (!isPlainObject(action)) {
|
||||
throw new Error(formatProdErrorMessage(7) );
|
||||
}
|
||||
if (typeof action.type === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(8) );
|
||||
}
|
||||
if (isDispatching) {
|
||||
throw new Error(formatProdErrorMessage(9) );
|
||||
}
|
||||
try {
|
||||
isDispatching = true;
|
||||
currentState = currentReducer(currentState, action);
|
||||
} finally {
|
||||
isDispatching = false;
|
||||
}
|
||||
var listeners = currentListeners = nextListeners;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
var listener = listeners[i];
|
||||
listener();
|
||||
}
|
||||
return action;
|
||||
}
|
||||
/**
|
||||
* Replaces the reducer currently used by the store to calculate the state.
|
||||
*
|
||||
* You might need this if your app implements code splitting and you want to
|
||||
* load some of the reducers dynamically. You might also need this if you
|
||||
* implement a hot reloading mechanism for Redux.
|
||||
*
|
||||
* @param {Function} nextReducer The reducer for the store to use instead.
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function replaceReducer(nextReducer) {
|
||||
if (typeof nextReducer !== 'function') {
|
||||
throw new Error(formatProdErrorMessage(10) );
|
||||
}
|
||||
currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
|
||||
// Any reducers that existed in both the new and old rootReducer
|
||||
// will receive the previous state. This effectively populates
|
||||
// the new state tree with any relevant data from the old one.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.REPLACE
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Interoperability point for observable/reactive libraries.
|
||||
* @returns {observable} A minimal observable of state changes.
|
||||
* For more information, see the observable proposal:
|
||||
* https://github.com/tc39/proposal-observable
|
||||
*/
|
||||
|
||||
function observable() {
|
||||
var _ref;
|
||||
var outerSubscribe = subscribe;
|
||||
return _ref = {
|
||||
/**
|
||||
* The minimal observable subscription method.
|
||||
* @param {Object} observer Any object that can be used as an observer.
|
||||
* The observer object should have a `next` method.
|
||||
* @returns {subscription} An object with an `unsubscribe` method that can
|
||||
* be used to unsubscribe the observable from the store, and prevent further
|
||||
* emission of values from the observable.
|
||||
*/
|
||||
subscribe: function subscribe(observer) {
|
||||
if (typeof observer !== 'object' || observer === null) {
|
||||
throw new Error(formatProdErrorMessage(11) );
|
||||
}
|
||||
function observeState() {
|
||||
if (observer.next) {
|
||||
observer.next(getState());
|
||||
}
|
||||
}
|
||||
observeState();
|
||||
var unsubscribe = outerSubscribe(observeState);
|
||||
return {
|
||||
unsubscribe: unsubscribe
|
||||
};
|
||||
}
|
||||
}, _ref[$$observable] = function () {
|
||||
return this;
|
||||
}, _ref;
|
||||
} // When a store is created, an "INIT" action is dispatched so that every
|
||||
// reducer returns their initial state. This effectively populates
|
||||
// the initial state tree.
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
return _ref2 = {
|
||||
dispatch: dispatch,
|
||||
subscribe: subscribe,
|
||||
getState: getState,
|
||||
replaceReducer: replaceReducer
|
||||
}, _ref2[$$observable] = observable, _ref2;
|
||||
}
|
||||
function assertReducerShape(reducers) {
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var reducer = reducers[key];
|
||||
var initialState = reducer(undefined, {
|
||||
type: ActionTypes.INIT
|
||||
});
|
||||
if (typeof initialState === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(12) );
|
||||
}
|
||||
if (typeof reducer(undefined, {
|
||||
type: ActionTypes.PROBE_UNKNOWN_ACTION()
|
||||
}) === 'undefined') {
|
||||
throw new Error(formatProdErrorMessage(13) );
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Turns an object whose values are different reducer functions, into a single
|
||||
* reducer function. It will call every child reducer, and gather their results
|
||||
* into a single state object, whose keys correspond to the keys of the passed
|
||||
* reducer functions.
|
||||
*
|
||||
* @param {Object} reducers An object whose values correspond to different
|
||||
* reducer functions that need to be combined into one. One handy way to obtain
|
||||
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
|
||||
* undefined for any action. Instead, they should return their initial state
|
||||
* if the state passed to them was undefined, and the current state for any
|
||||
* unrecognized action.
|
||||
*
|
||||
* @returns {Function} A reducer function that invokes every reducer inside the
|
||||
* passed object, and builds a state object with the same shape.
|
||||
*/
|
||||
|
||||
function combineReducers(reducers) {
|
||||
var reducerKeys = Object.keys(reducers);
|
||||
var finalReducers = {};
|
||||
for (var i = 0; i < reducerKeys.length; i++) {
|
||||
var key = reducerKeys[i];
|
||||
if (typeof reducers[key] === 'function') {
|
||||
finalReducers[key] = reducers[key];
|
||||
}
|
||||
}
|
||||
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
|
||||
var shapeAssertionError;
|
||||
try {
|
||||
assertReducerShape(finalReducers);
|
||||
} catch (e) {
|
||||
shapeAssertionError = e;
|
||||
}
|
||||
return function combination(state, action) {
|
||||
if (state === void 0) {
|
||||
state = {};
|
||||
}
|
||||
if (shapeAssertionError) {
|
||||
throw shapeAssertionError;
|
||||
}
|
||||
var hasChanged = false;
|
||||
var nextState = {};
|
||||
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
||||
var _key = finalReducerKeys[_i];
|
||||
var reducer = finalReducers[_key];
|
||||
var previousStateForKey = state[_key];
|
||||
var nextStateForKey = reducer(previousStateForKey, action);
|
||||
if (typeof nextStateForKey === 'undefined') {
|
||||
action && action.type;
|
||||
throw new Error(formatProdErrorMessage(14) );
|
||||
}
|
||||
nextState[_key] = nextStateForKey;
|
||||
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
||||
}
|
||||
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
|
||||
return hasChanged ? nextState : state;
|
||||
};
|
||||
}
|
||||
|
||||
function items(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function items(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach(function (obj) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
item.selected = true;
|
||||
var el = item.element;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
return __spreadArray(__spreadArray([], state, true), [item], false).map(function (obj) {
|
||||
var choice = obj;
|
||||
choice.highlighted = false;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item_1 = action.item;
|
||||
if (!item_1.id) {
|
||||
return state;
|
||||
if (item_1.id) {
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
update = true;
|
||||
state = state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
}
|
||||
item_1.selected = false;
|
||||
var el = item_1.element;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
return state.filter(function (choice) { return choice.id !== item_1.id; });
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (item) { return item.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "HIGHLIGHT_ITEM" /* ActionType.HIGHLIGHT_ITEM */: {
|
||||
var highlightItemAction_1 = action;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var item = obj;
|
||||
if (item.id === highlightItemAction_1.item.id) {
|
||||
item.highlighted = highlightItemAction_1.highlighted;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function groups(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function groups(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_GROUP" /* ActionType.ADD_GROUP */: {
|
||||
var addGroupAction = action;
|
||||
return __spreadArray(__spreadArray([], state, true), [addGroupAction.group], false);
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
function choices(state, action) {
|
||||
if (state === void 0) { state = []; }
|
||||
if (action === void 0) { action = {}; }
|
||||
function choices(s, action) {
|
||||
var state = s;
|
||||
var update = false;
|
||||
switch (action.type) {
|
||||
case "ADD_CHOICE" /* ActionType.ADD_CHOICE */: {
|
||||
var choice = action.choice;
|
||||
|
|
@ -1423,36 +1050,41 @@ function choices(state, action) {
|
|||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return __spreadArray(__spreadArray([], state, true), [choice], false);
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_CHOICE" /* ActionType.REMOVE_CHOICE */: {
|
||||
var choice_1 = action.choice;
|
||||
return state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
update = true;
|
||||
state = state.filter(function (obj) { return obj.id !== choice_1.id; });
|
||||
break;
|
||||
}
|
||||
case "ADD_ITEM" /* ActionType.ADD_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "REMOVE_ITEM" /* ActionType.REMOVE_ITEM */: {
|
||||
var item = action.item;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return __spreadArray([], state, true);
|
||||
update = true;
|
||||
}
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
case "FILTER_CHOICES" /* ActionType.FILTER_CHOICES */: {
|
||||
var results = action.results;
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
var scoreLookup_1 = [];
|
||||
results.forEach(function (result) {
|
||||
scoreLookup_1[result.item.id] = result;
|
||||
});
|
||||
return state.map(function (obj) {
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
var result = scoreLookup_1[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -1465,102 +1097,110 @@ function choices(state, action) {
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "ACTIVATE_CHOICES" /* ActionType.ACTIVATE_CHOICES */: {
|
||||
var active_1 = action.active;
|
||||
return state.map(function (obj) {
|
||||
update = true;
|
||||
state.forEach(function (obj) {
|
||||
var choice = obj;
|
||||
choice.active = active_1;
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "CLEAR_CHOICES" /* ActionType.CLEAR_CHOICES */: {
|
||||
return [];
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { state: state, update: update };
|
||||
}
|
||||
|
||||
var general = function (state, action) {
|
||||
if (state === void 0) { state = 0; }
|
||||
if (action === void 0) { action = {}; }
|
||||
switch (action.type) {
|
||||
case "SET_TRANSACTION" /* ActionType.SET_TRANSACTION */: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var defaultState = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
var appReducer = combineReducers({
|
||||
items: items,
|
||||
var reducers = {
|
||||
groups: groups,
|
||||
items: items,
|
||||
choices: choices,
|
||||
txn: general,
|
||||
});
|
||||
var rootReducer = function (passedState, action) {
|
||||
var state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === "CLEAR_ALL" /* ActionType.CLEAR_ALL */) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
var paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
var Store = /** @class */ (function () {
|
||||
function Store() {
|
||||
this._store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__());
|
||||
this._store = this.defaultState;
|
||||
this._listeners = [];
|
||||
this._txn = 0;
|
||||
}
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._store.subscribe(onChange);
|
||||
Object.defineProperty(Store.prototype, "defaultState", {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get: function () {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
Store.prototype.changeSet = function (init) {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
};
|
||||
Store.prototype.resetStore = function () {
|
||||
this._store = this.defaultState;
|
||||
var changes = this.changeSet(true);
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
};
|
||||
Store.prototype.subscribe = function (onChange) {
|
||||
this._listeners.push(onChange);
|
||||
};
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
Store.prototype.dispatch = function (action) {
|
||||
this._store.dispatch(action);
|
||||
var state = this._store;
|
||||
var hasChanges = false;
|
||||
var changes = this._outstandingChanges || this.changeSet(false);
|
||||
Object.keys(reducers).forEach(function (key) {
|
||||
var stateUpdate = reducers[key](state[key], action);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
}
|
||||
else {
|
||||
this._listeners.forEach(function (l) { return l(changes); });
|
||||
}
|
||||
}
|
||||
};
|
||||
Store.prototype.withTxn = function (func) {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
}
|
||||
finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
if (!this._txn) {
|
||||
var changeSet_1 = this._outstandingChanges;
|
||||
if (changeSet_1) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach(function (l) { return l(changeSet_1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.defineProperty(Store.prototype, "state", {
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get: function () {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
|
|
@ -1630,10 +1270,10 @@ var Store = /** @class */ (function () {
|
|||
* Get active groups from store
|
||||
*/
|
||||
get: function () {
|
||||
var _a = this, groups = _a.groups, choices = _a.choices;
|
||||
return groups.filter(function (group) {
|
||||
var _this = this;
|
||||
return this.state.groups.filter(function (group) {
|
||||
var isActive = group.active && !group.disabled;
|
||||
var hasActiveOptions = choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });
|
||||
return isActive && hasActiveOptions;
|
||||
}, []);
|
||||
},
|
||||
|
|
@ -1641,7 +1281,7 @@ var Store = /** @class */ (function () {
|
|||
configurable: true
|
||||
});
|
||||
Store.prototype.inTxn = function () {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
};
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
|
|
@ -2102,9 +1742,6 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this.initialised = false;
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -2187,8 +1824,7 @@ var Choices = /** @class */ (function () {
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
this._store.subscribe(this._render);
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
var shouldDisable = (this._isTextElement && !this.config.addItems) ||
|
||||
this.passedElement.element.hasAttribute('disabled') ||
|
||||
|
|
@ -2212,6 +1848,7 @@ var Choices = /** @class */ (function () {
|
|||
this.passedElement.reveal();
|
||||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
this._templates = templates;
|
||||
this.initialised = false;
|
||||
|
|
@ -2617,7 +2254,7 @@ var Choices = /** @class */ (function () {
|
|||
return this;
|
||||
};
|
||||
Choices.prototype.clearStore = function () {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -2646,15 +2283,12 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
}
|
||||
};
|
||||
Choices.prototype._render = function () {
|
||||
Choices.prototype._render = function (changes) {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
this._currentState = this._store.state;
|
||||
var shouldRenderItems = this._currentState.items !== this._prevState.items;
|
||||
var stateChanged = this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
var shouldRenderItems = changes === null || changes === void 0 ? void 0 : changes.items;
|
||||
var stateChanged = (changes === null || changes === void 0 ? void 0 : changes.choices) || (changes === null || changes === void 0 ? void 0 : changes.groups) || shouldRenderItems;
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2664,7 +2298,6 @@ var Choices = /** @class */ (function () {
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
this._prevState = this._currentState;
|
||||
};
|
||||
Choices.prototype._renderChoices = function () {
|
||||
var _this = this;
|
||||
|
|
@ -3883,7 +3516,6 @@ var Choices = /** @class */ (function () {
|
|||
});
|
||||
};
|
||||
Choices.prototype._createStructure = function () {
|
||||
var _this = this;
|
||||
// Hide original element
|
||||
this.passedElement.conceal();
|
||||
// Wrap input in container preserving DOM ordering
|
||||
|
|
@ -3911,6 +3543,10 @@ var Choices = /** @class */ (function () {
|
|||
}
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
};
|
||||
Choices.prototype._initStore = function () {
|
||||
var _this = this;
|
||||
this._store.subscribe(this._render);
|
||||
this._store.withTxn(function () {
|
||||
_this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);
|
||||
});
|
||||
|
|
|
|||
17
public/types/src/scripts/actions/choices.d.ts
vendored
17
public/types/src/scripts/actions/choices.d.ts
vendored
|
|
@ -1,24 +1,21 @@
|
|||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { SearchResult } from '../interfaces/search';
|
||||
export interface AddChoiceAction {
|
||||
type: ActionType.ADD_CHOICE;
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
export type ChoiceActions = AddChoiceAction | RemoveChoiceAction | FilterChoicesAction | ActivateChoicesAction | ClearChoicesAction;
|
||||
export interface AddChoiceAction extends AnyAction<ActionType.ADD_CHOICE> {
|
||||
choice: ChoiceFull;
|
||||
}
|
||||
export interface RemoveChoiceAction {
|
||||
type: ActionType.REMOVE_CHOICE;
|
||||
export interface RemoveChoiceAction extends AnyAction<ActionType.REMOVE_CHOICE> {
|
||||
choice: ChoiceFull;
|
||||
}
|
||||
export interface FilterChoicesAction {
|
||||
type: ActionType.FILTER_CHOICES;
|
||||
export interface FilterChoicesAction extends AnyAction<ActionType.FILTER_CHOICES> {
|
||||
results: SearchResult<ChoiceFull>[];
|
||||
}
|
||||
export interface ActivateChoicesAction {
|
||||
type: ActionType.ACTIVATE_CHOICES;
|
||||
export interface ActivateChoicesAction extends AnyAction<ActionType.ACTIVATE_CHOICES> {
|
||||
active: boolean;
|
||||
}
|
||||
export interface ClearChoicesAction {
|
||||
type: ActionType.CLEAR_CHOICES;
|
||||
export interface ClearChoicesAction extends AnyAction<ActionType.CLEAR_CHOICES> {
|
||||
}
|
||||
export declare const addChoice: (choice: ChoiceFull) => AddChoiceAction;
|
||||
export declare const removeChoice: (choice: ChoiceFull) => RemoveChoiceAction;
|
||||
|
|
|
|||
5
public/types/src/scripts/actions/groups.d.ts
vendored
5
public/types/src/scripts/actions/groups.d.ts
vendored
|
|
@ -1,7 +1,8 @@
|
|||
import { GroupFull } from '../interfaces/group-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
export interface AddGroupAction {
|
||||
type: ActionType.ADD_GROUP;
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
export type GroupActions = AddGroupAction;
|
||||
export interface AddGroupAction extends AnyAction<ActionType.ADD_GROUP> {
|
||||
group: GroupFull;
|
||||
}
|
||||
export declare const addGroup: (group: GroupFull) => AddGroupAction;
|
||||
|
|
|
|||
11
public/types/src/scripts/actions/items.d.ts
vendored
11
public/types/src/scripts/actions/items.d.ts
vendored
|
|
@ -1,15 +1,14 @@
|
|||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
export interface AddItemAction {
|
||||
type: ActionType.ADD_ITEM;
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
export type ItemActions = AddItemAction | RemoveItemAction | HighlightItemAction;
|
||||
export interface AddItemAction extends AnyAction<ActionType.ADD_ITEM> {
|
||||
item: ChoiceFull;
|
||||
}
|
||||
export interface RemoveItemAction {
|
||||
type: ActionType.REMOVE_ITEM;
|
||||
export interface RemoveItemAction extends AnyAction<ActionType.REMOVE_ITEM> {
|
||||
item: ChoiceFull;
|
||||
}
|
||||
export interface HighlightItemAction {
|
||||
type: ActionType.HIGHLIGHT_ITEM;
|
||||
export interface HighlightItemAction extends AnyAction<ActionType.HIGHLIGHT_ITEM> {
|
||||
item: ChoiceFull;
|
||||
highlighted: boolean;
|
||||
}
|
||||
|
|
|
|||
10
public/types/src/scripts/actions/misc.d.ts
vendored
10
public/types/src/scripts/actions/misc.d.ts
vendored
|
|
@ -1,10 +0,0 @@
|
|||
import { ActionType } from '../interfaces';
|
||||
export interface ClearAllAction {
|
||||
type: ActionType.CLEAR_ALL;
|
||||
}
|
||||
export interface SetTransactionStateAction {
|
||||
type: ActionType.SET_TRANSACTION;
|
||||
txn: boolean;
|
||||
}
|
||||
export declare const clearAll: () => ClearAllAction;
|
||||
export declare const setTxn: (txn: boolean) => SetTransactionStateAction;
|
||||
8
public/types/src/scripts/choices.d.ts
vendored
8
public/types/src/scripts/choices.d.ts
vendored
|
|
@ -3,7 +3,7 @@ import { InputChoice } from './interfaces/input-choice';
|
|||
import { InputGroup } from './interfaces/input-group';
|
||||
import { Notice } from './interfaces/notice';
|
||||
import { Options } from './interfaces/options';
|
||||
import { State } from './interfaces/state';
|
||||
import { StateChangeSet } from './interfaces/state';
|
||||
import Store from './store/store';
|
||||
import { ChoiceFull } from './interfaces/choice-full';
|
||||
import { GroupFull } from './interfaces/group-full';
|
||||
|
|
@ -41,9 +41,6 @@ declare class Choices {
|
|||
_canAddUserChoices: boolean;
|
||||
_store: Store;
|
||||
_templates: Templates;
|
||||
_initialState: State;
|
||||
_currentState: State;
|
||||
_prevState: State;
|
||||
_lastAddedChoiceId: number;
|
||||
_lastAddedGroupId: number;
|
||||
_currentValue: string;
|
||||
|
|
@ -148,7 +145,7 @@ declare class Choices {
|
|||
clearStore(): this;
|
||||
clearInput(): this;
|
||||
_validateConfig(): void;
|
||||
_render(): void;
|
||||
_render(changes?: StateChangeSet): void;
|
||||
_renderChoices(): void;
|
||||
_renderItems(): void;
|
||||
_createGroupsFragment(groups: GroupFull[], choices: ChoiceFull[], fragment?: DocumentFragment): DocumentFragment;
|
||||
|
|
@ -200,6 +197,7 @@ declare class Choices {
|
|||
_createTemplates(): void;
|
||||
_createElements(): void;
|
||||
_createStructure(): void;
|
||||
_initStore(): void;
|
||||
_addPredefinedChoices(choices: (ChoiceFull | GroupFull)[], selectFirstOption?: boolean, withEvents?: boolean): void;
|
||||
_findAndSelectChoiceByValue(value: string): boolean;
|
||||
_generatePlaceholderValue(): string | null;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,5 @@ export declare const enum ActionType {
|
|||
ADD_GROUP = "ADD_GROUP",
|
||||
ADD_ITEM = "ADD_ITEM",
|
||||
REMOVE_ITEM = "REMOVE_ITEM",
|
||||
HIGHLIGHT_ITEM = "HIGHLIGHT_ITEM",
|
||||
CLEAR_ALL = "CLEAR_ALL",
|
||||
SET_TRANSACTION = "SET_TRANSACTION"
|
||||
HIGHLIGHT_ITEM = "HIGHLIGHT_ITEM"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,7 @@ export interface State {
|
|||
choices: ChoiceFull[];
|
||||
groups: GroupFull[];
|
||||
items: ChoiceFull[];
|
||||
txn: number;
|
||||
}
|
||||
export type StateChangeSet = {
|
||||
[K in keyof State]: boolean;
|
||||
};
|
||||
|
|
|
|||
17
public/types/src/scripts/interfaces/store.d.ts
vendored
17
public/types/src/scripts/interfaces/store.d.ts
vendored
|
|
@ -1,10 +1,23 @@
|
|||
import { State } from './state';
|
||||
import { StateChangeSet, State } from './state';
|
||||
import { ChoiceFull } from './choice-full';
|
||||
import { GroupFull } from './group-full';
|
||||
import { ActionType } from './action-type';
|
||||
export interface AnyAction<A extends ActionType = ActionType> {
|
||||
type: A;
|
||||
}
|
||||
export interface StateUpdate<T> {
|
||||
update: boolean;
|
||||
state: T;
|
||||
}
|
||||
export type Reducer<T> = (state: T, action: AnyAction) => StateUpdate<T>;
|
||||
export type StoreListener = (changes: StateChangeSet) => void;
|
||||
export interface Store {
|
||||
dispatch(action: AnyAction): void;
|
||||
subscribe(onChange: StoreListener): void;
|
||||
withTxn(func: () => void): void;
|
||||
get defaultState(): State;
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get state(): State;
|
||||
/**
|
||||
|
|
|
|||
12
public/types/src/scripts/reducers/choices.d.ts
vendored
12
public/types/src/scripts/reducers/choices.d.ts
vendored
|
|
@ -1,6 +1,8 @@
|
|||
import { AddChoiceAction, RemoveChoiceAction, FilterChoicesAction, ActivateChoicesAction, ClearChoicesAction } from '../actions/choices';
|
||||
import { AddItemAction, RemoveItemAction } from '../actions/items';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
type ActionTypes = AddChoiceAction | RemoveChoiceAction | FilterChoicesAction | ActivateChoicesAction | ClearChoicesAction | AddItemAction | RemoveItemAction | Record<string, never>;
|
||||
export default function choices(state?: ChoiceFull[], action?: ActionTypes): ChoiceFull[];
|
||||
import { State } from '../interfaces';
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
import { ItemActions } from '../actions/items';
|
||||
type ActionTypes = ChoiceActions | ItemActions;
|
||||
type StateType = State['choices'];
|
||||
export default function choices(s: StateType, action: ActionTypes): StateUpdate<StateType>;
|
||||
export {};
|
||||
|
|
|
|||
11
public/types/src/scripts/reducers/groups.d.ts
vendored
11
public/types/src/scripts/reducers/groups.d.ts
vendored
|
|
@ -1,7 +1,8 @@
|
|||
import { AddGroupAction } from '../actions/groups';
|
||||
import { ClearChoicesAction } from '../actions/choices';
|
||||
import { GroupActions } from '../actions/groups';
|
||||
import { State } from '../interfaces/state';
|
||||
import { GroupFull } from '../interfaces/group-full';
|
||||
type ActionTypes = AddGroupAction | ClearChoicesAction | Record<string, never>;
|
||||
export default function groups(state?: GroupFull[], action?: ActionTypes): State['groups'];
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
type ActionTypes = ChoiceActions | GroupActions;
|
||||
type StateType = State['groups'];
|
||||
export default function groups(s: StateType, action: ActionTypes): StateUpdate<StateType>;
|
||||
export {};
|
||||
|
|
|
|||
5
public/types/src/scripts/reducers/index.d.ts
vendored
5
public/types/src/scripts/reducers/index.d.ts
vendored
|
|
@ -1,5 +0,0 @@
|
|||
import { AnyAction } from 'redux';
|
||||
import { State } from '../interfaces';
|
||||
export declare const defaultState: State;
|
||||
declare const rootReducer: (passedState: State, action: AnyAction) => object;
|
||||
export default rootReducer;
|
||||
11
public/types/src/scripts/reducers/items.d.ts
vendored
11
public/types/src/scripts/reducers/items.d.ts
vendored
|
|
@ -1,7 +1,8 @@
|
|||
import { AddItemAction, RemoveItemAction, HighlightItemAction } from '../actions/items';
|
||||
import { ItemActions } from '../actions/items';
|
||||
import { State } from '../interfaces/state';
|
||||
import { RemoveChoiceAction } from '../actions/choices';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
type ActionTypes = AddItemAction | RemoveChoiceAction | RemoveItemAction | HighlightItemAction | Record<string, never>;
|
||||
export default function items(state?: ChoiceFull[], action?: ActionTypes): State['items'];
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
type ActionTypes = ChoiceActions | ItemActions;
|
||||
type StateType = State['items'];
|
||||
export default function items(s: StateType, action: ActionTypes): StateUpdate<StateType>;
|
||||
export {};
|
||||
|
|
|
|||
5
public/types/src/scripts/reducers/txn.d.ts
vendored
5
public/types/src/scripts/reducers/txn.d.ts
vendored
|
|
@ -1,5 +0,0 @@
|
|||
import { SetTransactionStateAction } from '../actions/misc';
|
||||
import { State } from '../interfaces/state';
|
||||
type ActionTypes = SetTransactionStateAction | Record<string, never>;
|
||||
declare const general: (state?: number, action?: ActionTypes) => State["txn"];
|
||||
export default general;
|
||||
24
public/types/src/scripts/store/store.d.ts
vendored
24
public/types/src/scripts/store/store.d.ts
vendored
|
|
@ -1,22 +1,20 @@
|
|||
import { Store as ReduxStore, AnyAction } from 'redux';
|
||||
import { Store as IStore } from '../interfaces/store';
|
||||
import { State } from '../interfaces/state';
|
||||
import { AnyAction, Store as IStore, StoreListener } from '../interfaces/store';
|
||||
import { StateChangeSet, State } from '../interfaces/state';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { GroupFull } from '../interfaces/group-full';
|
||||
export default class Store implements IStore {
|
||||
_store: ReduxStore;
|
||||
constructor();
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
subscribe(onChange: () => void): void;
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
_store: State;
|
||||
_listeners: StoreListener[];
|
||||
_txn: number;
|
||||
_outstandingChanges?: StateChangeSet;
|
||||
get defaultState(): State;
|
||||
changeSet(init: boolean): StateChangeSet;
|
||||
resetStore(): void;
|
||||
subscribe(onChange: StoreListener): void;
|
||||
dispatch(action: AnyAction): void;
|
||||
withTxn(func: () => void): void;
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get state(): State;
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,30 +1,36 @@
|
|||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { SearchResult } from '../interfaces/search';
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
|
||||
export interface AddChoiceAction {
|
||||
type: ActionType.ADD_CHOICE;
|
||||
export type ChoiceActions =
|
||||
| AddChoiceAction
|
||||
| RemoveChoiceAction
|
||||
| FilterChoicesAction
|
||||
| ActivateChoicesAction
|
||||
| ClearChoicesAction;
|
||||
|
||||
export interface AddChoiceAction extends AnyAction<ActionType.ADD_CHOICE> {
|
||||
choice: ChoiceFull;
|
||||
}
|
||||
|
||||
export interface RemoveChoiceAction {
|
||||
type: ActionType.REMOVE_CHOICE;
|
||||
export interface RemoveChoiceAction
|
||||
extends AnyAction<ActionType.REMOVE_CHOICE> {
|
||||
choice: ChoiceFull;
|
||||
}
|
||||
|
||||
export interface FilterChoicesAction {
|
||||
type: ActionType.FILTER_CHOICES;
|
||||
export interface FilterChoicesAction
|
||||
extends AnyAction<ActionType.FILTER_CHOICES> {
|
||||
results: SearchResult<ChoiceFull>[];
|
||||
}
|
||||
|
||||
export interface ActivateChoicesAction {
|
||||
type: ActionType.ACTIVATE_CHOICES;
|
||||
export interface ActivateChoicesAction
|
||||
extends AnyAction<ActionType.ACTIVATE_CHOICES> {
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface ClearChoicesAction {
|
||||
type: ActionType.CLEAR_CHOICES;
|
||||
}
|
||||
export interface ClearChoicesAction
|
||||
extends AnyAction<ActionType.CLEAR_CHOICES> {}
|
||||
|
||||
export const addChoice = (choice: ChoiceFull): AddChoiceAction => ({
|
||||
type: ActionType.ADD_CHOICE,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { GroupFull } from '../interfaces/group-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
|
||||
export interface AddGroupAction {
|
||||
type: ActionType.ADD_GROUP;
|
||||
export type GroupActions = AddGroupAction;
|
||||
|
||||
export interface AddGroupAction extends AnyAction<ActionType.ADD_GROUP> {
|
||||
group: GroupFull;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { AnyAction } from '../interfaces/store';
|
||||
|
||||
export interface AddItemAction {
|
||||
type: ActionType.ADD_ITEM;
|
||||
export type ItemActions =
|
||||
| AddItemAction
|
||||
| RemoveItemAction
|
||||
| HighlightItemAction;
|
||||
|
||||
export interface AddItemAction extends AnyAction<ActionType.ADD_ITEM> {
|
||||
item: ChoiceFull;
|
||||
}
|
||||
|
||||
export interface RemoveItemAction {
|
||||
type: ActionType.REMOVE_ITEM;
|
||||
export interface RemoveItemAction extends AnyAction<ActionType.REMOVE_ITEM> {
|
||||
item: ChoiceFull;
|
||||
}
|
||||
|
||||
export interface HighlightItemAction {
|
||||
type: ActionType.HIGHLIGHT_ITEM;
|
||||
export interface HighlightItemAction
|
||||
extends AnyAction<ActionType.HIGHLIGHT_ITEM> {
|
||||
item: ChoiceFull;
|
||||
highlighted: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import { ActionType } from '../interfaces';
|
||||
|
||||
export interface ClearAllAction {
|
||||
type: ActionType.CLEAR_ALL;
|
||||
}
|
||||
|
||||
export interface SetTransactionStateAction {
|
||||
type: ActionType.SET_TRANSACTION;
|
||||
txn: boolean;
|
||||
}
|
||||
|
||||
export const clearAll = (): ClearAllAction => ({
|
||||
type: ActionType.CLEAR_ALL,
|
||||
});
|
||||
|
||||
export const setTxn = (txn: boolean): SetTransactionStateAction => ({
|
||||
type: ActionType.SET_TRANSACTION,
|
||||
txn,
|
||||
});
|
||||
|
|
@ -8,7 +8,6 @@ import {
|
|||
} from './actions/choices';
|
||||
import { addGroup } from './actions/groups';
|
||||
import { addItem, highlightItem, removeItem } from './actions/items';
|
||||
import { clearAll } from './actions/misc';
|
||||
import {
|
||||
Container,
|
||||
Dropdown,
|
||||
|
|
@ -23,7 +22,7 @@ import { InputChoice } from './interfaces/input-choice';
|
|||
import { InputGroup } from './interfaces/input-group';
|
||||
import { Notice } from './interfaces/notice';
|
||||
import { Options, ObjectsInConfig } from './interfaces/options';
|
||||
import { State } from './interfaces/state';
|
||||
import { StateChangeSet } from './interfaces/state';
|
||||
import {
|
||||
diff,
|
||||
generateId,
|
||||
|
|
@ -35,7 +34,6 @@ import {
|
|||
sortByRank,
|
||||
strToEl,
|
||||
} from './lib/utils';
|
||||
import { defaultState } from './reducers';
|
||||
import Store from './store/store';
|
||||
import templates, { escapeForTemplate } from './templates';
|
||||
import { mapInputToChoice } from './lib/choice-input';
|
||||
|
|
@ -131,12 +129,6 @@ class Choices {
|
|||
|
||||
_templates: Templates;
|
||||
|
||||
_initialState: State;
|
||||
|
||||
_currentState: State;
|
||||
|
||||
_prevState: State;
|
||||
|
||||
_lastAddedChoiceId: number = 0;
|
||||
|
||||
_lastAddedGroupId: number = 0;
|
||||
|
|
@ -273,9 +265,6 @@ class Choices {
|
|||
this.initialised = false;
|
||||
|
||||
this._store = new Store();
|
||||
this._initialState = defaultState;
|
||||
this._currentState = defaultState;
|
||||
this._prevState = defaultState;
|
||||
this._currentValue = '';
|
||||
this.config.searchEnabled =
|
||||
(!this._isTextElement && this.config.searchEnabled) ||
|
||||
|
|
@ -358,10 +347,7 @@ class Choices {
|
|||
this._createTemplates();
|
||||
this._createElements();
|
||||
this._createStructure();
|
||||
|
||||
this._store.subscribe(this._render);
|
||||
|
||||
this._render();
|
||||
this._initStore();
|
||||
this._addEventListeners();
|
||||
|
||||
const shouldDisable =
|
||||
|
|
@ -393,6 +379,7 @@ class Choices {
|
|||
this.containerOuter.unwrap(this.passedElement.element);
|
||||
|
||||
this.clearStore();
|
||||
this._store._listeners = [];
|
||||
this._stopSearch();
|
||||
|
||||
this._templates = templates;
|
||||
|
|
@ -898,7 +885,7 @@ class Choices {
|
|||
}
|
||||
|
||||
clearStore(): this {
|
||||
this._store.dispatch(clearAll());
|
||||
this._store.resetStore();
|
||||
this._lastAddedChoiceId = 0;
|
||||
this._lastAddedGroupId = 0;
|
||||
// @todo integrate with Store
|
||||
|
|
@ -941,19 +928,14 @@ class Choices {
|
|||
}
|
||||
}
|
||||
|
||||
_render(): void {
|
||||
_render(changes?: StateChangeSet): void {
|
||||
if (this._store.inTxn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._currentState = this._store.state;
|
||||
|
||||
const shouldRenderItems =
|
||||
this._currentState.items !== this._prevState.items;
|
||||
const shouldRenderItems = changes?.items;
|
||||
const stateChanged =
|
||||
this._currentState.choices !== this._prevState.choices ||
|
||||
this._currentState.groups !== this._prevState.groups ||
|
||||
shouldRenderItems;
|
||||
changes?.choices || changes?.groups || shouldRenderItems;
|
||||
|
||||
if (!stateChanged) {
|
||||
return;
|
||||
|
|
@ -966,8 +948,6 @@ class Choices {
|
|||
if (shouldRenderItems) {
|
||||
this._renderItems();
|
||||
}
|
||||
|
||||
this._prevState = this._currentState;
|
||||
}
|
||||
|
||||
_renderChoices(): void {
|
||||
|
|
@ -2570,6 +2550,11 @@ class Choices {
|
|||
|
||||
this._highlightPosition = 0;
|
||||
this._isSearching = false;
|
||||
}
|
||||
|
||||
_initStore(): void {
|
||||
this._store.subscribe(this._render);
|
||||
|
||||
this._store.withTxn(() => {
|
||||
this._addPredefinedChoices(
|
||||
this._presetChoices,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,4 @@ export const enum ActionType {
|
|||
ADD_ITEM = 'ADD_ITEM',
|
||||
REMOVE_ITEM = 'REMOVE_ITEM',
|
||||
HIGHLIGHT_ITEM = 'HIGHLIGHT_ITEM',
|
||||
CLEAR_ALL = 'CLEAR_ALL',
|
||||
SET_TRANSACTION = 'SET_TRANSACTION',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,8 @@ export interface State {
|
|||
choices: ChoiceFull[];
|
||||
groups: GroupFull[];
|
||||
items: ChoiceFull[];
|
||||
txn: number;
|
||||
}
|
||||
|
||||
export type StateChangeSet = {
|
||||
[K in keyof State]: boolean;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,32 @@
|
|||
import { State } from './state';
|
||||
import { StateChangeSet, State } from './state';
|
||||
import { ChoiceFull } from './choice-full';
|
||||
import { GroupFull } from './group-full';
|
||||
import { ActionType } from './action-type';
|
||||
|
||||
export interface AnyAction<A extends ActionType = ActionType> {
|
||||
type: A;
|
||||
}
|
||||
|
||||
export interface StateUpdate<T> {
|
||||
update: boolean;
|
||||
state: T;
|
||||
}
|
||||
|
||||
export type Reducer<T> = (state: T, action: AnyAction) => StateUpdate<T>;
|
||||
|
||||
export type StoreListener = (changes: StateChangeSet) => void;
|
||||
|
||||
export interface Store {
|
||||
dispatch(action: AnyAction): void;
|
||||
|
||||
subscribe(onChange: StoreListener): void;
|
||||
|
||||
withTxn(func: () => void): void;
|
||||
|
||||
get defaultState(): State;
|
||||
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get state(): State;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,77 +1,73 @@
|
|||
import {
|
||||
AddChoiceAction,
|
||||
RemoveChoiceAction,
|
||||
FilterChoicesAction,
|
||||
ActivateChoicesAction,
|
||||
ClearChoicesAction,
|
||||
} from '../actions/choices';
|
||||
import { AddItemAction, RemoveItemAction } from '../actions/items';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { ActionType, State } from '../interfaces';
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
import { ItemActions } from '../actions/items';
|
||||
import { SearchResult } from '../interfaces/search';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
|
||||
type ActionTypes =
|
||||
| AddChoiceAction
|
||||
| RemoveChoiceAction
|
||||
| FilterChoicesAction
|
||||
| ActivateChoicesAction
|
||||
| ClearChoicesAction
|
||||
| AddItemAction
|
||||
| RemoveItemAction
|
||||
| Record<string, never>;
|
||||
type ActionTypes = ChoiceActions | ItemActions;
|
||||
type StateType = State['choices'];
|
||||
|
||||
export default function choices(
|
||||
state: ChoiceFull[] = [],
|
||||
action: ActionTypes = {},
|
||||
): ChoiceFull[] {
|
||||
s: StateType,
|
||||
action: ActionTypes,
|
||||
): StateUpdate<StateType> {
|
||||
let state = s;
|
||||
let update = false;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionType.ADD_CHOICE: {
|
||||
const { choice } = action as AddChoiceAction;
|
||||
const { choice } = action;
|
||||
|
||||
/*
|
||||
A disabled choice appears in the choice dropdown but cannot be selected
|
||||
A selected choice has been added to the passed input's value (added as an item)
|
||||
An active choice appears within the choice dropdown
|
||||
*/
|
||||
return [...state, choice];
|
||||
state.push(choice);
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.REMOVE_CHOICE: {
|
||||
const { choice } = action as RemoveChoiceAction;
|
||||
const { choice } = action;
|
||||
|
||||
return state.filter((obj) => obj.id !== choice.id);
|
||||
update = true;
|
||||
state = state.filter((obj) => obj.id !== choice.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.ADD_ITEM: {
|
||||
const { item } = action as AddItemAction;
|
||||
const { item } = action;
|
||||
// trigger a rebuild of the choices list as the item can not be added multiple times
|
||||
if (item.id && item.selected) {
|
||||
return [...state];
|
||||
update = true;
|
||||
}
|
||||
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.REMOVE_ITEM: {
|
||||
const { item } = action as RemoveItemAction;
|
||||
const { item } = action;
|
||||
// trigger a rebuild of the choices list as the item can be added
|
||||
if (item.id && !item.selected) {
|
||||
return [...state];
|
||||
update = true;
|
||||
}
|
||||
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.FILTER_CHOICES: {
|
||||
const { results } = action as FilterChoicesAction;
|
||||
const { results } = action;
|
||||
|
||||
update = true;
|
||||
// avoid O(n^2) algorithm complexity when searching/filtering choices
|
||||
const scoreLookup: SearchResult<ChoiceFull>[] = [];
|
||||
results.forEach((result) => {
|
||||
scoreLookup[result.item.id] = result;
|
||||
});
|
||||
|
||||
return state.map((obj) => {
|
||||
state.forEach((obj) => {
|
||||
const choice = obj;
|
||||
const result = scoreLookup[choice.id];
|
||||
if (result !== undefined) {
|
||||
|
|
@ -83,28 +79,33 @@ export default function choices(
|
|||
choice.rank = 0;
|
||||
choice.active = false;
|
||||
}
|
||||
|
||||
return choice;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.ACTIVATE_CHOICES: {
|
||||
const { active } = action as ActivateChoicesAction;
|
||||
const { active } = action;
|
||||
|
||||
return state.map((obj) => {
|
||||
update = true;
|
||||
state.forEach((obj) => {
|
||||
const choice = obj;
|
||||
choice.active = active;
|
||||
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.CLEAR_CHOICES: {
|
||||
return [];
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return { state, update };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,37 @@
|
|||
import { AddGroupAction } from '../actions/groups';
|
||||
import { ClearChoicesAction } from '../actions/choices';
|
||||
import { GroupActions } from '../actions/groups';
|
||||
import { State } from '../interfaces/state';
|
||||
import { GroupFull } from '../interfaces/group-full';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
|
||||
type ActionTypes = AddGroupAction | ClearChoicesAction | Record<string, never>;
|
||||
type ActionTypes = ChoiceActions | GroupActions;
|
||||
type StateType = State['groups'];
|
||||
|
||||
export default function groups(
|
||||
state: GroupFull[] = [],
|
||||
action: ActionTypes = {},
|
||||
): State['groups'] {
|
||||
s: StateType,
|
||||
action: ActionTypes,
|
||||
): StateUpdate<StateType> {
|
||||
let state = s;
|
||||
let update = false;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionType.ADD_GROUP: {
|
||||
const addGroupAction = action as AddGroupAction;
|
||||
const addGroupAction = action;
|
||||
|
||||
return [...state, addGroupAction.group];
|
||||
update = true;
|
||||
state.push(addGroupAction.group);
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.CLEAR_CHOICES: {
|
||||
return [];
|
||||
update = true;
|
||||
state = [];
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return { state, update };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
import { AnyAction, combineReducers } from 'redux';
|
||||
import items from './items';
|
||||
import groups from './groups';
|
||||
import choices from './choices';
|
||||
import txn from './txn';
|
||||
import { cloneObject } from '../lib/utils';
|
||||
import { ActionType, State } from '../interfaces';
|
||||
|
||||
export const defaultState: State = {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
};
|
||||
|
||||
const appReducer = combineReducers({
|
||||
items,
|
||||
groups,
|
||||
choices,
|
||||
txn,
|
||||
});
|
||||
|
||||
const rootReducer = (passedState: State, action: AnyAction): object => {
|
||||
let state = passedState;
|
||||
// If we are clearing all items, groups and options we reassign
|
||||
// state and then pass that state to our proper reducer. This isn't
|
||||
// mutating our actual state
|
||||
// See: http://stackoverflow.com/a/35641992
|
||||
if (action.type === ActionType.CLEAR_ALL) {
|
||||
// preserve the txn state as to allow withTxn to work
|
||||
const paused = state.txn;
|
||||
state = cloneObject(defaultState);
|
||||
state.txn = paused;
|
||||
}
|
||||
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
export default rootReducer;
|
||||
|
|
@ -1,83 +1,82 @@
|
|||
import {
|
||||
AddItemAction,
|
||||
RemoveItemAction,
|
||||
HighlightItemAction,
|
||||
} from '../actions/items';
|
||||
import { ItemActions } from '../actions/items';
|
||||
import { State } from '../interfaces/state';
|
||||
import { RemoveChoiceAction } from '../actions/choices';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { ChoiceActions } from '../actions/choices';
|
||||
import { ActionType } from '../interfaces';
|
||||
import { StateUpdate } from '../interfaces/store';
|
||||
|
||||
type ActionTypes =
|
||||
| AddItemAction
|
||||
| RemoveChoiceAction
|
||||
| RemoveItemAction
|
||||
| HighlightItemAction
|
||||
| Record<string, never>;
|
||||
type ActionTypes = ChoiceActions | ItemActions;
|
||||
type StateType = State['items'];
|
||||
|
||||
export default function items(
|
||||
state: ChoiceFull[] = [],
|
||||
action: ActionTypes = {},
|
||||
): State['items'] {
|
||||
s: StateType,
|
||||
action: ActionTypes,
|
||||
): StateUpdate<StateType> {
|
||||
let state = s;
|
||||
let update = false;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionType.ADD_ITEM: {
|
||||
const { item } = action as AddItemAction;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
const { item } = action;
|
||||
if (item.id) {
|
||||
item.selected = true;
|
||||
const el = item.element as HTMLOptionElement | undefined;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
|
||||
update = true;
|
||||
state.push(item);
|
||||
state.forEach((obj) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
obj.highlighted = false;
|
||||
});
|
||||
}
|
||||
|
||||
item.selected = true;
|
||||
const el = item.element as HTMLOptionElement;
|
||||
if (el) {
|
||||
el.selected = true;
|
||||
el.setAttribute('selected', '');
|
||||
}
|
||||
|
||||
return [...state, item].map((obj) => {
|
||||
const choice = obj;
|
||||
choice.highlighted = false;
|
||||
|
||||
return choice;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.REMOVE_ITEM: {
|
||||
const { item } = action as RemoveItemAction;
|
||||
if (!item.id) {
|
||||
return state;
|
||||
}
|
||||
const { item } = action;
|
||||
if (item.id) {
|
||||
item.selected = false;
|
||||
const el = item.element as HTMLOptionElement | undefined;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
|
||||
item.selected = false;
|
||||
const el = item.element as HTMLOptionElement;
|
||||
if (el) {
|
||||
el.selected = false;
|
||||
el.removeAttribute('selected');
|
||||
update = true;
|
||||
state = state.filter((choice) => choice.id !== item.id);
|
||||
}
|
||||
|
||||
return state.filter((choice) => choice.id !== item.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.REMOVE_CHOICE: {
|
||||
const { choice } = action as RemoveChoiceAction;
|
||||
const { choice } = action;
|
||||
|
||||
return state.filter((item) => item.id !== choice.id);
|
||||
update = true;
|
||||
state = state.filter((item) => item.id !== choice.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionType.HIGHLIGHT_ITEM: {
|
||||
const highlightItemAction = action as HighlightItemAction;
|
||||
const highlightItemAction = action;
|
||||
|
||||
return state.map((obj) => {
|
||||
update = true;
|
||||
state.forEach((obj) => {
|
||||
const item = obj;
|
||||
if (item.id === highlightItemAction.item.id) {
|
||||
item.highlighted = highlightItemAction.highlighted;
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return { state, update };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
import { SetTransactionStateAction } from '../actions/misc';
|
||||
import { State } from '../interfaces/state';
|
||||
import { ActionType } from '../interfaces';
|
||||
|
||||
type ActionTypes = SetTransactionStateAction | Record<string, never>;
|
||||
|
||||
const general = (state: number = 0, action: ActionTypes = {}): State['txn'] => {
|
||||
switch (action.type) {
|
||||
case ActionType.SET_TRANSACTION: {
|
||||
if (action.txn) {
|
||||
return state + 1;
|
||||
}
|
||||
|
||||
return Math.max(0, state - 1);
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
@ -1,51 +1,109 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { createStore, Store as ReduxStore, AnyAction } from 'redux';
|
||||
import { Store as IStore } from '../interfaces/store';
|
||||
import { State } from '../interfaces/state';
|
||||
import rootReducer from '../reducers/index';
|
||||
import { setTxn } from '../actions/misc';
|
||||
import {
|
||||
AnyAction,
|
||||
Reducer,
|
||||
Store as IStore,
|
||||
StoreListener,
|
||||
} from '../interfaces/store';
|
||||
import { StateChangeSet, State } from '../interfaces/state';
|
||||
import { ChoiceFull } from '../interfaces/choice-full';
|
||||
import { GroupFull } from '../interfaces/group-full';
|
||||
import items from '../reducers/items';
|
||||
import groups from '../reducers/groups';
|
||||
import choices from '../reducers/choices';
|
||||
|
||||
type ReducerList = { [K in keyof State]: Reducer<State[K]> };
|
||||
|
||||
const reducers: ReducerList = {
|
||||
groups,
|
||||
items,
|
||||
choices,
|
||||
} as const;
|
||||
|
||||
export default class Store implements IStore {
|
||||
_store: ReduxStore;
|
||||
_store: State = this.defaultState;
|
||||
|
||||
constructor() {
|
||||
this._store = createStore(
|
||||
rootReducer,
|
||||
(window as any).__REDUX_DEVTOOLS_EXTENSION__ &&
|
||||
(window as any).__REDUX_DEVTOOLS_EXTENSION__(),
|
||||
);
|
||||
_listeners: StoreListener[] = [];
|
||||
|
||||
_txn: number = 0;
|
||||
|
||||
_outstandingChanges?: StateChangeSet;
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
get defaultState(): State {
|
||||
return {
|
||||
groups: [],
|
||||
items: [],
|
||||
choices: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe store to function call (wrapped Redux method)
|
||||
*/
|
||||
subscribe(onChange: () => void): void {
|
||||
this._store.subscribe(onChange);
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
changeSet(init: boolean): StateChangeSet {
|
||||
return {
|
||||
groups: init,
|
||||
items: init,
|
||||
choices: init,
|
||||
};
|
||||
}
|
||||
|
||||
resetStore(): void {
|
||||
this._store = this.defaultState;
|
||||
const changes = this.changeSet(true);
|
||||
this._listeners.forEach((l) => l(changes));
|
||||
}
|
||||
|
||||
subscribe(onChange: StoreListener): void {
|
||||
this._listeners.push(onChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch event to store (wrapped Redux method)
|
||||
*/
|
||||
dispatch(action: AnyAction): void {
|
||||
this._store.dispatch(action);
|
||||
const state = this._store;
|
||||
let hasChanges = false;
|
||||
const changes = this._outstandingChanges || this.changeSet(false);
|
||||
|
||||
Object.keys(reducers).forEach((key: string) => {
|
||||
const stateUpdate = (reducers[key] as Reducer<unknown>)(
|
||||
state[key],
|
||||
action,
|
||||
);
|
||||
if (stateUpdate.update) {
|
||||
hasChanges = true;
|
||||
changes[key] = true;
|
||||
state[key] = stateUpdate.state;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasChanges) {
|
||||
if (this._txn) {
|
||||
this._outstandingChanges = changes;
|
||||
} else {
|
||||
this._listeners.forEach((l) => l(changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withTxn(func: () => void): void {
|
||||
this._store.dispatch(setTxn(true));
|
||||
this._txn++;
|
||||
try {
|
||||
func();
|
||||
} finally {
|
||||
this._store.dispatch(setTxn(false));
|
||||
this._txn = Math.max(0, this._txn - 1);
|
||||
|
||||
if (!this._txn) {
|
||||
const changeSet = this._outstandingChanges;
|
||||
if (changeSet) {
|
||||
this._outstandingChanges = undefined;
|
||||
this._listeners.forEach((l) => l(changeSet));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get store object (wrapping Redux method)
|
||||
* Get store object
|
||||
*/
|
||||
get state(): State {
|
||||
return this._store.getState();
|
||||
return this._store;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -98,11 +156,9 @@ export default class Store implements IStore {
|
|||
* Get active groups from store
|
||||
*/
|
||||
get activeGroups(): GroupFull[] {
|
||||
const { groups, choices } = this;
|
||||
|
||||
return groups.filter((group) => {
|
||||
return this.state.groups.filter((group) => {
|
||||
const isActive = group.active && !group.disabled;
|
||||
const hasActiveOptions = choices.some(
|
||||
const hasActiveOptions = this.state.choices.some(
|
||||
(choice) => choice.active && !choice.disabled,
|
||||
);
|
||||
|
||||
|
|
@ -111,7 +167,7 @@ export default class Store implements IStore {
|
|||
}
|
||||
|
||||
inTxn(): boolean {
|
||||
return this.state.txn > 0;
|
||||
return this._txn > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
import { expect } from 'chai';
|
||||
import * as actions from '../../../src/scripts/actions/misc';
|
||||
import { ActionType } from '../../../src';
|
||||
|
||||
describe('actions/misc', () => {
|
||||
describe('clearAll action', () => {
|
||||
it('returns CLEAR_ALL action', () => {
|
||||
const expectedAction: actions.ClearAllAction = {
|
||||
type: ActionType.CLEAR_ALL,
|
||||
};
|
||||
|
||||
expect(actions.clearAll()).to.deep.equal(expectedAction);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTxn action', () => {
|
||||
describe('setting paused state to true', () => {
|
||||
it('returns expected action', () => {
|
||||
const expectedAction: actions.SetTransactionStateAction = {
|
||||
type: ActionType.SET_TRANSACTION,
|
||||
txn: true,
|
||||
};
|
||||
|
||||
expect(actions.setTxn(true)).to.deep.equal(expectedAction);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setting paused state to false', () => {
|
||||
it('returns expected action', () => {
|
||||
const expectedAction: actions.SetTransactionStateAction = {
|
||||
type: ActionType.SET_TRANSACTION,
|
||||
txn: false,
|
||||
};
|
||||
|
||||
expect(actions.setTxn(false)).to.deep.equal(expectedAction);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -352,8 +352,8 @@ describe('choices', () => {
|
|||
expect(storeSubscribeSpy.lastCall.args[0]).to.equal(instance._render);
|
||||
});
|
||||
|
||||
it('fires initial render', () => {
|
||||
expect(renderSpy.called).to.equal(true);
|
||||
it('does not fire initial render with no items or choices', () => {
|
||||
expect(renderSpy.called).to.equal(false);
|
||||
});
|
||||
|
||||
it('adds event listeners', () => {
|
||||
|
|
@ -633,9 +633,8 @@ describe('choices', () => {
|
|||
expect(
|
||||
passedElementTriggerEventStub.lastCall.args[0],
|
||||
).to.deep.equal(EventType.showDropdown);
|
||||
expect(
|
||||
passedElementTriggerEventStub.lastCall.args[1],
|
||||
).to.undefined;
|
||||
expect(passedElementTriggerEventStub.lastCall.args[1]).to
|
||||
.undefined;
|
||||
done(true);
|
||||
});
|
||||
}));
|
||||
|
|
@ -737,9 +736,8 @@ describe('choices', () => {
|
|||
expect(
|
||||
passedElementTriggerEventStub.lastCall.args[0],
|
||||
).to.deep.equal(EventType.hideDropdown);
|
||||
expect(
|
||||
passedElementTriggerEventStub.lastCall.args[1],
|
||||
).to.undefined;
|
||||
expect(passedElementTriggerEventStub.lastCall.args[1]).to
|
||||
.undefined;
|
||||
done(true);
|
||||
});
|
||||
}));
|
||||
|
|
@ -1137,31 +1135,6 @@ describe('choices', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('clearStore', () => {
|
||||
let storeDispatchStub;
|
||||
|
||||
beforeEach(() => {
|
||||
storeDispatchStub = stub();
|
||||
instance._store.dispatch = storeDispatchStub;
|
||||
|
||||
output = instance.clearStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
instance._store.dispatch.reset();
|
||||
});
|
||||
|
||||
it('returns this', () => {
|
||||
expect(output).to.deep.equal(instance);
|
||||
});
|
||||
|
||||
it('dispatches clearAll action', () => {
|
||||
expect(storeDispatchStub.lastCall.args[0]).to.deep.equal({
|
||||
type: ActionType.CLEAR_ALL,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearInput', () => {
|
||||
let inputClearSpy;
|
||||
let storeDispatchStub;
|
||||
|
|
|
|||
|
|
@ -3,15 +3,9 @@ import choices from '../../../src/scripts/reducers/choices';
|
|||
import { cloneObject } from '../../../src/scripts/lib/utils';
|
||||
import { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';
|
||||
import { ActionType } from '../../../src';
|
||||
import { defaultState } from '../../../src/scripts/reducers';
|
||||
import { StateUpdate } from '../../../src/scripts/interfaces/store';
|
||||
|
||||
describe('reducers/choices', () => {
|
||||
it('should return same state when no action matches', () => {
|
||||
expect(choices(defaultState.choices, {} as any)).to.equal(
|
||||
defaultState.choices,
|
||||
);
|
||||
});
|
||||
|
||||
describe('when choices do not exist', () => {
|
||||
describe('ADD_CHOICE', () => {
|
||||
const choice: ChoiceFull = {
|
||||
|
|
@ -34,9 +28,12 @@ describe('reducers/choices', () => {
|
|||
|
||||
describe('passing expected values', () => {
|
||||
it('adds choice', () => {
|
||||
const expectedResponse = [choice];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [choice],
|
||||
};
|
||||
|
||||
const actualResponse = choices(undefined, {
|
||||
const actualResponse = choices([], {
|
||||
type: ActionType.ADD_CHOICE,
|
||||
choice: cloneObject(choice),
|
||||
});
|
||||
|
|
@ -51,9 +48,12 @@ describe('reducers/choices', () => {
|
|||
const item = Object.assign(cloneObject(choice), {
|
||||
placeholder: false,
|
||||
});
|
||||
const expectedResponse = [item];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [item],
|
||||
};
|
||||
|
||||
const actualResponse = choices(undefined, {
|
||||
const actualResponse = choices([], {
|
||||
type: ActionType.ADD_CHOICE,
|
||||
choice: cloneObject(item),
|
||||
});
|
||||
|
|
@ -126,7 +126,7 @@ describe('reducers/choices', () => {
|
|||
rank,
|
||||
},
|
||||
],
|
||||
}).find((choice) => choice.id === id);
|
||||
}).state.find((choice) => choice.id === id);
|
||||
|
||||
expect(actualResponse).to.deep.equal(expectedResponse);
|
||||
});
|
||||
|
|
@ -134,16 +134,19 @@ describe('reducers/choices', () => {
|
|||
|
||||
describe('ACTIVATE_CHOICES', () => {
|
||||
it('sets active flag to passed value', () => {
|
||||
const expectedResponse = [
|
||||
{
|
||||
...state[0],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
active: true,
|
||||
},
|
||||
] as ChoiceFull[];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [
|
||||
{
|
||||
...state[0],
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
active: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const actualResponse = choices(cloneObject(state), {
|
||||
type: ActionType.ACTIVATE_CHOICES,
|
||||
|
|
@ -154,43 +157,21 @@ describe('reducers/choices', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('REMOVE_CHOICE', () => {
|
||||
it('the choice is removed', () => {
|
||||
const choice = state[0];
|
||||
const expectedResponse = state.filter((s) => s.id !== choice.id);
|
||||
|
||||
const actualResponse = choices(cloneObject(state), {
|
||||
type: ActionType.REMOVE_CHOICE,
|
||||
choice: cloneObject(choice),
|
||||
});
|
||||
|
||||
expect(actualResponse).to.deep.equal(expectedResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CLEAR_CHOICES', () => {
|
||||
it('restores to defaultState', () => {
|
||||
const expectedResponse = defaultState.choices;
|
||||
const actualResponse = choices(cloneObject(state), {
|
||||
type: ActionType.CLEAR_CHOICES,
|
||||
});
|
||||
|
||||
expect(actualResponse).to.deep.equal(expectedResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ADD_ITEM', () => {
|
||||
describe('when action has a choice id', () => {
|
||||
it('disables choice corresponding with id', () => {
|
||||
const expectedResponse = [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
selected: true,
|
||||
},
|
||||
] as ChoiceFull[];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const actualResponse = choices(cloneObject(state), {
|
||||
type: ActionType.ADD_ITEM,
|
||||
|
|
|
|||
|
|
@ -3,15 +3,9 @@ import groups from '../../../src/scripts/reducers/groups';
|
|||
import { cloneObject } from '../../../src/scripts/lib/utils';
|
||||
import { GroupFull } from '../../../src/scripts/interfaces/group-full';
|
||||
import { ActionType } from '../../../src';
|
||||
import { defaultState } from '../../../src/scripts/reducers';
|
||||
import { StateUpdate } from '../../../src/scripts/interfaces/store';
|
||||
|
||||
describe('reducers/groups', () => {
|
||||
it('should return same state when no action matches', () => {
|
||||
expect(groups(defaultState.groups, {} as any)).to.equal(
|
||||
defaultState.groups,
|
||||
);
|
||||
});
|
||||
|
||||
describe('when groups do not exist', () => {
|
||||
describe('ADD_GROUP', () => {
|
||||
it('adds group', () => {
|
||||
|
|
@ -23,9 +17,12 @@ describe('reducers/groups', () => {
|
|||
choices: [],
|
||||
};
|
||||
|
||||
const expectedResponse = [group];
|
||||
const expectedResponse: StateUpdate<GroupFull[]> = {
|
||||
update: true,
|
||||
state: [group],
|
||||
};
|
||||
|
||||
const actualResponse = groups(undefined, {
|
||||
const actualResponse = groups([], {
|
||||
type: ActionType.ADD_GROUP,
|
||||
group: cloneObject(group),
|
||||
});
|
||||
|
|
@ -34,38 +31,4 @@ describe('reducers/groups', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when groups exist', () => {
|
||||
let state: GroupFull[];
|
||||
|
||||
beforeEach(() => {
|
||||
state = [
|
||||
{
|
||||
id: 1,
|
||||
label: 'Group one',
|
||||
active: true,
|
||||
disabled: false,
|
||||
choices: [],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Group two',
|
||||
active: true,
|
||||
disabled: false,
|
||||
choices: [],
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
describe('CLEAR_CHOICES', () => {
|
||||
it('restores to defaultState', () => {
|
||||
const expectedResponse = defaultState.groups;
|
||||
const actualResponse = groups(cloneObject(state), {
|
||||
type: ActionType.CLEAR_CHOICES,
|
||||
});
|
||||
|
||||
expect(actualResponse).to.deep.equal(expectedResponse);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
import { createStore } from 'redux';
|
||||
import { expect } from 'chai';
|
||||
import rootReducer from '../../../src/scripts/reducers';
|
||||
import groups from '../../../src/scripts/reducers/groups';
|
||||
import choices from '../../../src/scripts/reducers/choices';
|
||||
import items from '../../../src/scripts/reducers/items';
|
||||
import txn from '../../../src/scripts/reducers/txn';
|
||||
import { ActionType } from '../../../src';
|
||||
|
||||
describe('reducers/rootReducer', () => {
|
||||
const store = createStore(rootReducer);
|
||||
|
||||
it('returns expected reducers', () => {
|
||||
const state = store.getState();
|
||||
|
||||
expect(state.groups).to.deep.equal(groups(undefined, {} as any));
|
||||
expect(state.choices).to.deep.equal(choices(undefined, {} as any));
|
||||
expect(state.items).to.deep.equal(items(undefined, {} as any));
|
||||
expect(state.txn).to.deep.equal(txn(undefined, {} as any));
|
||||
});
|
||||
|
||||
describe('CLEAR_ALL', () => {
|
||||
it('resets state', () => {
|
||||
const output = rootReducer(
|
||||
{
|
||||
items: [1, 2, 3],
|
||||
groups: [1, 2, 3],
|
||||
choices: [1, 2, 3],
|
||||
},
|
||||
{
|
||||
type: ActionType.CLEAR_ALL,
|
||||
},
|
||||
);
|
||||
|
||||
expect(output).to.deep.equal({
|
||||
items: [],
|
||||
groups: [],
|
||||
choices: [],
|
||||
txn: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -4,15 +4,9 @@ import { RemoveItemAction } from '../../../src/scripts/actions/items';
|
|||
import { cloneObject } from '../../../src/scripts/lib/utils';
|
||||
import { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';
|
||||
import { ActionType } from '../../../src';
|
||||
import { defaultState } from '../../../src/scripts/reducers';
|
||||
import { StateUpdate } from '../../../src/scripts/interfaces/store';
|
||||
|
||||
describe('reducers/items', () => {
|
||||
it('should return same state when no action matches', () => {
|
||||
expect(items(defaultState.items, {} as any)).to.deep.equal(
|
||||
defaultState.items,
|
||||
);
|
||||
});
|
||||
|
||||
describe('when items do not exist', () => {
|
||||
describe('ADD_ITEM', () => {
|
||||
const choice: ChoiceFull = {
|
||||
|
|
@ -36,10 +30,10 @@ describe('reducers/items', () => {
|
|||
let actualResponse: ChoiceFull[];
|
||||
|
||||
beforeEach(() => {
|
||||
actualResponse = items(undefined, {
|
||||
actualResponse = items([], {
|
||||
type: ActionType.ADD_ITEM,
|
||||
item: cloneObject(choice),
|
||||
});
|
||||
}).state;
|
||||
});
|
||||
|
||||
it('adds item', () => {
|
||||
|
|
@ -61,9 +55,12 @@ describe('reducers/items', () => {
|
|||
placeholder: false,
|
||||
});
|
||||
it('adds item with placeholder set to false', () => {
|
||||
const expectedResponse = [item];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [item],
|
||||
};
|
||||
|
||||
const actualResponse = items(undefined, {
|
||||
const actualResponse = items([], {
|
||||
type: ActionType.ADD_ITEM,
|
||||
item: cloneObject(item),
|
||||
});
|
||||
|
|
@ -113,11 +110,14 @@ describe('reducers/items', () => {
|
|||
|
||||
describe('REMOVE_ITEM', () => {
|
||||
it('sets an item to be inactive based on passed ID', () => {
|
||||
const expectedResponse = [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
] as ChoiceFull[];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const actualResponse = items(cloneObject(state), {
|
||||
type: ActionType.REMOVE_ITEM,
|
||||
|
|
@ -131,7 +131,10 @@ describe('reducers/items', () => {
|
|||
describe('REMOVE_CHOICE', () => {
|
||||
it('the item is removed', () => {
|
||||
const choice = state[0];
|
||||
const expectedResponse = state.filter((s) => s.id !== choice.id);
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: state.filter((s) => s.id !== choice.id),
|
||||
};
|
||||
|
||||
const actualResponse = items(cloneObject(state), {
|
||||
type: ActionType.REMOVE_CHOICE,
|
||||
|
|
@ -144,15 +147,18 @@ describe('reducers/items', () => {
|
|||
|
||||
describe('HIGHLIGHT_ITEM', () => {
|
||||
it('sets an item to be inactive based on passed ID', () => {
|
||||
const expectedResponse = [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
highlighted: true,
|
||||
},
|
||||
] as ChoiceFull[];
|
||||
const expectedResponse: StateUpdate<ChoiceFull[]> = {
|
||||
update: true,
|
||||
state: [
|
||||
{
|
||||
...state[0],
|
||||
},
|
||||
{
|
||||
...state[1],
|
||||
highlighted: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const actualResponse = items(cloneObject(state), {
|
||||
type: ActionType.HIGHLIGHT_ITEM,
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
import { expect } from 'chai';
|
||||
import general from '../../../src/scripts/reducers/txn';
|
||||
import { ActionType, State } from '../../../src';
|
||||
import { defaultState } from '../../../src/scripts/reducers';
|
||||
|
||||
describe('reducers/txn', () => {
|
||||
it('should return same state when no action matches', () => {
|
||||
expect(general(defaultState.txn, {} as any)).to.equal(defaultState.txn);
|
||||
});
|
||||
|
||||
describe('SET_TRANSACTION', () => {
|
||||
it('sets transaction state', () => {
|
||||
const expectedState: State['txn'] = 1;
|
||||
|
||||
const actualState = general(undefined, {
|
||||
type: ActionType.SET_TRANSACTION,
|
||||
txn: true,
|
||||
});
|
||||
|
||||
expect(expectedState).to.deep.equal(actualState);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,21 +1,24 @@
|
|||
import { expect } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
import { AnyAction, Unsubscribe } from 'redux';
|
||||
import Store from '../../../src/scripts/store/store';
|
||||
import { State } from '../../../src';
|
||||
import { ActionType, State } from '../../../src';
|
||||
import { cloneObject } from '../../../src/scripts/lib/utils';
|
||||
import {
|
||||
AnyAction,
|
||||
StoreListener,
|
||||
} from '../../../src/scripts/interfaces/store';
|
||||
|
||||
describe('reducers/store', () => {
|
||||
let instance: Store;
|
||||
let subscribeStub: sinon.SinonStub<[listener: () => void], Unsubscribe>;
|
||||
let dispatchStub: sinon.SinonStub<[action: AnyAction], AnyAction>;
|
||||
let getStateStub: sinon.SinonStub<[], State>;
|
||||
let subscribeStub: sinon.SinonStub<[listener: StoreListener], void>;
|
||||
let dispatchStub: sinon.SinonStub<[action: AnyAction], void>;
|
||||
let getStateStub: sinon.SinonStub<any[], State>;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new Store();
|
||||
subscribeStub = sinon.stub(instance._store, 'subscribe');
|
||||
dispatchStub = sinon.stub(instance._store, 'dispatch');
|
||||
getStateStub = sinon.stub(instance._store, 'getState');
|
||||
subscribeStub = sinon.stub(instance, 'subscribe');
|
||||
dispatchStub = sinon.stub(instance, 'dispatch');
|
||||
getStateStub = sinon.stub(instance, 'state');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -25,17 +28,13 @@ describe('reducers/store', () => {
|
|||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('creates redux store', () => {
|
||||
expect(instance._store).to.contain.keys([
|
||||
'subscribe',
|
||||
'dispatch',
|
||||
'getState',
|
||||
]);
|
||||
it('creates redux-like store', () => {
|
||||
expect(instance).to.contain.keys(['_store', '_listeners', '_txn']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('subscribe', () => {
|
||||
it('wraps redux subscribe method', () => {
|
||||
it('wraps redux-like subscribe method', () => {
|
||||
const onChange = (): void => {};
|
||||
expect(subscribeStub.callCount).to.equal(0);
|
||||
instance.subscribe(onChange);
|
||||
|
|
@ -45,8 +44,8 @@ describe('reducers/store', () => {
|
|||
});
|
||||
|
||||
describe('dispatch', () => {
|
||||
it('wraps redux dispatch method', () => {
|
||||
const action = { type: 'TEST_ACTION' };
|
||||
it('wraps redux-like dispatch method', () => {
|
||||
const action: AnyAction = { type: ActionType.CLEAR_CHOICES };
|
||||
expect(dispatchStub.callCount).to.equal(0);
|
||||
instance.dispatch(action);
|
||||
expect(dispatchStub.callCount).to.equal(1);
|
||||
|
|
@ -56,8 +55,8 @@ describe('reducers/store', () => {
|
|||
|
||||
describe('state getter', () => {
|
||||
it('returns state', () => {
|
||||
const state: State = { items: [], choices: [], groups: [], txn: 0 };
|
||||
getStateStub.returns(cloneObject(state));
|
||||
const state: State = { items: [], choices: [], groups: [] };
|
||||
getStateStub.value(cloneObject(state));
|
||||
|
||||
expect(instance.state).to.deep.equal(state);
|
||||
});
|
||||
|
|
@ -68,7 +67,6 @@ describe('reducers/store', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
state = {
|
||||
txn: 0,
|
||||
items: [
|
||||
{
|
||||
id: 1,
|
||||
|
|
@ -163,7 +161,7 @@ describe('reducers/store', () => {
|
|||
],
|
||||
};
|
||||
|
||||
getStateStub.returns(state);
|
||||
getStateStub.value(state);
|
||||
});
|
||||
|
||||
describe('items getter', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue