Skip to content

Commit 000a313

Browse files
committed
fixed syntax/semantics of hpass() to more closely resemble h()
1 parent e887aea commit 000a313

File tree

2 files changed

+113
-37
lines changed

2 files changed

+113
-37
lines changed

packages/virtualdom/src/index.ts

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,6 @@ class VirtualElement {
762762
*/
763763
export
764764
class VirtualElementPass{
765-
766765
/**
767766
* The type of the node.
768767
*
@@ -774,26 +773,44 @@ class VirtualElementPass{
774773
/**
775774
* Construct a new virtual element pass thru node.
776775
*
777-
* @param renderer - an object with render and unrender functions,
778-
* each of which should take a single argument of type HTMLElement
779-
* and return nothing
780-
*
781776
* @param tag - the tag of the parent element of this node. Once the parent
782777
* element is rendered, it will be passed as an argument to
783778
* renderer.render
784779
*
785-
* @param attrs - optional attributes that will assigned to the
780+
* @param attrs - attributes that will assigned to the
786781
* parent element
782+
*
783+
* @param renderer - an object with render and unrender
784+
* functions, each of which should take a single argument of type
785+
* HTMLElement and return nothing. If null, the parent element
786+
* will be rendered barren without any children.
787787
*/
788-
constructor(readonly renderer: VirtualElementPass.IRenderer, readonly tag: string, readonly attrs: ElementAttrs) {}
788+
constructor(readonly tag: string, readonly attrs: ElementAttrs, readonly renderer: VirtualElementPass.IRenderer | null) {}
789+
790+
render(host: HTMLElement): void {
791+
// skip actual render if renderer is null
792+
if (this.renderer) {
793+
this.renderer.render(host);
794+
}
795+
}
796+
797+
unrender(host: HTMLElement): void {
798+
// skip actual unrender if renderer is null
799+
if (this.renderer) {
800+
this.renderer.unrender(host);
801+
}
802+
}
789803
}
790804

791805

792806
/**
793807
* The namespace for the VirtualElementPass class statics.
794808
*/
795809
export namespace VirtualElementPass {
796-
export type IRenderer = {render: (host: HTMLElement) => void, unrender: (host: HTMLElement) => void};
810+
export type IRenderer = {
811+
render: (host: HTMLElement) => void,
812+
unrender: (host: HTMLElement) => void
813+
};
797814
}
798815

799816

@@ -988,17 +1005,35 @@ namespace h {
9881005
/**
9891006
* Create a new "pass thru" virtual element node.
9901007
*
991-
* @param renderer - an object with render and unrender functions.
992-
*
9931008
* @param tag - The tag name for the parent element.
9941009
*
9951010
* @param attrs - The attributes for the parent element, if any.
9961011
*
1012+
* @param renderer - an object with render and unrender functions, if any.
1013+
*
9971014
* @returns A new "pass thru" virtual element node for the given parameters.
9981015
*
9991016
*/
1000-
export function hpass(renderer: VirtualElementPass.IRenderer, tag: string, attrs: ElementAttrs = {}): VirtualElementPass {
1001-
return new VirtualElementPass(renderer, tag, attrs);
1017+
export function hpass(tag: string, renderer?: VirtualElementPass.IRenderer): VirtualElementPass;
1018+
export function hpass(tag: string, attrs: ElementAttrs, renderer?: VirtualElementPass.IRenderer): VirtualElementPass;
1019+
export function hpass(tag: string): VirtualElementPass {
1020+
let attrs: ElementAttrs = {};
1021+
let renderer: VirtualElementPass.IRenderer | null = null;
1022+
1023+
if (arguments.length === 2) {
1024+
const arg = arguments[1];
1025+
1026+
if ("render" in arg && "unrender" in arg) {
1027+
renderer = arg;
1028+
} else {
1029+
attrs = arg;
1030+
}
1031+
} else if (arguments.length === 3) {
1032+
attrs = arguments[1];
1033+
renderer = arguments[2];
1034+
}
1035+
1036+
return new VirtualElementPass(tag, attrs, renderer);
10021037
}
10031038

10041039

@@ -1103,7 +1138,7 @@ namespace Private {
11031138
addAttrs(host, node.attrs);
11041139

11051140
if (node.type === 'passthru') {
1106-
node.renderer.render(host);
1141+
node.render(host);
11071142
return host;
11081143
}
11091144

@@ -1168,7 +1203,7 @@ namespace Private {
11681203

11691204
// Handle the case of passthru update.
11701205
if (oldVNode.type === 'passthru' && newVNode.type === 'passthru') {
1171-
newVNode.renderer.render(currElem as HTMLElement);
1206+
newVNode.render(currElem as HTMLElement);
11721207
currElem = currElem!.nextSibling;
11731208
continue;
11741209
}
@@ -1252,7 +1287,7 @@ namespace Private {
12521287

12531288
// recursively clean up host children
12541289
if (oldNode.type === 'text') {} else if (oldNode.type === 'passthru') {
1255-
oldNode.renderer.unrender!(child!);
1290+
oldNode.unrender(child!);
12561291
} else {
12571292
removeContent(child!, oldNode.children, 0);
12581293
}

packages/virtualdom/tests/src/index.spec.ts

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('@lumino/virtualdom', () => {
109109
describe('#constructor()', () => {
110110

111111
it('should create a virtual element node', () => {
112-
let vnode = new VirtualElementPass(mockRenderer, 'div', {});
112+
let vnode = new VirtualElementPass('div', {}, mockRenderer);
113113
expect(vnode).to.be.an.instanceof(VirtualElementPass);
114114
});
115115

@@ -118,26 +118,16 @@ describe('@lumino/virtualdom', () => {
118118
describe('#type', () => {
119119

120120
it('should be `element`', () => {
121-
let vnode = new VirtualElementPass(mockRenderer,'div', {});
121+
let vnode = new VirtualElementPass('div', {}, mockRenderer);
122122
expect(vnode.type).to.equal('passthru');
123123
});
124124

125125
});
126126

127-
describe('#renderer', () => {
128-
129-
it('should be the element children renderer', () => {
130-
let vnode = new VirtualElementPass(mockRenderer, 'div', {});
131-
expect(vnode.renderer.render).to.equal(mockRenderer.render);
132-
expect(vnode.renderer.unrender).to.equal(mockRenderer.unrender);
133-
});
134-
135-
});
136-
137127
describe('#tag', () => {
138128

139129
it('should be the element tag name', () => {
140-
let vnode = new VirtualElementPass(mockRenderer,'img', {});
130+
let vnode = new VirtualElementPass('img', {}, mockRenderer);
141131
expect(vnode.tag).to.equal('img');
142132
});
143133

@@ -147,12 +137,22 @@ describe('@lumino/virtualdom', () => {
147137

148138
it('should be the element attrs', () => {
149139
let attrs = { className: 'baz' };
150-
let vnode = new VirtualElementPass(mockRenderer,'img', attrs);
140+
let vnode = new VirtualElementPass('img', attrs, mockRenderer);
151141
expect(vnode.attrs).to.deep.equal(attrs);
152142
});
153143

154144
});
155145

146+
describe('#renderer', () => {
147+
148+
it('should be the element children renderer', () => {
149+
let vnode = new VirtualElementPass('div', {}, mockRenderer);
150+
expect(vnode.renderer!.render).to.equal(mockRenderer.render);
151+
expect(vnode.renderer!.unrender).to.equal(mockRenderer.unrender);
152+
});
153+
154+
});
155+
156156
});
157157

158158
describe('h()', () => {
@@ -346,16 +346,57 @@ describe('@lumino/virtualdom', () => {
346346
});
347347

348348
describe('hpass()', () => {
349+
let tag = 'div';
350+
let attrs = { className: 'baz' };
351+
let mockRenderer = {
352+
render: (host: HTMLElement) => {},
353+
unrender: (host: HTMLElement) =>{}
354+
};
349355

350356
it('should create a new virtual element passthru node', () => {
351357
let vnode = hpass(
352-
{
353-
render: (host: HTMLElement) => {},
354-
unrender: (host: HTMLElement) =>{}
355-
},
358+
tag,
359+
attrs,
360+
mockRenderer
361+
);
362+
expect(vnode).to.be.an.instanceof(VirtualElementPass);
363+
expect(vnode.tag).to.equal(tag);
364+
expect(vnode.attrs).to.deep.equal(attrs);
365+
expect(vnode.renderer!.render).to.equal(mockRenderer.render);
366+
expect(vnode.renderer!.unrender).to.equal(mockRenderer.unrender);
367+
});
368+
369+
it('should create a passthru vnode without attrs', () => {
370+
let vnode = hpass(
371+
'div',
372+
mockRenderer
373+
);
374+
expect(vnode).to.be.an.instanceof(VirtualElementPass);
375+
expect(vnode.tag).to.equal('div');
376+
expect(vnode.attrs).to.deep.equal({});
377+
expect(vnode.renderer!.render).to.equal(mockRenderer.render);
378+
expect(vnode.renderer!.unrender).to.equal(mockRenderer.unrender);
379+
});
380+
381+
it('should create a passthru vnode without renderer', () => {
382+
let vnode = hpass(
383+
'div',
384+
attrs
385+
);
386+
expect(vnode).to.be.an.instanceof(VirtualElementPass);
387+
expect(vnode.tag).to.equal(tag);
388+
expect(vnode.attrs).to.deep.equal(attrs);
389+
expect(vnode.renderer).to.equal(null);
390+
});
391+
392+
it('should create a passthru vnode without attrs or renderer', () => {
393+
let vnode = hpass(
356394
'div'
357395
);
358396
expect(vnode).to.be.an.instanceof(VirtualElementPass);
397+
expect(vnode.tag).to.equal('div');
398+
expect(vnode.attrs).to.deep.equal({});
399+
expect(vnode.renderer).to.equal(null);
359400
});
360401

361402
});
@@ -510,7 +551,7 @@ describe('@lumino/virtualdom', () => {
510551

511552
describe('realize()', () => {
512553
it('should realize successfully', () => {
513-
let node = VirtualDOM.realize(hpass(rendererClosure(), 'span'));
554+
let node = VirtualDOM.realize(hpass('span', rendererClosure()));
514555
expect(node.tagName.toLowerCase()).to.equal('span');
515556
expect(node.children[0].tagName.toLowerCase()).to.equal('div');
516557
expect(node.children[0].className).to.equal('p-render');
@@ -522,7 +563,7 @@ describe('@lumino/virtualdom', () => {
522563
it('should render successfully at top of tree', () => {
523564
let host = document.createElement('div');
524565

525-
VirtualDOM.render(hpass(rendererClosure(), 'span'), host);
566+
VirtualDOM.render(hpass('span', rendererClosure()), host);
526567
expect(host.children[0].tagName.toLowerCase()).to.equal('span');
527568
expect(host.children[0].children[0].tagName.toLowerCase()).to.equal('div');
528569
expect(host.children[0].children[0].className).to.equal('p-render');
@@ -532,7 +573,7 @@ describe('@lumino/virtualdom', () => {
532573
let host = document.createElement('div');
533574
let record: any = {child: undefined, cleanedUp: false};
534575

535-
let children = [h.a(), h.span(), h.div(h.div(), hpass(rendererClosure(record), 'span'), h.div())];
576+
let children = [h.a(), h.span(), h.div(h.div(), hpass('span', rendererClosure(record)), h.div())];
536577
VirtualDOM.render(children, host);
537578
expect(host.children[2].children[1].children[0]).to.equal(record.child);
538579
expect(host.children[2].children[1].children[0].className).to.equal('p-render');
@@ -543,7 +584,7 @@ describe('@lumino/virtualdom', () => {
543584
let record: any = {child: undefined, cleanedUp: false};
544585

545586
// first pass, render the hpass children
546-
let children0 = [h.a(), h.span(), h.div(h.div(), hpass(rendererClosure(record), 'span'), h.div())];
587+
let children0 = [h.a(), h.span(), h.div(h.div(), hpass('span', rendererClosure(record)), h.div())];
547588
VirtualDOM.render(children0, host);
548589

549590
// second pass, explicitly unrender the hpass children

0 commit comments

Comments
 (0)