UNPKG

@wordpress/block-editor

Version:
146 lines (120 loc) 3.87 kB
/** * WordPress dependencies */ import { useRef } from '@wordpress/element'; import { useRefEffect } from '@wordpress/compose'; import { insert, toHTMLString } from '@wordpress/rich-text'; import { getBlockTransforms, findTransform } from '@wordpress/blocks'; import { useDispatch } from '@wordpress/data'; /** * Internal dependencies */ import { store as blockEditorStore } from '../../store'; import { preventEventDiscovery } from './prevent-event-discovery'; import { retrieveSelectedAttribute, START_OF_SELECTED_AREA } from '../../utils/selection'; function findSelection(blocks) { let i = blocks.length; while (i--) { const attributeKey = retrieveSelectedAttribute(blocks[i].attributes); if (attributeKey) { blocks[i].attributes[attributeKey] = blocks[i].attributes[attributeKey].replace(START_OF_SELECTED_AREA, ''); return [blocks[i].clientId, attributeKey, 0, 0]; } const nestedSelection = findSelection(blocks[i].innerBlocks); if (nestedSelection) { return nestedSelection; } } return []; } export function useInputRules(props) { const { __unstableMarkLastChangeAsPersistent, __unstableMarkAutomaticChange } = useDispatch(blockEditorStore); const propsRef = useRef(props); propsRef.current = props; return useRefEffect(element => { function inputRule() { const { getValue, onReplace, selectionChange } = propsRef.current; if (!onReplace) { return; } // We must use getValue() here because value may be update // asynchronously. const value = getValue(); const { start, text } = value; const characterBefore = text.slice(start - 1, start); // The character right before the caret must be a plain space. if (characterBefore !== ' ') { return; } const trimmedTextBefore = text.slice(0, start).trim(); const prefixTransforms = getBlockTransforms('from').filter(({ type }) => type === 'prefix'); const transformation = findTransform(prefixTransforms, ({ prefix }) => { return trimmedTextBefore === prefix; }); if (!transformation) { return; } const content = toHTMLString({ value: insert(value, START_OF_SELECTED_AREA, 0, start) }); const block = transformation.transform(content); selectionChange(...findSelection([block])); onReplace([block]); __unstableMarkAutomaticChange(); return true; } function onInput(event) { const { inputType, type } = event; const { getValue, onChange, __unstableAllowPrefixTransformations, formatTypes } = propsRef.current; // Only run input rules when inserting text. if (inputType !== 'insertText' && type !== 'compositionend') { return; } if (__unstableAllowPrefixTransformations && inputRule) { if (inputRule()) return; } const value = getValue(); const transformed = formatTypes.reduce((accumlator, { __unstableInputRule }) => { if (__unstableInputRule) { accumlator = __unstableInputRule(accumlator); } return accumlator; }, preventEventDiscovery(value)); if (transformed !== value) { __unstableMarkLastChangeAsPersistent(); onChange({ ...transformed, activeFormats: value.activeFormats }); __unstableMarkAutomaticChange(); } } element.addEventListener('input', onInput); element.addEventListener('compositionend', onInput); return () => { element.removeEventListener('input', onInput); element.removeEventListener('compositionend', onInput); }; }, []); } //# sourceMappingURL=use-input-rules.js.map