diff --git a/package-lock.json b/package-lock.json index 9018a55410..652200f5a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27089,6 +27089,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/snarkdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/snarkdown/-/snarkdown-2.0.0.tgz", + "integrity": "sha512-MgL/7k/AZdXCTJiNgrO7chgDqaB9FGM/1Tvlcenenb7div6obaDATzs16JhFyHHBGodHT3B7RzRc5qk8pFhg3A==" + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", @@ -30868,6 +30873,7 @@ "d3": "7.9.0", "modern-css-reset": "1.4.0", "react-use": "17.5.1", + "snarkdown": "2.0.0", "use-query-params": "2.2.1" }, "devDependencies": { diff --git a/packages/ui/package.json b/packages/ui/package.json index fd35f103a0..34486a48c9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -79,6 +79,7 @@ "d3": "7.9.0", "modern-css-reset": "1.4.0", "react-use": "17.5.1", + "snarkdown": "2.0.0", "use-query-params": "2.2.1" } } diff --git a/packages/ui/src/ui/index.js b/packages/ui/src/ui/index.js index 60141b3d80..50bbd80451 100644 --- a/packages/ui/src/ui/index.js +++ b/packages/ui/src/ui/index.js @@ -13,6 +13,7 @@ export { Icon } from './icon'; export { Input } from './input'; export { InputSearch } from './input-search'; export { Loader } from './loader'; +export { Markdown } from './markdown'; export { Skeleton } from './skeleton'; export { Table } from './table'; export { Tabs } from './tabs'; diff --git a/packages/ui/src/ui/markdown/index.ts b/packages/ui/src/ui/markdown/index.ts new file mode 100644 index 0000000000..99334b53de --- /dev/null +++ b/packages/ui/src/ui/markdown/index.ts @@ -0,0 +1 @@ +export * from './markdown'; diff --git a/packages/ui/src/ui/markdown/markdown.module.css b/packages/ui/src/ui/markdown/markdown.module.css new file mode 100644 index 0000000000..d5f73f6aed --- /dev/null +++ b/packages/ui/src/ui/markdown/markdown.module.css @@ -0,0 +1,7 @@ +.root code { + padding: 2px var(--space-xxxsmall); + background: var(--color-highlight); + outline: 1px solid var(--color-outline); + border-radius: var(--radius-small); + color: var(--color-text); +} diff --git a/packages/ui/src/ui/markdown/markdown.stories.tsx b/packages/ui/src/ui/markdown/markdown.stories.tsx new file mode 100644 index 0000000000..b87e3a67e1 --- /dev/null +++ b/packages/ui/src/ui/markdown/markdown.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { Markdown } from '.'; + +const meta: Meta = { + title: 'UI/Markdown', + component: Markdown, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + content: '**One line** _markdown_ content', + }, +}; + +const MULTI_LINE_MARKDOWN = ` +**Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Habitant morbi tristique senectus et netus et malesuada. + +Eget nunc scelerisque viverra mauris in. Ipsum dolor sit amet consectetur adipiscing. +`; + +export const MultiLine: Story = { + args: { + content: MULTI_LINE_MARKDOWN, + }, +}; diff --git a/packages/ui/src/ui/markdown/markdown.tsx b/packages/ui/src/ui/markdown/markdown.tsx new file mode 100644 index 0000000000..e4ddc3b958 --- /dev/null +++ b/packages/ui/src/ui/markdown/markdown.tsx @@ -0,0 +1,24 @@ +import React, { ComponentProps, ElementType, useMemo } from 'react'; +import cx from 'classnames'; +import snarkdown from 'snarkdown'; + +import css from './markdown.module.css'; + +type MarkdownProps = { + content?: string; + as?: ElementType; +} & ComponentProps<'div'>; + +export const Markdown = (props: MarkdownProps) => { + const { className = '', content = '', as: Component = 'div', ...restProps } = props; + + const html = useMemo(() => snarkdown(content), [content]); + + return ( + + ); +};