Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 37 additions & 32 deletions src/wrapMatches.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactNode } from 'react';
import type { ReactNode } from "react";

/**
* Replaces all instances of a target substring in the input with a custom ReactNode.
Expand All @@ -9,23 +9,23 @@ import type { ReactNode } from 'react';
* @returns An array of strings and ReactNodes.
*/
export function wrapMatchesInText(
input: string,
target: string,
render: (match: string, index: number) => ReactNode
input: string,
target: string,
render: (match: string, index: number) => ReactNode,
): ReactNode[] {
if (!target) return [input];
if (!target) return [input];

const parts = input.split(target);
const result: ReactNode[] = [];
const parts = input.split(target);
const result: ReactNode[] = [];

parts.forEach((part, index) => {
result.push(part);
if (index < parts.length - 1) {
result.push(render(target, index));
}
});
parts.forEach((part, index) => {
result.push(part);
if (index < parts.length) {
result.push(render(target, index));
}
});

return result;
return result;
}

/**
Expand All @@ -36,23 +36,28 @@ export function wrapMatchesInText(
* @param matches - An array of { target, render } match definitions
*/
export function wrapMultipleMatchesInText(
input: string | ReactNode[],
matches: {
target: string;
render: (match: string, index: number) => ReactNode;
}[]
input: string | ReactNode[],
matches: {
target: string;
render: (match: string, index: number) => ReactNode;
}[],
): ReactNode[] {
return matches.reduce((current, { target, render }) => {
// Wrap all strings inside the current array
return current.flatMap((node, outerIndex) => {
if (typeof node === 'string') {
// Apply match to string segments only
return wrapMatchesInText(node, target, (match, i) =>
render(match, outerIndex * 1000 + i) // key strategy
);
}
// Leave already-wrapped nodes as-is
return [node];
});
}, typeof input === 'string' ? [input] : input);
return matches.reduce(
(current, { target, render }) => {
// Wrap all strings inside the current array
return current.flatMap((node, outerIndex) => {
if (typeof node === "string") {
// Apply match to string segments only
return wrapMatchesInText(
node,
target,
(match, i) => render(match, outerIndex * 1000 + i), // key strategy
);
}
// Leave already-wrapped nodes as-is
return [node];
});
},
typeof input === "string" ? [input] : input,
);
}
Loading