diff --git a/package.json b/package.json index 32c5a3728..f3d56945a 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "react": "^19.2.3", "react-dom": "^19.2.3", "react-hook-form": "^7.68.0", + "react-markdown": "^10.1.0", "remark-gfm": "^4.0.1", "rimraf": "^6.0.1", "rollup-preserve-directives": "^1.1.3", @@ -109,6 +110,7 @@ "stylelint-order": "^6.0.4", "stylelint-plugin-logical-css": "^1.3.0", "stylelint-prettier": "^5.0.3", + "ts-dedent": "^2.2.0", "tsx": "^4.19.3", "turbo": "^2.9.14", "typescript": "^6.0.3", diff --git a/packages/components/package.json b/packages/components/package.json index 71a3caa64..2f0964452 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -16,6 +16,10 @@ "types": "./dist/index.d.ts", "default": "./dist/index.js" }, + "./markdown": { + "types": "./dist/markdown.d.ts", + "default": "./dist/markdown.js" + }, "./style.css": "./dist/style.css" }, "type": "module", @@ -30,19 +34,29 @@ }, "sideEffects": false, "dependencies": { + "@internationalized/date": "^3.12.0", "@koobiq/design-tokens": "^3.17.2", "@koobiq/logger": "workspace:*", "@koobiq/react-core": "workspace:*", "@koobiq/react-icons": "^12.0.0", "@koobiq/react-primitives": "workspace:*", "@types/react-transition-group": "^4.4.12", - "react-transition-group": "^4.4.5", - "@internationalized/date": "^3.12.0" + "react-transition-group": "^4.4.5" }, "peerDependencies": { "@koobiq/design-tokens": "^3.17.2", "@koobiq/react-icons": "^12.0.0", "react": "18.x || 19.x", - "react-dom": "18.x || 19.x" + "react-dom": "18.x || 19.x", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1" + }, + "peerDependenciesMeta": { + "react-markdown": { + "optional": true + }, + "remark-gfm": { + "optional": true + } } } diff --git a/packages/components/src/components/Markdown/Markdown.mdx b/packages/components/src/components/Markdown/Markdown.mdx new file mode 100644 index 000000000..f9cfded8f --- /dev/null +++ b/packages/components/src/components/Markdown/Markdown.mdx @@ -0,0 +1,96 @@ +import { + Meta, + Story, + Props, + Status, +} from '../../../../../.storybook/components'; + +import * as Stories from './Markdown.stories'; + + + +# Markdown + + + +`Markdown` renders a Markdown string as HTML. + +## Import + +```tsx +import { Markdown } from '@koobiq/react-components/markdown'; +``` + +## Usage + +Pass the Markdown text as `children`. + + + +## Typography + + + +## Headers + + + +### Headers combinations + + + +## Paragraph + + + +## Text emphasis + + + +## Blockquote + + + +## Lists + + + +## Inline code + + + +## Code block + + + +## Horizontal rule + + + +## Link + + + +## Image + + + +## Table + + + +## Line break + +To create a line break, add two trailing spaces at the end of the line. + + + +## Large article + +A larger combined example, useful as a visual sanity check for spacing and typography. + + + +## Props + + diff --git a/packages/components/src/components/Markdown/Markdown.module.css b/packages/components/src/components/Markdown/Markdown.module.css new file mode 100644 index 000000000..ae4f89720 --- /dev/null +++ b/packages/components/src/components/Markdown/Markdown.module.css @@ -0,0 +1,282 @@ +@import url('../../styles/mixins.css'); + +.base { + display: block; + color: var(--kbq-foreground-contrast); + background: var(--kbq-markdown-bg, transparent); +} + +.base > :first-child { + margin-block-start: 0; +} + +.base > :last-child { + margin-block-end: 0; +} + +.base h1, +.base h2, +.base h3, +.base h4, +.base h5, +.base h6 { + color: var(--kbq-foreground-contrast); +} + +.base :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) { + margin-block-start: 0; +} + +.base h1 { + margin-block: var(--kbq-markdown-h1-size-margin-top) + var(--kbq-markdown-h1-size-margin-bottom); + + @mixin markdown-typography h1; +} + +.base h2 { + margin-block: var(--kbq-markdown-h2-size-margin-top) + var(--kbq-markdown-h2-size-margin-bottom); + + @mixin markdown-typography h2; +} + +.base h3 { + margin-block: var(--kbq-markdown-h3-size-margin-top) + var(--kbq-markdown-h3-size-margin-bottom); + + @mixin markdown-typography h3; +} + +.base h4 { + margin-block: var(--kbq-markdown-h4-size-margin-top) + var(--kbq-markdown-h4-size-margin-bottom); + + @mixin markdown-typography h4; +} + +.base h5 { + margin-block: var(--kbq-markdown-h5-size-margin-top) + var(--kbq-markdown-h5-size-margin-bottom); + + @mixin markdown-typography h5; +} + +.base h6 { + margin-block: var(--kbq-markdown-h6-size-margin-top) + var(--kbq-markdown-h6-size-margin-bottom); + + @mixin markdown-typography h6; +} + +.base p { + margin-block: var(--kbq-markdown-p-size-margin-top) + var(--kbq-markdown-p-size-margin-bottom); + color: var(--kbq-foreground-contrast); + + @mixin markdown-typography body; +} + +.base ul, +.base ol { + margin-block: var(--kbq-markdown-list-size-margin-top) + var(--kbq-markdown-list-size-margin-bottom); + color: var(--kbq-foreground-contrast); + + @mixin markdown-typography body; +} + +.base p + ul, +.base p + ol { + margin-block-start: var(--kbq-markdown-list-size-margin-top-after-paragraph); +} + +.base ul { + position: relative; + list-style: none; + padding-inline: var(--kbq-size-xxl) 0; + padding-block: 0; +} + +.base ul > li::before { + content: '—'; + display: block; + position: absolute; + inset-inline-start: 0; + inline-size: 24px; + text-align: start; +} + +.base ol { + list-style: none; + padding: 0; + counter-reset: li; +} + +.base ol > li { + counter-increment: li; +} + +.base ol > li::before { + content: counter(li) '.'; + padding-inline-end: var(--kbq-markdown-list-size-ol-number-padding-right); +} + +.base ol > li > * { + display: inline-block; +} + +.base li { + margin-block-end: var(--kbq-markdown-list-size-item-margin-bottom); +} + +.base blockquote { + margin-block: var(--kbq-markdown-blockquote-size-margin-top) + var(--kbq-markdown-blockquote-size-margin-bottom); + margin-inline: 0; + padding: var(--kbq-markdown-blockquote-size-padding); + border-inline-start: var(--kbq-markdown-blockquote-size-line-width) solid + var(--kbq-markdown-blockquote-line); + color: var(--kbq-markdown-blockquote-text); + background: var(--kbq-markdown-blockquote-background); +} + +.base blockquote > p { + margin-block: 0; +} + +.base pre { + position: relative; + overflow-x: auto; + margin-block: var(--kbq-markdown-code-size-multiline-margin-top) + var(--kbq-markdown-code-size-multiline-margin-bottom); + padding: var(--kbq-markdown-code-size-multiline-padding); + border-radius: var(--kbq-markdown-code-size-border-radius); + color: var(--kbq-markdown-code-text); + background-color: var(--kbq-markdown-code-background); +} + +.base code { + border-radius: var(--kbq-markdown-code-size-border-radius); + + @mixin markdown-typography inline-code; +} + +.base code:not(pre > code) { + white-space: nowrap; + padding: var(--kbq-markdown-code-size-inline-padding); +} + +.base code:not(pre > code, a code) { + color: var(--kbq-markdown-code-text); + background-color: var(--kbq-markdown-code-background); +} + +.base a code { + background-color: var(--kbq-markdown-code-background); + + @mixin markdown-typography inline-code-as-link; +} + +.base img { + max-inline-size: 100%; + margin-block: var(--kbq-markdown-image-size-margin-top) + var(--kbq-markdown-image-size-margin-bottom); +} + +.base img + em { + display: block; + margin-block: var(--kbq-markdown-image-size-caption-margin-top) + var(--kbq-markdown-image-size-caption-margin-bottom); + color: var(--kbq-markdown-image-caption-text); + + @mixin markdown-typography caption; +} + +.base hr { + block-size: 0; + margin-block: var(--kbq-markdown-hr-size-margin-vertical); + border: none; + border-block-end: var(--kbq-markdown-hr-size-width) solid + var(--kbq-markdown-hr-color); +} + +.base table { + max-inline-size: 100%; + overflow-x: auto; + display: table; + border-collapse: collapse; + margin-block-end: var(--kbq-markdown-table-size-margin-bottom); + color: var(--kbq-markdown-table-body); +} + +.base table td, +.base table th { + padding: var(--kbq-markdown-table-size-padding); + vertical-align: top; +} + +.base thead { + border-block-end: var(--kbq-markdown-table-size-border-width) solid + var(--kbq-markdown-table-border); + text-align: start; + color: var(--kbq-markdown-table-header); + + @mixin markdown-typography table-header; +} + +.base thead th:first-child { + padding-inline-start: 0; +} + +.base thead th:last-child { + padding-inline-end: 0; +} + +.base tbody { + @mixin markdown-typography table-cell; +} + +.base tbody td:first-child { + padding-inline-start: 0; +} + +.base tbody td:last-child { + padding-inline-end: 0; +} + +.base a { + color: var(--kbq-foreground-theme); + text-decoration-line: underline; + text-decoration-color: var(--kbq-line-theme-less); + outline: var(--kbq-markdown-link-size-state-focused-outline-width) solid + transparent; + outline-offset: var(--kbq-markdown-link-size-state-focused-outline-offset); + transition: + color var(--kbq-transition-default), + outline-color var(--kbq-transition-default), + text-decoration-color var(--kbq-transition-default); + + @mixin markdown-typography body; +} + +.base a:hover { + color: var(--kbq-states-foreground-theme-hover); +} + +.base a:active { + color: var(--kbq-states-foreground-theme-active); +} + +.base a:focus-visible { + outline-color: var(--kbq-states-line-focus-theme); +} + +.base a:visited { + color: var(--kbq-foreground-visited); + text-decoration-color: var(--kbq-line-visited); +} + +.base a:has(code) { + text-decoration-line: none; +} diff --git a/packages/components/src/components/Markdown/Markdown.stories.tsx b/packages/components/src/components/Markdown/Markdown.stories.tsx new file mode 100644 index 000000000..3f0e23bd5 --- /dev/null +++ b/packages/components/src/components/Markdown/Markdown.stories.tsx @@ -0,0 +1,301 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import dedent from 'ts-dedent'; + +import { Markdown } from './index.js'; + +const meta = { + title: 'Components/Markdown', + component: Markdown, + parameters: { + layout: 'padded', + }, + tags: ['status:new', 'date:2026-08-05'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Overview: Story = { + render: () => ( + + {dedent` + # Heading 1 + ## Heading 2 + ### Heading 3 + #### Heading 4 + ##### Heading 5 + ###### Heading 6 + `} + + ), +}; + +export const Typography: Story = { + render: () => ( + + {dedent` + # Heading 1 + ## Heading 2 + ### Heading 3 + #### Heading 4 + ##### Heading 5 + ###### Heading 6 + + Paragraph with **bold**, *italic*, [link](#), and [\`inline code as link\`](#). + + - Unordered list item + - Another list item + + 1. Ordered list item + 2. Another list item + + > Blockquote text + + Inline \`code\`. + + ![With caption text](https://koobiq.io/assets/images/markdown/markdown-image.png) + *Image caption* + + | Header | Value | + | ------ | ----- | + | Cell | 123 | + `} + + ), +}; + +export const Headers: Story = { + render: () => ( + + {dedent` + # Heading 1 + ## Heading 2 + ### Heading 3 + #### Heading 4 + ##### Heading 5 + ###### Heading 6 + `} + + ), +}; + +export const HeadersCombinations: Story = { + render: () => ( + + {dedent` + ## Data Protection System + ### Security Levels + #### Threat Types + + Recommended password length is 12 characters, encryption key length is 256 bits. Weak passwords are not rejected, the system raises security requirements. + + ### Attack Detection + + Monitoring happens in real time. Multiple incidents form a unified threat picture. New events are displayed in the security log. If there are many threats, critical ones are highlighted with priority. Most often attacks are detected automatically, but an administrator can initiate a manual check. + `} + + ), +}; + +export const Paragraph: Story = { + render: () => ( + + {dedent` + A brute-force attack is a cryptanalytic attack that can, in theory, be used to attempt to decrypt any encrypted data (except for data encrypted in an information-theoretically secure manner). + + Such an attack might be used when it is not possible to take advantage of other weaknesses in an encryption system (if any exist) that would make the task easier. + `} + + ), +}; + +export const TextEmphasis: Story = { + render: () => ( + + {dedent` + **bold** + __bold__ + + _italic_ + *italic* + + ***bold and italic*** + ___bold and italic___ + `} + + ), +}; + +export const Blockquote: Story = { + render: () => ( + + {dedent` + > A [brute-force attack](#) is a cryptanalytic attack that can, in theory, be used to attempt to decrypt any encrypted data (except for data encrypted in an information-theoretically secure manner). Such an attack might be used when it is not possible to take advantage of other weaknesses in an encryption system (if any exist) that would make the task easier. + `} + + ), +}; + +export const Lists: Story = { + render: () => ( + + {dedent` + ### Ordered List: + + 1. First item + 2. Second item + 3. Third item + 4. Fourth item + + ### Unordered List: + + - First item + - Second item + - Third item + - Fourth item + `} + + ), +}; + +export const InlineCode: Story = { + render: () => ( + {'Use the `bypassSecurityTrustHtml()` function'} + ), +}; + +export const CodeBlock: Story = { + render: () => ( + + {dedent` + \`\`\`html + + + + + + Koobiq + + + + + + \`\`\` + `} + + ), +}; + +export const Divider: Story = { + render: () => {'---'}, +}; + +export const Link: Story = { + render: () => ( + + {dedent` + [Link](#) + + A [\`brute-force\` attack](#) is a cryptanalytic attack that can, in theory, be used to attempt to decrypt any encrypted data (except for data encrypted in an information-theoretically secure manner). + `} + + ), +}; + +export const Image: Story = { + render: () => ( + + {dedent` + ![With caption text](https://koobiq.io/assets/images/markdown/markdown-image.png) + *Caption* + `} + + ), +}; + +export const Table: Story = { + render: () => ( + + {dedent` + | Default | Left align | Center align | Right align | + | ---------- | :--------- | :----------: | ----------: | + | Babable | Zillya | ClamAV | Acronis | + | Cybereason | McAfee | Cyren | Zoner | + | ESET NOD32 | Alibaba | eScan | Dr.Web | + `} + + ), +}; + +export const LineBreak: Story = { + render: () => {'First line \nSecond line'}, +}; + +export const Article: Story = { + render: () => ( + + {dedent` + # Cybersecurity Fundamentals + + ![With caption text](https://koobiq.io/assets/images/markdown/markdown-image.png) + *Caption* + + ## Network Security + + Cybersecurity is the practice of protecting systems, networks, and programs from digital attacks. These cyberattacks are usually aimed at accessing, changing, or destroying sensitive information; extorting money from users; or interrupting normal business processes. + + Implementing effective cybersecurity measures is particularly challenging today because there are more devices than people, and attackers are becoming more innovative. A successful cybersecurity approach has multiple layers of protection spread across the computers, networks, programs, or data that one intends to keep safe. + + ## Data Protection + + ### Encryption Standards + + Network security involves protecting the usability and integrity of network and data. It includes both hardware and software technologies. Effective network security manages access to the network and targets a variety of threats and stops them from entering or spreading on your network. + + ### Authentication Methods + + Multi-factor authentication adds an extra layer of security by requiring users to provide two or more verification factors to gain access to a resource. This significantly reduces the risk of unauthorized access even if passwords are compromised. + + ## Threat Detection + + ![With caption text](https://koobiq.io/assets/images/markdown/markdown-image.png) + *Image with a caption* + + Advanced persistent threats represent sophisticated, long-term cyber attacks where intruders gain access to a network and remain undetected for extended periods. These attacks are typically aimed at stealing data rather than causing damage to the network or organization. Threat detection systems use machine learning and behavioral analysis to identify suspicious activities and potential security breaches before they can cause significant damage. + + > Security is not a product, but a process that requires continuous monitoring and improvement. + + Incident response planning is crucial for organizations to effectively handle security breaches when they occur. A well-structured incident response plan helps minimize damage and recovery time. + + 1. Identify and assess the security incident + 2. Contain the threat to prevent further damage + 3. Eradicate the threat from all affected systems + 4. Recover normal operations and monitor for signs of weakness + + Risk assessment and vulnerability management are ongoing processes that help organizations identify potential security gaps. Regular security audits and penetration testing help ensure that security measures remain effective against evolving threats. + + Cybersecurity awareness training is essential for all employees as human error remains one of the leading causes of security breaches. Regular training helps staff recognize phishing attempts, social engineering tactics, and other common attack vectors. + + ### Security Monitoring + + Security information and event management systems collect and analyze security-related data from various sources across an organization's infrastructure. + + \`\`\`bash + $ nmap -sS -O 192.168.1.1 + \`\`\` + + ### Compliance Standards + + #### Regulatory Requirements + + Organizations must comply with various cybersecurity regulations and standards depending on their industry and location. These may include GDPR, HIPAA, SOX, and industry-specific requirements that mandate specific security controls and practices. + + - Regular security assessments and audits + - Implementation of appropriate technical and organizational measures + - Incident reporting and breach notification procedures + + Continuous improvement in cybersecurity requires staying updated with the latest threats, technologies, and best practices in the field. + `} + + ), +}; diff --git a/packages/components/src/components/Markdown/Markdown.test.tsx b/packages/components/src/components/Markdown/Markdown.test.tsx new file mode 100644 index 000000000..f84b33653 --- /dev/null +++ b/packages/components/src/components/Markdown/Markdown.test.tsx @@ -0,0 +1,106 @@ +import { createRef } from 'react'; + +import { render, screen } from '@testing-library/react'; +import { renderToStaticMarkup } from 'react-dom/server'; +import { describe, it, expect } from 'vitest'; + +import { Markdown } from './index.js'; + +describe('Markdown', () => { + it('should render on the server', () => { + const html = renderToStaticMarkup(# Heading); + + expect(html).toContain('

Heading

'); + }); + + it('should accept the ref', () => { + const ref = createRef(); + const { container } = render(# Heading); + + expect(ref.current).toBe(container.firstElementChild); + + expect(ref.current?.firstElementChild).toBe( + screen.getByRole('heading', { name: 'Heading' }) + ); + }); + + it('should accept a custom class', () => { + const { container } = render( + # Heading + ); + + expect(container.firstElementChild).toHaveClass('foo'); + }); + + it('should render headers', () => { + render({'# Heading 1\n\n## Heading 2'}); + + expect( + screen.getByRole('heading', { level: 1, name: 'Heading 1' }) + ).toBeInTheDocument(); + + expect( + screen.getByRole('heading', { level: 2, name: 'Heading 2' }) + ).toBeInTheDocument(); + }); + + it('should render a paragraph', () => { + render(Some paragraph text.); + expect(screen.getByText('Some paragraph text.')).toBeInTheDocument(); + }); + + it('should render a list', () => { + render({'- First item\n- Second item'}); + + expect(screen.getByText('First item')).toBeInTheDocument(); + expect(screen.getByText('Second item')).toBeInTheDocument(); + }); + + it('should render a table', () => { + render({'| A | B |\n| - | - |\n| 1 | 2 |'}); + + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getByText('A')).toBeInTheDocument(); + expect(screen.getByText('1')).toBeInTheDocument(); + }); + + it('should render a link with href', () => { + render({'[koobiq](https://www.koobiq.io)'}); + + const link = screen.getByRole('link', { name: 'koobiq' }); + expect(link).toHaveAttribute('href', 'https://www.koobiq.io'); + }); + + it('should re-render when children change', () => { + const { rerender } = render(# First); + expect(screen.getByRole('heading', { name: 'First' })).toBeInTheDocument(); + + rerender(# Second); + expect(screen.getByRole('heading', { name: 'Second' })).toBeInTheDocument(); + + expect( + screen.queryByRole('heading', { name: 'First' }) + ).not.toBeInTheDocument(); + }); + + it('should not render raw HTML', () => { + const { container } = render( + {''} + ); + + expect(container.querySelector('script')).not.toBeInTheDocument(); + + expect(container).toHaveTextContent( + '' + ); + }); + + it('should keep the language class on a fenced code block', () => { + const { container } = render( + {'```js\nconst a = 1;\n```'} + ); + + const code = container.querySelector('pre > code'); + expect(code).toHaveClass('language-js'); + }); +}); diff --git a/packages/components/src/components/Markdown/Markdown.tsx b/packages/components/src/components/Markdown/Markdown.tsx new file mode 100644 index 000000000..4c4a6514d --- /dev/null +++ b/packages/components/src/components/Markdown/Markdown.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { forwardRef } from 'react'; + +import { clsx } from '@koobiq/react-core'; +import ReactMarkdown from 'react-markdown'; +import remarkGfm from 'remark-gfm'; + +import s from './Markdown.module.css'; +import type { MarkdownProps } from './types'; + +const remarkPlugins = [remarkGfm]; + +/** Markdown renders a Markdown string as React elements. */ +export const Markdown = forwardRef( + (props, ref) => { + const { children, className, ...other } = props; + + return ( +
+ {children} +
+ ); + } +); + +Markdown.displayName = 'Markdown'; diff --git a/packages/components/src/components/Markdown/index.ts b/packages/components/src/components/Markdown/index.ts new file mode 100644 index 000000000..c5c27091c --- /dev/null +++ b/packages/components/src/components/Markdown/index.ts @@ -0,0 +1,2 @@ +export * from './Markdown.js'; +export * from './types.js'; diff --git a/packages/components/src/components/Markdown/types.ts b/packages/components/src/components/Markdown/types.ts new file mode 100644 index 000000000..e001131ba --- /dev/null +++ b/packages/components/src/components/Markdown/types.ts @@ -0,0 +1,9 @@ +import type { ComponentPropsWithoutRef } from 'react'; + +export interface MarkdownProps extends Omit< + ComponentPropsWithoutRef<'div'>, + 'children' | 'dangerouslySetInnerHTML' +> { + /** Markdown text to convert into HTML. */ + children: string; +} diff --git a/packages/components/src/markdown.ts b/packages/components/src/markdown.ts new file mode 100644 index 000000000..2bdc5e1d3 --- /dev/null +++ b/packages/components/src/markdown.ts @@ -0,0 +1 @@ +export * from './components/Markdown'; diff --git a/packages/components/src/styles/mixins.css b/packages/components/src/styles/mixins.css index d27247090..9b9729347 100644 --- a/packages/components/src/styles/mixins.css +++ b/packages/components/src/styles/mixins.css @@ -17,6 +17,18 @@ ); } +@define-mixin markdown-typography $name { + font-size: var(--kbq-md-typography-md-$(name)-font-size); + font-weight: var(--kbq-md-typography-md-$(name)-font-weight); + line-height: var(--kbq-md-typography-md-$(name)-line-height); + font-family: var(--kbq-md-typography-md-$(name)-font-family); + text-transform: var(--kbq-md-typography-md-$(name)-text-transform); + font-feature-settings: var( + --kbq-md-typography-md-$(name)-font-feature-settings + ); + letter-spacing: var(--kbq-md-typography-md-$(name)-letter-spacing); +} + @define-mixin ellipsis { overflow: hidden; white-space: nowrap; diff --git a/packages/components/vite.config.ts b/packages/components/vite.config.ts index 05d4787b5..f7a70e27c 100644 --- a/packages/components/vite.config.ts +++ b/packages/components/vite.config.ts @@ -22,7 +22,10 @@ export default defineConfig({ plugins: [tsconfigPaths(), react(), preserveDirectives()], build: { lib: { - entry: path.resolve(__dirname, 'src/index.ts'), + entry: { + index: path.resolve(__dirname, 'src/index.ts'), + markdown: path.resolve(__dirname, 'src/markdown.ts'), + }, fileName: (_, entryName: string) => `${entryName}.js`, formats: ['es'], cssFileName: 'style', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2cae3875a..4cc8b09fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -187,6 +187,9 @@ importers: react-hook-form: specifier: ^7.68.0 version: 7.68.0(react@19.2.3) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.7)(react@19.2.3) remark-gfm: specifier: ^4.0.1 version: 4.0.1 @@ -217,6 +220,9 @@ importers: stylelint-prettier: specifier: ^5.0.3 version: 5.0.3(prettier@3.8.3)(stylelint@16.26.1(typescript@6.0.3)) + ts-dedent: + specifier: ^2.2.0 + version: 2.2.0 tsx: specifier: ^4.19.3 version: 4.19.3 @@ -268,9 +274,15 @@ importers: react-dom: specifier: ^19.0.0 version: 19.2.3(react@19.2.3) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.7)(react@19.2.3) react-transition-group: specifier: ^4.4.5 version: 4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 packages/core: dependencies: @@ -3153,6 +3165,9 @@ packages: '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -3162,6 +3177,9 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3211,6 +3229,9 @@ packages: '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -3281,6 +3302,9 @@ packages: resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + '@unrs/resolver-binding-android-arm-eabi@1.12.2': resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} cpu: [arm] @@ -3801,7 +3825,7 @@ packages: basic-ftp@5.1.0: resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} engines: {node: '>=10.0.0'} - deprecated: Security vulnerability fixed in 5.2.1, please upgrade + deprecated: Security vulnerability fixed in 5.2.0, please upgrade bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -3982,9 +4006,18 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} @@ -4112,6 +4145,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -4967,6 +5003,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -5490,6 +5529,12 @@ packages: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + heap-js@2.7.1: resolution: {integrity: sha512-EQfezRg0NCZGNlhlDR3Evrw1FVL2G3LhU7EgPoxufQKruNBSYA8MiRPHeWbU+36o+Fhel0wMwM+sLEiBAlNLJA==} engines: {node: '>=10.0.0'} @@ -5532,6 +5577,9 @@ packages: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -5624,6 +5672,9 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + install-artifact-from-github@1.4.0: resolution: {integrity: sha512-+y6WywKZREw5rq7U2jvr2nmZpT7cbWbQQ0N/qfcseYnzHFz2cZz1Et52oY+XttYuYeTkI8Y+R2JNWj68MpQFSg==} hasBin: true @@ -5651,6 +5702,12 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -5724,6 +5781,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5757,6 +5817,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -6498,9 +6561,21 @@ packages: mdast-util-gfm@3.0.0: resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==} + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} @@ -7072,6 +7147,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-imports-exports@0.2.4: resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} @@ -7355,6 +7433,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -7471,6 +7552,12 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': ^19.0.0 + react: ^19.0.0 + react-refresh@0.18.0: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} @@ -7562,6 +7649,9 @@ packages: remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} @@ -7850,6 +7940,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -7988,6 +8081,9 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -8019,6 +8115,12 @@ packages: stubs@3.0.0: resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -8261,6 +8363,9 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} @@ -8443,6 +8548,9 @@ packages: unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -11932,6 +12040,10 @@ snapshots: '@types/esrecurse@4.3.1': {} + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + '@types/estree@1.0.8': {} '@types/estree@1.0.9': {} @@ -11941,6 +12053,10 @@ snapshots: '@types/jsonfile': 6.1.4 '@types/node': 25.8.0 + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -11985,6 +12101,8 @@ snapshots: '@types/triple-beam@1.3.5': {} + '@types/unist@2.0.11': {} + '@types/unist@3.0.3': {} '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': @@ -12133,6 +12251,8 @@ snapshots: '@typescript-eslint/types': 8.61.0 eslint-visitor-keys: 5.0.1 + '@ungap/structured-clone@1.3.3': {} + '@unrs/resolver-binding-android-arm-eabi@1.12.2': optional: true @@ -12900,8 +13020,14 @@ snapshots: char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + character-entities@2.0.2: {} + character-reference-invalid@2.0.1: {} + chardet@2.1.1: {} check-error@2.1.1: {} @@ -13016,6 +13142,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} commander@2.20.3: {} @@ -14183,6 +14311,8 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -14970,6 +15100,30 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + heap-js@2.7.1: {} hermes-estree@0.25.1: {} @@ -15004,6 +15158,8 @@ snapshots: html-tags@3.3.1: {} + html-url-attributes@3.0.1: {} + http-cache-semantics@4.2.0: optional: true @@ -15094,6 +15250,8 @@ snapshots: ini@4.1.1: {} + inline-style-parser@0.2.7: {} + install-artifact-from-github@1.4.0: optional: true @@ -15118,6 +15276,13 @@ snapshots: ipaddr.js@1.9.1: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -15202,6 +15367,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-docker@3.0.0: {} is-extglob@2.1.1: {} @@ -15232,6 +15399,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -15996,11 +16165,62 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 unist-util-is: 6.0.0 + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + mdast-util-to-markdown@2.1.2: dependencies: '@types/mdast': 4.0.4 @@ -16701,6 +16921,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-imports-exports@0.2.4: dependencies: parse-statements: 1.0.11 @@ -16954,6 +17184,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@7.2.0: {} + proto-list@1.2.4: {} proto3-json-serializer@3.0.4: @@ -17174,6 +17406,24 @@ snapshots: react-is@17.0.2: {} + react-markdown@10.1.0(@types/react@19.2.7)(react@19.2.3): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/react': 19.2.7 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.3 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-refresh@0.18.0: {} react-stately@3.45.0(react@19.2.3): @@ -17346,6 +17596,14 @@ snapshots: transitivePeerDependencies: - supports-color + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + remark-stringify@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -17737,6 +17995,8 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 @@ -17927,6 +18187,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -17949,6 +18214,14 @@ snapshots: stubs@3.0.0: {} + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.3): dependencies: client-only: 0.0.1 @@ -18256,6 +18529,8 @@ snapshots: dependencies: punycode: 2.3.1 + trim-lines@3.0.1: {} + trim-newlines@3.0.1: {} triple-beam@1.4.1: {} @@ -18472,6 +18747,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 diff --git a/tools/api-extractor/config.json b/tools/api-extractor/config.json index ed92420e0..9d220102f 100644 --- a/tools/api-extractor/config.json +++ b/tools/api-extractor/config.json @@ -32,6 +32,7 @@ "layout", "Link", "List", + "Markdown", "Menu", "Modal", "Navbar", diff --git a/tools/public_api_guard/components/Markdown.api.md b/tools/public_api_guard/components/Markdown.api.md new file mode 100644 index 000000000..5b92c071b --- /dev/null +++ b/tools/public_api_guard/components/Markdown.api.md @@ -0,0 +1,21 @@ +## API Report File for "koobiq-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { ComponentPropsWithoutRef } from 'react'; +import { ForwardRefExoticComponent } from 'react'; +import { RefAttributes } from 'react'; + +// @public +export const Markdown: ForwardRefExoticComponent>; + +// @public (undocumented) +export interface MarkdownProps extends Omit, 'children' | 'dangerouslySetInnerHTML'> { + children: string; +} + +// (No @packageDocumentation comment for this package) + +```