@mdxeditor/editor 2.11.0 → 2.12.1

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
@@ -1028,6 +1028,11 @@ export declare type EditorSubscription = (activeEditor: LexicalEditor) => () =>
1028
1028
 
1029
1029
  /* Excluded from this release type: exportVisitors$ */
1030
1030
 
1031
+ declare type ExpressionValue = {
1032
+ type: 'expression';
1033
+ value: string;
1034
+ };
1035
+
1031
1036
  /**
1032
1037
  * A default option to be displayed in the {@link ConditionalContents} component if none of the other options match.
1033
1038
  * @group Toolbar Primitives
@@ -1384,12 +1389,12 @@ export declare interface InsertImageParameters {
1384
1389
  export declare const insertJsx$: NodeRef<{
1385
1390
  kind: 'text';
1386
1391
  name: string;
1387
- props: Record<string, string>;
1392
+ props: JsxProperties;
1388
1393
  children?: Mdast.PhrasingContent[] | undefined;
1389
1394
  } | {
1390
1395
  kind: 'flow';
1391
1396
  name: string;
1392
- props: Record<string, string>;
1397
+ props: JsxProperties;
1393
1398
  children?: (Mdast.BlockContent | Mdast.DefinitionContent)[] | undefined;
1394
1399
  }>;
1395
1400
 
@@ -1496,9 +1501,10 @@ export declare function joinProc(...procs: Array<() => unknown>): () => void;
1496
1501
  */
1497
1502
  export declare interface JsxComponentDescriptor {
1498
1503
  /**
1499
- * The tag name
1504
+ * The tag name. For example: 'div', 'span', 'MyComponent'.
1505
+ * Note: For fragments, use null.
1500
1506
  */
1501
- name: string;
1507
+ name: string | null;
1502
1508
  /**
1503
1509
  * Wether the component is a flow or text component (inline or block)
1504
1510
  */
@@ -1526,7 +1532,11 @@ export declare interface JsxComponentDescriptor {
1526
1532
  Editor: React_2.ComponentType<JsxEditorProps>;
1527
1533
  }
1528
1534
 
1529
- /* 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[]>;
1530
1540
 
1531
1541
  /**
1532
1542
  * The properties passed to a custom JSX Editor component.
@@ -1539,18 +1549,30 @@ export declare interface JsxEditorProps {
1539
1549
  descriptor: JsxComponentDescriptor;
1540
1550
  }
1541
1551
 
1542
- /* 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>;
1543
1557
 
1544
1558
  /**
1545
1559
  * a plugin that adds support for JSX elements (MDX).
1546
1560
  * @group JSX
1547
1561
  */
1548
- export declare const jsxPlugin: (params?: {
1562
+ export declare const jsxPlugin: (params?: JsxPluginParams | undefined) => RealmPlugin;
1563
+
1564
+ declare type JsxPluginParams = {
1549
1565
  /**
1550
1566
  * A set of descriptors that document the JSX elements used in the document.
1551
1567
  */
1552
1568
  jsxComponentDescriptors: JsxComponentDescriptor[];
1553
- } | 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>;
1554
1576
 
1555
1577
  /**
1556
1578
  * Defines the structure of a JSX component property.
@@ -1564,7 +1586,7 @@ export declare interface JsxPropertyDescriptor {
1564
1586
  /**
1565
1587
  * The type of the property
1566
1588
  */
1567
- type: 'string' | 'number';
1589
+ type: 'string' | 'number' | 'expression';
1568
1590
  /**
1569
1591
  * Wether the property is required
1570
1592
  */
@@ -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",
@@ -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 {
@@ -12,7 +12,7 @@ const BoldItalicUnderlineToggles = () => {
12
12
  const underlineIsOn = (currentFormat & IS_UNDERLINE) !== 0;
13
13
  const boldTitle = boldIsOn ? t("toolbar.removeBold", "Remove bold") : t("toolbar.bold", "Bold");
14
14
  const italicTitle = italicIsOn ? t("toolbar.removeItalic", "Remove italic") : t("toolbar.italic", "Italic");
15
- const underlineTitle = underlineIsOn ? t("toolbar.underline", "Remove underline") : t("toolbar.removeUnderline", "Underline");
15
+ const underlineTitle = underlineIsOn ? t("toolbar.removeUnderline", "Remove underline") : t("toolbar.underline", "Underline");
16
16
  return /* @__PURE__ */ React__default.createElement(
17
17
  MultipleChoiceToggleGroup,
18
18
  {
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "*.css"
12
12
  ],
13
13
  "type": "module",
14
- "version": "2.11.0",
14
+ "version": "2.12.1",
15
15
  "description": "React component for rich text markdown editing",
16
16
  "scripts": {
17
17
  "build": "vite build",