22 * Example component demonstrating state manager integration
33 */
44console . log ( 'Loading state-example.js' ) ;
5- import { createStore , StoreConnector } from '../deps .js' ;
6- console . log ( 'Imported createStore and StoreConnector from deps.js ' ) ;
5+ import { createStateManager , createConnectedComponent } from '../modules/state-manager/dist/index .js' ;
6+ console . log ( 'Imported createStateManager from state-manager module ' ) ;
77
8- // Create a store for this component
9- const store = createStore ( 'stateExample' , {
8+ // Create a state manager with initial state
9+ const stateManager = createStateManager ( {
1010 counter : 0 ,
1111 theme : document . documentElement . getAttribute ( 'data-theme' ) || 'light' ,
1212 user : { loggedIn : false }
13+ } , {
14+ enablePersistence : true ,
15+ persistenceKey : 'state_example' ,
16+ debug : true
1317} ) ;
1418
15- // Define a base component class
16- class StateExampleBase extends HTMLElement {
19+ // Define the component class
20+ class StateExampleElement extends HTMLElement {
1721 constructor ( ) {
1822 super ( ) ;
23+ console . log ( 'StateExampleElement constructor called' ) ;
1924 this . attachShadow ( { mode : 'open' } ) ;
2025 }
2126
2227 connectedCallback ( ) {
23- // Connect to state keys
24- this . connectToState ( [ 'counter' , 'theme' , 'user' ] ) ;
25- console . log ( 'Connected to state keys: counter, theme, user' ) ;
28+ console . log ( 'StateExampleElement connected to DOM' ) ;
29+ this . render ( ) ;
30+ }
31+
32+ /**
33+ * This method will be called when state changes
34+ * @param {object } state - The current state
35+ * @param {string } path - The path that changed
36+ * @param {object } fullState - The full state object
37+ */
38+ stateChanged ( state , path , fullState ) {
39+ console . log ( 'State changed in component:' , path ) ;
40+ console . log ( 'New state:' , fullState ) ;
41+ console . log ( 'State value:' , state ) ;
2642
43+ // Re-render the component
2744 this . render ( ) ;
28- this . addEventListeners ( ) ;
45+
46+ // If the theme changed, update the document theme
47+ if ( path === 'theme' ) {
48+ document . documentElement . setAttribute ( 'data-theme' , state ) ;
49+ }
2950 }
3051
3152 render ( ) {
32- // Get current counter value from state
53+ // Get current values from state
3354 const counter = this . getState ( 'counter' ) || 0 ;
3455 const theme = this . getState ( 'theme' ) || 'light' ;
3556 const user = this . getState ( 'user' ) || { loggedIn : false } ;
@@ -128,6 +149,9 @@ class StateExampleBase extends HTMLElement {
128149 </div>
129150 </div>
130151 ` ;
152+
153+ // Add event listeners after rendering
154+ this . addEventListeners ( ) ;
131155 }
132156
133157 addEventListeners ( ) {
@@ -139,11 +163,14 @@ class StateExampleBase extends HTMLElement {
139163 console . log ( 'Increment button clicked' ) ;
140164 const currentCounter = this . getState ( 'counter' ) || 0 ;
141165 console . log ( 'Current counter value:' , currentCounter ) ;
142- this . setState ( { counter : currentCounter + 1 } ) ;
143- console . log ( 'Counter incremented to:' , currentCounter + 1 ) ;
166+
167+ try {
168+ this . setState ( { counter : currentCounter + 1 } ) ;
169+ console . log ( 'Counter incremented to:' , currentCounter + 1 ) ;
170+ } catch ( error ) {
171+ console . error ( 'Error setting state:' , error ) ;
172+ }
144173 } ) ;
145- } else {
146- console . warn ( 'Increment button not found in the shadow DOM' ) ;
147174 }
148175
149176 this . shadowRoot . getElementById ( 'decrement' ) ?. addEventListener ( 'click' , ( ) => {
@@ -161,15 +188,6 @@ class StateExampleBase extends HTMLElement {
161188 const newTheme = currentTheme === 'light' ? 'dark' : 'light' ;
162189
163190 this . setState ( { theme : newTheme } ) ;
164-
165- // Also update document theme for the whole application
166- document . documentElement . setAttribute ( 'data-theme' , newTheme ) ;
167-
168- // Dispatch theme change event for other components
169- const event = new CustomEvent ( 'themechange' , {
170- detail : { theme : newTheme }
171- } ) ;
172- document . dispatchEvent ( event ) ;
173191 } ) ;
174192
175193 // User login/logout
@@ -178,84 +196,25 @@ class StateExampleBase extends HTMLElement {
178196
179197 if ( user . loggedIn ) {
180198 // Logout
181- this . setState ( {
182- user : { loggedIn : false }
183- } ) ;
199+ this . setState ( { user : { loggedIn : false } } ) ;
184200 } else {
185201 // Login (simulate)
186- this . setState ( {
187- user : {
188- loggedIn : true ,
189- username : 'DemoUser' ,
202+ this . setState ( {
203+ user : {
204+ loggedIn : true ,
205+ username : 'DemoUser' ,
190206 email : 'demo@example.com' ,
191207 lastLogin : new Date ( ) . toISOString ( )
192- }
208+ }
193209 } ) ;
194210 }
195211 } ) ;
196212 }
197-
198- // This method will be called when state changes
199- stateChanged ( state , changedKeys ) {
200- console . log ( 'State changed in component:' , changedKeys ) ;
201- console . log ( 'New state:' , state ) ;
202-
203- // Check if the counter key changed
204- if ( changedKeys . includes ( 'counter' ) ) {
205- console . log ( 'Counter changed, updating display directly' ) ;
206-
207- // Get the counter display element
208- const counterDisplay = this . shadowRoot . querySelector ( '.counter-display' ) ;
209- if ( counterDisplay ) {
210- // Update the counter display directly
211- // Handle both cases: when state is the full state object or just the counter value
212- let counterValue ;
213- if ( typeof state === 'object' && state !== null ) {
214- // If state is an object, it's the full state object
215- counterValue = state . counter ;
216- console . log ( 'State is an object, counter value:' , counterValue ) ;
217- } else {
218- // If state is not an object, it's the counter value itself
219- counterValue = state ;
220- console . log ( 'State is the counter value itself:' , counterValue ) ;
221- }
222-
223- counterDisplay . textContent = `Counter: ${ counterValue } ` ;
224- console . log ( 'Counter display updated directly to:' , counterValue ) ;
225- console . log ( 'Counter display element text after update:' , counterDisplay . textContent ) ;
226- } else {
227- console . error ( 'Counter display element not found' ) ;
228- // If the element doesn't exist, do a full render
229- this . render ( ) ;
230- }
231-
232- // Also update the state display
233- const stateDisplayPre = this . shadowRoot . querySelector ( '.state-display pre' ) ;
234- if ( stateDisplayPre ) {
235- // Get the full state from the state manager
236- const fullState = this . getState ( ) ;
237- stateDisplayPre . textContent = JSON . stringify ( fullState , null , 2 ) ;
238- }
239- } else {
240- // For other state changes, do a full render
241- console . log ( 'Other state changed, doing full render' ) ;
242- this . render ( ) ;
243-
244- // Re-attach event listeners after render
245- console . log ( 'Re-attaching event listeners after render' ) ;
246- this . addEventListeners ( ) ;
247- }
248- }
249213}
250214
251- // Create the connected component using the StoreConnector
252- const StateExample = StoreConnector ( store ) ( StateExampleBase ) ;
253-
254- // Register the custom element
255- customElements . define ( 'state-example' , StateExample ) ;
256-
257- // Initialize default state if not already set
258- // No need for DOMContentLoaded event handler as we're using a local store
259- // that's already initialized with default values
215+ // Register the component with the state manager
216+ createConnectedComponent ( 'state-example' , StateExampleElement , {
217+ statePaths : [ 'counter' , 'theme' , 'user' ]
218+ } , stateManager ) ;
260219
261- export default StateExample ;
220+ export default StateExampleElement ;
0 commit comments