fix: tables in markdown preview (#1013)

This commit is contained in:
Daniel Lautzenheiser 2024-01-02 12:29:54 -05:00 committed by GitHub
parent 94b21424ce
commit 49597697d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 684 additions and 297 deletions

View File

@ -32,5 +32,6 @@
}, },
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
] ],
"dependencies": {}
} }

View File

@ -67,8 +67,8 @@
"@emotion/react": "11.10.6", "@emotion/react": "11.10.6",
"@emotion/styled": "11.10.6", "@emotion/styled": "11.10.6",
"@lezer/common": "1.0.2", "@lezer/common": "1.0.2",
"@mdx-js/mdx": "2.3.0", "@mdx-js/mdx": "3.0.0",
"@mdx-js/react": "2.3.0", "@mdx-js/react": "3.0.0",
"@mui/base": "5.0.0-beta.14", "@mui/base": "5.0.0-beta.14",
"@mui/material": "5.11.16", "@mui/material": "5.11.16",
"@mui/system": "5.11.16", "@mui/system": "5.11.16",
@ -120,15 +120,15 @@
"jwt-decode": "3.1.2", "jwt-decode": "3.1.2",
"localforage": "1.10.0", "localforage": "1.10.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"mdast-util-gfm-footnote": "1.0.2", "mdast-util-gfm-footnote": "2.0.0",
"mdast-util-gfm-strikethrough": "1.0.3", "mdast-util-gfm-strikethrough": "2.0.0",
"mdast-util-gfm-table": "1.0.7", "mdast-util-gfm-table": "2.0.0",
"mdast-util-gfm-task-list-item": "1.0.2", "mdast-util-gfm-task-list-item": "2.0.0",
"micromark-extension-gfm-footnote": "1.1.0", "micromark-extension-gfm-footnote": "2.0.0",
"micromark-extension-gfm-strikethrough": "1.0.5", "micromark-extension-gfm-strikethrough": "2.0.0",
"micromark-extension-gfm-table": "1.0.5", "micromark-extension-gfm-table": "2.0.0",
"micromark-extension-gfm-task-list-item": "1.0.4", "micromark-extension-gfm-task-list-item": "2.0.1",
"micromark-util-combine-extensions": "1.0.0", "micromark-util-combine-extensions": "2.0.0",
"minimatch": "9.0.0", "minimatch": "9.0.0",
"moment": "2.29.4", "moment": "2.29.4",
"node-polyglot": "2.5.0", "node-polyglot": "2.5.0",
@ -142,7 +142,7 @@
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-frame-component": "5.2.6", "react-frame-component": "5.2.6",
"react-is": "18.2.0", "react-is": "18.2.0",
"react-markdown": "8.0.7", "react-markdown": "9.0.1",
"react-polyglot": "0.7.2", "react-polyglot": "0.7.2",
"react-redux": "8.0.5", "react-redux": "8.0.5",
"react-router-dom": "6.10.0", "react-router-dom": "6.10.0",
@ -153,9 +153,9 @@
"react-waypoint": "10.3.0", "react-waypoint": "10.3.0",
"react-window": "1.8.9", "react-window": "1.8.9",
"remark-gfm": "4.0.0", "remark-gfm": "4.0.0",
"remark-html": "15.0.2", "remark-html": "16.0.1",
"remark-mdx": "2.3.0", "remark-mdx": "3.0.0",
"remark-parse": "10.0.1", "remark-parse": "11.0.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"scheduler": "0.23.0", "scheduler": "0.23.0",
"semaphore": "1.1.0", "semaphore": "1.1.0",
@ -166,15 +166,15 @@
"stream-browserify": "3.0.0", "stream-browserify": "3.0.0",
"styled-components": "5.3.10", "styled-components": "5.3.10",
"symbol-observable": "4.0.0", "symbol-observable": "4.0.0",
"unified": "10.1.2", "unified": "11.0.4",
"unist-util-visit": "4.1.2", "unist-util-visit": "5.0.0",
"url": "0.11.0", "url": "0.11.0",
"url-join": "5.0.0", "url-join": "5.0.0",
"uuid": "9.0.0", "uuid": "9.0.0",
"validate-color": "2.2.4", "validate-color": "2.2.4",
"vfile": "5.3.7", "vfile": "6.0.1",
"vfile-message": "3.1.4", "vfile-message": "4.0.2",
"vfile-statistics": "2.0.1", "vfile-statistics": "3.0.0",
"what-input": "5.2.12", "what-input": "5.2.12",
"what-the-diff": "0.6.0", "what-the-diff": "0.6.0",
"yaml": "2.2.2" "yaml": "2.2.2"
@ -218,6 +218,7 @@
"@types/react-virtualized-auto-sizer": "1.0.1", "@types/react-virtualized-auto-sizer": "1.0.1",
"@types/react-window": "1.8.5", "@types/react-window": "1.8.5",
"@types/styled-components": "5.1.26", "@types/styled-components": "5.1.26",
"@types/unist": "3.0.2",
"@types/url-join": "4.0.1", "@types/url-join": "4.0.1",
"@types/uuid": "9.0.1", "@types/uuid": "9.0.1",
"@typescript-eslint/eslint-plugin": "5.59.1", "@typescript-eslint/eslint-plugin": "5.59.1",

View File

@ -8,6 +8,8 @@ import { getShortcodes } from '../../../../lib/registry';
import gfm from '../serialization/gfm'; import gfm from '../serialization/gfm';
import toSlatePlugin from '../serialization/slate/toSlatePlugin'; import toSlatePlugin from '../serialization/slate/toSlatePlugin';
import type { ProcessCallback } from 'unified';
import type { VFile } from 'vfile';
import type { ShortcodeConfig } from '../../../../interface'; import type { ShortcodeConfig } from '../../../../interface';
import type { MdValue } from '../plateTypes'; import type { MdValue } from '../plateTypes';
@ -22,19 +24,22 @@ export const markdownToSlate = async (
{ useMdx, shortcodeConfigs }: UseMarkdownToSlateOptions, { useMdx, shortcodeConfigs }: UseMarkdownToSlateOptions,
) => { ) => {
return new Promise<MdValue>(resolve => { return new Promise<MdValue>(resolve => {
const callback: ProcessCallback<VFile> = (err, file) => {
if (err) {
console.error(err);
return;
}
resolve(file?.result as MdValue);
return undefined;
};
unified() unified()
.use(markdown) .use(markdown)
.use(gfm) .use(gfm)
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
.use(useMdx ? mdx : () => {}) .use(useMdx ? mdx : () => {})
.use(toSlatePlugin({ shortcodeConfigs: shortcodeConfigs ?? getShortcodes(), useMdx })) .use(toSlatePlugin({ shortcodeConfigs: shortcodeConfigs ?? getShortcodes(), useMdx }))
.process(markdownValue, (err, file) => { .process(markdownValue, callback);
if (err) {
console.error(err);
return;
}
resolve(file?.result as MdValue);
});
}); });
}; };

View File

@ -2,13 +2,15 @@ import { evaluate } from '@mdx-js/mdx';
import * as provider from '@mdx-js/react'; import * as provider from '@mdx-js/react';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import * as runtime from 'react/jsx-runtime'; import * as runtime from 'react/jsx-runtime';
import remarkGfm from 'remark-gfm';
import { VFile } from 'vfile'; import { VFile } from 'vfile';
import { VFileMessage } from 'vfile-message'; import { VFileMessage } from 'vfile-message';
import useDebouncedCallback from '@staticcms/core/lib/hooks/useDebouncedCallback';
import flattenListItemParagraphs from '../serialization/slate/flattenListItemParagraphs';
import useDebounce from '@staticcms/core/lib/hooks/useDebounce'; import useDebounce from '@staticcms/core/lib/hooks/useDebounce';
import useDebouncedCallback from '@staticcms/core/lib/hooks/useDebouncedCallback';
import remarkGfm from '../serialization/gfm';
import flattenListItemParagraphs from '../serialization/slate/flattenListItemParagraphs';
import type { Compatible } from 'vfile';
export interface UseMdxState { export interface UseMdxState {
file: VFile | null; file: VFile | null;
@ -33,7 +35,7 @@ export default function useMdx(
}; };
try { try {
file.result = (await evaluate(file, options)).default; file.result = (await evaluate(file as Readonly<Compatible>, options)).default;
} catch (error) { } catch (error) {
const message = error instanceof VFileMessage ? error : new VFileMessage(String(error)); const message = error instanceof VFileMessage ? error : new VFileMessage(String(error));

View File

@ -20,9 +20,9 @@ import type { Plugin, Processor } from 'unified';
function gfmFromMarkdown() { function gfmFromMarkdown() {
return [ return [
gfmFootnoteFromMarkdown(), gfmFootnoteFromMarkdown(),
gfmStrikethroughFromMarkdown, gfmStrikethroughFromMarkdown(),
gfmTableFromMarkdown, gfmTableFromMarkdown(),
gfmTaskListItemFromMarkdown, gfmTaskListItemFromMarkdown(),
]; ];
} }
@ -30,15 +30,22 @@ function gfmToMarkdown() {
return { return {
extensions: [ extensions: [
gfmFootnoteToMarkdown(), gfmFootnoteToMarkdown(),
gfmStrikethroughToMarkdown, gfmStrikethroughToMarkdown(),
gfmTableToMarkdown({}), gfmTableToMarkdown({}),
gfmTaskListItemToMarkdown, gfmTaskListItemToMarkdown(),
], ],
}; };
} }
function gfm() { function gfm() {
return combineExtensions([gfmFootnote(), gfmStrikethrough({}), gfmTable, gfmTaskListItem]); return combineExtensions([gfmFootnote(), gfmStrikethrough({}), gfmTable(), gfmTaskListItem()]);
}
declare module 'unified' {
interface Data {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
toMarkdownExtensions?: Array<any>;
}
} }
/** /**
@ -47,15 +54,13 @@ function gfm() {
const remarkGfm: Plugin<void[], Root> = function (this: Processor) { const remarkGfm: Plugin<void[], Root> = function (this: Processor) {
const data = this.data(); const data = this.data();
add('micromarkExtensions', gfm()); const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = []);
add('fromMarkdownExtensions', gfmFromMarkdown()); const fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = []);
add('toMarkdownExtensions', gfmToMarkdown()); const toMarkdownExtensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
function add(field: string, value: unknown) { micromarkExtensions.push(gfm());
const list = (data[field] ? data[field] : (data[field] = [])) as unknown[]; fromMarkdownExtensions.push(gfmFromMarkdown());
toMarkdownExtensions.push(gfmToMarkdown());
list.push(value);
}
}; };
export default remarkGfm; export default remarkGfm;

View File

@ -1,7 +1,8 @@
import { visit } from 'unist-util-visit'; import { visit } from 'unist-util-visit';
import type { Plugin } from 'unified'; import type { Plugin } from 'unified';
import type { Parent, Node, VisitorResult } from 'unist-util-visit/lib'; import type { Node, Parent } from 'unist';
import type { VisitorResult } from 'unist-util-visit';
const flattenListItemParagraphs: Plugin = function () { const flattenListItemParagraphs: Plugin = function () {
return ast => { return ast => {

View File

@ -1,7 +1,7 @@
import transform from './deserializeMarkdown'; import transform from './deserializeMarkdown';
import type { ShortcodeConfig } from '@staticcms/core/interface'; import type { ShortcodeConfig } from '@staticcms/core/interface';
import type { Plugin } from 'unified'; import type { Compiler, Plugin } from 'unified';
import type { MdastNode } from './ast-types'; import type { MdastNode } from './ast-types';
export interface ToSlatePluginOptions { export interface ToSlatePluginOptions {
@ -19,7 +19,7 @@ export const slateCompiler =
const toSlatePlugin = (options: ToSlatePluginOptions): Plugin => const toSlatePlugin = (options: ToSlatePluginOptions): Plugin =>
function () { function () {
this.Compiler = slateCompiler(options); this.compiler = slateCompiler(options) as unknown as Compiler;
}; };
export default toSlatePlugin; export default toSlatePlugin;

868
yarn.lock

File diff suppressed because it is too large Load Diff