@uistate/core 4.1.1 → 4.1.2

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A revolutionary approach to UI state management using CSS custom properties and DOM attributes, featuring Attribute-Driven State Inheritance (ADSI).
4
4
 
5
- **Current Version**: 4.1.1
5
+ **Current Version**: 4.1.2
6
6
 
7
7
  **Author**: Ajdin Imsirovic <ajdika@live.com> (GitHub)
8
8
  **Maintainer**: uistate <ajdika.i@gmail.com> (npm)
@@ -15,7 +15,7 @@ npm install @uistate/core
15
15
 
16
16
  ## Quick Start
17
17
 
18
- UIstate v4.1.1 provides four core modules that can be imported individually:
18
+ UIstate v4.1.2 provides four core modules that can be imported individually:
19
19
 
20
20
  ```javascript
21
21
  import { createCssState, createEventState, stateSerializer, createTemplateManager } from '@uistate/core';
package/cssState.js CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * UIstate - CSS-based state management module with integrated serialization
3
- * Part of the UIstate declarative state management system
4
- * Uses CSS custom properties and data attributes for state representation
5
- * Features modular extension capabilities for DOM binding and events
6
- */
7
1
  import StateSerializer from './stateSerializer.js';
8
2
 
9
3
  const createCssState = (initialState = {}, serializer = StateSerializer) => {
@@ -12,7 +6,7 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
12
6
  _observers: new Map(),
13
7
  _serializer: serializer,
14
8
  _specialHandlers: {},
15
- _eventHandlers: new Map(), // Store custom event binding handlers
9
+ _eventHandlers: new Map(),
16
10
 
17
11
  init(serializerConfig) {
18
12
  if (!this._sheet) {
@@ -22,12 +16,10 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
22
16
  this._addRule(':root {}');
23
17
  }
24
18
 
25
- // Configure serializer if options provided
26
19
  if (serializerConfig && typeof serializerConfig === 'object') {
27
20
  this._serializer.configure(serializerConfig);
28
21
  }
29
22
 
30
- // Initialize with any provided state
31
23
  if (initialState && typeof initialState === 'object') {
32
24
  Object.entries(initialState).forEach(([key, value]) => {
33
25
  this.setState(key, value);
@@ -38,14 +30,11 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
38
30
  },
39
31
 
40
32
  setState(key, value) {
41
- // Use serializer for CSS variables
42
33
  const cssValue = this._serializer.serialize(key, value);
43
34
  document.documentElement.style.setProperty(`--${key}`, cssValue);
44
35
 
45
- // Use serializer to handle all attribute application consistently
46
36
  this._serializer.applyToAttributes(key, value);
47
37
 
48
- // Notify any registered observers of the state change
49
38
  this._notifyObservers(key, value);
50
39
  return value;
51
40
  },
@@ -61,7 +50,6 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
61
50
  const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
62
51
  if (!value) return '';
63
52
 
64
- // Use serializer for deserialization
65
53
  return this._serializer.deserialize(key, value);
66
54
  },
67
55
 
@@ -90,7 +78,6 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
90
78
  return this;
91
79
  },
92
80
 
93
- // New method for registering event bindings
94
81
  registerEventBinding(eventType, handler) {
95
82
  this._eventHandlers.set(eventType, handler);
96
83
  return this;
@@ -101,27 +88,21 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
101
88
  const stateKey = el.dataset.observe;
102
89
 
103
90
  this.observe(stateKey, (value) => {
104
- // Special handlers should run first to set data-state
105
91
  if (this._specialHandlers[stateKey]?.observe) {
106
92
  this._specialHandlers[stateKey].observe(value, el);
107
93
  } else if (stateKey.endsWith('-state') && el.hasAttribute('data-state')) {
108
- // Only update data-state for elements that already have this attribute
109
94
  el.dataset.state = value;
110
95
  } else {
111
- // For normal state observers like theme, counter, etc.
112
96
  el.textContent = value;
113
97
  }
114
98
  });
115
99
 
116
- // Trigger initial state
117
100
  const initialValue = this.getState(stateKey);
118
101
  if (this._specialHandlers[stateKey]?.observe) {
119
102
  this._specialHandlers[stateKey].observe(initialValue, el);
120
103
  } else if (stateKey.endsWith('-state') && el.hasAttribute('data-state')) {
121
- // Only set data-state for elements that should have this attribute
122
104
  el.dataset.state = initialValue;
123
105
  } else {
124
- // For normal elements
125
106
  el.textContent = initialValue;
126
107
  }
127
108
 
@@ -131,7 +112,6 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
131
112
  return this;
132
113
  },
133
114
 
134
- // Default event handlers available for implementations to use
135
115
  defaultClickHandler(e) {
136
116
  const target = e.target.closest('[data-state-action]');
137
117
  if (!target) return;
@@ -139,13 +119,11 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
139
119
  const stateAction = target.dataset.stateAction;
140
120
  if (!stateAction) return;
141
121
 
142
- // Special handlers get first priority
143
122
  if (this._specialHandlers[stateAction]?.action) {
144
123
  this._specialHandlers[stateAction].action(target);
145
124
  return;
146
125
  }
147
126
 
148
- // Handle direct value setting via data-state-value
149
127
  if (target.dataset.stateValue !== undefined) {
150
128
  const valueToSet = target.dataset.stateValue;
151
129
  this.setState(stateAction, valueToSet);
@@ -158,20 +136,16 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
158
136
 
159
137
  if (!stateAction) return;
160
138
 
161
- // Special handlers should access any needed data directly from the target
162
139
  if (this._specialHandlers[stateAction]?.action) {
163
140
  this._specialHandlers[stateAction].action(target);
164
141
  }
165
142
  },
166
143
 
167
- // Updated setupStateActions to use registered event handlers
168
144
  setupStateActions(container = document) {
169
- // Only bind the registered event types
170
145
  this._eventHandlers.forEach((handler, eventType) => {
171
146
  container.addEventListener(eventType, handler);
172
147
  });
173
148
 
174
- // If no event handlers registered, register the default ones
175
149
  if (this._eventHandlers.size === 0) {
176
150
  container.addEventListener('click', (e) => this.defaultClickHandler(e));
177
151
  container.addEventListener('input', (e) => this.defaultInputHandler(e));
@@ -186,7 +160,6 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
186
160
  }
187
161
  },
188
162
 
189
- // Add serializer configuration method
190
163
  configureSerializer(config) {
191
164
  if (this._serializer.configure) {
192
165
  this._serializer.configure(config);
@@ -194,18 +167,14 @@ const createCssState = (initialState = {}, serializer = StateSerializer) => {
194
167
  return this;
195
168
  },
196
169
 
197
- // Clean up resources
198
170
  destroy() {
199
171
  this._observers.clear();
200
- // The style element will remain in the DOM
201
- // as removing it would affect the UI state
202
172
  }
203
173
  };
204
174
 
205
175
  return state.init();
206
176
  };
207
177
 
208
- // Create a singleton instance for easy usage
209
178
  const UIstate = createCssState();
210
179
 
211
180
  export { createCssState };
package/eventState.js CHANGED
@@ -1,23 +1,12 @@
1
- /**
2
- * UIstate - Event-based hierarchical state management module
3
- * Part of the UIstate declarative state management system
4
- * Uses DOM events for pub/sub with hierarchical path support
5
- */
6
-
7
1
  const createEventState = (initial = {}) => {
8
- // Clone the initial state to avoid direct mutations to the passed object
9
2
  const store = JSON.parse(JSON.stringify(initial));
10
3
 
11
- // Create a dedicated DOM element to use as an event bus
12
4
  const bus = document.createElement("x-store");
13
5
 
14
- // Optional: Keep the bus element off the actual DOM for better encapsulation
15
- // but this isn't strictly necessary for functionality
16
6
  bus.style.display = "none";
17
7
  document.documentElement.appendChild(bus);
18
8
 
19
9
  return {
20
- // get a value from the store by path
21
10
  get: (path) => {
22
11
  if (!path) return store;
23
12
  return path
@@ -29,16 +18,13 @@ const createEventState = (initial = {}) => {
29
18
  );
30
19
  },
31
20
 
32
- // set a value in the store by path
33
21
  set: (path, value) => {
34
22
  if(!path) return;
35
23
 
36
- // Update the store
37
24
  let target = store;
38
25
  const parts = path.split(".");
39
26
  const last = parts.pop();
40
27
 
41
- // Create the path if it doesn't exist
42
28
  parts.forEach((part) => {
43
29
  if (!target[part] || typeof target[part] !== "object") {
44
30
  target[part] = {};
@@ -46,13 +32,10 @@ const createEventState = (initial = {}) => {
46
32
  target = target[part];
47
33
  });
48
34
 
49
- // Set the value
50
35
  target[last] = value;
51
36
 
52
- // Notify subscribers with a DOM event
53
37
  bus.dispatchEvent(new CustomEvent(path, { detail: value }));
54
38
 
55
- // Also dispatch events for parent paths to support wildcards
56
39
  if (parts.length > 0) {
57
40
  let parentPath = "";
58
41
  for (const part of parts) {
@@ -64,7 +47,6 @@ const createEventState = (initial = {}) => {
64
47
  );
65
48
  }
66
49
 
67
- // Dispatch root wildcard for any state change
68
50
  bus.dispatchEvent(
69
51
  new CustomEvent("*", {
70
52
  detail: { path, value},
@@ -75,7 +57,6 @@ const createEventState = (initial = {}) => {
75
57
  return value;
76
58
  },
77
59
 
78
- // Subscribe to changes on a path
79
60
  subscribe: (path, callback) => {
80
61
  if (!path || typeof callback !== "function") return () => {};
81
62
 
@@ -85,7 +66,6 @@ const createEventState = (initial = {}) => {
85
66
  return () => bus.removeEventListener(path, handler);
86
67
  },
87
68
 
88
- // Optional method to clean up resources
89
69
  destroy: () => {
90
70
  if (bus.parentNode) {
91
71
  bus.parentNode.removeChild(bus);
package/index.js CHANGED
@@ -1,18 +1,6 @@
1
- /**
2
- * UIstate - Simple barrel file for core modules
3
- *
4
- * Exports the four core UIstate modules:
5
- * - cssState: CSS custom properties state management
6
- * - eventState: Event-based state management
7
- * - stateSerializer: State serialization utilities
8
- * - templateManager: Declarative template management
9
- */
10
-
11
- // Export the four core modules
12
1
  export { createCssState } from './cssState.js';
13
2
  export { createEventState } from './eventState.js';
14
3
  export { default as stateSerializer } from './stateSerializer.js';
15
4
  export { createTemplateManager } from './templateManager.js';
16
5
 
17
- // For convenience, also export cssState as default
18
6
  export { createCssState as default } from './cssState.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uistate/core",
3
- "version": "4.1.1",
3
+ "version": "4.1.2",
4
4
  "description": "Revolutionary DOM-based state management using CSS custom properties - zero dependencies, potential O(1) updates",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,17 +1,3 @@
1
- /**
2
- * StateSerializer - Configurable serialization module for UIstate
3
- * Handles transformation between JavaScript values and CSS-compatible string values
4
- *
5
- * Supports multiple serialization strategies:
6
- * - 'escape': Uses custom escaping for all values (original UIstate approach)
7
- * - 'json': Uses JSON.stringify for complex objects, direct values for primitives
8
- * - 'hybrid': Automatically selects the best strategy based on value type
9
- *
10
- * Also handles serialization of values for data attributes and CSS variables
11
- * with consistent rules and unified serialization behavior
12
- */
13
-
14
- // Utility functions for CSS value escaping/unescaping
15
1
  function escapeCssValue(value) {
16
2
  if (typeof value !== 'string') return value;
17
3
  return value.replace(/[^\x20-\x7E]|[!;{}:()[\]/@,'"]/g, function(char) {
@@ -22,7 +8,6 @@ function escapeCssValue(value) {
22
8
 
23
9
  function unescapeCssValue(value) {
24
10
  if (typeof value !== 'string') return value;
25
- // Only perform unescaping if there are escape sequences
26
11
  if (!value.includes('\\')) return value;
27
12
 
28
13
  return value.replace(/\\([0-9a-f]{1,6})\s?/gi, function(match, hex) {
@@ -30,32 +15,19 @@ function unescapeCssValue(value) {
30
15
  });
31
16
  }
32
17
 
33
- /**
34
- * Create a configured serializer instance
35
- * @param {Object} config - Configuration options
36
- * @returns {Object} - Serializer instance
37
- */
38
18
  function createSerializer(config = {}) {
39
- // Default configuration
40
19
  const defaultConfig = {
41
- mode: 'hybrid', // 'escape', 'json', or 'hybrid'
42
- debug: false, // Enable debug logging
43
- complexThreshold: 3, // Object properties threshold for hybrid mode
44
- preserveTypes: true // Preserve type information in serialization
20
+ mode: 'hybrid',
21
+ debug: false,
22
+ complexThreshold: 3,
23
+ preserveTypes: true,
45
24
  };
46
25
 
47
- // Merge provided config with defaults
48
26
  const options = { ...defaultConfig, ...config };
49
27
 
50
- // Serializer instance
51
28
  const serializer = {
52
- // Current configuration
53
29
  config: options,
54
30
 
55
- /**
56
- * Update configuration
57
- * @param {Object} newConfig - New configuration options
58
- */
59
31
  configure(newConfig) {
60
32
  Object.assign(this.config, newConfig);
61
33
  if (this.config.debug) {
@@ -63,14 +35,7 @@ function createSerializer(config = {}) {
63
35
  }
64
36
  },
65
37
 
66
- /**
67
- * Serialize a value for storage in CSS variables
68
- * @param {string} key - The state key (for context-aware serialization)
69
- * @param {any} value - The value to serialize
70
- * @returns {string} - Serialized value
71
- */
72
38
  serialize(key, value) {
73
- // Handle null/undefined
74
39
  if (value === null || value === undefined) {
75
40
  return '';
76
41
  }
@@ -80,37 +45,24 @@ function createSerializer(config = {}) {
80
45
  (Array.isArray(value) ||
81
46
  (Object.keys(value).length >= this.config.complexThreshold));
82
47
 
83
- // Select serialization strategy based on configuration and value type
84
48
  if (this.config.mode === 'escape' ||
85
49
  (this.config.mode === 'hybrid' && !isComplex)) {
86
- // Use escape strategy for primitives or when escape mode is forced
87
50
  if (valueType === 'string') {
88
51
  return escapeCssValue(value);
89
52
  } else if (valueType === 'object') {
90
- // For simple objects in escape mode, still use JSON but with escaping
91
53
  const jsonStr = JSON.stringify(value);
92
54
  return escapeCssValue(jsonStr);
93
55
  } else {
94
- // For other primitives, convert to string
95
56
  return String(value);
96
57
  }
97
58
  } else {
98
- // Use JSON strategy for complex objects or when JSON mode is forced
99
59
  return JSON.stringify(value);
100
60
  }
101
61
  },
102
62
 
103
- /**
104
- * Deserialize a value from CSS variable storage
105
- * @param {string} key - The state key (for context-aware deserialization)
106
- * @param {string} value - The serialized value
107
- * @returns {any} - Deserialized value
108
- */
109
63
  deserialize(key, value) {
110
- // Handle empty values
111
64
  if (!value) return '';
112
65
 
113
- // Try JSON parse first for values that look like JSON
114
66
  if (this.config.mode !== 'escape' &&
115
67
  ((value.startsWith('{') && value.endsWith('}')) ||
116
68
  (value.startsWith('[') && value.endsWith(']')))) {
@@ -120,64 +72,42 @@ function createSerializer(config = {}) {
120
72
  if (this.config.debug) {
121
73
  console.warn(`Failed to parse JSON for key "${key}":`, value);
122
74
  }
123
- // Fall through to unescaping if JSON parse fails
124
75
  }
125
76
  }
126
77
 
127
- // For non-JSON or escape mode, try unescaping
128
78
  const unescaped = unescapeCssValue(value);
129
79
 
130
- // If unescaped looks like JSON (might have been double-escaped), try parsing it
131
80
  if (this.config.mode !== 'escape' &&
132
81
  ((unescaped.startsWith('{') && unescaped.endsWith('}')) ||
133
82
  (unescaped.startsWith('[') && unescaped.endsWith(']')))) {
134
83
  try {
135
84
  return JSON.parse(unescaped);
136
85
  } catch (e) {
137
- // Not valid JSON, return unescaped string
138
86
  }
139
87
  }
140
88
 
141
89
  return unescaped;
142
90
  },
143
91
 
144
- /**
145
- * Serialize a value for data-* attribute
146
- * @param {string} key - The state key
147
- * @param {any} value - The value to serialize for attribute
148
- * @returns {string} - Serialized attribute value
149
- */
150
92
  serializeForAttribute(key, value) {
151
93
  if (value === null || value === undefined) return null;
152
94
 
153
- // For objects, use the standard serializer
154
95
  if (typeof value === 'object') {
155
96
  return this.serialize(key, value);
156
97
  }
157
98
 
158
- // For primitive values, use direct string conversion
159
99
  return String(value);
160
100
  },
161
101
 
162
- /**
163
- * Apply serialized state to HTML element attributes and properties
164
- * @param {string} key - State key
165
- * @param {any} value - Value to apply
166
- * @param {HTMLElement} element - Target element (defaults to documentElement)
167
- */
168
102
  applyToAttributes(key, value, element = document.documentElement) {
169
- // Skip null/undefined values
170
103
  if (value === null || value === undefined) {
171
104
  element.removeAttribute(`data-${key}`);
172
105
  return;
173
106
  }
174
107
 
175
- // Handle objects specially
176
108
  if (typeof value === 'object') {
177
- // Set the main attribute with serialized value
178
109
  element.setAttribute(`data-${key}`, this.serialize(key, value));
179
110
 
180
- // For non-array objects, set individual property attributes
181
111
  if (!Array.isArray(value)) {
182
112
  Object.entries(value).forEach(([propKey, propValue]) => {
183
113
  const attributeKey = `data-${key}-${propKey.toLowerCase()}`;
@@ -196,37 +126,21 @@ function createSerializer(config = {}) {
196
126
  });
197
127
  }
198
128
  } else {
199
- // For primitives, set directly
200
129
  element.setAttribute(`data-${key}`, value);
201
130
  }
202
131
  },
203
132
 
204
- /**
205
- * Utility method to determine if a value needs complex serialization
206
- * @param {any} value - Value to check
207
- * @returns {boolean} - True if complex serialization is needed
208
- */
209
133
  needsComplexSerialization(value) {
210
134
  return typeof value === 'object' && value !== null;
211
135
  },
212
136
 
213
- /**
214
- * Set state with proper serialization for CSS variables
215
- * @param {Object} uistate - UIstate instance
216
- * @param {string} path - State path
217
- * @param {any} value - Value to set
218
- * @returns {any} - The set value
219
- */
220
137
  setStateWithCss(uistate, path, value) {
221
- // Update UIstate
222
138
  uistate.setState(path, value);
223
139
 
224
- // Update CSS variable with properly serialized value
225
140
  const cssPath = path.replace(/\./g, '-');
226
141
  const serialized = this.serialize(path, value);
227
142
  document.documentElement.style.setProperty(`--${cssPath}`, serialized);
228
143
 
229
- // Update data attribute for root level state
230
144
  const segments = path.split('.');
231
145
  if (segments.length === 1) {
232
146
  document.documentElement.dataset[path] = typeof value === 'object'
@@ -237,18 +151,10 @@ function createSerializer(config = {}) {
237
151
  return value;
238
152
  },
239
153
 
240
- /**
241
- * Get state with fallback to CSS variables
242
- * @param {Object} uistate - UIstate instance
243
- * @param {string} path - State path
244
- * @returns {any} - Retrieved value
245
- */
246
154
  getStateFromCss(uistate, path) {
247
- // First try UIstate
248
155
  const value = uistate.getState(path);
249
156
  if (value !== undefined) return value;
250
157
 
251
- // If not found, try CSS variable
252
158
  const cssPath = path.replace(/\./g, '-');
253
159
  const cssValue = getComputedStyle(document.documentElement)
254
160
  .getPropertyValue(`--${cssPath}`).trim();
@@ -260,7 +166,6 @@ function createSerializer(config = {}) {
260
166
  return serializer;
261
167
  }
262
168
 
263
- // Create a default instance with hybrid mode
264
169
  const StateSerializer = createSerializer();
265
170
 
266
171
  export default StateSerializer;
@@ -1,8 +1,3 @@
1
- /**
2
- * TemplateManager - Component mounting and event delegation
3
- * Handles HTML templating, component mounting, and event delegation
4
- */
5
-
6
1
  const createTemplateManager = (stateManager) => {
7
2
  const manager = {
8
3
  handlers: {},
@@ -12,25 +7,11 @@ const createTemplateManager = (stateManager) => {
12
7
  return this;
13
8
  },
14
9
 
15
- /**
16
- * Register multiple actions with their handlers in a declarative way
17
- * @param {Object} actionsMap - Map of action names to handlers or handler configs
18
- * @returns {Object} - The manager instance for chaining
19
- *
20
- * Example usage:
21
- * templateManager.registerActions({
22
- * 'add-item': addItem,
23
- * 'delete-item': { fn: deleteItem, extractId: true },
24
- * 'toggle-state': toggleState
25
- * });
26
- */
27
10
  registerActions(actionsMap) {
28
11
  Object.entries(actionsMap).forEach(([action, handler]) => {
29
12
  if (typeof handler === 'function') {
30
- // Simple function handler
31
13
  this.onAction(action, handler);
32
14
  } else if (typeof handler === 'object' && handler !== null) {
33
- // Handler with configuration
34
15
  const { fn, extractId = true, idAttribute = 'id' } = handler;
35
16
 
36
17
  if (typeof fn !== 'function') {
@@ -40,7 +21,6 @@ const createTemplateManager = (stateManager) => {
40
21
  this.onAction(action, (e) => {
41
22
  if (extractId) {
42
23
  const target = e.target.closest('[data-action]');
43
- // Look for common ID attributes in order of preference
44
24
  const id = target.dataset[idAttribute] ||
45
25
  target.dataset.actionId ||
46
26
  target.dataset.cardId ||
@@ -70,40 +50,30 @@ const createTemplateManager = (stateManager) => {
70
50
  if (typeof handler === 'function') {
71
51
  handler(e);
72
52
  } else if (target.dataset.value !== undefined && stateManager) {
73
- // If we have a state manager, use it to update state
74
53
  stateManager.setState(action, target.dataset.value);
75
54
  }
76
55
  });
77
56
  return this;
78
57
  },
79
58
 
80
- /**
81
- * Render a template from a CSS variable
82
- * @param {string} templateName - Name of the template (will be prefixed with --template-)
83
- * @param {Object} data - Data to inject into the template
84
- * @returns {HTMLElement} - The rendered element
85
- */
86
59
  renderTemplateFromCss(templateName, data = {}) {
87
60
  const cssTemplate = getComputedStyle(document.documentElement)
88
61
  .getPropertyValue(`--template-${templateName}`)
89
62
  .trim()
90
- .replace(/^['"]|['"]$/g, ''); // Remove surrounding quotes
63
+ .replace(/^['"]|['"]$/g, '');
91
64
 
92
65
  if (!cssTemplate) throw new Error(`Template not found in CSS: --template-${templateName}`);
93
66
 
94
67
  let html = cssTemplate;
95
68
 
96
- // Replace all placeholders with actual data
97
69
  Object.entries(data).forEach(([key, value]) => {
98
70
  const regex = new RegExp(`{{${key}}}`, 'g');
99
71
  html = html.replace(regex, value);
100
72
  });
101
73
 
102
- // Create a temporary container
103
74
  const temp = document.createElement('div');
104
75
  temp.innerHTML = html;
105
76
 
106
- // Return the first child (the rendered template)
107
77
  return temp.firstElementChild;
108
78
  },
109
79
 
@@ -131,13 +101,11 @@ const createTemplateManager = (stateManager) => {
131
101
  return clone.firstElementChild;
132
102
  },
133
103
 
134
- // Helper to create a reactive component with automatic updates
135
104
  createComponent(name, renderFn, stateKeys = []) {
136
105
  if (!stateManager) {
137
106
  throw new Error('State manager is required for reactive components');
138
107
  }
139
108
 
140
- // Create template element if it doesn't exist
141
109
  let tpl = document.getElementById(`${name}-template`);
142
110
  if (!tpl) {
143
111
  tpl = document.createElement('template');
@@ -145,10 +113,8 @@ const createTemplateManager = (stateManager) => {
145
113
  document.body.appendChild(tpl);
146
114
  }
147
115
 
148
- // Initial render
149
116
  tpl.innerHTML = renderFn(stateManager);
150
117
 
151
- // Set up observers for reactive updates
152
118
  if (stateKeys.length > 0) {
153
119
  stateKeys.forEach(key => {
154
120
  stateManager.observe(key, () => {
@@ -162,17 +128,6 @@ const createTemplateManager = (stateManager) => {
162
128
  };
163
129
  },
164
130
 
165
- /**
166
- * Apply CSS classes to an element based on a state key stored in CSS variables
167
- * @param {HTMLElement} element - Element to apply classes to
168
- * @param {string} stateKey - State key to look up in CSS variables
169
- * @param {Object} options - Options for class application
170
- * @returns {HTMLElement} - The element for chaining
171
- *
172
- * Example usage:
173
- * // CSS: :root { --card-primary-classes: "bg-primary text-white"; }
174
- * templateManager.applyClassesFromState(cardElement, 'card-primary');
175
- */
176
131
  applyClassesFromState(element, stateKey, options = {}) {
177
132
  if (!element) return element;
178
133
 
@@ -191,25 +146,22 @@ const createTemplateManager = (stateManager) => {
191
146
  .replace(/^['"]|['"]$/g, '');
192
147
 
193
148
  if (classString) {
194
- // Clear existing classes if specified
195
149
  if (clearExisting) {
196
150
  element.className = '';
197
151
  }
198
152
 
199
- // Add new classes
200
153
  classString.split(' ').forEach(cls => {
201
154
  if (cls) element.classList.add(cls);
202
155
  });
203
156
  }
204
157
 
205
- return element; // For chaining
158
+ return element;
206
159
  }
207
160
  };
208
161
 
209
162
  return manager;
210
163
  };
211
164
 
212
- // Create a standalone instance that doesn't depend on any state manager
213
165
  const TemplateManager = createTemplateManager();
214
166
 
215
167
  export default createTemplateManager;