diff --git a/src/dom.js b/src/dom.js index bad27cb..94a9b72 100644 --- a/src/dom.js +++ b/src/dom.js @@ -8,7 +8,17 @@ const isStr = (x) => typeof x === "string"; const isObjectLiteral = (x) => Object.prototype.toString.call(x) === "[object Object]"; -const rename = (obj, oldKey, newKey) => (oldKey in obj ? ((obj[newKey] = obj[oldKey]), delete obj[oldKey], obj) : obj); +const isMark = (x) => x instanceof Mark; + +const isTruthy = (x) => x != null && x !== false; + +function preprocess(options) { + if (options.marks) { + options.children = options.marks; + delete options.marks; + } + return options; +} function postprocess(nodes) { if (!nodes) return null; @@ -63,9 +73,17 @@ function renderNodes(mark) { } return dom; }); - for (const child of children.filter(Boolean).flat(Infinity)) { - if (child._data) { - for (let i = 0; i < nodes.length; i++) { + for (const child of children.filter(isTruthy).flat(Infinity)) { + const n = nodes.length; + if (!isMark(child)) { + for (let i = 0; i < n; i++) { + const node = nodes[i]; + const datum = data[i]; + const text = isFunc(child) ? child(datum, i, data) : child; + node.append(document.createTextNode(text)); + } + } else if (child._data) { + for (let i = 0; i < n; i++) { const node = nodes[i]; const datum = data[i]; const childData = child._data; @@ -78,7 +96,7 @@ function renderNodes(mark) { const clonedChild = child.clone(); clonedChild._data = data; const childNodes = renderNodes(clonedChild); - for (let i = 0; i < nodes.length; i++) nodes[i].append(childNodes[i]); + for (let i = 0; i < n; i++) nodes[i].append(childNodes[i]); } } return nodes; @@ -86,7 +104,7 @@ function renderNodes(mark) { export const renderMark = (mark) => postprocess(renderNodes(mark)); -export const render = (options) => renderMark(svg("svg", rename(options, "marks", "children"))); +export const render = (options) => renderMark(svg("svg", preprocess(options))); export const tag = (ns) => (tag, data, options) => new Mark(ns, tag, data, options); diff --git a/test/output/setDataDrivenNonMarkChildren.html b/test/output/setDataDrivenNonMarkChildren.html new file mode 100644 index 0000000..ceaf017 --- /dev/null +++ b/test/output/setDataDrivenNonMarkChildren.html @@ -0,0 +1,11 @@ +
+ + 0-1 + + + 1-2 + + + 2-3 + +
\ No newline at end of file diff --git a/test/output/setNonMarkChildren.html b/test/output/setNonMarkChildren.html new file mode 100644 index 0000000..8bc88c4 --- /dev/null +++ b/test/output/setNonMarkChildren.html @@ -0,0 +1,7 @@ +
+ hello + + world + + [object Object] +
\ No newline at end of file diff --git a/test/output/setZeroChildren.html b/test/output/setZeroChildren.html new file mode 100644 index 0000000..8cac90a --- /dev/null +++ b/test/output/setZeroChildren.html @@ -0,0 +1,3 @@ +
+ 0 +
\ No newline at end of file diff --git a/test/snapshots.js b/test/snapshots.js index 964e485..7fcee50 100644 --- a/test/snapshots.js +++ b/test/snapshots.js @@ -66,6 +66,10 @@ export function setChildren() { }); } +export function setZeroChildren() { + return renderMark(html("div").with([0])); +} + export function setFalsyChildren() { return render({ marks: [ @@ -80,6 +84,26 @@ export function setFalsyChildren() { }); } +export function setNonMarkChildren() { + return renderMark( + html("div").with([ + "hello", + html("span").with(["world"]), // Similar to textContent + {key: "foo"}, + ]), + ); +} + +export function setDataDrivenNonMarkChildren() { + return renderMark( + html("div").with([ + svg("span", [1, 2, 3]).with([ + (d, i) => `${i}-${d}`, // Data-driven textContent + ]), + ]), + ); +} + export function setDataDrivenAttributes() { return render({ width: 100,