@wordpress/block-editor
Version:
478 lines (407 loc) • 13.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "RichTextShortcut", {
enumerable: true,
get: function () {
return _shortcut.RichTextShortcut;
}
});
Object.defineProperty(exports, "RichTextToolbarButton", {
enumerable: true,
get: function () {
return _toolbarButton.RichTextToolbarButton;
}
});
Object.defineProperty(exports, "__unstableRichTextInputEvent", {
enumerable: true,
get: function () {
return _inputEvent.__unstableRichTextInputEvent;
}
});
exports.keyboardShortcutContext = exports.inputEventContext = exports.default = void 0;
var _element = require("@wordpress/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _classnames = _interopRequireDefault(require("classnames"));
var _data = require("@wordpress/data");
var _blocks = require("@wordpress/blocks");
var _compose = require("@wordpress/compose");
var _richText = require("@wordpress/rich-text");
var _deprecated = _interopRequireDefault(require("@wordpress/deprecated"));
var _components = require("@wordpress/components");
var _autocomplete = require("../autocomplete");
var _blockEdit = require("../block-edit");
var _formatToolbarContainer = _interopRequireDefault(require("./format-toolbar-container"));
var _store = require("../../store");
var _useUndoAutomaticChange = require("./use-undo-automatic-change");
var _useMarkPersistent = require("./use-mark-persistent");
var _usePasteHandler = require("./use-paste-handler");
var _useBeforeInputRules = require("./use-before-input-rules");
var _useInputRules = require("./use-input-rules");
var _useDelete = require("./use-delete");
var _useEnter = require("./use-enter");
var _useFormatTypes = require("./use-format-types");
var _useRemoveBrowserShortcuts = require("./use-remove-browser-shortcuts");
var _useShortcuts = require("./use-shortcuts");
var _useInputEvents = require("./use-input-events");
var _useInsertReplacementText = require("./use-insert-replacement-text");
var _useFirefoxCompat = require("./use-firefox-compat");
var _formatEdit = _interopRequireDefault(require("./format-edit"));
var _utils = require("./utils");
var _shortcut = require("./shortcut");
var _toolbarButton = require("./toolbar-button");
var _inputEvent = require("./input-event");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const keyboardShortcutContext = (0, _element.createContext)();
exports.keyboardShortcutContext = keyboardShortcutContext;
const inputEventContext = (0, _element.createContext)();
/**
* Removes props used for the native version of RichText so that they are not
* passed to the DOM element and log warnings.
*
* @param {Object} props Props to filter.
*
* @return {Object} Filtered props.
*/
exports.inputEventContext = inputEventContext;
function removeNativeProps(props) {
const {
__unstableMobileNoFocusOnMount,
deleteEnter,
placeholderTextColor,
textAlign,
selectionColor,
tagsToEliminate,
disableEditingMenu,
fontSize,
fontFamily,
fontWeight,
fontStyle,
minWidth,
maxWidth,
setRef,
disableSuggestions,
disableAutocorrection,
...restProps
} = props;
return restProps;
}
function RichTextWrapper({
children,
tagName = 'div',
value: originalValue = '',
onChange: originalOnChange,
isSelected: originalIsSelected,
multiline,
inlineToolbar,
wrapperClassName,
autocompleters,
onReplace,
placeholder,
allowedFormats,
withoutInteractiveFormatting,
onRemove,
onMerge,
onSplit,
__unstableOnSplitAtEnd: onSplitAtEnd,
__unstableOnSplitMiddle: onSplitMiddle,
identifier,
preserveWhiteSpace,
__unstablePastePlainText: pastePlainText,
__unstableEmbedURLOnPaste,
__unstableDisableFormats: disableFormats,
disableLineBreaks,
__unstableAllowPrefixTransformations,
...props
}, forwardedRef) {
if (multiline) {
(0, _deprecated.default)('wp.blockEditor.RichText multiline prop', {
since: '6.1',
version: '6.3',
alternative: 'nested blocks (InnerBlocks)',
link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/'
});
}
const instanceId = (0, _compose.useInstanceId)(RichTextWrapper);
identifier = identifier || instanceId;
props = removeNativeProps(props);
const anchorRef = (0, _element.useRef)();
const {
clientId
} = (0, _blockEdit.useBlockEditContext)();
const selector = select => {
const {
getSelectionStart,
getSelectionEnd
} = select(_store.store);
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
let isSelected;
if (originalIsSelected === undefined) {
isSelected = selectionStart.clientId === clientId && selectionEnd.clientId === clientId && selectionStart.attributeKey === identifier;
} else if (originalIsSelected) {
isSelected = selectionStart.clientId === clientId;
}
return {
selectionStart: isSelected ? selectionStart.offset : undefined,
selectionEnd: isSelected ? selectionEnd.offset : undefined,
isSelected
};
}; // This selector must run on every render so the right selection state is
// retreived from the store on merge.
// To do: fix this somehow.
const {
selectionStart,
selectionEnd,
isSelected
} = (0, _data.useSelect)(selector);
const {
getSelectionStart,
getSelectionEnd,
getBlockRootClientId
} = (0, _data.useSelect)(_store.store);
const {
selectionChange
} = (0, _data.useDispatch)(_store.store);
const multilineTag = (0, _utils.getMultilineTag)(multiline);
const adjustedAllowedFormats = (0, _utils.getAllowedFormats)({
allowedFormats,
disableFormats
});
const hasFormats = !adjustedAllowedFormats || adjustedAllowedFormats.length > 0;
let adjustedValue = originalValue;
let adjustedOnChange = originalOnChange; // Handle deprecated format.
if (Array.isArray(originalValue)) {
(0, _deprecated.default)('wp.blockEditor.RichText value prop as children type', {
since: '6.1',
version: '6.3',
alternative: 'value prop as string',
link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/'
});
adjustedValue = _blocks.children.toHTML(originalValue);
adjustedOnChange = newValue => originalOnChange(_blocks.children.fromDOM((0, _richText.__unstableCreateElement)(document, newValue).childNodes));
}
const onSelectionChange = (0, _element.useCallback)((start, end) => {
const selection = {};
const unset = start === undefined && end === undefined;
if (typeof start === 'number' || unset) {
// If we are only setting the start (or the end below), which
// means a partial selection, and we're not updating a selection
// with the same client ID, abort. This means the selected block
// is a parent block.
if (end === undefined && getBlockRootClientId(clientId) !== getBlockRootClientId(getSelectionEnd().clientId)) {
return;
}
selection.start = {
clientId,
attributeKey: identifier,
offset: start
};
}
if (typeof end === 'number' || unset) {
if (start === undefined && getBlockRootClientId(clientId) !== getBlockRootClientId(getSelectionStart().clientId)) {
return;
}
selection.end = {
clientId,
attributeKey: identifier,
offset: end
};
}
selectionChange(selection);
}, [clientId, identifier]);
const {
formatTypes,
prepareHandlers,
valueHandlers,
changeHandlers,
dependencies
} = (0, _useFormatTypes.useFormatTypes)({
clientId,
identifier,
withoutInteractiveFormatting,
allowedFormats: adjustedAllowedFormats
});
function addEditorOnlyFormats(value) {
return valueHandlers.reduce((accumulator, fn) => fn(accumulator, value.text), value.formats);
}
function removeEditorOnlyFormats(value) {
formatTypes.forEach(formatType => {
// Remove formats created by prepareEditableTree, because they are editor only.
if (formatType.__experimentalCreatePrepareEditableTree) {
value = (0, _richText.removeFormat)(value, formatType.name, 0, value.text.length);
}
});
return value.formats;
}
function addInvisibleFormats(value) {
return prepareHandlers.reduce((accumulator, fn) => fn(accumulator, value.text), value.formats);
}
const {
value,
getValue,
onChange,
ref: richTextRef
} = (0, _richText.__unstableUseRichText)({
value: adjustedValue,
onChange(html, {
__unstableFormats,
__unstableText
}) {
adjustedOnChange(html);
Object.values(changeHandlers).forEach(changeHandler => {
changeHandler(__unstableFormats, __unstableText);
});
},
selectionStart,
selectionEnd,
onSelectionChange,
placeholder,
__unstableIsSelected: isSelected,
__unstableMultilineTag: multilineTag,
__unstableDisableFormats: disableFormats,
preserveWhiteSpace,
__unstableDependencies: [...dependencies, tagName],
__unstableAfterParse: addEditorOnlyFormats,
__unstableBeforeSerialize: removeEditorOnlyFormats,
__unstableAddInvisibleFormats: addInvisibleFormats
});
const autocompleteProps = (0, _autocomplete.useBlockEditorAutocompleteProps)({
onReplace,
completers: autocompleters,
record: value,
onChange
});
(0, _useMarkPersistent.useMarkPersistent)({
html: adjustedValue,
value
});
const keyboardShortcuts = (0, _element.useRef)(new Set());
const inputEvents = (0, _element.useRef)(new Set());
function onFocus() {
anchorRef.current?.focus();
}
const TagName = tagName;
return (0, _element.createElement)(_element.Fragment, null, isSelected && (0, _element.createElement)(keyboardShortcutContext.Provider, {
value: keyboardShortcuts
}, (0, _element.createElement)(inputEventContext.Provider, {
value: inputEvents
}, (0, _element.createElement)(_components.Popover.__unstableSlotNameProvider, {
value: "__unstable-block-tools-after"
}, children && children({
value,
onChange,
onFocus
}), (0, _element.createElement)(_formatEdit.default, {
value: value,
onChange: onChange,
onFocus: onFocus,
formatTypes: formatTypes,
forwardedRef: anchorRef
})))), isSelected && hasFormats && (0, _element.createElement)(_formatToolbarContainer.default, {
inline: inlineToolbar,
editableContentElement: anchorRef.current,
value: value
}), (0, _element.createElement)(TagName // Overridable props.
, (0, _extends2.default)({
role: "textbox",
"aria-multiline": !disableLineBreaks,
"aria-label": placeholder
}, props, autocompleteProps, {
ref: (0, _compose.useMergeRefs)([forwardedRef, autocompleteProps.ref, props.ref, richTextRef, (0, _useBeforeInputRules.useBeforeInputRules)({
value,
onChange
}), (0, _useInputRules.useInputRules)({
getValue,
onChange,
__unstableAllowPrefixTransformations,
formatTypes,
onReplace,
selectionChange
}), (0, _useInsertReplacementText.useInsertReplacementText)(), (0, _useRemoveBrowserShortcuts.useRemoveBrowserShortcuts)(), (0, _useShortcuts.useShortcuts)(keyboardShortcuts), (0, _useInputEvents.useInputEvents)(inputEvents), (0, _useUndoAutomaticChange.useUndoAutomaticChange)(), (0, _usePasteHandler.usePasteHandler)({
isSelected,
disableFormats,
onChange,
value,
formatTypes,
tagName,
onReplace,
onSplit,
onSplitMiddle,
__unstableEmbedURLOnPaste,
multilineTag,
preserveWhiteSpace,
pastePlainText
}), (0, _useDelete.useDelete)({
value,
onMerge,
onRemove
}), (0, _useEnter.useEnter)({
removeEditorOnlyFormats,
value,
onReplace,
onSplit,
onSplitMiddle,
multilineTag,
onChange,
disableLineBreaks,
onSplitAtEnd
}), (0, _useFirefoxCompat.useFirefoxCompat)({
value,
onChange
}), anchorRef]),
contentEditable: true,
suppressContentEditableWarning: true,
className: (0, _classnames.default)('block-editor-rich-text__editable', props.className, 'rich-text')
})));
}
const ForwardedRichTextContainer = (0, _element.forwardRef)(RichTextWrapper);
ForwardedRichTextContainer.Content = ({
value,
tagName: Tag,
multiline,
...props
}) => {
// Handle deprecated `children` and `node` sources.
if (Array.isArray(value)) {
(0, _deprecated.default)('wp.blockEditor.RichText value prop as children type', {
since: '6.1',
version: '6.3',
alternative: 'value prop as string',
link: 'https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields/'
});
value = _blocks.children.toHTML(value);
}
const MultilineTag = (0, _utils.getMultilineTag)(multiline);
if (!value && MultilineTag) {
value = `<${MultilineTag}></${MultilineTag}>`;
}
const content = (0, _element.createElement)(_element.RawHTML, null, value);
if (Tag) {
const {
format,
...restProps
} = props;
return (0, _element.createElement)(Tag, restProps, content);
}
return content;
};
ForwardedRichTextContainer.isEmpty = value => {
return !value || value.length === 0;
};
/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/rich-text/README.md
*/
var _default = ForwardedRichTextContainer;
exports.default = _default;
//# sourceMappingURL=index.js.map