Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: onUpdate and onDetach APIs for dom pragma #829

Merged
merged 1 commit into from
Sep 23, 2020
Merged
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
4 changes: 4 additions & 0 deletions src/core/interfaces.d.ts
Original file line number Diff line number Diff line change
@@ -171,6 +171,8 @@ export interface DomOptions {
on?: On;
diffType?: DiffType;
onAttach?: () => void;
onUpdate?: () => void;
onDetach?: () => void;
}

export interface VDomOptions {
@@ -1217,6 +1219,8 @@ export interface VNode {
export interface DomVNode extends VNode {
domNode: Text | Element;
onAttach?: () => void;
onUpdate?: () => void;
onDetach?: () => void;
}

export interface ESMDefaultWidgetBase<T extends WidgetBaseTypes> {
14 changes: 12 additions & 2 deletions src/core/vdom.ts
Original file line number Diff line number Diff line change
@@ -557,7 +557,7 @@ export function v(
* Create a VNode for an existing DOM Node.
*/
export function dom(
{ node, attrs = {}, props = {}, on = {}, diffType = 'none', onAttach }: DomOptions,
{ node, attrs = {}, props = {}, on = {}, diffType = 'none', onAttach, onDetach, onUpdate }: DomOptions,
children?: DNode[]
): DomVNode {
return {
@@ -570,7 +570,9 @@ export function dom(
domNode: node,
text: isElementNode(node) ? undefined : node.data,
diffType,
onAttach
onAttach,
onUpdate,
onDetach
};
}

@@ -1923,6 +1925,9 @@ export function renderer(renderer: () => RenderResult): Renderer {
processProperties(next, previousProperties);
runDeferredProperties(next);
}
if (isDomVNode(next.node) && next.node.onUpdate) {
next.node.onUpdate();
}
} else if (item.type === 'delete') {
const { current } = item;
const { exitAnimation, exitAnimationActive } = current.node.properties;
@@ -1931,6 +1936,9 @@ export function renderer(renderer: () => RenderResult): Renderer {
} else {
current.domNode!.parentNode!.removeChild(current.domNode!);
}
if (isDomVNode(current.node) && current.node.onDetach) {
current.node.onDetach();
}
} else if (item.type === 'attach') {
const { instance, attached } = item;
const instanceData = widgetInstanceMap.get(instance);
@@ -2603,6 +2611,8 @@ export function renderer(renderer: () => RenderResult): Renderer {
} else if (wrapper.domNode && wrapper.domNode.parentNode) {
wrapper.domNode.parentNode.removeChild(wrapper.domNode);
}
} else if (isDomVNode(wrapper.node) && wrapper.node.onDetach) {
wrapper.node.onDetach();
}
_idToChildrenWrappers.delete(wrapper.id);
_idToWrapperMap.delete(wrapper.id);
65 changes: 65 additions & 0 deletions tests/core/unit/vdom.tsx
Original file line number Diff line number Diff line change
@@ -5999,6 +5999,71 @@ jsdomDescribe('vdom', () => {
meta.setRenderResult(vnode);
assert.strictEqual(onAttachCallCount, 2);
});
it('Should run onUpdate after the dom node has been updated in the dom', () => {
let onUpdateCallCount = 0;
const myDomNode = document.createElement('div');
const div = document.createElement('div');
let vnode = d({
node: myDomNode,
onUpdate: () => {
onUpdateCallCount++;
}
});
const [Widget, meta] = getWidget(vnode);
const r = renderer(() => w(Widget, {}));
r.mount({ domNode: div, sync: true });
assert.strictEqual(onUpdateCallCount, 0);
meta.setRenderResult(vnode);
assert.strictEqual(onUpdateCallCount, 1);
meta.setRenderResult(vnode);
assert.strictEqual(onUpdateCallCount, 2);
meta.setRenderResult(vnode);
assert.strictEqual(onUpdateCallCount, 3);
});
it('Should run onDetach after the dom node has been removed from the dom', () => {
let onDetachCallCount = 0;
const myDomNode = document.createElement('div');
const div = document.createElement('div');
let vnode = d({
node: myDomNode,
onDetach: () => {
onDetachCallCount++;
}
});
const [Widget, meta] = getWidget(vnode);
const r = renderer(() => w(Widget, {}));
r.mount({ domNode: div, sync: true });
assert.strictEqual(onDetachCallCount, 0);
meta.setRenderResult(vnode);
assert.strictEqual(onDetachCallCount, 0);
meta.setRenderResult(null);
assert.strictEqual(onDetachCallCount, 1);
meta.setRenderResult(vnode);
assert.strictEqual(onDetachCallCount, 1);
});
it('Should run onDetach after the dom node has been removed from the dom in nested dom node', () => {
let onDetachCallCount = 0;
const myDomNode = document.createElement('div');
const div = document.createElement('div');
let vnode = v('div', [
d({
node: myDomNode,
onDetach: () => {
onDetachCallCount++;
}
})
]);
const [Widget, meta] = getWidget(vnode);
const r = renderer(() => w(Widget, {}));
r.mount({ domNode: div, sync: true });
assert.strictEqual(onDetachCallCount, 0);
meta.setRenderResult(vnode);
assert.strictEqual(onDetachCallCount, 0);
meta.setRenderResult(null);
assert.strictEqual(onDetachCallCount, 1);
meta.setRenderResult(vnode);
assert.strictEqual(onDetachCallCount, 1);
});
});

describe('deferred properties', () => {