Skip to content
Snippets Groups Projects
Commit 9f0bba1b authored by Remi Lazarini's avatar Remi Lazarini
Browse files

[Ivette] markdown : refacto component

parent 2c23dbb6
No related branches found
No related tags found
No related merge requests found
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
/* ************************************************************************ */ /* ************************************************************************ */
import React from 'react'; import React from 'react';
import ReactMarkdown, { Components, Options } from 'react-markdown'; import ReactMarkdown, { Options } from 'react-markdown';
import { classes } from 'dome/misc/utils'; import { classes } from 'dome/misc/utils';
import { Icon } from 'dome/controls/icons'; import { Icon } from 'dome/controls/icons';
...@@ -38,82 +38,67 @@ export const iconTag: Pattern = { ...@@ -38,82 +38,67 @@ export const iconTag: Pattern = {
} }
}; };
class Counter {
private val: number = 0;
increment(): number { return this.val++; }
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- Replacement function // --- Replacement function
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Replace all tag in the text. * Replace all tag in children.
* This function doesn't replace any tags added by a previous replacement. * This function doesn't replace any tags added by a previous replacement.
*/ */
function replaceTagsByElement(
text: string,
counter: Counter,
patterns?: Pattern[],
): (string | JSX.Element | null)[] {
if(!patterns || patterns.length < 1) return [text];
type Content = string | JSX.Element | null;
let newContent: (Content|Content[])[] = [text];
let match;
let lastIndex: number;
patterns.forEach(({ pattern, replace }) => {
newContent = newContent.flat();
newContent.slice().forEach((content, i) => {
if(typeof content === "string") {
const contentTab: (string | JSX.Element | null)[] = [];
lastIndex = 0;
while ((match = pattern.exec(content)) !== null) {
if (match.index > lastIndex) {
contentTab.push(content.slice(lastIndex, match.index));
}
contentTab.push(replace(counter.increment(), match));
lastIndex = pattern.lastIndex;
}
if (lastIndex < content.length) {
contentTab.push(content.slice(lastIndex));
}
newContent.splice(i, 1, contentTab);
}
});
});
return newContent.flat();
}
function replaceTags( function replaceTags(
children: React.ReactNode, children: React.ReactNode,
patterns: Pattern[], patterns: Pattern[],
counter: Counter
): React.ReactNode { ): React.ReactNode {
if(patterns.length < 1) return children;
const buffer: React.ReactNode[] = [];
let counter = 0;
const childrenTab = React.Children.toArray(children); const childrenTab = React.Children.toArray(children);
const newContent = childrenTab.map((child) => { const makeReplace = (text: string, index: number): void => {
if(index >= patterns.length) {
buffer.push(text);
return;
}
const { pattern, replace } = patterns[index];
let match;
let lastIndex = 0;
while ((match = pattern.exec(text)) !== null) {
if (match.index > lastIndex) {
makeReplace(text.slice(lastIndex, match.index), index+1);
}
buffer.push(replace(counter++, match));
lastIndex = pattern.lastIndex;
}
if (lastIndex < text.length) {
makeReplace(text.slice(lastIndex), index+1);
}
};
/** makeReplace is applied if child is a string,
* otherwise it is pushed into the buffer
*/
childrenTab.forEach((child) => {
if (typeof child === 'string') { if (typeof child === 'string') {
return replaceTagsByElement(child, counter, patterns.slice()); return makeReplace(child, 0);
} }
return child; return buffer.push(child);
}); });
return newContent; return buffer;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// --- Markdown component // --- Markdown component
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
type tagHtmlList = [ k: keyof Components, v: keyof Components ][]
interface MarkdownProps { interface MarkdownProps {
/** classes for Markdown component */ /** classes for Markdown component */
className?: string; className?: string;
/** html tag of the markdown to be processed and possible replacement */ /** Tab of patterns */
htmlTag?: tagHtmlList; patterns?: Pattern[];
/** Tab of tag replacement */
pattern?: Pattern[];
/** Children */ /** Children */
children?: string | null; children?: string | null;
} }
...@@ -121,41 +106,15 @@ interface MarkdownProps { ...@@ -121,41 +106,15 @@ interface MarkdownProps {
export function Markdown( export function Markdown(
props: MarkdownProps props: MarkdownProps
): JSX.Element { ): JSX.Element {
const { className, pattern, htmlTag, children } = props; const { className, patterns, children } = props;
const markdownClasses = classes( const markdownClasses = classes(
"dome-xMarkdown", "dome-pages", "dome-xMarkdown", "dome-pages", className
className,
); );
const counter = new Counter(); const options: Options = { className: markdownClasses };
const transformChildren = (c: React.ReactNode): React.ReactNode => { if(patterns && patterns.length > 0) options.components = {
return !pattern ? c : replaceTags(c, pattern, counter); p: ({ children }) => <div>{replaceTags(children, patterns)}</div>,
}; li: ({ children }) => <li>{replaceTags(children, patterns)}</li>
const getComponentsOption = (): Components | null => {
if(!htmlTag) return null;
const getDynamicElement = (
tagName: keyof JSX.IntrinsicElements,
children: React.ReactNode
): JSX.Element => {
const Tag = tagName;
return <Tag>{children}</Tag>;
};
const component = [];
for (const [key, val] of htmlTag) {
component.push([key, ({ children }: {
children: React.ReactNode;
}) => getDynamicElement(val, transformChildren(children))]);
}
return Object.fromEntries(component);
};
const options: Options = {
className: markdownClasses,
components: getComponentsOption()
}; };
return <ReactMarkdown {...options}>{ children }</ReactMarkdown>; return <ReactMarkdown {...options}>{ children }</ReactMarkdown>;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment