wc-context
Advanced tools
Comparing version 0.7.0 to 0.8.0
const orphanMap = {}; | ||
const resolved = Promise.resolve(); | ||
const orphanResolveQueue = { | ||
contexts: new Set(), | ||
running: false, | ||
add(context) { | ||
this.contexts.add(context); | ||
if (!this.running) { | ||
@@ -17,2 +17,3 @@ this.running = true; | ||
const event = sendContextEvent(orphan, context); | ||
if (event.detail.handled) { | ||
@@ -28,2 +29,3 @@ orphans.delete(orphan); | ||
} | ||
}; | ||
@@ -38,2 +40,3 @@ | ||
const orphans = orphanMap[name]; | ||
if (orphans) { | ||
@@ -55,3 +58,3 @@ orphans.delete(el); | ||
function addChildContext(el, name) { | ||
function registerProvidedContext(el, name, providedContexts) { | ||
const observerMap = el.__wcContextObserverMap || (el.__wcContextObserverMap = {}); | ||
@@ -63,6 +66,9 @@ const observers = observerMap[name] || (observerMap[name] = []); | ||
const targetEl = event.target; | ||
const value = el.__wcChildContext[name]; | ||
const oldValue = targetEl.__wcContext[name]; | ||
const value = providedContexts[name]; | ||
const context = targetEl.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
targetEl.__wcContext[name] = value; | ||
context[name] = value; | ||
if (targetEl.contextChangedCallback) { | ||
@@ -72,5 +78,7 @@ targetEl.contextChangedCallback(name, oldValue, value); | ||
} | ||
observers.push(targetEl); | ||
event.detail.handled = true; | ||
}); | ||
if (orphans && orphans.size) { | ||
@@ -81,15 +89,5 @@ orphanResolveQueue.add(name); | ||
function updateChildContext(el, value) { | ||
const childContext = el.__wcChildContext; | ||
Object.keys(value).forEach(propName => { | ||
const propValue = value[propName]; | ||
if (childContext[propName] !== propValue) { | ||
notifyContextChange(el, propName, propValue); | ||
} | ||
childContext[propName] = propValue; | ||
}); | ||
} | ||
function observeContext(el, name) { | ||
const event = sendContextEvent(el, name); | ||
if (!event.detail.handled) { | ||
@@ -107,7 +105,11 @@ addOrphan(el, name); | ||
const observers = observerMap && observerMap[name]; | ||
if (observers) { | ||
observers.forEach(observer => { | ||
const oldValue = observer.__wcContext[name]; | ||
const context = observer.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
observer.__wcContext[name] = value; | ||
context[name] = value; | ||
if (observer.contextChangedCallback) { | ||
@@ -121,35 +123,14 @@ observer.contextChangedCallback(name, oldValue, value); | ||
class PropMapper { | ||
constructor(property) { | ||
this.property = property; | ||
} | ||
} | ||
const initializedElements = new WeakSet(); | ||
function fromProp(property) { | ||
return new PropMapper(property); | ||
} | ||
const withContext = Base => { | ||
return class extends Base { | ||
constructor(...args) { | ||
var _temp; | ||
return _temp = super(...args), this.__wcContext = {}, this.__wcChildContext = {}, this.__wcChildContextInitialized = false, this.__wcMappedProps = {}, _temp; | ||
} | ||
get context() { | ||
return this.__wcContext; | ||
return this.__wcContext || (this.__wcContext = {}); | ||
} | ||
get childContext() { | ||
return this.__wcChildContext; | ||
} | ||
set childContext(value) { | ||
updateChildContext(this, value); | ||
} | ||
connectedCallback() { | ||
super.connectedCallback(); | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -159,13 +140,22 @@ observedContexts.forEach(context => observeContext(this, context)); | ||
if (!this.__wcChildContextInitialized) { | ||
const childContext = this.childContext; | ||
Object.keys(childContext).forEach(key => { | ||
const value = childContext[key]; | ||
if (value instanceof PropMapper) { | ||
this.__wcMappedProps[key] = value; | ||
childContext[key] = this[value.property]; | ||
} | ||
addChildContext(this, key); | ||
}); | ||
this.__wcChildContextInitialized = true; | ||
if (!initializedElements.has(this)) { | ||
const providedContextConfigs = this.constructor.providedContexts; | ||
if (providedContextConfigs) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
const mappedProps = this.__wcMappedProps || (this.__wcMappedProps = {}); | ||
Object.keys(providedContextConfigs).forEach(name => { | ||
const config = providedContextConfigs[name]; | ||
const property = typeof config === 'string' ? config : config.property; | ||
providedContexts[name] = property ? this[property] : config.value; | ||
if (property) { | ||
mappedProps[name] = property; | ||
} | ||
registerProvidedContext(this, name, providedContexts); | ||
}); | ||
} | ||
initializedElements.add(this); | ||
} | ||
@@ -177,2 +167,3 @@ } | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -185,16 +176,24 @@ observedContexts.forEach(context => unobserveContext(this, context)); | ||
const shouldChange = super.shouldUpdate(changedProperties); | ||
Object.keys(this.__wcMappedProps).forEach(contextKey => { | ||
const mapper = this.__wcMappedProps[contextKey]; | ||
if (changedProperties.has(mapper.property)) { | ||
const value = this[mapper.property]; | ||
notifyContextChange(this, contextKey, value); | ||
this.__wcChildContext[contextKey] = value; | ||
} | ||
}); | ||
const mappedProps = this.__wcMappedProps; | ||
if (mappedProps) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
Object.keys(mappedProps).forEach(contextName => { | ||
const property = mappedProps[contextName]; | ||
if (changedProperties.has(property)) { | ||
const value = this[property]; | ||
providedContexts[contextName] = value; | ||
notifyContextChange(this, contextName, value); | ||
} | ||
}); | ||
} | ||
return shouldChange; | ||
} | ||
}; | ||
}; | ||
export { withContext, fromProp }; | ||
export { withContext }; | ||
//# sourceMappingURL=lit-element.js.map |
{ | ||
"name": "wc-context", | ||
"version": "0.7.0", | ||
"version": "0.8.0", | ||
"description": "Simple context for HTML custom elements", | ||
@@ -5,0 +5,0 @@ "repository": "blikblum/wc-context", |
156
README.md
@@ -9,8 +9,160 @@ # wc-context | ||
✓ Small and fast<br> | ||
✓ Integrates with lit-element and skatejs<br> | ||
### Documentation | ||
### Usage | ||
* To be done | ||
> Warning: the interface may change in future | ||
The simplest way to use `wc-context` is through the `withContext` class mixin | ||
Live examples: | ||
* lit-element: [version 1](https://codesandbox.io/s/8n89qz95q2) / | ||
[version 2](https://codesandbox.io/s/wq6jyo3jvw) | ||
* skatejs: [version 1](https://codesandbox.io/s/xj1k8x936w) / | ||
[version 2](https://codesandbox.io/s/82q46lo3x8) | ||
#### Publishes a context | ||
```javascript | ||
import { withContext } from 'wc-context' | ||
class Provider extends withContext(HTMLElement) { | ||
static get providedContexts () { | ||
return { | ||
theme: { value: 'blue' } | ||
} | ||
} | ||
toggleTheme () { | ||
this.updateProvidedContext('theme', 'newtheme') | ||
} | ||
} | ||
``` | ||
#### Consumes a context | ||
```javascript | ||
import { withContext } from 'wc-context' | ||
class Consumer extends withContext(HTMLElement) { | ||
static get observedContexts () { | ||
return ['theme'] | ||
} | ||
contextChangedCallback(name, oldValue, value) { | ||
console.log( | ||
`theme changed from "${oldValue}" to "${value}"` | ||
); | ||
// updates el accordingly | ||
} | ||
connectedCallback () { | ||
super.connectedCallback() | ||
this.innerHTML = `<div>Theme is ${this.context.theme}</div>` | ||
} | ||
} | ||
``` | ||
#### lit-element and skatejs integration | ||
Along side the generic class mixin, `wc-context` provides specialized mixins that hooks into lit-element / skatejs reactivity system | ||
```javascript | ||
// @polymer/lit-element | ||
import { withContext, fromProp } from 'wc-context/lit-element' | ||
import { LitElement } from '@polymer/lit-element' | ||
const Component = withContext(LitElement) | ||
class Provider extends { | ||
static get properties () { | ||
return { | ||
value: {type: String} | ||
} | ||
} | ||
constructor () { | ||
super() | ||
this.childContext = { | ||
theme: fromProp('value') | ||
} | ||
} | ||
toggleTheme () { | ||
this.value = 'newtheme' | ||
} | ||
} | ||
``` | ||
```javascript | ||
// skatejs | ||
import withLit from '@skatejs/renderer-lit-html/dist/esnext' | ||
import { withUpdate, withRenderer } from 'skatejs/dist/esnext' | ||
import { withContext, fromProp, fromStateProp } from 'wc-context/skatejs' | ||
const Component = withLit(withContext(withUpdate(withRenderer(HTMLElement)))) | ||
class Provider extends { | ||
static get props () { | ||
return { | ||
altTheme: String | ||
} | ||
} | ||
constructor () { | ||
super() | ||
this.childContext = { | ||
theme: fromStateProp('value'), | ||
altTheme: fromProp('altTheme') | ||
} | ||
this.state = {value: 'blue'} | ||
this.altTheme = 'yellow' | ||
} | ||
toggleTheme () { | ||
this.state = {value: 'newtheme'} | ||
this.altTheme = 'newalttheme' | ||
} | ||
} | ||
``` | ||
#### Low level API | ||
`wc-context` also exports its low level functions that can be used to handle specific cases or create a new interface | ||
```javascript | ||
import { registerProvidedContext, notifyContextChange } from 'wc-context/core' | ||
// custom element that publishes an arbitrary context key and value | ||
class ContextProvider extends HTMLElement { | ||
connnectedCallback () { | ||
const providedContexts = this.__providedContexts || (this.__providedContexts = {}) | ||
providedContexts[this.key] = this.value | ||
registerProvidedContext(this, this.key, providedContexts) | ||
} | ||
set value (val) { | ||
const providedContexts = this.__providedContexts || (this.__providedContexts = {}) | ||
providedContexts[this.key] = val | ||
this.__value = val | ||
notifyContextChange(this, this.key, val) | ||
} | ||
get value () { | ||
return this.__value | ||
} | ||
} | ||
customElements.define('context-provider', ContextProvider) | ||
// later | ||
import { html } from 'lit-html' | ||
let theme = 'blue' | ||
html`<context-provider .key="theme" .value=${theme}> | ||
<div> | ||
<my-theme-consumer></my-theme-consumer> | ||
</div> | ||
</context-provider>` | ||
``` | ||
### License | ||
@@ -17,0 +169,0 @@ |
150
skatejs.js
const orphanMap = {}; | ||
const resolved = Promise.resolve(); | ||
const orphanResolveQueue = { | ||
contexts: new Set(), | ||
running: false, | ||
add(context) { | ||
this.contexts.add(context); | ||
if (!this.running) { | ||
@@ -17,2 +17,3 @@ this.running = true; | ||
const event = sendContextEvent(orphan, context); | ||
if (event.detail.handled) { | ||
@@ -28,2 +29,3 @@ orphans.delete(orphan); | ||
} | ||
}; | ||
@@ -38,2 +40,3 @@ | ||
const orphans = orphanMap[name]; | ||
if (orphans) { | ||
@@ -55,3 +58,3 @@ orphans.delete(el); | ||
function addChildContext(el, name) { | ||
function registerProvidedContext(el, name, providedContexts) { | ||
const observerMap = el.__wcContextObserverMap || (el.__wcContextObserverMap = {}); | ||
@@ -63,6 +66,9 @@ const observers = observerMap[name] || (observerMap[name] = []); | ||
const targetEl = event.target; | ||
const value = el.__wcChildContext[name]; | ||
const oldValue = targetEl.__wcContext[name]; | ||
const value = providedContexts[name]; | ||
const context = targetEl.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
targetEl.__wcContext[name] = value; | ||
context[name] = value; | ||
if (targetEl.contextChangedCallback) { | ||
@@ -72,5 +78,7 @@ targetEl.contextChangedCallback(name, oldValue, value); | ||
} | ||
observers.push(targetEl); | ||
event.detail.handled = true; | ||
}); | ||
if (orphans && orphans.size) { | ||
@@ -81,15 +89,5 @@ orphanResolveQueue.add(name); | ||
function updateChildContext(el, value) { | ||
const childContext = el.__wcChildContext; | ||
Object.keys(value).forEach(propName => { | ||
const propValue = value[propName]; | ||
if (childContext[propName] !== propValue) { | ||
notifyContextChange(el, propName, propValue); | ||
} | ||
childContext[propName] = propValue; | ||
}); | ||
} | ||
function observeContext(el, name) { | ||
const event = sendContextEvent(el, name); | ||
if (!event.detail.handled) { | ||
@@ -107,7 +105,11 @@ addOrphan(el, name); | ||
const observers = observerMap && observerMap[name]; | ||
if (observers) { | ||
observers.forEach(observer => { | ||
const oldValue = observer.__wcContext[name]; | ||
const context = observer.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
observer.__wcContext[name] = value; | ||
context[name] = value; | ||
if (observer.contextChangedCallback) { | ||
@@ -121,57 +123,14 @@ observer.contextChangedCallback(name, oldValue, value); | ||
class PropMapper { | ||
constructor(property) { | ||
this.property = property; | ||
} | ||
const initializedElements = new WeakSet(); | ||
getValue(el) { | ||
return el[this.property]; | ||
} | ||
propertyChanged(el, prevProps, prevState) { | ||
return el[this.property] !== prevProps[this.property]; | ||
} | ||
} | ||
class StatePropMapper extends PropMapper { | ||
getValue(el) { | ||
return el.state[this.property]; | ||
} | ||
propertyChanged(el, prevProps, prevState) { | ||
return el.state[this.property] !== prevState[this.property]; | ||
} | ||
} | ||
function fromProp(property) { | ||
return new PropMapper(property); | ||
} | ||
function fromStateProp(property) { | ||
return new StatePropMapper(property); | ||
} | ||
const withContext = Base => { | ||
return class extends Base { | ||
constructor(...args) { | ||
var _temp; | ||
return _temp = super(...args), this.__wcContext = {}, this.__wcChildContext = {}, this.__wcChildContextInitialized = false, this.__wcMappedProps = {}, _temp; | ||
} | ||
get context() { | ||
return this.__wcContext; | ||
return this.__wcContext || (this.__wcContext = {}); | ||
} | ||
get childContext() { | ||
return this.__wcChildContext; | ||
} | ||
set childContext(value) { | ||
updateChildContext(this, value); | ||
} | ||
connectedCallback() { | ||
super.connectedCallback(); | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -181,13 +140,22 @@ observedContexts.forEach(context => observeContext(this, context)); | ||
if (!this.__wcChildContextInitialized) { | ||
const childContext = this.childContext; | ||
Object.keys(childContext).forEach(key => { | ||
const value = childContext[key]; | ||
if (value instanceof PropMapper) { | ||
this.__wcMappedProps[key] = value; | ||
childContext[key] = value.getValue(this); | ||
} | ||
addChildContext(this, key); | ||
}); | ||
this.__wcChildContextInitialized = true; | ||
if (!initializedElements.has(this)) { | ||
const providedContextConfigs = this.constructor.providedContexts; | ||
if (providedContextConfigs) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
const mappedProps = this.__wcMappedProps || (this.__wcMappedProps = {}); | ||
Object.keys(providedContextConfigs).forEach(name => { | ||
const config = providedContextConfigs[name]; | ||
const property = typeof config === 'string' ? config : config.property; | ||
providedContexts[name] = property ? this[property] : config.value; | ||
if (property) { | ||
mappedProps[name] = property; | ||
} | ||
registerProvidedContext(this, name, providedContexts); | ||
}); | ||
} | ||
initializedElements.add(this); | ||
} | ||
@@ -199,2 +167,3 @@ } | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -205,17 +174,24 @@ observedContexts.forEach(context => unobserveContext(this, context)); | ||
updating(prevProps, prevState) { | ||
super.updating && super.updating(prevProps, prevState); | ||
Object.keys(this.__wcMappedProps).forEach(contextKey => { | ||
const mapper = this.__wcMappedProps[contextKey]; | ||
if (mapper.propertyChanged(this, prevProps, prevState)) { | ||
const value = mapper.getValue(this); | ||
notifyContextChange(this, contextKey, value); | ||
this.__wcChildContext[contextKey] = value; | ||
} | ||
}); | ||
updated(props) { | ||
super.updated(props); | ||
const mappedProps = this.__wcMappedProps; | ||
if (mappedProps) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
Object.keys(mappedProps).forEach(contextName => { | ||
const property = mappedProps[contextName]; | ||
if (property in props) { | ||
const value = this[property]; | ||
providedContexts[contextName] = value; | ||
notifyContextChange(this, contextName, value); | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
}; | ||
export { withContext, fromProp, fromStateProp }; | ||
export { withContext }; | ||
//# sourceMappingURL=skatejs.js.map |
const orphanMap = {}; | ||
const resolved = Promise.resolve(); | ||
const orphanResolveQueue = { | ||
contexts: new Set(), | ||
running: false, | ||
add(context) { | ||
this.contexts.add(context); | ||
if (!this.running) { | ||
@@ -17,2 +17,3 @@ this.running = true; | ||
const event = sendContextEvent(orphan, context); | ||
if (event.detail.handled) { | ||
@@ -28,2 +29,3 @@ orphans.delete(orphan); | ||
} | ||
}; | ||
@@ -38,2 +40,3 @@ | ||
const orphans = orphanMap[name]; | ||
if (orphans) { | ||
@@ -55,3 +58,3 @@ orphans.delete(el); | ||
function addChildContext(el, name) { | ||
function registerProvidedContext(el, name, providedContexts) { | ||
const observerMap = el.__wcContextObserverMap || (el.__wcContextObserverMap = {}); | ||
@@ -63,6 +66,9 @@ const observers = observerMap[name] || (observerMap[name] = []); | ||
const targetEl = event.target; | ||
const value = el.__wcChildContext[name]; | ||
const oldValue = targetEl.__wcContext[name]; | ||
const value = providedContexts[name]; | ||
const context = targetEl.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
targetEl.__wcContext[name] = value; | ||
context[name] = value; | ||
if (targetEl.contextChangedCallback) { | ||
@@ -72,5 +78,7 @@ targetEl.contextChangedCallback(name, oldValue, value); | ||
} | ||
observers.push(targetEl); | ||
event.detail.handled = true; | ||
}); | ||
if (orphans && orphans.size) { | ||
@@ -81,15 +89,5 @@ orphanResolveQueue.add(name); | ||
function updateChildContext(el, value) { | ||
const childContext = el.__wcChildContext; | ||
Object.keys(value).forEach(propName => { | ||
const propValue = value[propName]; | ||
if (childContext[propName] !== propValue) { | ||
notifyContextChange(el, propName, propValue); | ||
} | ||
childContext[propName] = propValue; | ||
}); | ||
} | ||
function observeContext(el, name) { | ||
const event = sendContextEvent(el, name); | ||
if (!event.detail.handled) { | ||
@@ -107,7 +105,11 @@ addOrphan(el, name); | ||
const observers = observerMap && observerMap[name]; | ||
if (observers) { | ||
observers.forEach(observer => { | ||
const oldValue = observer.__wcContext[name]; | ||
const context = observer.context; | ||
const oldValue = context[name]; | ||
if (oldValue !== value) { | ||
observer.__wcContext[name] = value; | ||
context[name] = value; | ||
if (observer.contextChangedCallback) { | ||
@@ -121,25 +123,20 @@ observer.contextChangedCallback(name, oldValue, value); | ||
const initializedElements = new WeakSet(); | ||
const withContext = Base => { | ||
return class extends Base { | ||
constructor(...args) { | ||
var _temp; | ||
return _temp = super(...args), this.__wcContext = {}, this.__wcChildContext = {}, this.__wcChildContextInitialized = false, _temp; | ||
} | ||
get context() { | ||
return this.__wcContext; | ||
return this.__wcContext || (this.__wcContext = {}); | ||
} | ||
get childContext() { | ||
return this.__wcChildContext; | ||
updateProvidedContext(name, value) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
providedContexts[name] = value; | ||
notifyContextChange(this, name, value); | ||
} | ||
set childContext(value) { | ||
updateChildContext(this, value); | ||
} | ||
connectedCallback() { | ||
super.connectedCallback && super.connectedCallback(); | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -149,8 +146,16 @@ observedContexts.forEach(context => observeContext(this, context)); | ||
if (!this.__wcChildContextInitialized) { | ||
const childContext = this.childContext; | ||
Object.keys(childContext).forEach(key => { | ||
addChildContext(this, key); | ||
}); | ||
this.__wcChildContextInitialized = true; | ||
if (!initializedElements.has(this)) { | ||
const providedContextConfigs = this.constructor.providedContexts; | ||
if (providedContextConfigs) { | ||
const providedContexts = this.__wcProvidedContexts || (this.__wcProvidedContexts = {}); | ||
Object.keys(providedContextConfigs).forEach(name => { | ||
const config = providedContextConfigs[name]; | ||
const property = typeof config === 'string' ? config : config.property; | ||
providedContexts[name] = property ? this[property] : config.value; | ||
registerProvidedContext(this, name, providedContexts); | ||
}); | ||
} | ||
initializedElements.add(this); | ||
} | ||
@@ -162,2 +167,3 @@ } | ||
const observedContexts = this.constructor.observedContexts; | ||
if (observedContexts) { | ||
@@ -167,2 +173,3 @@ observedContexts.forEach(context => unobserveContext(this, context)); | ||
} | ||
}; | ||
@@ -169,0 +176,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
52243
171
434