Skip to content

Commit a5ce18c

Browse files
committed
add onUpdate and onDetach API for dom pragme
1 parent d7cf6b9 commit a5ce18c

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

src/core/interfaces.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ export interface DomOptions {
171171
on?: On;
172172
diffType?: DiffType;
173173
onAttach?: () => void;
174+
onUpdate?: () => void;
175+
onDetach?: () => void;
174176
}
175177

176178
export interface VDomOptions {
@@ -1217,6 +1219,8 @@ export interface VNode {
12171219
export interface DomVNode extends VNode {
12181220
domNode: Text | Element;
12191221
onAttach?: () => void;
1222+
onUpdate?: () => void;
1223+
onDetach?: () => void;
12201224
}
12211225

12221226
export interface ESMDefaultWidgetBase<T extends WidgetBaseTypes> {

src/core/vdom.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ export function v(
557557
* Create a VNode for an existing DOM Node.
558558
*/
559559
export function dom(
560-
{ node, attrs = {}, props = {}, on = {}, diffType = 'none', onAttach }: DomOptions,
560+
{ node, attrs = {}, props = {}, on = {}, diffType = 'none', onAttach, onDetach, onUpdate }: DomOptions,
561561
children?: DNode[]
562562
): DomVNode {
563563
return {
@@ -570,7 +570,9 @@ export function dom(
570570
domNode: node,
571571
text: isElementNode(node) ? undefined : node.data,
572572
diffType,
573-
onAttach
573+
onAttach,
574+
onUpdate,
575+
onDetach
574576
};
575577
}
576578

@@ -1923,6 +1925,9 @@ export function renderer(renderer: () => RenderResult): Renderer {
19231925
processProperties(next, previousProperties);
19241926
runDeferredProperties(next);
19251927
}
1928+
if (isDomVNode(next.node) && next.node.onUpdate) {
1929+
next.node.onUpdate();
1930+
}
19261931
} else if (item.type === 'delete') {
19271932
const { current } = item;
19281933
const { exitAnimation, exitAnimationActive } = current.node.properties;
@@ -1931,6 +1936,9 @@ export function renderer(renderer: () => RenderResult): Renderer {
19311936
} else {
19321937
current.domNode!.parentNode!.removeChild(current.domNode!);
19331938
}
1939+
if (isDomVNode(current.node) && current.node.onDetach) {
1940+
current.node.onDetach();
1941+
}
19341942
} else if (item.type === 'attach') {
19351943
const { instance, attached } = item;
19361944
const instanceData = widgetInstanceMap.get(instance);
@@ -2603,6 +2611,8 @@ export function renderer(renderer: () => RenderResult): Renderer {
26032611
} else if (wrapper.domNode && wrapper.domNode.parentNode) {
26042612
wrapper.domNode.parentNode.removeChild(wrapper.domNode);
26052613
}
2614+
} else if (isDomVNode(wrapper.node) && wrapper.node.onDetach) {
2615+
wrapper.node.onDetach();
26062616
}
26072617
_idToChildrenWrappers.delete(wrapper.id);
26082618
_idToWrapperMap.delete(wrapper.id);

tests/core/unit/vdom.tsx

+65
Original file line numberDiff line numberDiff line change
@@ -5999,6 +5999,71 @@ jsdomDescribe('vdom', () => {
59995999
meta.setRenderResult(vnode);
60006000
assert.strictEqual(onAttachCallCount, 2);
60016001
});
6002+
it('Should run onUpdate after the dom node has been updated in the dom', () => {
6003+
let onUpdateCallCount = 0;
6004+
const myDomNode = document.createElement('div');
6005+
const div = document.createElement('div');
6006+
let vnode = d({
6007+
node: myDomNode,
6008+
onUpdate: () => {
6009+
onUpdateCallCount++;
6010+
}
6011+
});
6012+
const [Widget, meta] = getWidget(vnode);
6013+
const r = renderer(() => w(Widget, {}));
6014+
r.mount({ domNode: div, sync: true });
6015+
assert.strictEqual(onUpdateCallCount, 0);
6016+
meta.setRenderResult(vnode);
6017+
assert.strictEqual(onUpdateCallCount, 1);
6018+
meta.setRenderResult(vnode);
6019+
assert.strictEqual(onUpdateCallCount, 2);
6020+
meta.setRenderResult(vnode);
6021+
assert.strictEqual(onUpdateCallCount, 3);
6022+
});
6023+
it('Should run onDetach after the dom node has been removed from the dom', () => {
6024+
let onDetachCallCount = 0;
6025+
const myDomNode = document.createElement('div');
6026+
const div = document.createElement('div');
6027+
let vnode = d({
6028+
node: myDomNode,
6029+
onDetach: () => {
6030+
onDetachCallCount++;
6031+
}
6032+
});
6033+
const [Widget, meta] = getWidget(vnode);
6034+
const r = renderer(() => w(Widget, {}));
6035+
r.mount({ domNode: div, sync: true });
6036+
assert.strictEqual(onDetachCallCount, 0);
6037+
meta.setRenderResult(vnode);
6038+
assert.strictEqual(onDetachCallCount, 0);
6039+
meta.setRenderResult(null);
6040+
assert.strictEqual(onDetachCallCount, 1);
6041+
meta.setRenderResult(vnode);
6042+
assert.strictEqual(onDetachCallCount, 1);
6043+
});
6044+
it('Should run onDetach after the dom node has been removed from the dom in nested dom node', () => {
6045+
let onDetachCallCount = 0;
6046+
const myDomNode = document.createElement('div');
6047+
const div = document.createElement('div');
6048+
let vnode = v('div', [
6049+
d({
6050+
node: myDomNode,
6051+
onDetach: () => {
6052+
onDetachCallCount++;
6053+
}
6054+
})
6055+
]);
6056+
const [Widget, meta] = getWidget(vnode);
6057+
const r = renderer(() => w(Widget, {}));
6058+
r.mount({ domNode: div, sync: true });
6059+
assert.strictEqual(onDetachCallCount, 0);
6060+
meta.setRenderResult(vnode);
6061+
assert.strictEqual(onDetachCallCount, 0);
6062+
meta.setRenderResult(null);
6063+
assert.strictEqual(onDetachCallCount, 1);
6064+
meta.setRenderResult(vnode);
6065+
assert.strictEqual(onDetachCallCount, 1);
6066+
});
60026067
});
60036068

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

0 commit comments

Comments
 (0)