@mdxeditor/editor 2.10.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -818,6 +818,11 @@ export declare const diffSourcePlugin: (params?: {
818
818
  * Optional, additional CodeMirror extensions to load in the diff/source mode.
819
819
  */
820
820
  codeMirrorExtensions?: Extension_2[] | undefined;
821
+ /**
822
+ * Set the diff editor to read-only.
823
+ * @default false
824
+ */
825
+ readOnlyDiff?: boolean | undefined;
821
826
  } | undefined) => RealmPlugin;
822
827
 
823
828
  /**
@@ -1023,6 +1028,11 @@ export declare type EditorSubscription = (activeEditor: LexicalEditor) => () =>
1023
1028
 
1024
1029
  /* Excluded from this release type: exportVisitors$ */
1025
1030
 
1031
+ declare type ExpressionValue = {
1032
+ type: 'expression';
1033
+ value: string;
1034
+ };
1035
+
1026
1036
  /**
1027
1037
  * A default option to be displayed in the {@link ConditionalContents} component if none of the other options match.
1028
1038
  * @group Toolbar Primitives
@@ -1379,12 +1389,12 @@ export declare interface InsertImageParameters {
1379
1389
  export declare const insertJsx$: NodeRef<{
1380
1390
  kind: 'text';
1381
1391
  name: string;
1382
- props: Record<string, string>;
1392
+ props: JsxProperties;
1383
1393
  children?: Mdast.PhrasingContent[] | undefined;
1384
1394
  } | {
1385
1395
  kind: 'flow';
1386
1396
  name: string;
1387
- props: Record<string, string>;
1397
+ props: JsxProperties;
1388
1398
  children?: (Mdast.BlockContent | Mdast.DefinitionContent)[] | undefined;
1389
1399
  }>;
1390
1400
 
@@ -1491,9 +1501,10 @@ export declare function joinProc(...procs: Array<() => unknown>): () => void;
1491
1501
  */
1492
1502
  export declare interface JsxComponentDescriptor {
1493
1503
  /**
1494
- * The tag name
1504
+ * The tag name. For example: 'div', 'span', 'MyComponent'.
1505
+ * Note: For fragments, use null.
1495
1506
  */
1496
- name: string;
1507
+ name: string | null;
1497
1508
  /**
1498
1509
  * Wether the component is a flow or text component (inline or block)
1499
1510
  */
@@ -1521,7 +1532,11 @@ export declare interface JsxComponentDescriptor {
1521
1532
  Editor: React_2.ComponentType<JsxEditorProps>;
1522
1533
  }
1523
1534
 
1524
- /* Excluded from this release type: jsxComponentDescriptors$ */
1535
+ /**
1536
+ * Contains the currently registered JSX component descriptors.
1537
+ * @group JSX
1538
+ */
1539
+ export declare const jsxComponentDescriptors$: NodeRef<JsxComponentDescriptor[]>;
1525
1540
 
1526
1541
  /**
1527
1542
  * The properties passed to a custom JSX Editor component.
@@ -1534,18 +1549,30 @@ export declare interface JsxEditorProps {
1534
1549
  descriptor: JsxComponentDescriptor;
1535
1550
  }
1536
1551
 
1537
- /* Excluded from this release type: jsxIsAvailable$ */
1552
+ /**
1553
+ * This JSX plugin will fill this value.
1554
+ * @group JSX
1555
+ */
1556
+ export declare const jsxIsAvailable$: NodeRef<boolean>;
1538
1557
 
1539
1558
  /**
1540
1559
  * a plugin that adds support for JSX elements (MDX).
1541
1560
  * @group JSX
1542
1561
  */
1543
- export declare const jsxPlugin: (params?: {
1562
+ export declare const jsxPlugin: (params?: JsxPluginParams | undefined) => RealmPlugin;
1563
+
1564
+ declare type JsxPluginParams = {
1544
1565
  /**
1545
1566
  * A set of descriptors that document the JSX elements used in the document.
1546
1567
  */
1547
1568
  jsxComponentDescriptors: JsxComponentDescriptor[];
1548
- } | undefined) => RealmPlugin;
1569
+ /**
1570
+ * Wether or not to allow default React fragments <></> processing in MDX.
1571
+ */
1572
+ allowFragment?: boolean;
1573
+ };
1574
+
1575
+ declare type JsxProperties = Record<string, string | ExpressionValue>;
1549
1576
 
1550
1577
  /**
1551
1578
  * Defines the structure of a JSX component property.
@@ -1559,7 +1586,7 @@ export declare interface JsxPropertyDescriptor {
1559
1586
  /**
1560
1587
  * The type of the property
1561
1588
  */
1562
- type: 'string' | 'number';
1589
+ type: 'string' | 'number' | 'expression';
1563
1590
  /**
1564
1591
  * Wether the property is required
1565
1592
  */
@@ -2204,6 +2231,8 @@ export declare const quotePlugin: (params?: unknown) => RealmPlugin;
2204
2231
  */
2205
2232
  export declare const readOnly$: NodeRef<boolean>;
2206
2233
 
2234
+ /* Excluded from this release type: readOnlyDiff$ */
2235
+
2207
2236
  /**
2208
2237
  * A plugin for the editor.
2209
2238
  * @group Core
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import { ADMONITION_TYPES, AdmonitionDirectiveDescriptor } from "./directive-edi
24
24
  import { GenericDirectiveEditor } from "./directive-editors/GenericDirectiveEditor.js";
25
25
  import { applyLinkChanges$, cancelLinkEdit$, linkAutocompleteSuggestions$, linkDialogPlugin, linkDialogState$, onClickLinkCallback$, onWindowChange$, openLinkEditDialog$, removeLink$, switchFromPreviewToLinkEdit$, updateLink$ } from "./plugins/link-dialog/index.js";
26
26
  import { toolbarContents$, toolbarPlugin } from "./plugins/toolbar/index.js";
27
- import { cmExtensions$, diffMarkdown$, diffSourcePlugin } from "./plugins/diff-source/index.js";
27
+ import { cmExtensions$, diffMarkdown$, diffSourcePlugin, readOnlyDiff$ } from "./plugins/diff-source/index.js";
28
28
  import { markdownShortcutPlugin } from "./plugins/markdown-shortcut/index.js";
29
29
  import { BlockTypeSelect } from "./plugins/toolbar/components/BlockTypeSelect.js";
30
30
  import { BoldItalicUnderlineToggles } from "./plugins/toolbar/components/BoldItalicUnderlineToggles.js";
@@ -260,6 +260,7 @@ export {
260
260
  prop,
261
261
  quotePlugin,
262
262
  readOnly$,
263
+ readOnlyDiff$,
263
264
  realmPlugin,
264
265
  removeFrontmatter$,
265
266
  removeLink$,
@@ -2,48 +2,67 @@ import React__default from "react";
2
2
  import { useMdastNodeUpdater, NestedLexicalEditor } from "../plugins/core/NestedLexicalEditor.js";
3
3
  import { PropertyPopover } from "../plugins/core/PropertyPopover.js";
4
4
  import styles from "../styles/ui.module.css.js";
5
+ const isExpressionValue = (value) => {
6
+ if (typeof value === "object" && value !== null && "type" in value && value.type === "mdxJsxAttributeValueExpression" && "value" in value && typeof value.value === "string") {
7
+ return true;
8
+ }
9
+ return false;
10
+ };
11
+ const isStringValue = (value) => typeof value === "string";
12
+ const isMdxJsxAttribute = (value) => {
13
+ if (value.type === "mdxJsxAttribute" && typeof value.name === "string") {
14
+ return true;
15
+ }
16
+ return false;
17
+ };
5
18
  const GenericJsxEditor = ({ mdastNode, descriptor }) => {
6
19
  const updateMdastNode = useMdastNodeUpdater();
7
- const properties = React__default.useMemo(() => {
8
- return descriptor.props.reduce(
9
- (acc, descriptor2) => {
10
- const attribute = mdastNode.attributes.find((attr) => attr.name === descriptor2.name);
11
- if (attribute) {
12
- acc[descriptor2.name] = attribute.value;
13
- } else {
14
- acc[descriptor2.name] = "";
20
+ const properties = React__default.useMemo(
21
+ () => descriptor.props.reduce((acc, { name }) => {
22
+ const attribute = mdastNode.attributes.find((attr) => isMdxJsxAttribute(attr) ? attr.name === name : false);
23
+ if (attribute) {
24
+ if (isExpressionValue(attribute.value)) {
25
+ acc[name] = attribute.value.value;
26
+ return acc;
15
27
  }
16
- return acc;
17
- },
18
- {}
19
- );
20
- }, [mdastNode, descriptor]);
28
+ if (isStringValue(attribute.value)) {
29
+ acc[name] = attribute.value;
30
+ return acc;
31
+ }
32
+ }
33
+ acc[name] = "";
34
+ return acc;
35
+ }, {}),
36
+ [mdastNode, descriptor]
37
+ );
21
38
  const onChange = React__default.useCallback(
22
39
  (values) => {
23
- const newAttributes = mdastNode.attributes.slice();
24
- Object.entries(values).forEach(([key, value]) => {
25
- const attributeToUpdate = newAttributes.find((attr) => attr.name === key);
40
+ const updatedAttributes = Object.entries(values).reduce((acc, [name, value]) => {
26
41
  if (value === "") {
27
- if (attributeToUpdate) {
28
- newAttributes.splice(newAttributes.indexOf(attributeToUpdate), 1);
29
- }
30
- } else {
31
- if (attributeToUpdate) {
32
- attributeToUpdate.value = value;
33
- } else {
34
- newAttributes.push({
35
- type: "mdxJsxAttribute",
36
- name: key,
37
- value
38
- });
39
- }
42
+ return acc;
40
43
  }
41
- });
42
- updateMdastNode({ attributes: newAttributes });
44
+ const property = descriptor.props.find((prop) => prop.name === name);
45
+ if ((property == null ? void 0 : property.type) === "expression") {
46
+ acc.push({
47
+ type: "mdxJsxAttribute",
48
+ name,
49
+ value: { type: "mdxJsxAttributeValueExpression", value }
50
+ });
51
+ return acc;
52
+ }
53
+ acc.push({
54
+ type: "mdxJsxAttribute",
55
+ name,
56
+ value
57
+ });
58
+ return acc;
59
+ }, []);
60
+ updateMdastNode({ attributes: updatedAttributes });
43
61
  },
44
- [mdastNode, updateMdastNode]
62
+ [mdastNode, updateMdastNode, descriptor]
45
63
  );
46
- return /* @__PURE__ */ React__default.createElement("div", { className: descriptor.kind === "text" ? styles.inlineEditor : styles.blockEditor }, descriptor.props.length == 0 && descriptor.hasChildren && descriptor.kind === "flow" ? /* @__PURE__ */ React__default.createElement("span", { className: styles.genericComponentName }, mdastNode.name) : null, descriptor.props.length > 0 ? /* @__PURE__ */ React__default.createElement(PropertyPopover, { properties, title: mdastNode.name || "", onChange }) : null, descriptor.hasChildren ? /* @__PURE__ */ React__default.createElement(
64
+ const shouldRenderComponentName = descriptor.props.length == 0 && descriptor.hasChildren && descriptor.kind === "flow";
65
+ return /* @__PURE__ */ React__default.createElement("div", { className: descriptor.kind === "text" ? styles.inlineEditor : styles.blockEditor }, shouldRenderComponentName ? /* @__PURE__ */ React__default.createElement("span", { className: styles.genericComponentName }, mdastNode.name ?? "Fragment") : null, descriptor.props.length > 0 ? /* @__PURE__ */ React__default.createElement(PropertyPopover, { properties, title: mdastNode.name ?? "", onChange }) : null, descriptor.hasChildren ? /* @__PURE__ */ React__default.createElement(
47
66
  NestedLexicalEditor,
48
67
  {
49
68
  block: descriptor.kind === "flow",
@@ -1,6 +1,6 @@
1
1
  import React__default from "react";
2
- import { diffMarkdown$, cmExtensions$ } from "./index.js";
3
- import { markdown$, markdownSourceEditorValue$, onBlur$ } from "../core/index.js";
2
+ import { diffMarkdown$, readOnlyDiff$, cmExtensions$ } from "./index.js";
3
+ import { markdown$, readOnly$, markdownSourceEditorValue$, onBlur$ } from "../core/index.js";
4
4
  import { MergeView } from "@codemirror/merge";
5
5
  import { EditorState } from "@codemirror/state";
6
6
  import { EditorView } from "@codemirror/view";
@@ -13,7 +13,7 @@ function setContent(view, content) {
13
13
  }
14
14
  const DiffViewer = () => {
15
15
  const realm = useRealm();
16
- const [newMarkdown, oldMarkdown] = useCellValues(markdown$, diffMarkdown$);
16
+ const [newMarkdown, oldMarkdown, readOnly, readOnlyDiff] = useCellValues(markdown$, diffMarkdown$, readOnly$, readOnlyDiff$);
17
17
  const onUpdate = usePublisher(markdownSourceEditorValue$);
18
18
  const elRef = React__default.useRef(null);
19
19
  const cmMergeViewRef = React__default.useRef(null);
@@ -32,16 +32,23 @@ const DiffViewer = () => {
32
32
  });
33
33
  }, [realm]);
34
34
  React__default.useEffect(() => {
35
- cmMergeViewRef.current = new MergeView({
35
+ const isReadOnly = readOnly || readOnlyDiff;
36
+ const revertParams = isReadOnly ? {
37
+ renderRevertControl: void 0,
38
+ revertControls: void 0
39
+ } : {
36
40
  renderRevertControl: () => {
37
41
  const el = document.createElement("button");
38
42
  el.classList.add("cm-merge-revert");
39
43
  el.appendChild(document.createTextNode("⮕"));
40
44
  return el;
41
45
  },
46
+ revertControls: "a-to-b"
47
+ };
48
+ cmMergeViewRef.current = new MergeView({
49
+ ...revertParams,
42
50
  parent: elRef.current,
43
51
  orientation: "a-b",
44
- revertControls: "a-to-b",
45
52
  gutter: true,
46
53
  a: {
47
54
  doc: oldMarkdown,
@@ -52,6 +59,7 @@ const DiffViewer = () => {
52
59
  extensions: [
53
60
  ...cmExtensions,
54
61
  ...COMMON_STATE_CONFIG_EXTENSIONS,
62
+ EditorState.readOnly.of(isReadOnly),
55
63
  EditorView.updateListener.of(({ state }) => {
56
64
  const md = state.doc.toString();
57
65
  onUpdate(md);
@@ -4,21 +4,24 @@ import { Cell } from "@mdxeditor/gurx";
4
4
  import { realmPlugin } from "../../RealmWithPlugins.js";
5
5
  const diffMarkdown$ = Cell("");
6
6
  const cmExtensions$ = Cell([]);
7
+ const readOnlyDiff$ = Cell(false);
7
8
  const diffSourcePlugin = realmPlugin({
8
9
  update: (r, params) => {
9
- r.pub(diffMarkdown$, (params == null ? void 0 : params.diffMarkdown) || "");
10
+ r.pub(diffMarkdown$, (params == null ? void 0 : params.diffMarkdown) ?? "");
10
11
  },
11
12
  init(r, params) {
12
13
  r.pubIn({
13
- [diffMarkdown$]: (params == null ? void 0 : params.diffMarkdown) || "",
14
- [cmExtensions$]: (params == null ? void 0 : params.codeMirrorExtensions) || [],
14
+ [diffMarkdown$]: (params == null ? void 0 : params.diffMarkdown) ?? "",
15
+ [cmExtensions$]: (params == null ? void 0 : params.codeMirrorExtensions) ?? [],
15
16
  [addEditorWrapper$]: DiffSourceWrapper,
16
- [viewMode$]: (params == null ? void 0 : params.viewMode) || "rich-text"
17
+ [readOnlyDiff$]: (params == null ? void 0 : params.readOnlyDiff) ?? false,
18
+ [viewMode$]: (params == null ? void 0 : params.viewMode) ?? "rich-text"
17
19
  });
18
20
  }
19
21
  });
20
22
  export {
21
23
  cmExtensions$,
22
24
  diffMarkdown$,
23
- diffSourcePlugin
25
+ diffSourcePlugin,
26
+ readOnlyDiff$
24
27
  };
@@ -10,16 +10,23 @@ import { realmPlugin } from "../../RealmWithPlugins.js";
10
10
  import { MdastMdxTextExpressionVisitor } from "./MdastMdxTextExpressionVisitor.js";
11
11
  import { LexicalMdxTextExpressionNode } from "./LexicalMdxTextExpressionNode.js";
12
12
  import { LexicalMdxTextExpressionVisitor } from "./LexicalMdxTextExpressionVisitor.js";
13
+ import { GenericJsxEditor } from "../../jsx-editors/GenericJsxEditor.js";
13
14
  function isMdastJsxNode(node) {
14
15
  return node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
15
16
  }
16
- function toMdastJsxAttributes(attributes) {
17
- return Object.entries(attributes).map(([name, value]) => ({
17
+ const isExpressionValue = (value) => {
18
+ if (typeof value === "object" && value !== null && "type" in value && value.type === "expression" && "value" in value && typeof value.value === "string") {
19
+ return true;
20
+ }
21
+ return false;
22
+ };
23
+ const toMdastJsxAttributes = (attributes) => Object.entries(attributes).map(
24
+ ([name, value]) => ({
18
25
  type: "mdxJsxAttribute",
19
26
  name,
20
- value
21
- }));
22
- }
27
+ value: isExpressionValue(value) ? { type: "mdxJsxAttributeValueExpression", value: value.value } : value
28
+ })
29
+ );
23
30
  const insertJsx$ = Signal((r) => {
24
31
  r.link(
25
32
  r.pipe(
@@ -48,6 +55,22 @@ const insertJsx$ = Signal((r) => {
48
55
  insertDecoratorNode$
49
56
  );
50
57
  });
58
+ const fragmentDescriptor = {
59
+ name: null,
60
+ kind: "flow",
61
+ props: [],
62
+ hasChildren: true,
63
+ Editor: GenericJsxEditor
64
+ };
65
+ const getDescriptors = (params) => {
66
+ if (params) {
67
+ if (params.allowFragment ?? true) {
68
+ return [fragmentDescriptor, ...params.jsxComponentDescriptors];
69
+ }
70
+ return params.jsxComponentDescriptors;
71
+ }
72
+ return [fragmentDescriptor];
73
+ };
51
74
  const jsxPlugin = realmPlugin({
52
75
  init: (realm, params) => {
53
76
  realm.pubIn({
@@ -60,11 +83,11 @@ const jsxPlugin = realmPlugin({
60
83
  [addLexicalNode$]: [LexicalJsxNode, LexicalMdxTextExpressionNode],
61
84
  [addExportVisitor$]: [LexicalJsxVisitor, LexicalMdxTextExpressionVisitor],
62
85
  [addToMarkdownExtension$]: mdxToMarkdown(),
63
- [jsxComponentDescriptors$]: (params == null ? void 0 : params.jsxComponentDescriptors) || []
86
+ [jsxComponentDescriptors$]: getDescriptors(params)
64
87
  });
65
88
  },
66
89
  update(realm, params) {
67
- realm.pub(jsxComponentDescriptors$, (params == null ? void 0 : params.jsxComponentDescriptors) || []);
90
+ realm.pub(jsxComponentDescriptors$, getDescriptors(params));
68
91
  }
69
92
  });
70
93
  export {
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "*.css"
12
12
  ],
13
13
  "type": "module",
14
- "version": "2.10.0",
14
+ "version": "2.12.0",
15
15
  "description": "React component for rich text markdown editing",
16
16
  "scripts": {
17
17
  "build": "vite build",