Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ The element tags are the bread and butter of your slide content. Most of these t

This tag does not extend from Base. It's special. Wrapping elements in the appear tag makes them appear/disappear in order in response to navigation.

|Name|PropType|Description|
|---|---|---|
|order|PropTypes.number| An optional integer starting at 1 for the presentation order of the Appear tags within a slide. If a slide contains ordered and unordered Appear tags, the unordered will show first.


<a name="blockquote-quote-and-cite-base"></a>
#### BlockQuote, Quote and Cite (Base)

Expand Down
11 changes: 9 additions & 2 deletions src/components/appear.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ class Appear extends Component {
this.setState({ active: true });
return;
}

const order = this.props.order || 0;
const node = findDOMNode(this.fragmentRef);
if (!node.dataset) {
node.dataset = {};
}
node.dataset.order = order;
}

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -55,7 +62,6 @@ class Appear extends Component {
const child = React.Children.only(this.props.children);
const endValue = this.state.active ? 1 : 0;
const transitionDuration = this.props.transitionDuration;

return (
<VictoryAnimation
data={{ opacity: endValue }}
Expand All @@ -64,7 +70,7 @@ class Appear extends Component {
>
{({ opacity }) =>
React.cloneElement(child, {
className: 'fragment',
className: `fragment ${child.props.className}`.trim(),
style: { ...child.props.style, ...this.props.style, opacity },
ref: f => {
this.fragmentRef = f;
Expand All @@ -82,6 +88,7 @@ Appear.defaultProps = {
Appear.propTypes = {
children: PropTypes.node,
fragment: PropTypes.object,
order: PropTypes.number,
route: PropTypes.object,
style: PropTypes.object,
transitionDuration: PropTypes.number
Expand Down
30 changes: 17 additions & 13 deletions src/components/slide.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,24 @@ class Slide extends React.PureComponent {
this.setZoom();
const slide = this.slideRef;
const frags = slide.querySelectorAll('.fragment');
let currentOrder = 0;
if (frags && frags.length && !this.context.overview) {
Array.prototype.slice.call(frags, 0).forEach((frag, i) => {
frag.dataset.fid = i;
return (
this.props.dispatch &&
this.props.dispatch(
addFragment({
slide: this.props.hash,
id: `${this.props.slideIndex}-${i}`,
visible: this.props.lastSlideIndex > this.props.slideIndex,
})
)
);
});
Array.prototype.slice.call(frags, 0)
.sort((lhs, rhs) => parseInt(lhs.dataset.order, 10) - parseInt(rhs.dataset.order, 10))
.forEach(frag => {
frag.dataset.fid = currentOrder;
if (this.props.dispatch) {
this.props.dispatch(
addFragment({
className: frag.className || '',
slide: this.props.hash,
id: `${this.props.slideIndex}-${currentOrder}`,
visible: this.props.lastSlideIndex > this.props.slideIndex,
})
);
}
currentOrder += 1;
});
}
window.addEventListener('load', this.setZoom);
window.addEventListener('resize', this.setZoom);
Expand Down
71 changes: 70 additions & 1 deletion src/components/slide.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Slide from './slide';
import Appear from './appear';

const _mockContext = function() {
return {
Expand All @@ -15,7 +16,9 @@ const _mockContext = function() {
},
},
store: {
getState: () => ({ route: '' }),
getState: () => ({ route: { params: '', slide: 0 } }),
subscribe: () => {},
dispatch: () => {}
},
};
};
Expand Down Expand Up @@ -75,4 +78,70 @@ describe('<Slide />', () => {
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toBeCalledWith(5);
});

test('should create <Appear /> fragments with their appearance in order', () => {
const spy = jest.fn();
mount(
<Slide slideIndex={4} dispatch={spy} hash={4}>
<Appear order={2} fragment={{ fragments: [] }}>
<div className="second">This shows second</div>
</Appear>
<Appear order={3} fragment={{ fragments: [] }}>
<div className="third">This shows third</div>
</Appear>
<Appear order={1} fragment={{ fragments: [] }}>
<div className="first">This shows first</div>
</Appear>
</Slide>,
{ context: _mockContext() }
);
expect(spy).toHaveBeenCalledTimes(3);
expect(spy.mock.calls).toEqual([
[{
payload: { slide: 4, id: '4-0', visible: false, className: 'fragment first' },
type: 'ADD_FRAGMENT'
}],
[{
payload: { slide: 4, id: '4-1', visible: false, className: 'fragment second' },
type: 'ADD_FRAGMENT'
}],
[{
payload: { slide: 4, id: '4-2', visible: false, className: 'fragment third' },
type: 'ADD_FRAGMENT'
}]
]);
});

test('should order <Appear /> fragments without an order first', () => {
const spy = jest.fn();
mount(
<Slide slideIndex={7} dispatch={spy} hash={7}>
<Appear order={1} fragment={{ fragments: [] }}>
<div className="first">This shows second</div>
</Appear>
<Appear fragment={{ fragments: [] }}>
<div className="no-order">This shows third</div>
</Appear>
<Appear order={2} fragment={{ fragments: [] }}>
<div className="second">This shows first</div>
</Appear>
</Slide>,
{ context: _mockContext() }
);
expect(spy).toHaveBeenCalledTimes(3);
expect(spy.mock.calls).toEqual([
[{
payload: { slide: 7, id: '7-0', visible: false, className: 'fragment no-order' },
type: 'ADD_FRAGMENT'
}],
[{
payload: { slide: 7, id: '7-1', visible: false, className: 'fragment first' },
type: 'ADD_FRAGMENT'
}],
[{
payload: { slide: 7, id: '7-2', visible: false, className: 'fragment second' },
type: 'ADD_FRAGMENT'
}]
]);
});
});