remons-markdown-editor 1.0.0-beta.7 → 1.0.0-beta.9

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
2
- import { Button, Dropdown, Modal, Splitter, Tooltip, message } from "antd";
2
+ import { Button, ColorPicker, DatePicker, Dropdown, Form, Input, InputNumber, Modal, Rate, Select, Slider, Splitter, Switch, Tooltip, message } from "antd";
3
3
  import { EditorView, basicSetup } from "codemirror";
4
4
  import { EditorState, Facet } from "@codemirror/state";
5
5
  import { Decoration, EditorView as EditorView$1, ViewPlugin, WidgetType, keymap } from "@codemirror/view";
@@ -552,15 +552,16 @@ var Preview = forwardRef(({ content, previewOptions }, ref) => {
552
552
  Preview.displayName = "Preview";
553
553
  //#endregion
554
554
  //#region src/components/Panel/SplitPanels.tsx
555
+ var { Panel } = Splitter;
555
556
  function SplitPanels({ leftPanel, rightPanel }) {
556
557
  return /* @__PURE__ */ jsxs(Splitter, {
557
558
  className: "split-panels",
558
- children: [/* @__PURE__ */ jsx(Splitter.Panel, {
559
+ children: [/* @__PURE__ */ jsx(Panel, {
559
560
  defaultSize: "50%",
560
561
  min: "20%",
561
562
  max: "80%",
562
563
  children: leftPanel
563
- }), /* @__PURE__ */ jsx(Splitter.Panel, { children: rightPanel })]
564
+ }), /* @__PURE__ */ jsx(Panel, { children: rightPanel })]
564
565
  });
565
566
  }
566
567
  //#endregion
@@ -1041,12 +1042,59 @@ function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems
1041
1042
  //#endregion
1042
1043
  //#region src/components/Dialog/EditDialog.tsx
1043
1044
  /**
1045
+ * 组件类型到 antd 表单组件的映射
1046
+ */
1047
+ var FormComponents = {
1048
+ input: Input,
1049
+ textarea: Input.TextArea,
1050
+ number: InputNumber,
1051
+ select: Select,
1052
+ switch: Switch,
1053
+ slider: Slider,
1054
+ rate: Rate,
1055
+ color: ColorPicker,
1056
+ date: DatePicker,
1057
+ dateRange: DatePicker.RangePicker
1058
+ };
1059
+ /**
1060
+ * 渲染对应类型的 antd 表单组件
1061
+ */
1062
+ function renderFormItemComponent(field) {
1063
+ const props = field.componentProps || {};
1064
+ const Component = field.componentType ? FormComponents[field.componentType] : Input;
1065
+ return /* @__PURE__ */ jsx(Component, { ...props });
1066
+ }
1067
+ /**
1068
+ * 根据 fields 自动生成 Form.Item 列表
1069
+ */
1070
+ function renderAutoForm(form, fields) {
1071
+ if (!fields || fields.length === 0) return null;
1072
+ return /* @__PURE__ */ jsx(Form, {
1073
+ form,
1074
+ layout: "vertical",
1075
+ children: fields.map((field) => {
1076
+ if (!field.componentType) return null;
1077
+ const formItemProps = {
1078
+ name: field.key,
1079
+ label: field.name || field.key,
1080
+ valuePropName: field.componentType === "switch" ? "checked" : void 0,
1081
+ ...field.componentProps
1082
+ };
1083
+ return /* @__PURE__ */ jsx(Form.Item, {
1084
+ ...formItemProps,
1085
+ children: renderFormItemComponent(field)
1086
+ }, field.key);
1087
+ })
1088
+ });
1089
+ }
1090
+ /**
1044
1091
  * 属性编辑弹窗组件
1045
1092
  * 根据组件 schema 的 renderDialog 函数渲染弹窗内容
1046
1093
  */
1047
1094
  function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
1048
1095
  const schema = componentRegistry.get(typeName);
1049
1096
  const [formProps, setFormProps] = useState({});
1097
+ const [form] = Form.useForm();
1050
1098
  const mergedProps = useMemo(() => {
1051
1099
  if (!schema) return currentProps;
1052
1100
  const defaults = {};
@@ -1056,24 +1104,52 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
1056
1104
  ...currentProps
1057
1105
  };
1058
1106
  }, [schema, currentProps]);
1107
+ useEffect(() => {
1108
+ if (visible) {
1109
+ form.setFieldsValue(mergedProps);
1110
+ setFormProps({});
1111
+ }
1112
+ }, [
1113
+ visible,
1114
+ mergedProps,
1115
+ form
1116
+ ]);
1059
1117
  const handleDialogChange = (key, value) => {
1060
1118
  setFormProps((prev) => ({
1061
1119
  ...prev,
1062
1120
  [key]: value
1063
1121
  }));
1064
1122
  };
1065
- const handleOk = () => {
1066
- onSave(visible ? {
1123
+ const handleOk = async () => {
1124
+ let finalProps = visible ? {
1067
1125
  ...mergedProps,
1068
1126
  ...formProps
1069
- } : mergedProps);
1070
- setFormProps({});
1127
+ } : mergedProps;
1128
+ try {
1129
+ const formValues = await form.validateFields();
1130
+ finalProps = {
1131
+ ...finalProps,
1132
+ ...formValues
1133
+ };
1134
+ } catch {}
1135
+ onSave(finalProps);
1071
1136
  };
1072
1137
  const handleClose = () => {
1073
1138
  setFormProps({});
1074
1139
  onClose();
1075
1140
  };
1076
- if (!schema || !schema.renderDialog) return null;
1141
+ if (!schema) return null;
1142
+ const context = {
1143
+ props: mergedProps,
1144
+ form,
1145
+ onChange: handleDialogChange,
1146
+ onSave
1147
+ };
1148
+ const renderDialogContent = () => {
1149
+ if (schema.renderDialog) return schema.renderDialog(context);
1150
+ if (schema.fields?.some((f) => f.componentType) && schema.fields) return renderAutoForm(form, schema.fields);
1151
+ return null;
1152
+ };
1077
1153
  return /* @__PURE__ */ jsx(Modal, {
1078
1154
  title: `${schema.label} 属性编辑`,
1079
1155
  open: visible,
@@ -1081,10 +1157,7 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
1081
1157
  onCancel: handleClose,
1082
1158
  okText: "保存",
1083
1159
  cancelText: "取消",
1084
- children: schema.renderDialog(visible ? {
1085
- ...mergedProps,
1086
- ...formProps
1087
- } : mergedProps, handleDialogChange)
1160
+ children: renderDialogContent()
1088
1161
  });
1089
1162
  }
1090
1163
  //#endregion
@@ -1194,7 +1267,7 @@ function useScrollSync(sourceRef, targetRef) {
1194
1267
  }
1195
1268
  //#endregion
1196
1269
  //#region src/MarkdownEditor.tsx
1197
- var MarkdownEditor_default = forwardRef(function MarkdownEditor({ defaultValue = "", value, onChange, showPreview = true, fullscreen: fullscreenProp = false, previewOptions, uploadConfig }, ref) {
1270
+ var MarkdownEditor_default = forwardRef(function MarkdownEditor({ defaultValue = "", value, onChange, showPreview = true, fullscreen: fullscreenProp = true, previewOptions, uploadConfig }, ref) {
1198
1271
  const [content, setContent] = useState(value ?? defaultValue);
1199
1272
  const [editorView, setEditorView] = useState(null);
1200
1273
  const scrollDOMRef = useRef(null);
@@ -1213,14 +1286,19 @@ var MarkdownEditor_default = forwardRef(function MarkdownEditor({ defaultValue =
1213
1286
  onChange?.(newContent);
1214
1287
  }, [onChange]);
1215
1288
  useImperativeHandle(ref, () => ({ getContent: () => content }), [content]);
1216
- const extraToolbarItems = componentRegistry.getAll().map((schema) => {
1289
+ const extraToolbarItems = componentRegistry.getAll().flatMap((schema) => {
1290
+ if (schema.wrapTags) return {
1291
+ id: `wrap-${schema.name}`,
1292
+ label: schema.label,
1293
+ icon: () => schema.icon ?? /* @__PURE__ */ jsx(ReadOutlined, {}),
1294
+ wrapTags: schema.wrapTags
1295
+ };
1217
1296
  const defaultProps = {};
1218
1297
  for (const field of schema?.fields ?? []) defaultProps[field.key] = field.defaultValue ?? "";
1219
- const iconNode = schema.icon ?? /* @__PURE__ */ jsx(ReadOutlined, {});
1220
1298
  return {
1221
1299
  id: `container-${schema.name}`,
1222
1300
  label: schema.label,
1223
- icon: () => iconNode,
1301
+ icon: () => schema.icon ?? /* @__PURE__ */ jsx(ReadOutlined, {}),
1224
1302
  handler: (view, _state) => insertContainer(view, schema.name, defaultProps)
1225
1303
  };
1226
1304
  });
@@ -1302,15 +1380,36 @@ var MarkdownEditor_default = forwardRef(function MarkdownEditor({ defaultValue =
1302
1380
  * 2. 标签包裹模式:name + wrapTags
1303
1381
  * 插入简单的标签包裹文本,如 <plugin-container>...</plugin-container>
1304
1382
  *
1305
- * @example 容器模式
1383
+ * @example 容器模式 - 使用 fields 自动生成表单(最简)
1384
+ * ```tsx
1385
+ * const schema: ComponentSchema = {
1386
+ * name: 'alert',
1387
+ * label: '警告框',
1388
+ * icon: <AlertOutlined />,
1389
+ * fields: [
1390
+ * { key: 'type', name: '类型', componentType: 'select',
1391
+ * componentProps: { options: [{ value: 'price', label: '价格' }, { value: 'info', label: '信息' }] } },
1392
+ * { key: 'content', name: '内容', componentType: 'textarea',
1393
+ * componentProps: { rows: 3 } },
1394
+ * { key: 'enabled', name: '启用', componentType: 'switch' },
1395
+ * ],
1396
+ * }
1397
+ * // 支持的 componentType: 'input' | 'textarea' | 'number' | 'select' | 'switch' | 'slider' | 'rate' | 'color' | 'date' | 'dateRange'
1398
+ * ```
1399
+ *
1400
+ * @example 容器模式 - 使用 Form.Item 自动绑定(推荐)
1306
1401
  * ```tsx
1307
1402
  * const schema: ComponentSchema = {
1308
1403
  * name: 'alert',
1309
1404
  * label: '警告框',
1310
1405
  * icon: <AlertOutlined />,
1311
1406
  * fields: [{ key: 'level', defaultValue: 'info' }],
1312
- * renderDialog: (props, onChange) => (
1313
- * <Input value={props.level} onChange={e => onChange('level', e.target.value)} />
1407
+ * renderDialog: ({ form }) => (
1408
+ * <Form form={form} layout="vertical">
1409
+ * <Form.Item name="level" label="级别">
1410
+ * <Input />
1411
+ * </Form.Item>
1412
+ * </Form>
1314
1413
  * ),
1315
1414
  * }
1316
1415
  *
@@ -1320,6 +1419,35 @@ var MarkdownEditor_default = forwardRef(function MarkdownEditor({ defaultValue =
1320
1419
  * }
1321
1420
  * ```
1322
1421
  *
1422
+ * @example 容器模式 - 手动控制
1423
+ * ```tsx
1424
+ * const schema: ComponentSchema = {
1425
+ * name: 'alert',
1426
+ * label: '警告框',
1427
+ * icon: <AlertOutlined />,
1428
+ * fields: [{ key: 'level', defaultValue: 'info' }],
1429
+ * renderDialog: ({ props, onChange }) => (
1430
+ * <Input value={props.level} onChange={e => onChange('level', e.target.value)} />
1431
+ * ),
1432
+ * }
1433
+ * ```
1434
+ *
1435
+ * @example 容器模式 - 完全自定义弹窗
1436
+ * ```tsx
1437
+ * const schema: ComponentSchema = {
1438
+ * name: 'alert',
1439
+ * label: '警告框',
1440
+ * icon: <AlertOutlined />,
1441
+ * fields: [{ key: 'level', defaultValue: 'info' }],
1442
+ * renderDialog: ({ props, onSave }) => (
1443
+ * <MyCustomEditor
1444
+ * value={props.level}
1445
+ * onSave={({ level }) => onSave({ level })}
1446
+ * />
1447
+ * ),
1448
+ * }
1449
+ * ```
1450
+ *
1323
1451
  * @example 标签包裹模式
1324
1452
  * ```tsx
1325
1453
  * function MyPage() {