: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
const listener = event => {
// Do nothing if clicking ref's element or descendent elements, or if the ref is not referencing an element
if (!ref.current || ref.current.contains(event.target)) {
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
// Disable reason: `ref` is a ref object and should not be included in a
// hook's dependency list.
// eslint-disable-next-line react-hooks/exhaustive-deps
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/autocomplete/index.js
const getNodeText = node => {
if (node instanceof Array) {
return node.map(getNodeText).join('');
return getNodeText(node.props.children);
const EMPTY_FILTERED_OPTIONS = [];
function useAutocomplete({
const instanceId = (0,external_wp_compose_namespaceObject.useInstanceId)(useAutocomplete);
const [selectedIndex, setSelectedIndex] = (0,external_wp_element_namespaceObject.useState)(0);
const [filteredOptions, setFilteredOptions] = (0,external_wp_element_namespaceObject.useState)(EMPTY_FILTERED_OPTIONS);
const [filterValue, setFilterValue] = (0,external_wp_element_namespaceObject.useState)('');
const [autocompleter, setAutocompleter] = (0,external_wp_element_namespaceObject.useState)(null);
const [AutocompleterUI, setAutocompleterUI] = (0,external_wp_element_namespaceObject.useState)(null);
const backspacing = (0,external_wp_element_namespaceObject.useRef)(false);
function insertCompletion(replacement) {
if (autocompleter === null) {
const end = record.start;
const start = end - autocompleter.triggerPrefix.length - filterValue.length;
const toInsert = (0,external_wp_richText_namespaceObject.create)({
html: (0,external_wp_element_namespaceObject.renderToString)(replacement)
onChange((0,external_wp_richText_namespaceObject.insert)(record, toInsert, start, end));
function select(option) {
if (getOptionCompletion) {
const completion = getOptionCompletion(option.value, filterValue);
const isCompletionObject = obj => {
return obj !== null && typeof obj === 'object' && 'action' in obj && obj.action !== undefined && 'value' in obj && obj.value !== undefined;
const completionObject = isCompletionObject(completion) ? completion : {
action: 'insert-at-caret',
if ('replace' === completionObject.action) {
onReplace([completionObject.value]);
// When replacing, the component will unmount, so don't reset
// state (below) on an unmounted component.
} else if ('insert-at-caret' === completionObject.action) {
insertCompletion(completionObject.value);
// Reset autocomplete state after insertion rather than before
// so insertion events don't cause the completion menu to redisplay.
setFilteredOptions(EMPTY_FILTERED_OPTIONS);
setAutocompleterUI(null);
* Load options for an autocompleter.
function onChangeOptions(options) {
setSelectedIndex(options.length === filteredOptions.length ? selectedIndex : 0);
setFilteredOptions(options);
function handleKeyDown(event) {
backspacing.current = event.key === 'Backspace';
if (filteredOptions.length === 0) {
if (event.defaultPrevented) {
const newIndex = (selectedIndex === 0 ? filteredOptions.length : selectedIndex) - 1;
setSelectedIndex(newIndex);
// See the related PR as to why this is necessary: https://github.com/WordPress/gutenberg/pull/54902.
if ((0,external_wp_keycodes_namespaceObject.isAppleOS)()) {
(0,external_wp_a11y_namespaceObject.speak)(getNodeText(filteredOptions[newIndex].label), 'assertive');
const newIndex = (selectedIndex + 1) % filteredOptions.length;
setSelectedIndex(newIndex);
if ((0,external_wp_keycodes_namespaceObject.isAppleOS)()) {
(0,external_wp_a11y_namespaceObject.speak)(getNodeText(filteredOptions[newIndex].label), 'assertive');
setAutocompleterUI(null);
select(filteredOptions[selectedIndex]);
// Any handled key should prevent original behavior. This relies on
// the early return in the default case.
// textContent is a primitive (string), memoizing is not strictly necessary
// but this is a preemptive performance improvement, since the autocompleter
// is a potential bottleneck for the editor type metric.
const textContent = (0,external_wp_element_namespaceObject.useMemo)(() => {
if ((0,external_wp_richText_namespaceObject.isCollapsed)(record)) {
return (0,external_wp_richText_namespaceObject.getTextContent)((0,external_wp_richText_namespaceObject.slice)(record, 0));
(0,external_wp_element_namespaceObject.useEffect)(() => {
// Find the completer with the highest triggerPrefix index in the
const completer = completers.reduce((lastTrigger, currentCompleter) => {
const triggerIndex = textContent.lastIndexOf(currentCompleter.triggerPrefix);
const lastTriggerIndex = lastTrigger !== null ? textContent.lastIndexOf(lastTrigger.triggerPrefix) : -1;
return triggerIndex > lastTriggerIndex ? currentCompleter : lastTrigger;
const triggerIndex = textContent.lastIndexOf(triggerPrefix);
const textWithoutTrigger = textContent.slice(triggerIndex + triggerPrefix.length);
const tooDistantFromTrigger = textWithoutTrigger.length > 50; // 50 chars seems to be a good limit.
// This is a final barrier to prevent the effect from completing with
// an extremely long string, which causes the editor to slow-down
// significantly. This could happen, for example, if `matchingWhileBackspacing`
// is true and one of the "words" end up being too long. If that's the case,
// it will be caught by this guard.
if (tooDistantFromTrigger) {
const mismatch = filteredOptions.length === 0;
const wordsFromTrigger = textWithoutTrigger.split(/\s/);
// We need to allow the effect to run when not backspacing and if there
// was a mismatch. i.e when typing a trigger + the match string or when
// clicking in an existing trigger word on the page. We do that if we
// detect that we have one word from trigger in the current textual context.
// Ex.: "Some text @a" <-- "@a" will be detected as the trigger word and
// allow the effect to run. It will run until there's a mismatch.
const hasOneTriggerWord = wordsFromTrigger.length === 1;
// This is used to allow the effect to run when backspacing and if
// "touching" a word that "belongs" to a trigger. We consider a "trigger
// word" any word up to the limit of 3 from the trigger character.
// Anything beyond that is ignored if there's a mismatch. This allows
// us to "escape" a mismatch when backspacing, but still imposing some
// Ex: "Some text @marcelo sekkkk" <--- "kkkk" caused a mismatch, but
// if the user presses backspace here, it will show the completion popup again.
const matchingWhileBackspacing = backspacing.current && wordsFromTrigger.length <= 3;
if (mismatch && !(matchingWhileBackspacing || hasOneTriggerWord)) {
const textAfterSelection = (0,external_wp_richText_namespaceObject.getTextContent)((0,external_wp_richText_namespaceObject.slice)(record, undefined, (0,external_wp_richText_namespaceObject.getTextContent)(record).length));
if (allowContext && !allowContext(textContent.slice(0, triggerIndex), textAfterSelection)) {
if (/^\s/.test(textWithoutTrigger) || /\s\s+$/.test(textWithoutTrigger)) {
if (!/[\u0000-\uFFFF]*$/.test(textWithoutTrigger)) {
const safeTrigger = escapeRegExp(completer.triggerPrefix);
const text = remove_accents_default()(textContent);
const match = text.slice(text.lastIndexOf(completer.triggerPrefix)).match(new RegExp(`${safeTrigger}([\u0000-\uFFFF]*)$`));
const query = match && match[1];
setAutocompleter(completer);
setAutocompleterUI(() => completer !== autocompleter ? getAutoCompleterUI(completer) : AutocompleterUI);
setFilterValue(query === null ? '' : query);
// Temporarily disabling exhaustive-deps to avoid introducing unexpected side effecst.
// See https://github.com/WordPress/gutenberg/pull/41820
// eslint-disable-next-line react-hooks/exhaustive-deps
} = filteredOptions[selectedIndex] || {};
const isExpanded = !!autocompleter && filteredOptions.length > 0;
const listBoxId = isExpanded ? `components-autocomplete-listbox-${instanceId}` : undefined;
const activeId = isExpanded ? `components-autocomplete-item-${instanceId}-${selectedKey}` : null;
const hasSelection = record.start !== undefined;
onKeyDown: withIgnoreIMEEvents(handleKeyDown),
popover: hasSelection && AutocompleterUI && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(AutocompleterUI, {
filterValue: filterValue,
selectedIndex: selectedIndex,
onChangeOptions: onChangeOptions,
function useLastDifferentValue(value) {
const history = (0,external_wp_element_namespaceObject.useRef)(new Set());
history.current.add(value);
// Keep the history size to 2.
if (history.current.size > 2) {
history.current.delete(Array.from(history.current)[0]);
return Array.from(history.current)[0];
function useAutocompleteProps(options) {
const ref = (0,external_wp_element_namespaceObject.useRef)(null);
const onKeyDownRef = (0,external_wp_element_namespaceObject.useRef)();
const previousRecord = useLastDifferentValue(record);
onKeyDownRef.current = onKeyDown;
const mergedRefs = (0,external_wp_compose_namespaceObject.useMergeRefs)([ref, (0,external_wp_compose_namespaceObject.useRefEffect)(element => {
function _onKeyDown(event) {
onKeyDownRef.current?.(event);
element.addEventListener('keydown', _onKeyDown);
element.removeEventListener('keydown', _onKeyDown);
// We only want to show the popover if the user has typed something.
const didUserInput = record.text !== previousRecord?.text;
'aria-autocomplete': listBoxId ? 'list' : undefined,
'aria-activedescendant': activeId
} = useAutocomplete(options);
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
children: [children(props), isSelected && popover]
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/base-control/hooks.js
* Generate props for the `BaseControl` and the inner control itself.
* Namely, it takes care of generating a unique `id`, properly associating it with the `label` and `help` elements.
function useBaseControlProps(props) {
const uniqueId = (0,external_wp_compose_namespaceObject.useInstanceId)(base_control, 'wp-components-base-control', preferredId);
'aria-describedby': `${uniqueId}__help`
;// CONCATENATED MODULE: ./node_modules/@wordpress/icons/build-module/library/link.js
const link_link = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
xmlns: "http://www.w3.org/2000/svg",
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
d: "M10 17.389H8.444A5.194 5.194 0 1 1 8.444 7H10v1.5H8.444a3.694 3.694 0 0 0 0 7.389H10v1.5ZM14 7h1.556a5.194 5.194 0 0 1 0 10.39H14v-1.5h1.556a3.694 3.694 0 0 0 0-7.39H14V7Zm-4.5 6h5v-1.5h-5V13Z"
/* harmony default export */ const library_link = (link_link);
;// CONCATENATED MODULE: ./node_modules/@wordpress/icons/build-module/library/link-off.js
const linkOff = /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.SVG, {
xmlns: "http://www.w3.org/2000/svg",
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_primitives_namespaceObject.Path, {
d: "M17.031 4.703 15.576 4l-1.56 3H14v.03l-2.324 4.47H9.5V13h1.396l-1.502 2.889h-.95a3.694 3.694 0 0 1 0-7.389H10V7H8.444a5.194 5.194 0 1 0 0 10.389h.17L7.5 19.53l1.416.719L15.049 8.5h.507a3.694 3.694 0 0 1 0 7.39H14v1.5h1.556a5.194 5.194 0 0 0 .273-10.383l1.202-2.304Z"
/* harmony default export */ const link_off = (linkOff);
;// CONCATENATED MODULE: ./node_modules/@wordpress/components/build-module/border-box-control/styles.js
function border_box_control_styles_EMOTION_STRINGIFIED_CSS_ERROR_() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
const borderBoxControl = /*#__PURE__*/emotion_react_browser_esm_css( true ? "" : 0, true ? "" : 0);
const linkedBorderControl = () => /*#__PURE__*/emotion_react_browser_esm_css("flex:1;", rtl({
})(), ";" + ( true ? "" : 0), true ? "" : 0);
styles: "position:relative"
const borderBoxControlLinkedButton = size => {
return /*#__PURE__*/emotion_react_browser_esm_css("position:absolute;top:", size === '__unstable-large' ? '8px' : '3px', ";", rtl({
})(), " line-height:0;" + ( true ? "" : 0), true ? "" : 0);
const borderBoxStyleWithFallback = border => {
color = COLORS.gray[200],
width = config_values.borderWidth
const clampedWidth = width !== config_values.borderWidth ? `clamp(1px, ${width}, 10px)` : width;
const hasVisibleBorder = !!width && width !== '0' || !!color;
const borderStyle = hasVisibleBorder ? style || 'solid' : style;
return `${color} ${borderStyle} ${clampedWidth}`;
const borderBoxControlVisualizer = (borders, size) => {
return /*#__PURE__*/emotion_react_browser_esm_css("position:absolute;top:", size === '__unstable-large' ? '20px' : '15px', ";right:", size === '__unstable-large' ? '39px' : '29px', ";bottom:", size === '__unstable-large' ? '20px' : '15px', ";left:", size === '__unstable-large' ? '39px' : '29px', ";border-top:", borderBoxStyleWithFallback(borders?.top), ";border-bottom:", borderBoxStyleWithFallback(borders?.bottom), ";", rtl({
borderLeft: borderBoxStyleWithFallback(borders?.left)
borderRight: borderBoxStyleWithFallback(borders?.right)
})(), ";" + ( true ? "" : 0), true ? "" : 0);