Skip to content

Commit

Permalink
feat: Allow ScrollSyncPane to belong to multiple groups
Browse files Browse the repository at this point in the history
  • Loading branch information
jakent authored and okonet committed Aug 14, 2018
1 parent 5d6b000 commit 3000067
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 39 deletions.
68 changes: 37 additions & 31 deletions src/ScrollSync.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,34 @@ export default class ScrollSync extends Component {

panes = {}

registerPane = (node, group) => {
if (!this.panes[group]) {
this.panes[group] = []
}
registerPane = (node, groups) => {
groups.forEach((group) => {
if (!this.panes[group]) {
this.panes[group] = []
}

if (!this.findPane(node, group)) {
if (this.panes[group].length > 0) {
this.syncScrollPosition(this.panes[group][0], node)
if (!this.findPane(node, group)) {
if (this.panes[group].length > 0) {
this.syncScrollPosition(this.panes[group][0], node)
}
this.panes[group].push(node)
}
this.addEvents(node, group)
this.panes[group].push(node)
}
})
this.addEvents(node, groups)
}

unregisterPane = (node, group) => {
if (this.findPane(node, group)) {
this.removeEvents(node)
this.panes[group].splice(this.panes[group].indexOf(node), 1)
}
unregisterPane = (node, groups) => {
groups.forEach((group) => {
if (this.findPane(node, group)) {
this.removeEvents(node)
this.panes[group].splice(this.panes[group].indexOf(node), 1)
}
})
}

addEvents = (node, group) => {
addEvents = (node, groups) => {
/* For some reason element.addEventListener doesnt work with document.body */
node.onscroll = this.handlePaneScroll.bind(this, node, group) // eslint-disable-line
node.onscroll = this.handlePaneScroll.bind(this, node, groups) // eslint-disable-line
}

removeEvents = (node) => {
Expand All @@ -76,13 +80,13 @@ export default class ScrollSync extends Component {
return this.panes[group].find(pane => pane === node)
}

handlePaneScroll = (node, group) => {
handlePaneScroll = (node, groups) => {
if (!this.props.enabled) {
return
}

window.requestAnimationFrame(() => {
this.syncScrollPositions(node, group)
this.syncScrollPositions(node, groups)
})
}

Expand Down Expand Up @@ -113,18 +117,20 @@ export default class ScrollSync extends Component {
}
}

syncScrollPositions = (scrolledPane, group) => {
this.panes[group].forEach((pane) => {
/* For all panes beside the currently scrolling one */
if (scrolledPane !== pane) {
/* Remove event listeners from the node that we'll manipulate */
this.removeEvents(pane, group)
this.syncScrollPosition(scrolledPane, pane)
/* Re-attach event listeners after we're done scrolling */
window.requestAnimationFrame(() => {
this.addEvents(pane, group)
})
}
syncScrollPositions = (scrolledPane, groups) => {
groups.forEach((group) => {
this.panes[group].forEach((pane) => {
/* For all panes beside the currently scrolling one */
if (scrolledPane !== pane) {
/* Remove event listeners from the node that we'll manipulate */
this.removeEvents(pane, group)
this.syncScrollPosition(scrolledPane, pane)
/* Re-attach event listeners after we're done scrolling */
window.requestAnimationFrame(() => {
this.addEvents(pane, groups)
})
}
})
})
}

Expand Down
18 changes: 10 additions & 8 deletions src/ScrollSyncPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class ScrollSyncPane extends Component {
static propTypes = {
children: PropTypes.node.isRequired,
attachTo: PropTypes.object,
group: PropTypes.string,
group: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
enabled: PropTypes.bool
}

Expand All @@ -28,30 +28,32 @@ export default class ScrollSyncPane extends Component {
}

static contextTypes = {
registerPane: PropTypes.func.isRequired,
unregisterPane: PropTypes.func.isRequired
};
registerPane: PropTypes.func,
unregisterPane: PropTypes.func
}

componentDidMount() {
if (this.props.enabled) {
this.node = this.props.attachTo || ReactDOM.findDOMNode(this)
this.context.registerPane(this.node, this.props.group)
this.context.registerPane(this.node, this.toArray(this.props.group))
}
}

componentWillReceiveProps(nextProps) {
if (this.props.enabled && this.props.group !== nextProps.group) {
this.context.unregisterPane(this.node, this.props.group)
this.context.registerPane(this.node, nextProps.group)
this.context.unregisterPane(this.node, this.toArray(this.props.group))
this.context.registerPane(this.node, this.toArray(nextProps.group))
}
}

componentWillUnmount() {
if (this.props.enabled) {
this.context.unregisterPane(this.node, this.props.group)
this.context.unregisterPane(this.node, this.toArray(this.props.group))
}
}

toArray = groups => [].concat(groups)

render() {
return this.props.children
}
Expand Down
132 changes: 132 additions & 0 deletions src/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,135 @@ Provide an arbitrary group name in the `group` prop to ScrollSyncPane components
</ScrollSync>
```

In some situations, it is also useful for a `ScrollSyncPane` to belong to multiple groups. In these cases, provide an array of group names to the `group` prop.

```
const cellStyle = { minWidth: 200, padding: '.5em 1em', textAlign: 'left', borderLeft: '1px solid white', borderBottom: '1px solid white'};
<ScrollSync>
<div style={{ display: 'flex', position: 'relative', height: 300 }}>
<table style={{ minWidth: 200, borderCollapse: 'collapse' }}>
<thead style={{ display: 'block', minWidth: 200, overflow: 'auto', color: 'white', background: 'grey' }}>
<tr>
<th style={cellStyle}>Fixed Column Header</th>
</tr>
</thead>
<ScrollSyncPane group="vertical">
<tbody style={{ display: 'block', minWidth: 200, height: 200, overflowY: 'auto', background: 'lightblue' }}>
<tr>
<td style={cellStyle}>Fixed Column, Row 1</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 2</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 3</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 4</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 5</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 6</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 7</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 8</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 9</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 10</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 11</td>
</tr>
<tr>
<td style={cellStyle}>Fixed Column, Row 12</td>
</tr>
</tbody>
</ScrollSyncPane>
</table>
<table style={{ width: 400, borderCollapse: 'collapse' }}>
<ScrollSyncPane group="horizontal">
<thead style={{ display: 'block', width: 400, overflow: 'auto', color: 'white', background: 'black' }}>
<tr>
<th style={cellStyle}>Table 2 - Header 1</th>
<th style={cellStyle}>Table 2 - Header 2</th>
<th style={cellStyle}>Table 2 - Header 3</th>
</tr>
</thead>
</ScrollSyncPane>
<ScrollSyncPane group={["horizontal", "vertical"]}>
<tbody style={{ display: 'block', width: 400, height: 200, overflow: 'auto', background: 'pink' }}>
<tr>
<td style={cellStyle}>Cell 1, Row 1</td>
<td style={cellStyle}>Cell 2, Row 1</td>
<td style={cellStyle}>Cell 3, Row 1</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 2</td>
<td style={cellStyle}>Cell 2, Row 2</td>
<td style={cellStyle}>Cell 3, Row 2</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 3</td>
<td style={cellStyle}>Cell 2, Row 3</td>
<td style={cellStyle}>Cell 3, Row 3</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 4</td>
<td style={cellStyle}>Cell 2, Row 4</td>
<td style={cellStyle}>Cell 3, Row 4</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 5</td>
<td style={cellStyle}>Cell 2, Row 5</td>
<td style={cellStyle}>Cell 3, Row 5</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 6</td>
<td style={cellStyle}>Cell 2, Row 6</td>
<td style={cellStyle}>Cell 3, Row 6</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 7</td>
<td style={cellStyle}>Cell 2, Row 7</td>
<td style={cellStyle}>Cell 3, Row 7</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 8</td>
<td style={cellStyle}>Cell 2, Row 8</td>
<td style={cellStyle}>Cell 3, Row 8</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 9</td>
<td style={cellStyle}>Cell 2, Row 9</td>
<td style={cellStyle}>Cell 3, Row 9</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 10</td>
<td style={cellStyle}>Cell 2, Row 10</td>
<td style={cellStyle}>Cell 3, Row 10</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 11</td>
<td style={cellStyle}>Cell 2, Row 11</td>
<td style={cellStyle}>Cell 3, Row 11</td>
</tr>
<tr>
<td style={cellStyle}>Cell 1, Row 12</td>
<td style={cellStyle}>Cell 2, Row 12</td>
<td style={cellStyle}>Cell 3, Row 12</td>
</tr>
</tbody>
</ScrollSyncPane>
</table>
</div>
</ScrollSync>
```

0 comments on commit 3000067

Please sign in to comment.