@manyducks.co/dolla 2.0.0-alpha.64 → 2.0.0-alpha.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/core/app.d.ts +24 -0
  2. package/dist/core/index.d.ts +3 -2
  3. package/dist/core/markup.d.ts +9 -1
  4. package/dist/core/nodes/element.d.ts +1 -0
  5. package/dist/core/scheduler.d.ts +12 -4
  6. package/dist/core/signals.d.ts +10 -9
  7. package/dist/core/views/portal.d.ts +17 -0
  8. package/dist/hooks/index.d.ts +21 -5
  9. package/dist/hooks.js +27 -21
  10. package/dist/hooks.js.map +1 -1
  11. package/dist/http.js +1 -1
  12. package/dist/i18n.js +3 -3
  13. package/dist/index-BEDDzyd9.js +556 -0
  14. package/dist/index-BEDDzyd9.js.map +1 -0
  15. package/dist/index.js +125 -70
  16. package/dist/index.js.map +1 -1
  17. package/dist/jsx-dev-runtime.js +1 -1
  18. package/dist/jsx-runtime.js +1 -1
  19. package/dist/{logger-B7RBYtzP.js → logger-CmXtRdEI.js} +7 -7
  20. package/dist/{logger-B7RBYtzP.js.map → logger-CmXtRdEI.js.map} +1 -1
  21. package/dist/markup-DjDexAN5.js +1179 -0
  22. package/dist/markup-DjDexAN5.js.map +1 -0
  23. package/dist/router/hooks.d.ts +2 -0
  24. package/dist/router/index.d.ts +1 -0
  25. package/dist/router/router.d.ts +1 -0
  26. package/dist/router.js +3 -5
  27. package/dist/router.js.map +1 -1
  28. package/dist/{signals-DbDmN2gr.js → signals-CkfFHd0d.js} +264 -255
  29. package/dist/signals-CkfFHd0d.js.map +1 -0
  30. package/dist/typeChecking-_dGK_0uR.js +62 -0
  31. package/dist/{typeChecking-CbltMOUt.js.map → typeChecking-_dGK_0uR.js.map} +1 -1
  32. package/dist/utils.d.ts +5 -0
  33. package/docs/components.md +21 -0
  34. package/docs/hooks.md +3 -3
  35. package/docs/signals.md +67 -53
  36. package/docs/stores.md +13 -4
  37. package/package.json +4 -4
  38. package/dist/core/mount.d.ts +0 -15
  39. package/dist/core/mount.test.d.ts +0 -0
  40. package/dist/markup-DeZDwQ9F.js +0 -1117
  41. package/dist/markup-DeZDwQ9F.js.map +0 -1
  42. package/dist/router-C35XmU3k.js +0 -543
  43. package/dist/router-C35XmU3k.js.map +0 -1
  44. package/dist/signals-DbDmN2gr.js.map +0 -1
  45. package/dist/typeChecking-CbltMOUt.js +0 -71
  46. package/docs/state.md +0 -141
  47. package/examples/webcomponent/index.html +0 -14
  48. package/examples/webcomponent/main.js +0 -165
  49. package/notes/TODO.md +0 -6
  50. package/notes/context-routes.md +0 -61
  51. package/notes/custom-nodes.md +0 -17
  52. package/notes/effection-idea.md +0 -34
  53. package/notes/mixins.md +0 -22
  54. package/notes/molecule.md +0 -35
  55. package/notes/readme-scratch.md +0 -260
  56. package/notes/route-middleware.md +0 -42
  57. package/notes/stores.md +0 -79
@@ -1 +0,0 @@
1
- {"version":3,"file":"signals-DbDmN2gr.js","sources":["../node_modules/alien-signals/esm/system.mjs","../src/utils.ts","../src/core/env.ts","../src/core/signals.ts"],"sourcesContent":["export var ReactiveFlags;\n(function (ReactiveFlags) {\n ReactiveFlags[ReactiveFlags[\"None\"] = 0] = \"None\";\n ReactiveFlags[ReactiveFlags[\"Mutable\"] = 1] = \"Mutable\";\n ReactiveFlags[ReactiveFlags[\"Watching\"] = 2] = \"Watching\";\n ReactiveFlags[ReactiveFlags[\"RecursedCheck\"] = 4] = \"RecursedCheck\";\n ReactiveFlags[ReactiveFlags[\"Recursed\"] = 8] = \"Recursed\";\n ReactiveFlags[ReactiveFlags[\"Dirty\"] = 16] = \"Dirty\";\n ReactiveFlags[ReactiveFlags[\"Pending\"] = 32] = \"Pending\";\n})(ReactiveFlags || (ReactiveFlags = {}));\nexport function createReactiveSystem({ update, notify, unwatched, }) {\n return {\n link,\n unlink,\n propagate,\n checkDirty,\n endTracking,\n startTracking,\n shallowPropagate,\n };\n function link(dep, sub) {\n const prevDep = sub.depsTail;\n if (prevDep !== undefined && prevDep.dep === dep) {\n return;\n }\n let nextDep = undefined;\n const recursedCheck = sub.flags & 4;\n if (recursedCheck) {\n nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps;\n if (nextDep !== undefined && nextDep.dep === dep) {\n sub.depsTail = nextDep;\n return;\n }\n }\n const prevSub = dep.subsTail;\n if (prevSub !== undefined\n && prevSub.sub === sub\n && (!recursedCheck || isValidLink(prevSub, sub))) {\n return;\n }\n const newLink = sub.depsTail\n = dep.subsTail\n = {\n dep,\n sub,\n prevDep,\n nextDep,\n prevSub,\n nextSub: undefined,\n };\n if (nextDep !== undefined) {\n nextDep.prevDep = newLink;\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = newLink;\n }\n else {\n sub.deps = newLink;\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = newLink;\n }\n else {\n dep.subs = newLink;\n }\n }\n function unlink(link, sub = link.sub) {\n const dep = link.dep;\n const prevDep = link.prevDep;\n const nextDep = link.nextDep;\n const nextSub = link.nextSub;\n const prevSub = link.prevSub;\n if (nextDep !== undefined) {\n nextDep.prevDep = prevDep;\n }\n else {\n sub.depsTail = prevDep;\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = nextDep;\n }\n else {\n sub.deps = nextDep;\n }\n if (nextSub !== undefined) {\n nextSub.prevSub = prevSub;\n }\n else {\n dep.subsTail = prevSub;\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = nextSub;\n }\n else if ((dep.subs = nextSub) === undefined) {\n unwatched(dep);\n }\n return nextDep;\n }\n function propagate(link) {\n let next = link.nextSub;\n let stack;\n top: do {\n const sub = link.sub;\n let flags = sub.flags;\n if (flags & 3) {\n if (!(flags & 60)) {\n sub.flags = flags | 32;\n }\n else if (!(flags & 12)) {\n flags = 0;\n }\n else if (!(flags & 4)) {\n sub.flags = (flags & ~8) | 32;\n }\n else if (!(flags & 48) && isValidLink(link, sub)) {\n sub.flags = flags | 40;\n flags &= 1;\n }\n else {\n flags = 0;\n }\n if (flags & 2) {\n notify(sub);\n }\n if (flags & 1) {\n const subSubs = sub.subs;\n if (subSubs !== undefined) {\n link = subSubs;\n if (subSubs.nextSub !== undefined) {\n stack = { value: next, prev: stack };\n next = link.nextSub;\n }\n continue;\n }\n }\n }\n if ((link = next) !== undefined) {\n next = link.nextSub;\n continue;\n }\n while (stack !== undefined) {\n link = stack.value;\n stack = stack.prev;\n if (link !== undefined) {\n next = link.nextSub;\n continue top;\n }\n }\n break;\n } while (true);\n }\n function startTracking(sub) {\n sub.depsTail = undefined;\n sub.flags = (sub.flags & ~56) | 4;\n }\n function endTracking(sub) {\n const depsTail = sub.depsTail;\n let toRemove = depsTail !== undefined ? depsTail.nextDep : sub.deps;\n while (toRemove !== undefined) {\n toRemove = unlink(toRemove, sub);\n }\n sub.flags &= ~4;\n }\n function checkDirty(link, sub) {\n let stack;\n let checkDepth = 0;\n top: do {\n const dep = link.dep;\n const depFlags = dep.flags;\n let dirty = false;\n if (sub.flags & 16) {\n dirty = true;\n }\n else if ((depFlags & 17) === 17) {\n if (update(dep)) {\n const subs = dep.subs;\n if (subs.nextSub !== undefined) {\n shallowPropagate(subs);\n }\n dirty = true;\n }\n }\n else if ((depFlags & 33) === 33) {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack };\n }\n link = dep.deps;\n sub = dep;\n ++checkDepth;\n continue;\n }\n if (!dirty && link.nextDep !== undefined) {\n link = link.nextDep;\n continue;\n }\n while (checkDepth) {\n --checkDepth;\n const firstSub = sub.subs;\n const hasMultipleSubs = firstSub.nextSub !== undefined;\n if (hasMultipleSubs) {\n link = stack.value;\n stack = stack.prev;\n }\n else {\n link = firstSub;\n }\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) {\n shallowPropagate(firstSub);\n }\n sub = link.sub;\n continue;\n }\n }\n else {\n sub.flags &= ~32;\n }\n sub = link.sub;\n if (link.nextDep !== undefined) {\n link = link.nextDep;\n continue top;\n }\n dirty = false;\n }\n return dirty;\n } while (true);\n }\n function shallowPropagate(link) {\n do {\n const sub = link.sub;\n const nextSub = link.nextSub;\n const subFlags = sub.flags;\n if ((subFlags & 48) === 32) {\n sub.flags = subFlags | 16;\n if (subFlags & 2) {\n notify(sub);\n }\n }\n link = nextSub;\n } while (link !== undefined);\n }\n function isValidLink(checkLink, sub) {\n const depsTail = sub.depsTail;\n if (depsTail !== undefined) {\n let link = sub.deps;\n do {\n if (link === checkLink) {\n return true;\n }\n if (link === depsTail) {\n break;\n }\n link = link.nextDep;\n } while (link !== undefined);\n }\n return false;\n }\n}\n","import { isFunction, isObject, typeOf } from \"./typeChecking.js\";\n\nexport const noOp = () => {};\n\n// Guarantee unique ID by incrementing a global counter.\nlet idCounter = 1;\nexport function getUniqueId(): string {\n idCounter = (idCounter % Number.MAX_SAFE_INTEGER) + 1;\n return idCounter.toString(36) + Date.now().toString(36);\n}\n\n/*=============================*\\\n|| Object Equality ||\n\\*=============================*/\n\n/**\n * Equality check that passes if both values are the same object.\n * This is the default equality check for states.\n */\nexport function strictEqual(a: any, b: any): boolean {\n return Object.is(a, b);\n}\n\n/**\n * Equality check that passes if both values are the same object, or if both are objects or arrays with equal keys and values.\n */\nexport function shallowEqual(a: any, b: any): boolean {\n if (Object.is(a, b)) return true;\n\n // Must be same type\n const t = typeOf(a);\n if (t !== typeOf(b)) {\n return false;\n }\n\n switch (t) {\n case \"object\":\n // Objects must have same number of keys with strict equal values\n let size = 0;\n for (const key in a) {\n if (a[key] !== b[key]) return false;\n size++;\n }\n return Object.keys(b).length === size;\n case \"array\":\n // Arrays must be the same length with strict equal values\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n case \"map\":\n if (a.size !== b.size) return false;\n for (const key of a.keys()) {\n if (a[key] !== b[key]) return false;\n }\n return true;\n case \"set\":\n if (isFunction(a.symmetricDifference)) {\n return a.symmetricDifference(b).size === 0;\n } else {\n for (const key of a.keys()) {\n if (a[key] !== b.get(key)) return false;\n }\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Equality check that passes if two objects have equal values, even if they are not the same object.\n */\n// NOTE: This code is https://github.com/epoberezkin/fast-deep-equal licensed under MIT.\n// I imported it because I couldn't get the old school module to play nice with my modern ES code as an external dependency.\nexport function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a && b && typeof a == \"object\" && typeof b == \"object\") {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0; ) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (i of a.entries()) if (!b.has(i[0])) return false;\n for (i of a.entries()) if (!deepEqual(i[1], b.get(i[0]))) return false;\n return true;\n }\n\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n for (i of a.entries()) if (!b.has(i[0])) return false;\n return true;\n }\n\n if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {\n length = (a as any).length;\n if (length != (b as any).length) return false;\n for (i = length; i-- !== 0; ) if ((a as any)[i] !== (b as any)[i]) return false;\n return true;\n }\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0; ) {\n var key = keys[i];\n\n if (!deepEqual(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a !== a && b !== b;\n}\n\n/*=============================*\\\n|| Object Utils ||\n\\*=============================*/\n\n/**\n * Takes an old value and a new value. Returns a merged copy if both are objects, otherwise returns the new value.\n */\nexport function merge(one: unknown, two: unknown) {\n if (isObject(one)) {\n if (!isObject(two)) {\n return two;\n }\n\n const merged = Object.assign({}, one) as any;\n\n for (const key in two) {\n merged[key] = merge(merged[key], two[key]);\n }\n\n return merged;\n } else {\n return two;\n }\n}\n\n/**\n * Returns a new object without the specified keys.\n * If called without object, returns a function that takes an object\n * and returns a version with the original keys omitted.\n *\n * @param keys - An array of keys to omit.\n * @param object - An object to clone without the omitted keys.\n */\nexport function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any> {\n const newObject: Record<any, any> = {};\n\n for (const key in object) {\n if (!keys.includes(key)) {\n newObject[key] = object[key];\n }\n }\n\n return newObject;\n}\n\n/*=============================*\\\n|| Misc Utils ||\n\\*=============================*/\n\nexport function toArray<T>(value: T | T[]): T[] {\n if (Array.isArray(value)) {\n return value;\n } else {\n return [value];\n }\n}\n\nexport function toCamelCase(s: string) {\n return s.replace(/-./g, (x) => x[1].toUpperCase());\n}\n\n/**\n * Takes any string and returns an OKLCH color.\n */\nexport function okhash(value: string) {\n let hue = 0;\n for (let i = 0; i < value.length; i++) {\n hue = (hue + value.charCodeAt(i) * 10) % 360;\n }\n return `oklch(0.68 0.15 ${hue}deg)`;\n}\n\nexport type MatcherFunction = (value: string) => boolean;\n\n/**\n * Parses a filter string into a matcher function.\n *\n * @param pattern - A string or regular expression that specifies a pattern for names of loggers whose messages you want to display.\n */\nexport function createMatcher(pattern: string | RegExp): MatcherFunction {\n if (pattern instanceof RegExp) {\n return (value: string) => pattern.test(value);\n }\n\n const matchers: Record<\"positive\" | \"negative\", MatcherFunction[]> = {\n positive: [],\n negative: [],\n };\n\n const parts = pattern\n .split(\",\")\n .map((p) => p.trim())\n .filter((p) => p !== \"\");\n\n for (let part of parts) {\n let section: \"positive\" | \"negative\" = \"positive\";\n\n if (part.startsWith(\"-\")) {\n section = \"negative\";\n part = part.slice(1);\n }\n\n if (part === \"*\") {\n matchers[section].push(function () {\n return true;\n });\n } else if (part.endsWith(\"*\")) {\n matchers[section].push(function (value) {\n return value.startsWith(part.slice(0, part.length - 1));\n });\n } else {\n matchers[section].push(function (value) {\n return value === part;\n });\n }\n }\n\n return function (name: string) {\n const { positive, negative } = matchers;\n\n // Matching any negative matcher disqualifies.\n if (negative.some((fn) => fn(name))) {\n return false;\n }\n\n // Matching at least one positive matcher is required if any are specified.\n if (positive.length > 0 && !positive.some((fn) => fn(name))) {\n return false;\n }\n\n return true;\n };\n}\n","import type { Env } from \"../types\";\n\nlet currentEnv = \"production\";\n\nexport function getEnv() {\n return currentEnv;\n}\n\nexport function setEnv(value: Env) {\n currentEnv = value;\n}\n","import type { ReactiveFlags, ReactiveNode } from \"alien-signals\";\nimport { createReactiveSystem } from \"alien-signals/system\";\nimport { isFunction } from \"../typeChecking\";\nimport { strictEqual } from \"../utils\";\nimport { Context } from \"./context\";\nimport { getEnv } from \"./env\";\n\nconst enum EffectFlags {\n Queued = 1 << 6,\n}\n\ninterface EffectScope extends ReactiveNode {}\n\ninterface Effect extends ReactiveNode {\n fn(): void | (() => void);\n cleanup?: () => void;\n}\n\ninterface ComputedGetterState<T> {\n value?: T;\n}\n\ninterface Computed<T = any> extends ReactiveNode {\n value: T | undefined;\n getter: (this: ComputedGetterState<T>) => T;\n equals: EqualityFn<T>;\n}\n\ninterface Value<T = any> extends ReactiveNode {\n previousValue: T;\n value: T;\n equals: EqualityFn<T>;\n}\n\nconst queuedEffects: (Effect | EffectScope | undefined)[] = [];\nconst { link, unlink, propagate, checkDirty, endTracking, startTracking, shallowPropagate } = createReactiveSystem({\n update(signal: Value | Computed): boolean {\n if (\"getter\" in signal) {\n return updateComputed(signal);\n } else {\n return updateSignal(signal, signal.value);\n }\n },\n notify,\n unwatched(node: Value | Computed | Effect | EffectScope) {\n if (\"getter\" in node) {\n let toRemove = node.deps;\n if (toRemove !== undefined) {\n node.flags = 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty;\n do {\n toRemove = unlink(toRemove, node);\n } while (toRemove !== undefined);\n }\n } else if (!(\"previousValue\" in node)) {\n _effect.call(node);\n }\n },\n});\n\nlet batchDepth = 0;\n\nlet notifyIndex = 0;\nlet queuedEffectsLength = 0;\nlet activeSub: ReactiveNode | undefined;\nlet activeScope: EffectScope | undefined;\nlet activeContext: Context | undefined;\n\nfunction getCurrentSub(): ReactiveNode | undefined {\n return activeSub;\n}\n\nfunction setCurrentSub(sub: ReactiveNode | undefined) {\n const prevSub = activeSub;\n activeSub = sub;\n return prevSub;\n}\n\nexport function getCurrentContext(): Context | undefined {\n return activeContext;\n}\n\nexport function setCurrentContext(context: Context | undefined) {\n const prevContext = activeContext;\n activeContext = context;\n return prevContext;\n}\n\n// function getCurrentScope(): EffectScope | undefined {\n// return activeScope;\n// }\n\n// function setCurrentScope(scope: EffectScope | undefined) {\n// const prevScope = activeScope;\n// activeScope = scope;\n// return prevScope;\n// }\n\n// export function effectScope(fn: () => void): () => void {\n// const e: EffectScope = {\n// deps: undefined,\n// depsTail: undefined,\n// subs: undefined,\n// subsTail: undefined,\n// flags: 0 satisfies ReactiveFlags.None,\n// };\n// if (activeScope !== undefined) {\n// link(e, activeScope);\n// }\n// const prevSub = setCurrentSub(undefined);\n// const prevScope = setCurrentScope(e);\n// try {\n// fn();\n// } finally {\n// setCurrentScope(prevScope);\n// setCurrentSub(prevSub);\n// }\n// return effectOper.bind(e);\n// }\n\nfunction updateComputed(c: Computed): boolean {\n const prevSub = setCurrentSub(c);\n startTracking(c);\n try {\n const oldValue = c.value;\n const state: ComputedGetterState<any> = { value: c.value };\n // return oldValue !== (c.value = c.getter.call(state));\n return !c.equals(oldValue, (c.value = c.getter.call(state)));\n } finally {\n setCurrentSub(prevSub);\n endTracking(c);\n }\n}\n\nfunction updateSignal(s: Value, value: any): boolean {\n s.flags = 1 satisfies ReactiveFlags.Mutable;\n // return s.previousValue !== (s.previousValue = value);\n return !s.equals(s.previousValue, (s.previousValue = value));\n}\n\nfunction notify(e: Effect | EffectScope) {\n const flags = e.flags;\n if (!(flags & EffectFlags.Queued)) {\n e.flags = flags | EffectFlags.Queued;\n const subs = e.subs;\n if (subs !== undefined) {\n notify(subs.sub as Effect | EffectScope);\n } else {\n queuedEffects[queuedEffectsLength++] = e;\n }\n }\n}\n\nfunction run(e: Effect | EffectScope, flags: ReactiveFlags): void {\n if (\n flags & (16 satisfies ReactiveFlags.Dirty) ||\n (flags & (32 satisfies ReactiveFlags.Pending) && checkDirty(e.deps!, e))\n ) {\n const prev = setCurrentSub(e);\n startTracking(e);\n try {\n if (\"cleanup\" in e && e.cleanup !== undefined) {\n e.cleanup();\n }\n const result = (e as Effect).fn();\n if (\"cleanup\" in e && isFunction(result)) {\n e.cleanup = result;\n }\n } finally {\n setCurrentSub(prev);\n endTracking(e);\n }\n return;\n } else if (flags & (32 satisfies ReactiveFlags.Pending)) {\n e.flags = flags & ~(32 satisfies ReactiveFlags.Pending);\n }\n let link = e.deps;\n while (link !== undefined) {\n const dep = link.dep;\n const depFlags = dep.flags;\n if (depFlags & EffectFlags.Queued) {\n run(dep, (dep.flags = depFlags & ~EffectFlags.Queued));\n }\n link = link.nextDep;\n }\n}\n\nfunction flush(): void {\n while (notifyIndex < queuedEffectsLength) {\n const effect = queuedEffects[notifyIndex]!;\n queuedEffects[notifyIndex++] = undefined;\n run(effect, (effect.flags &= ~EffectFlags.Queued));\n }\n notifyIndex = 0;\n queuedEffectsLength = 0;\n}\n\nfunction _computed<T>(this: Computed<T>): T {\n const flags = this.flags;\n if (\n flags & (16 satisfies ReactiveFlags.Dirty) ||\n (flags & (32 satisfies ReactiveFlags.Pending) && checkDirty(this.deps!, this))\n ) {\n if (updateComputed(this)) {\n const subs = this.subs;\n if (subs !== undefined) {\n shallowPropagate(subs);\n }\n }\n } else if (flags & (32 satisfies ReactiveFlags.Pending)) {\n this.flags = flags & ~(32 satisfies ReactiveFlags.Pending);\n }\n if (activeSub !== undefined) {\n link(this, activeSub);\n } else if (activeScope !== undefined) {\n link(this, activeScope);\n }\n return this.value!;\n}\n\nfunction _getter<T>(this: Value<T>): T {\n const value = this.value;\n if (this.flags & (16 satisfies ReactiveFlags.Dirty)) {\n if (updateSignal(this, value)) {\n const subs = this.subs;\n if (subs !== undefined) {\n shallowPropagate(subs);\n }\n }\n }\n if (activeSub !== undefined) {\n link(this, activeSub);\n }\n return value;\n}\n\nfunction _setter<T>(this: Value<T>, value: T | ((current: T) => T)): void {\n let next = isFunction(value) ? (get(value(this.value)) as T) : (value as T);\n if (!this.equals(this.value, next)) {\n this.value = next;\n this.flags = 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty;\n const subs = this.subs;\n if (subs !== undefined) {\n propagate(subs);\n if (!batchDepth) {\n flush();\n }\n }\n }\n}\n\nfunction _effect(this: Effect | EffectScope): void {\n let dep = this.deps;\n while (dep !== undefined) {\n dep = unlink(dep, this);\n }\n const sub = this.subs;\n if (sub !== undefined) {\n unlink(sub);\n }\n this.flags = 0 satisfies ReactiveFlags.None;\n\n if (\"cleanup\" in this && this.cleanup != null) {\n this.cleanup();\n }\n}\n\n/*===================================*\\\n|| API ||\n\\*===================================*/\n\n/* -------------- TYPES --------------- */\n\n/**\n * A function that returns the current value of a signal.\n * Automatically tracked as a dependency when called within a tracking scope (such as `memo` or `effect` functions).\n */\nexport interface Signal<T> {\n (): T;\n}\n\n/**\n * A function that sets the value of the signal.\n */\nexport interface Setter<T> {\n (value: T): void;\n (update: (current: T) => T): void;\n}\n\n/**\n * A getter and setter in a single object. Callable like a getter, but includes a `set` method for updating the signal's value.\n */\nexport interface Writable<T> extends Signal<T> {\n set: Setter<T>;\n}\n\n/**\n * Utility type for a value that may be a getter or a plain value.\n * This value can be unwrapped to a plain value with `get` or `untracked` (depending on whether you're in a tracking context and need to track it).\n */\nexport type MaybeSignal<T> = Signal<T> | T;\n\nexport type EqualityFn<T> = (current: T, next: T) => boolean;\n\nexport interface SignalOptions<T> {\n /**\n * A function to compare the current and next values. Returning `true` means the value has changed.\n */\n equals?: EqualityFn<T>;\n}\n\n/* -------------- PUBLIC API --------------- */\n\nexport function $<T>(compute: (previousValue?: T) => MaybeSignal<T>, options?: MemoOptions<T>): Signal<T>;\n\nexport function $<T>(): Writable<T | undefined>;\nexport function $<T>(value: undefined, options: SignalOptions<T | undefined>): Writable<T | undefined>;\nexport function $<T>(value: T, options?: SignalOptions<T>): Writable<T>;\n\nexport function $<T>(...args: any) {\n if (isFunction(args[0])) {\n return memo(args[0], args[1]);\n } else {\n return writable(args[0], args[1]);\n }\n}\n\nexport function writable<T>(): Writable<T | undefined>;\nexport function writable<T>(value: undefined, options: SignalOptions<T | undefined>): Writable<T | undefined>;\nexport function writable<T>(value: T, options?: SignalOptions<T>): Writable<T>;\n\nexport function writable<T>(value?: T, options?: SignalOptions<T>): Writable<T> {\n const v: Value<unknown> = {\n previousValue: value as T,\n value: value as T,\n equals: (options?.equals as EqualityFn<unknown>) ?? strictEqual,\n subs: undefined,\n subsTail: undefined,\n flags: 1 satisfies ReactiveFlags.Mutable,\n };\n const fn = _getter.bind(v) as Writable<T>;\n fn.set = _setter.bind(v);\n return fn;\n}\n\nexport interface MemoOptions<T> extends SignalOptions<T> {\n /**\n * An array of signals this `memo` depends on. If this is passed, calls to signals within `fn` will NOT be tracked.\n * Instead the `deps` array will be tracked and `fn` will re-run when any value in `deps` changes.\n */\n deps?: Signal<any>[];\n}\n\n/**\n * Creates a derived Signal that recomputes its value only when its dependencies change.\n * Dependencies are tracked when called inside `fn` by default,\n * but can be overridden by passing a `deps` array in the options object.\n */\nexport function memo<T>(fn: (previousValue?: T) => MaybeSignal<T>, options?: MemoOptions<T>): Signal<T> {\n return _computed.bind({\n value: undefined,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty,\n getter: function (this: ComputedGetterState<any>) {\n if (options?.deps) {\n for (let dep of options.deps) get(dep);\n return get(untracked(() => fn(this.value)));\n }\n return get(fn(this.value));\n },\n equals: (options?.equals as EqualityFn<unknown>) ?? strictEqual,\n }) as () => T;\n}\n\n/**\n * Suspends effects during `fn`. Effects for all updated Signal values are called at the end of the batch.\n */\nexport function batch(fn: () => void): void {\n ++batchDepth;\n fn();\n if (!--batchDepth) flush();\n}\n\n/**\n * Call a Signal function without tracking its value.\n */\nexport function untracked<T>(value: MaybeSignal<T>): T {\n if (isFunction(value)) {\n let result: T;\n const pausedSub = setCurrentSub(undefined);\n result = value();\n setCurrentSub(pausedSub);\n return result;\n } else {\n return value;\n }\n}\n\n/**\n * Unwraps the plain value from a Signal. If the value is not a Signal it is returned as-is.\n */\nexport function get<T>(value: MaybeSignal<T>): T {\n if (isFunction(value)) {\n return (value as () => T)();\n } else {\n return value;\n }\n}\n\n/**\n * Function to be invoked for the effect. Can return an optional cleanup function to be called between invocations.\n */\nexport type EffectFn = () => void | (() => void);\n\nexport type UnsubscribeFn = () => void;\n\nexport const INTERNAL_EFFECT = Symbol(\"INTERNAL_EFFECT\");\n\nexport interface EffectOptions {\n /**\n * An array of signals this effect depends on. If this is passed, calls to signals within `fn` will NOT be tracked.\n * Instead the `deps` array will be tracked and `fn` will re-run when any value in `deps` changes.\n */\n deps?: Signal<any>[];\n\n /**\n * For internal use.\n */\n _type?: symbol;\n}\n\n/**\n * Creates a tracked scope that re-runs whenever the values of any tracked reactives changes.\n * Reactives are tracked by accessing their `value` within the body of the function.\n *\n * NOTE: You must call the unsubscribe function to stop watching for changes.\n * If you are using an effect inside a View or Store, use `ctx.effect` instead, which cleans up automatically when the component unmounts.\n */\nexport function effect(fn: EffectFn, options?: EffectOptions): UnsubscribeFn {\n const internal = options?._type === INTERNAL_EFFECT;\n\n // Automatically bind to active context if called within one.\n if (!internal && activeContext) {\n return activeContext.effect(fn);\n }\n\n // Warn about memory leaks in dev mode.\n if (!internal && getEnv() === \"development\") {\n console.warn(\n `This effect is not bound to a scope. You must call the unsubscribe function when done to avoid memory leaks.`,\n );\n }\n\n const e: Effect = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: 2 satisfies ReactiveFlags.Watching,\n };\n if (activeSub !== undefined) {\n link(e, activeSub);\n } else if (activeScope !== undefined) {\n link(e, activeScope);\n }\n const prev = setCurrentSub(e);\n try {\n e.cleanup?.();\n const result = e.fn();\n e.cleanup = isFunction(result) ? result : undefined;\n } finally {\n setCurrentSub(prev);\n }\n return _effect.bind(e);\n}\n"],"names":["ReactiveFlags","createReactiveSystem","update","notify","unwatched","link","unlink","propagate","checkDirty","endTracking","startTracking","shallowPropagate","dep","sub","prevDep","nextDep","recursedCheck","prevSub","isValidLink","newLink","nextSub","next","stack","top","flags","subSubs","depsTail","toRemove","checkDepth","depFlags","dirty","subs","firstSub","hasMultipleSubs","subFlags","checkLink","noOp","idCounter","getUniqueId","strictEqual","a","b","shallowEqual","t","typeOf","size","key","i","isFunction","deepEqual","length","keys","omit","object","newObject","toArray","value","toCamelCase","s","x","okhash","hue","createMatcher","pattern","matchers","parts","p","part","section","name","positive","negative","fn","currentEnv","getEnv","setEnv","queuedEffects","signal","updateComputed","updateSignal","node","_effect","batchDepth","notifyIndex","queuedEffectsLength","activeSub","activeContext","setCurrentSub","getCurrentContext","setCurrentContext","context","prevContext","c","oldValue","state","run","prev","result","flush","effect","_computed","_getter","_setter","get","$","args","memo","writable","options","v","untracked","batch","pausedSub","INTERNAL_EFFECT","internal","e","_a"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,71 +0,0 @@
1
- function o(r) {
2
- const t = typeof r;
3
- switch (t) {
4
- case "undefined":
5
- return t;
6
- case "number":
7
- return isNaN(r) ? "NaN" : t;
8
- case "function":
9
- return /^\s*class\s+/.test(r.toString()) ? "class" : t;
10
- case "object":
11
- return r === null ? "null" : r instanceof Promise ? "promise" : r instanceof Map ? "map" : r instanceof Set ? "set" : Array.isArray(r) ? "array" : t;
12
- default:
13
- return t;
14
- }
15
- }
16
- function c(r) {
17
- return Array.isArray(r);
18
- }
19
- function u(r, t) {
20
- return c(t) && t.every((n) => r(n));
21
- }
22
- function y(r, t, n) {
23
- if (u(r, t))
24
- return !0;
25
- throw new TypeError(i(t, n));
26
- }
27
- function f(r) {
28
- return typeof r == "string";
29
- }
30
- function p(r, t) {
31
- if (f(r))
32
- return !0;
33
- throw new TypeError(i(r, t ?? "Expected a string. Got type: %t, value: %v"));
34
- }
35
- function w(r) {
36
- return o(r) === "function";
37
- }
38
- function A(...r) {
39
- const t = r[0], n = f(r[2]) ? r[2] : `Expected instance of ${t.name}. Got type: %t, value: %v`, s = (e) => {
40
- if (e instanceof t)
41
- return !0;
42
- throw new TypeError(i(e, n));
43
- };
44
- return r.length < 2 ? s : s(r[1]);
45
- }
46
- function a(r) {
47
- return r != null && typeof r == "object" && !c(r);
48
- }
49
- function g(r, t) {
50
- if (a(r))
51
- return !0;
52
- throw new TypeError(i(r, t));
53
- }
54
- function i(r, t) {
55
- var e;
56
- const n = o(r), s = ((e = r == null ? void 0 : r.toString) == null ? void 0 : e.call(r)) || String(r);
57
- return t.replaceAll("%t", n).replaceAll("%v", s);
58
- }
59
- export {
60
- A as a,
61
- f as b,
62
- w as c,
63
- y as d,
64
- p as e,
65
- g as f,
66
- c as g,
67
- u as h,
68
- a as i,
69
- o as t
70
- };
71
- //# sourceMappingURL=typeChecking-CbltMOUt.js.map
package/docs/state.md DELETED
@@ -1,141 +0,0 @@
1
- ## ⚡ Reactive Updates with `State`
2
-
3
- Dolla sets out to solve the challenge of keeping your UI in sync with your data. All apps have state that changes at runtime, and as those values change your UI must update itself to stay in sync with that state. JavaScript frameworks all have their own ways of meeting this challenge, but there are two main ones; virtual DOM and signals.
4
-
5
- [React](https://react.dev) and similar frameworks make use of a [virtual DOM](https://svelte.dev/blog/virtual-dom-is-pure-overhead), in which every state change causes a "diff" of the real DOM nodes on the page against a lightweight representation of what those nodes _should_ look like, followed by a "patch" where the minimal updates are performed to bring the DOM in line with the ideal virtual DOM.
6
-
7
- [Solid](https://www.solidjs.com) and similar frameworks make use of [signals](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob), which are containers for data that will change over time. Signal values are accessed through special getter functions that can be called inside of a "scope" to track their values. When the value of a tracked signal changes, any computations that happened in scopes that depend on those signals are re-run. In an app like this, all of your DOM updates are performed with pinpoint accuracy without diffing as signal values change.
8
-
9
- Dolla uses a concept of a `State`, which is a signal-like container for values that change over time. Where `State` differs from signals, however, is that there is no magical scope tracking going on behind the scenes. All States that depend on others do so explicity, so your code is easier to read and understand.
10
-
11
- The `State` API has just four functions:
12
-
13
- - `createState` to create a new state and a linked setter function.
14
- - `derive` to create a new state whose value depends on one or more other states.
15
- - `toState` to ensure that a value is a state object.
16
- - `toValue` to ensure that a value is a plain value.
17
-
18
- ### Basic State API
19
-
20
- ```js
21
- import { createState } from "@manyducks.co/dolla";
22
-
23
- // Equivalent to React's `useState` or Solid's `createSignal`.
24
- // A new read-only State and linked Setter are created.
25
- const [$count, setCount] = createState(72);
26
-
27
- // Get the current value.
28
- $count.get(): // 72
29
-
30
- // Set a new value.
31
- setCount(300);
32
-
33
- // The State now reflects the latest value.
34
- $count.get(); // 300
35
-
36
- // Data can also be updated by passing a function.
37
- // This function takes the current state and returns a new one.
38
- setCount((current) => current + 1);
39
- $count.get(); // 301
40
- ```
41
-
42
- ### Deriving States from other States
43
-
44
- #### Example 1: Doubled
45
-
46
- ```js
47
- import { createState, derive } from "@manyducks.co/dolla";
48
-
49
- const [$count, setCount] = createState(1);
50
-
51
- const $doubled = derive([$count], (count) => count * 2);
52
-
53
- setCount(10);
54
- $doubled.get(); // 20
55
- ```
56
-
57
- That was a typical toy example where we create a `$doubled` state that always contains the value of `$count`... doubled! This is the essential basic example of computed properties, as written in Dolla.
58
-
59
- #### Example 2: Selecting a User
60
-
61
- ```js
62
- import { createState, derive } from "@manyducks.co/dolla";
63
-
64
- const [$users, setUsers] = createState([
65
- { id: 1, name: "Audie" },
66
- { id: 2, name: "Bob" },
67
- { id: 3, name: "Cabel" },
68
- ]);
69
- const [$selectedUserId, setSelectedUserId] = createState(1);
70
-
71
- const $selectedUser = derive([$users, $selectedUserId], (users, id) => {
72
- return users.find((user) => user.id === id);
73
- });
74
-
75
- $selectedUser.get(); // { id: 1, name: "Audie" }
76
-
77
- setSelectedId(3);
78
-
79
- $selectedUser.get(); // { id: 3, name: "Cabel" }
80
- ```
81
-
82
- That was a more realistic example you might actually use in real life. Here we are selecting a user from a list based on its `id` field. This is kind of similar to a `JOIN` operation in a SQL database. I use this kind of pattern constantly in my apps.
83
-
84
- The strength of setting up a join like this is that the `$users` array can be updated (by API call, websockets, etc.) and your `$selectedUser` will always be pointing to the latest version of the user data.
85
-
86
- #### Example 3: Narrowing Complex Data
87
-
88
- ```jsx
89
- import { createState, derive } from "@manyducks.co/dolla";
90
-
91
- const [$user, setUser] = createState({ id: 1, name: "Audie" });
92
-
93
- const $name = derive([$user], (user) => user.name);
94
-
95
- $name.get(); // "Audie"
96
-
97
- // In a view:
98
- <span class="user-name">{$name}</span>;
99
- ```
100
-
101
- Another common pattern. In a real app, most data is stored as arrays of objects. But what you need in order to slot it into a view is just a string. In the example above we've selected the user's name and slotted it into a `span`. If the `$user` value ever changes, the name will stay in sync.
102
-
103
- ### Converting to and from States
104
-
105
- ```js
106
- import { createState, toState, toValue } from "@manyducks.co/dolla";
107
-
108
- const [$count, setCount] = createState(512);
109
-
110
- // Unwrap the value of $count. Returns 512.
111
- const count = toValue($count);
112
- // Passing a non-state value will simply return it.
113
- const name = toValue("World");
114
-
115
- // Wrap "Hello" into a State containing "Hello"
116
- const $value = toState("Hello");
117
- // Passing a state will simply return that same state.
118
- const $number = toState($count);
119
- ```
120
-
121
- ### In Views
122
-
123
- ```jsx
124
- import { derive } from "@manyducks.co/dolla";
125
-
126
- function UserNameView(props, ctx) {
127
- const $name = derive([props.$user], (user) => user.name);
128
-
129
- return <span class={{ "user-name": true, "is-selected": props.$selected }}>{$name}</span>;
130
- });
131
- ```
132
-
133
- In the example above we've displayed the `name` field from a `$user` object inside of a span. We are also assigning an `is-selected` class dynamically based on whether the `$selected` prop contains a truthy or falsy value.
134
-
135
- ---
136
-
137
- End.
138
-
139
- - [🗂️ Docs](./index.md)
140
- - [🏠 README](../README.md)
141
- - [🦆 That's a lot of ducks.](https://www.manyducks.co)
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
-
4
- <head>
5
- <title>Web Component Example</title>
6
- </head>
7
-
8
- <body>
9
- <my-counter></my-counter>
10
-
11
- <script type="module" src="./main.js"></script>
12
- </body>
13
-
14
- </html>
@@ -1,165 +0,0 @@
1
- import { $, effect, when } from "../../dist/index.js";
2
-
3
- class EffectScope {
4
- #observing = false;
5
- #observers = [];
6
- #cleanups = [];
7
-
8
- get observing() {
9
- return this.#observing;
10
- }
11
-
12
- observe(callback) {
13
- this.#observers.push(callback);
14
- if (this.#observing) {
15
- this.#cleanups.push(effect(callback));
16
- }
17
- }
18
-
19
- start() {
20
- this.#observing = true;
21
- for (const callback of this.#observers) {
22
- this.#cleanups.push(effect(callback));
23
- }
24
- }
25
-
26
- stop() {
27
- this.#observing = false;
28
- for (const cleanup of this.#cleanups) {
29
- cleanup();
30
- }
31
- this.#cleanups.length = 0;
32
- }
33
- }
34
-
35
- function setAttribute(el, attr, value) {
36
- // handle special case attributes
37
- el.setAttribute(attr, value);
38
- }
39
-
40
- function createElement(tag, attrs, children) {
41
- // attrs can contain signals as values
42
- // children can contain signals as values
43
-
44
- // signals will be observed while the element is connected.
45
-
46
- const el = document.createElement(tag);
47
- const scope = new EffectScope();
48
-
49
- for (const key in attrs) {
50
- if (typeof attrs[key] === "function") {
51
- // determine if it's an event handler or a signal
52
- // this is determined by the name beginning with "on"
53
- if (key.startsWith("on")) {
54
- el.addEventListener(key.slice(2), attrs[key]);
55
- } else {
56
- // if signal then add an observer on the scope.
57
- scope.observe(() => {
58
- setAttribute(el, key, attrs[key]());
59
- });
60
- }
61
- } else {
62
- // attr is static
63
- setAttribute(el, key, attrs[key]);
64
- }
65
- }
66
-
67
- for (const child of children) {
68
- if (typeof child === "function") {
69
- // transform into a dynamic element
70
- // for now just printing it as a string
71
- const node = document.createTextNode(String(child()));
72
- console.log("HELLO", node, child);
73
- scope.observe(() => {
74
- node.textContent = String(child());
75
- });
76
- el.appendChild(node);
77
- } else if (child instanceof Node) {
78
- el.appendChild(child);
79
- } else {
80
- el.appendChild(document.createTextNode(String(child)));
81
- }
82
- }
83
-
84
- // run custom setup logic on connect and disconnect
85
- el.$dolla = {
86
- connected: false,
87
- connect() {
88
- if (this.connected) return;
89
- console.log(el, "$dolla connected");
90
- scope.start();
91
-
92
- for (const child of el.childNodes) {
93
- if ("$dolla" in child) {
94
- child.$dolla.connect();
95
- }
96
- }
97
- },
98
- disconnect() {
99
- if (!this.connected) return;
100
- console.log(el, "$dolla disconnected");
101
- scope.stop();
102
-
103
- for (const child of el.childNodes) {
104
- if ("$dolla" in child) {
105
- child.$dolla.disconnect();
106
- }
107
- }
108
- },
109
- };
110
-
111
- return el;
112
- }
113
-
114
- function mount(element, parent) {
115
- // Observe childList changes on subtree and run lifecycle callbacks.
116
- const observer = new MutationObserver((mutations) => {
117
- for (const mutation of mutations) {
118
- for (const node of mutation.addedNodes) {
119
- if ("$dolla" in node) {
120
- node.$dolla.connect();
121
- }
122
- }
123
-
124
- for (const node of mutation.removedNodes) {
125
- if ("$dolla" in node) {
126
- node.$dolla.disconnect();
127
- }
128
- }
129
- }
130
- });
131
- observer.observe(parent, { childList: true, subtree: true });
132
-
133
- parent.appendChild(element);
134
- }
135
-
136
- // const html = htm.bind(createElement);
137
-
138
- // need array of all event handler names
139
-
140
- class DollaElement extends HTMLElement {
141
- connectedCallback() {
142
- if (this.template) {
143
- mount(this.template, this);
144
- }
145
- }
146
- }
147
-
148
- class MyCounter extends DollaElement {
149
- count = $(0);
150
- increment = () => this.count((x) => x + 1);
151
-
152
- template = createElement("div", {}, [
153
- createElement("span", {}, ["Clicks: ", this.count]),
154
- createElement("button", { onclick: this.increment }, ["Click Me!"]),
155
- () => this.count() > 10 && createElement("span", {}, ["That's a lot of clicks."]),
156
- ]);
157
-
158
- // template = html`
159
- // <span>Clicks: ${this.count}</span>
160
- // <button onclick=${this.increment}>Click Me!</button>
161
- // ${() => this.count() > 10 && html`<span>That's a lot!</span>`}
162
- // `;
163
- }
164
-
165
- customElements.define("my-counter", MyCounter);
package/notes/TODO.md DELETED
@@ -1,6 +0,0 @@
1
- # TO DO LIST
2
-
3
- - Combine/refactor very similar Group, Outlet and Observer nodes.
4
- - Group is simplest and exists to mount an array of MarkupElements as one.
5
- - Outlet is basically the same as Group but it expects a $children state with an array of MarkupElements.
6
- - Observer is a generic catch-all that works with a set of states and a render function. The render function can return any kind of Renderable which is then converted into a MarkupElement, but very similar update logic outside of that. Observer uses Group internally.
@@ -1,61 +0,0 @@
1
- # Context routing
2
-
3
- I had an idea to integrate routing back into views instead of having a separate router. I originally had it work this way but I wasn't good enough to pull it off then.
4
-
5
- Here's how it might look:
6
-
7
- ```jsx
8
- function Example(props, ctx) {
9
- return <div>
10
- <header>
11
- <h1>Some kind of layout.</h1>
12
- </header>
13
- <main>
14
- {this.router(function () {
15
- this.route("something/*", SomethingView);
16
- this.redirect("*", "./something/*");
17
- })}
18
-
19
- {ctx.router([
20
- // Route path is relative to parent routes.
21
- // Nested route definitions are a thing of the past.
22
- // View could define its own routes.
23
- { path: "something/*", view: SomethingView }
24
- ])}
25
- </main>
26
- <div>
27
- }
28
-
29
- html`
30
- <${Router}>
31
- <${Route} path="something/*">
32
- This child content isn't materialized until the route matches.
33
- <${SomethingView} />
34
- <//>
35
- <//>
36
- `
37
- ```
38
-
39
- This removes the need to import and define the whole app at the top level. You can also add routes as you need them when prototyping.
40
-
41
- Route matching would be done by forwarding the wildcard portion of a match to child routers. Routers would be stored on the element context.
42
-
43
- Where would route info be stored then? It would have to be on the context as well.
44
-
45
- ```js
46
- // Merged data from all parent segments.
47
- ctx.route.params;
48
- ctx.route.query;
49
- ctx.route.path;
50
- ctx.route.pattern;
51
-
52
- ctx.go("/some/path");
53
- ctx.back();
54
- ctx.forward();
55
- ```
56
-
57
- ## Thoughts
58
-
59
- - Would eliminate the need for `ctx.outlet()`. Can pass children directly via `children` prop now.
60
- - Would eliminate the need for `ViewElement` and `setChildView` method because a top level router no longer needs to call it.
61
- - Couldn't do the current routing strategy of combining all routes into one flat list at the top level.
@@ -1,17 +0,0 @@
1
- What if people could define custom Markup nodes and use them in JSX. Alternative to writing a view if you need lighter weight or more custom elements.
2
-
3
- ```js
4
- class CustomNode implements MarkupNode {
5
- domNode = document.createElement('div');
6
-
7
- isMounted = false;
8
-
9
- mount(parent, before) {
10
-
11
- }
12
-
13
- unmount(parentIsUnmounting) {
14
-
15
- }
16
- }
17
- ```
@@ -1,34 +0,0 @@
1
- # Effection Idea
2
-
3
- This is probably a different framework, but I've been looking into Effection lately. Effection uses generators to manage async code, guaranteeing that cleanup runs and that you can use synchronous constructs like try/catch as you'd expect. I kind of like it, so I was thinking of adapting dolla views to use generators as well for async mounting and cleanup. It's worth trying just as an experiment and for learning more about generators.
4
-
5
- Generators are a poorly understood concept to me and I'm guessing most devs, because I never see them suggested as a solution to any problem in mainstream circles.
6
-
7
- ```js
8
- const ExampleStore = store(function* () {
9
- // Yield setup (optional)
10
- yield* function* () {};
11
-
12
- //
13
- yield {};
14
-
15
- // Yield teardown (optional)
16
- yield* function* () {};
17
- });
18
-
19
- const ExampleView = view(function* () {
20
- yield* provide(ExampleStore);
21
-
22
- const example = yield* use(ExampleStore);
23
-
24
- // Yield setup (optional)
25
- yield* function* () {};
26
-
27
- // Yield markup for rendering.
28
- // When mounting, the view is considered mounted when the view yields markup.
29
- yield <div>TEST</div>;
30
-
31
- // Yield teardown (optional)
32
- yield* function* () {};
33
- });
34
- ```
package/notes/mixins.md DELETED
@@ -1,22 +0,0 @@
1
- # Mixins
2
-
3
- Sometimes you want to attach logic to a DOM node without writing a whole view around it.
4
-
5
- ```js
6
- function myMixin(options: any): Mixin {
7
- return function(element: Element, ctx: MixinContext) {
8
- ctx.onMount(() => {
9
-
10
- })
11
-
12
- ctx.onUnmount(() => {
13
-
14
- })
15
- }
16
-
17
-
18
- // Returns nothing. Use context methods to attach event listeners / behavior / whatever.
19
- }
20
-
21
- <h1 mixins={[myMixin({ /* options */ }), /* ... */]}>Whatever</h1>
22
- ```