wc-context
Advanced tools
Comparing version 0.13.0 to 0.14.0
@@ -1,4 +0,101 @@ | ||
import { ContextConsumer } from './consumer.js' | ||
import { ContextProvider } from './provider.js' | ||
import { | ||
observeContext, | ||
unobserveContext, | ||
onContextObserve, | ||
registerContext, | ||
updateContext, | ||
} from './core.js' | ||
function setValue(host, value, instance) { | ||
instance._value = value | ||
if (typeof instance.callback === 'function') { | ||
instance.callback.call(host, value) | ||
} else { | ||
host.requestUpdate() | ||
} | ||
} | ||
class ContextConsumer { | ||
constructor(host, context, callback) { | ||
host.addController(this) | ||
this.host = host | ||
this.context = context | ||
this.callback = callback | ||
this._value = undefined | ||
} | ||
get value() { | ||
return this._value | ||
} | ||
hostConnected() { | ||
observeContext(this.host, this.context, this, setValue) | ||
} | ||
hostDisconnected() { | ||
unobserveContext(this.host, this.context) | ||
} | ||
} | ||
function getFromValue(host, instance) { | ||
return instance._value | ||
} | ||
class ContextProvider { | ||
constructor(host, context, initialValue) { | ||
if (typeof host.addController === 'function') { | ||
host.addController(this) | ||
} | ||
this.host = host | ||
this.context = context | ||
this._value = initialValue | ||
this._initialized = false | ||
this._finalized = false | ||
registerContext(host, context, this, getFromValue) | ||
onContextObserve(host, context, () => { | ||
if (!this._initialized) { | ||
this._initialized = true | ||
this.initialize() | ||
} | ||
}) | ||
} | ||
get value() { | ||
return this._value | ||
} | ||
set value(value) { | ||
this._value = value | ||
updateContext(this.host, this.context) | ||
} | ||
connect() { | ||
if (this._finalized) { | ||
this.initialize() | ||
this._finalized = false | ||
this._initialized = true | ||
} | ||
} | ||
disconnect() { | ||
if (this._initialized) { | ||
this._initialized = false | ||
this._finalized = true | ||
this.finalize() | ||
} | ||
} | ||
hostConnected() { | ||
this.connect() | ||
} | ||
hostDisconnected() { | ||
this.disconnect() | ||
} | ||
initialize() {} | ||
finalize() {} | ||
} | ||
export { ContextConsumer, ContextProvider } |
134
core.js
@@ -0,1 +1,3 @@ | ||
const noContext = Symbol('noContext') | ||
const orphanMap = {} | ||
@@ -16,7 +18,5 @@ | ||
orphans.forEach(({ setter, payload }, orphan) => { | ||
const event = sendContextEvent(orphan, context, payload, setter) | ||
const provider = event.detail.provider | ||
if (provider) { | ||
const handled = sendContextEvent(orphan, context, payload, setter) | ||
if (handled) { | ||
orphans.delete(orphan) | ||
registerProvider(orphan, context, provider) | ||
} | ||
@@ -44,21 +44,34 @@ }) | ||
export class ContextRequestEvent extends Event { | ||
constructor(context, callback, subscribe) { | ||
super('context-request', { | ||
bubbles: true, | ||
cancelable: true, | ||
composed: true, | ||
}) | ||
this.context = context | ||
this.callback = callback | ||
this.subscribe = subscribe | ||
} | ||
} | ||
function sendContextEvent(consumer, context, payload, setter) { | ||
const event = new CustomEvent(`context-request-${context}`, { | ||
detail: { setter, payload, consumer }, | ||
bubbles: true, | ||
cancelable: true, | ||
composed: true, | ||
}) | ||
let handled | ||
const callback = (value, unsubscribe) => { | ||
if (!handled) { | ||
registerProvider(consumer, context, unsubscribe) | ||
} | ||
setter(consumer, value, payload) | ||
handled = true | ||
} | ||
const event = new ContextRequestEvent(context, callback, true) | ||
consumer.dispatchEvent(event) | ||
return event | ||
return handled | ||
} | ||
let contextCount = 0 | ||
function createContext(name) { | ||
function createContext(key) { | ||
return { | ||
id: `${name}${++contextCount}`, | ||
name, | ||
key, | ||
toString() { | ||
return this.id | ||
return this.key | ||
}, | ||
@@ -84,10 +97,26 @@ } | ||
const orphans = orphanMap[context] | ||
provider.addEventListener(`context-request-${context}`, (event) => { | ||
provider.addEventListener(`context-request`, (event) => { | ||
const { target, callback, subscribe } = event | ||
if (event.context !== context || typeof callback !== 'function') { | ||
return | ||
} | ||
event.stopPropagation() | ||
const value = getProviderValue(provider, providedContexts[context]) | ||
const { setter, payload, consumer } = event.detail | ||
setter(consumer, value, payload) | ||
observers.push({ consumer, setter, payload }) | ||
runListeners(provider, context, 'observe', observers.length) | ||
event.detail.provider = provider | ||
if (subscribe || value === noContext) { | ||
const unsubscribe = () => { | ||
removeObserver(provider, context, target) | ||
} | ||
observers.push({ | ||
consumer: target, | ||
callback, | ||
unsubscribe, | ||
once: !subscribe, | ||
}) | ||
if (value !== noContext) { | ||
callback(value, unsubscribe) | ||
} | ||
runListeners(provider, context, 'observe', observers.length) | ||
} else { | ||
callback(value) | ||
} | ||
}) | ||
@@ -120,8 +149,15 @@ if (orphans && orphans.size) { | ||
if (value === noContext) { | ||
return | ||
} | ||
const observers = observerMap && observerMap[context] | ||
if (observers) { | ||
observers.forEach(({ consumer, setter, payload }) => { | ||
setter(consumer, value, payload) | ||
}) | ||
} | ||
// if we got here, observers is necessarily defined | ||
observers.forEach(({ consumer, callback, unsubscribe, once }) => { | ||
if (once) { | ||
unsubscribe() | ||
unsubscribe = undefined | ||
} | ||
callback.call(consumer, value, unsubscribe) | ||
}) | ||
} | ||
@@ -163,7 +199,4 @@ function consumerSetter(consumer, value, name) { | ||
) { | ||
const event = sendContextEvent(consumer, context, payload, setter) | ||
const provider = event.detail.provider | ||
if (provider) { | ||
registerProvider(consumer, context, provider) | ||
} else { | ||
const handled = sendContextEvent(consumer, context, payload, setter) | ||
if (!handled) { | ||
addOrphan(consumer, context, payload, setter) | ||
@@ -174,15 +207,11 @@ } | ||
function removeObserver(provider, context, consumer) { | ||
if (provider) { | ||
const observerMap = provider.__wcContextObserverMap | ||
if (observerMap) { | ||
const observers = observerMap[context] | ||
const consumerIndex = observers.findIndex( | ||
(observer) => observer.consumer === consumer | ||
) | ||
if (consumerIndex !== -1) { | ||
observers.splice(consumerIndex, 1) | ||
} | ||
runListeners(provider, context, 'unobserve', observers.length) | ||
} | ||
const observerMap = provider.__wcContextObserverMap | ||
const observers = observerMap[context] | ||
const consumerIndex = observers.findIndex( | ||
(observer) => observer.consumer === consumer | ||
) | ||
if (consumerIndex !== -1) { | ||
observers.splice(consumerIndex, 1) | ||
} | ||
runListeners(provider, context, 'unobserve', observers.length) | ||
} | ||
@@ -193,3 +222,7 @@ | ||
if (providerMap) { | ||
removeObserver(providerMap[context], context, consumer) | ||
const unsubscribe = providerMap[context] | ||
if (unsubscribe) { | ||
unsubscribe() | ||
providerMap[context] = undefined | ||
} | ||
} | ||
@@ -223,3 +256,11 @@ | ||
async function getContext(consumer, context) { | ||
return new Promise((resolve) => { | ||
const event = new ContextRequestEvent(context, resolve, false) | ||
consumer.dispatchEvent(event) | ||
}) | ||
} | ||
export { | ||
noContext, | ||
createContext, | ||
@@ -234,2 +275,3 @@ registerContext, | ||
onContextUnobserve, | ||
getContext, | ||
} |
{ | ||
"name": "wc-context", | ||
"version": "0.13.0", | ||
"version": "0.14.0", | ||
"description": "Context for HTML custom elements / web components", | ||
@@ -19,3 +19,3 @@ "repository": "blikblum/wc-context", | ||
"type": "module", | ||
"main": "wc-context.js", | ||
"main": "core.js", | ||
"files": [ | ||
@@ -27,3 +27,3 @@ "context-provider.js", | ||
"controllers.js", | ||
"wc-context.js" | ||
"mixin.js" | ||
], | ||
@@ -44,7 +44,9 @@ "jest": { | ||
"lit": "^2.6.1", | ||
"prettier": "^2.5.1" | ||
"prettier": "^2.5.1", | ||
"vitepress": "^1.0.0-alpha.46", | ||
"vue": "^3.2.47" | ||
}, | ||
"exports": { | ||
".": "./wc-context.js", | ||
"./core.js": "./core.js", | ||
".": "./core.js", | ||
"./mixin.js": "./mixin.js", | ||
"./lit.js": "./lit.js", | ||
@@ -57,2 +59,5 @@ "./lit": "./lit.js", | ||
"scripts": { | ||
"docs:dev": "vitepress dev docs", | ||
"docs:build": "vitepress build docs", | ||
"docs:preview": "vitepress preview docs", | ||
"format": "prettier lit-element.js lit.js wc-context.js core.js test --write", | ||
@@ -59,0 +64,0 @@ "lint": "eslint lit-element.js lit.js wc-context.js core.js test", |
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
24571
546
9