JSFiddle - React, Tailwind, and code Playground
HTML
Select your side:
<select onchange="updateText('side', event)">
<option value="---">---</option>
<option value="Good">Good</option>
<option value="Evil">Evil</option>
<option value="Noop">noop</option>
</select>
<fieldset>
The good one:
<p s-text="goodCharacter"></p>
<input type="text" s-model="goodCharacter" oninput="updateText('goodCharacter', event)"/>
</fieldset>
<fieldset>
The evil one:
<p s-text="evilCharacter"></p>
<input type="text" s-model="evilCharacter" oninput="updateText('evilCharacter', event)"/>
</fieldset>
<h3>Your character:</h3>
<p s-text="selectedCharacter"></p>
<label>Sentence length:</label>
<strong s-text="selectedCharacterSentenceLength"></strong>
JavaScript
function Seer (config) {
let signals = {}
let Dep = {
// Name of the currently evaluated computed value
// Doesn’t get overriden even if it depends on other computed values
target: null,
// Stores dependency keys of computed values
subs: {},
depend (deps, dep) {
// Add the computed value as depending on this value
// if not yet added
if (!deps.includes(this.target)) {
deps.push(this.target)
}
// Add this value as a dependency of the computed value
// if not yet added
if (!Dep.subs[this.target].includes(dep)) {
Dep.subs[this.target].push(dep)
}
},
getValidDeps (deps, key) {
// Filter only valid dependencies by removing dead dependencies
// that were not used during last computation
return deps.filter(dep => this.subs[dep].includes(key))
},
notifyDeps (deps) {
// notify all existing deps
deps.forEach(notify)
}
}
observeData(config.data)
subscribeWatchers(config.watch, config.data)
return {
data: config.data,
observe,
notify
}
function subscribeWatchers(watchers, context) {
for (let key in watchers) {
if (watchers.hasOwnProperty(key)) {
observe(key, watchers[key].bind(context))
}
}
}
function observe (property, signalHandler) {
if(!signals[property]) signals[property] = []
signals[property].push(signalHandler)
}
function notify (signal) {
if(!signals[signal] || signals[signal].length < 1) return
signals[signal].forEach(signalHandler => signalHandler())
}
function makeReactive (obj, key, computeFunc) {
let deps = []
let val = obj[key]
Object.defineProperty(obj, key, {
get () {
// Run only when getting within a computed value context
if (Dep.target) {
Dep.depend(deps, key)
}
return val
},
set (newVal) {
val = newVal
// Clean up and notify valid deps
...