remons-markdown-editor 2.0.0-beta.0 → 2.0.0-beta.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/components/Dialog/EditDialog.d.ts +3 -1
- package/dist/components/Editor/containerWidget.d.ts +12 -1
- package/dist/index.cjs +121 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +122 -45
- package/dist/index.js.map +1 -1
- package/dist/utils/parseContainer.d.ts +6 -0
- package/dist/utils/writeContainer.d.ts +2 -1
- package/package.json +3 -3
|
@@ -9,6 +9,8 @@ interface EditDialogProps {
|
|
|
9
9
|
typeName: string;
|
|
10
10
|
/** 当前属性值 */
|
|
11
11
|
currentProps: ContainerProps;
|
|
12
|
+
/** 每次打开递增的序号:作为 Form 的 key,切换容器时触发重挂载重新取 initialValues */
|
|
13
|
+
initKey: number;
|
|
12
14
|
/** 保存回调 */
|
|
13
15
|
onSave: (props: ContainerProps) => void;
|
|
14
16
|
/** 关闭回调 */
|
|
@@ -18,5 +20,5 @@ interface EditDialogProps {
|
|
|
18
20
|
* 属性编辑弹窗组件
|
|
19
21
|
* 根据组件 schema 的 renderDialog 函数渲染弹窗内容
|
|
20
22
|
*/
|
|
21
|
-
export default function EditDialog({ visible, typeName, currentProps, onSave, onClose }: EditDialogProps): import('react').JSX.Element | null;
|
|
23
|
+
export default function EditDialog({ visible, typeName, currentProps, initKey, onSave, onClose }: EditDialogProps): import('react').JSX.Element | null;
|
|
22
24
|
export {};
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { ViewPlugin, EditorView, DecorationSet } from '@codemirror/view';
|
|
2
|
-
import { EditorState, Facet } from '@codemirror/state';
|
|
2
|
+
import { EditorState, Facet, Transaction } from '@codemirror/state';
|
|
3
3
|
import { ContainerBlock } from '../../utils/parseContainer';
|
|
4
|
+
/**
|
|
5
|
+
* 唤醒容器装饰重建的状态 effect(不改变文档)。
|
|
6
|
+
* 编辑按钮是否展示取决于容器类型是否已注册,而宿主常在编辑器挂载之后才
|
|
7
|
+
* 通过 useRegisterToolbar 异步注册 schema;注册不是 CodeMirror 事务,默认不会触发
|
|
8
|
+
* ViewPlugin.update,导致初始化时烘焙的 registered=false 无法刷新(需手动改一个字才出现)。
|
|
9
|
+
* 宿主在注册中心版本变化时 dispatch 本 effect,驱动插件重新求值 registered。
|
|
10
|
+
*/
|
|
11
|
+
export declare const refreshContainers: import('@codemirror/state').StateEffectType<null>;
|
|
4
12
|
/**
|
|
5
13
|
* 编辑容器属性的回调函数类型
|
|
6
14
|
* @param view 当前编辑器实例
|
|
@@ -18,8 +26,11 @@ export declare const containerEditCallback: Facet<OnEditContainer, OnEditContain
|
|
|
18
26
|
*/
|
|
19
27
|
export declare const containerWidgetPlugin: ViewPlugin<{
|
|
20
28
|
decorations: DecorationSet;
|
|
29
|
+
/** 上次构建装饰时的注册中心版本,用于感知异步注册(不能标 private,否则导出匿名类的 dts 报 TS4094) */
|
|
30
|
+
registryVersion: number;
|
|
21
31
|
update(update: {
|
|
22
32
|
docChanged: boolean;
|
|
23
33
|
state: EditorState;
|
|
34
|
+
transactions: readonly Transaction[];
|
|
24
35
|
}): void;
|
|
25
36
|
}, undefined>;
|
package/dist/index.cjs
CHANGED
|
@@ -1278,8 +1278,25 @@ function parseContainerProps(line) {
|
|
|
1278
1278
|
}
|
|
1279
1279
|
}
|
|
1280
1280
|
/**
|
|
1281
|
+
* 解析行首的引用(blockquote)嵌套前缀。
|
|
1282
|
+
* markdown-it 解析引用内部内容时会剥掉一层 "> ",因此 "> :::badge" 在渲染侧
|
|
1283
|
+
* 等同于 ":::badge";编辑器侧需同样识别,否则嵌套引用的容器匹配不到标签。
|
|
1284
|
+
* 返回 [前缀文本(含 "> " 及尾随空格), 去掉前缀后的内容],无前缀时返回 ['', 原文本]。
|
|
1285
|
+
*/
|
|
1286
|
+
function splitQuotePrefix(line) {
|
|
1287
|
+
const m = line.match(/^((?:>\s*)+)(\S.*)$/);
|
|
1288
|
+
if (!m) return ["", line];
|
|
1289
|
+
return [m[1], m[2]];
|
|
1290
|
+
}
|
|
1291
|
+
/** 引用嵌套深度("> > x" 为 2,无前缀为 0) */
|
|
1292
|
+
function quoteDepth(prefix) {
|
|
1293
|
+
return (prefix.match(/>/g) ?? []).length;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1281
1296
|
* 在编辑器文档中查找容器块。
|
|
1282
1297
|
* 单次遍历 + 预累计行偏移,复杂度 O(行数)。
|
|
1298
|
+
* 支持整体嵌套在引用中的容器:头行、属性行、闭合行需具有相同的 "> " 前缀深度,
|
|
1299
|
+
* 避免跨引用层级错误配对。闭合 ::: 改为按栈配对,嵌套容器不会被内层闭合误截断。
|
|
1283
1300
|
*/
|
|
1284
1301
|
function findContainers(docText) {
|
|
1285
1302
|
const containers = [];
|
|
@@ -1290,34 +1307,53 @@ function findContainers(docText) {
|
|
|
1290
1307
|
offsets[i] = pos;
|
|
1291
1308
|
pos += lines[i].length + 1;
|
|
1292
1309
|
}
|
|
1310
|
+
const stack = [];
|
|
1293
1311
|
for (let i = 0; i < lines.length; i++) {
|
|
1294
|
-
const
|
|
1312
|
+
const [prefix, body] = splitQuotePrefix(lines[i]);
|
|
1313
|
+
const depth = quoteDepth(prefix);
|
|
1314
|
+
if (/^:::$/.test(body)) {
|
|
1315
|
+
let top = stack.length - 1;
|
|
1316
|
+
while (top >= 0 && stack[top].depth !== depth) top--;
|
|
1317
|
+
if (top >= 0) {
|
|
1318
|
+
stack[top].block.endPos = offsets[i];
|
|
1319
|
+
stack.length = top;
|
|
1320
|
+
}
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1323
|
+
const match = body.match(/^:::(\w+)$/);
|
|
1295
1324
|
if (!match) continue;
|
|
1296
1325
|
const typeName = match[1];
|
|
1297
1326
|
const headerPos = offsets[i];
|
|
1298
1327
|
let props = {};
|
|
1299
1328
|
let propsLineFrom = 0;
|
|
1300
1329
|
let propsLineTo = 0;
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1330
|
+
let propsQuotePrefix = "";
|
|
1331
|
+
const nextLine = lines[i + 1];
|
|
1332
|
+
if (nextLine) {
|
|
1333
|
+
const [nextPrefix, nextBody] = splitQuotePrefix(nextLine);
|
|
1334
|
+
if ((quoteDepth(nextPrefix) === depth || nextPrefix === "") && nextBody.trimStart().startsWith("{") && nextBody.trimEnd().endsWith("}")) {
|
|
1335
|
+
props = parseContainerProps(nextBody);
|
|
1336
|
+
propsLineFrom = offsets[i + 1];
|
|
1337
|
+
propsLineTo = propsLineFrom + nextLine.length;
|
|
1338
|
+
propsQuotePrefix = nextPrefix;
|
|
1339
|
+
i += 1;
|
|
1340
|
+
}
|
|
1312
1341
|
}
|
|
1313
|
-
|
|
1342
|
+
const block = {
|
|
1314
1343
|
startPos: headerPos,
|
|
1315
1344
|
typeName,
|
|
1316
1345
|
propsLineFrom,
|
|
1317
1346
|
propsLineTo,
|
|
1318
1347
|
props,
|
|
1319
|
-
endPos,
|
|
1320
|
-
registered: componentRegistry.has(typeName)
|
|
1348
|
+
endPos: 0,
|
|
1349
|
+
registered: componentRegistry.has(typeName),
|
|
1350
|
+
quotePrefix: prefix,
|
|
1351
|
+
propsQuotePrefix
|
|
1352
|
+
};
|
|
1353
|
+
containers.push(block);
|
|
1354
|
+
stack.push({
|
|
1355
|
+
block,
|
|
1356
|
+
depth
|
|
1321
1357
|
});
|
|
1322
1358
|
}
|
|
1323
1359
|
return containers;
|
|
@@ -1325,6 +1361,14 @@ function findContainers(docText) {
|
|
|
1325
1361
|
//#endregion
|
|
1326
1362
|
//#region src/components/Editor/containerWidget.ts
|
|
1327
1363
|
/**
|
|
1364
|
+
* 唤醒容器装饰重建的状态 effect(不改变文档)。
|
|
1365
|
+
* 编辑按钮是否展示取决于容器类型是否已注册,而宿主常在编辑器挂载之后才
|
|
1366
|
+
* 通过 useRegisterToolbar 异步注册 schema;注册不是 CodeMirror 事务,默认不会触发
|
|
1367
|
+
* ViewPlugin.update,导致初始化时烘焙的 registered=false 无法刷新(需手动改一个字才出现)。
|
|
1368
|
+
* 宿主在注册中心版本变化时 dispatch 本 effect,驱动插件重新求值 registered。
|
|
1369
|
+
*/
|
|
1370
|
+
var refreshContainers = _codemirror_state.StateEffect.define();
|
|
1371
|
+
/**
|
|
1328
1372
|
* 自定义 facet 用于传递编辑回调
|
|
1329
1373
|
*/
|
|
1330
1374
|
var containerEditCallback = _codemirror_state.Facet.define({ combine: (values) => values.length ? values[values.length - 1] : null });
|
|
@@ -1337,18 +1381,20 @@ var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
|
1337
1381
|
typeName;
|
|
1338
1382
|
containerIndex;
|
|
1339
1383
|
registered;
|
|
1340
|
-
|
|
1384
|
+
quotePrefix;
|
|
1385
|
+
constructor(typeName, containerIndex, registered, quotePrefix) {
|
|
1341
1386
|
super();
|
|
1342
1387
|
this.typeName = typeName;
|
|
1343
1388
|
this.containerIndex = containerIndex;
|
|
1344
1389
|
this.registered = registered;
|
|
1390
|
+
this.quotePrefix = quotePrefix;
|
|
1345
1391
|
}
|
|
1346
1392
|
toDOM() {
|
|
1347
1393
|
const container = document.createElement("span");
|
|
1348
1394
|
container.className = "container-widget-header";
|
|
1349
1395
|
const text = document.createElement("span");
|
|
1350
1396
|
text.className = "container-widget-text";
|
|
1351
|
-
text.textContent =
|
|
1397
|
+
text.textContent = `${this.quotePrefix}:::${this.typeName}`;
|
|
1352
1398
|
container.appendChild(text);
|
|
1353
1399
|
if (this.registered) {
|
|
1354
1400
|
const button = document.createElement("button");
|
|
@@ -1362,7 +1408,7 @@ var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
|
1362
1408
|
return container;
|
|
1363
1409
|
}
|
|
1364
1410
|
eq(other) {
|
|
1365
|
-
return this.typeName === other.typeName && this.containerIndex === other.containerIndex && this.registered === other.registered;
|
|
1411
|
+
return this.typeName === other.typeName && this.containerIndex === other.containerIndex && this.registered === other.registered && this.quotePrefix === other.quotePrefix;
|
|
1366
1412
|
}
|
|
1367
1413
|
ignoreEvent() {
|
|
1368
1414
|
return false;
|
|
@@ -1370,38 +1416,46 @@ var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
|
1370
1416
|
};
|
|
1371
1417
|
/**
|
|
1372
1418
|
* 只读的容器属性行 Widget(显示 { key: value, ... })
|
|
1419
|
+
* 嵌套在引用中时原始行带 "> " 前缀,展示时剔除,与头行 widget 风格一致
|
|
1373
1420
|
*/
|
|
1374
1421
|
var ContainerPropsWidget = class extends _codemirror_view.WidgetType {
|
|
1375
1422
|
propsText;
|
|
1376
|
-
|
|
1423
|
+
quotePrefix;
|
|
1424
|
+
constructor(propsText, quotePrefix) {
|
|
1377
1425
|
super();
|
|
1378
1426
|
this.propsText = propsText;
|
|
1427
|
+
this.quotePrefix = quotePrefix;
|
|
1379
1428
|
}
|
|
1380
1429
|
toDOM() {
|
|
1381
1430
|
const span = document.createElement("span");
|
|
1382
1431
|
span.className = "container-widget-props";
|
|
1383
|
-
span.textContent = this.propsText;
|
|
1432
|
+
span.textContent = this.propsText.startsWith(this.quotePrefix) ? this.propsText.slice(this.quotePrefix.length) : this.propsText;
|
|
1384
1433
|
return span;
|
|
1385
1434
|
}
|
|
1386
1435
|
eq(other) {
|
|
1387
|
-
return this.propsText === other.propsText;
|
|
1436
|
+
return this.propsText === other.propsText && this.quotePrefix === other.quotePrefix;
|
|
1388
1437
|
}
|
|
1389
1438
|
ignoreEvent() {
|
|
1390
1439
|
return false;
|
|
1391
1440
|
}
|
|
1392
1441
|
};
|
|
1393
1442
|
/**
|
|
1394
|
-
* 只读的容器结束行 Widget(显示
|
|
1443
|
+
* 只读的容器结束行 Widget(显示 :::,嵌套引用时保留 "> " 前缀)
|
|
1395
1444
|
*/
|
|
1396
1445
|
var ContainerCloseWidget = class extends _codemirror_view.WidgetType {
|
|
1446
|
+
text;
|
|
1447
|
+
constructor(text) {
|
|
1448
|
+
super();
|
|
1449
|
+
this.text = text;
|
|
1450
|
+
}
|
|
1397
1451
|
toDOM() {
|
|
1398
1452
|
const span = document.createElement("span");
|
|
1399
1453
|
span.className = "container-widget-text";
|
|
1400
|
-
span.textContent =
|
|
1454
|
+
span.textContent = this.text;
|
|
1401
1455
|
return span;
|
|
1402
1456
|
}
|
|
1403
|
-
eq() {
|
|
1404
|
-
return
|
|
1457
|
+
eq(other) {
|
|
1458
|
+
return this.text === other.text;
|
|
1405
1459
|
}
|
|
1406
1460
|
ignoreEvent() {
|
|
1407
1461
|
return false;
|
|
@@ -1419,14 +1473,14 @@ function findContainerDecorations(state) {
|
|
|
1419
1473
|
decorations.push({
|
|
1420
1474
|
from: headerLine.from,
|
|
1421
1475
|
to: headerLine.to,
|
|
1422
|
-
value: _codemirror_view.Decoration.replace({ widget: new ContainerHeaderWidget(container.typeName, index, container.registered) })
|
|
1476
|
+
value: _codemirror_view.Decoration.replace({ widget: new ContainerHeaderWidget(container.typeName, index, container.registered, container.quotePrefix ?? "") })
|
|
1423
1477
|
});
|
|
1424
1478
|
if (container.propsLineFrom > 0 && container.propsLineTo > 0) {
|
|
1425
1479
|
const propsLine = state.doc.lineAt(container.propsLineFrom);
|
|
1426
1480
|
decorations.push({
|
|
1427
1481
|
from: propsLine.from,
|
|
1428
1482
|
to: propsLine.to,
|
|
1429
|
-
value: _codemirror_view.Decoration.replace({ widget: new ContainerPropsWidget(propsLine.text) })
|
|
1483
|
+
value: _codemirror_view.Decoration.replace({ widget: new ContainerPropsWidget(propsLine.text, container.quotePrefix ?? "") })
|
|
1430
1484
|
});
|
|
1431
1485
|
}
|
|
1432
1486
|
if (container.endPos > 0) {
|
|
@@ -1434,10 +1488,11 @@ function findContainerDecorations(state) {
|
|
|
1434
1488
|
decorations.push({
|
|
1435
1489
|
from: endLine.from,
|
|
1436
1490
|
to: endLine.to,
|
|
1437
|
-
value: _codemirror_view.Decoration.replace({ widget: new ContainerCloseWidget() })
|
|
1491
|
+
value: _codemirror_view.Decoration.replace({ widget: new ContainerCloseWidget(endLine.text) })
|
|
1438
1492
|
});
|
|
1439
1493
|
}
|
|
1440
1494
|
});
|
|
1495
|
+
decorations.sort((a, b) => a.from - b.from || b.to - a.to);
|
|
1441
1496
|
return decorations;
|
|
1442
1497
|
}
|
|
1443
1498
|
/**
|
|
@@ -1466,11 +1521,19 @@ function handleEditButtonClick(event, view) {
|
|
|
1466
1521
|
*/
|
|
1467
1522
|
var containerWidgetPlugin = _codemirror_view.ViewPlugin.fromClass(class {
|
|
1468
1523
|
decorations;
|
|
1524
|
+
/** 上次构建装饰时的注册中心版本,用于感知异步注册(不能标 private,否则导出匿名类的 dts 报 TS4094) */
|
|
1525
|
+
registryVersion;
|
|
1469
1526
|
constructor(view) {
|
|
1527
|
+
this.registryVersion = componentRegistry.getVersion();
|
|
1470
1528
|
this.decorations = _codemirror_view.Decoration.set(findContainerDecorations(view.state), true);
|
|
1471
1529
|
}
|
|
1472
1530
|
update(update) {
|
|
1473
|
-
|
|
1531
|
+
const registryChanged = componentRegistry.getVersion() !== this.registryVersion;
|
|
1532
|
+
const woken = update.transactions.some((tr) => tr.effects.some((e) => e.is(refreshContainers)));
|
|
1533
|
+
if (update.docChanged || registryChanged || woken) {
|
|
1534
|
+
this.registryVersion = componentRegistry.getVersion();
|
|
1535
|
+
this.decorations = _codemirror_view.Decoration.set(findContainerDecorations(update.state), true);
|
|
1536
|
+
}
|
|
1474
1537
|
}
|
|
1475
1538
|
}, {
|
|
1476
1539
|
decorations: (value) => value.decorations,
|
|
@@ -2861,13 +2924,17 @@ function renderFormItemComponent(field) {
|
|
|
2861
2924
|
}
|
|
2862
2925
|
/**
|
|
2863
2926
|
* 根据 fields 自动生成 Form.Item 列表
|
|
2927
|
+
* 初始值走 <Form initialValues> + 按次打开的 key:
|
|
2928
|
+
* initialValues 在字段实体注册时消费,天然避开“Modal 首次挂载前 setFieldsValue 落空”的时序竞态;
|
|
2929
|
+
* key 每次打开变化触发 Form 重挂载,确保切换到不同容器时重新取值。
|
|
2864
2930
|
*/
|
|
2865
|
-
function renderAutoForm(form, fields) {
|
|
2931
|
+
function renderAutoForm(form, fields, initialValues, initKey) {
|
|
2866
2932
|
if (!fields || fields.length === 0) return null;
|
|
2867
2933
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Form, {
|
|
2868
2934
|
form,
|
|
2869
2935
|
layout: "vertical",
|
|
2870
2936
|
preserve: false,
|
|
2937
|
+
initialValues,
|
|
2871
2938
|
children: fields.map((field) => {
|
|
2872
2939
|
if (!field.componentType) return null;
|
|
2873
2940
|
const formItemProps = {
|
|
@@ -2881,7 +2948,7 @@ function renderAutoForm(form, fields) {
|
|
|
2881
2948
|
children: renderFormItemComponent(field)
|
|
2882
2949
|
}, field.key);
|
|
2883
2950
|
})
|
|
2884
|
-
});
|
|
2951
|
+
}, initKey);
|
|
2885
2952
|
}
|
|
2886
2953
|
/** 字符串形式的历史属性值('true'/'false')还原为布尔,供 Switch 初始化 */
|
|
2887
2954
|
function toFormInitialValue(field, value) {
|
|
@@ -2920,7 +2987,7 @@ function normalizeValue(field, value) {
|
|
|
2920
2987
|
* 属性编辑弹窗组件
|
|
2921
2988
|
* 根据组件 schema 的 renderDialog 函数渲染弹窗内容
|
|
2922
2989
|
*/
|
|
2923
|
-
function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
|
|
2990
|
+
function EditDialog({ visible, typeName, currentProps, initKey, onSave, onClose }) {
|
|
2924
2991
|
const schema = componentRegistry.get(typeName);
|
|
2925
2992
|
const [formProps, setFormProps] = (0, react.useState)({});
|
|
2926
2993
|
const [form] = antd.Form.useForm();
|
|
@@ -2936,16 +3003,19 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
|
|
|
2936
3003
|
...currentProps
|
|
2937
3004
|
};
|
|
2938
3005
|
}, [schema, currentProps]);
|
|
3006
|
+
const initialValues = (0, react.useMemo)(() => {
|
|
3007
|
+
const initial = {};
|
|
3008
|
+
for (const [key, value] of Object.entries(mergedProps)) {
|
|
3009
|
+
const field = schema?.fields?.find((f) => f.key === key);
|
|
3010
|
+
const formValue = toFormInitialValue(field ?? { key }, value);
|
|
3011
|
+
if (formValue !== void 0) initial[key] = formValue;
|
|
3012
|
+
}
|
|
3013
|
+
return initial;
|
|
3014
|
+
}, [mergedProps, schema]);
|
|
2939
3015
|
(0, react.useEffect)(() => {
|
|
2940
3016
|
if (visible) {
|
|
2941
3017
|
setFormProps({});
|
|
2942
|
-
|
|
2943
|
-
for (const [key, value] of Object.entries(mergedProps)) {
|
|
2944
|
-
const field = schema?.fields?.find((f) => f.key === key);
|
|
2945
|
-
const formValue = toFormInitialValue(field ?? { key }, value);
|
|
2946
|
-
if (formValue !== void 0) initial[key] = formValue;
|
|
2947
|
-
}
|
|
2948
|
-
form.setFieldsValue(initial);
|
|
3018
|
+
form.setFieldsValue(initialValues);
|
|
2949
3019
|
dirtyRef.current = false;
|
|
2950
3020
|
}
|
|
2951
3021
|
}, [visible, form]);
|
|
@@ -3000,7 +3070,7 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
|
|
|
3000
3070
|
};
|
|
3001
3071
|
const renderDialogContent = () => {
|
|
3002
3072
|
if (schema.renderDialog) return schema.renderDialog(context);
|
|
3003
|
-
if (schema.fields?.some((f) => f.componentType) && schema.fields) return renderAutoForm(form, schema.fields);
|
|
3073
|
+
if (schema.fields?.some((f) => f.componentType) && schema.fields) return renderAutoForm(form, schema.fields, initialValues, initKey);
|
|
3004
3074
|
return null;
|
|
3005
3075
|
};
|
|
3006
3076
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Modal, {
|
|
@@ -3027,19 +3097,20 @@ function writeContainerProps(props) {
|
|
|
3027
3097
|
* 更新编辑器文档中的容器属性。
|
|
3028
3098
|
* 已有属性行则整行替换;没有属性行则在容器头行后插入一行。
|
|
3029
3099
|
* @param headerPos 容器头行(:::type)任意位置,用于无属性行时定位插入点
|
|
3100
|
+
* @param quotePrefix 容器所处的引用前缀(如 "> "),嵌套在引用中时插入的属性行需保持一致
|
|
3030
3101
|
*/
|
|
3031
|
-
function updateContainerProps(view, headerPos, propsLineFrom, propsLineTo, newProps) {
|
|
3102
|
+
function updateContainerProps(view, headerPos, propsLineFrom, propsLineTo, newProps, quotePrefix = "") {
|
|
3032
3103
|
const newPropsLine = writeContainerProps(newProps);
|
|
3033
3104
|
if (propsLineTo > propsLineFrom) view.dispatch({ changes: {
|
|
3034
3105
|
from: propsLineFrom,
|
|
3035
3106
|
to: propsLineTo,
|
|
3036
|
-
insert: newPropsLine
|
|
3107
|
+
insert: `${quotePrefix}${newPropsLine}`
|
|
3037
3108
|
} });
|
|
3038
3109
|
else {
|
|
3039
3110
|
const headerLine = view.state.doc.lineAt(headerPos);
|
|
3040
3111
|
view.dispatch({ changes: {
|
|
3041
3112
|
from: headerLine.to,
|
|
3042
|
-
insert: `\n${newPropsLine}`
|
|
3113
|
+
insert: `\n${quotePrefix}${newPropsLine}`
|
|
3043
3114
|
} });
|
|
3044
3115
|
}
|
|
3045
3116
|
}
|
|
@@ -3164,6 +3235,7 @@ var MarkdownEditorInner = ({ defaultValue = "", value, onChange, showPreview = t
|
|
|
3164
3235
|
const [dialogVisible, setDialogVisible] = (0, react.useState)(false);
|
|
3165
3236
|
const [dialogTypeName, setDialogTypeName] = (0, react.useState)("");
|
|
3166
3237
|
const [dialogContainer, setDialogContainer] = (0, react.useState)(null);
|
|
3238
|
+
const [dialogSeq, setDialogSeq] = (0, react.useState)(0);
|
|
3167
3239
|
const app = antd.App.useApp();
|
|
3168
3240
|
const notify = (0, react.useCallback)((type, text) => {
|
|
3169
3241
|
if (onNotify) {
|
|
@@ -3183,6 +3255,9 @@ var MarkdownEditorInner = ({ defaultValue = "", value, onChange, showPreview = t
|
|
|
3183
3255
|
}, [onChange]);
|
|
3184
3256
|
(0, react.useImperativeHandle)(ref, () => ({ getContent: () => content }), [content]);
|
|
3185
3257
|
const registryVersion = useRegistryVersion();
|
|
3258
|
+
(0, react.useEffect)(() => {
|
|
3259
|
+
editorView?.dispatch({ effects: refreshContainers.of(null) });
|
|
3260
|
+
}, [registryVersion, editorView]);
|
|
3186
3261
|
const extraToolbarItems = (0, react.useMemo)(() => {
|
|
3187
3262
|
const merged = /* @__PURE__ */ new Map();
|
|
3188
3263
|
for (const schema of componentRegistry.getAll()) merged.set(schema.name, schema);
|
|
@@ -3216,10 +3291,11 @@ var MarkdownEditorInner = ({ defaultValue = "", value, onChange, showPreview = t
|
|
|
3216
3291
|
const handleEditContainer = (0, react.useCallback)((_view, container) => {
|
|
3217
3292
|
setDialogTypeName(container.typeName);
|
|
3218
3293
|
setDialogContainer(container);
|
|
3294
|
+
setDialogSeq((seq) => seq + 1);
|
|
3219
3295
|
setDialogVisible(true);
|
|
3220
3296
|
}, []);
|
|
3221
3297
|
const handleDialogSave = (0, react.useCallback)((newProps) => {
|
|
3222
|
-
if (editorView && dialogContainer) updateContainerProps(editorView, dialogContainer.startPos, dialogContainer.propsLineFrom, dialogContainer.propsLineTo, newProps);
|
|
3298
|
+
if (editorView && dialogContainer) updateContainerProps(editorView, dialogContainer.startPos, dialogContainer.propsLineFrom, dialogContainer.propsLineTo, newProps, dialogContainer.quotePrefix);
|
|
3223
3299
|
}, [editorView, dialogContainer]);
|
|
3224
3300
|
const handleDialogClose = (0, react.useCallback)(() => {
|
|
3225
3301
|
setDialogVisible(false);
|
|
@@ -3256,6 +3332,7 @@ var MarkdownEditorInner = ({ defaultValue = "", value, onChange, showPreview = t
|
|
|
3256
3332
|
visible: dialogVisible,
|
|
3257
3333
|
typeName: dialogTypeName,
|
|
3258
3334
|
currentProps: dialogContainer?.props ?? {},
|
|
3335
|
+
initKey: dialogSeq,
|
|
3259
3336
|
onSave: handleDialogSave,
|
|
3260
3337
|
onClose: handleDialogClose
|
|
3261
3338
|
})
|