@stencil/store
Advanced tools
Comparing version 0.2.1 to 0.3.0
@@ -16,20 +16,2 @@ 'use strict'; | ||
}; | ||
const toSubscription = (subscription) => { | ||
if (typeof subscription === 'function') { | ||
return subscription; | ||
} | ||
const hasGet = 'get' in subscription; | ||
const hasSet = 'set' in subscription; | ||
const hasReset = 'reset' in subscription; | ||
return (action, propNameOrStore, newValue, oldValue) => { | ||
switch (action) { | ||
case 'get': | ||
return hasGet && subscription.get(propNameOrStore); | ||
case 'set': | ||
return hasSet && subscription.set(propNameOrStore, newValue, oldValue); | ||
case 'reset': | ||
return hasReset && subscription.reset(); | ||
} | ||
}; | ||
}; | ||
const debounce = (fn, ms) => { | ||
@@ -64,3 +46,3 @@ let timeoutId; | ||
}, 2000); | ||
const stencilSubscription = ({ subscribe }) => { | ||
const stencilSubscription = ({ on }) => { | ||
const elmsToUpdate = new Map(); | ||
@@ -72,20 +54,19 @@ if (typeof core.getRenderingRef !== 'function') { | ||
} | ||
subscribe({ | ||
get(propName) { | ||
const elm = core.getRenderingRef(); | ||
if (elm) { | ||
appendToMap(elmsToUpdate, propName, elm); | ||
} | ||
}, | ||
reset() { | ||
elmsToUpdate.forEach(elms => elms.forEach(core.forceUpdate)); | ||
}, | ||
set(propName) { | ||
const elements = elmsToUpdate.get(propName); | ||
if (elements) { | ||
elmsToUpdate.set(propName, elements.filter(core.forceUpdate)); | ||
} | ||
}, | ||
on('get', propName => { | ||
const elm = core.getRenderingRef(); | ||
if (elm) { | ||
appendToMap(elmsToUpdate, propName, elm); | ||
} | ||
}); | ||
subscribe(() => cleanupElements(elmsToUpdate)); | ||
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); | ||
}); | ||
}; | ||
@@ -95,9 +76,11 @@ | ||
let states = new Map(Object.entries((defaultState !== null && defaultState !== void 0 ? defaultState : {}))); | ||
const subscriptions = []; | ||
const setListeners = []; | ||
const getListeners = []; | ||
const resetListeners = []; | ||
const reset = () => { | ||
states = new Map(Object.entries((defaultState !== null && defaultState !== void 0 ? defaultState : {}))); | ||
subscriptions.forEach(s => s('reset')); | ||
resetListeners.forEach(cb => cb()); | ||
}; | ||
const get = (propName) => { | ||
subscriptions.forEach(s => s('get', propName)); | ||
getListeners.forEach(cb => cb(propName)); | ||
return states.get(propName); | ||
@@ -109,3 +92,3 @@ }; | ||
states.set(propName, value); | ||
subscriptions.forEach(s => s('set', propName, value, oldValue)); | ||
setListeners.forEach(cb => cb(propName, value, oldValue)); | ||
} | ||
@@ -122,41 +105,52 @@ }; | ||
}); | ||
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); | ||
}; | ||
const onChange = (propName, cb) => { | ||
on('set', (key, newValue) => { | ||
if (key === propName) { | ||
cb(newValue); | ||
} | ||
}); | ||
on('reset', () => { | ||
cb(defaultState[propName]); | ||
}); | ||
}; | ||
const use = (...subscriptions) => { | ||
subscriptions.forEach(subscribe); | ||
}; | ||
const subscribe = (subscription) => { | ||
subscriptions.push(toSubscription(subscription)); | ||
if (subscription.set) { | ||
on('set', subscription.set); | ||
} | ||
if (subscription.get) { | ||
on('get', subscription.get); | ||
} | ||
if (subscription.reset) { | ||
on('reset', subscription.reset); | ||
} | ||
}; | ||
return { | ||
/** | ||
* Proxied object that will detect dependencies and call | ||
* the subscriptions and computed properties. | ||
* | ||
* If available, it will detect from which Stencil Component | ||
* it was called and rerender it when the property changes. | ||
*/ | ||
state, | ||
/** | ||
* Only useful if you need to support IE11. | ||
* | ||
* @example | ||
* const { state, get } = createStore({ hola: 'hello', adios: 'goodbye' }); | ||
* console.log(state.hola); // If you don't need to support IE11, use this way. | ||
* console.log(get('hola')); // If you need to support IE11, use this other way. | ||
*/ | ||
get, | ||
/** | ||
* Only useful if you need to support IE11. | ||
* | ||
* @example | ||
* const { state, get } = createStore({ hola: 'hello', adios: 'goodbye' }); | ||
* state.hola = 'ola'; // If you don't need to support IE11, use this way. | ||
* set('hola', 'ola')); // If you need to support IE11, use this other way. | ||
*/ | ||
set, | ||
/** | ||
* Register a subscription that will be called whenever the user gets, sets, or | ||
* resets a value. | ||
*/ | ||
on, | ||
onChange, | ||
use, | ||
reset, | ||
// Deprecated | ||
subscribe, | ||
/** | ||
* Resets the state to its original state. | ||
*/ | ||
reset, | ||
}; | ||
@@ -171,15 +165,13 @@ }; | ||
const computedSubscription = ({ get, set, subscribe, }) => { | ||
const computedSubscription = ({ get, set, on }) => { | ||
const computedStates = new Map(); | ||
subscribe({ | ||
reset() { | ||
computedStates.forEach(computeds => computeds.forEach(h => h())); | ||
}, | ||
set(propName) { | ||
const computed = computedStates.get(propName); | ||
if (computed) { | ||
computed.forEach(h => h()); | ||
} | ||
}, | ||
on('reset', () => { | ||
computedStates.forEach(computeds => computeds.forEach(h => h())); | ||
}); | ||
on('set', propName => { | ||
const computed = computedStates.get(propName); | ||
if (computed) { | ||
computed.forEach(h => h()); | ||
} | ||
}); | ||
return (gen) => { | ||
@@ -186,0 +178,0 @@ const states = new Proxy({}, { |
import { ComputedReturn, ObservableMap } from '../types'; | ||
export declare const computedSubscription: <T>({ get, set, subscribe, }: Pick<ObservableMap<T>, "set" | "get" | "subscribe">) => ComputedReturn<T>; | ||
export declare const computedSubscription: <T>({ get, set, on }: ObservableMap<T>) => ComputedReturn<T>; |
import { ObservableMap } from '../types'; | ||
export declare const stencilSubscription: <T>({ subscribe }: Pick<ObservableMap<T>, "subscribe">) => void; | ||
export declare const stencilSubscription: <T>({ on }: ObservableMap<T>) => void; |
@@ -0,1 +1,12 @@ | ||
export declare type SetEventHandler<StoreType> = (key: keyof StoreType, newValue: any, oldValue: any) => void; | ||
export declare type GetEventHandler<StoreType> = (key: keyof StoreType) => void; | ||
export declare type ResetEventHandler = () => void; | ||
export interface OnHandler<StoreType> { | ||
(eventName: 'set', callback: SetEventHandler<StoreType>): void; | ||
(eventName: 'get', callback: GetEventHandler<StoreType>): void; | ||
(eventName: 'reset', callback: ResetEventHandler): void; | ||
} | ||
export interface OnChangeHandler<StoreType> { | ||
<Key extends keyof StoreType>(propName: Key, cb: (newValue: StoreType[Key]) => void): void; | ||
} | ||
export interface StoreSubscription<StoreType> { | ||
@@ -18,7 +29,54 @@ <KeyFromStoreType extends keyof StoreType>(action: 'set', key: KeyFromStoreType, newValue: StoreType[KeyFromStoreType], oldValue: StoreType[KeyFromStoreType]): void; | ||
export interface ObservableMap<T> { | ||
/** | ||
* Proxied object that will detect dependencies and call | ||
* the subscriptions and computed properties. | ||
* | ||
* If available, it will detect from which Stencil Component | ||
* it was called and rerender it when the property changes. | ||
*/ | ||
state: T; | ||
/** | ||
* Only useful if you need to support IE11. | ||
* | ||
* @example | ||
* const { state, get } = createStore({ hola: 'hello', adios: 'goodbye' }); | ||
* console.log(state.hola); // If you don't need to support IE11, use this way. | ||
* console.log(get('hola')); // If you need to support IE11, use this other way. | ||
*/ | ||
get: Getter<T>; | ||
/** | ||
* Only useful if you need to support IE11. | ||
* | ||
* @example | ||
* const { state, get } = createStore({ hola: 'hello', adios: 'goodbye' }); | ||
* state.hola = 'ola'; // If you don't need to support IE11, use this way. | ||
* set('hola', 'ola')); // If you need to support IE11, use this other way. | ||
*/ | ||
set: Setter<T>; | ||
reset: () => void; | ||
subscribe(subscription: StoreSubscription<T> | StoreSubscriptionObject<T>): void; | ||
/** | ||
* Register a event listener, you can listen to `set`, `get` and `reset` events. | ||
* | ||
* @example | ||
* store.on('set', (prop, value) => { | ||
* console.log(`Prop ${prop} changed to: ${value}`); | ||
* }); | ||
*/ | ||
on: OnHandler<T>; | ||
/** | ||
* Easily listen for value changes of the specified key. | ||
*/ | ||
onChange: OnChangeHandler<T>; | ||
/** | ||
* Resets the state to its original state. | ||
*/ | ||
reset(): void; | ||
/** | ||
* Registers a subscription that will be called whenever the user gets, sets, or | ||
* resets a value. | ||
*/ | ||
use(...plugins: StoreSubscriptionObject<T>[]): void; | ||
/** | ||
* @deprecated Use `use()` instead. | ||
*/ | ||
subscribe(subscription: StoreSubscriptionObject<T>): void; | ||
} | ||
@@ -25,0 +83,0 @@ export interface ComputedReturn<T> { |
@@ -1,5 +0,3 @@ | ||
import { StoreSubscription, StoreSubscriptionObject } from './types'; | ||
export declare const appendToMap: <K, V>(map: Map<K, V[]>, propName: K, value: V) => void; | ||
export declare const toSubscription: <T>(subscription: StoreSubscription<T> | StoreSubscriptionObject<T>) => StoreSubscription<T>; | ||
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>; |
{ | ||
"name": "@stencil/store", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -14,3 +14,3 @@ # @stencil/store | ||
const { state, subscribe } = createStore({ | ||
const { state, onChange } = createStore({ | ||
'clicks': 0, | ||
@@ -24,5 +24,4 @@ 'seconds': 0, | ||
// Subscribe is only executed when 'seconds' and 'click' changes! | ||
subscribe(state => { | ||
state.sum = state.seconds + state.clicks; | ||
state.squaredClicks = state.seconds ** 2; | ||
onChange('clicks', value => { | ||
state.squaredClicks = value ** 2; | ||
}); | ||
@@ -29,0 +28,0 @@ |
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
17799
477
65