Files

102 lines
3.1 KiB
TypeScript

/**
* External dependencies
*/
import { renderHTMLFromMarkdown } from '@automattic/jetpack-ai-client';
import { rawHandler } from '@wordpress/blocks';
import { useDispatch } from '@wordpress/data';
import { useCallback, useRef } from '@wordpress/element';
import debugFactory from 'debug';
import type { Block } from '@automattic/jetpack-ai-client';
const debug = debugFactory( 'voice-to-content:use-transcription-inserter' );
/**
* The return value for the transcription inserter hook.
*/
export type UseTranscriptionInserterReturn = {
upsertTranscription: ( transcription: string ) => void;
};
/**
* Hook to handle the insertion of the transcription into the editor.
*
* @returns {UseTranscriptionInserterReturn} - Object with function to handle transcription upserting.
*/
export default function useTranscriptionInserter(): UseTranscriptionInserterReturn {
const { updateBlockAttributes, insertBlocks, replaceInnerBlocks } =
useDispatch( 'core/block-editor' );
/*
* List of blocks currently on the editor.
*/
const currentBlocks = useRef< Block[] >( [] );
const upsertTranscription = useCallback(
( transcription: string ) => {
debug( 'Upserting transcription' );
/*
* Convert the markdown to HTML
*/
const html = renderHTMLFromMarkdown( { content: transcription || '' } );
/*
* Parse the HTML into blocks
*/
const blocksFromHTML = rawHandler( { HTML: html } );
/*
* Go through the blocks and update or insert them
*/
for ( let i = 0; i < blocksFromHTML.length; i++ ) {
/*
* If the block is already there, update its content
*/
if ( i < currentBlocks.current.length ) {
const currentblockClientId = currentBlocks.current[ i ].clientId;
const currentBlockContent = currentBlocks.current[ i ].attributes?.content;
/*
* If the block has content, update it
*/
if (
blocksFromHTML[ i ].attributes?.content &&
currentBlockContent !== blocksFromHTML[ i ].attributes?.content
) {
updateBlockAttributes( currentblockClientId, {
content: blocksFromHTML[ i ].attributes.content,
} );
}
/*
* If the block has inner blocks, update them
*/
if ( blocksFromHTML[ i ].innerBlocks.length > 0 ) {
replaceInnerBlocks( currentblockClientId, blocksFromHTML[ i ].innerBlocks );
}
} else {
/*
* The block is not there, insert it. Using the insertBlocks version since
* it allows to manage the block focus after inserting, disabling the focus
* on the inserted block. To do it, it's necessary to set index and rootClientId
* as undefined so they are set to the default values. updateSelection is set to
* true to stay as the default value. The last parameter is set to null to prevent
* focusing the inserted block, the behavior we want.
*/
insertBlocks( [ blocksFromHTML[ i ] ], undefined, undefined, true, null );
/*
* Append the new block to the list of current blocks
*/
currentBlocks.current.push( blocksFromHTML[ i ] );
}
}
},
[ currentBlocks, insertBlocks, updateBlockAttributes, replaceInnerBlocks ]
);
return {
upsertTranscription,
};
}