### Initialize Markdown Editor with Plugins Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-latex-extension.md Integrate the configured plugins into your markdown editor's initialization. This example shows a simplified setup. ```typescript const editor = new MarkdownEditor({ // Editor configuration plugins, // Other configurations }); ``` -------------------------------- ### Start Development Server Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md After applying the necessary configurations, start the development server to see the changes. ```bash npm start ``` -------------------------------- ### Install Markdown Editor Page Constructor Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/page-constructor-extension/README.md Install the extension using npm. Ensure you have the necessary peer dependencies installed. ```bash npm install @gravity-ui/markdown-editor-page-constructor-extension ``` ```bash npm install @gravity-ui/markdown-editor @gravity-ui/uikit @gravity-ui/page-constructor @diplodoc/page-constructor-extension react react-dom ``` -------------------------------- ### Install Podman and Configure Resources Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Install Podman and configure its resources for visual testing. Ensure sufficient CPU and memory are allocated. ```shell brew install podman podman machine init podman machine set --cpus 4 --memory 12288 podman machine start ``` -------------------------------- ### Install HTML Extension Packages Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-html-extension.md Install the required versions of the markdown-editor and html-extension packages using npm or yarn. ```bash npm install @gravity-ui/markdown-editor@^13.4.0 npm install @diplodoc/html-extension@^1.2.7 ``` -------------------------------- ### GalleryProvider Setup Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md Wrap your content with GalleryProvider to enable the useFilesGallery hook. Configure theme and empty message. ```tsx import {GalleryProvider} from '@gravity-ui/components'; children ; ``` -------------------------------- ### Install LaTeX Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/latex-extension/README.md Install the necessary packages for the LaTeX extension, including the markdown editor, the LaTeX extension itself, and the @diplodoc/latex-extension. ```bash npm install @gravity-ui/markdown-editor @gravity-ui/markdown-editor-latex-extension @diplodoc/latex-extension ``` -------------------------------- ### Install Markdown Editor Package Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md Install the core markdown editor package using npm. ```bash npm install @gravity-ui/markdown-editor ``` -------------------------------- ### Install Playwright Dependencies Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Install necessary Playwright dependencies for visual testing. ```shell pnpm run playwright:install ``` -------------------------------- ### Start Podman Machine Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Ensure the Podman machine is running before executing tests. This is a prerequisite for all test runs. ```bash podman machine start ``` -------------------------------- ### Install Latex Extension Packages Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-latex-extension.md Install the necessary packages for the markdown editor and the LaTeX extension using npm or yarn. Ensure you use the specified versions or higher. ```bash npm install @gravity-ui/markdown-editor@^13.4.0 npm install @diplodoc/latex-extension@^1.1.0 ``` -------------------------------- ### Basic LaTeX Extension Setup Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/latex-extension/README.md Integrate the LatexExtension into the markdown editor's configuration. Ensure the runtime scripts for LaTeX processing are loaded. ```typescript import {useMarkdownEditor} from '@gravity-ui/markdown-editor'; import {LatexExtension} from '@gravity-ui/markdown-editor-latex-extension'; const editor = new useMarkdownEditor({ wysiwygConfig: { extensions: (builder) => { builder .use(LatexExtension, { loadRuntimeScript: () => { import('@diplodoc/latex-extension/runtime'); import('@diplodoc/latex-extension/runtime/styles'); }, }); }, }, }); ``` -------------------------------- ### Initialize and Use Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/README.md This React hook and component setup demonstrates how to initialize the markdown editor, handle submission, and render the editor view. Ensure you have the necessary UIKit styles configured. ```tsx import React from 'react'; import {useMarkdownEditor, MarkdownEditorView} from '@gravity-ui/markdown-editor'; function Editor({onSubmit}) { const editor = useMarkdownEditor({allowHTML: false}); React.useEffect(() => { function submitHandler() { // Serialize current content to markdown markup const value = editor.getValue(); onSubmit(value); } editor.on('submit', submitHandler); return () => { editor.off('submit', submitHandler); }; }, [onSubmit]); return ; } ``` -------------------------------- ### Install Mermaid Extension Packages Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-mermaid-extension.md Install the necessary packages for the markdown editor and the Mermaid extension using npm or yarn. Ensure you use versions 13.4.0 or higher for the editor and 1.2.3 or higher for the extension. ```bash npm install @gravity-ui/markdown-editor@^13.4.0 npm install @diplodoc/mermaid-extension@^1.2.3 ``` -------------------------------- ### Initialize and Use Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/markup/codemirror/html-to-markdown/__tests__/fixtures/code/input.html Initialize the Markdown Editor with specific configurations like `allowHTML: false`. This snippet demonstrates setting up the editor, handling the 'submit' event to get the markdown value, and rendering the editor view. ```javascript import React from 'react'; import { useMarkdownEditor, MarkdownEditorView } from '@gravity-ui/markdown-editor'; import { toaster } from '@gravity-ui/uikit/toaster-singleton-react-18'; function Editor({ onSubmit }) { const editor = useMarkdownEditor({ allowHTML: false }); React.useEffect(() => { function submitHandler() { // Serialize current content to markdown markup const value = editor.getValue(); onSubmit(value); } editor.on('submit', submitHandler); return () => { editor.off('submit', submitHandler); }; }, [onSubmit]); return ; } ``` -------------------------------- ### Install CRACO for Webpack Configuration Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md Install CRACO, a custom Create React App configuration tool, to modify Webpack settings. ```bash npm install @craco/craco ``` -------------------------------- ### Create Visual Test with Playwright Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Example of a visual test file using Playwright. It mounts a component and takes a screenshot for comparison. ```tsx import {test} from 'playwright/core'; import {MarkdownStories} from './MarkdownExtensions.helpers'; test.describe('Extensions, Markdown', () => { test('Heading', async ({mount, expectScreenshot}) => { await mount(); await expectScreenshot(); }); }); ``` -------------------------------- ### Configure Static Rendering with Mermaid HOC Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-mermaid-extension.md Set up a Higher-Order Component (HOC) for static rendering to load the Mermaid runtime and apply styling hooks. This example uses React hooks and memoization for theme and configuration. ```typescript import {useEffect} from 'react'; import {YfmHtml} from '@gravity-ui/markdown-editor/view/components/YfmHtml'; import {useEffect, useState} from 'react'; import {useThemeValue} from '@gravity-ui/uikit'; // HOC export const MERMAID_RUNTIME = 'mermaid'; const YfmStaticView = withMermaid({runtime: MERMAID_RUNTIME})(YfmHtml); // hooks export const useMermaidTheme = () => { const theme = useThemeType(); useEffect(() => { window.mermaidJsonp = window.mermaidJsonp || []; window.mermaidJsonp.push((m: {initialize: (opts: {theme: string}) => void}) => { m.initialize({theme: theme === 'dark' ? 'dark' : 'default'}); }); }, [theme]); return theme; }; // render const HtmlRenderer = React.forwardRef((props, ref) => { // ... const theme = useThemeType(); // your hook for get theme const mermaidConfig = useMemo( () => ({ theme, zoom: {showMenu: true, bindKeys: true, resetOnBlur: true}, }), [theme], ); useMermaidTheme(); // ... return (
{props.children}
); }); ``` -------------------------------- ### Install TypeScript with Specific Version Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md If there's a mismatch between the TypeScript version in devDependencies and overrides in package.json, use this command to update it. ```bash npm install typescript@ --save-dev ``` -------------------------------- ### Integrate HTML Transformer Plugin Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-html-extension.md Import and configure the HTML transformer plugin for your editor setup. Ensure the runtime marker constant is defined. ```typescript import { transform as transformHTML } from '@diplodoc/html-extension'; // Define the runtime marker constant const HTML_RUNTIME = 'html-runtime'; // Configure the plugins in your transformer setup const plugins: PluginWithParams[] = [ // Add HTML transformer plugin transformHTML({ bundle: false, runtimeJsPath: HTML_RUNTIME }), // Add other plugins as needed ]; ``` -------------------------------- ### Basic useFilesGallery Hook Usage Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md Use the useFilesGallery hook inside your component to get the function to open the file gallery. Attach this function to an event handler. ```tsx import {YfmStaticView, useFilesGallery} from '@gravity-ui/markdown-editor/view'; const {openFilesGallery} = useFilesGallery();
; ``` -------------------------------- ### Integrate Latex Transformer Plugin Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-latex-extension.md Import and configure the LaTeX transformer plugin for your editor setup. This involves defining a runtime marker and adding the transformer to the plugins array. ```typescript import { transform as transformLatex } from '@diplodoc/latex-extension'; // Define the runtime marker constant const LATEX_RUNTIME = 'latex-runtime'; // Configure the plugins in your transformer setup const plugins: PluginWithParams[] = [ // Add LaTeX transformer plugin transformLatex({ bundle: false, runtime: LATEX_RUNTIME }), // Add other plugins as needed ]; ``` -------------------------------- ### Integrate Mermaid Transformer Plugin Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-mermaid-extension.md Import and configure the Mermaid transformer plugin for your editor setup. This involves defining a runtime marker and adding the transformMermaid function to your plugins array. ```typescript import { transform as transformMermaid } from '@diplodoc/mermaid-extension'; // Define the runtime marker constant const MERMAID_RUNTIME = 'mermaid-runtime'; // Configure the plugins in your transformer setup const plugins: PluginWithParams[] = [ // Add Mermaid transformer plugin transformMermaid({ bundle: false, runtime: MERMAID_RUNTIME }), // Add other plugins as needed ]; ``` -------------------------------- ### Create React App with Gravity UI Template Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md Use this command to create a new React project with the gravity-ui-pure template and navigate into the project directory. ```bash npx create-react-app markdown-editor --template gravity-ui-pure && cd markdown-editor ``` -------------------------------- ### Prepare Component for Visual Testing Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Helper file to prepare the component for visual testing by composing Storybook stories. Ensure correct import paths. ```tsx import {composeStories} from '@storybook/react'; import * as DefaultMarkdownStories from '../../demo/stories/markdown/Markdown.stories'; export const MarkdownStories = composeStories(DefaultMarkdownStories); ``` -------------------------------- ### Adding Download and Copy Link Actions Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md Configure download and copy URL actions by providing functions to the useFilesGallery hook. These functions receive the URL from the content and return the desired URL for the action. ```tsx import {YfmStaticView, useFilesGallery} from '@gravity-ui/markdown-editor/view'; const {openFilesGallery} = useFilesGallery(undefined, {download: urlFromContent => getDownloadUrl(urlFromContent), copyUrl: urlFromContent => getUrlForCopy(urlFromContent)});
; ``` -------------------------------- ### Update package.json Scripts to Use CRACO Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md Modify the scripts in package.json to use CRACO for starting, building, and testing the React application. ```json { "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "react-scripts eject" } } ``` -------------------------------- ### Initialize and Use Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/markup/codemirror/html-to-markdown/__tests__/fixtures/code/output.md Use the `useMarkdownEditor` hook to manage editor state and `MarkdownEditorView` to render the UI. Handles submission by serializing content to markdown. ```javascript import React from 'react'; import { useMarkdownEditor, MarkdownEditorView } from '@gravity-ui/markdown-editor'; import { toaster } from '@gravity-ui/uikit/toaster-singleton-react-18'; function Editor({ onSubmit }) { const editor = useMarkdownEditor({ allowHTML: false }); React.useEffect(() => { function submitHandler() { // Serialize current content to markdown markup const value = editor.getValue(); onSubmit(value); } editor.on('submit', submitHandler); return () => { editor.off('submit', submitHandler); }; }, [onSubmit]); return ; } ``` -------------------------------- ### Run Unit Tests Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Execute all unit tests for the project from the root directory. This command runs tests using the configured test runner. ```bash pnpm test ``` -------------------------------- ### Import Toolbar Button Configuration Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/page-constructor-extension/README.md Import the configuration for the WYSIWYG Page Constructor toolbar item. ```typescript import {wYfmPageConstructorItemData} from '@gravity-ui/markdown-editor-page-constructor-extension/configs'; ``` -------------------------------- ### Run Visual Tests from Monorepo Root Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Execute visual tests for a specific package within the monorepo from the root directory. Ensure the package name is correctly specified. ```bash nx playwright:docker @markdown-editor/demo ``` -------------------------------- ### Show Visual Test Report in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Generate and display the test report after running visual tests. This report provides an overview of test results. ```bash pnpm run playwright:docker:report ``` -------------------------------- ### Run Playwright Tests in Docker from Demo Package Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Execute Playwright tests within Docker from the 'demo/' subpackage. Includes commands to clear cache and display reports. ```shell pnpm run playwright:docker pnpm run playwright:docker:clear pnpm run playwright:docker:report ``` -------------------------------- ### Run Visual (Playwright) Tests in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Execute visual regression tests using Playwright within a Docker environment. Navigate to the 'demo/' directory before running. ```bash pnpm run playwright:docker ``` -------------------------------- ### Toolbar Configuration Structure Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md A custom toolbar configuration object includes an `items` dictionary for defining toolbar elements and an `orders` array for specifying their display sequence. ```json { "items": { "bold": { "label": "Bold", "icon": "bold-icon", "action": "toggleBold" }, "italic": { "label": "Italic", "icon": "italic-icon", "action": "toggleItalic" } }, "orders": { "toolbar-1": ["bold", "italic"] } } ``` -------------------------------- ### Providing Custom Files to useFilesGallery Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md Pass an array of custom file objects to useFilesGallery to display files not present in the content. Custom file configurations override existing ones if URLs match. ```tsx import {YfmStaticView, useFilesGallery} from '@gravity-ui/markdown-editor/view'; import {getGalleryItemImage} from '@gravity-ui/components' const customImages = [ 'https://i.pinimg.com/originals/d8/bd/b4/d8bdb45a931b4265bec8e8d3f15021bf.jpg', 'https://i.pinimg.com/originals/c2/31/a0/c231a069c5e24099723564dae736f438.jpg', ]; const customFiles = customImages.map((image) => ({ url: image, ...getGalleryItemImage({src: image, name: image}), })); const {openFilesGallery} = useFilesGallery(customFiles);
; ``` -------------------------------- ### Run All Tests in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Execute all end-to-end tests within a Docker container to match CI results. Use the report command to view results. ```shell pnpm run test:e2e pnpm run test:e2e:report ``` -------------------------------- ### Initialize Editor with Preset Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md Initialize the Markdown Editor with a specific preset. The `preset` property defines the set of extensions and functionality. ```typescript useMarkdownEditor({ preset: 'default' }) ``` -------------------------------- ### Implement gptWidgetProps for GPT Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-gpt-extensions.md Define the `gptWidgetProps` object to configure the GPT extension's behavior, including custom prompt handling, prompt presets, and callbacks for applying results and tracking feedback. ```typescript import React from 'react'; import {type GptWidgetOptions} from '@gravity-ui/markdown-editor'; // Your function to implement GPT response const gptRequestHandler = async ({ markup, customPrompt, promptData, }: { markup: string; customPrompt?: string; promptData: unknown; }) => { await new Promise((resolve) => setTimeout(resolve, 1000)); let gptResponseMarkup = markup; if (customPrompt) { gptResponseMarkup = markup + ` \`enhanced with ${customPrompt}\``; } else if (promptData === 'do-uno-reverse') { gptResponseMarkup = gptResponseMarkup.replace(/[а-яЁёА-Я]+/g, (match) => match.split('').reverse().join(''); ); } else if (promptData === 'do-shout-out') { gptResponseMarkup = gptResponseMarkup.toLocaleUpperCase(); } return { rawText: gptResponseMarkup, }; }; function renderAnswer(data: {rawText: string}) { return
{data.rawText}
; } export const gptWidgetProps: GptWidgetOptions = { answerRender: renderAnswer, customPromptPlaceholder: 'Ask Yandex GPT to edit the text highlighted text', disabledPromptPlaceholder: 'Ask Yandex GPT to generate the text', gptAlertProps: { showedGptAlert: true, onCloseGptAlert: () => {}, }, promptPresets: [ { hotKey: 'control+3', data: 'do-uno-reverse', display: 'Use the uno card', key: 'do-uno-reverse', }, { hotKey: 'control+4', data: 'do-shout-out', display: 'Make the text flashy', key: 'do-shout-out', }, ], onCustomPromptApply: async ({markup, customPrompt, promptData}) => { return gptRequestHandler({markup, customPrompt, promptData}); }, onPromptPresetClick: async ({markup, customPrompt, promptData}) => { return gptRequestHandler({markup, customPrompt, promptData}); }, onTryAgain: async ({markup, customPrompt, promptData}) => { return gptRequestHandler({markup, customPrompt, promptData}); }, onApplyResult: (markup) => { // add your callback for apply GPT result text console.log(markup); }, onUpdate: (event) => { if (event?.rawText) { // add your callback for any text updates console.log(event.rawText); } }, onLike: async () => {}, // function to track feedback for good onDislike: async () => {}, // and bad GPT answers }; ``` -------------------------------- ### Update All Visual Test Snapshots in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Update all existing visual test snapshots. This command should be used when visual test baselines need to be refreshed. ```bash pnpm run playwright:docker:update ``` -------------------------------- ### Define Custom Toolbar Preset Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md Create a `ToolbarsPreset` object to define custom toolbar items and their order for different editor views (WYSIWYG and markup). ```typescript export const toolbarPresets: Record = { custom: { items: { [Action.undo]: { view: undoItemView, wysiwyg: undoItemWysiwyg, markup: undoItemMarkup, }, [Action.redo]: { view: redoItemView, wysiwyg: redoItemWysiwyg, markup: redoItemMarkup, }, [Action.bold]: { view: boldItemView, wysiwyg: boldItemWysiwyg, }, [Action.italic]: { view: italicItemView, markup: italicItemMarkup, }, [Action.colorify]: { view: colorifyItemView, wysiwyg: colorifyItemWysiwyg, markup: colorifyItemMarkup, }, }, orders: { [Toolbar.wysiwygMain]: [[Action.colorify], [Action.bold], [Action.undo, Action.redo]], [Toolbar.markupMain]: [[Action.colorify], [Action.italic], [Action.undo, Action.redo]], }, }, }; ``` -------------------------------- ### Implement Conditional Toolbar Items Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md Create a getter function that dynamically returns toolbar configurations based on input parameters, allowing for conditional display of toolbar items. ```typescript type Falsy = false | 0 | 0n | '' | null | undefined; export function isTruthy(value: T): value is Exclude { return Boolean(value); } export const getToolbarPresets = ({ enableColorify, }): Record => ({ custom: { items: { [Action.undo]: { view: undoItemView, wysiwyg: undoItemWysiwyg, markup: undoItemMarkup, }, [Action.redo]: { view: redoItemView, wysiwyg: redoItemWysiwyg, markup: redoItemMarkup, }, [Action.bold]: { view: boldItemView, wysiwyg: boldItemWysiwyg, }, [Action.italic]: { view: italicItemView, markup: italicItemMarkup, }, [Action.colorify]: { view: colorifyItemView, wysiwyg: colorifyItemWysiwyg, markup: colorifyItemMarkup, }, }, orders: { [Toolbar.wysiwygMain]: [ enableColorify && [Action.colorify], [Action.bold], [Action.undo, Action.redo], ].filter(isTruthy), [Toolbar.markupMain]: [ enableColorify && [Action.colorify], [Action.italic], [Action.undo, Action.redo], ].filter(isTruthy), }, }, }); ``` -------------------------------- ### Integrate WYSIWYG Latex Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-latex-extension.md Integrate the WYSIWYG extension for LaTeX, including loading the runtime script and its styles. This is done using the builder's `use` method. ```typescript import {Math} from '@gravity-ui/markdown-editor/extensions/yfm/Math'; // ... builder.use(Math, { loadRuntimeScript: () => { import('@diplodoc/latex-extension/runtime'); // @ts-expect-error no types for styles import('@diplodoc/latex-extension/runtime/styles'); }, }); ``` -------------------------------- ### Configure Webpack resolve.fallback Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-nextjs.md Add this to your Webpack configuration to resolve 'fs', 'process', and 'path' module issues. ```javascript module.exports = { webpack: { configure: (webpackConfig) => { webpackConfig.resolve.fallback = { fs: false, process: false, path: false, }; return webpackConfig; }, }, }; ``` -------------------------------- ### Configure Turbopack resolveAlias Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-nextjs.md If using Turbopack, set up 'resolveAlias' to handle 'fs' module dependencies. ```javascript experimental: { turbo: { resolveAlias: { fs: './stubs/fs.js', }, }, }, ``` -------------------------------- ### Update Specific Snapshots in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Update reference screenshots for a specific test in Docker using the --grep flag. This is useful for targeted updates. ```shell pnpm run playwright:docker:update --grep 'Punctuation boundaries' ``` -------------------------------- ### Add a Preview Component with Re-render Handler Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-preview.md This snippet shows how to create a preview component using `YfmStaticView` and handle re-renders when the markdown content changes. It utilizes `useState`, `useRef`, `useMemo`, and `useEffect` for state management and debounced rendering. ```typescript const {plugins, getValue, allowHTML, breaks, linkify, linkifyTlds, needToSanitizeHtml} = props; const [html, setHtml] = useState(''); const [meta, setMeta] = useState({}); const divRef = useRef(null); const theme = useThemeValue(); const render = useMemo( () => debounce(() => { const res = transform(getValue(), { allowHTML, breaks, plugins, linkify, linkifyTlds, needToSanitizeHtml, }).result; setHtml(res.html); setMeta(res.meta); }, 200), [getValue, allowHTML, breaks, plugins, linkify, linkifyTlds, needToSanitizeHtml, theme], ); useEffect(() => { render(); }, [props, render]); return ( ); }; ``` -------------------------------- ### Add Higher-Order Component for Static Rendering Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-html-extension.md Use the `withYfmHtmlBlock` HOC to create a static view component that loads runtime and applies styling hooks for HTML blocks. ```typescript import {useEffect} from 'react'; import {YfmHtml} from '@gravity-ui/markdown-editor/view/components/YfmHtml'; import type {WithYfmHtmlBlockProps} from '@gravity-ui/markdown-editor/view/hocs/withYfmHtml'; import {withYfmHtmlBlock} from '@gravity-ui/markdown-editor/view/hocs/withYfmHtml'; import {useEffect, useState} from 'react'; import {IHTMLIFrameElementConfig} from '@diplodoc/html-extension/runtime'; import {getYfmHtmlBlockCssVariables} from '@gravity-ui/markdown-editor/view/hocs/withYfmHtml/utils'; import {useThemeValue} from '@gravity-ui/uikit'; // HOC export const YFM_HTML_BLOCK_RUNTIME = 'yfm-html-block'; const YfmStaticView = withYfmHtmlBlock({runtime: YFM_HTML_BLOCK_RUNTIME})(YfmHtml); const variablesMapping = { colorBackground: '--g-color-base-background', colorTextPrimary: '--g-color-text-primary', colorTextSecondary: '--g-color-text-secondary', fontFamily: '--g-font-family-sans', fontSize: '--g-text-body-1-font-size', }; // hooks export const useYfmHtmlBlockStyles = () => { const theme = useThemeValue(); const [config, setConfig] = useState(); useEffect(() => { const bodyStyles = window.getComputedStyle(document.body); const styles = Object.entries(variablesMapping).reduce( (acc, [key, cssVariable]) => { acc[key] = bodyStyles.getPropertyValue(cssVariable); return acc; }, {} as Record, ); setConfig({ styles: getYfmHtmlBlockCssVariables(styles), classNames: [theme], resizePadding: 50, resizeDelay: 100, }); }, [theme]); return config; }; // render const HtmlRenderer = React.forwardRef((props, ref) => { // ... const theme = useThemeType(); // your hook for get theme const yfmHtmlBlockConfig = useYfmHtmlBlockStyles(); () => ({ theme, zoom: {showMenu: true, bindKeys: true, resetOnBlur: true}, }), [theme], ); // ... return (
{props.children}
); }); ``` -------------------------------- ### Integrate Extension and Toolbar Button into Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-text-binding-extension-in-markdown.md Connects the custom extension and toolbar button to the Markdown editor configuration. This involves importing necessary components and updating the editor's markup configuration. ```typescript import {markupToolbarConfigs, useMarkdownEditor} from '@gravity-ui/markdown-editor'; import {ghostPopupExtension} from './ghostExtension'; import {ghostPopupToolbarItem} from './toolbar'; const mToolbarConfig = [...markupToolbarConfigs.mToolbarConfig,]; mToolbarConfig.mToolbarConfig.push(ghostPopupToolbarItem); const mdEditor = useMarkdownEditor({ // ... // Add extension markupConfig: { extensions: [ghostPopupExtension], }, }); return ``` -------------------------------- ### Pass Additional Properties to useMarkdownEditor for Preview Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-preview.md This snippet demonstrates how to configure the `useMarkdownEditor` hook to enable split mode preview. It defines a `renderPreview` callback and passes it along with other editor configurations. ```typescript // ... const renderPreview = useCallback( ({getValue}) => ( ), [], ); const editor = useMarkdownEditor({ allowHTML: false, renderPreview, initialEditorMode: 'wysiwyg', initialSplitModeEnabled: true, initialToolbarVisible: true, splitMode: 'horizontal', }); // ... ``` -------------------------------- ### Handling Custom File Types with resolveCustomItem Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md Extend the gallery to support custom file types like PDFs by implementing the `resolveCustomItem` option. This function determines how to render non-image/video files. ```tsx import {YfmStaticView, useFilesGallery} from '@gravity-ui/markdown-editor/view'; import {getGalleryItemImage} from '@gravity-ui/components'; function resolveCustomItem(url: string, type: 'file', element: Element, {name, mimetype}: {name?: string | null; mimetype?: string | null}) { if (mimetype !== 'application/pdf') return undefined; return getGalleryItemImage({src: '/icons/pdf.svg', name: name ?? url}); } const {openFilesGallery} = useFilesGallery(undefined, {resolveCustomItem});
; ``` -------------------------------- ### Implement Split-Mode Preview HOC Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/page-constructor-extension/README.md Use the withYfmPageConstructor HOC to create a split-mode preview component for your Markdown editor content. Specify the runtime identifier for Page Constructor. ```typescript import {withYfmPageConstructor} from '@gravity-ui/markdown-editor-page-constructor-extension/view'; const PAGE_CONSTRUCTOR_RUNTIME = 'extension:page-constructor'; const Preview = withYfmPageConstructor({runtime: PAGE_CONSTRUCTOR_RUNTIME})(YfmStaticView); ``` -------------------------------- ### useFilesGallery Hook Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/view/hooks/useFilesGallery/README.md The useFilesGallery hook provides a function to open a gallery of images and videos embedded in HTML content. It accepts custom files and options to customize the gallery's behavior, such as download and copy URL actions. ```APIDOC ## useFilesGallery Hook ### Description The `useFilesGallery` hook is designed to facilitate the opening of a gallery displaying images and videos embedded within HTML content. It allows for the inclusion of additional custom files and provides extensive options for customizing the gallery's functionality, including download and URL copying features. ### Usage ```javascript const { openFilesGallery } = useFilesGallery({ customFiles: [ { url: 'http://example.com/image.jpg', alt: 'Custom Image' }, { url: 'http://example.com/video.mp4', alt: 'Custom Video' } ], options: { download: (url, type, element) => { // Custom download logic return url; // Return URL to enable download }, copyUrl: (url, type, element) => { // Custom copy URL logic return url; // Return URL to enable copy }, overrideItemProps: (url, type, element, currentProps) => { // Override item properties return currentProps; }, resolveCustomItem: (url, type, element, linkObj) => { // Resolve custom item properties for non-image/video files if (type === 'file') { return { url, type: 'file', name: linkObj.name }; } return undefined; } } }); // To open the gallery, call openFilesGallery with the click event const handleClick = (event) => { const opened = openFilesGallery({ event }); if (opened) { console.log('Gallery opened successfully'); } }; ``` ### Parameters #### `useFilesGallery` Hook Options ##### `customFiles` - **Type**: `Array` - **Description**: An array of additional files to include in the gallery. Providing a `url` allows these items to be excluded from content if found. ##### `options` (`UseFilesGalleryOptions`) - **Type**: `object` - **Description**: Configuration options for the files gallery. **`UseFilesGalleryOptions` Properties:** - **`download`** (`(url: string, type: FilesGalleryItemType, element: Element) => string | undefined`) - **Description**: A function that returns a file download link. If implemented, a download action will be shown. `FilesGalleryItemType` can be `'image'`, `'video'`, or `'file'`. - **`copyUrl`** (`(url: string, type: FilesGalleryItemType, element: Element) => string | undefined`) - **Description**: A function that returns a file copy URL. If implemented, a copy URL action will be shown. `FilesGalleryItemType` can be `'image'`, `'video'`, or `'file'`. - **`overrideItemProps`** (`(url: string, type: FilesGalleryItemType, element: Element, currentProps: GalleryItemProps) => GalleryItemProps`) - **Description**: A function to override the default gallery item properties. It receives the current item's properties and should return the modified properties. - **`resolveCustomItem`** (`(url: string, type: 'file', element: Element, linkObj: { name?: string | null; mimetype?: string | null }) => GalleryItemProps | undefined`) - **Description**: A function to resolve properties for custom file types not handled by default image/video logic. Return `undefined` to skip the element. The returned props are processed by `download`/`copyUrl`/`overrideItemProps`. `FilesGalleryItemType` is now `'image' | 'video' | 'file'`. ### Return Value The `useFilesGallery` hook returns an object with a single function: - **`openFilesGallery`** (`(args: { event: React.MouseEvent }) => boolean`) - **Description**: This function opens the files gallery. It requires the click event as an argument. It returns `true` if the gallery was successfully opened, and `false` otherwise. ### GalleryProvider Props (Optional Configuration) While not directly used by `useFilesGallery`, these props are relevant if you are using a `GalleryProvider` context: - **`theme`** (`ThemeProviderProps['theme']`) - **Description**: The theme for the gallery. - **`className`** (`String`) - **Description**: A CSS class to apply to the modal. - **`container`** (`HTMLElement`) - **Description**: The DOM element to use as the modal container. - **`emptyMessage`** (`String`) - **Description**: Message to display when the gallery is empty. Defaults to 'No data'. ``` -------------------------------- ### Run Specific Visual Test in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Execute a specific visual test by providing a grep pattern to filter tests. This is useful for targeted debugging. ```bash pnpm run playwright:docker --grep 'Test name' ``` -------------------------------- ### Update Specific Visual Test Snapshot in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/AGENTS.md Update a specific visual test snapshot by providing a grep pattern. This allows for targeted snapshot updates. ```bash pnpm run playwright:docker:update --grep 'Test name' ``` -------------------------------- ### Stub fs module for client-side Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-nextjs.md Provide a stub for the 'fs' module to prevent errors in browser environments. ```javascript let fs; if (typeof window === 'undefined') { fs = require('node:fs'); } else { fs = {}; } module.exports = fs; ``` -------------------------------- ### Create Commands for Ghost Popup Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-text-binding-extension-in-markdown.md Defines state effects for showing and hiding a ghost popup and creates functions to dispatch these effects to the editor view. These commands are used to control the popup's visibility. ```typescript import type {EditorView} from '@gravity-ui/markdown-editor/cm/view'; import {StateEffect} from '@gravity-ui/markdown-editor/cm/state'; // Empty effects without parameters export const ShowGhostPopupEffect = StateEffect.define(); export const HideGhostPopupEffect = StateEffect.define(); // Creating events that will trigger the plugin // Effect on the similarity of meta information for update, we use it as a Boolean flag export const showGhostPopup = (view: EditorView) => { view.dispatch({effects: [ShowGhostPopupEffect.of(null)]}); }; export const hideGhostPopup = (view: EditorView) => { view.dispatch({effects: [HideGhostPopupEffect.of(null)]}); }; ``` -------------------------------- ### Import EditorView from ProseMirror View Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/pm/readme.md Import the EditorView class from the '@gravity-ui/markdown-editor/pm/view' module. This is typically used to interact with the ProseMirror editor instance. ```javascript import {EditorView} from '@gravity-ui/markdown-editor/pm/view'; ``` -------------------------------- ### Add Math Buttons to Toolbar Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-latex-extension.md Add buttons for inline and block math to the markdown editor's toolbar by configuring the `extensionOptions` with command menu actions. ```typescript import { mMathListItem, } from '@gravity-ui/markdown-editor/bundle/config/markup'; import { wMathBlockItemData, wMathInlineItemData, } from '@gravity-ui/markdown-editor'; // add to useMarkdownEditor const mdEditor = useMarkdownEditor({ // ... extensionOptions: { commandMenu: {actions: [wMathInlineItemData, wMathBlockItemData]}, }, }); ``` -------------------------------- ### Initialize WYSIWYG Extension in Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/page-constructor-extension/README.md Use the YfmPageConstructorExtension with the builder to enable WYSIWYG editing for Page Constructor blocks. Configure autoSave options if needed. ```typescript import {YfmPageConstructorExtension} from '@gravity-ui/markdown-editor-page-constructor-extension'; builder.use(YfmPageConstructorExtension, { autoSave: {enabled: true, delay: 1000}, }); ``` -------------------------------- ### Use Custom Toolbar Preset with Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md Integrate your custom toolbar preset into the Markdown Editor by passing it to the `toolbarsPreset` prop of the `MarkdownEditorView` component. ```typescript import {useMarkdownEditor, MarkdownEditorView} from '@gravity-ui/markdown-editor'; import {toolbarPresets} from './your-toolbar-presets'; function MyEditor() { // Initialize editor with an editor preset (defines functionality) const editor = useMarkdownEditor({ preset: 'default', // or 'zero', 'commonmark', 'yfm', 'full' }); return ( ); } ``` -------------------------------- ### Run Specific End-to-End Test with Grep Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Filter and run specific end-to-end tests from the root directory using the --grep flag. ```shell pnpm run test:e2e --grep 'Punctuation boundaries' ``` -------------------------------- ### Import EditorView from CM View Source: https://github.com/gravity-ui/markdown-editor/blob/main/packages/editor/src/cm/readme.md Import the EditorView class from the '@gravity-ui/markdown-editor/cm/view' path. This is used for interacting with the CodeMirror editor instance. ```javascript import {EditorView} from '@gravity-ui/markdown-editor/cm/view'; ``` -------------------------------- ### App Component with Editor Integration Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-create-react-app.md Integrates the Editor component into the main App component, setting up theming and toaster services. ```tsx import {ThemeProvider, Toaster, ToasterComponent, ToasterProvider} from '@gravity-ui/uikit'; import {MarkupString} from '@gravity-ui/markdown-editor'; import {Editor} from './Editor'; const toaster = new Toaster(); const App = () => { const handleSubmit = (value: MarkupString) => { console.log(value); }; return ( ); }; export default App; ``` -------------------------------- ### Load Editor on Client-Side with Next.js Dynamic Import Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-editor-with-nextjs.md Use dynamic import with SSR disabled to load editor components that depend on the DOM on the client side. ```javascript import dynamic from 'next/dynamic'; ... const MarkdownEditor = dynamic( () => import('./MarkdownEditor').then( (mod) => mod.MarkdownEditor, ), { ssr: false, }, ); ``` -------------------------------- ### Implement Custom NodeView Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-create-extension.md Imports necessary components from 'prosemirror-view' to implement a custom NodeView for editor extensions. This is required for custom rendering and interaction within the editor. ```typescript import {EditorView, NodeView} from 'prosemirror-view'; // ... export class WMermaidNodeView implements NodeView { // ... } ``` -------------------------------- ### Update Reference Screenshots in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Command to update reference screenshots in Docker for a specific test name. Use the -g flag to specify the test name. ```shell pnpm run playwright:docker:update -g "test name" ``` -------------------------------- ### Implement Ghost Popup Plugin for Markdown Editor Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-text-binding-extension-in-markdown.md This plugin handles text decorations and popup rendering in Markdown mode. It uses CodeMirror's ViewPlugin to manage decorations and ReactRendererFacet for rendering UI components. Use this when you need to attach interactive elements to specific text ranges. ```typescript // plugin.ts import { ReactRendererFacet, } from '@gravity-ui/markdown-editor'; import { Decoration, type DecorationSet, type EditorView, type PluginValue, ViewPlugin, type ViewUpdate, WidgetType, } from '@gravity-ui/markdown-editor/cm/view'; // We'll talk about it later import {hideGhostPopup} from './commands'; import {HideGhostPopupEffect, ShowGhostPopupEffect} from './effects'; import {renderPopup} from './popup'; const DECO_CLASS_NAME = 'ghost-example'; // The class that will return the span element to the decoration class SpanWidget extends WidgetType { private className = ''; private textContent = ''; constructor(className: string, textContent: string) { super(); this.className = className; this.textContent = textContent; } toDOM() { const spanElem = document.createElement('span'); spanElem.className = this.className; spanElem.textContent = this.textContent; return spanElem; } } // Using ViewPlugin.fromClass imported from CodeMirror // It accepts an anonymous class and PluginSpec export const GhostPopupPlugin = ViewPlugin.fromClass( class implements PluginValue { // The class allows you to implement the following methods: update, docViewUpdate, destroy. decos: DecorationSet = Decoration.none; readonly _view: EditorView; readonly _renderItem; _anchor: Element | null = null; constructor(view: EditorView) { // Saving the view and creating a renderItem this._view = view; this._renderItem = view.state .facet(ReactRendererFacet) .createItem('ghost-popup-example-in-markup-mode', () => this.renderPopup()); } // Called when transactions want to be applied to the view update(update: ViewUpdate) { if (update.docChanged || update.selectionSet) { this.decos = Decoration.none; return; } this.decos = this.decos.map(update.changes); const {from, to} = update.state.selection.main; for (const tr of update.transactions) { for (const eff of tr.effects) { // Check for the desired effect if (eff.is(ShowGhostPopupEffect)) { if (from === to) { // Creating a decoration const decorationWidget = Decoration.widget({ widget: new SpanWidget(DECO_CLASS_NAME, ''), }); this.decos = Decoration.set([decorationWidget.range(from)]); return; } this.decos = Decoration.set([ { from, to, value: Decoration.mark({class: DECO_CLASS_NAME}), }, ]); } // If such an effect has come, then we cancel the decorations if (eff.is(HideGhostPopupEffect)) { this.decos = Decoration.none; } } } } // Is called after accepting a new state in the view and dom docViewUpdate() { // Save the link to our decoration this._anchor = this._view.dom.getElementsByClassName(DECO_CLASS_NAME).item(0); this._renderItem.rerender(); } // Called when unmounting the view destroy() { this._renderItem.remove(); } // Function for popup render renderPopup() { // Passing the link to our popup return this._anchor ? renderPopup(this._anchor as HTMLElement, { onClose: () => hideGhostPopup(this._view), }) : null; } }, // Used to draw decorations { // Value is a reference to our anonymous class and returns the decoration decorations: (value) => value.decos, }, ); ``` -------------------------------- ### Use MarkdownEditorView with Custom Toolbar Preset Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-customize-toolbars.md Configure the MarkdownEditorView component to use a custom toolbar preset by passing it to the `toolbarsPreset` property. This overrides the default toolbar configuration. ```typescript ``` -------------------------------- ### Integrate WYSIWYG Mermaid Extension Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-connect-mermaid-extension.md Integrate the WYSIWYG Mermaid extension into the markdown editor builder. This involves importing the Mermaid extension and specifying the path to load its runtime script. ```typescript import {Mermaid} from '@gravity-ui/markdown-editor/extensions/yfm/Mermaid'; // ... builder.use(Mermaid, { loadRuntimeScript: () => { import('@diplodoc/mermaid-extension/runtime'); }, }); ``` -------------------------------- ### Run Specific Playwright Test in Docker Source: https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-visual-test.md Filter and run specific Playwright tests in Docker using the --grep flag. Supports substring and regex matching. ```shell pnpm run playwright:docker --grep 'Punctuation boundaries' ```