Comparing version 4.5.2 to 4.6.0-beta.0
@@ -8,3 +8,3 @@ | ||
function makeComponent(Container) { | ||
function makeComponent(Scheduler) { | ||
function component(renderer, baseElementOrOptions, options) { | ||
@@ -22,6 +22,6 @@ const BaseElement = (options || baseElementOrOptions || {}).baseElement || HTMLElement; | ||
if (useShadowDOM === false) { | ||
this._container = new Container(renderer, this); | ||
this._scheduler = new Scheduler(renderer, this); | ||
} else { | ||
this.attachShadow({ mode: "open", ...shadowRootInit}); | ||
this._container = new Container(renderer, this.shadowRoot, this); | ||
this._scheduler = new Scheduler(renderer, this.shadowRoot, this); | ||
} | ||
@@ -31,7 +31,7 @@ } | ||
connectedCallback() { | ||
this._container.update(); | ||
this._scheduler.update(); | ||
} | ||
disconnectedCallback() { | ||
this._container.teardown(); | ||
this._scheduler.teardown(); | ||
} | ||
@@ -55,3 +55,3 @@ | ||
value = newValue; | ||
this._container.update(); | ||
this._scheduler.update(); | ||
} | ||
@@ -89,3 +89,2 @@ }) | ||
return Element; | ||
@@ -92,0 +91,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { makeContainer } from './container.js'; | ||
import { makeScheduler } from './scheduler.js'; | ||
import { makeComponent } from './component.js'; | ||
@@ -6,7 +6,7 @@ import { makeContext } from './create-context.js'; | ||
function haunted({ render }) { | ||
const Container = makeContainer(render); | ||
const component = makeComponent(Container); | ||
const Scheduler = makeScheduler(render); | ||
const component = makeComponent(Scheduler); | ||
const createContext = makeContext(component); | ||
return { Container, component, createContext }; | ||
return { Scheduler, component, createContext }; | ||
} | ||
@@ -22,2 +22,3 @@ | ||
export { useRef } from './use-ref.js'; | ||
export { hook, Hook } from './hook.js'; | ||
export { hook, Hook } from './hook.js'; | ||
export { State } from './state.js'; |
@@ -5,5 +5,5 @@ import { current, notify } from './interface.js'; | ||
class Hook { | ||
constructor(id, el) { | ||
constructor(id, state) { | ||
this.id = id; | ||
this.el = el; | ||
this.el = this.state = state; | ||
} | ||
@@ -10,0 +10,0 @@ } |
@@ -5,3 +5,3 @@ import { html, render } from 'lit-html'; | ||
const { Container, component, createContext } = haunted({ | ||
const { Scheduler, component, createContext } = haunted({ | ||
render(what, where) { | ||
@@ -12,3 +12,3 @@ render(what, where); | ||
const virtual = makeVirtual(Container); | ||
const virtual = makeVirtual(Scheduler); | ||
@@ -15,0 +15,0 @@ export { |
@@ -9,4 +9,3 @@ const symbolFor = typeof Symbol === 'function' ? Symbol.for : str => str; | ||
export const effectsSymbol = symbolFor('haunted.effects'); | ||
export const contextSymbol = symbolFor('haunted.context'); | ||
export const contextEvent = 'haunted.context'; |
@@ -1,24 +0,16 @@ | ||
import { contextSymbol, contextEvent } from './symbols.js'; | ||
import { contextEvent } from './symbols.js'; | ||
import { hook, Hook } from './hook.js'; | ||
import { setEffects } from './use-effect.js'; | ||
function setContexts(el, consumer) { | ||
if(!(contextSymbol in el)) { | ||
el[contextSymbol] = []; | ||
} | ||
el[contextSymbol].push(consumer); | ||
} | ||
const useContext = hook(class extends Hook { | ||
constructor(id, el) { | ||
super(id, el); | ||
setContexts(el, this); | ||
constructor(id, state) { | ||
super(id, state); | ||
this._updater = this._updater.bind(this); | ||
this._ranEffect = false; | ||
this._unsubscribe = null; | ||
setEffects(el, this); | ||
setEffects(state, this); | ||
} | ||
update(Context) { | ||
if (this.el.virtual) { | ||
if (this.state.virtual) { | ||
throw new Error('can\'t be used with virtual components'); | ||
@@ -40,3 +32,3 @@ } | ||
this._subscribe(this.Context); | ||
this.el.update(); | ||
this.state.update(); | ||
} | ||
@@ -47,3 +39,3 @@ } | ||
this.value = value; | ||
this.el.update(); | ||
this.state.update(); | ||
} | ||
@@ -54,3 +46,3 @@ | ||
this.el.host.dispatchEvent(new CustomEvent(contextEvent, { | ||
this.state.host.dispatchEvent(new CustomEvent(contextEvent, { | ||
detail, // carrier | ||
@@ -57,0 +49,0 @@ bubbles: true, // to bubble up in tree |
import { effectsSymbol } from './symbols.js'; | ||
import { hook, Hook } from './hook.js'; | ||
function setEffects(el, cb) { | ||
if(!(effectsSymbol in el)) { | ||
el[effectsSymbol] = []; | ||
function setEffects(state, cb) { | ||
if(!(effectsSymbol in state)) { | ||
state[effectsSymbol] = []; | ||
} | ||
el[effectsSymbol].push(cb); | ||
state[effectsSymbol].push(cb); | ||
} | ||
const useEffect = hook(class extends Hook { | ||
constructor(id, el) { | ||
super(id, el); | ||
constructor(id, state) { | ||
super(id, state); | ||
this.values = false; | ||
setEffects(el, this); | ||
setEffects(state, this); | ||
} | ||
@@ -36,3 +36,3 @@ | ||
this.teardown(); | ||
this._teardown = this.callback.call(this.el); | ||
this._teardown = this.callback.call(this.state); | ||
} | ||
@@ -39,0 +39,0 @@ |
import { hook, Hook } from './hook.js'; | ||
const useMemo = hook(class extends Hook { | ||
constructor(id, el, fn, values) { | ||
super(id, el); | ||
constructor(id, state, fn, values) { | ||
super(id, state); | ||
this.value = fn(); | ||
@@ -7,0 +7,0 @@ this.values = values; |
import { hook, Hook } from './hook.js'; | ||
const useReducer = hook(class extends Hook { | ||
constructor(id, el, _, initialState) { | ||
super(id, el); | ||
constructor(id, state, _, initialState) { | ||
super(id, state); | ||
this.dispatch = this.dispatch.bind(this); | ||
@@ -17,3 +17,3 @@ this.state = initialState; | ||
this.state = this.reducer(this.state, action); | ||
this.el.update(); | ||
this.state.update(); | ||
} | ||
@@ -20,0 +20,0 @@ }); |
import { hook, Hook } from './hook.js'; | ||
const useState = hook(class extends Hook { | ||
constructor(id, el, initialValue) { | ||
super(id, el); | ||
constructor(id, state, initialValue) { | ||
super(id, state); | ||
this.updater = this.updater.bind(this); | ||
@@ -27,3 +27,3 @@ | ||
this.makeArgs(value); | ||
this.el.update(); | ||
this.state.update(); | ||
} | ||
@@ -30,0 +30,0 @@ |
@@ -5,7 +5,7 @@ import { directive } from 'lit-html'; | ||
function makeVirtual(Container) { | ||
function makeVirtual(Scheduler) { | ||
const partToContainer = new WeakMap(); | ||
const containerToPart = new WeakMap(); | ||
class DirectiveContainer extends Container { | ||
class DirectiveContainer extends Scheduler { | ||
constructor(renderer, part) { | ||
@@ -12,0 +12,0 @@ super(renderer, part); |
{ | ||
"name": "haunted", | ||
"version": "4.5.2", | ||
"version": "4.6.0-beta.0", | ||
"description": "Hooks for web components", | ||
@@ -5,0 +5,0 @@ "main": "lib/haunted.js", |
@@ -456,10 +456,10 @@ # Haunted 🦇 🎃 | ||
Most functionality can be achieved with the provided hooks above, but you can also create your own hooks for custom functionality. | ||
Most functionality can be achieved with the provided hooks above, but you can also create your own hooks for custom functionality like so: | ||
```html | ||
```js | ||
import { hook, Hook } from 'haunted'; | ||
const useMyHook = hook(class extends Hook { | ||
constructor(id, el) { | ||
super(id, el); | ||
constructor(id, state) { | ||
super(id, state); | ||
... | ||
@@ -475,2 +475,58 @@ } | ||
### State | ||
At its heart, Haunted is a container for state derived from hooks. The `component` and `virtual` signatures build on top of this state container. | ||
In order to use Haunted outside of its component types, such as to extend another custom element base class, you can use the `State` constructor. | ||
It has a signature of: `new State(update, [ hostElement ])`. | ||
> Note that the second argument `hostElement` is optional. If you want to use the `useContext` hook you will need to provide a host element, however. | ||
Here's an example how it can be used to run hooks code: | ||
```js | ||
import { State, useState } from 'haunted'; | ||
let state = new State(() => { | ||
update(); | ||
}); | ||
function update() { | ||
state.run(() => { | ||
const [count, setCount] = useState(0); | ||
console.log('count is', count); | ||
setTimeout(() => setCount(count + 1), 3000); | ||
}); | ||
} | ||
update(); | ||
``` | ||
The above will result in the count being incremented every 3 seconds and the current count being logged. | ||
A more practical example is integration with a custom element base class. Here's a simple integration with [LitElement](https://lit-element.polymer-project.org/): | ||
```js | ||
import { LitElement } from 'lit-element'; | ||
import { State } from 'haunted'; | ||
export default class LitHauntedElement extends LitElement { | ||
constructor() { | ||
super(); | ||
this.hauntedState = new State(() => this.requestUpdate(), this); | ||
} | ||
update(changedProperties) { | ||
this.hauntedState.run(() => super.update(changedProperties)); | ||
this.hauntedState.runEffects(); | ||
} | ||
} | ||
``` | ||
More example integrations can be found in [this gist](https://gist.github.com/matthewp/92c4daa6588eaef484c6f389d20d5700). | ||
### Function Signatures | ||
@@ -477,0 +533,0 @@ |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
61105
26
1552
544
1