draftjs-utils icon indicating copy to clipboard operation
draftjs-utils copied to clipboard

text-align not persisted on new lines

Open kwarr128 opened this issue 6 years ago • 9 comments

I notice that the text-align attributes (really, anything in the "data" object of a block, but i dont think you are using it here for anything other than text-align) are not carried over to new blocks when hitting the enter key to create a new line. If i'm currently right aligned with my text, I would expect that alignment to continue when hitting the enter key for a new line (this is how bold, underline, lists, etc behave).

I found this issue on draftjs https://github.com/facebook/draft-js/issues/723 that suggests some workarounds that can be done for persisting things in the "data" object when splitting a block. Maybe something similar can be done here in the insertNewUnstyledBlock function https://github.com/jpuri/draftjs-utils/blob/master/js/block.js#L169 (though the name of the function might not make sense anymore if it were to persist styling from the current block)

kwarr128 avatar Mar 01 '18 20:03 kwarr128

That is very good point @kwarr128. I will consider doing it - though I am not sure how soon I can get to it coz of other priorities. Thx :)

jpuri avatar Mar 02 '18 17:03 jpuri

@jpuri I could potentially work on it in a few weeks if you haven't gotten to it by then (and if you're open to a PR for it). I wanted to make sure this is something you'd want first. (my other option being to maintain a fork, but i'd rather contribute back if you think its a good idea)

kwarr128 avatar Mar 02 '18 17:03 kwarr128

It definitely good idea, I will be happy to have a PR for this.

jpuri avatar Mar 02 '18 17:03 jpuri

@jpuri So I finally had time to look into this some more. It turns out I didn't fully understand what was going on at first. Your handleNewLine function only does anything if you are doing a soft line break, or doing a normal line break for a block type that isnt 'unstyled' (with the exception of the list types special cases) in order to just reset the new block type to 'unstyled'. Otherwise, it just returns undefined and lets the draftjs default handling kick in. Maintaining the data properties when resetting block type is arguable, I'm not really sure if it makes sense or not. I'm leaning towards not.

My use case is my own editor (not using your react-draft-wisywig directly, but being inspired by it, and still using this helper library), so i was able to fix my problem myself in my editor's handleReturn function like this:

  handleReturn = event => {
    const { editorState } = this.state;

    // Your handleNewLine function imported from this package
    const newEditorState = handleNewLine(editorState, event);
    if (newEditorState) {
      this.onChange(newEditorState);
      return true;
    }

    // Maintain content of the "data" property of the current block when splitting to create the
    // new block (instead of draftjs normal behavior of not maintaining any part of data).
    // This is adapted from https://github.com/facebook/draft-js/issues/723#issuecomment-367918580
    const contentState = editorState.getCurrentContent();
    const selection = editorState.getSelection();
    const startKey = selection.getStartKey();
    const currentBlock = contentState.getBlockForKey(startKey);
    if (currentBlock) {
      const blockData = currentBlock.getData();
      if (blockData) {
        const newContentState = Modifier.splitBlock(contentState, selection);
        const splitState = EditorState.push(
          editorState,
          newContentState,
          'split-block'
        );
        const splitStateWithData = Modifier.mergeBlockData(
          splitState.getCurrentContent(),
          splitState.getSelection(),
          blockData
        );
        const finalState = EditorState.push(
          editorState,
          splitStateWithData,
          'split-block'
        );
        this.onChange(finalState);
        return true;
      }
    }
    return false;
  }

kwarr128 avatar Mar 21 '18 19:03 kwarr128

@kwarr128 : thanks its useful for me, let me wait and see. If more users complain about this, I will add this fix to repo also.

jpuri avatar May 02 '18 17:05 jpuri

Handler provided by @kwarr128 works great for me. My case is the same: bare draftjs and my own logic. Thanks!

Codeluck avatar May 03 '18 15:05 Codeluck

Looks like @kwarr128's solution works over here too (a year and a half later). I do think this should be default behavior!

jtsternberg avatar Oct 02 '19 21:10 jtsternberg

FYI, I opted for a slightly more hacky approach, but requires me to maintain less code:

/**
 * Replacement react-draft-wysiwyg handleReturn method, where we override the
 * default new line functionality.
 *
 * @since  5.15.27
 *
 * @param  {Object} event The event object.
 *
 * @return {bool}
 */
handleReturn = event => {

	// draftjs-utils handleNewLine will keep prior block properties
	// with a shift + enter. That is the default functionality we want,
	// so we give it a fake event where getModifierState( 'Shift' )
	// always returns true, giving us the desired behavior.
	const fakeEvent = {
		which: event.which,
		getModifierState: key => 'Shift' === key ? true : event.getModifierState('Shift'),
	};

	// Your handleNewLine function imported from this package
	const editorState = handleNewLine(this.state.editorState, fakeEvent);
	if (editorState) {
		this.onEditorChange(editorState);
		return true;
	}

	return false;
};

jtsternberg avatar Oct 02 '19 21:10 jtsternberg

@jpuri So I finally had time to look into this some more. It turns out I didn't fully understand what was going on at first. Your handleNewLine function only does anything if you are doing a soft line break, or doing a normal line break for a block type that isnt 'unstyled' (with the exception of the list types special cases) in order to just reset the new block type to 'unstyled'. Otherwise, it just returns undefined and lets the draftjs default handling kick in. Maintaining the data properties when resetting block type is arguable, I'm not really sure if it makes sense or not. I'm leaning towards not.

My use case is my own editor (not using your react-draft-wisywig directly, but being inspired by it, and still using this helper library), so i was able to fix my problem myself in my editor's handleReturn function like this:

  handleReturn = event => {
    const { editorState } = this.state;

    // Your handleNewLine function imported from this package
    const newEditorState = handleNewLine(editorState, event);
    if (newEditorState) {
      this.onChange(newEditorState);
      return true;
    }

    // Maintain content of the "data" property of the current block when splitting to create the
    // new block (instead of draftjs normal behavior of not maintaining any part of data).
    // This is adapted from https://github.com/facebook/draft-js/issues/723#issuecomment-367918580
    const contentState = editorState.getCurrentContent();
    const selection = editorState.getSelection();
    const startKey = selection.getStartKey();
    const currentBlock = contentState.getBlockForKey(startKey);
    if (currentBlock) {
      const blockData = currentBlock.getData();
      if (blockData) {
        const newContentState = Modifier.splitBlock(contentState, selection);
        const splitState = EditorState.push(
          editorState,
          newContentState,
          'split-block'
        );
        const splitStateWithData = Modifier.mergeBlockData(
          splitState.getCurrentContent(),
          splitState.getSelection(),
          blockData
        );
        const finalState = EditorState.push(
          editorState,
          splitStateWithData,
          'split-block'
        );
        this.onChange(finalState);
        return true;
      }
    }
    return false;
  }

code works perfectly but there's one issue with it, when i hit space i preserve alignment, but the cursor is gone, but if i type any symbol it appears again, but if i delete symbol from that line cursor is gone again, so apparently if it's an empty string there will be no cursor blinking on this line, which is weird)

although when i'm not using any alignment everything is working correctly (i mean a cursor)

so can i force selection on this line somehow? this should solve another my issue, when hitting enter like a dozens of type and start typing it jumps right into that line, and i want to have that exact line to be visible, like for example here in github editor, no matter how many enters you hit you will always be on the right line

upd: it appears that cursor dissapearing even if i just click on any of the "align" buttons, if row is empty

@jpuri or @kwarr128 pls can you help?

x3malmusic avatar Nov 24 '22 18:11 x3malmusic