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