diff --git a/README.md b/README.md
index bd26a9f..0cd56d0 100644
--- a/README.md
+++ b/README.md
@@ -317,6 +317,14 @@ If defined, allows to specify a different animation delay for each attribute
If defined, allows to specify a different animation easing for each attribute
+
+ # children
+
+
+- Type: Any Valid React Node
+
+If defined, the child node(s) will be created for each entry in dataset, allowing for complex nesting hierarchies of react-animated-dataset
+
## Contributing
If you make some edits and wish to test them locally you can run `yarn test`.
diff --git a/build/AnimatedDataset.js b/build/AnimatedDataset.js
index f0055f3..ca36501 100644
--- a/build/AnimatedDataset.js
+++ b/build/AnimatedDataset.js
@@ -94,7 +94,8 @@ function AnimatedDataset(_ref) {
_ref$easingByAttr = _ref.easingByAttr,
easingByAttr = _ref$easingByAttr === void 0 ? {} : _ref$easingByAttr,
_ref$easing = _ref.easing,
- easing = _ref$easing === void 0 ? easeCubic : _ref$easing;
+ easing = _ref$easing === void 0 ? easeCubic : _ref$easing,
+ children = _ref.children;
var ref = /*#__PURE__*/React.createRef();
var refOldAttrs = React.useRef();
React.useLayoutEffect(function () {
@@ -111,8 +112,10 @@ function AnimatedDataset(_ref) {
var eventsList = Object.keys(events);
var oldAttrs = refOldAttrs.current || {};
var animate = function animate() {
- select(ref.current).selectAll(tag).data(dataset, keyFn).join(function (enter) {
- return enter.append(tag).text(attrs.text).call(function (sel) {
+ select(ref.current).selectAll(tag).data(dataset, function (d) {
+ return d && keyFn(d) || select(this).attr("data-key");
+ }).join(function (enter) {
+ var enterEls = enter.append(tag).call(function (sel) {
attrsList.forEach(function (a) {
sel.attr(a, init.hasOwnProperty(a) ? init[a] : oldAttrs.hasOwnProperty(a) ? oldAttrs[a] : attrs[a]);
});
@@ -126,13 +129,17 @@ function AnimatedDataset(_ref) {
tran.attr(a, attrs[a]);
});
});
+ if (attrs.text) enterEls.text(attrs.text);
+ return enterEls;
}, function (update) {
- return update.text(attrs.text).call(function (sel) {
+ var updateEls = update.call(function (sel) {
attrsList.forEach(function (a) {
var tran = disableAnimation ? sel : sel.transition(a).ease(easingByAttrParsed.hasOwnProperty(a) ? easingByAttrParsed[a] : easing).delay(delayByAttrParsed.hasOwnProperty(a) ? delayByAttrParsed[a] : delay).duration(durationByAttrParsed.hasOwnProperty(a) ? durationByAttrParsed[a] : duration);
tran.attr(a, attrs[a]);
});
});
+ if (attrs.text) updateEls.text(attrs.text);
+ return updateEls;
}, function (exit) {
return exit.call(function (sel) {
attrsList.forEach(function (a) {
@@ -151,7 +158,19 @@ function AnimatedDataset(_ref) {
}, [dataset, unparsedInit, keyFn, ref, tag, unparsedAttrs, duration, disableAnimation, unparsedEvents, delay, easing, durationByAttr, delayByAttr, easingByAttr]);
return /*#__PURE__*/React.createElement('g', {
ref: ref
- });
+ },
+ // Create the structure first so that react can add the children
+ children && dataset.map(function (data) {
+ return /*#__PURE__*/React.createElement(tag, {
+ key: keyFn(data),
+ 'data-key': keyFn(data)
+ }, children && React.Children.toArray(children).map(function (child) {
+ return /*#__PURE__*/React.cloneElement(child, {
+ key: child.toString(),
+ dataset: [data]
+ });
+ }));
+ }));
}
export { AnimatedDataset };
diff --git a/src/AnimatedDataset.js b/src/AnimatedDataset.js
index d90d18c..e1830dd 100644
--- a/src/AnimatedDataset.js
+++ b/src/AnimatedDataset.js
@@ -19,6 +19,7 @@ export function AnimatedDataset({
delayByAttr = {},
easingByAttr = {},
easing = easeCubic,
+ children,
}) {
const ref = React.createRef()
const refOldAttrs = React.useRef()
@@ -40,12 +41,11 @@ export function AnimatedDataset({
const animate = () => {
select(ref.current)
.selectAll(tag)
- .data(dataset, keyFn)
+ .data(dataset, function (d) { return (d && keyFn(d)) || select(this).attr("data-key"); })
.join(
- enter =>
- enter
+ enter => {
+ const enterEls = enter
.append(tag)
- .text(attrs.text)
.call(sel => {
attrsList.forEach(a => {
sel.attr(
@@ -79,23 +79,32 @@ export function AnimatedDataset({
tran.attr(a, attrs[a])
})
- }),
- update =>
- update.text(attrs.text).call(sel => {
- attrsList.forEach(a => {
- const tran = disableAnimation
- ? sel
- : sel
- .transition(a)
- .ease(easingByAttrParsed.hasOwnProperty(a) ? easingByAttrParsed[a] : easing)
- .delay(delayByAttrParsed.hasOwnProperty(a) ? delayByAttrParsed[a] : delay)
- .duration(
- durationByAttrParsed.hasOwnProperty(a) ? durationByAttrParsed[a] : duration
- )
+ })
+ if (attrs.text) enterEls.text(attrs.text)
+ return enterEls
+ },
+
+ update => {
+ const updateEls = update
+ .call(sel => {
+ attrsList.forEach(a => {
+ const tran = disableAnimation
+ ? sel
+ : sel
+ .transition(a)
+ .ease(easingByAttrParsed.hasOwnProperty(a) ? easingByAttrParsed[a] : easing)
+ .delay(delayByAttrParsed.hasOwnProperty(a) ? delayByAttrParsed[a] : delay)
+ .duration(
+ durationByAttrParsed.hasOwnProperty(a) ? durationByAttrParsed[a] : duration
+ )
- tran.attr(a, attrs[a])
+ tran.attr(a, attrs[a])
+ }
+ )
})
- }),
+ if (attrs.text) updateEls.text(attrs.text)
+ return updateEls;
+ },
exit =>
exit.call(sel => {
@@ -139,5 +148,17 @@ export function AnimatedDataset({
easingByAttr,
])
- return React.createElement('g', { ref })
+ return React.createElement(
+ 'g',
+ { ref },
+ // Create the structure first so that react can add the children
+ children && dataset.map(
+ (data) => React.createElement(
+ tag,
+ { key: keyFn(data), 'data-key': keyFn(data) },
+ children && React.Children.toArray(children)
+ .map(child => React.cloneElement(child, { key: child.toString(), dataset: [data] }))
+ )
+ )
+ )
}
diff --git a/tests/AnimatedDataset.test.js b/tests/AnimatedDataset.test.js
index b672996..2122a72 100644
--- a/tests/AnimatedDataset.test.js
+++ b/tests/AnimatedDataset.test.js
@@ -130,4 +130,29 @@ describe(AnimatedDataset, () => {
expect(callArguments[0]).toEqual(dataset[index])
expect(callArguments[1]).toEqual(index)
})
+
+ it('should allow nested nodes', () => {
+ const wrapper = mount(
+
+ t}
+ disableAnimation
+ >
+ t }}
+ keyFn={t => t}
+ disableAnimation
+ />
+
+
+ )
+
+ expect(wrapper.find('g').first().html()).toMatchInlineSnapshot(
+ `"Hello World Goodbye World "`
+ )
+ })
})