Решить проблему с заменой текста на JSX
Первая проблема это отступ между списками, почему он появляется? Если дописать в конец регулярки \n? (нажимаем чекбокс), тогда его нет, но и чтобы появился между последним списком и текстом отступ, придется писать две строки.
var isRegExp = function (re)
{
return re instanceof RegExp;
};
var escapeRegExp = function escapeRegExp(string)
{
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
reHasRegExpChar = RegExp(reRegExpChar.source);
return (string && reHasRegExpChar.test(string))
? string.replace(reRegExpChar, '\\$&')
: string;
};
var isString = function (value)
{
return typeof value === 'string';
};
var flatten = function (array)
{
var newArray = [];
array.forEach(function (item)
{
if (Array.isArray(item))
{
newArray = newArray.concat(item);
} else
{
newArray.push(item);
}
});
return newArray;
};
function replaceString(str, match, fn)
{
var curCharStart = 0;
var curCharLen = 0;
if (str === '')
{
return str;
} else if (!str || !isString(str))
{
throw new TypeError('First argument to react-string-replace#replaceString must be a string');
}
var re = match;
if (!isRegExp(re))
{
re = new RegExp('(' + escapeRegExp(re) + ')', 'gi');
}
var result = str.split(re);
for (var i = 1, length = result.length; i < length; i += 2)
{
if (result[ i ] === undefined || result[ i - 1 ] === undefined)
{
console.warn('reactStringReplace: Encountered undefined value during string replacement. Your RegExp may not be working the way you expect.');
continue;
}
curCharLen = result[ i ].length;
curCharStart += result[ i - 1 ].length;
result[ i ] = fn(result[ i ], i, curCharStart);
curCharStart += curCharLen;
}
return result;
}
function reactStringReplace(source, match, fn)
{
if (!Array.isArray(source)) source = [ source ];
return flatten(source.map(function (x)
{
return isString(x) ? replaceString(x, match, fn) : x;
}));
}
function randomKey(): string
{
return Date.now() + "" + Math.random();
}
function _wrappedItalic(match: string): ReactNode
{
return <em key={randomKey()}>{match}</em>;
}
function _wrappedBold(match: string): ReactNode
{
return <strong key={randomKey()}>{match}</strong>;
}
function _wrappedBoldAndItalic(match: string): ReactNode
{
return <em key={randomKey()}><strong>{match}</strong></em>;
}
function _wrappedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^-\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ul style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ul>
);
}
function _wrappedOrderedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^\d+\.\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ol style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ol>
);
}
function convertMarkdown(text: string | ReactNodeArray | undefined): ReactNodeArray
{
// Bold and Italic
text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic);
// Bold
text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold);
text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold);
// Italic
text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic);
text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic);
// Unordered Lists
text = reactStringReplace(text, /((?:^-\s+.*\n?)+)(?=\n|$)/gm, _wrappedList);
// Ordered Lists
text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)(?=\n|$)/gm, _wrappedOrderedList);
// Line break
text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />));
return text;
}
function convertMarkdownTwo(text: string | ReactNodeArray | undefined): ReactNodeArray
{
// Bold and Italic
text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic);
// Bold
text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold);
text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold);
// Italic
text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic);
text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic);
// Unordered Lists
text = reactStringReplace(text, /((?:^-\s+.*\n?)+)(?=\n|$)\n?/gm, _wrappedList);
// Ordered Lists
text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)(?=\n|$)\n?/gm, _wrappedOrderedList);
// Line break
text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />));
return text;
}
const { useState } = React;
function App()
{
const [isCheckbox, setIsCheckbox] = useState(false);
const [text, setText] = useState("It’s up to you how you complete the quest. We recommend to complete **one mission per week** for the best results.\n\n- list item 1\n- list item 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n- list item 1\n- list item 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n\nIt will allow you enough time to digest your reflections without losing your momentum.")
return (
<div style={{width: "70%"}}>
<div style={{marginBottom: "15px"}}>
<textarea
style={{width: "100%"}}
rows={6}
value={text}
onChange={
({target}: ChangeEvent<HTMLTextAreaElement>) =>
{
setText(target.value);
}
}
/>
</div>
Preview: <label><input type="checkbox" checked={isCheckbox} onChange={({target}: ChangeEvent<HTMLInputElement>) => setIsCheckbox(target.checked)} />\n?</label>
<hr />
{isCheckbox === false ? convertMarkdown(text) : convertMarkdownTwo(text)}
</div>
);
}
// Рендеринг
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Следующая проблема заключается в следующем, если я захочу в списке выделить какое-то слово курсивом/жирным/курсив и жирный, тогда текст переносится и создается несколько списков, почему это происходит и как исправить?
var isRegExp = function (re)
{
return re instanceof RegExp;
};
var escapeRegExp = function escapeRegExp(string)
{
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
reHasRegExpChar = RegExp(reRegExpChar.source);
return (string && reHasRegExpChar.test(string))
? string.replace(reRegExpChar, '\\$&')
: string;
};
var isString = function (value)
{
return typeof value === 'string';
};
var flatten = function (array)
{
var newArray = [];
array.forEach(function (item)
{
if (Array.isArray(item))
{
newArray = newArray.concat(item);
} else
{
newArray.push(item);
}
});
return newArray;
};
function replaceString(str, match, fn)
{
var curCharStart = 0;
var curCharLen = 0;
if (str === '')
{
return str;
} else if (!str || !isString(str))
{
throw new TypeError('First argument to react-string-replace#replaceString must be a string');
}
var re = match;
if (!isRegExp(re))
{
re = new RegExp('(' + escapeRegExp(re) + ')', 'gi');
}
var result = str.split(re);
for (var i = 1, length = result.length; i < length; i += 2)
{
if (result[ i ] === undefined || result[ i - 1 ] === undefined)
{
console.warn('reactStringReplace: Encountered undefined value during string replacement. Your RegExp may not be working the way you expect.');
continue;
}
curCharLen = result[ i ].length;
curCharStart += result[ i - 1 ].length;
result[ i ] = fn(result[ i ], i, curCharStart);
curCharStart += curCharLen;
}
return result;
}
function reactStringReplace(source, match, fn)
{
if (!Array.isArray(source)) source = [ source ];
return flatten(source.map(function (x)
{
return isString(x) ? replaceString(x, match, fn) : x;
}));
}
function randomKey(): string
{
return Date.now() + "" + Math.random();
}
function _wrappedItalic(match: string): ReactNode
{
return <em key={randomKey()}>{match}</em>;
}
function _wrappedBold(match: string): ReactNode
{
return <strong key={randomKey()}>{match}</strong>;
}
function _wrappedBoldAndItalic(match: string): ReactNode
{
return <em key={randomKey()}><strong>{match}</strong></em>;
}
function _wrappedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^-\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ul style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ul>
);
}
function _wrappedOrderedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^\d+\.\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ol style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ol>
);
}
function convertMarkdown(text: string | ReactNodeArray | undefined): ReactNodeArray
{
// Bold and Italic
text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic);
// Bold
text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold);
text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold);
// Italic
text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic);
text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic);
// Unordered Lists
text = reactStringReplace(text, /((?:^-\s+.*\n?)+)(?=\n|$)\n?/gm, _wrappedList);
// Ordered Lists
text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)(?=\n|$)\n?/gm, _wrappedOrderedList);
// Line break
text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />));
return text;
}
const { useState } = React;
function App()
{
const [text, setText] = useState("It’s up to you how you complete the quest. We recommend to complete **one mission per week** for the best results.\n\n- list item 1\n- list **item** bold 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n- list item 1\n- list item 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n\nIt will allow you enough time to digest your reflections without losing your momentum.")
return (
<div style={{width: "70%"}}>
<div style={{marginBottom: "15px"}}>
<textarea
style={{width: "100%"}}
rows={6}
value={text}
onChange={
({target}: ChangeEvent<HTMLTextAreaElement>) =>
{
setText(target.value);
}
}
/>
</div>
Preview:
<hr />
{convertMarkdown(text)}
</div>
);
}
// Рендеринг
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Ответы (1 шт):
Ответ на первый вопрос: надо убрать (?=\n|$) из регулярки. Я не до конца разобрался, если честно, но насколько я понял эта вещь создавала ещё одну группу для match и потому образовывались пустые строки
function randomKey(): string
{
return Date.now() + "" + Math.random();
}
function _wrappedItalic(match: string): ReactNode
{
return <em key={randomKey()}>{match}</em>;
}
function _wrappedBold(match: string): ReactNode
{
return <strong key={randomKey()}>{match}</strong>;
}
function _wrappedBoldAndItalic(match: string): ReactNode
{
return <em key={randomKey()}><strong>{match}</strong></em>;
}
function _wrappedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^-\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ul style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ul>
);
}
function _wrappedOrderedList(match: string): ReactNode
{
const items: string[] = match.trim().split(/\n|\\n/g)
.map((item) => item.replace(/^\d+\.\s+/, "").trim())
.filter((item) => item.trim() !== "");
return (
<ol style={{ margin: 0 }} key={randomKey()}>
{items.map((item) => <li key={item}>{item}</li>)}
</ol>
);
}
function convertMarkdown(text: string | ReactNodeArray | undefined): ReactNodeArray
{
// Bold and Italic
text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic);
text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic);
// Bold
text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold);
text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold);
// Italic
text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic);
text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic);
// Unordered Lists
text = reactStringReplace(text, /((?:^-\s+.*\n?)+)/gm, _wrappedList);
// Ordered Lists
text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)/gm, _wrappedOrderedList);
// Line break
text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />));
return text;
}
const { useState } = React;
function App() {
const [text, setText] = useState("It’s up to you how you complete the quest. We recommend to complete **one mission per week** for the best results.\n\n- list item 1\n- list item 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n- list item 1\n- list item 2\n- list item 3\n0. item 1\n0. item 2\n0. item 3\n\nIt will allow you enough time to digest your reflections without losing your momentum.")
return (
<div style={{width: "70%"}}>
<div style={{marginBottom: "15px"}}>
<textarea
style={{width: "100%"}}
rows={6}
value={text}
onChange={
({target}: ChangeEvent<HTMLTextAreaElement>) =>
{
setText(target.value);
}
}
/>
</div>
{convertMarkdown(text)}
</div>
);
}
// Рендеринг
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
var isRegExp = function (re)
{
return re instanceof RegExp;
};
var escapeRegExp = function escapeRegExp(string)
{
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
reHasRegExpChar = RegExp(reRegExpChar.source);
return (string && reHasRegExpChar.test(string))
? string.replace(reRegExpChar, '\\$&')
: string;
};
var isString = function (value)
{
return typeof value === 'string';
};
var flatten = function (array)
{
var newArray = [];
array.forEach(function (item)
{
if (Array.isArray(item))
{
newArray = newArray.concat(item);
} else
{
newArray.push(item);
}
});
return newArray;
};
function replaceString(str, match, fn)
{
var curCharStart = 0;
var curCharLen = 0;
if (str === '')
{
return str;
} else if (!str || !isString(str))
{
throw new TypeError('First argument to react-string-replace#replaceString must be a string');
}
var re = match;
if (!isRegExp(re))
{
re = new RegExp('(' + escapeRegExp(re) + ')', 'gi');
}
var result = str.split(re);
for (var i = 1, length = result.length; i < length; i += 2)
{
if (result[ i ] === undefined || result[ i - 1 ] === undefined)
{
console.warn('reactStringReplace: Encountered undefined value during string replacement. Your RegExp may not be working the way you expect.');
continue;
}
curCharLen = result[ i ].length;
curCharStart += result[ i - 1 ].length;
result[ i ] = fn(result[ i ], i, curCharStart);
curCharStart += curCharLen;
}
return result;
}
function reactStringReplace(source, match, fn)
{
if (!Array.isArray(source)) source = [ source ];
return flatten(source.map(function (x)
{
return isString(x) ? replaceString(x, match, fn) : x;
}));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Ответ на второй вопрос: отвратительная библиотека проблема в том, что после очередного форматирования текст попадает в поле children объекта обозначающего какой-то тег, а в самом начале библиотеки написано, что если элемент массива - это не строка, то просто возращать его, а если строка, то работать с ним. Потому возникает острая необходимость в рекурсивном вызвозе библиотеки самой себя
Потому я переписал его изначальный функционал и получилось так:
function reactStringReplace(source, match, fn) { if (!Array.isArray(source)) source = [source]; return flatten(source.map(function(x) { if (isString(x)) return replaceString(x, match, fn); const children = x.props.children; if (isString(children)) x.props.children = reactStringReplace(children); if (Array.isArray(children)) x.props.children = children.map(child => reactStringReplace(child, match, fn)); return x; })); }Там ещё бывают случаи, когда
children- это просто объект, но посмотрев через консоль я увидел что я не попадаю в эти случаи, потому не стал обрабатывать это, но возможно вам в дальнейшем надо будет это сделать для других случаевПервый пункт частично решил проблему, в некоторых местах всё ещё были необработанные звёздочки, опять через консоль посмотрев, я увидел что иногда (честно не понял почему) строка типа
***item***делится на<strong>*item</strong>*и из-за того что одна звезда остаётся заstrong, то при обработке дляItalicона работает не корректно т.к. эта строка хранится как[ { key: 'strong', props: { children: ['* item'] } }, '*' ]И такую структуру он ясно что не сможет обработать для
Italic. Там ещё странности были, но не запомнил если четсно, простите :) Решило проблему перенос обработки спиков раньше всехfunction convertMarkdown(text: string | ReactNodeArray | undefined): ReactNodeArray { // Unordered Lists text = reactStringReplace(text, /((?:^-\s+.*\n?)+)/gm, _wrappedList); // Ordered Lists text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)/gm, _wrappedOrderedList); // Bold and Italic text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic); // Bold text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold); text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold); // Italic text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic); text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic); // Line break text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />)); return text; }function randomKey(): string { return Date.now() + "" + Math.random(); } function _wrappedItalic(match: string): ReactNode { return <em key={randomKey()}>{match}</em>; } function _wrappedBold(match: string): ReactNode { return <strong key={randomKey()}>{match}</strong>; } function _wrappedBoldAndItalic(match: string): ReactNode { return <em key={randomKey()}><strong>{match}</strong></em>; } function _wrappedList(match: string): ReactNode { const items: string[] = match.trim().split(/\n|\\n/g) .map((item) => item.replace(/^-\s+/, "").trim()) .filter((item) => item.trim() !== ""); return ( <ul style={{ margin: 0 }} key={randomKey()}> {items.map((item) => <li key={item}>{item}</li>)} </ul> ); } function _wrappedOrderedList(match: string): ReactNode { const items: string[] = match.trim().split(/\n|\\n/g) .map((item) => item.replace(/^\d+\.\s+/, "").trim()) .filter((item) => item.trim() !== ""); return ( <ol style={{ margin: 0 }} key={randomKey()}> {items.map((item) => <li key={item}>{item}</li>)} </ol> ); } function convertMarkdown(text: string | ReactNodeArray | undefined): ReactNodeArray { // Unordered Lists text = reactStringReplace(text, /((?:^-\s+.*\n?)+)/gm, _wrappedList); // Ordered Lists text = reactStringReplace(text, /((?:^\d+\.\s+.*\n?)+)/gm, _wrappedOrderedList); // Bold and Italic text = reactStringReplace(text, /___(.*?)___/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /\*\*\*(.*?)\*\*\*/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /__\*(.*?)\*__/g, _wrappedBoldAndItalic); text = reactStringReplace(text, /\*\*_(.*?)_\*\*/g, _wrappedBoldAndItalic); // Bold text = reactStringReplace(text, /\*\*(.*?)\*\*/g, _wrappedBold); text = reactStringReplace(text, /__(.*?)__/g, _wrappedBold); // Italic text = reactStringReplace(text, /\*(.*?)\*/g, _wrappedItalic); text = reactStringReplace(text, /_(.*?)_/g, _wrappedItalic); // Line break text = reactStringReplace(text, /(\n|\\n)/g, () => (<br key={randomKey()} />)); return text; } const { useState } = React; function App() { const [text, setText] = useState("It’s up to you how you complete the quest. We recommend to complete **one mission per week** for the best results.\n\n- list item 1\n- list *item* bold 2\n- list item 3\n0. **item** 4\n0. item 5\n0. item 6\n- list ***item*** 7\n- list item 8\n- list item 9\n0. item 10\n0. item 11\n0. item 12\n\nIt will allow you enough time to digest your reflections without losing your momentum.") return ( <div style={{width: "70%"}}> <div style={{marginBottom: "15px"}}> <textarea style={{width: "100%"}} rows={6} value={text} onChange={ ({target}: ChangeEvent<HTMLTextAreaElement>) => { setText(target.value); } } /> </div> Preview: <hr /> {convertMarkdown(text)} </div> ); } // Рендеринг ReactDOM.createRoot(document.getElementById('root')).render(<App/>); var isRegExp = function (re) { return re instanceof RegExp; }; var isString = function (value) { return typeof value === 'string'; }; var escapeRegExp = function escapeRegExp(string) { var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source); return (string && reHasRegExpChar.test(string)) ? string.replace(reRegExpChar, '\\$&') : string; }; var flatten = function (array) { var newArray = []; array.forEach(function (item) { if (Array.isArray(item)) { newArray = newArray.concat(item); } else { newArray.push(item); } }); return newArray; }; function replaceString(str, match, fn) { var curCharStart = 0; var curCharLen = 0; if (str === '') { return str; } else if (!str || !isString(str)) { throw new TypeError('First argument to react-string-replace#replaceString must be a string'); } var re = match; if (!isRegExp(re)) { re = new RegExp('(' + escapeRegExp(re) + ')', 'gi'); } var result = str.split(re); for (var i = 1, length = result.length; i < length; i += 2) { if (result[ i ] === undefined || result[ i - 1 ] === undefined) { console.warn('reactStringReplace: Encountered undefined value during string replacement. Your RegExp may not be working the way you expect.'); continue; } curCharLen = result[ i ].length; curCharStart += result[ i - 1 ].length; result[ i ] = fn(result[ i ], i, curCharStart); curCharStart += curCharLen; } return result; } function reactStringReplace(source, match, fn) { if (!Array.isArray(source)) source = [source]; return flatten(source.map(function(x) { if (isString(x)) return replaceString(x, match, fn); const children = x.props.children; if (isString(children)) x.props.children = reactStringReplace(children); if (Array.isArray(children)) x.props.children = children.map(child => reactStringReplace(child, match, fn)); return x; })); }<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script> <div id="root"></div>
Мой вердикт - не используйте эту библиотеку, она очень не продуманная для сложных вещей
Настоятельно рекомендую найти другую библиотеку или же использовать dangerouslySetInnerHTML={{__html: data}}. Я лично обеими ручками за второй вариант :)
На самый худой конец, напишите свою более продуманную библиотеку вместо этой