@stencil/store
Advanced tools
Comparing version 1.0.0 to 1.0.1
export { createStore } from './store'; | ||
export { ObservableMap, StoreSubscriptionObject } from './types'; | ||
export { ObservableMap, Subscription } from './types'; |
@@ -23,4 +23,4 @@ 'use strict'; | ||
timeoutId = setTimeout(() => { | ||
timeoutId = null; | ||
fn.apply(null, args); | ||
timeoutId = 0; | ||
fn(...args); | ||
}, ms); | ||
@@ -40,5 +40,4 @@ }; | ||
const isConnected = (maybeElement) => !('isConnected' in maybeElement) || maybeElement.isConnected; | ||
const cleanupElements = debounce(async (map) => { | ||
const keys = Array.from(map.keys()); | ||
for (let key of keys) { | ||
const cleanupElements = debounce((map) => { | ||
for (let key of map.keys()) { | ||
map.set(key, map.get(key).filter(isConnected)); | ||
@@ -49,24 +48,23 @@ } | ||
const elmsToUpdate = new Map(); | ||
if (typeof core.getRenderingRef !== 'function') { | ||
if (typeof core.getRenderingRef === 'function') { | ||
// If we are not in a stencil project, we do nothing. | ||
// This function is not really exported by @stencil/core. | ||
return; | ||
on('get', (propName) => { | ||
const elm = core.getRenderingRef(); | ||
if (elm) { | ||
appendToMap(elmsToUpdate, propName, elm); | ||
} | ||
}); | ||
on('set', (propName) => { | ||
const elements = elmsToUpdate.get(propName); | ||
if (elements) { | ||
elmsToUpdate.set(propName, elements.filter(core.forceUpdate)); | ||
} | ||
cleanupElements(elmsToUpdate); | ||
}); | ||
on('reset', () => { | ||
elmsToUpdate.forEach((elms) => elms.forEach(core.forceUpdate)); | ||
cleanupElements(elmsToUpdate); | ||
}); | ||
} | ||
on('get', (propName) => { | ||
const elm = core.getRenderingRef(); | ||
if (elm) { | ||
appendToMap(elmsToUpdate, propName, elm); | ||
} | ||
}); | ||
on('set', (propName) => { | ||
const elements = elmsToUpdate.get(propName); | ||
if (elements) { | ||
elmsToUpdate.set(propName, elements.filter(core.forceUpdate)); | ||
} | ||
cleanupElements(elmsToUpdate); | ||
}); | ||
on('reset', () => { | ||
elmsToUpdate.forEach((elms) => elms.forEach(core.forceUpdate)); | ||
cleanupElements(elmsToUpdate); | ||
}); | ||
}; | ||
@@ -76,11 +74,13 @@ | ||
let states = new Map(Object.entries(defaultState !== null && defaultState !== void 0 ? defaultState : {})); | ||
const setListeners = []; | ||
const getListeners = []; | ||
const resetListeners = []; | ||
const handlers = { | ||
get: [], | ||
set: [], | ||
reset: [], | ||
}; | ||
const reset = () => { | ||
states = new Map(Object.entries(defaultState !== null && defaultState !== void 0 ? defaultState : {})); | ||
resetListeners.forEach((cb) => cb()); | ||
handlers.reset.forEach((cb) => cb()); | ||
}; | ||
const get = (propName) => { | ||
getListeners.forEach((cb) => cb(propName)); | ||
handlers.get.forEach((cb) => cb(propName)); | ||
return states.get(propName); | ||
@@ -92,6 +92,6 @@ }; | ||
states.set(propName, value); | ||
setListeners.forEach((cb) => cb(propName, value, oldValue)); | ||
handlers.set.forEach((cb) => cb(propName, value, oldValue)); | ||
} | ||
}; | ||
const state = (window.Proxy === undefined | ||
const state = (typeof Proxy === 'undefined' | ||
? {} | ||
@@ -102,2 +102,14 @@ : new Proxy(defaultState, { | ||
}, | ||
ownKeys(_) { | ||
return Array.from(states.keys()); | ||
}, | ||
getOwnPropertyDescriptor() { | ||
return { | ||
enumerable: true, | ||
configurable: true, | ||
}; | ||
}, | ||
has(_, propName) { | ||
return states.has(propName); | ||
}, | ||
set(_, propName, value) { | ||
@@ -109,16 +121,3 @@ set(propName, value); | ||
const on = (eventName, callback) => { | ||
let listeners = setListeners; | ||
if (eventName === 'set') { | ||
listeners = setListeners; | ||
} | ||
else if (eventName === 'get') { | ||
listeners = getListeners; | ||
} | ||
else if (eventName === 'reset') { | ||
listeners = resetListeners; | ||
} | ||
else { | ||
throw new Error(`Unknown event ${eventName}`); | ||
} | ||
listeners.push(callback); | ||
handlers[eventName].push(callback); | ||
}; | ||
@@ -131,10 +130,5 @@ const onChange = (propName, cb) => { | ||
}); | ||
on('reset', () => { | ||
cb(defaultState[propName]); | ||
}); | ||
on('reset', () => cb(defaultState[propName])); | ||
}; | ||
const use = (...subscriptions) => { | ||
subscriptions.forEach(subscribe); | ||
}; | ||
const subscribe = (subscription) => { | ||
const use = (...subscriptions) => subscriptions.forEach((subscription) => { | ||
if (subscription.set) { | ||
@@ -149,3 +143,3 @@ on('set', subscription.set); | ||
} | ||
}; | ||
}); | ||
return { | ||
@@ -152,0 +146,0 @@ state, |
@@ -0,1 +1,6 @@ | ||
export interface Handlers<T> { | ||
set: SetEventHandler<T>[]; | ||
get: GetEventHandler<T>[]; | ||
reset: ResetEventHandler[]; | ||
} | ||
export declare type SetEventHandler<StoreType> = (key: keyof StoreType, newValue: any, oldValue: any) => void; | ||
@@ -12,3 +17,3 @@ export declare type GetEventHandler<StoreType> = (key: keyof StoreType) => void; | ||
} | ||
export interface StoreSubscriptionObject<StoreType> { | ||
export interface Subscription<StoreType> { | ||
get?<KeyFromStoreType extends keyof StoreType>(key: KeyFromStoreType): void; | ||
@@ -76,3 +81,3 @@ set?<KeyFromStoreType extends keyof StoreType>(key: KeyFromStoreType, newValue: StoreType[KeyFromStoreType], oldValue: StoreType[KeyFromStoreType]): void; | ||
*/ | ||
use(...plugins: StoreSubscriptionObject<T>[]): void; | ||
use(...plugins: Subscription<T>[]): void; | ||
} |
export declare const appendToMap: <K, V>(map: Map<K, V[]>, propName: K, value: V) => void; | ||
export declare const debounce: <T extends (...args: any) => any>(fn: T, ms: number) => (...args: Parameters<T>) => void; | ||
export declare const forMs: (ms: number) => Promise<void>; | ||
export declare const debounce: <T extends (...args: any[]) => any>(fn: T, ms: number) => (...args: Parameters<T>) => void; |
{ | ||
"name": "@stencil/store", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Store is a lightweight shared state library by the StencilJS core team. Implements a simple key/value map that efficiently re-renders components when necessary.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -15,3 +15,3 @@ # @stencil/store | ||
``` | ||
npm install @stencil/store | ||
npm install @stencil/store --save-dev | ||
``` | ||
@@ -43,3 +43,3 @@ | ||
import { Component, h } from '@stencil/core'; | ||
import store from '../store'; | ||
import state from '../store'; | ||
@@ -52,3 +52,3 @@ @Component({ | ||
componentWillLoad() { | ||
setInterval(() => store.seconds++, 1000); | ||
setInterval(() => state.seconds++, 1000); | ||
} | ||
@@ -62,5 +62,5 @@ | ||
<p> | ||
Seconds: {store.seconds} | ||
Seconds: {state.seconds} | ||
<br /> | ||
Squared Clicks: {store.squaredClicks} | ||
Squared Clicks: {state.squaredClicks} | ||
</p> | ||
@@ -75,4 +75,4 @@ </p> | ||
return ( | ||
<button onClick={() => store.clicks++}> | ||
{store.clicks} | ||
<button onClick={() => state.clicks++}> | ||
{state.clicks} | ||
</button> | ||
@@ -120,1 +120,15 @@ ); | ||
Use the given subscriptions in the store. A subscription is an object that defines one or more of the properties `get`, `set` or `reset`. | ||
## Testing | ||
Like any global state library, state should be reset between each spec test. | ||
Use the `reset()` API in the `beforeEach` hook. | ||
```ts | ||
import store from '../store'; | ||
beforeEach(() => { | ||
store.reset(); | ||
}); | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16810
129
385