8

How can I scroll a newly inserted block into the view in the wordpress gutenberg editor?

I am creating the block with

const nextBlock = createBlock( 'core/paragraph' );
wp.data.dispatch( 'core/editor' ).insertBlock( nextBlock );
//scroll the block into the view

I have also seen that gutenberg uses the dom-scroll-into-view package like e.g. here.

Their documentation says:

var scrollIntoView = require('dom-scroll-into-view');
scrollIntoView(source,container,config);

but how can I get it working in my case, how to get the source and container DOM elements?

niklas
  • 2,734
  • 3
  • 31
  • 62
  • Wonder if you could use `const blockNode = getBlockDOMNode( blockId )` and `const scrollContainer = getScrollContainer( blockNode )` as in [MultiSelectScrollIntoView](https://github.com/WordPress/gutenberg/blob/359858da0675943d8a759a0a7c03e7b3846536f5/packages/block-editor/src/components/multi-select-scroll-into-view/index.js). Maybe like `scrollIntoView( blockNode, scrollContainer, { onlyScrollIfNeeded: true, } );` . Do we have the block Id from `nextBlock.id` or with the `'block-'` prefix ? – birgire Jun 22 '19 at 15:35
  • Can you create a JSFiddle for this so we can reproduce your issue? – Lajos Arpad Jun 23 '19 at 13:07
  • 1
    Well I guess not. Its the default wordpress installation with many wordpress specific js and css files. To reproduce, one would have to setup a wordpress environment with wordpress > 5.0 ... but maybe I will find a wordpress playground online somewhere? – niklas Jun 23 '19 at 13:29

2 Answers2

1

dom-scroll-into-view is an NPM package by itself at https://github.com/yiminghe/dom-scroll-into-view

They have a demo available at http://yiminghe.me/dom-scroll-into-view/examples/demo.html

And their main source code is https://github.com/yiminghe/dom-scroll-into-view/blob/master/src/dom-scroll-into-view.js


Short answer:

  • source is the HTML element you want to be brought into view.

  • container is its container element, or you can simply put it to be window if you don't have a particular container wrapping your element.

  • Finally config is an optional object that lets you configurate some fine tuning like a little bit of margin to top of left if you don't want this to hit the exact top border of the browser. You can start by passing {} to it for now.

Aidin
  • 7,505
  • 2
  • 35
  • 33
  • I know, but I cant figure that concrete usage in the case of gutenberg. – niklas Jun 23 '19 at 00:53
  • 1
    @niklas `scrollIntoView` needs DOM elements as it's a pure DOM action. And React doesn't advise accessing DOM elements explicitly. The only workaround is using `ref` which is exactly what the last guy who added `scrollIntoView` to gutenberg has done. Here is the PR that you can follow: https://github.com/WordPress/gutenberg/commit/9e2be1806501ff00ac628f8ec84344603451e164#diff-b35d15bd7807d4f198117c45c99c3443 . Basically, just add a ref to your created blocks, then get DOM using that ref and pass it to scrollIntoView. – Aidin Jun 24 '19 at 01:37
  • and how to add refs to the "block editor container"? – niklas Jun 24 '19 at 09:26
  • 1
    @niklas you might be able to just leave it to be `window` and see how it works. Otherwise, you can follow `this.inserterResults` in the PR I shared. – Aidin Jun 24 '19 at 21:57
1

in my case, how to get the source and container DOM elements?

It's actually quite easy.. just use document.querySelector() to get the block node and then wp.dom.getScrollContainer() to get that node's container:

const nextBlock = wp.blocks.createBlock( 'core/paragraph' );
wp.data.dispatch( 'core/editor' ).insertBlock( nextBlock );

const source = document.querySelector( '[data-block="' + nextBlock.clientId + '"]' );
const container = wp.dom.getScrollContainer( source );

References: One Two

And here's my code:

/**
 * External dependencies
 */
import scrollIntoView from 'dom-scroll-into-view';

/**
 * WordPress dependencies
 */
import { createBlock } from '@wordpress/blocks';     // wp.blocks.createBlock
import { dispatch } from '@wordpress/data';          // wp.data.dispatch
import { getScrollContainer } from '@wordpress/dom'; // wp.dom.getScrollContainer

function getBlockDOMNode( clientId ) {
    return document.querySelector( '[data-block="' + clientId + '"]' );
}

const nextBlock = createBlock( 'core/paragraph' );
dispatch( 'core/editor' ).insertBlock( nextBlock );

const source = getBlockDOMNode( nextBlock.clientId );
const container = source ? getScrollContainer( source ) : null;
if ( source && container ) {
    scrollIntoView( source, container );
}

UPDATE

For testing the imported scrollIntoView(), try this:

function scrollBlockIntoView( block ) {
    const source = getBlockDOMNode( block.clientId );
    const container = source ? getScrollContainer( source ) : null;
    if ( source && container ) {
        console.log( source, container );
        scrollIntoView( source, container );
    }
}

window.scrollBlockIntoView = function( block ) {
    scrollBlockIntoView( block || {} );
};

And then from the browser console, run this:

scrollBlockIntoView( wp.data.select('core/editor').getBlocks()[1] )

But make sure that you have at least two blocks in the editor — e.g. a paragraph with a lengthy content and an image block.

Tried and tested working on Chrome (Windows 10).

Sally CJ
  • 13,617
  • 2
  • 13
  • 29
  • Is it working for you? Source and container are valid and seem to be the correct elements, but its not scrolling. – niklas Jun 27 '19 at 12:58
  • Your solution only works in safari, but I think the answer is complete and correct and closest to what I needed. Guess its a `dom-scroll-into-view` issue? Or might we using it wrong? – niklas Jun 27 '19 at 13:02
  • 1
    So I'm on WordPress 5.2.2. And actually, the `insertBlock()` call actually auto-scrolls the inserted block into view, without having to call `scrollIntoView()`. And yes, the `scrollIntoView()` in my code does work properly. – Sally CJ Jun 27 '19 at 14:16