From 27cf8cfb8369f6a38f59ece54e8d6f64687117a3 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Sat, 25 May 2019 01:59:39 -0700 Subject: [PATCH] Update to latest version of dom expressions --- dom-expressions.config.js | 12 ++-- package-lock.json | 101 ++++++++++++++++++++------------- package.json | 16 +++--- src/core.ts | 112 ++++++++++++++++++++++++++++++++----- src/h.ts | 2 +- src/html.ts | 2 +- src/index.ts | 2 +- src/runtime.d.ts | 4 +- src/runtime.js | 115 +++++++++++++++++++++----------------- 9 files changed, 243 insertions(+), 123 deletions(-) diff --git a/dom-expressions.config.js b/dom-expressions.config.js index 8dde983..34a43b4 100644 --- a/dom-expressions.config.js +++ b/dom-expressions.config.js @@ -3,12 +3,12 @@ module.exports = { includeTypes: true, variables: { imports: [ - `import { untracked } from 'mobx'`, - `import { root as mRoot, cleanup as mCleanup, computed as mComputed } from './core'` + `import { untracked as sample } from 'mobx'`, + `import { + root, cleanup, computed as wrap, setContext, + registerSuspense, getContextOwner as currentContext + } from './core'` ], - computed: 'mComputed', - sample: 'untracked', - root: 'mRoot', - cleanup: 'mCleanup' + includeContext: true } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 593f065..892a307 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "mobx-jsx", - "version": "0.4.2", + "version": "0.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,18 +14,18 @@ } }, "@babel/core": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.3.tgz", - "integrity": "sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", + "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.0", - "@babel/helpers": "^7.4.3", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.5", + "@babel/types": "^7.4.4", "convert-source-map": "^1.1.0", "debug": "^4.1.0", "json5": "^2.1.0", @@ -115,9 +115,9 @@ } }, "@babel/parser": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", - "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", + "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", "dev": true }, "@babel/plugin-syntax-typescript": { @@ -161,16 +161,16 @@ } }, "@babel/traverse": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", - "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", + "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "@babel/generator": "^7.4.4", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.4.4", + "@babel/parser": "^7.4.5", "@babel/types": "^7.4.4", "debug": "^4.1.0", "globals": "^11.1.0", @@ -504,9 +504,9 @@ } }, "dom-expressions": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/dom-expressions/-/dom-expressions-0.8.4.tgz", - "integrity": "sha512-5/ySaxPYapIu3pu7CsbK1bRwep1WrAvSsN7u/t9uCZTTzEbwX/NYpVeoogJROXALfQAi2hLaW/nreyxIFdnrFg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/dom-expressions/-/dom-expressions-0.9.0.tgz", + "integrity": "sha512-5yFadO6skKdNPG1cIFMtcQBjEj5oylED+OIq/9fZXNRbwpwLyrBoodB8N0hUCcygYbui/eD3cKH/WtprWkqT/A==", "dev": true, "requires": { "ejs": "^2.6.1" @@ -761,9 +761,9 @@ } }, "hyper-dom-expressions": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/hyper-dom-expressions/-/hyper-dom-expressions-0.8.0.tgz", - "integrity": "sha512-pKAMO0Q8PdSYd42sKo+JjpCeZdAStR8+pyvtgi8HO+xdHEQ+OTfZwKFzNqO3uzZOHiQgN5RcFe1kohd0eqqMoA==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/hyper-dom-expressions/-/hyper-dom-expressions-0.9.0.tgz", + "integrity": "sha512-skQBauB1zaehQvq+kd6jdHRQQjzwTkImMmalcSpNpTTYfbGaaWnlFVMkM+uj8cDwFB9L3N5UtHQxe2pkLj3h4Q==", "dev": true }, "is-accessor-descriptor": { @@ -918,9 +918,9 @@ "dev": true }, "lit-dom-expressions": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/lit-dom-expressions/-/lit-dom-expressions-0.8.0.tgz", - "integrity": "sha512-WdKcbUDikJD/Q5qRIDxno5j9t0ZYi7JNYjiEfzZuNVbj3V+uCnTcCOx+O7EaCOmIwa7TYOTeYrOcvkUmy4S33A==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/lit-dom-expressions/-/lit-dom-expressions-0.9.0.tgz", + "integrity": "sha512-0dcorHcRZMBka+0conN8dcPaGwO47e344gEpjy6BA/U+Ro3MW5AhR0vnJsW2rlFnOPP2wnDXpin6DcOwyhuhCA==", "dev": true }, "lodash": { @@ -1113,9 +1113,9 @@ "dev": true }, "resolve": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", - "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1134,14 +1134,22 @@ "dev": true }, "rollup": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.11.3.tgz", - "integrity": "sha512-81MR7alHcFKxgWzGfG7jSdv+JQxSOIOD/Fa3iNUmpzbd7p+V19e1l9uffqT8/7YAHgGOzmoPGN3Fx3L2ptOf5g==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.12.3.tgz", + "integrity": "sha512-ueWhPijWN+GaPgD3l77hXih/gcDXmYph6sWeQegwBYtaqAE834e8u+MC2wT6FKIUsz1DBOyOXAQXUZB+rjWDoQ==", "dev": true, "requires": { "@types/estree": "0.0.39", - "@types/node": "^11.13.9", + "@types/node": "^12.0.2", "acorn": "^6.1.1" + }, + "dependencies": { + "@types/node": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", + "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", + "dev": true + } } }, "rollup-plugin-babel": { @@ -1155,15 +1163,28 @@ } }, "rollup-plugin-node-resolve": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.2.3.tgz", - "integrity": "sha512-r+WaesPzdGEynpLZLALFEDugA4ACa5zn7bc/+LVX4vAXQQ8IgDHv0xfsSvJ8tDXUtprfBtrDtRFg27ifKjcJTg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.0.0.tgz", + "integrity": "sha512-JUFr7DkFps3div9DYwpSg0O+s8zuSSRASUZUVNx6h6zhw2m8vcpToeS68JDPsFbmisMVSMYK0IxftngCRv7M9Q==", "dev": true, "requires": { "@types/resolve": "0.0.8", "builtin-modules": "^3.1.0", "is-module": "^1.0.0", - "resolve": "^1.10.0" + "resolve": "^1.10.1", + "rollup-pluginutils": "^2.7.0" + }, + "dependencies": { + "rollup-pluginutils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.7.1.tgz", + "integrity": "sha512-3nRf3buQGR9qz/IsSzhZAJyoK663kzseps8itkYHr+Z7ESuaffEPfgRinxbCRA0pf0gzLqkNKkSb8aNVTq75NA==", + "dev": true, + "requires": { + "estree-walker": "^0.6.0", + "micromatch": "^3.1.10" + } + } } }, "rollup-pluginutils": { @@ -1461,9 +1482,9 @@ "dev": true }, "typescript": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.4.tgz", - "integrity": "sha512-xt5RsIRCEaf6+j9AyOBgvVuAec0i92rgCaS3S+UVf5Z/vF2Hvtsw08wtUTJqp4djwznoAgjSxeCcU4r+CcDBJA==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", "dev": true }, "union-value": { diff --git a/package.json b/package.json index 248bf9f..3311a0b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mobx-jsx", "description": "Raw MobX performance without the restraints of a Virtual DOM", - "version": "0.4.2", + "version": "0.5.0", "author": "Ryan Carniato", "license": "MIT", "repository": { @@ -16,16 +16,16 @@ "prepublishOnly": "npm run build" }, "devDependencies": { - "@babel/core": "7.4.3", + "@babel/core": "7.4.5", "@babel/preset-typescript": "7.3.3", - "dom-expressions": "0.8.4", - "hyper-dom-expressions": "~0.8.0", - "lit-dom-expressions": "~0.8.0", + "dom-expressions": "0.9.0", + "hyper-dom-expressions": "0.9.0", + "lit-dom-expressions": "0.9.0", "mobx": "^5.9.0", - "rollup": "^1.11.3", + "rollup": "^1.12.3", "rollup-plugin-babel": "4.3.2", - "rollup-plugin-node-resolve": "4.2.3", - "typescript": "3.4.4" + "rollup-plugin-node-resolve": "5.0.0", + "typescript": "3.4.5" }, "peerDependencies": { "mobx": "*" diff --git a/src/core.ts b/src/core.ts index 7f8b32f..e38efde 100644 --- a/src/core.ts +++ b/src/core.ts @@ -1,25 +1,26 @@ -import { autorun, untracked } from 'mobx' +import { autorun, untracked, observable, IObservableValue } from 'mobx' -type Context = { disposables: any[] }; -let globalContext: Context; +type ContextOwner = { disposables: any[], owner: ContextOwner | null, context?: any }; +interface Context { id: symbol, initFn: Function }; + +let globalContext: ContextOwner | null = null; + +export function getContextOwner() { return globalContext; } export function root(fn: (dispose: () => void) => T) { - let context, d: any[], ret: T; - context = globalContext; + let d: any[], ret: T; globalContext = { - disposables: d = [] + disposables: d = [], + owner: globalContext }; ret = untracked(() => fn(() => { - let disposable, k, len: number; - for (k = 0, len = d.length; k < len; k++) { - disposable = d[k]; - disposable(); - } + let k, len: number; + for (k = 0, len = d.length; k < len; k++) d[k](); d = []; }) ); - globalContext = context; + globalContext = globalContext.owner; return ret; }; @@ -29,7 +30,88 @@ export function cleanup(fn: () => void) { } export function computed(fn: (prev?: T) => T) { - let current: T, - dispose = autorun(() => current = fn(current)); - cleanup(dispose); + let current: T, d: any[]; + const context = { + disposables: d = [], + owner: globalContext + }, + dispose = autorun(() => { + for (let k = 0, len = d.length; k < len; k++) d[k](); + d = []; + globalContext = context; + current = fn(current) + globalContext = globalContext.owner; + }); + cleanup(() => { + for (let k = 0, len = d.length; k < len; k++) d[k](); + dispose(); + }); +} + +function lookup(owner: ContextOwner, key: symbol | string): any { + return (owner && owner.context && owner.context[key]) || (owner.owner && lookup(owner.owner, key)); +} + +export function setContext(key: symbol | string, value: any) { + if (globalContext === null) return console.warn("Context keys cannot be set without a root or parent"); + const context = globalContext.context || (globalContext.context = {}); + context[key] = value; +} + +export function createContext(initFn: any) { + const id = Symbol('context'); + return { id, initFn }; +} + +export function useContext(context: Context) { + if (globalContext === null) return console.warn("Context keys cannot be looked up without a root or parent"); + return lookup(globalContext, context.id); +} + +// Suspense Context +export const SuspenseContext = createContext(() => { + let counter = 0; + const obsv = observable.box(0), + store = { + increment: () => ++counter === 1 && !store.initializing && obsv.set(counter), + decrement: () => --counter === 0 && obsv.set(counter), + suspended: () => { + obsv.get(); + return !!counter; + }, + initializing: true + } + return store; +}); + +// used in the runtime to seed the Suspend control flow +export function registerSuspense(fn: (o: { suspended: () => any, initializing: boolean }) => void) { + computed(() => { + const c = SuspenseContext.initFn(); + setContext(SuspenseContext.id, c); + fn(c); + c.initializing = false; + }); +}; + +// lazy load a function component asyncronously +export function lazy(fn: () => Promise<{default: T}>) { + return (props: object) => { + const getComp = loadResource(fn().then(mod => mod.default)) + let Comp: T | undefined; + return () => (Comp = getComp()) && untracked(() => (Comp as T)(props)); + } +} + +// load any async resource and return an accessor +export function loadResource(p: Promise) { + const { increment, decrement } = useContext(SuspenseContext) || { increment: undefined, decrement: undefined}; + const results = observable.box(), + error = observable.box(); + increment && increment(); + p.then(data => results.set(data)) + .catch(err => error.set(err)) + .finally(() => decrement && decrement()); + (results as (any & { error: () => any})).error = error; + return results.get.bind(results); } \ No newline at end of file diff --git a/src/h.ts b/src/h.ts index f8b668a..9667baa 100644 --- a/src/h.ts +++ b/src/h.ts @@ -2,5 +2,5 @@ import { createHyperScript } from 'hyper-dom-expressions'; import * as r from './index'; -export { root, cleanup, selectWhen, selectEach } from './index'; +export * from './index'; export const h = createHyperScript(r); \ No newline at end of file diff --git a/src/html.ts b/src/html.ts index 6f1208a..8f091ef 100644 --- a/src/html.ts +++ b/src/html.ts @@ -2,5 +2,5 @@ import { createHTML } from 'lit-dom-expressions'; import * as r from './index'; -export { root, cleanup, selectWhen, selectEach } from './index'; +export * from './index'; export const html = createHTML(r); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 9a6f937..40b0f9d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { autorun } from 'mobx'; import { cleanup } from './core'; -export { cleanup, root } from './core' +export * from './core' export * from './runtime' type DelegatableNode = Node & { model: any } diff --git a/src/runtime.d.ts b/src/runtime.d.ts index c23b297..10a276b 100644 --- a/src/runtime.d.ts +++ b/src/runtime.d.ts @@ -5,7 +5,9 @@ export function delegateEvents(eventNames: string[]): void; export function clearDelegatedEvents(): void; export function spread(node: HTMLElement, accessor: any): void; export function classList(node: HTMLElement, value: { [k: string]: boolean; }): void; +export function currentContext(): any; export function when(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; export function each(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; export function suspend(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; -export function portal(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; \ No newline at end of file +export function portal(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; +export function provide(parent: Node, accessor: () => any, expr: (...args: any[]) => any, options: any, marker?: Node): void; \ No newline at end of file diff --git a/src/runtime.js b/src/runtime.js index 674f34f..c9597d6 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -1,18 +1,18 @@ import { Attributes } from 'dom-expressions'; -import { untracked } from 'mobx'; -import { root as mRoot, cleanup as mCleanup, computed as mComputed } from './core'; +import { untracked as sample } from 'mobx'; +import { + root, cleanup, computed as wrap, setContext, + registerSuspense, getContextOwner as currentContext + } from './core'; + -const wrap = mComputed, - root = mRoot, - sample = untracked, - cleanup = mCleanup; const GROUPING = '__rGroup', FORWARD = 'nextSibling', BACKWARD = 'previousSibling'; let groupCounter = 0; -export { wrap }; +export { wrap, currentContext }; function normalizeIncomingArray(normalized, array) { for (let i = 0, len = array.length; i < len; i++) { @@ -73,7 +73,7 @@ function removeNodes(parent, node, end) { } function clearAll(parent, current, marker, startNode) { - if (!marker) return parent.textContent = ''; + if (marker === undefined) return parent.textContent = ''; if (Array.isArray(current)) startNode = current[0]; else if (current != null && current != '' && startNode === undefined) { startNode = step(marker.previousSibling, BACKWARD, true); @@ -88,14 +88,15 @@ function insertExpression(parent, value, current, marker) { const t = typeof value; if (t === 'string' || t === 'number') { if (t === 'number') value = value.toString(); - if (marker) { + if (marker !== undefined) { + const startNode = (marker && marker.previousSibling) || parent.lastChild; if (value === '') clearAll(parent, current, marker) else if (current !== '' && typeof current === 'string') { - marker.previousSibling.data = value; + startNode.data = value; } else { const node = document.createTextNode(value); if (current !== '' && current != null) { - parent.replaceChild(node, marker.previousSibling); + parent.replaceChild(node, startNode); } else parent.insertBefore(node, marker); } current = value; @@ -368,7 +369,7 @@ export function each(parent, accessor, expr, options, afterNode) { if (length === 0 || isFallback) { if (beforeNode || afterNode) { let node = beforeNode ? beforeNode.nextSibling : parent.firstChild; - removeNodes(parent, node, afterNode === undefined ? null : afterNode); + removeNodes(parent, node, afterNode ? afterNode : null); } else parent.textContent = ""; disposeAll(); if (length === 0) { @@ -432,8 +433,8 @@ export function each(parent, accessor, expr, options, afterNode) { a = renderedValues[prevEnd], b = data[newStart]; while(a === b) { loop = true; - _node = step(prevEndNode, BACKWARD); - let mark = _node.nextSibling; + let mark = step(prevEndNode, BACKWARD, true); + _node = mark.previousSibling; if (newStartNode !== mark) { insertNodes(parent, mark, prevEndNode.nextSibling, newStartNode) prevEndNode = _node; @@ -568,53 +569,67 @@ export function each(parent, accessor, expr, options, afterNode) { } export function suspend(parent, accessor, expr, options, marker) { - let beforeNode, disposable, current, first = true; + let beforeNode, disposable, current; const { fallback } = options, - doc = document.implementation.createHTMLDocument(), - rendered = sample(expr); + doc = document.implementation.createHTMLDocument(); if (marker) beforeNode = marker.previousSibling; for (let name of eventRegistry.keys()) doc.addEventListener(name, eventHandler); Object.defineProperty(doc.body, 'host', { get() { return (marker && marker.parentNode) || parent; } }); cleanup(function dispose() { disposable && disposable(); }); - wrap(cached => { - const value = !!accessor(); - let node; - if (value === cached) return cached; - parent = (marker && marker.parentNode) || parent; - if (value) { - if (first) { - insertExpression(doc.body, rendered); - first = false; - } else { - node = beforeNode ? beforeNode.nextSibling : parent.firstChild; - while (node && node !== marker) { - const next = node.nextSibling; - doc.body.appendChild(node); - node = next; + function suspense(options) { + const rendered = sample(expr); + wrap(cached => { + const value = !!options.suspended(); + if (value === cached) return cached; + let node; + parent = (marker && marker.parentNode) || parent; + if (value) { + if (options.initializing) insertExpression(doc.body, rendered); + else { + node = beforeNode ? beforeNode.nextSibling : parent.firstChild; + while (node && node !== marker) { + const next = node.nextSibling; + doc.body.appendChild(node); + node = next; + } } + if (fallback) { + sample(() => root(disposer => { + disposable = disposer; + current = insertExpression(parent, fallback(), null, marker) + })); + } + return value; } - if (fallback) { - sample(() => root(disposer => { - disposable = disposer; - current = insertExpression(parent, fallback(), null, marker) - })); + if (options.initializing) insertExpression(parent, rendered, null, marker); + else { + if (disposable) { + clearAll(parent, current, marker, beforeNode ? beforeNode.nextSibling : parent.firstChild); + disposable(); + } + while (node = doc.body.firstChild) parent.insertBefore(node, marker); } return value; - } - if (first) { - insertExpression(parent, rendered, null, marker); - first = false; - } else { - if (disposable) { - clearAll(parent, current, marker, beforeNode ? beforeNode.nextSibling : parent.firstChild); - disposable(); - } - while (node = doc.body.firstChild) parent.insertBefore(node, marker); - } - return value; - }); + }); + } + + if (accessor) { + const config = { suspended: accessor, initializing: true } + suspense(config); + config.initializing = false; + } else registerSuspense(suspense); + +} + +export function provide(parent, accessor, expr, options, marker) { + const Context = accessor(), + { value } = options; + insertExpression(parent, () => sample(() => { + setContext(Context.id, Context.initFn ? Context.initFn(value) : value); + return expr(); + }), undefined, marker); } export function portal(parent, accessor, expr, options, marker) {