Gutenberg editor scroll block into view
Asked Answered
I

2

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?

Ionic answered 9/6, 2019 at 11:26 Comment(3)
Wonder if you could use const blockNode = getBlockDOMNode( blockId ) and const scrollContainer = getScrollContainer( blockNode ) as in MultiSelectScrollIntoView. Maybe like scrollIntoView( blockNode, scrollContainer, { onlyScrollIfNeeded: true, } ); . Do we have the block Id from nextBlock.id or with the 'block-' prefix ?Scriabin
Can you create a JSFiddle for this so we can reproduce your issue?Tricrotic
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?Ionic
V
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).

Vermicular answered 27/6, 2019 at 9:16 Comment(3)
Is it working for you? Source and container are valid and seem to be the correct elements, but its not scrolling.Ionic
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?Ionic
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.Vermicular
U
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.

Unfolded answered 22/6, 2019 at 23:57 Comment(4)
I know, but I cant figure that concrete usage in the case of gutenberg.Ionic
@Ionic 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: github.com/WordPress/gutenberg/commit/… . Basically, just add a ref to your created blocks, then get DOM using that ref and pass it to scrollIntoView.Unfolded
and how to add refs to the "block editor container"?Ionic
@Ionic 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.Unfolded
V
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).

Vermicular answered 27/6, 2019 at 9:16 Comment(3)
Is it working for you? Source and container are valid and seem to be the correct elements, but its not scrolling.Ionic
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?Ionic
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.Vermicular

© 2022 - 2024 — McMap. All rights reserved.