+2
-2
@@ -1,2 +0,2 @@ | ||
| /* statez 1.0.0, by Craig Buckler, 2022-06-14T17:16 */ | ||
| var i={},f={page:null,session:"sessionStorage",permanent:"localStorage"},c=class extends EventTarget{#t=null;#e=null;#s=0;#n=null;constructor(e,s,n,l){super(),this.#t=s,this.#e=e&&window[e],this.#s=(l||0)*1e3,this.#e&&(n=JSON.parse(this.#e.getItem(s))||n);for(let o in n)this[o]=n[o];this.#s&&this.syncState()}dispatchEvent(e={}){e.state=i[this.#t],super.dispatchEvent(new CustomEvent("change",{detail:e,bubbles:!1,cancelable:!1})),this.#s&&(clearTimeout(this.#n),this.#n=setTimeout(()=>this.syncState(),this.#s))}cleanState(){Object.getOwnPropertyNames(this).forEach(e=>{let s={property:e,valueOld:this[e]};delete this[e],this.dispatchEvent(s)})}syncState(){if(!this.#e)return;let e=JSON.stringify(this);e.length<3?this.#e.removeItem(this.#t):this.#e.setItem(this.#t,e)}},h={set:(t,e,s)=>{let n=Reflect.get(t,e),l=!0;return n!==s&&typeof t[e]!="function"&&(l=Reflect.set(t,e,s),l&&t.dispatchEvent({property:e,value:s,valueOld:n}),typeof s>"u"&&Reflect.deleteProperty(t,e)),l},deleteProperty:(t,e)=>{let s=Reflect.get(t,e);return Reflect.getOwnPropertyDescriptor(t,e)&&Reflect.deleteProperty(t,e)&&t.dispatchEvent({property:e,valueOld:s}),!0},get:(t,e)=>{let s=t[e];return typeof s=="function"?function(...n){return s.apply(t,n)}:Reflect.get(t,e)}};function d({type:t=f.permanent,name:e=null,init:s=null,sync:n=0}={}){return e=e||"stateZ"+(t||"page"),i[e]||(i[e]=new Proxy(new c(t,e,s,n),h)),i[e]}window.addEventListener("storage",t=>{let e=i[t.key];if(e){let s=JSON.parse(t.newValue);for(let n in s)JSON.stringify(e[n])!=JSON.stringify(s[n])&&(e[n]=s[n])}});window.addEventListener("beforeunload",()=>{for(let t in i)i[t].syncState()});export{d as stateZ,f as stateZtype}; | ||
| /* statez 1.0.1, by Craig Buckler, 2022-06-17T11:11 */ | ||
| var c={},f={page:null,session:"sessionStorage",permanent:"localStorage"},l=class extends EventTarget{#s=null;#e=null;#t=0;#n=null;constructor(e,s,n,i=0){super(),this.#s=s,this.#e=e&&window[e],this.#t=i,this.#e&&(n=JSON.parse(this.#e.getItem(s))||n);for(let o in n)this[o]=n[o];this.#t&&this.syncState()}dispatchEvent(e={}){e.state=c[this.#s],super.dispatchEvent(new CustomEvent("change",{detail:e,bubbles:!1,cancelable:!1})),this.#t&&(clearTimeout(this.#n),this.#n=setTimeout(()=>this.syncState(),this.#t))}cleanState(){Object.getOwnPropertyNames(this).forEach(e=>{let s={property:e,valueOld:this[e]};delete this[e],this.dispatchEvent(s)})}syncState(){this.#e&&this.#e.setItem(this.#s,JSON.stringify(this))}},h={set:(t,e,s)=>{let n=Reflect.get(t,e),i=!0;return n!==s&&typeof t[e]!="function"&&(i=Reflect.set(t,e,s),i&&t.dispatchEvent({property:e,value:s,valueOld:n}),typeof s>"u"&&Reflect.deleteProperty(t,e)),i},deleteProperty:(t,e)=>{let s=Reflect.get(t,e);return Reflect.getOwnPropertyDescriptor(t,e)&&Reflect.deleteProperty(t,e)&&t.dispatchEvent({property:e,valueOld:s}),!0},get:(t,e)=>{let s=t[e];return typeof s=="function"?function(...n){return s.apply(t,n)}:Reflect.get(t,e)}};function d({type:t=f.permanent,name:e=null,init:s=null,sync:n=0}={}){return e=e||"stateZ"+(t||"page"),c[e]||(c[e]=new Proxy(new l(t,e,s,n),h)),c[e]}window.addEventListener("storage",t=>{let e=c[t.key];if(e){let s=JSON.parse(t.newValue);new Set([...Object.getOwnPropertyNames(e),...Object.getOwnPropertyNames(s)]).forEach(i=>{JSON.stringify(e[i])!=JSON.stringify(s[i])&&(typeof s[i]>"u"?delete e[i]:e[i]=s[i])})}});window.addEventListener("beforeunload",()=>{Object.values(c).forEach(t=>t.syncState())});export{d as stateZ,f as stateZtype}; |
+3
-3
| { | ||
| "name": "statez", | ||
| "version": "1.0.0", | ||
| "version": "1.0.1", | ||
| "description": "Simple client-side state manager", | ||
@@ -12,3 +12,3 @@ "type": "module", | ||
| "build": "node ./esbuild.config.js production", | ||
| "watch": "node ./esbuild.config.js development" | ||
| "start": "node ./esbuild.config.js development" | ||
| }, | ||
@@ -32,4 +32,4 @@ "repository": { | ||
| "devDependencies": { | ||
| "esbuild": "^0.14.43" | ||
| "esbuild": "^0.14.45" | ||
| } | ||
| } |
+27
-27
@@ -5,6 +5,6 @@ # stateZ | ||
| * simple to use, e.g. `myState.x = 1` | ||
| * can store data for [current page, current session, or permanently](#advanced-initialization) | ||
| * can [synchronize data](#advanced-initialization) across tabs | ||
| * [triggers events](#state-change-events) when state changes | ||
| * simple to use, e.g. `myState.x = 1; console.log( myState.x );` | ||
| * can store data for the [current page, current session, or permanently](#advanced-initialization) | ||
| * [triggers events](#state-change-events) when any state changes | ||
| * [synchronizes data](#advanced-initialization) across browser tabs | ||
| * vanilla JavaScript compatible with all frameworks | ||
@@ -46,3 +46,3 @@ * fast and lightweight - less than 2KB of code | ||
| then set and retrieve values: | ||
| Set and retrieve values: | ||
@@ -67,3 +67,3 @@ ```js | ||
| You can use the same state in any other script to access the same values: | ||
| You can use the same state in any other script on the same domain to access the same values: | ||
@@ -90,9 +90,9 @@ ```js | ||
| * `init`: an initial object when no previous state is available. | ||
| * `sync`: cross-tab [auto-synchronization](#state-synchronization) time in seconds. | ||
| * `sync`: cross-tab [auto-synchronization](#state-synchronization) time in milliseconds. | ||
| The type can be: | ||
| The storage `type` can be: | ||
| * `stateZtype.permanent`: permanent data storage shared across all tabs which persists until the user wipes their browser's cache (the default). | ||
| * `stateZtype.session`: temporary data storage which persists in the current tab and is wiped on close. | ||
| * `stateZtype.page`: temporary data storage which persists in the current page view and is wiped on a page refresh or tab close. | ||
| * `stateZtype.permanent` (default): permanent data shared across all browser tabs on the same domain which persists until the user wipes their browser cache. | ||
| * `stateZtype.session`: temporary data which persists in the current tab and is wiped when it is closed. | ||
| * `stateZtype.page`: temporary data which persists in the current page view and is wiped on a page refresh or tab close. | ||
@@ -109,3 +109,3 @@ When no `name` is specified, a default store is created for each `type`. The following stores are the same: | ||
| ```js | ||
| const s3 = stateZ({ type: stateZtype.permanent }); | ||
| const s3 = stateZ({ type: stateZtype.permanent }); // identical to s1 and s2 | ||
| const s4 = stateZ({ type: stateZtype.session }); | ||
@@ -120,3 +120,3 @@ const s4 = stateZ({ type: stateZtype.page }); | ||
| console.log( s.a ); // 1 unless the state was stored or set elsewhere | ||
| console.log( s.a ); // 1 unless state was previously stored or set elsewhere | ||
| ``` | ||
@@ -127,11 +127,11 @@ | ||
| Permanent and session states are automatically saved when the page unloads. Permanent state is synchronized to other tabs at that point, but this may never occur on some applications. | ||
| Permanent and session state is automatically saved when the page unloads. Permanent state is synchronized to other tabs at that point but this may never occur on some long-running web pages. | ||
| Setting `sync` to a non-zero value automatically synchronises **permanent** data stores to other browser tabs on the same domain where **stateZ** is loaded: | ||
| Setting `sync` to a non-zero value automatically synchronises **permanent** data stores to other browser tabs on the same domain where the same **stateZ** object is loaded: | ||
| ```js | ||
| const s = stateZ({ name: 'myState', sync: 3 }); | ||
| const s = stateZ({ name: 'myState', sync: 3000 }); | ||
| ``` | ||
| Synchronizing larger states is an expensive operation. The `sync` value sets a (debounce) number of seconds to wait before synchronization occurs. The example above will synchronize no more than once every three seconds regardless of how many state values are updated. | ||
| Synchronizing larger states is an expensive operation. The `sync` value sets a (debounce) number of milliseconds to wait before synchronization occurs. The example above will synchronize no more than once every three seconds regardless of how many state values are updated. | ||
@@ -158,3 +158,3 @@ Alternatively, you can set `sync` to `0` (the default) and manually synchronize to other tabs using the `.syncState()` method: | ||
| or by setting a property to `undefined`: | ||
| Setting a property to `undefined` is identical: | ||
@@ -171,3 +171,3 @@ ```js | ||
| An empty state object will remove itself from session/permanent storage. | ||
| An empty state still overrides any `init` object set when initializing. | ||
@@ -177,3 +177,3 @@ | ||
| You can trigger an event handler when a property updates. This could be useful for data binding or similar activities. | ||
| You can trigger an event handler when a property value changes. This could be useful for data binding or similar activities. | ||
@@ -183,4 +183,4 @@ The event handler function receives an object with a `details` property that has the following child properties: | ||
| * `.detail.property`: the name of the updated property | ||
| * `.detail.value`: the new value | ||
| * `.detail.valueOld`: the old value | ||
| * `.detail.value`: the new value (`undefined` when a property has been deleted) | ||
| * `.detail.valueOld`: the previous value before the update | ||
| * `.detail.state`: the **stateZ** object | ||
@@ -241,3 +241,5 @@ | ||
| Be wary about unconditionally changing states in an event handler. You could trigger an infinite cascade of change and synchronization events. | ||
| ## Nested objects and arrays | ||
@@ -257,6 +259,4 @@ | ||
| This triggers change events as necessary. | ||
| This triggers change events. Setting the same value again will also trigger an event: the values may be identical but the object is different: | ||
| Setting the same value again will also trigger an event. The values may be identical but the object is different: | ||
| ```js | ||
@@ -274,3 +274,3 @@ myState.arr = [1, 2, 3]; // change event triggered | ||
| It may be preferable to create a new named store with native values rather than use nested arrays and objects. | ||
| It may be preferable to create a new named **stateZ** object with native values rather than use nested arrays or objects. | ||
@@ -282,2 +282,2 @@ | ||
| Please consider [sponsorship](https://github.com/sponsors/craigbuckler) if you use **stateZ** commercially, require support or new features. | ||
| Please consider [sponsorship](https://github.com/sponsors/craigbuckler) if you use **stateZ** commercially, require support, or need new features. |
10900
4%