eleva 1.0.0-rc.6 → 1.0.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +133 -4
  2. package/dist/eleva-plugins.cjs.js +645 -43
  3. package/dist/eleva-plugins.cjs.js.map +1 -1
  4. package/dist/eleva-plugins.esm.js +645 -44
  5. package/dist/eleva-plugins.esm.js.map +1 -1
  6. package/dist/eleva-plugins.umd.js +645 -43
  7. package/dist/eleva-plugins.umd.js.map +1 -1
  8. package/dist/eleva-plugins.umd.min.js +2 -2
  9. package/dist/eleva-plugins.umd.min.js.map +1 -1
  10. package/dist/eleva.cjs.js +31 -25
  11. package/dist/eleva.cjs.js.map +1 -1
  12. package/dist/eleva.esm.js +31 -25
  13. package/dist/eleva.esm.js.map +1 -1
  14. package/dist/eleva.umd.js +31 -25
  15. package/dist/eleva.umd.js.map +1 -1
  16. package/dist/eleva.umd.min.js +2 -2
  17. package/dist/eleva.umd.min.js.map +1 -1
  18. package/dist/plugins/attr.umd.js +2 -2
  19. package/dist/plugins/attr.umd.js.map +1 -1
  20. package/dist/plugins/attr.umd.min.js +1 -1
  21. package/dist/plugins/attr.umd.min.js.map +1 -1
  22. package/dist/plugins/props.umd.js +18 -15
  23. package/dist/plugins/props.umd.js.map +1 -1
  24. package/dist/plugins/props.umd.min.js +1 -1
  25. package/dist/plugins/props.umd.min.js.map +1 -1
  26. package/dist/plugins/router.umd.js +22 -25
  27. package/dist/plugins/router.umd.js.map +1 -1
  28. package/dist/plugins/router.umd.min.js +1 -1
  29. package/dist/plugins/router.umd.min.js.map +1 -1
  30. package/dist/plugins/store.umd.js +632 -0
  31. package/dist/plugins/store.umd.js.map +1 -0
  32. package/dist/plugins/store.umd.min.js +3 -0
  33. package/dist/plugins/store.umd.min.js.map +1 -0
  34. package/package.json +4 -4
  35. package/src/plugins/Store.js +741 -0
  36. package/src/plugins/index.js +6 -1
  37. package/types/plugins/Store.d.ts +86 -0
  38. package/types/plugins/Store.d.ts.map +1 -0
  39. package/types/plugins/index.d.ts +1 -0
@@ -1,4 +1,4 @@
1
- /*! Eleva Plugins v1.0.0-rc.6 | MIT License | https://elevajs.com */
1
+ /*! Eleva Plugins v1.0.0-rc.7 | MIT License | https://elevajs.com */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
4
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -133,7 +133,7 @@
133
133
  if (hasProperty) {
134
134
  // Boolean attribute handling
135
135
  if (enableBoolean) {
136
- const isBoolean = typeof oldEl[prop] === "boolean" || descriptor?.get && typeof descriptor.get.call(oldEl) === "boolean";
136
+ const isBoolean = typeof oldEl[prop] === "boolean" || (descriptor == null ? void 0 : descriptor.get) && typeof descriptor.get.call(oldEl) === "boolean";
137
137
  if (isBoolean) {
138
138
  const boolValue = value !== "false" && (value === "" || value === prop || value === "true");
139
139
  oldEl[prop] = boolValue;
@@ -175,7 +175,7 @@
175
175
 
176
176
  // Override the _patchNode method to use our attribute handler
177
177
  eleva.renderer._patchNode = function (oldNode, newNode) {
178
- if (oldNode?._eleva_instance) return;
178
+ if (oldNode != null && oldNode._eleva_instance) return;
179
179
  if (!this._isSameNode(oldNode, newNode)) {
180
180
  oldNode.replaceWith(newNode.cloneNode(true));
181
181
  return;
@@ -225,18 +225,16 @@
225
225
  }
226
226
  };
227
227
 
228
- /**
229
- * @typedef {import('eleva').Eleva} Eleva
230
- * @typedef {import('eleva').Signal} Signal
231
- * @typedef {import('eleva').ComponentDefinition} ComponentDefinition
232
- */
228
+ function _extends() {
229
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
230
+ for (var e = 1; e < arguments.length; e++) {
231
+ var t = arguments[e];
232
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
233
+ }
234
+ return n;
235
+ }, _extends.apply(null, arguments);
236
+ }
233
237
 
234
- /**
235
- * Simple error handler for the core router.
236
- * Can be overridden by error handling plugins.
237
- * Provides consistent error formatting and logging for router operations.
238
- * @private
239
- */
240
238
  const CoreErrorHandler = {
241
239
  /**
242
240
  * Handles router errors with basic formatting.
@@ -345,12 +343,11 @@
345
343
  this.eleva = eleva;
346
344
 
347
345
  /** @type {RouterOptions} The merged router options. */
348
- this.options = {
346
+ this.options = _extends({
349
347
  mode: "hash",
350
348
  queryParam: "view",
351
- viewSelector: "root",
352
- ...options
353
- };
349
+ viewSelector: "root"
350
+ }, options);
354
351
 
355
352
  /** @private @type {RouteDefinition[]} The processed list of route definitions. */
356
353
  this.routes = this._processRoutes(options.routes || []);
@@ -414,10 +411,9 @@
414
411
  const processedRoutes = [];
415
412
  for (const route of routes) {
416
413
  try {
417
- processedRoutes.push({
418
- ...route,
414
+ processedRoutes.push(_extends({}, route, {
419
415
  segments: this._parsePathIntoSegments(route.path)
420
- });
416
+ }));
421
417
  } catch (error) {
422
418
  this.errorHandler.warn(`Invalid path in route definition "${route.path || "undefined"}": ${error.message}`, {
423
419
  route,
@@ -672,13 +668,12 @@
672
668
  return false;
673
669
  }
674
670
  }
675
- const to = {
676
- ...toLocation,
671
+ const to = _extends({}, toLocation, {
677
672
  params: toMatch.params,
678
673
  meta: toMatch.route.meta || {},
679
674
  name: toMatch.route.name,
680
675
  matched: toMatch.route
681
- };
676
+ });
682
677
  try {
683
678
  // 1. Run all *pre-navigation* guards.
684
679
  const canNavigate = await this._runGuards(to, from, toMatch.route);
@@ -909,7 +904,10 @@
909
904
  * @returns {Function} A getter function.
910
905
  */
911
906
  _createRouteGetter(property, defaultValue) {
912
- return () => this.currentRoute.value?.[property] ?? defaultValue;
907
+ return () => {
908
+ var _this$currentRoute$va, _this$currentRoute$va2;
909
+ return (_this$currentRoute$va = (_this$currentRoute$va2 = this.currentRoute.value) == null ? void 0 : _this$currentRoute$va2[property]) != null ? _this$currentRoute$va : defaultValue;
910
+ };
913
911
  }
914
912
 
915
913
  /**
@@ -921,8 +919,7 @@
921
919
  _wrapComponent(component) {
922
920
  const originalSetup = component.setup;
923
921
  const self = this;
924
- return {
925
- ...component,
922
+ return _extends({}, component, {
926
923
  async setup(ctx) {
927
924
  ctx.router = {
928
925
  navigate: self.navigate.bind(self),
@@ -947,7 +944,7 @@
947
944
  };
948
945
  return originalSetup ? await originalSetup(ctx) : {};
949
946
  }
950
- };
947
+ });
951
948
  }
952
949
 
953
950
  /**
@@ -1341,12 +1338,6 @@
1341
1338
  * const result = TemplateEngine.parse(template, data); // Returns: "Hello, World!"
1342
1339
  */
1343
1340
  class TemplateEngine {
1344
- /**
1345
- * @private {RegExp} Regular expression for matching template expressions in the format {{ expression }}
1346
- * @type {RegExp}
1347
- */
1348
- static expressionPattern = /\{\{\s*(.*?)\s*\}\}/g;
1349
-
1350
1341
  /**
1351
1342
  * Parses a template string, replacing expressions with their evaluated values.
1352
1343
  * Expressions are evaluated in the provided data context.
@@ -1385,11 +1376,16 @@
1385
1376
  if (typeof expression !== "string") return expression;
1386
1377
  try {
1387
1378
  return new Function("data", `with(data) { return ${expression}; }`)(data);
1388
- } catch {
1379
+ } catch (_unused) {
1389
1380
  return "";
1390
1381
  }
1391
1382
  }
1392
1383
  }
1384
+ /**
1385
+ * @private {RegExp} Regular expression for matching template expressions in the format {{ expression }}
1386
+ * @type {RegExp}
1387
+ */
1388
+ TemplateEngine.expressionPattern = /\{\{\s*(.*?)\s*\}\}/g;
1393
1389
 
1394
1390
  /**
1395
1391
  * @class 🎯 PropsPlugin
@@ -1725,10 +1721,7 @@
1725
1721
  });
1726
1722
 
1727
1723
  // Merge signal props with regular props (signal props take precedence)
1728
- enhancedProps = {
1729
- ...extractedProps,
1730
- ...signalProps
1731
- };
1724
+ enhancedProps = _extends({}, extractedProps, signalProps);
1732
1725
  }
1733
1726
 
1734
1727
  // Create reactive props for non-signal props only
@@ -1747,10 +1740,7 @@
1747
1740
  const reactiveNonSignalProps = createReactiveProps(nonSignalProps);
1748
1741
 
1749
1742
  // Merge signal props with reactive non-signal props
1750
- finalProps = {
1751
- ...reactiveNonSignalProps,
1752
- ...enhancedProps // Signal props take precedence
1753
- };
1743
+ finalProps = _extends({}, reactiveNonSignalProps, enhancedProps);
1754
1744
  }
1755
1745
 
1756
1746
  /** @type {MountResult} */
@@ -1921,9 +1911,621 @@
1921
1911
  }
1922
1912
  };
1923
1913
 
1914
+ const StorePlugin = {
1915
+ /**
1916
+ * Unique identifier for the plugin
1917
+ * @type {string}
1918
+ */
1919
+ name: "store",
1920
+ /**
1921
+ * Plugin version
1922
+ * @type {string}
1923
+ */
1924
+ version: "1.0.0-rc.1",
1925
+ /**
1926
+ * Plugin description
1927
+ * @type {string}
1928
+ */
1929
+ description: "Reactive state management for sharing data across the entire Eleva application",
1930
+ /**
1931
+ * Installs the plugin into the Eleva instance
1932
+ *
1933
+ * @param {Object} eleva - The Eleva instance
1934
+ * @param {Object} options - Plugin configuration options
1935
+ * @param {Object} [options.state={}] - Initial state object
1936
+ * @param {Object} [options.actions={}] - Action functions for state mutations
1937
+ * @param {Object} [options.namespaces={}] - Namespaced modules for organizing store
1938
+ * @param {Object} [options.persistence] - Persistence configuration
1939
+ * @param {boolean} [options.persistence.enabled=false] - Enable state persistence
1940
+ * @param {string} [options.persistence.key="eleva-store"] - Storage key
1941
+ * @param {"localStorage" | "sessionStorage"} [options.persistence.storage="localStorage"] - Storage type
1942
+ * @param {Array<string>} [options.persistence.include] - State keys to persist (if not provided, all state is persisted)
1943
+ * @param {Array<string>} [options.persistence.exclude] - State keys to exclude from persistence
1944
+ * @param {boolean} [options.devTools=false] - Enable development tools integration
1945
+ * @param {Function} [options.onError=null] - Error handler function
1946
+ *
1947
+ * @example
1948
+ * // Basic installation
1949
+ * app.use(StorePlugin, {
1950
+ * state: { count: 0, user: null },
1951
+ * actions: {
1952
+ * increment: (state) => state.count.value++,
1953
+ * setUser: (state, user) => state.user.value = user
1954
+ * }
1955
+ * });
1956
+ *
1957
+ * // Advanced installation with persistence and namespaces
1958
+ * app.use(StorePlugin, {
1959
+ * state: { theme: "light" },
1960
+ * namespaces: {
1961
+ * auth: {
1962
+ * state: { user: null, token: null },
1963
+ * actions: {
1964
+ * login: (state, { user, token }) => {
1965
+ * state.user.value = user;
1966
+ * state.token.value = token;
1967
+ * },
1968
+ * logout: (state) => {
1969
+ * state.user.value = null;
1970
+ * state.token.value = null;
1971
+ * }
1972
+ * }
1973
+ * }
1974
+ * },
1975
+ * persistence: {
1976
+ * enabled: true,
1977
+ * include: ["theme", "auth.user"]
1978
+ * }
1979
+ * });
1980
+ */
1981
+ install(eleva, options = {}) {
1982
+ const {
1983
+ state = {},
1984
+ actions = {},
1985
+ namespaces = {},
1986
+ persistence = {},
1987
+ devTools = false,
1988
+ onError = null
1989
+ } = options;
1990
+
1991
+ /**
1992
+ * Store instance that manages all state and provides the API
1993
+ * @private
1994
+ */
1995
+ class Store {
1996
+ constructor() {
1997
+ this.state = {};
1998
+ this.actions = {};
1999
+ this.subscribers = new Set();
2000
+ this.mutations = [];
2001
+ this.persistence = _extends({
2002
+ enabled: false,
2003
+ key: "eleva-store",
2004
+ storage: "localStorage",
2005
+ include: null,
2006
+ exclude: null
2007
+ }, persistence);
2008
+ this.devTools = devTools;
2009
+ this.onError = onError;
2010
+ this._initializeState(state, actions);
2011
+ this._initializeNamespaces(namespaces);
2012
+ this._loadPersistedState();
2013
+ this._setupDevTools();
2014
+ }
2015
+
2016
+ /**
2017
+ * Initializes the root state and actions
2018
+ * @private
2019
+ */
2020
+ _initializeState(initialState, initialActions) {
2021
+ // Create reactive signals for each state property
2022
+ Object.entries(initialState).forEach(([key, value]) => {
2023
+ this.state[key] = new eleva.signal(value);
2024
+ });
2025
+
2026
+ // Set up actions
2027
+ this.actions = _extends({}, initialActions);
2028
+ }
2029
+
2030
+ /**
2031
+ * Initializes namespaced modules
2032
+ * @private
2033
+ */
2034
+ _initializeNamespaces(namespaces) {
2035
+ Object.entries(namespaces).forEach(([namespace, module]) => {
2036
+ const {
2037
+ state: moduleState = {},
2038
+ actions: moduleActions = {}
2039
+ } = module;
2040
+
2041
+ // Create namespace object if it doesn't exist
2042
+ if (!this.state[namespace]) {
2043
+ this.state[namespace] = {};
2044
+ }
2045
+ if (!this.actions[namespace]) {
2046
+ this.actions[namespace] = {};
2047
+ }
2048
+
2049
+ // Initialize namespaced state
2050
+ Object.entries(moduleState).forEach(([key, value]) => {
2051
+ this.state[namespace][key] = new eleva.signal(value);
2052
+ });
2053
+
2054
+ // Set up namespaced actions
2055
+ this.actions[namespace] = _extends({}, moduleActions);
2056
+ });
2057
+ }
2058
+
2059
+ /**
2060
+ * Loads persisted state from storage
2061
+ * @private
2062
+ */
2063
+ _loadPersistedState() {
2064
+ if (!this.persistence.enabled || typeof window === "undefined") {
2065
+ return;
2066
+ }
2067
+ try {
2068
+ const storage = window[this.persistence.storage];
2069
+ const persistedData = storage.getItem(this.persistence.key);
2070
+ if (persistedData) {
2071
+ const data = JSON.parse(persistedData);
2072
+ this._applyPersistedData(data);
2073
+ }
2074
+ } catch (error) {
2075
+ if (this.onError) {
2076
+ this.onError(error, "Failed to load persisted state");
2077
+ } else {
2078
+ console.warn("[StorePlugin] Failed to load persisted state:", error);
2079
+ }
2080
+ }
2081
+ }
2082
+
2083
+ /**
2084
+ * Applies persisted data to the current state
2085
+ * @private
2086
+ */
2087
+ _applyPersistedData(data, currentState = this.state, path = "") {
2088
+ Object.entries(data).forEach(([key, value]) => {
2089
+ const fullPath = path ? `${path}.${key}` : key;
2090
+ if (this._shouldPersist(fullPath)) {
2091
+ if (currentState[key] && typeof currentState[key] === "object" && "value" in currentState[key]) {
2092
+ // This is a signal, update its value
2093
+ currentState[key].value = value;
2094
+ } else if (typeof value === "object" && value !== null && currentState[key]) {
2095
+ // This is a nested object, recurse
2096
+ this._applyPersistedData(value, currentState[key], fullPath);
2097
+ }
2098
+ }
2099
+ });
2100
+ }
2101
+
2102
+ /**
2103
+ * Determines if a state path should be persisted
2104
+ * @private
2105
+ */
2106
+ _shouldPersist(path) {
2107
+ const {
2108
+ include,
2109
+ exclude
2110
+ } = this.persistence;
2111
+ if (include && include.length > 0) {
2112
+ return include.some(includePath => path.startsWith(includePath));
2113
+ }
2114
+ if (exclude && exclude.length > 0) {
2115
+ return !exclude.some(excludePath => path.startsWith(excludePath));
2116
+ }
2117
+ return true;
2118
+ }
2119
+
2120
+ /**
2121
+ * Saves current state to storage
2122
+ * @private
2123
+ */
2124
+ _saveState() {
2125
+ if (!this.persistence.enabled || typeof window === "undefined") {
2126
+ return;
2127
+ }
2128
+ try {
2129
+ const storage = window[this.persistence.storage];
2130
+ const dataToSave = this._extractPersistedData();
2131
+ storage.setItem(this.persistence.key, JSON.stringify(dataToSave));
2132
+ } catch (error) {
2133
+ if (this.onError) {
2134
+ this.onError(error, "Failed to save state");
2135
+ } else {
2136
+ console.warn("[StorePlugin] Failed to save state:", error);
2137
+ }
2138
+ }
2139
+ }
2140
+
2141
+ /**
2142
+ * Extracts data that should be persisted
2143
+ * @private
2144
+ */
2145
+ _extractPersistedData(currentState = this.state, path = "") {
2146
+ const result = {};
2147
+ Object.entries(currentState).forEach(([key, value]) => {
2148
+ const fullPath = path ? `${path}.${key}` : key;
2149
+ if (this._shouldPersist(fullPath)) {
2150
+ if (value && typeof value === "object" && "value" in value) {
2151
+ // This is a signal, extract its value
2152
+ result[key] = value.value;
2153
+ } else if (typeof value === "object" && value !== null) {
2154
+ // This is a nested object, recurse
2155
+ const nestedData = this._extractPersistedData(value, fullPath);
2156
+ if (Object.keys(nestedData).length > 0) {
2157
+ result[key] = nestedData;
2158
+ }
2159
+ }
2160
+ }
2161
+ });
2162
+ return result;
2163
+ }
2164
+
2165
+ /**
2166
+ * Sets up development tools integration
2167
+ * @private
2168
+ */
2169
+ _setupDevTools() {
2170
+ if (!this.devTools || typeof window === "undefined" || !window.__ELEVA_DEVTOOLS__) {
2171
+ return;
2172
+ }
2173
+ window.__ELEVA_DEVTOOLS__.registerStore(this);
2174
+ }
2175
+
2176
+ /**
2177
+ * Dispatches an action to mutate the state
2178
+ * @param {string} actionName - The name of the action to dispatch (supports namespaced actions like "auth.login")
2179
+ * @param {any} payload - The payload to pass to the action
2180
+ * @returns {Promise<any>} The result of the action
2181
+ */
2182
+ async dispatch(actionName, payload) {
2183
+ try {
2184
+ const action = this._getAction(actionName);
2185
+ if (!action) {
2186
+ const error = new Error(`Action "${actionName}" not found`);
2187
+ if (this.onError) {
2188
+ this.onError(error, actionName);
2189
+ }
2190
+ throw error;
2191
+ }
2192
+ const mutation = {
2193
+ type: actionName,
2194
+ payload,
2195
+ timestamp: Date.now()
2196
+ };
2197
+
2198
+ // Record mutation for devtools
2199
+ this.mutations.push(mutation);
2200
+ if (this.mutations.length > 100) {
2201
+ this.mutations.shift(); // Keep only last 100 mutations
2202
+ }
2203
+
2204
+ // Execute the action
2205
+ const result = await action.call(null, this.state, payload);
2206
+
2207
+ // Save state if persistence is enabled
2208
+ this._saveState();
2209
+
2210
+ // Notify subscribers
2211
+ this.subscribers.forEach(callback => {
2212
+ try {
2213
+ callback(mutation, this.state);
2214
+ } catch (error) {
2215
+ if (this.onError) {
2216
+ this.onError(error, "Subscriber callback failed");
2217
+ }
2218
+ }
2219
+ });
2220
+
2221
+ // Notify devtools
2222
+ if (this.devTools && typeof window !== "undefined" && window.__ELEVA_DEVTOOLS__) {
2223
+ window.__ELEVA_DEVTOOLS__.notifyMutation(mutation, this.state);
2224
+ }
2225
+ return result;
2226
+ } catch (error) {
2227
+ if (this.onError) {
2228
+ this.onError(error, `Action dispatch failed: ${actionName}`);
2229
+ }
2230
+ throw error;
2231
+ }
2232
+ }
2233
+
2234
+ /**
2235
+ * Gets an action by name (supports namespaced actions)
2236
+ * @private
2237
+ */
2238
+ _getAction(actionName) {
2239
+ const parts = actionName.split(".");
2240
+ let current = this.actions;
2241
+ for (const part of parts) {
2242
+ if (current[part] === undefined) {
2243
+ return null;
2244
+ }
2245
+ current = current[part];
2246
+ }
2247
+ return typeof current === "function" ? current : null;
2248
+ }
2249
+
2250
+ /**
2251
+ * Subscribes to store mutations
2252
+ * @param {Function} callback - Callback function to call on mutations
2253
+ * @returns {Function} Unsubscribe function
2254
+ */
2255
+ subscribe(callback) {
2256
+ if (typeof callback !== "function") {
2257
+ throw new Error("Subscribe callback must be a function");
2258
+ }
2259
+ this.subscribers.add(callback);
2260
+
2261
+ // Return unsubscribe function
2262
+ return () => {
2263
+ this.subscribers.delete(callback);
2264
+ };
2265
+ }
2266
+
2267
+ /**
2268
+ * Gets a deep copy of the current state values (not signals)
2269
+ * @returns {Object} The current state values
2270
+ */
2271
+ getState() {
2272
+ return this._extractPersistedData();
2273
+ }
2274
+
2275
+ /**
2276
+ * Replaces the entire state (useful for testing or state hydration)
2277
+ * @param {Object} newState - The new state object
2278
+ */
2279
+ replaceState(newState) {
2280
+ this._applyPersistedData(newState);
2281
+ this._saveState();
2282
+ }
2283
+
2284
+ /**
2285
+ * Clears persisted state from storage
2286
+ */
2287
+ clearPersistedState() {
2288
+ if (!this.persistence.enabled || typeof window === "undefined") {
2289
+ return;
2290
+ }
2291
+ try {
2292
+ const storage = window[this.persistence.storage];
2293
+ storage.removeItem(this.persistence.key);
2294
+ } catch (error) {
2295
+ if (this.onError) {
2296
+ this.onError(error, "Failed to clear persisted state");
2297
+ }
2298
+ }
2299
+ }
2300
+
2301
+ /**
2302
+ * Registers a new namespaced module at runtime
2303
+ * @param {string} namespace - The namespace for the module
2304
+ * @param {Object} module - The module definition
2305
+ * @param {Object} module.state - The module's initial state
2306
+ * @param {Object} module.actions - The module's actions
2307
+ */
2308
+ registerModule(namespace, module) {
2309
+ if (this.state[namespace] || this.actions[namespace]) {
2310
+ console.warn(`[StorePlugin] Module "${namespace}" already exists`);
2311
+ return;
2312
+ }
2313
+
2314
+ // Initialize the module
2315
+ this.state[namespace] = {};
2316
+ this.actions[namespace] = {};
2317
+ const namespaces = {
2318
+ [namespace]: module
2319
+ };
2320
+ this._initializeNamespaces(namespaces);
2321
+ this._saveState();
2322
+ }
2323
+
2324
+ /**
2325
+ * Unregisters a namespaced module
2326
+ * @param {string} namespace - The namespace to unregister
2327
+ */
2328
+ unregisterModule(namespace) {
2329
+ if (!this.state[namespace] && !this.actions[namespace]) {
2330
+ console.warn(`[StorePlugin] Module "${namespace}" does not exist`);
2331
+ return;
2332
+ }
2333
+ delete this.state[namespace];
2334
+ delete this.actions[namespace];
2335
+ this._saveState();
2336
+ }
2337
+
2338
+ /**
2339
+ * Creates a new reactive state property at runtime
2340
+ * @param {string} key - The state key
2341
+ * @param {*} initialValue - The initial value
2342
+ * @returns {Object} The created signal
2343
+ */
2344
+ createState(key, initialValue) {
2345
+ if (this.state[key]) {
2346
+ return this.state[key]; // Return existing state
2347
+ }
2348
+ this.state[key] = new eleva.signal(initialValue);
2349
+ this._saveState();
2350
+ return this.state[key];
2351
+ }
2352
+
2353
+ /**
2354
+ * Creates a new action at runtime
2355
+ * @param {string} name - The action name
2356
+ * @param {Function} actionFn - The action function
2357
+ */
2358
+ createAction(name, actionFn) {
2359
+ if (typeof actionFn !== "function") {
2360
+ throw new Error("Action must be a function");
2361
+ }
2362
+ this.actions[name] = actionFn;
2363
+ }
2364
+ }
2365
+
2366
+ // Create the store instance
2367
+ const store = new Store();
2368
+
2369
+ // Store the original mount method to override it
2370
+ const originalMount = eleva.mount;
2371
+
2372
+ /**
2373
+ * Override the mount method to inject store context into components
2374
+ */
2375
+ eleva.mount = async (container, compName, props = {}) => {
2376
+ // Get the component definition
2377
+ const componentDef = typeof compName === "string" ? eleva._components.get(compName) || compName : compName;
2378
+ if (!componentDef) {
2379
+ return await originalMount.call(eleva, container, compName, props);
2380
+ }
2381
+
2382
+ // Create a wrapped component that injects store into setup
2383
+ const wrappedComponent = _extends({}, componentDef, {
2384
+ async setup(ctx) {
2385
+ // Inject store into the context with enhanced API
2386
+ ctx.store = {
2387
+ // Core store functionality
2388
+ state: store.state,
2389
+ dispatch: store.dispatch.bind(store),
2390
+ subscribe: store.subscribe.bind(store),
2391
+ getState: store.getState.bind(store),
2392
+ // Module management
2393
+ registerModule: store.registerModule.bind(store),
2394
+ unregisterModule: store.unregisterModule.bind(store),
2395
+ // Utilities for dynamic state/action creation
2396
+ createState: store.createState.bind(store),
2397
+ createAction: store.createAction.bind(store),
2398
+ // Access to signal constructor for manual state creation
2399
+ signal: eleva.signal
2400
+ };
2401
+
2402
+ // Call original setup if it exists
2403
+ const originalSetup = componentDef.setup;
2404
+ const result = originalSetup ? await originalSetup(ctx) : {};
2405
+ return result;
2406
+ }
2407
+ });
2408
+
2409
+ // Call original mount with wrapped component
2410
+ return await originalMount.call(eleva, container, wrappedComponent, props);
2411
+ };
2412
+
2413
+ // Override _mountComponents to ensure child components also get store context
2414
+ const originalMountComponents = eleva._mountComponents;
2415
+ eleva._mountComponents = async (container, children, childInstances) => {
2416
+ // Create wrapped children with store injection
2417
+ const wrappedChildren = {};
2418
+ for (const [selector, childComponent] of Object.entries(children)) {
2419
+ const componentDef = typeof childComponent === "string" ? eleva._components.get(childComponent) || childComponent : childComponent;
2420
+ if (componentDef && typeof componentDef === "object") {
2421
+ wrappedChildren[selector] = _extends({}, componentDef, {
2422
+ async setup(ctx) {
2423
+ // Inject store into the context with enhanced API
2424
+ ctx.store = {
2425
+ // Core store functionality
2426
+ state: store.state,
2427
+ dispatch: store.dispatch.bind(store),
2428
+ subscribe: store.subscribe.bind(store),
2429
+ getState: store.getState.bind(store),
2430
+ // Module management
2431
+ registerModule: store.registerModule.bind(store),
2432
+ unregisterModule: store.unregisterModule.bind(store),
2433
+ // Utilities for dynamic state/action creation
2434
+ createState: store.createState.bind(store),
2435
+ createAction: store.createAction.bind(store),
2436
+ // Access to signal constructor for manual state creation
2437
+ signal: eleva.signal
2438
+ };
2439
+
2440
+ // Call original setup if it exists
2441
+ const originalSetup = componentDef.setup;
2442
+ const result = originalSetup ? await originalSetup(ctx) : {};
2443
+ return result;
2444
+ }
2445
+ });
2446
+ } else {
2447
+ wrappedChildren[selector] = childComponent;
2448
+ }
2449
+ }
2450
+
2451
+ // Call original _mountComponents with wrapped children
2452
+ return await originalMountComponents.call(eleva, container, wrappedChildren, childInstances);
2453
+ };
2454
+
2455
+ // Expose store instance and utilities on the Eleva instance
2456
+ eleva.store = store;
2457
+
2458
+ /**
2459
+ * Expose utility methods on the Eleva instance
2460
+ * @namespace eleva.store
2461
+ */
2462
+ eleva.createAction = (name, actionFn) => {
2463
+ store.actions[name] = actionFn;
2464
+ };
2465
+ eleva.dispatch = (actionName, payload) => {
2466
+ return store.dispatch(actionName, payload);
2467
+ };
2468
+ eleva.getState = () => {
2469
+ return store.getState();
2470
+ };
2471
+ eleva.subscribe = callback => {
2472
+ return store.subscribe(callback);
2473
+ };
2474
+
2475
+ // Store original methods for cleanup
2476
+ eleva._originalMount = originalMount;
2477
+ eleva._originalMountComponents = originalMountComponents;
2478
+ },
2479
+ /**
2480
+ * Uninstalls the plugin from the Eleva instance
2481
+ *
2482
+ * @param {Object} eleva - The Eleva instance
2483
+ *
2484
+ * @description
2485
+ * Restores the original Eleva methods and removes all plugin-specific
2486
+ * functionality. This method should be called when the plugin is no
2487
+ * longer needed.
2488
+ *
2489
+ * @example
2490
+ * // Uninstall the plugin
2491
+ * StorePlugin.uninstall(app);
2492
+ */
2493
+ uninstall(eleva) {
2494
+ // Restore original mount method
2495
+ if (eleva._originalMount) {
2496
+ eleva.mount = eleva._originalMount;
2497
+ delete eleva._originalMount;
2498
+ }
2499
+
2500
+ // Restore original _mountComponents method
2501
+ if (eleva._originalMountComponents) {
2502
+ eleva._mountComponents = eleva._originalMountComponents;
2503
+ delete eleva._originalMountComponents;
2504
+ }
2505
+
2506
+ // Remove store instance and utility methods
2507
+ if (eleva.store) {
2508
+ delete eleva.store;
2509
+ }
2510
+ if (eleva.createAction) {
2511
+ delete eleva.createAction;
2512
+ }
2513
+ if (eleva.dispatch) {
2514
+ delete eleva.dispatch;
2515
+ }
2516
+ if (eleva.getState) {
2517
+ delete eleva.getState;
2518
+ }
2519
+ if (eleva.subscribe) {
2520
+ delete eleva.subscribe;
2521
+ }
2522
+ }
2523
+ };
2524
+
1924
2525
  exports.Attr = AttrPlugin;
1925
2526
  exports.Props = PropsPlugin;
1926
2527
  exports.Router = RouterPlugin;
2528
+ exports.Store = StorePlugin;
1927
2529
 
1928
2530
  }));
1929
2531
  //# sourceMappingURL=eleva-plugins.umd.js.map