Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 32 additions & 36 deletions src/core/vdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,27 @@ export function renderer(renderer: () => RenderResult): Renderer {
return {};
}

function createWidgetOptions(id: string, widgetId: string, middleware?: any) {
return {
id,
properties: () => {
const widgetMeta = widgetMetaMap.get(widgetId);
if (widgetMeta) {
return { ...widgetMeta.properties };
}
return {};
},
children: () => {
const widgetMeta = widgetMetaMap.get(widgetId);
if (widgetMeta) {
return widgetMeta.children || [];
}
return [];
},
middleware
};
}

function resolveMiddleware(
middlewares: any,
id: string,
Expand All @@ -1641,23 +1662,7 @@ export function renderer(renderer: () => RenderResult): Renderer {
const uniqueId = `${id}-${metaId++}`;
for (let i = 0; i < keys.length; i++) {
const middleware = middlewares[keys[i]]();
const payload: any = {
id: uniqueId,
properties: () => {
const widgetMeta = widgetMetaMap.get(id);
if (widgetMeta) {
return { ...widgetMeta.properties };
}
return {};
},
children: () => {
const widgetMeta = widgetMetaMap.get(id);
if (widgetMeta) {
return widgetMeta.children;
}
return [];
}
};
const payload = createWidgetOptions(uniqueId, id);
if (middleware.middlewares) {
const { middlewares: resolvedMiddleware } = resolveMiddleware(
middleware.middlewares,
Expand Down Expand Up @@ -1731,12 +1736,7 @@ export function renderer(renderer: () => RenderResult): Renderer {
invalidate = widgetMeta.invalidator;
}

rendered = Constructor({
id,
properties: () => next.node.properties,
children: () => next.node.children,
middleware: widgetMeta.middleware
});
rendered = Constructor(createWidgetOptions(id, id, widgetMeta.middleware));
widgetMeta.rendering = false;
if (widgetMeta.deferRefs > 0) {
return false;
Expand Down Expand Up @@ -1786,7 +1786,7 @@ export function renderer(renderer: () => RenderResult): Renderer {

function _updateWidget({ current, next }: UpdateWidgetInstruction): ProcessResult {
current = getWNodeWrapper(current.id) || current;
const { instance, domNode, hasAnimations } = current;
const { instance, domNode, hasAnimations, id } = current;
let {
node: { widgetConstructor }
} = next;
Expand All @@ -1800,7 +1800,7 @@ export function renderer(renderer: () => RenderResult): Renderer {
let didRender = false;
let currentChildren = _idToChildrenWrappers.get(current.id);
next.hasAnimations = hasAnimations;
next.id = current.id;
next.id = id;
next.childDomWrapperId = current.childDomWrapperId;
next.properties = next.node.properties;
_wrapperSiblingMap.delete(current);
Expand All @@ -1809,9 +1809,10 @@ export function renderer(renderer: () => RenderResult): Renderer {
}

if (!isWidgetBaseConstructor(Constructor)) {
const widgetMeta = widgetMetaMap.get(next.id);
const widgetMeta = widgetMetaMap.get(id);
if (widgetMeta) {
widgetMeta.properties = next.properties;
widgetMeta.children = next.node.children;
widgetMeta.rendering = true;
runDiffs(widgetMeta, current.properties, next.properties);
if (current.node.children.length > 0 || next.node.children.length > 0) {
Expand All @@ -1828,15 +1829,10 @@ export function renderer(renderer: () => RenderResult): Renderer {
);
}
if (widgetMeta.dirty) {
_idToChildrenWrappers.delete(next.id);
_idToChildrenWrappers.delete(id);
didRender = true;
widgetMeta.dirty = false;
rendered = Constructor({
id: next.id,
properties: () => next.node.properties,
children: () => next.node.children,
middleware: widgetMeta.middleware
});
rendered = Constructor(createWidgetOptions(id, id, widgetMeta.middleware));
if (widgetMeta.deferRefs > 0) {
rendered = null;
}
Expand All @@ -1851,19 +1847,19 @@ export function renderer(renderer: () => RenderResult): Renderer {
instance!.__setChildren__(next.node.children);
if (instanceData.dirty) {
didRender = true;
_idToChildrenWrappers.delete(next.id);
_idToChildrenWrappers.delete(id);
rendered = instance!.__render__();
}
instanceData.rendering = false;
}
_idToWrapperMap.set(next.id, next);
processResult.widget = { type: 'attach', instance, id: next.id, attached: false };
processResult.widget = { type: 'attach', instance, id, attached: false };

let children: DNodeWrapper[] | undefined;
if (rendered) {
rendered = Array.isArray(rendered) ? rendered : [rendered];
children = renderedToWrapper(rendered, next, current);
_idToChildrenWrappers.set(next.id, children);
_idToChildrenWrappers.set(id, children);
}

if (didRender) {
Expand Down
76 changes: 75 additions & 1 deletion tests/core/unit/vdom.ts → tests/core/unit/vdom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import {
widgetInstanceMap,
v,
w,
dom as d
dom as d,
tsx
} from '../../../src/core/vdom';
import { VNode, DNode, DomVNode } from '../../../src/core/interfaces';
import { WidgetBase } from '../../../src/core/WidgetBase';
import Registry from '../../../src/core/Registry';
import { I18nMixin } from '../../../src/core/mixins/I18n';
import icache from '../../../src/core/middleware/icache';
import registry from '../../../src/core/decorators/registry';
import { alwaysRender } from '../../../src/core/decorators/alwaysRender';

Expand Down Expand Up @@ -3430,6 +3432,78 @@ jsdomDescribe('vdom', () => {
assert.isTrue(consoleWarnStub.calledOnce);
});

it('properties should have a live binding', () => {
const factory = create({ icache }).properties<any>();

const RunnerWidget = factory(({ properties, middleware: { icache } }) => {
return (
<div>
<button
onclick={() => {
const { doSomething } = properties();
icache.set('value', doSomething());
}}
>
Click me
</button>
<div>{icache.getOrSet('value', '')}</div>
</div>
);
});

const MyWidget = factory(({ properties }) => {
return (
<RunnerWidget
doSomething={() => {
return properties().value;
}}
/>
);
});

const App = factory(function App({ middleware: { icache } }) {
const value = icache.getOrSet('value', '1');
return (
<div>
<button
onclick={() => {
icache.set('value', `${value}1`);
}}
>
Increment Value
</button>
<MyWidget value={value} />
</div>
);
});

const root = document.createElement('div');
const r = renderer(() => <App />);
r.mount({ domNode: root });
(root as any).children[0].children[0].click();
resolvers.resolve();
(root as any).children[0].children[1].children[0].click();
resolvers.resolve();
assert.strictEqual(
root.outerHTML,
'<div><div><button>Increment Value</button><div><button>Click me</button><div>11</div></div></div></div>'
);
(root as any).children[0].children[0].click();
resolvers.resolve();
(root as any).children[0].children[0].click();
resolvers.resolve();
(root as any).children[0].children[0].click();
resolvers.resolve();
(root as any).children[0].children[0].click();
resolvers.resolve();
(root as any).children[0].children[1].children[0].click();
resolvers.resolve();
assert.strictEqual(
root.outerHTML,
'<div><div><button>Increment Value</button><div><button>Click me</button><div>111111</div></div></div></div>'
);
});

describe('core middleware', () => {
describe('node', () => {
it('should invalidate widget once node is available', () => {
Expand Down