UNPKG

wj-elements

Version:

WebJET Elements is a modern set of user interface tools harnessing the power of web components designed to simplify web application development.

401 lines (400 loc) 14.6 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); const addAction = (stateValueName) => { return (payload2) => { return { type: `${stateValueName}/ADD`, payload: structuredClone(payload2), actionType: "ADD" }; }; }; const addManyAction = (stateValueName) => { return (payload2) => { return { type: `${stateValueName}/ADD_MANY`, payload: structuredClone(payload2), actionType: "ADD_MANY" }; }; }; const updateAction = (stateValueName) => { return (payload2) => { return { type: `${stateValueName}/UPDATE`, payload: structuredClone(payload2), actionType: "UPDATE" }; }; }; const deleteAction = (stateValueName) => { return (payload2) => { return { type: `${stateValueName}/DELETE`, payload: structuredClone(payload2), actionType: "DELETE" }; }; }; const loadAction = (stateValueName) => { return (payload2) => { return { type: `${stateValueName}/LOAD`, payload: structuredClone(payload2), actionType: "LOAD" }; }; }; const defaultStoreActions = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, addAction, addManyAction, deleteAction, loadAction, updateAction }, Symbol.toStringTag, { value: "Module" })); class PubSub { constructor() { this.events = {}; } /** * Either create a new event instance for passed `event` name. * or push a new callback into the existing collection. * @param {string} event The event name to subscribe to * @param {Function} callback The callback function to subscribe to the event * @returns {number} A count of callbacks for this event * @memberof PubSub */ subscribe(event, callback) { let self = this; if (!self.events.hasOwnProperty(event)) { self.events[event] = []; } self.events[event].push(callback) - 1; return { unsubscribe() { self.events[event].splice(self.events[event].indexOf(callback), 1); } }; } /** * If the passed event has callbacks attached to it, loop through each one and call it. * @param {string} event The name of the event to publish * @param {any} state The current state to pass to the callbacks * @param {object} [newData] The new data to pass to the callbacks * @param {object} [oldData] The old data to pass to the callbacks * @returns {Array} The results of the callbacks for this event, or an empty array if no event exists * @memberof PubSub */ publish(event, state, newData = {}, oldData = {}) { let self = this; if (!self.events.hasOwnProperty(event)) { return []; } return self.events[event].map((callback) => callback(state, oldData, newData)); } } class Store { /** * Initializes the store with optional reducer and state. * @param {object} [params] Configuration for the store. * @param {Function} [params.reducer] Initial reducer function for handling state updates. * @param {object} [params.state] Initial state of the store. */ constructor(params = {}) { __publicField(this, "_state"); __publicField(this, "_reducer"); __publicField(this, "events"); __publicField(this, "status"); this._isPause = false; this._state = {}; this._reducer = () => { return {}; }; this.status = "resting"; this.events = new PubSub(); if (params == null ? void 0 : params.hasOwnProperty("reducer")) { this._reducer = params.reducer; } this.refreshProxy(params == null ? void 0 : params.state); } /** * Dispatches an action to update the state by invoking the reducer function. * @param {object} action The action object containing the type and any associated payload. * @param {string} action.type The type of the action being dispatched. * @returns {boolean} Returns `true` after the state has been successfully updated. * @example * const action = { type: 'INCREMENT', payload: { amount: 1 } }; * store.dispatch(action); */ dispatch(action) { this.status = "action"; let newState = this._reducer(this._state, action); this.status = "mutation"; this._state = Object.assign(this._state, newState); return true; } /** * Retrieves a deep copy of the current state to ensure immutability. * @returns {object} A deep copy of the current state. * @example * const currentState = store.getState(); * console.log(currentState); */ getState() { return JSON.parse(JSON.stringify(this._state)); } /** * Subscribes to a specific event with a provided callback function. * @param {string} eventName The name of the event to subscribe to. * @param {Function} callbackFn The function to execute when the event is triggered. * @returns {Function} - A function to unsubscribe from the event. * @example * const unsubscribe = store.subscribe('stateChange', (newState) => { * console.log('State changed:', newState); * }); * // Later, to unsubscribe * unsubscribe(); */ subscribe(eventName, callbackFn) { return this.events.subscribe(eventName, callbackFn); } /** * Unsubscribes from a specific event by removing all associated listeners. * @param {string} eventName The name of the event to unsubscribe from. * @returns {void} * @example * store.unsubscribe('stateChange'); */ unsubscribe(eventName) { delete this.events[eventName]; } /** * Pauses event handling or other operations. * @returns {this} Returns the current instance for method chaining. * @example * store.pause().doSomething(); */ pause() { this._isPause = true; return this; } /** * Resumes event handling or other operations. * @param {*} [val] Optional value to pass while resuming. * @returns {this} Returns the current instance for method chaining. * @example * store.play().doSomething(); */ play(val) { this._isPause = false; return this; } /** * Merges a new reducer function into the existing reducer for a specific state property. * @param {string} stateValueName The key in the state object that the new reducer will manage. * @param {Function} newReducer The reducer function to handle updates for the specified state property. * @returns {void} * @example * const newReducer = (newState, currentState) => ({ ...currentState, ...newState }); * store.mergeReducers('user', newReducer); */ mergeReducers(stateValueName, newReducer) { let reducerCopy = this._reducer; this._reducer = (state, newState) => { let preState = reducerCopy(state, newState); return { ...preState, [stateValueName]: newReducer(newState, state[stateValueName]) }; }; } /** * Synchronizes each entry in an array with the store by defining or updating state entries. * @param {string} storeKey The key prefix used for defining or updating store entries. * @param {Array<object>} [array] The array of entries to be synchronized with the store. * @param {string} [identificator] The property name used as a unique identifier for each entry. * @returns {void} * @example * const data = [{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }]; * store.makeEveryArrayEntryAsStoreState('items', data, 'id'); */ makeEveryArrayEntryAsStoreState(storeKey, array = [], identificator = "id") { array.forEach((entry) => { if (this.getState().hasOwnProperty(`${storeKey}-${entry[identificator]}`)) { this.dispatch(updateAction(`${storeKey}-${entry[identificator]}`)(entry)); } else { this.define( `${storeKey}-${entry.id || entry.source || entry[identificator]}`, entry, null, identificator ); } }); } /** * Defines a new state variable and associates it with a reducer. * @param {string} stateValueName The name of the state variable to define. * @param {*} defaultValue The initial value of the state variable. * @param {Function|null} [reducer] An optional reducer function to manage updates for the state variable. * @param {string} [key] The key used to identify individual entries if the state value is an array or object. * @returns {void} * @example * // Define a new state with a custom reducer * store.define('user', { id: 1, name: 'John Doe' }, (newState, currentState) => ({ ...currentState, ...newState })); * @example * // Define a new state with default array reducer * store.define('items', [], null, 'itemId'); */ define(stateValueName, defaultValue, reducer, key = "id") { if (this._state.hasOwnProperty(stateValueName)) { console.warn(`STATE už obsahuje premennú ${stateValueName},ktorú sa pokúšate pridať`); return; } if (reducer instanceof Function) { this.mergeReducers(stateValueName, reducer); } else { if (defaultValue instanceof Array) { this.mergeReducers(stateValueName, this.createArrayReducer(stateValueName, key)); } else { this.mergeReducers(stateValueName, this.createObjectReducer(stateValueName, key)); } } this.refreshProxy({ ...this._state, [stateValueName]: defaultValue }); } /** * Refreshes the state by wrapping it in a Proxy to track changes and notify subscribers. * @param {object} newState The new state object to be set. Defaults to an empty object if not provided. * @returns {void} * @example * store.refreshProxy({ user: { id: 1, name: 'John Doe' } }); */ refreshProxy(newState) { this._state = new Proxy(newState || {}, { set: (state, key, value) => { if (JSON.stringify(state[key]) === JSON.stringify(value)) { return true; } let oldState = state[key]; state[key] = value; if (!this._isPause) this.events.publish(key, this._state, state[key], oldState); if (this.status !== "mutation") { console.warn(`You should use a mutation to set ${key}`); } this.status = "resting"; return true; } }); } /** * Creates a reducer function to manage an object state. * @param {string} stateValueName The name of the state property this reducer manages. * @returns {Function} A reducer function that handles `ADD`, `UPDATE`, and `DELETE` actions for the specified state property. * @throws {Error} If the payload is an array, an error is logged since the reducer is designed for object state management. * @example * const userReducer = store.createObjectReducer('user'); * const newState = userReducer({ type: 'user/ADD', payload: { id: 1, name: 'John Doe' } }); */ createObjectReducer(stateValueName) { return (action, state = {}) => { if (Array.isArray(action.payload) && (action.type === `${stateValueName}/ADD` || action.type === `${stateValueName}/UPDATE`)) { console.error(`Nemôžete pridať do objektu ${stateValueName} hodnotu, ktorá je pole.`); } const actionType = action.type.split("/")[1]; if (!["ADD", "UPDATE", "DELETE"].includes(actionType)) { console.error( `Nemôžete použiť akciu ${actionType} na objekt. Správne akcie pre objekt sú: ADD, UPDATE, DELETE` ); } switch (action.type) { case `${stateValueName}/ADD`: return { ...action.payload }; case `${stateValueName}/UPDATE`: return { ...state, ...action.payload }; case `${stateValueName}/DELETE`: return {}; default: return state; } }; } /** * Creates a reducer function to manage an array state. * @param {string} stateValueName The name of the state property this reducer manages. * @param {string} key The unique key used to identify items in the array for updates and deletions. * @returns {Function} A reducer function that handles `ADD`, `ADD_MANY`, `UPDATE`, `DELETE`, and `LOAD` actions for the specified state property. * @throws {Error} If `action.payload` is not an array when required. * @example * const itemsReducer = store.createArrayReducer('items', 'id'); * const newState = itemsReducer({ type: 'items/ADD', payload: { id: 1, name: 'Item 1' } }); */ createArrayReducer(stateValueName, key) { return (action, state = []) => { var _a; if (action.actionType === "LOAD" && ((_a = action.type) == null ? void 0 : _a.includes(stateValueName))) { if (!Array.isArray(action.payload)) { console.error(`Snažíte sa použiť "LOAD" akciu na pole, ale payload nie je pole.`); return [...state]; } } switch (action.type) { case `${stateValueName}/ADD`: if (Array.isArray(action.payload)) { return [...state, ...action.payload]; } else { return [...state, action.payload]; } case `${stateValueName}/ADD_MANY`: return [...state, ...action.payload]; case `${stateValueName}/UPDATE`: if (state.some((obj) => obj[key] === action.payload[key])) { return [ ...state.map((obj) => { if (obj[key] === action.payload[key]) { return action.payload; } return obj; }) ]; } else { return [...state, action.payload]; } case `${stateValueName}/DELETE`: if (Array.isArray(action.payload)) { return [ ...state.filter( (obj) => !action.payload.some( (item) => obj.hasOwnProperty(key) && obj[key] !== item[key] || !obj.hasOwnProperty(key) && obj !== item ) ) ]; } return [ ...state.filter( (obj) => obj.hasOwnProperty(key) && obj[key] !== action.payload[key] || !obj.hasOwnProperty(key) && obj !== action.payload ) ]; case `${stateValueName}/LOAD`: return [...action.payload]; default: return state; } }; } } let store = new Store(); export { defaultStoreActions, store }; //# sourceMappingURL=wje-store.js.map