diff --git a/src/behaviors/Visibility/Visibility.d.ts b/src/behaviors/Visibility/Visibility.d.ts index 3e8bbd13a3..dc7ad7fdb8 100644 --- a/src/behaviors/Visibility/Visibility.d.ts +++ b/src/behaviors/Visibility/Visibility.d.ts @@ -9,6 +9,9 @@ export interface VisibilityProps { /** Primary content. */ children?: React.ReactNode; + /** Context which sticky element should stick to. */ + context?: object; + /** * When set to true a callback will occur anytime an element passes a condition not just immediately after the * threshold is met. diff --git a/src/behaviors/Visibility/Visibility.js b/src/behaviors/Visibility/Visibility.js index 1d8944bc24..4c1126eee1 100644 --- a/src/behaviors/Visibility/Visibility.js +++ b/src/behaviors/Visibility/Visibility.js @@ -20,6 +20,9 @@ export default class Visibility extends Component { /** Primary content. */ children: PropTypes.node, + /** Context which visibility should attach onscroll events. */ + context: PropTypes.object, + /** * When set to true a callback will occur anytime an element passes a condition not just immediately after the * threshold is met. @@ -138,6 +141,7 @@ export default class Visibility extends Component { } static defaultProps = { + context: window, continuous: false, once: true, } @@ -166,11 +170,13 @@ export default class Visibility extends Component { } componentDidMount() { - window.addEventListener('scroll', this.handleScroll) + const { context } = this.props + context.addEventListener('scroll', this.handleScroll) } componentWillUnmount() { - window.removeEventListener('scroll', this.handleScroll) + const { context } = this.props + context.removeEventListener('scroll', this.handleScroll) } execute = (callback, name) => { diff --git a/src/modules/Sticky/Sticky.d.ts b/src/modules/Sticky/Sticky.d.ts index ecb8a1bb34..6229beb5b9 100644 --- a/src/modules/Sticky/Sticky.d.ts +++ b/src/modules/Sticky/Sticky.d.ts @@ -55,6 +55,9 @@ export interface StickyProps { /** Whether element should be "pushed" by the viewport, attaching to the bottom of the screen when scrolling up. */ pushing?: boolean; + + /** Context which sticky should attach onscroll events. */ + scrollContext?: object; } declare const Sticky: React.ComponentClass; diff --git a/src/modules/Sticky/Sticky.js b/src/modules/Sticky/Sticky.js index b0433ff7de..3b7cd0316c 100644 --- a/src/modules/Sticky/Sticky.js +++ b/src/modules/Sticky/Sticky.js @@ -66,11 +66,15 @@ export default class Sticky extends Component { /** Whether element should be "pushed" by the viewport, attaching to the bottom of the screen when scrolling up. */ pushing: PropTypes.bool, + + /** Context which sticky should attach onscroll events. */ + scrollContext: PropTypes.object, } static defaultProps = { bottomOffset: 0, offset: 0, + scrollContext: window, } static _meta = { @@ -83,12 +87,14 @@ export default class Sticky extends Component { } componentDidMount() { + const { scrollContext } = this.props this.handleUpdate() - window.addEventListener('scroll', this.handleUpdate) + scrollContext.addEventListener('scroll', this.handleUpdate) } componentWillUnmount() { - window.removeEventListener('scroll', this.handleUpdate) + const { scrollContext } = this.props + scrollContext.removeEventListener('scroll', this.handleUpdate) } // ---------------------------------------- diff --git a/test/specs/behaviors/Visibility/Visibility-test.js b/test/specs/behaviors/Visibility/Visibility-test.js index cd2084af7e..703a37a335 100644 --- a/test/specs/behaviors/Visibility/Visibility-test.js +++ b/test/specs/behaviors/Visibility/Visibility-test.js @@ -103,6 +103,23 @@ describe('Visibility', () => { if (wrapper && wrapper.unmount) wrapper.unmount() }) + it('should use window as default scroll context', () => { + const onUpdate = sandbox.spy() + mount() + window.dispatchEvent(new Event('scroll')) + onUpdate.should.have.been.called() + }) + + it('should set a scroll context', () => { + const div = document.createElement('div') + const onUpdate = sandbox.spy() + mount() + window.dispatchEvent(new Event('scroll')) + onUpdate.should.not.have.been.called() + div.dispatchEvent(new Event('scroll')) + onUpdate.should.have.been.called() + }) + describe('calculations', () => { expectations.forEach((expectation) => { it(`calculates ${expectation.name}`, () => { diff --git a/test/specs/modules/Sticky/Sticky-test.js b/test/specs/modules/Sticky/Sticky-test.js index 480580f832..ce42e65af4 100644 --- a/test/specs/modules/Sticky/Sticky-test.js +++ b/test/specs/modules/Sticky/Sticky-test.js @@ -57,6 +57,27 @@ describe('Sticky', () => { window.requestAnimationFrame = requestAnimationFrame }) + it('should use window as default scroll context', () => { + const onStick = sandbox.spy() + const wrapper = mount() + const instance = wrapper.instance() + instance.triggerRef = { getBoundingClientRect: () => ({ top: -1 }) } + window.dispatchEvent(new Event('scroll')) + onStick.should.have.been.called() + }) + + it('should set a scroll context', () => { + const div = document.createElement('div') + const onStick = sandbox.spy() + const wrapper = mount() + const instance = wrapper.instance() + instance.triggerRef = { getBoundingClientRect: () => ({ top: -1 }) } + window.dispatchEvent(new Event('scroll')) + onStick.should.not.have.been.called() + div.dispatchEvent(new Event('scroll')) + onStick.should.have.been.called() + }) + it('should create two divs', () => { const children = shallow().children()