remons-markdown-editor 1.0.0-beta.9 → 2.0.0-beta.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/MarkdownEditor.d.ts +24 -5
- package/dist/components/Dialog/EditDialog.d.ts +4 -3
- package/dist/components/Editor/codemirrorExtensions.d.ts +4 -4
- package/dist/components/Editor/containerWidget.d.ts +13 -8
- package/dist/components/Editor/index.d.ts +3 -2
- package/dist/components/Icon/config.d.ts +9 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Preview/index.d.ts +6 -5
- package/dist/components/Toolbar/buttons.d.ts +40 -3
- package/dist/components/Toolbar/config.d.ts +9 -2
- package/dist/components/Toolbar/hooks/useToolbar.d.ts +3 -1
- package/dist/components/Toolbar/index.d.ts +6 -3
- package/dist/components/Toolbar/renderers/TablePicker/TableDropdown.d.ts +1 -2
- package/dist/components/Toolbar/renderers/TablePicker/index.d.ts +1 -1
- package/dist/components/Toolbar/renderers/ToolbarItemRenderer.d.ts +1 -1
- package/dist/hooks/useRegisterToolbar.d.ts +3 -0
- package/dist/hooks/useScrollSync.d.ts +7 -3
- package/dist/index.cjs +2326 -438
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +86 -63
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2348 -441
- package/dist/index.js.map +1 -1
- package/dist/registry/componentRegistry.d.ts +17 -4
- package/dist/types/index.d.ts +18 -9
- package/dist/utils/parseContainer.d.ts +20 -6
- package/dist/utils/writeContainer.d.ts +10 -7
- package/package.json +12 -17
- package/readme.md +29 -26
- package/dist/App.d.ts +0 -2
- package/dist/main.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
9
10
|
var __copyProps = (to, from, except, desc) => {
|
|
10
11
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
12
|
key = keys[i];
|
|
@@ -30,88 +31,1201 @@ let _codemirror_view = require("@codemirror/view");
|
|
|
30
31
|
let _codemirror_commands = require("@codemirror/commands");
|
|
31
32
|
let _codemirror_lang_markdown = require("@codemirror/lang-markdown");
|
|
32
33
|
let _codemirror_theme_one_dark = require("@codemirror/theme-one-dark");
|
|
34
|
+
let _codemirror_language = require("@codemirror/language");
|
|
33
35
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
34
36
|
let remons_render_markdown = require("remons-render-markdown");
|
|
35
37
|
remons_render_markdown = __toESM(remons_render_markdown, 1);
|
|
36
38
|
require("remons-render-markdown/dist/index.css");
|
|
37
39
|
let _ant_design_icons = require("@ant-design/icons");
|
|
38
|
-
//#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
48
|
-
const inner = trimmed.slice(1, -1).trim();
|
|
49
|
-
if (!inner) return props;
|
|
50
|
-
const matches = inner.matchAll(/(?:["']?)(\w+)(?:["']?)\s*:\s*(?:"([^"]*)"|'([^']*)'|(\d+))/g);
|
|
51
|
-
for (const m of matches) props[m[1]] = m[2] ?? m[3] ?? m[4] ?? "";
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/registry/componentRegistry.tsx
|
|
42
|
+
var import_dist = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
43
|
+
(function(global, factory) {
|
|
44
|
+
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global.JSON5 = factory();
|
|
45
|
+
})(exports, (function() {
|
|
46
|
+
"use strict";
|
|
47
|
+
function createCommonjsModule(fn, module$1) {
|
|
48
|
+
return module$1 = { exports: {} }, fn(module$1, module$1.exports), module$1.exports;
|
|
52
49
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
50
|
+
var _global = createCommonjsModule(function(module$2) {
|
|
51
|
+
var global = module$2.exports = typeof window != "undefined" && window.Math == Math ? window : typeof self != "undefined" && self.Math == Math ? self : Function("return this")();
|
|
52
|
+
if (typeof __g == "number") __g = global;
|
|
53
|
+
});
|
|
54
|
+
var _core = createCommonjsModule(function(module$3) {
|
|
55
|
+
var core = module$3.exports = { version: "2.6.5" };
|
|
56
|
+
if (typeof __e == "number") __e = core;
|
|
57
|
+
});
|
|
58
|
+
_core.version;
|
|
59
|
+
var _isObject = function(it) {
|
|
60
|
+
return typeof it === "object" ? it !== null : typeof it === "function";
|
|
61
|
+
};
|
|
62
|
+
var _anObject = function(it) {
|
|
63
|
+
if (!_isObject(it)) throw TypeError(it + " is not an object!");
|
|
64
|
+
return it;
|
|
65
|
+
};
|
|
66
|
+
var _fails = function(exec) {
|
|
67
|
+
try {
|
|
68
|
+
return !!exec();
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var _descriptors = !_fails(function() {
|
|
74
|
+
return Object.defineProperty({}, "a", { get: function() {
|
|
75
|
+
return 7;
|
|
76
|
+
} }).a != 7;
|
|
77
|
+
});
|
|
78
|
+
var document = _global.document;
|
|
79
|
+
var is = _isObject(document) && _isObject(document.createElement);
|
|
80
|
+
var _domCreate = function(it) {
|
|
81
|
+
return is ? document.createElement(it) : {};
|
|
82
|
+
};
|
|
83
|
+
var _ie8DomDefine = !_descriptors && !_fails(function() {
|
|
84
|
+
return Object.defineProperty(_domCreate("div"), "a", { get: function() {
|
|
85
|
+
return 7;
|
|
86
|
+
} }).a != 7;
|
|
87
|
+
});
|
|
88
|
+
var _toPrimitive = function(it, S) {
|
|
89
|
+
if (!_isObject(it)) return it;
|
|
90
|
+
var fn, val;
|
|
91
|
+
if (S && typeof (fn = it.toString) == "function" && !_isObject(val = fn.call(it))) return val;
|
|
92
|
+
if (typeof (fn = it.valueOf) == "function" && !_isObject(val = fn.call(it))) return val;
|
|
93
|
+
if (!S && typeof (fn = it.toString) == "function" && !_isObject(val = fn.call(it))) return val;
|
|
94
|
+
throw TypeError("Can't convert object to primitive value");
|
|
95
|
+
};
|
|
96
|
+
var dP = Object.defineProperty;
|
|
97
|
+
var _objectDp = { f: _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes) {
|
|
98
|
+
_anObject(O);
|
|
99
|
+
P = _toPrimitive(P, true);
|
|
100
|
+
_anObject(Attributes);
|
|
101
|
+
if (_ie8DomDefine) try {
|
|
102
|
+
return dP(O, P, Attributes);
|
|
103
|
+
} catch (e) {}
|
|
104
|
+
if ("get" in Attributes || "set" in Attributes) throw TypeError("Accessors not supported!");
|
|
105
|
+
if ("value" in Attributes) O[P] = Attributes.value;
|
|
106
|
+
return O;
|
|
107
|
+
} };
|
|
108
|
+
var _propertyDesc = function(bitmap, value) {
|
|
109
|
+
return {
|
|
110
|
+
enumerable: !(bitmap & 1),
|
|
111
|
+
configurable: !(bitmap & 2),
|
|
112
|
+
writable: !(bitmap & 4),
|
|
113
|
+
value
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
var _hide = _descriptors ? function(object, key, value) {
|
|
117
|
+
return _objectDp.f(object, key, _propertyDesc(1, value));
|
|
118
|
+
} : function(object, key, value) {
|
|
119
|
+
object[key] = value;
|
|
120
|
+
return object;
|
|
121
|
+
};
|
|
122
|
+
var hasOwnProperty = {}.hasOwnProperty;
|
|
123
|
+
var _has = function(it, key) {
|
|
124
|
+
return hasOwnProperty.call(it, key);
|
|
125
|
+
};
|
|
126
|
+
var id = 0;
|
|
127
|
+
var px = Math.random();
|
|
128
|
+
var _uid = function(key) {
|
|
129
|
+
return "Symbol(".concat(key === void 0 ? "" : key, ")_", (++id + px).toString(36));
|
|
130
|
+
};
|
|
131
|
+
var _library = false;
|
|
132
|
+
var _functionToString = createCommonjsModule(function(module$4) {
|
|
133
|
+
var SHARED = "__core-js_shared__";
|
|
134
|
+
var store = _global[SHARED] || (_global[SHARED] = {});
|
|
135
|
+
(module$4.exports = function(key, value) {
|
|
136
|
+
return store[key] || (store[key] = value !== void 0 ? value : {});
|
|
137
|
+
})("versions", []).push({
|
|
138
|
+
version: _core.version,
|
|
139
|
+
mode: _library ? "pure" : "global",
|
|
140
|
+
copyright: "© 2019 Denis Pushkarev (zloirock.ru)"
|
|
141
|
+
});
|
|
142
|
+
})("native-function-to-string", Function.toString);
|
|
143
|
+
var _redefine = createCommonjsModule(function(module$5) {
|
|
144
|
+
var SRC = _uid("src");
|
|
145
|
+
var TO_STRING = "toString";
|
|
146
|
+
var TPL = ("" + _functionToString).split(TO_STRING);
|
|
147
|
+
_core.inspectSource = function(it) {
|
|
148
|
+
return _functionToString.call(it);
|
|
149
|
+
};
|
|
150
|
+
(module$5.exports = function(O, key, val, safe) {
|
|
151
|
+
var isFunction = typeof val == "function";
|
|
152
|
+
if (isFunction) _has(val, "name") || _hide(val, "name", key);
|
|
153
|
+
if (O[key] === val) return;
|
|
154
|
+
if (isFunction) _has(val, SRC) || _hide(val, SRC, O[key] ? "" + O[key] : TPL.join(String(key)));
|
|
155
|
+
if (O === _global) O[key] = val;
|
|
156
|
+
else if (!safe) {
|
|
157
|
+
delete O[key];
|
|
158
|
+
_hide(O, key, val);
|
|
159
|
+
} else if (O[key]) O[key] = val;
|
|
160
|
+
else _hide(O, key, val);
|
|
161
|
+
})(Function.prototype, TO_STRING, function toString() {
|
|
162
|
+
return typeof this == "function" && this[SRC] || _functionToString.call(this);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
var _aFunction = function(it) {
|
|
166
|
+
if (typeof it != "function") throw TypeError(it + " is not a function!");
|
|
167
|
+
return it;
|
|
168
|
+
};
|
|
169
|
+
var _ctx = function(fn, that, length) {
|
|
170
|
+
_aFunction(fn);
|
|
171
|
+
if (that === void 0) return fn;
|
|
172
|
+
switch (length) {
|
|
173
|
+
case 1: return function(a) {
|
|
174
|
+
return fn.call(that, a);
|
|
175
|
+
};
|
|
176
|
+
case 2: return function(a, b) {
|
|
177
|
+
return fn.call(that, a, b);
|
|
178
|
+
};
|
|
179
|
+
case 3: return function(a, b, c) {
|
|
180
|
+
return fn.call(that, a, b, c);
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return function() {
|
|
184
|
+
return fn.apply(that, arguments);
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
var PROTOTYPE = "prototype";
|
|
188
|
+
var $export = function(type, name, source) {
|
|
189
|
+
var IS_FORCED = type & $export.F;
|
|
190
|
+
var IS_GLOBAL = type & $export.G;
|
|
191
|
+
var IS_STATIC = type & $export.S;
|
|
192
|
+
var IS_PROTO = type & $export.P;
|
|
193
|
+
var IS_BIND = type & $export.B;
|
|
194
|
+
var target = IS_GLOBAL ? _global : IS_STATIC ? _global[name] || (_global[name] = {}) : (_global[name] || {})[PROTOTYPE];
|
|
195
|
+
var exports$1 = IS_GLOBAL ? _core : _core[name] || (_core[name] = {});
|
|
196
|
+
var expProto = exports$1[PROTOTYPE] || (exports$1[PROTOTYPE] = {});
|
|
197
|
+
var key, own, out, exp;
|
|
198
|
+
if (IS_GLOBAL) source = name;
|
|
199
|
+
for (key in source) {
|
|
200
|
+
own = !IS_FORCED && target && target[key] !== void 0;
|
|
201
|
+
out = (own ? target : source)[key];
|
|
202
|
+
exp = IS_BIND && own ? _ctx(out, _global) : IS_PROTO && typeof out == "function" ? _ctx(Function.call, out) : out;
|
|
203
|
+
if (target) _redefine(target, key, out, type & $export.U);
|
|
204
|
+
if (exports$1[key] != out) _hide(exports$1, key, exp);
|
|
205
|
+
if (IS_PROTO && expProto[key] != out) expProto[key] = out;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
_global.core = _core;
|
|
209
|
+
$export.F = 1;
|
|
210
|
+
$export.G = 2;
|
|
211
|
+
$export.S = 4;
|
|
212
|
+
$export.P = 8;
|
|
213
|
+
$export.B = 16;
|
|
214
|
+
$export.W = 32;
|
|
215
|
+
$export.U = 64;
|
|
216
|
+
$export.R = 128;
|
|
217
|
+
var _export = $export;
|
|
218
|
+
var ceil = Math.ceil;
|
|
219
|
+
var floor = Math.floor;
|
|
220
|
+
var _toInteger = function(it) {
|
|
221
|
+
return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
|
|
222
|
+
};
|
|
223
|
+
var _defined = function(it) {
|
|
224
|
+
if (it == void 0) throw TypeError("Can't call method on " + it);
|
|
225
|
+
return it;
|
|
226
|
+
};
|
|
227
|
+
var _stringAt = function(TO_STRING) {
|
|
228
|
+
return function(that, pos) {
|
|
229
|
+
var s = String(_defined(that));
|
|
230
|
+
var i = _toInteger(pos);
|
|
231
|
+
var l = s.length;
|
|
232
|
+
var a, b;
|
|
233
|
+
if (i < 0 || i >= l) return TO_STRING ? "" : void 0;
|
|
234
|
+
a = s.charCodeAt(i);
|
|
235
|
+
return a < 55296 || a > 56319 || i + 1 === l || (b = s.charCodeAt(i + 1)) < 56320 || b > 57343 ? TO_STRING ? s.charAt(i) : a : TO_STRING ? s.slice(i, i + 2) : (a - 55296 << 10) + (b - 56320) + 65536;
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
var $at = _stringAt(false);
|
|
239
|
+
_export(_export.P, "String", { codePointAt: function codePointAt(pos) {
|
|
240
|
+
return $at(this, pos);
|
|
241
|
+
} });
|
|
242
|
+
_core.String.codePointAt;
|
|
243
|
+
var max = Math.max;
|
|
244
|
+
var min = Math.min;
|
|
245
|
+
var _toAbsoluteIndex = function(index, length) {
|
|
246
|
+
index = _toInteger(index);
|
|
247
|
+
return index < 0 ? max(index + length, 0) : min(index, length);
|
|
248
|
+
};
|
|
249
|
+
var fromCharCode = String.fromCharCode;
|
|
250
|
+
var $fromCodePoint = String.fromCodePoint;
|
|
251
|
+
_export(_export.S + _export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), "String", { fromCodePoint: function fromCodePoint(x) {
|
|
252
|
+
var arguments$1 = arguments;
|
|
253
|
+
var res = [];
|
|
254
|
+
var aLen = arguments.length;
|
|
255
|
+
var i = 0;
|
|
256
|
+
var code;
|
|
257
|
+
while (aLen > i) {
|
|
258
|
+
code = +arguments$1[i++];
|
|
259
|
+
if (_toAbsoluteIndex(code, 1114111) !== code) throw RangeError(code + " is not a valid code point");
|
|
260
|
+
res.push(code < 65536 ? fromCharCode(code) : fromCharCode(((code -= 65536) >> 10) + 55296, code % 1024 + 56320));
|
|
261
|
+
}
|
|
262
|
+
return res.join("");
|
|
263
|
+
} });
|
|
264
|
+
_core.String.fromCodePoint;
|
|
265
|
+
var unicode = {
|
|
266
|
+
Space_Separator: /[\u1680\u2000-\u200A\u202F\u205F\u3000]/,
|
|
267
|
+
ID_Start: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/,
|
|
268
|
+
ID_Continue: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
|
|
269
|
+
};
|
|
270
|
+
var util = {
|
|
271
|
+
isSpaceSeparator: function isSpaceSeparator(c) {
|
|
272
|
+
return typeof c === "string" && unicode.Space_Separator.test(c);
|
|
273
|
+
},
|
|
274
|
+
isIdStartChar: function isIdStartChar(c) {
|
|
275
|
+
return typeof c === "string" && (c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c === "$" || c === "_" || unicode.ID_Start.test(c));
|
|
276
|
+
},
|
|
277
|
+
isIdContinueChar: function isIdContinueChar(c) {
|
|
278
|
+
return typeof c === "string" && (c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c >= "0" && c <= "9" || c === "$" || c === "_" || c === "" || c === "" || unicode.ID_Continue.test(c));
|
|
279
|
+
},
|
|
280
|
+
isDigit: function isDigit(c) {
|
|
281
|
+
return typeof c === "string" && /[0-9]/.test(c);
|
|
282
|
+
},
|
|
283
|
+
isHexDigit: function isHexDigit(c) {
|
|
284
|
+
return typeof c === "string" && /[0-9A-Fa-f]/.test(c);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var source;
|
|
288
|
+
var parseState;
|
|
289
|
+
var stack;
|
|
290
|
+
var pos;
|
|
291
|
+
var line;
|
|
292
|
+
var column;
|
|
293
|
+
var token;
|
|
294
|
+
var key;
|
|
295
|
+
var root;
|
|
296
|
+
var parse = function parse(text, reviver) {
|
|
297
|
+
source = String(text);
|
|
298
|
+
parseState = "start";
|
|
299
|
+
stack = [];
|
|
300
|
+
pos = 0;
|
|
301
|
+
line = 1;
|
|
302
|
+
column = 0;
|
|
303
|
+
token = void 0;
|
|
304
|
+
key = void 0;
|
|
305
|
+
root = void 0;
|
|
306
|
+
do {
|
|
307
|
+
token = lex();
|
|
308
|
+
parseStates[parseState]();
|
|
309
|
+
} while (token.type !== "eof");
|
|
310
|
+
if (typeof reviver === "function") return internalize({ "": root }, "", reviver);
|
|
311
|
+
return root;
|
|
312
|
+
};
|
|
313
|
+
function internalize(holder, name, reviver) {
|
|
314
|
+
var value = holder[name];
|
|
315
|
+
if (value != null && typeof value === "object") {
|
|
316
|
+
if (Array.isArray(value)) for (var i = 0; i < value.length; i++) {
|
|
317
|
+
var key = String(i);
|
|
318
|
+
var replacement = internalize(value, key, reviver);
|
|
319
|
+
if (replacement === void 0) delete value[key];
|
|
320
|
+
else Object.defineProperty(value, key, {
|
|
321
|
+
value: replacement,
|
|
322
|
+
writable: true,
|
|
323
|
+
enumerable: true,
|
|
324
|
+
configurable: true
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
else for (var key$1 in value) {
|
|
328
|
+
var replacement$1 = internalize(value, key$1, reviver);
|
|
329
|
+
if (replacement$1 === void 0) delete value[key$1];
|
|
330
|
+
else Object.defineProperty(value, key$1, {
|
|
331
|
+
value: replacement$1,
|
|
332
|
+
writable: true,
|
|
333
|
+
enumerable: true,
|
|
334
|
+
configurable: true
|
|
335
|
+
});
|
|
79
336
|
}
|
|
80
337
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
338
|
+
return reviver.call(holder, name, value);
|
|
339
|
+
}
|
|
340
|
+
var lexState;
|
|
341
|
+
var buffer;
|
|
342
|
+
var doubleQuote;
|
|
343
|
+
var sign;
|
|
344
|
+
var c;
|
|
345
|
+
function lex() {
|
|
346
|
+
lexState = "default";
|
|
347
|
+
buffer = "";
|
|
348
|
+
doubleQuote = false;
|
|
349
|
+
sign = 1;
|
|
350
|
+
for (;;) {
|
|
351
|
+
c = peek();
|
|
352
|
+
var token = lexStates[lexState]();
|
|
353
|
+
if (token) return token;
|
|
88
354
|
}
|
|
89
|
-
containers.push({
|
|
90
|
-
startPos: charPos,
|
|
91
|
-
typeName,
|
|
92
|
-
propsLineFrom,
|
|
93
|
-
propsLineTo,
|
|
94
|
-
props,
|
|
95
|
-
endPos
|
|
96
|
-
});
|
|
97
355
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
356
|
+
function peek() {
|
|
357
|
+
if (source[pos]) return String.fromCodePoint(source.codePointAt(pos));
|
|
358
|
+
}
|
|
359
|
+
function read() {
|
|
360
|
+
var c = peek();
|
|
361
|
+
if (c === "\n") {
|
|
362
|
+
line++;
|
|
363
|
+
column = 0;
|
|
364
|
+
} else if (c) column += c.length;
|
|
365
|
+
else column++;
|
|
366
|
+
if (c) pos += c.length;
|
|
367
|
+
return c;
|
|
368
|
+
}
|
|
369
|
+
var lexStates = {
|
|
370
|
+
default: function default$1() {
|
|
371
|
+
switch (c) {
|
|
372
|
+
case " ":
|
|
373
|
+
case "\v":
|
|
374
|
+
case "\f":
|
|
375
|
+
case " ":
|
|
376
|
+
case "\xA0":
|
|
377
|
+
case "":
|
|
378
|
+
case "\n":
|
|
379
|
+
case "\r":
|
|
380
|
+
case "\u2028":
|
|
381
|
+
case "\u2029":
|
|
382
|
+
read();
|
|
383
|
+
return;
|
|
384
|
+
case "/":
|
|
385
|
+
read();
|
|
386
|
+
lexState = "comment";
|
|
387
|
+
return;
|
|
388
|
+
case void 0:
|
|
389
|
+
read();
|
|
390
|
+
return newToken("eof");
|
|
391
|
+
}
|
|
392
|
+
if (util.isSpaceSeparator(c)) {
|
|
393
|
+
read();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
return lexStates[parseState]();
|
|
397
|
+
},
|
|
398
|
+
comment: function comment() {
|
|
399
|
+
switch (c) {
|
|
400
|
+
case "*":
|
|
401
|
+
read();
|
|
402
|
+
lexState = "multiLineComment";
|
|
403
|
+
return;
|
|
404
|
+
case "/":
|
|
405
|
+
read();
|
|
406
|
+
lexState = "singleLineComment";
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
throw invalidChar(read());
|
|
410
|
+
},
|
|
411
|
+
multiLineComment: function multiLineComment() {
|
|
412
|
+
switch (c) {
|
|
413
|
+
case "*":
|
|
414
|
+
read();
|
|
415
|
+
lexState = "multiLineCommentAsterisk";
|
|
416
|
+
return;
|
|
417
|
+
case void 0: throw invalidChar(read());
|
|
418
|
+
}
|
|
419
|
+
read();
|
|
420
|
+
},
|
|
421
|
+
multiLineCommentAsterisk: function multiLineCommentAsterisk() {
|
|
422
|
+
switch (c) {
|
|
423
|
+
case "*":
|
|
424
|
+
read();
|
|
425
|
+
return;
|
|
426
|
+
case "/":
|
|
427
|
+
read();
|
|
428
|
+
lexState = "default";
|
|
429
|
+
return;
|
|
430
|
+
case void 0: throw invalidChar(read());
|
|
431
|
+
}
|
|
432
|
+
read();
|
|
433
|
+
lexState = "multiLineComment";
|
|
434
|
+
},
|
|
435
|
+
singleLineComment: function singleLineComment() {
|
|
436
|
+
switch (c) {
|
|
437
|
+
case "\n":
|
|
438
|
+
case "\r":
|
|
439
|
+
case "\u2028":
|
|
440
|
+
case "\u2029":
|
|
441
|
+
read();
|
|
442
|
+
lexState = "default";
|
|
443
|
+
return;
|
|
444
|
+
case void 0:
|
|
445
|
+
read();
|
|
446
|
+
return newToken("eof");
|
|
447
|
+
}
|
|
448
|
+
read();
|
|
449
|
+
},
|
|
450
|
+
value: function value() {
|
|
451
|
+
switch (c) {
|
|
452
|
+
case "{":
|
|
453
|
+
case "[": return newToken("punctuator", read());
|
|
454
|
+
case "n":
|
|
455
|
+
read();
|
|
456
|
+
literal("ull");
|
|
457
|
+
return newToken("null", null);
|
|
458
|
+
case "t":
|
|
459
|
+
read();
|
|
460
|
+
literal("rue");
|
|
461
|
+
return newToken("boolean", true);
|
|
462
|
+
case "f":
|
|
463
|
+
read();
|
|
464
|
+
literal("alse");
|
|
465
|
+
return newToken("boolean", false);
|
|
466
|
+
case "-":
|
|
467
|
+
case "+":
|
|
468
|
+
if (read() === "-") sign = -1;
|
|
469
|
+
lexState = "sign";
|
|
470
|
+
return;
|
|
471
|
+
case ".":
|
|
472
|
+
buffer = read();
|
|
473
|
+
lexState = "decimalPointLeading";
|
|
474
|
+
return;
|
|
475
|
+
case "0":
|
|
476
|
+
buffer = read();
|
|
477
|
+
lexState = "zero";
|
|
478
|
+
return;
|
|
479
|
+
case "1":
|
|
480
|
+
case "2":
|
|
481
|
+
case "3":
|
|
482
|
+
case "4":
|
|
483
|
+
case "5":
|
|
484
|
+
case "6":
|
|
485
|
+
case "7":
|
|
486
|
+
case "8":
|
|
487
|
+
case "9":
|
|
488
|
+
buffer = read();
|
|
489
|
+
lexState = "decimalInteger";
|
|
490
|
+
return;
|
|
491
|
+
case "I":
|
|
492
|
+
read();
|
|
493
|
+
literal("nfinity");
|
|
494
|
+
return newToken("numeric", Infinity);
|
|
495
|
+
case "N":
|
|
496
|
+
read();
|
|
497
|
+
literal("aN");
|
|
498
|
+
return newToken("numeric", NaN);
|
|
499
|
+
case "\"":
|
|
500
|
+
case "'":
|
|
501
|
+
doubleQuote = read() === "\"";
|
|
502
|
+
buffer = "";
|
|
503
|
+
lexState = "string";
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
throw invalidChar(read());
|
|
507
|
+
},
|
|
508
|
+
identifierNameStartEscape: function identifierNameStartEscape() {
|
|
509
|
+
if (c !== "u") throw invalidChar(read());
|
|
510
|
+
read();
|
|
511
|
+
var u = unicodeEscape();
|
|
512
|
+
switch (u) {
|
|
513
|
+
case "$":
|
|
514
|
+
case "_": break;
|
|
515
|
+
default: if (!util.isIdStartChar(u)) throw invalidIdentifier();
|
|
516
|
+
}
|
|
517
|
+
buffer += u;
|
|
518
|
+
lexState = "identifierName";
|
|
519
|
+
},
|
|
520
|
+
identifierName: function identifierName() {
|
|
521
|
+
switch (c) {
|
|
522
|
+
case "$":
|
|
523
|
+
case "_":
|
|
524
|
+
case "":
|
|
525
|
+
case "":
|
|
526
|
+
buffer += read();
|
|
527
|
+
return;
|
|
528
|
+
case "\\":
|
|
529
|
+
read();
|
|
530
|
+
lexState = "identifierNameEscape";
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
if (util.isIdContinueChar(c)) {
|
|
534
|
+
buffer += read();
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
return newToken("identifier", buffer);
|
|
538
|
+
},
|
|
539
|
+
identifierNameEscape: function identifierNameEscape() {
|
|
540
|
+
if (c !== "u") throw invalidChar(read());
|
|
541
|
+
read();
|
|
542
|
+
var u = unicodeEscape();
|
|
543
|
+
switch (u) {
|
|
544
|
+
case "$":
|
|
545
|
+
case "_":
|
|
546
|
+
case "":
|
|
547
|
+
case "": break;
|
|
548
|
+
default: if (!util.isIdContinueChar(u)) throw invalidIdentifier();
|
|
549
|
+
}
|
|
550
|
+
buffer += u;
|
|
551
|
+
lexState = "identifierName";
|
|
552
|
+
},
|
|
553
|
+
sign: function sign$1() {
|
|
554
|
+
switch (c) {
|
|
555
|
+
case ".":
|
|
556
|
+
buffer = read();
|
|
557
|
+
lexState = "decimalPointLeading";
|
|
558
|
+
return;
|
|
559
|
+
case "0":
|
|
560
|
+
buffer = read();
|
|
561
|
+
lexState = "zero";
|
|
562
|
+
return;
|
|
563
|
+
case "1":
|
|
564
|
+
case "2":
|
|
565
|
+
case "3":
|
|
566
|
+
case "4":
|
|
567
|
+
case "5":
|
|
568
|
+
case "6":
|
|
569
|
+
case "7":
|
|
570
|
+
case "8":
|
|
571
|
+
case "9":
|
|
572
|
+
buffer = read();
|
|
573
|
+
lexState = "decimalInteger";
|
|
574
|
+
return;
|
|
575
|
+
case "I":
|
|
576
|
+
read();
|
|
577
|
+
literal("nfinity");
|
|
578
|
+
return newToken("numeric", sign * Infinity);
|
|
579
|
+
case "N":
|
|
580
|
+
read();
|
|
581
|
+
literal("aN");
|
|
582
|
+
return newToken("numeric", NaN);
|
|
583
|
+
}
|
|
584
|
+
throw invalidChar(read());
|
|
585
|
+
},
|
|
586
|
+
zero: function zero() {
|
|
587
|
+
switch (c) {
|
|
588
|
+
case ".":
|
|
589
|
+
buffer += read();
|
|
590
|
+
lexState = "decimalPoint";
|
|
591
|
+
return;
|
|
592
|
+
case "e":
|
|
593
|
+
case "E":
|
|
594
|
+
buffer += read();
|
|
595
|
+
lexState = "decimalExponent";
|
|
596
|
+
return;
|
|
597
|
+
case "x":
|
|
598
|
+
case "X":
|
|
599
|
+
buffer += read();
|
|
600
|
+
lexState = "hexadecimal";
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
return newToken("numeric", sign * 0);
|
|
604
|
+
},
|
|
605
|
+
decimalInteger: function decimalInteger() {
|
|
606
|
+
switch (c) {
|
|
607
|
+
case ".":
|
|
608
|
+
buffer += read();
|
|
609
|
+
lexState = "decimalPoint";
|
|
610
|
+
return;
|
|
611
|
+
case "e":
|
|
612
|
+
case "E":
|
|
613
|
+
buffer += read();
|
|
614
|
+
lexState = "decimalExponent";
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (util.isDigit(c)) {
|
|
618
|
+
buffer += read();
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
return newToken("numeric", sign * Number(buffer));
|
|
622
|
+
},
|
|
623
|
+
decimalPointLeading: function decimalPointLeading() {
|
|
624
|
+
if (util.isDigit(c)) {
|
|
625
|
+
buffer += read();
|
|
626
|
+
lexState = "decimalFraction";
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
throw invalidChar(read());
|
|
630
|
+
},
|
|
631
|
+
decimalPoint: function decimalPoint() {
|
|
632
|
+
switch (c) {
|
|
633
|
+
case "e":
|
|
634
|
+
case "E":
|
|
635
|
+
buffer += read();
|
|
636
|
+
lexState = "decimalExponent";
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (util.isDigit(c)) {
|
|
640
|
+
buffer += read();
|
|
641
|
+
lexState = "decimalFraction";
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
return newToken("numeric", sign * Number(buffer));
|
|
645
|
+
},
|
|
646
|
+
decimalFraction: function decimalFraction() {
|
|
647
|
+
switch (c) {
|
|
648
|
+
case "e":
|
|
649
|
+
case "E":
|
|
650
|
+
buffer += read();
|
|
651
|
+
lexState = "decimalExponent";
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (util.isDigit(c)) {
|
|
655
|
+
buffer += read();
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
return newToken("numeric", sign * Number(buffer));
|
|
659
|
+
},
|
|
660
|
+
decimalExponent: function decimalExponent() {
|
|
661
|
+
switch (c) {
|
|
662
|
+
case "+":
|
|
663
|
+
case "-":
|
|
664
|
+
buffer += read();
|
|
665
|
+
lexState = "decimalExponentSign";
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
if (util.isDigit(c)) {
|
|
669
|
+
buffer += read();
|
|
670
|
+
lexState = "decimalExponentInteger";
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
throw invalidChar(read());
|
|
674
|
+
},
|
|
675
|
+
decimalExponentSign: function decimalExponentSign() {
|
|
676
|
+
if (util.isDigit(c)) {
|
|
677
|
+
buffer += read();
|
|
678
|
+
lexState = "decimalExponentInteger";
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
throw invalidChar(read());
|
|
682
|
+
},
|
|
683
|
+
decimalExponentInteger: function decimalExponentInteger() {
|
|
684
|
+
if (util.isDigit(c)) {
|
|
685
|
+
buffer += read();
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
return newToken("numeric", sign * Number(buffer));
|
|
689
|
+
},
|
|
690
|
+
hexadecimal: function hexadecimal() {
|
|
691
|
+
if (util.isHexDigit(c)) {
|
|
692
|
+
buffer += read();
|
|
693
|
+
lexState = "hexadecimalInteger";
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
throw invalidChar(read());
|
|
697
|
+
},
|
|
698
|
+
hexadecimalInteger: function hexadecimalInteger() {
|
|
699
|
+
if (util.isHexDigit(c)) {
|
|
700
|
+
buffer += read();
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
return newToken("numeric", sign * Number(buffer));
|
|
704
|
+
},
|
|
705
|
+
string: function string() {
|
|
706
|
+
switch (c) {
|
|
707
|
+
case "\\":
|
|
708
|
+
read();
|
|
709
|
+
buffer += escape();
|
|
710
|
+
return;
|
|
711
|
+
case "\"":
|
|
712
|
+
if (doubleQuote) {
|
|
713
|
+
read();
|
|
714
|
+
return newToken("string", buffer);
|
|
715
|
+
}
|
|
716
|
+
buffer += read();
|
|
717
|
+
return;
|
|
718
|
+
case "'":
|
|
719
|
+
if (!doubleQuote) {
|
|
720
|
+
read();
|
|
721
|
+
return newToken("string", buffer);
|
|
722
|
+
}
|
|
723
|
+
buffer += read();
|
|
724
|
+
return;
|
|
725
|
+
case "\n":
|
|
726
|
+
case "\r": throw invalidChar(read());
|
|
727
|
+
case "\u2028":
|
|
728
|
+
case "\u2029":
|
|
729
|
+
separatorChar(c);
|
|
730
|
+
break;
|
|
731
|
+
case void 0: throw invalidChar(read());
|
|
732
|
+
}
|
|
733
|
+
buffer += read();
|
|
734
|
+
},
|
|
735
|
+
start: function start() {
|
|
736
|
+
switch (c) {
|
|
737
|
+
case "{":
|
|
738
|
+
case "[": return newToken("punctuator", read());
|
|
739
|
+
}
|
|
740
|
+
lexState = "value";
|
|
741
|
+
},
|
|
742
|
+
beforePropertyName: function beforePropertyName() {
|
|
743
|
+
switch (c) {
|
|
744
|
+
case "$":
|
|
745
|
+
case "_":
|
|
746
|
+
buffer = read();
|
|
747
|
+
lexState = "identifierName";
|
|
748
|
+
return;
|
|
749
|
+
case "\\":
|
|
750
|
+
read();
|
|
751
|
+
lexState = "identifierNameStartEscape";
|
|
752
|
+
return;
|
|
753
|
+
case "}": return newToken("punctuator", read());
|
|
754
|
+
case "\"":
|
|
755
|
+
case "'":
|
|
756
|
+
doubleQuote = read() === "\"";
|
|
757
|
+
lexState = "string";
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (util.isIdStartChar(c)) {
|
|
761
|
+
buffer += read();
|
|
762
|
+
lexState = "identifierName";
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
throw invalidChar(read());
|
|
766
|
+
},
|
|
767
|
+
afterPropertyName: function afterPropertyName() {
|
|
768
|
+
if (c === ":") return newToken("punctuator", read());
|
|
769
|
+
throw invalidChar(read());
|
|
770
|
+
},
|
|
771
|
+
beforePropertyValue: function beforePropertyValue() {
|
|
772
|
+
lexState = "value";
|
|
773
|
+
},
|
|
774
|
+
afterPropertyValue: function afterPropertyValue() {
|
|
775
|
+
switch (c) {
|
|
776
|
+
case ",":
|
|
777
|
+
case "}": return newToken("punctuator", read());
|
|
778
|
+
}
|
|
779
|
+
throw invalidChar(read());
|
|
780
|
+
},
|
|
781
|
+
beforeArrayValue: function beforeArrayValue() {
|
|
782
|
+
if (c === "]") return newToken("punctuator", read());
|
|
783
|
+
lexState = "value";
|
|
784
|
+
},
|
|
785
|
+
afterArrayValue: function afterArrayValue() {
|
|
786
|
+
switch (c) {
|
|
787
|
+
case ",":
|
|
788
|
+
case "]": return newToken("punctuator", read());
|
|
789
|
+
}
|
|
790
|
+
throw invalidChar(read());
|
|
791
|
+
},
|
|
792
|
+
end: function end() {
|
|
793
|
+
throw invalidChar(read());
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
function newToken(type, value) {
|
|
797
|
+
return {
|
|
798
|
+
type,
|
|
799
|
+
value,
|
|
800
|
+
line,
|
|
801
|
+
column
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function literal(s) {
|
|
805
|
+
for (var i = 0, list = s; i < list.length; i += 1) {
|
|
806
|
+
var c = list[i];
|
|
807
|
+
if (peek() !== c) throw invalidChar(read());
|
|
808
|
+
read();
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
function escape() {
|
|
812
|
+
switch (peek()) {
|
|
813
|
+
case "b":
|
|
814
|
+
read();
|
|
815
|
+
return "\b";
|
|
816
|
+
case "f":
|
|
817
|
+
read();
|
|
818
|
+
return "\f";
|
|
819
|
+
case "n":
|
|
820
|
+
read();
|
|
821
|
+
return "\n";
|
|
822
|
+
case "r":
|
|
823
|
+
read();
|
|
824
|
+
return "\r";
|
|
825
|
+
case "t":
|
|
826
|
+
read();
|
|
827
|
+
return " ";
|
|
828
|
+
case "v":
|
|
829
|
+
read();
|
|
830
|
+
return "\v";
|
|
831
|
+
case "0":
|
|
832
|
+
read();
|
|
833
|
+
if (util.isDigit(peek())) throw invalidChar(read());
|
|
834
|
+
return "\0";
|
|
835
|
+
case "x":
|
|
836
|
+
read();
|
|
837
|
+
return hexEscape();
|
|
838
|
+
case "u":
|
|
839
|
+
read();
|
|
840
|
+
return unicodeEscape();
|
|
841
|
+
case "\n":
|
|
842
|
+
case "\u2028":
|
|
843
|
+
case "\u2029":
|
|
844
|
+
read();
|
|
845
|
+
return "";
|
|
846
|
+
case "\r":
|
|
847
|
+
read();
|
|
848
|
+
if (peek() === "\n") read();
|
|
849
|
+
return "";
|
|
850
|
+
case "1":
|
|
851
|
+
case "2":
|
|
852
|
+
case "3":
|
|
853
|
+
case "4":
|
|
854
|
+
case "5":
|
|
855
|
+
case "6":
|
|
856
|
+
case "7":
|
|
857
|
+
case "8":
|
|
858
|
+
case "9": throw invalidChar(read());
|
|
859
|
+
case void 0: throw invalidChar(read());
|
|
860
|
+
}
|
|
861
|
+
return read();
|
|
862
|
+
}
|
|
863
|
+
function hexEscape() {
|
|
864
|
+
var buffer = "";
|
|
865
|
+
var c = peek();
|
|
866
|
+
if (!util.isHexDigit(c)) throw invalidChar(read());
|
|
867
|
+
buffer += read();
|
|
868
|
+
c = peek();
|
|
869
|
+
if (!util.isHexDigit(c)) throw invalidChar(read());
|
|
870
|
+
buffer += read();
|
|
871
|
+
return String.fromCodePoint(parseInt(buffer, 16));
|
|
872
|
+
}
|
|
873
|
+
function unicodeEscape() {
|
|
874
|
+
var buffer = "";
|
|
875
|
+
var count = 4;
|
|
876
|
+
while (count-- > 0) {
|
|
877
|
+
var c = peek();
|
|
878
|
+
if (!util.isHexDigit(c)) throw invalidChar(read());
|
|
879
|
+
buffer += read();
|
|
880
|
+
}
|
|
881
|
+
return String.fromCodePoint(parseInt(buffer, 16));
|
|
882
|
+
}
|
|
883
|
+
var parseStates = {
|
|
884
|
+
start: function start() {
|
|
885
|
+
if (token.type === "eof") throw invalidEOF();
|
|
886
|
+
push();
|
|
887
|
+
},
|
|
888
|
+
beforePropertyName: function beforePropertyName() {
|
|
889
|
+
switch (token.type) {
|
|
890
|
+
case "identifier":
|
|
891
|
+
case "string":
|
|
892
|
+
key = token.value;
|
|
893
|
+
parseState = "afterPropertyName";
|
|
894
|
+
return;
|
|
895
|
+
case "punctuator":
|
|
896
|
+
pop();
|
|
897
|
+
return;
|
|
898
|
+
case "eof": throw invalidEOF();
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
afterPropertyName: function afterPropertyName() {
|
|
902
|
+
if (token.type === "eof") throw invalidEOF();
|
|
903
|
+
parseState = "beforePropertyValue";
|
|
904
|
+
},
|
|
905
|
+
beforePropertyValue: function beforePropertyValue() {
|
|
906
|
+
if (token.type === "eof") throw invalidEOF();
|
|
907
|
+
push();
|
|
908
|
+
},
|
|
909
|
+
beforeArrayValue: function beforeArrayValue() {
|
|
910
|
+
if (token.type === "eof") throw invalidEOF();
|
|
911
|
+
if (token.type === "punctuator" && token.value === "]") {
|
|
912
|
+
pop();
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
push();
|
|
916
|
+
},
|
|
917
|
+
afterPropertyValue: function afterPropertyValue() {
|
|
918
|
+
if (token.type === "eof") throw invalidEOF();
|
|
919
|
+
switch (token.value) {
|
|
920
|
+
case ",":
|
|
921
|
+
parseState = "beforePropertyName";
|
|
922
|
+
return;
|
|
923
|
+
case "}": pop();
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
afterArrayValue: function afterArrayValue() {
|
|
927
|
+
if (token.type === "eof") throw invalidEOF();
|
|
928
|
+
switch (token.value) {
|
|
929
|
+
case ",":
|
|
930
|
+
parseState = "beforeArrayValue";
|
|
931
|
+
return;
|
|
932
|
+
case "]": pop();
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
end: function end() {}
|
|
936
|
+
};
|
|
937
|
+
function push() {
|
|
938
|
+
var value;
|
|
939
|
+
switch (token.type) {
|
|
940
|
+
case "punctuator":
|
|
941
|
+
switch (token.value) {
|
|
942
|
+
case "{":
|
|
943
|
+
value = {};
|
|
944
|
+
break;
|
|
945
|
+
case "[": value = [];
|
|
946
|
+
}
|
|
947
|
+
break;
|
|
948
|
+
case "null":
|
|
949
|
+
case "boolean":
|
|
950
|
+
case "numeric":
|
|
951
|
+
case "string": value = token.value;
|
|
952
|
+
}
|
|
953
|
+
if (root === void 0) root = value;
|
|
954
|
+
else {
|
|
955
|
+
var parent = stack[stack.length - 1];
|
|
956
|
+
if (Array.isArray(parent)) parent.push(value);
|
|
957
|
+
else Object.defineProperty(parent, key, {
|
|
958
|
+
value,
|
|
959
|
+
writable: true,
|
|
960
|
+
enumerable: true,
|
|
961
|
+
configurable: true
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
if (value !== null && typeof value === "object") {
|
|
965
|
+
stack.push(value);
|
|
966
|
+
if (Array.isArray(value)) parseState = "beforeArrayValue";
|
|
967
|
+
else parseState = "beforePropertyName";
|
|
968
|
+
} else {
|
|
969
|
+
var current = stack[stack.length - 1];
|
|
970
|
+
if (current == null) parseState = "end";
|
|
971
|
+
else if (Array.isArray(current)) parseState = "afterArrayValue";
|
|
972
|
+
else parseState = "afterPropertyValue";
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function pop() {
|
|
976
|
+
stack.pop();
|
|
977
|
+
var current = stack[stack.length - 1];
|
|
978
|
+
if (current == null) parseState = "end";
|
|
979
|
+
else if (Array.isArray(current)) parseState = "afterArrayValue";
|
|
980
|
+
else parseState = "afterPropertyValue";
|
|
981
|
+
}
|
|
982
|
+
function invalidChar(c) {
|
|
983
|
+
if (c === void 0) return syntaxError("JSON5: invalid end of input at " + line + ":" + column);
|
|
984
|
+
return syntaxError("JSON5: invalid character '" + formatChar(c) + "' at " + line + ":" + column);
|
|
985
|
+
}
|
|
986
|
+
function invalidEOF() {
|
|
987
|
+
return syntaxError("JSON5: invalid end of input at " + line + ":" + column);
|
|
988
|
+
}
|
|
989
|
+
function invalidIdentifier() {
|
|
990
|
+
column -= 5;
|
|
991
|
+
return syntaxError("JSON5: invalid identifier character at " + line + ":" + column);
|
|
992
|
+
}
|
|
993
|
+
function separatorChar(c) {
|
|
994
|
+
console.warn("JSON5: '" + formatChar(c) + "' in strings is not valid ECMAScript; consider escaping");
|
|
995
|
+
}
|
|
996
|
+
function formatChar(c) {
|
|
997
|
+
var replacements = {
|
|
998
|
+
"'": "\\'",
|
|
999
|
+
"\"": "\\\"",
|
|
1000
|
+
"\\": "\\\\",
|
|
1001
|
+
"\b": "\\b",
|
|
1002
|
+
"\f": "\\f",
|
|
1003
|
+
"\n": "\\n",
|
|
1004
|
+
"\r": "\\r",
|
|
1005
|
+
" ": "\\t",
|
|
1006
|
+
"\v": "\\v",
|
|
1007
|
+
"\0": "\\0",
|
|
1008
|
+
"\u2028": "\\u2028",
|
|
1009
|
+
"\u2029": "\\u2029"
|
|
1010
|
+
};
|
|
1011
|
+
if (replacements[c]) return replacements[c];
|
|
1012
|
+
if (c < " ") {
|
|
1013
|
+
var hexString = c.charCodeAt(0).toString(16);
|
|
1014
|
+
return "\\x" + ("00" + hexString).substring(hexString.length);
|
|
1015
|
+
}
|
|
1016
|
+
return c;
|
|
1017
|
+
}
|
|
1018
|
+
function syntaxError(message) {
|
|
1019
|
+
var err = new SyntaxError(message);
|
|
1020
|
+
err.lineNumber = line;
|
|
1021
|
+
err.columnNumber = column;
|
|
1022
|
+
return err;
|
|
1023
|
+
}
|
|
1024
|
+
return {
|
|
1025
|
+
parse,
|
|
1026
|
+
stringify: function stringify(value, replacer, space) {
|
|
1027
|
+
var stack = [];
|
|
1028
|
+
var indent = "";
|
|
1029
|
+
var propertyList;
|
|
1030
|
+
var replacerFunc;
|
|
1031
|
+
var gap = "";
|
|
1032
|
+
var quote;
|
|
1033
|
+
if (replacer != null && typeof replacer === "object" && !Array.isArray(replacer)) {
|
|
1034
|
+
space = replacer.space;
|
|
1035
|
+
quote = replacer.quote;
|
|
1036
|
+
replacer = replacer.replacer;
|
|
1037
|
+
}
|
|
1038
|
+
if (typeof replacer === "function") replacerFunc = replacer;
|
|
1039
|
+
else if (Array.isArray(replacer)) {
|
|
1040
|
+
propertyList = [];
|
|
1041
|
+
for (var i = 0, list = replacer; i < list.length; i += 1) {
|
|
1042
|
+
var v = list[i];
|
|
1043
|
+
var item = void 0;
|
|
1044
|
+
if (typeof v === "string") item = v;
|
|
1045
|
+
else if (typeof v === "number" || v instanceof String || v instanceof Number) item = String(v);
|
|
1046
|
+
if (item !== void 0 && propertyList.indexOf(item) < 0) propertyList.push(item);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (space instanceof Number) space = Number(space);
|
|
1050
|
+
else if (space instanceof String) space = String(space);
|
|
1051
|
+
if (typeof space === "number") {
|
|
1052
|
+
if (space > 0) {
|
|
1053
|
+
space = Math.min(10, Math.floor(space));
|
|
1054
|
+
gap = " ".substr(0, space);
|
|
1055
|
+
}
|
|
1056
|
+
} else if (typeof space === "string") gap = space.substr(0, 10);
|
|
1057
|
+
return serializeProperty("", { "": value });
|
|
1058
|
+
function serializeProperty(key, holder) {
|
|
1059
|
+
var value = holder[key];
|
|
1060
|
+
if (value != null) {
|
|
1061
|
+
if (typeof value.toJSON5 === "function") value = value.toJSON5(key);
|
|
1062
|
+
else if (typeof value.toJSON === "function") value = value.toJSON(key);
|
|
1063
|
+
}
|
|
1064
|
+
if (replacerFunc) value = replacerFunc.call(holder, key, value);
|
|
1065
|
+
if (value instanceof Number) value = Number(value);
|
|
1066
|
+
else if (value instanceof String) value = String(value);
|
|
1067
|
+
else if (value instanceof Boolean) value = value.valueOf();
|
|
1068
|
+
switch (value) {
|
|
1069
|
+
case null: return "null";
|
|
1070
|
+
case true: return "true";
|
|
1071
|
+
case false: return "false";
|
|
1072
|
+
}
|
|
1073
|
+
if (typeof value === "string") return quoteString(value, false);
|
|
1074
|
+
if (typeof value === "number") return String(value);
|
|
1075
|
+
if (typeof value === "object") return Array.isArray(value) ? serializeArray(value) : serializeObject(value);
|
|
1076
|
+
}
|
|
1077
|
+
function quoteString(value) {
|
|
1078
|
+
var quotes = {
|
|
1079
|
+
"'": .1,
|
|
1080
|
+
"\"": .2
|
|
1081
|
+
};
|
|
1082
|
+
var replacements = {
|
|
1083
|
+
"'": "\\'",
|
|
1084
|
+
"\"": "\\\"",
|
|
1085
|
+
"\\": "\\\\",
|
|
1086
|
+
"\b": "\\b",
|
|
1087
|
+
"\f": "\\f",
|
|
1088
|
+
"\n": "\\n",
|
|
1089
|
+
"\r": "\\r",
|
|
1090
|
+
" ": "\\t",
|
|
1091
|
+
"\v": "\\v",
|
|
1092
|
+
"\0": "\\0",
|
|
1093
|
+
"\u2028": "\\u2028",
|
|
1094
|
+
"\u2029": "\\u2029"
|
|
1095
|
+
};
|
|
1096
|
+
var product = "";
|
|
1097
|
+
for (var i = 0; i < value.length; i++) {
|
|
1098
|
+
var c = value[i];
|
|
1099
|
+
switch (c) {
|
|
1100
|
+
case "'":
|
|
1101
|
+
case "\"":
|
|
1102
|
+
quotes[c]++;
|
|
1103
|
+
product += c;
|
|
1104
|
+
continue;
|
|
1105
|
+
case "\0": if (util.isDigit(value[i + 1])) {
|
|
1106
|
+
product += "\\x00";
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (replacements[c]) {
|
|
1111
|
+
product += replacements[c];
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
if (c < " ") {
|
|
1115
|
+
var hexString = c.charCodeAt(0).toString(16);
|
|
1116
|
+
product += "\\x" + ("00" + hexString).substring(hexString.length);
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
product += c;
|
|
1120
|
+
}
|
|
1121
|
+
var quoteChar = quote || Object.keys(quotes).reduce(function(a, b) {
|
|
1122
|
+
return quotes[a] < quotes[b] ? a : b;
|
|
1123
|
+
});
|
|
1124
|
+
product = product.replace(new RegExp(quoteChar, "g"), replacements[quoteChar]);
|
|
1125
|
+
return quoteChar + product + quoteChar;
|
|
1126
|
+
}
|
|
1127
|
+
function serializeObject(value) {
|
|
1128
|
+
if (stack.indexOf(value) >= 0) throw TypeError("Converting circular structure to JSON5");
|
|
1129
|
+
stack.push(value);
|
|
1130
|
+
var stepback = indent;
|
|
1131
|
+
indent = indent + gap;
|
|
1132
|
+
var keys = propertyList || Object.keys(value);
|
|
1133
|
+
var partial = [];
|
|
1134
|
+
for (var i = 0, list = keys; i < list.length; i += 1) {
|
|
1135
|
+
var key = list[i];
|
|
1136
|
+
var propertyString = serializeProperty(key, value);
|
|
1137
|
+
if (propertyString !== void 0) {
|
|
1138
|
+
var member = serializeKey(key) + ":";
|
|
1139
|
+
if (gap !== "") member += " ";
|
|
1140
|
+
member += propertyString;
|
|
1141
|
+
partial.push(member);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
var final;
|
|
1145
|
+
if (partial.length === 0) final = "{}";
|
|
1146
|
+
else {
|
|
1147
|
+
var properties;
|
|
1148
|
+
if (gap === "") {
|
|
1149
|
+
properties = partial.join(",");
|
|
1150
|
+
final = "{" + properties + "}";
|
|
1151
|
+
} else {
|
|
1152
|
+
var separator = ",\n" + indent;
|
|
1153
|
+
properties = partial.join(separator);
|
|
1154
|
+
final = "{\n" + indent + properties + ",\n" + stepback + "}";
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
stack.pop();
|
|
1158
|
+
indent = stepback;
|
|
1159
|
+
return final;
|
|
1160
|
+
}
|
|
1161
|
+
function serializeKey(key) {
|
|
1162
|
+
if (key.length === 0) return quoteString(key, true);
|
|
1163
|
+
var firstChar = String.fromCodePoint(key.codePointAt(0));
|
|
1164
|
+
if (!util.isIdStartChar(firstChar)) return quoteString(key, true);
|
|
1165
|
+
for (var i = firstChar.length; i < key.length; i++) if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) return quoteString(key, true);
|
|
1166
|
+
return key;
|
|
1167
|
+
}
|
|
1168
|
+
function serializeArray(value) {
|
|
1169
|
+
if (stack.indexOf(value) >= 0) throw TypeError("Converting circular structure to JSON5");
|
|
1170
|
+
stack.push(value);
|
|
1171
|
+
var stepback = indent;
|
|
1172
|
+
indent = indent + gap;
|
|
1173
|
+
var partial = [];
|
|
1174
|
+
for (var i = 0; i < value.length; i++) {
|
|
1175
|
+
var propertyString = serializeProperty(String(i), value);
|
|
1176
|
+
partial.push(propertyString !== void 0 ? propertyString : "null");
|
|
1177
|
+
}
|
|
1178
|
+
var final;
|
|
1179
|
+
if (partial.length === 0) final = "[]";
|
|
1180
|
+
else if (gap === "") final = "[" + partial.join(",") + "]";
|
|
1181
|
+
else {
|
|
1182
|
+
var separator = ",\n" + indent;
|
|
1183
|
+
var properties$1 = partial.join(separator);
|
|
1184
|
+
final = "[\n" + indent + properties$1 + ",\n" + stepback + "]";
|
|
1185
|
+
}
|
|
1186
|
+
stack.pop();
|
|
1187
|
+
indent = stepback;
|
|
1188
|
+
return final;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
}));
|
|
1193
|
+
})))(), 1);
|
|
108
1194
|
var ComponentRegistry = class {
|
|
109
1195
|
schemas = /* @__PURE__ */ new Map();
|
|
1196
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1197
|
+
version = 0;
|
|
110
1198
|
/**
|
|
111
1199
|
* 注册组件 schema
|
|
112
1200
|
*/
|
|
113
1201
|
register(name, schema) {
|
|
114
1202
|
this.schemas.set(name, schema);
|
|
1203
|
+
this.emit();
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* 移除组件注册
|
|
1207
|
+
*/
|
|
1208
|
+
unregister(name) {
|
|
1209
|
+
if (this.schemas.delete(name)) this.emit();
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* 当前版本号,任意注册变更都会自增
|
|
1213
|
+
*/
|
|
1214
|
+
getVersion() {
|
|
1215
|
+
return this.version;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* 订阅注册变更,返回退订函数
|
|
1219
|
+
*/
|
|
1220
|
+
subscribe(listener) {
|
|
1221
|
+
this.listeners.add(listener);
|
|
1222
|
+
return () => {
|
|
1223
|
+
this.listeners.delete(listener);
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
emit() {
|
|
1227
|
+
this.version += 1;
|
|
1228
|
+
this.listeners.forEach((listener) => listener(this.version));
|
|
115
1229
|
}
|
|
116
1230
|
/**
|
|
117
1231
|
* 根据组件名获取已注册的 schema
|
|
@@ -137,29 +1251,97 @@ var ComponentRegistry = class {
|
|
|
137
1251
|
getAll() {
|
|
138
1252
|
return Array.from(this.schemas.values());
|
|
139
1253
|
}
|
|
140
|
-
/**
|
|
141
|
-
* 移除组件注册
|
|
142
|
-
*/
|
|
143
|
-
unregister(name) {
|
|
144
|
-
this.schemas.delete(name);
|
|
145
|
-
}
|
|
146
1254
|
};
|
|
147
1255
|
var componentRegistry = new ComponentRegistry();
|
|
148
1256
|
//#endregion
|
|
1257
|
+
//#region src/utils/parseContainer.ts
|
|
1258
|
+
/**
|
|
1259
|
+
* 解析容器属性行。
|
|
1260
|
+
* 优先按 JSON5 解析(兼容标准 JSON 与 { key: 'value' } 宽松写法),
|
|
1261
|
+
* 失败时返回空对象,保证往返编辑不丢数据。
|
|
1262
|
+
*/
|
|
1263
|
+
function parseContainerProps(line) {
|
|
1264
|
+
const trimmed = line.trim();
|
|
1265
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return {};
|
|
1266
|
+
try {
|
|
1267
|
+
const parsed = import_dist.default.parse(trimmed);
|
|
1268
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
1269
|
+
const props = {};
|
|
1270
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
1271
|
+
if (value === null || value === void 0) continue;
|
|
1272
|
+
if (typeof value === "object") continue;
|
|
1273
|
+
props[key] = value;
|
|
1274
|
+
}
|
|
1275
|
+
return props;
|
|
1276
|
+
} catch {
|
|
1277
|
+
return {};
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* 在编辑器文档中查找容器块。
|
|
1282
|
+
* 单次遍历 + 预累计行偏移,复杂度 O(行数)。
|
|
1283
|
+
*/
|
|
1284
|
+
function findContainers(docText) {
|
|
1285
|
+
const containers = [];
|
|
1286
|
+
const lines = docText.split("\n");
|
|
1287
|
+
const offsets = new Array(lines.length);
|
|
1288
|
+
let pos = 0;
|
|
1289
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1290
|
+
offsets[i] = pos;
|
|
1291
|
+
pos += lines[i].length + 1;
|
|
1292
|
+
}
|
|
1293
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1294
|
+
const match = lines[i].match(/^:::(\w+)$/);
|
|
1295
|
+
if (!match) continue;
|
|
1296
|
+
const typeName = match[1];
|
|
1297
|
+
const headerPos = offsets[i];
|
|
1298
|
+
let props = {};
|
|
1299
|
+
let propsLineFrom = 0;
|
|
1300
|
+
let propsLineTo = 0;
|
|
1301
|
+
const propsLine = lines[i + 1];
|
|
1302
|
+
if (propsLine && propsLine.trim().startsWith("{") && propsLine.trim().endsWith("}")) {
|
|
1303
|
+
props = parseContainerProps(propsLine);
|
|
1304
|
+
propsLineFrom = offsets[i + 1];
|
|
1305
|
+
propsLineTo = propsLineFrom + propsLine.length;
|
|
1306
|
+
}
|
|
1307
|
+
let endPos = 0;
|
|
1308
|
+
for (let j = i + 1; j < lines.length; j++) if (lines[j].trim() === ":::") {
|
|
1309
|
+
endPos = offsets[j];
|
|
1310
|
+
i = j;
|
|
1311
|
+
break;
|
|
1312
|
+
}
|
|
1313
|
+
containers.push({
|
|
1314
|
+
startPos: headerPos,
|
|
1315
|
+
typeName,
|
|
1316
|
+
propsLineFrom,
|
|
1317
|
+
propsLineTo,
|
|
1318
|
+
props,
|
|
1319
|
+
endPos,
|
|
1320
|
+
registered: componentRegistry.has(typeName)
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
return containers;
|
|
1324
|
+
}
|
|
1325
|
+
//#endregion
|
|
149
1326
|
//#region src/components/Editor/containerWidget.ts
|
|
150
1327
|
/**
|
|
151
1328
|
* 自定义 facet 用于传递编辑回调
|
|
152
1329
|
*/
|
|
153
|
-
var containerEditCallback = _codemirror_state.Facet.define({ combine: (values) => values[
|
|
1330
|
+
var containerEditCallback = _codemirror_state.Facet.define({ combine: (values) => values.length ? values[values.length - 1] : null });
|
|
154
1331
|
/**
|
|
155
1332
|
* 只读的容器头行 Widget(显示 :::typeName + 编辑按钮)
|
|
156
|
-
* 使用 Decoration.replace
|
|
1333
|
+
* 使用 Decoration.replace 替换原始文本,使其不可直接编辑。
|
|
1334
|
+
* widget 直接携带所属容器索引与类型,点击时无需再做位置猜测。
|
|
157
1335
|
*/
|
|
158
1336
|
var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
159
1337
|
typeName;
|
|
160
|
-
|
|
1338
|
+
containerIndex;
|
|
1339
|
+
registered;
|
|
1340
|
+
constructor(typeName, containerIndex, registered) {
|
|
161
1341
|
super();
|
|
162
1342
|
this.typeName = typeName;
|
|
1343
|
+
this.containerIndex = containerIndex;
|
|
1344
|
+
this.registered = registered;
|
|
163
1345
|
}
|
|
164
1346
|
toDOM() {
|
|
165
1347
|
const container = document.createElement("span");
|
|
@@ -167,17 +1349,20 @@ var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
|
167
1349
|
const text = document.createElement("span");
|
|
168
1350
|
text.className = "container-widget-text";
|
|
169
1351
|
text.textContent = `:::${this.typeName}`;
|
|
170
|
-
const button = document.createElement("button");
|
|
171
|
-
button.className = "container-edit-btn";
|
|
172
|
-
button.title = `编辑 ${componentRegistry.get(this.typeName)?.label ?? this.typeName}`;
|
|
173
|
-
button.textContent = "✎";
|
|
174
|
-
button.__typeName = this.typeName;
|
|
175
1352
|
container.appendChild(text);
|
|
176
|
-
|
|
1353
|
+
if (this.registered) {
|
|
1354
|
+
const button = document.createElement("button");
|
|
1355
|
+
button.className = "container-edit-btn";
|
|
1356
|
+
button.title = `编辑 ${this.typeName}`;
|
|
1357
|
+
button.textContent = "✎";
|
|
1358
|
+
button.dataset.containerIndex = String(this.containerIndex);
|
|
1359
|
+
button.dataset.typeName = this.typeName;
|
|
1360
|
+
container.appendChild(button);
|
|
1361
|
+
}
|
|
177
1362
|
return container;
|
|
178
1363
|
}
|
|
179
1364
|
eq(other) {
|
|
180
|
-
return this.typeName === other.typeName;
|
|
1365
|
+
return this.typeName === other.typeName && this.containerIndex === other.containerIndex && this.registered === other.registered;
|
|
181
1366
|
}
|
|
182
1367
|
ignoreEvent() {
|
|
183
1368
|
return false;
|
|
@@ -185,7 +1370,6 @@ var ContainerHeaderWidget = class extends _codemirror_view.WidgetType {
|
|
|
185
1370
|
};
|
|
186
1371
|
/**
|
|
187
1372
|
* 只读的容器属性行 Widget(显示 { key: value, ... })
|
|
188
|
-
* 使用 Decoration.replace 替换原始文本,使其不可直接编辑
|
|
189
1373
|
*/
|
|
190
1374
|
var ContainerPropsWidget = class extends _codemirror_view.WidgetType {
|
|
191
1375
|
propsText;
|
|
@@ -208,7 +1392,6 @@ var ContainerPropsWidget = class extends _codemirror_view.WidgetType {
|
|
|
208
1392
|
};
|
|
209
1393
|
/**
|
|
210
1394
|
* 只读的容器结束行 Widget(显示 :::)
|
|
211
|
-
* 使用 Decoration.replace 替换原始文本,使其不可直接编辑
|
|
212
1395
|
*/
|
|
213
1396
|
var ContainerCloseWidget = class extends _codemirror_view.WidgetType {
|
|
214
1397
|
toDOM() {
|
|
@@ -231,20 +1414,19 @@ var ContainerCloseWidget = class extends _codemirror_view.WidgetType {
|
|
|
231
1414
|
function findContainerDecorations(state) {
|
|
232
1415
|
const containers = findContainers(state.doc.toString());
|
|
233
1416
|
const decorations = [];
|
|
234
|
-
|
|
1417
|
+
containers.forEach((container, index) => {
|
|
235
1418
|
const headerLine = state.doc.lineAt(container.startPos);
|
|
236
1419
|
decorations.push({
|
|
237
1420
|
from: headerLine.from,
|
|
238
1421
|
to: headerLine.to,
|
|
239
|
-
value: _codemirror_view.Decoration.replace({ widget: new ContainerHeaderWidget(container.typeName) })
|
|
1422
|
+
value: _codemirror_view.Decoration.replace({ widget: new ContainerHeaderWidget(container.typeName, index, container.registered) })
|
|
240
1423
|
});
|
|
241
1424
|
if (container.propsLineFrom > 0 && container.propsLineTo > 0) {
|
|
242
1425
|
const propsLine = state.doc.lineAt(container.propsLineFrom);
|
|
243
|
-
const propsText = propsLine.text;
|
|
244
1426
|
decorations.push({
|
|
245
1427
|
from: propsLine.from,
|
|
246
1428
|
to: propsLine.to,
|
|
247
|
-
value: _codemirror_view.Decoration.replace({ widget: new ContainerPropsWidget(
|
|
1429
|
+
value: _codemirror_view.Decoration.replace({ widget: new ContainerPropsWidget(propsLine.text) })
|
|
248
1430
|
});
|
|
249
1431
|
}
|
|
250
1432
|
if (container.endPos > 0) {
|
|
@@ -255,12 +1437,32 @@ function findContainerDecorations(state) {
|
|
|
255
1437
|
value: _codemirror_view.Decoration.replace({ widget: new ContainerCloseWidget() })
|
|
256
1438
|
});
|
|
257
1439
|
}
|
|
258
|
-
}
|
|
1440
|
+
});
|
|
259
1441
|
return decorations;
|
|
260
1442
|
}
|
|
261
1443
|
/**
|
|
1444
|
+
* 点击编辑按钮时,依据按钮携带的容器索引回查最新属性并触发回调
|
|
1445
|
+
*/
|
|
1446
|
+
function handleEditButtonClick(event, view) {
|
|
1447
|
+
const target = event.target;
|
|
1448
|
+
if (!target.classList.contains("container-edit-btn")) return false;
|
|
1449
|
+
event.preventDefault();
|
|
1450
|
+
event.stopPropagation();
|
|
1451
|
+
const indexAttr = target.dataset.containerIndex;
|
|
1452
|
+
if (indexAttr === void 0) return false;
|
|
1453
|
+
const container = findContainers(view.state.doc.toString())[Number(indexAttr)];
|
|
1454
|
+
if (!container || !container.registered) return false;
|
|
1455
|
+
const callback = view.state.facet(containerEditCallback);
|
|
1456
|
+
if (callback) callback(view, {
|
|
1457
|
+
...container,
|
|
1458
|
+
props: { ...container.props }
|
|
1459
|
+
});
|
|
1460
|
+
return true;
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
262
1463
|
* 容器编辑 ViewPlugin
|
|
263
|
-
* 将容器的 ::: 头行和 {} 属性行替换为只读 widget
|
|
1464
|
+
* 将容器的 ::: 头行和 {} 属性行替换为只读 widget,使其无法在编辑器中直接编辑。
|
|
1465
|
+
* 仅在文档内容变化时重建装饰,光标移动不触发全文扫描。
|
|
264
1466
|
*/
|
|
265
1467
|
var containerWidgetPlugin = _codemirror_view.ViewPlugin.fromClass(class {
|
|
266
1468
|
decorations;
|
|
@@ -268,29 +1470,20 @@ var containerWidgetPlugin = _codemirror_view.ViewPlugin.fromClass(class {
|
|
|
268
1470
|
this.decorations = _codemirror_view.Decoration.set(findContainerDecorations(view.state), true);
|
|
269
1471
|
}
|
|
270
1472
|
update(update) {
|
|
271
|
-
if (update.docChanged
|
|
1473
|
+
if (update.docChanged) this.decorations = _codemirror_view.Decoration.set(findContainerDecorations(update.state), true);
|
|
272
1474
|
}
|
|
273
1475
|
}, {
|
|
274
1476
|
decorations: (value) => value.decorations,
|
|
275
|
-
eventHandlers: {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const buttonPos = view.posAtDOM(target);
|
|
281
|
-
for (const container of containers) {
|
|
282
|
-
const headerLine = view.state.doc.lineAt(container.startPos);
|
|
283
|
-
if (buttonPos >= headerLine.from - 5 && buttonPos <= headerLine.to + 5) {
|
|
284
|
-
const callback = view.state.facet(containerEditCallback);
|
|
285
|
-
if (callback) callback(view, container.typeName, container.propsLineFrom, container.propsLineTo, { ...container.props });
|
|
286
|
-
return true;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
1477
|
+
eventHandlers: {
|
|
1478
|
+
mousedown: (event, _view) => {
|
|
1479
|
+
if (event.target.classList.contains("container-edit-btn")) {
|
|
1480
|
+
event.preventDefault();
|
|
1481
|
+
return true;
|
|
289
1482
|
}
|
|
290
1483
|
return false;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
}
|
|
1484
|
+
},
|
|
1485
|
+
click: handleEditButtonClick
|
|
1486
|
+
}
|
|
294
1487
|
});
|
|
295
1488
|
//#endregion
|
|
296
1489
|
//#region src/components/Toolbar/buttons.tsx
|
|
@@ -322,28 +1515,248 @@ function insertAtLineStart(view, text) {
|
|
|
322
1515
|
view.dispatch({ selection: { anchor: line.from + text.length } });
|
|
323
1516
|
}
|
|
324
1517
|
/**
|
|
325
|
-
*
|
|
1518
|
+
* 切换标题:
|
|
1519
|
+
* - 当前行已是目标级别标题 → 移除行首 # 前缀(变回普通文本)
|
|
1520
|
+
* - 当前行是其他级别标题 → 替换为目标级别
|
|
1521
|
+
* - 当前行是普通文本 → 插入目标级别前缀
|
|
1522
|
+
* @param view - CodeMirror 编辑器实例
|
|
1523
|
+
* @param level - 标题级别(1-6)
|
|
1524
|
+
*/
|
|
1525
|
+
function toggleHeading(view, level) {
|
|
1526
|
+
const line = view.state.doc.lineAt(view.state.selection.main.from);
|
|
1527
|
+
const m = line.text.match(/^(\s*)(#{1,6})(\s+|\s*$)/);
|
|
1528
|
+
const indent = m ? m[1] : "";
|
|
1529
|
+
const text = "#".repeat(level) + " ";
|
|
1530
|
+
if (m && m[2].length === level) view.dispatch({ changes: {
|
|
1531
|
+
from: line.from,
|
|
1532
|
+
to: line.from + m[0].length,
|
|
1533
|
+
insert: indent
|
|
1534
|
+
} });
|
|
1535
|
+
else {
|
|
1536
|
+
view.dispatch({ changes: {
|
|
1537
|
+
from: line.from,
|
|
1538
|
+
to: m ? line.from + m[0].length : line.from,
|
|
1539
|
+
insert: indent + text
|
|
1540
|
+
} });
|
|
1541
|
+
view.dispatch({ selection: { anchor: line.from + indent.length + text.length } });
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* 切换任务列表(checkbox 待办)
|
|
1546
|
+
* - 支持多行:对选区内每一行应用 `- [ ] `
|
|
1547
|
+
* - 普通列表项(如 `- 内容`)直接转换为 `- [ ] 内容`
|
|
1548
|
+
* - 切换:若所有目标行都已是任务项,则移除行首前缀
|
|
1549
|
+
*/
|
|
1550
|
+
function toggleTaskList(view) {
|
|
1551
|
+
const doc = view.state.doc;
|
|
1552
|
+
const { from, to } = view.state.selection.main;
|
|
1553
|
+
const first = doc.lineAt(from);
|
|
1554
|
+
const last = doc.lineAt(to);
|
|
1555
|
+
const lines = [];
|
|
1556
|
+
for (let n = first.number; n <= last.number; n++) lines.push(doc.line(n));
|
|
1557
|
+
const taskRe = /^(\s*)([-*+])\s\[( |x)\]\s?/;
|
|
1558
|
+
const allTask = lines.every((line) => taskRe.test(line.text));
|
|
1559
|
+
const changes = [];
|
|
1560
|
+
for (const line of lines) {
|
|
1561
|
+
const taskMatch = line.text.match(taskRe);
|
|
1562
|
+
if (taskMatch) changes.push({
|
|
1563
|
+
from: line.from,
|
|
1564
|
+
to: line.from + taskMatch[0].length,
|
|
1565
|
+
insert: allTask ? "" : `${taskMatch[1]}${taskMatch[2]} [ ] `
|
|
1566
|
+
});
|
|
1567
|
+
else {
|
|
1568
|
+
const bulletMatch = line.text.match(/^(\s*)([-*+])\s/);
|
|
1569
|
+
if (bulletMatch) {
|
|
1570
|
+
const idx = line.from + bulletMatch[1].length + bulletMatch[2].length;
|
|
1571
|
+
changes.push({
|
|
1572
|
+
from: idx,
|
|
1573
|
+
to: idx + 1,
|
|
1574
|
+
insert: " [ ] "
|
|
1575
|
+
});
|
|
1576
|
+
} else changes.push({
|
|
1577
|
+
from: line.from,
|
|
1578
|
+
to: line.from,
|
|
1579
|
+
insert: "- [ ] "
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
const anchor = view.state.changes(changes).mapPos(from, 1);
|
|
1584
|
+
view.dispatch({
|
|
1585
|
+
changes,
|
|
1586
|
+
selection: { anchor }
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* 切换行首前缀(支持多行选区)
|
|
1591
|
+
* - 已是对应前缀的行 → 移除前缀(变回普通文本)
|
|
1592
|
+
* - 未加前缀的行 → 在行首插入前缀
|
|
1593
|
+
* @param view - CodeMirror 编辑器实例
|
|
1594
|
+
* @param pattern - 匹配行首前缀的正则
|
|
1595
|
+
* @param insertText - 未匹配时插入的前缀文本
|
|
1596
|
+
*/
|
|
1597
|
+
function toggleLinePrefix(view, pattern, insertText) {
|
|
1598
|
+
const doc = view.state.doc;
|
|
1599
|
+
const { from, to } = view.state.selection.main;
|
|
1600
|
+
const first = doc.lineAt(from);
|
|
1601
|
+
const last = doc.lineAt(Math.max(to, from));
|
|
1602
|
+
const changes = [];
|
|
1603
|
+
for (let n = first.number; n <= last.number; n++) {
|
|
1604
|
+
const line = doc.line(n);
|
|
1605
|
+
const m = line.text.match(pattern);
|
|
1606
|
+
if (m) changes.push({
|
|
1607
|
+
from: line.from,
|
|
1608
|
+
to: line.from + m[0].length,
|
|
1609
|
+
insert: ""
|
|
1610
|
+
});
|
|
1611
|
+
else changes.push({
|
|
1612
|
+
from: line.from,
|
|
1613
|
+
to: line.from,
|
|
1614
|
+
insert: insertText
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
const anchor = view.state.changes(changes).mapPos(from, 1);
|
|
1618
|
+
view.dispatch({
|
|
1619
|
+
changes,
|
|
1620
|
+
selection: { anchor }
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
/** Markdown 列表行:缩进 + 列表标记(无序/有序)+ 空白 */
|
|
1624
|
+
var LIST_LINE_RE = /^(\s*)([-*+]|\d+\.)([ \t]+)/;
|
|
1625
|
+
/** 列表缩进台阶:4 个空格,确保缩进后能被解析为子列表 */
|
|
1626
|
+
var LIST_INDENT_WIDTH = 4;
|
|
1627
|
+
/** 判断位置是否位于代码块内(代码块内不参与列表缩进逻辑) */
|
|
1628
|
+
function isInCodeBlock(state, pos) {
|
|
1629
|
+
let node = (0, _codemirror_language.syntaxTree)(state).resolveInner(pos, 1);
|
|
1630
|
+
while (node) {
|
|
1631
|
+
if (node.name === "FencedCode" || node.name === "CodeBlock") return true;
|
|
1632
|
+
node = node.parent;
|
|
1633
|
+
}
|
|
1634
|
+
return false;
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* 向上查找同缩进的前一个列表项,返回其序号
|
|
1638
|
+
* - 跳过更深的子列表行和空行
|
|
1639
|
+
* - 遇到非列表内容或更浅层列表时结束
|
|
1640
|
+
*/
|
|
1641
|
+
function findPrevSiblingOrder(state, plans, lineNo, indent) {
|
|
1642
|
+
const doc = state.doc;
|
|
1643
|
+
for (let n = lineNo - 1; n >= 1; n--) {
|
|
1644
|
+
const plan = plans.get(n);
|
|
1645
|
+
if (plan) {
|
|
1646
|
+
if (plan.nextIndent === indent) return plan.nextOrder;
|
|
1647
|
+
if (plan.nextIndent < indent) return null;
|
|
1648
|
+
continue;
|
|
1649
|
+
}
|
|
1650
|
+
const text = doc.line(n).text;
|
|
1651
|
+
if (!text.trim()) continue;
|
|
1652
|
+
const m = text.match(LIST_LINE_RE);
|
|
1653
|
+
if (!m) return null;
|
|
1654
|
+
const lineIndent = m[1].length;
|
|
1655
|
+
if (lineIndent === indent) return /^\d+\.$/.test(m[2]) ? parseInt(m[2], 10) : null;
|
|
1656
|
+
if (lineIndent < indent) return null;
|
|
1657
|
+
}
|
|
1658
|
+
return null;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* 计算列表行缩进/反缩进的变更
|
|
1662
|
+
* - 仅当所有选区行都是列表行时生效,否则返回 null 交给默认缩进行为
|
|
1663
|
+
* - 有序列表缩进后重新编号,保证新一级子列表从 1 开始
|
|
1664
|
+
*/
|
|
1665
|
+
function planListIndent(view, direction) {
|
|
1666
|
+
const { state } = view;
|
|
1667
|
+
const doc = state.doc;
|
|
1668
|
+
const plans = /* @__PURE__ */ new Map();
|
|
1669
|
+
for (const range of state.selection.ranges) {
|
|
1670
|
+
const first = doc.lineAt(range.from).number;
|
|
1671
|
+
const last = doc.lineAt(range.to).number;
|
|
1672
|
+
for (let n = first; n <= last; n++) {
|
|
1673
|
+
if (plans.has(n)) continue;
|
|
1674
|
+
const line = doc.line(n);
|
|
1675
|
+
if (isInCodeBlock(state, line.from)) return null;
|
|
1676
|
+
const m = line.text.match(LIST_LINE_RE);
|
|
1677
|
+
if (!m) return null;
|
|
1678
|
+
const indent = m[1].length;
|
|
1679
|
+
plans.set(n, {
|
|
1680
|
+
indent,
|
|
1681
|
+
nextIndent: direction === 1 ? indent + LIST_INDENT_WIDTH : Math.max(0, indent - LIST_INDENT_WIDTH),
|
|
1682
|
+
order: /^\d+\.$/.test(m[2]) ? parseInt(m[2], 10) : null,
|
|
1683
|
+
nextOrder: null
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
if (plans.size === 0) return null;
|
|
1688
|
+
const ordered = [...plans.entries()].sort((a, b) => a[0] - b[0]);
|
|
1689
|
+
for (const [lineNo, info] of ordered) {
|
|
1690
|
+
if (info.order === null) continue;
|
|
1691
|
+
const prevOrder = findPrevSiblingOrder(state, plans, lineNo, info.nextIndent);
|
|
1692
|
+
info.nextOrder = prevOrder === null ? 1 : prevOrder + 1;
|
|
1693
|
+
}
|
|
1694
|
+
return ordered.map(([lineNo, info]) => {
|
|
1695
|
+
const line = doc.line(lineNo);
|
|
1696
|
+
const m = line.text.match(LIST_LINE_RE);
|
|
1697
|
+
const useNextOrder = (direction === 1 || info.indent > 0) && info.order !== null && info.nextOrder !== null && info.order !== info.nextOrder;
|
|
1698
|
+
return {
|
|
1699
|
+
from: line.from,
|
|
1700
|
+
to: line.from + m[0].length,
|
|
1701
|
+
insert: " ".repeat(info.nextIndent) + (useNextOrder ? `${info.nextOrder}.` : m[2]) + m[3]
|
|
1702
|
+
};
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Tab:列表行缩进一级(4 空格)
|
|
1707
|
+
* - 普通行返回 false,继续走默认缩进
|
|
1708
|
+
* - 有序列表缩进后重排序号,子列表从 1 开始
|
|
1709
|
+
*/
|
|
1710
|
+
function indentMarkdownList(view) {
|
|
1711
|
+
const changes = planListIndent(view, 1);
|
|
1712
|
+
if (!changes) return false;
|
|
1713
|
+
view.dispatch({
|
|
1714
|
+
changes,
|
|
1715
|
+
userEvent: "input.indent"
|
|
1716
|
+
});
|
|
1717
|
+
return true;
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Shift-Tab:列表行反缩进一级
|
|
1721
|
+
* - 普通行返回 false,继续走默认缩进
|
|
1722
|
+
* - 有序列表反缩进后并入上一层并重排序号
|
|
1723
|
+
*/
|
|
1724
|
+
function dedentMarkdownList(view) {
|
|
1725
|
+
const changes = planListIndent(view, -1);
|
|
1726
|
+
if (!changes) return false;
|
|
1727
|
+
view.dispatch({
|
|
1728
|
+
changes,
|
|
1729
|
+
userEvent: "delete.dedent"
|
|
1730
|
+
});
|
|
1731
|
+
return true;
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* 上传图片:失败(含网络异常)统一返回 null,不抛错
|
|
326
1735
|
* @param file - 要上传的文件
|
|
327
1736
|
* @param uploadConfig - 上传配置
|
|
328
1737
|
*/
|
|
329
1738
|
async function uploadFileToServer(file, uploadConfig) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
1739
|
+
try {
|
|
1740
|
+
if (uploadConfig.onUploadImage) return await uploadConfig.onUploadImage(file);
|
|
1741
|
+
if (uploadConfig.uploadUrl) {
|
|
1742
|
+
const formData = new FormData();
|
|
1743
|
+
formData.append("file", file);
|
|
1744
|
+
const response = await fetch(uploadConfig.uploadUrl, {
|
|
1745
|
+
method: "POST",
|
|
1746
|
+
body: formData
|
|
1747
|
+
});
|
|
1748
|
+
if (!response.ok) return null;
|
|
1749
|
+
const result = await response.json();
|
|
1750
|
+
if (uploadConfig.onGetUploadUrl) return uploadConfig.onGetUploadUrl(result);
|
|
1751
|
+
return result?.data?.path ?? null;
|
|
1752
|
+
}
|
|
1753
|
+
return null;
|
|
1754
|
+
} catch {
|
|
1755
|
+
return null;
|
|
342
1756
|
}
|
|
343
|
-
return null;
|
|
344
1757
|
}
|
|
345
1758
|
/**
|
|
346
|
-
*
|
|
1759
|
+
* 判断是否配置了图片上传(类型谓词,守卫后可安全访问配置)
|
|
347
1760
|
*/
|
|
348
1761
|
function isUploadConfigured(uploadConfig) {
|
|
349
1762
|
return !!(uploadConfig?.uploadUrl || uploadConfig?.onUploadImage);
|
|
@@ -357,7 +1770,6 @@ function uploadImage(view, uploadConfig) {
|
|
|
357
1770
|
const input = document.createElement("input");
|
|
358
1771
|
input.type = "file";
|
|
359
1772
|
input.accept = "image/*";
|
|
360
|
-
input.style.display = "none";
|
|
361
1773
|
input.addEventListener("change", async () => {
|
|
362
1774
|
if (!input.files || input.files.length === 0) return;
|
|
363
1775
|
const file = input.files[0];
|
|
@@ -374,7 +1786,6 @@ function uploadImage(view, uploadConfig) {
|
|
|
374
1786
|
}
|
|
375
1787
|
input.remove();
|
|
376
1788
|
});
|
|
377
|
-
document.body.appendChild(input);
|
|
378
1789
|
input.click();
|
|
379
1790
|
}
|
|
380
1791
|
/**
|
|
@@ -432,10 +1843,14 @@ function toggleWrap(view, openTag, closeTag) {
|
|
|
432
1843
|
}
|
|
433
1844
|
//#endregion
|
|
434
1845
|
//#region src/components/Editor/codemirrorExtensions.ts
|
|
435
|
-
/**
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
1846
|
+
/**
|
|
1847
|
+
* 图片上传配置 facet。
|
|
1848
|
+
* 传入 getter 而非配置本身:扩展只在 mount 时创建一次,
|
|
1849
|
+
* 运行期通过 getter 读取最新配置,避免闭包过期。
|
|
1850
|
+
*/
|
|
1851
|
+
var uploadConfigFacet = _codemirror_state.Facet.define({ combine: (values) => values.length ? values[values.length - 1] : null });
|
|
1852
|
+
/** 未配置上传时的提示回调 facet(同为 getter 形式) */
|
|
1853
|
+
var messageFacet = _codemirror_state.Facet.define({ combine: (values) => values.length ? values[values.length - 1] : null });
|
|
439
1854
|
/** 粘贴事件处理:拦截图片并上传 */
|
|
440
1855
|
var pasteHandler = _codemirror_view.EditorView.domEventHandlers({ paste: (event, view) => {
|
|
441
1856
|
const files = event.clipboardData?.files;
|
|
@@ -443,23 +1858,38 @@ var pasteHandler = _codemirror_view.EditorView.domEventHandlers({ paste: (event,
|
|
|
443
1858
|
const imageFiles = Array.from(files).filter((f) => f.type.startsWith("image/"));
|
|
444
1859
|
if (imageFiles.length === 0) return false;
|
|
445
1860
|
event.preventDefault();
|
|
446
|
-
const uploadConfig = view.state.facet(uploadConfigFacet);
|
|
447
|
-
const showMessage = view.state.facet(messageFacet);
|
|
1861
|
+
const uploadConfig = view.state.facet(uploadConfigFacet)?.();
|
|
1862
|
+
const showMessage = view.state.facet(messageFacet)?.();
|
|
448
1863
|
if (!isUploadConfigured(uploadConfig)) {
|
|
449
1864
|
showMessage?.();
|
|
450
1865
|
return true;
|
|
451
1866
|
}
|
|
452
|
-
const
|
|
453
|
-
let
|
|
454
|
-
for (const file of imageFiles) uploadFileToServer(file,
|
|
455
|
-
if (url)
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
1867
|
+
const config = uploadConfig;
|
|
1868
|
+
let isFirst = true;
|
|
1869
|
+
for (const file of imageFiles) uploadFileToServer(file, config).then((url) => {
|
|
1870
|
+
if (!url) return;
|
|
1871
|
+
const insert = `![${file.name.replace(/\.[^.]+$/, "")}](${url})`;
|
|
1872
|
+
const { state } = view;
|
|
1873
|
+
if (isFirst) {
|
|
1874
|
+
isFirst = false;
|
|
1875
|
+
const { from, to } = state.selection.main;
|
|
1876
|
+
view.dispatch({
|
|
1877
|
+
changes: {
|
|
1878
|
+
from,
|
|
1879
|
+
to,
|
|
1880
|
+
insert
|
|
1881
|
+
},
|
|
1882
|
+
selection: { anchor: from + insert.length }
|
|
1883
|
+
});
|
|
1884
|
+
} else {
|
|
1885
|
+
const end = state.doc.length;
|
|
1886
|
+
view.dispatch({
|
|
1887
|
+
changes: {
|
|
1888
|
+
from: end,
|
|
1889
|
+
insert: `\n${insert}`
|
|
1890
|
+
},
|
|
1891
|
+
selection: { anchor: end + insert.length + 1 }
|
|
1892
|
+
});
|
|
463
1893
|
}
|
|
464
1894
|
});
|
|
465
1895
|
return true;
|
|
@@ -468,7 +1898,18 @@ var getCodeMirrorExtensions = (opts) => {
|
|
|
468
1898
|
const extensions = [
|
|
469
1899
|
(0, _codemirror_lang_markdown.markdown)(),
|
|
470
1900
|
_codemirror_theme_one_dark.oneDark,
|
|
471
|
-
_codemirror_view.keymap.of([
|
|
1901
|
+
_codemirror_view.keymap.of([
|
|
1902
|
+
{
|
|
1903
|
+
key: "Tab",
|
|
1904
|
+
run: indentMarkdownList
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
key: "Shift-Tab",
|
|
1908
|
+
run: dedentMarkdownList
|
|
1909
|
+
},
|
|
1910
|
+
..._codemirror_commands.defaultKeymap,
|
|
1911
|
+
_codemirror_commands.indentWithTab
|
|
1912
|
+
]),
|
|
472
1913
|
_codemirror_view.EditorView.lineWrapping,
|
|
473
1914
|
pasteHandler,
|
|
474
1915
|
_codemirror_view.EditorView.baseTheme({
|
|
@@ -508,8 +1949,8 @@ var getCodeMirrorExtensions = (opts) => {
|
|
|
508
1949
|
];
|
|
509
1950
|
extensions.push(containerWidgetPlugin);
|
|
510
1951
|
if (opts?.onEditContainer) extensions.push(containerEditCallback.of(opts.onEditContainer));
|
|
511
|
-
if (opts?.
|
|
512
|
-
if (opts?.
|
|
1952
|
+
if (opts?.getUploadConfig) extensions.push(uploadConfigFacet.of(opts.getUploadConfig));
|
|
1953
|
+
if (opts?.getOnMessageNoUploadConfig) extensions.push(messageFacet.of(opts.getOnMessageNoUploadConfig));
|
|
513
1954
|
return extensions;
|
|
514
1955
|
};
|
|
515
1956
|
//#endregion
|
|
@@ -517,17 +1958,29 @@ var getCodeMirrorExtensions = (opts) => {
|
|
|
517
1958
|
function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer, uploadConfig, onMessageNoUploadConfig }) {
|
|
518
1959
|
const editorRef = (0, react.useRef)(null);
|
|
519
1960
|
const viewRef = (0, react.useRef)(null);
|
|
1961
|
+
const latestRef = (0, react.useRef)({
|
|
1962
|
+
onChange,
|
|
1963
|
+
onEditContainer,
|
|
1964
|
+
uploadConfig,
|
|
1965
|
+
onMessageNoUploadConfig
|
|
1966
|
+
});
|
|
1967
|
+
latestRef.current = {
|
|
1968
|
+
onChange,
|
|
1969
|
+
onEditContainer,
|
|
1970
|
+
uploadConfig,
|
|
1971
|
+
onMessageNoUploadConfig
|
|
1972
|
+
};
|
|
520
1973
|
(0, react.useEffect)(() => {
|
|
521
1974
|
if (!editorRef.current) return;
|
|
522
1975
|
const extensions = [
|
|
523
1976
|
codemirror.basicSetup,
|
|
524
1977
|
...getCodeMirrorExtensions({
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
1978
|
+
getUploadConfig: () => latestRef.current.uploadConfig,
|
|
1979
|
+
getOnMessageNoUploadConfig: () => latestRef.current.onMessageNoUploadConfig,
|
|
1980
|
+
onEditContainer: (view, container) => latestRef.current.onEditContainer?.(view, container)
|
|
528
1981
|
}),
|
|
529
1982
|
codemirror.EditorView.updateListener.of((update) => {
|
|
530
|
-
if (update.docChanged) onChange(update.state.doc.toString());
|
|
1983
|
+
if (update.docChanged) latestRef.current.onChange(update.state.doc.toString());
|
|
531
1984
|
})
|
|
532
1985
|
];
|
|
533
1986
|
const state = _codemirror_state.EditorState.create({
|
|
@@ -538,18 +1991,26 @@ function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer,
|
|
|
538
1991
|
state,
|
|
539
1992
|
parent: editorRef.current
|
|
540
1993
|
});
|
|
541
|
-
if (
|
|
542
|
-
|
|
1994
|
+
if (viewRef.current) {
|
|
1995
|
+
onScrollReady?.(viewRef.current.scrollDOM);
|
|
1996
|
+
onViewReady?.(viewRef.current);
|
|
1997
|
+
}
|
|
543
1998
|
return () => {
|
|
544
1999
|
viewRef.current?.destroy();
|
|
2000
|
+
viewRef.current = null;
|
|
545
2001
|
};
|
|
546
2002
|
}, []);
|
|
547
2003
|
(0, react.useEffect)(() => {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
2004
|
+
const view = viewRef.current;
|
|
2005
|
+
if (view && view.state.doc.toString() !== value) view.dispatch({
|
|
2006
|
+
changes: {
|
|
2007
|
+
from: 0,
|
|
2008
|
+
to: view.state.doc.length,
|
|
2009
|
+
insert: value
|
|
2010
|
+
},
|
|
2011
|
+
effects: view.scrollSnapshot(),
|
|
2012
|
+
scrollIntoView: false
|
|
2013
|
+
});
|
|
553
2014
|
}, [value]);
|
|
554
2015
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
555
2016
|
ref: editorRef,
|
|
@@ -558,23 +2019,25 @@ function Editor({ value, onChange, onScrollReady, onViewReady, onEditContainer,
|
|
|
558
2019
|
}
|
|
559
2020
|
//#endregion
|
|
560
2021
|
//#region src/components/Preview/index.tsx
|
|
561
|
-
var Preview = (0, react.forwardRef)(({ content, previewOptions }, ref) => {
|
|
2022
|
+
var Preview = (0, react.forwardRef)(({ content, previewOptions, languages }, ref) => {
|
|
562
2023
|
(0, react.useEffect)(() => {
|
|
563
2024
|
(0, remons_render_markdown.initHighlighter)({
|
|
564
2025
|
...remons_render_markdown.languagesCommon,
|
|
565
|
-
...
|
|
2026
|
+
...languages ?? {}
|
|
566
2027
|
});
|
|
567
|
-
}, [
|
|
2028
|
+
}, [languages]);
|
|
2029
|
+
const { languages: _ignored, ...restOptions } = previewOptions ?? {};
|
|
568
2030
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
569
2031
|
ref,
|
|
570
2032
|
className: "preview",
|
|
571
2033
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(remons_render_markdown.default, {
|
|
572
2034
|
content,
|
|
573
|
-
...
|
|
2035
|
+
...restOptions
|
|
574
2036
|
})
|
|
575
2037
|
});
|
|
576
2038
|
});
|
|
577
2039
|
Preview.displayName = "Preview";
|
|
2040
|
+
var Preview_default = (0, react.memo)(Preview);
|
|
578
2041
|
//#endregion
|
|
579
2042
|
//#region src/components/Panel/SplitPanels.tsx
|
|
580
2043
|
var { Panel } = antd.Splitter;
|
|
@@ -590,13 +2053,53 @@ function SplitPanels({ leftPanel, rightPanel }) {
|
|
|
590
2053
|
});
|
|
591
2054
|
}
|
|
592
2055
|
//#endregion
|
|
2056
|
+
//#region src/components/Icon/config.ts
|
|
2057
|
+
var scriptUrl = "https://at.alicdn.com/t/c/font_5241307_xoojyr52dqn.js";
|
|
2058
|
+
var IconComp = null;
|
|
2059
|
+
/**
|
|
2060
|
+
* 配置 iconfont 脚本地址(宿主在应用入口调用),需在首次渲染前设置;
|
|
2061
|
+
* 变更后重置内部缓存,下次渲染时以新地址重建图标组件。
|
|
2062
|
+
*/
|
|
2063
|
+
function setIconfontScriptUrl(url) {
|
|
2064
|
+
if (url === scriptUrl) return;
|
|
2065
|
+
scriptUrl = url;
|
|
2066
|
+
IconComp = null;
|
|
2067
|
+
}
|
|
2068
|
+
/** 读取当前 iconfont 脚本地址 */
|
|
2069
|
+
function getIconfontScriptUrl() {
|
|
2070
|
+
return scriptUrl;
|
|
2071
|
+
}
|
|
2072
|
+
/** 懒创建图标组件:首次渲染时才注入 iconfont 脚本,避免模块层副作用 */
|
|
2073
|
+
function getIconComponent() {
|
|
2074
|
+
if (!IconComp) IconComp = (0, _ant_design_icons.createFromIconfontCN)({ scriptUrl });
|
|
2075
|
+
return IconComp;
|
|
2076
|
+
}
|
|
2077
|
+
//#endregion
|
|
2078
|
+
//#region src/components/Icon/index.tsx
|
|
2079
|
+
function IconComponent(type, className) {
|
|
2080
|
+
const Icon = getIconComponent();
|
|
2081
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
2082
|
+
type: `icon-${type}`,
|
|
2083
|
+
className
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
//#endregion
|
|
593
2087
|
//#region src/components/Toolbar/config.ts
|
|
2088
|
+
function Quote() {
|
|
2089
|
+
return IconComponent("quote");
|
|
2090
|
+
}
|
|
2091
|
+
function InlineCode() {
|
|
2092
|
+
return IconComponent("inlinecode");
|
|
2093
|
+
}
|
|
2094
|
+
/** 未配置图片上传时的提示文案 */
|
|
2095
|
+
var UPLOAD_CONFIG_MISSING_MESSAGE = "请先配置图片上传功能";
|
|
594
2096
|
/**
|
|
595
2097
|
* 创建工具栏配置
|
|
596
2098
|
* @param options - 配置选项
|
|
597
2099
|
*/
|
|
598
2100
|
function createToolbarConfig(options) {
|
|
599
|
-
const hasUploadConfig = isUploadConfigured(options);
|
|
2101
|
+
const hasUploadConfig = isUploadConfigured(options?.upload);
|
|
2102
|
+
const notify = options?.notify;
|
|
600
2103
|
return [
|
|
601
2104
|
{
|
|
602
2105
|
id: "heading",
|
|
@@ -605,39 +2108,33 @@ function createToolbarConfig(options) {
|
|
|
605
2108
|
children: [
|
|
606
2109
|
{
|
|
607
2110
|
id: "heading1",
|
|
608
|
-
label: "
|
|
609
|
-
|
|
610
|
-
handler: (v) => insertAtLineStart(v, "# ")
|
|
2111
|
+
label: "H1",
|
|
2112
|
+
handler: (v) => toggleHeading(v, 1)
|
|
611
2113
|
},
|
|
612
2114
|
{
|
|
613
2115
|
id: "heading2",
|
|
614
|
-
label: "
|
|
615
|
-
|
|
616
|
-
handler: (v) => insertAtLineStart(v, "## ")
|
|
2116
|
+
label: "H2",
|
|
2117
|
+
handler: (v) => toggleHeading(v, 2)
|
|
617
2118
|
},
|
|
618
2119
|
{
|
|
619
2120
|
id: "heading3",
|
|
620
|
-
label: "
|
|
621
|
-
|
|
622
|
-
handler: (v) => insertAtLineStart(v, "### ")
|
|
2121
|
+
label: "H3",
|
|
2122
|
+
handler: (v) => toggleHeading(v, 3)
|
|
623
2123
|
},
|
|
624
2124
|
{
|
|
625
2125
|
id: "heading4",
|
|
626
|
-
label: "
|
|
627
|
-
|
|
628
|
-
handler: (v) => insertAtLineStart(v, "#### ")
|
|
2126
|
+
label: "H4",
|
|
2127
|
+
handler: (v) => toggleHeading(v, 4)
|
|
629
2128
|
},
|
|
630
2129
|
{
|
|
631
2130
|
id: "heading5",
|
|
632
|
-
label: "
|
|
633
|
-
|
|
634
|
-
handler: (v) => insertAtLineStart(v, "##### ")
|
|
2131
|
+
label: "H5",
|
|
2132
|
+
handler: (v) => toggleHeading(v, 5)
|
|
635
2133
|
},
|
|
636
2134
|
{
|
|
637
2135
|
id: "heading6",
|
|
638
|
-
label: "
|
|
639
|
-
|
|
640
|
-
handler: (v) => insertAtLineStart(v, "###### ")
|
|
2136
|
+
label: "H6",
|
|
2137
|
+
handler: (v) => toggleHeading(v, 6)
|
|
641
2138
|
}
|
|
642
2139
|
]
|
|
643
2140
|
},
|
|
@@ -646,38 +2143,44 @@ function createToolbarConfig(options) {
|
|
|
646
2143
|
id: "bold",
|
|
647
2144
|
label: "加粗",
|
|
648
2145
|
icon: _ant_design_icons.BoldOutlined,
|
|
649
|
-
handler: (v) =>
|
|
2146
|
+
handler: (v) => toggleWrap(v, "**", "**")
|
|
650
2147
|
},
|
|
651
2148
|
{
|
|
652
2149
|
id: "italic",
|
|
653
2150
|
label: "斜体",
|
|
654
2151
|
icon: _ant_design_icons.ItalicOutlined,
|
|
655
|
-
handler: (v) =>
|
|
2152
|
+
handler: (v) => toggleWrap(v, "*", "*")
|
|
656
2153
|
},
|
|
657
2154
|
{
|
|
658
2155
|
id: "strikethrough",
|
|
659
2156
|
label: "删除线",
|
|
660
2157
|
icon: _ant_design_icons.StrikethroughOutlined,
|
|
661
|
-
handler: (v) =>
|
|
2158
|
+
handler: (v) => toggleWrap(v, "~~", "~~")
|
|
662
2159
|
},
|
|
663
2160
|
{
|
|
664
2161
|
id: "underline",
|
|
665
2162
|
label: "下划线",
|
|
666
2163
|
icon: _ant_design_icons.UnderlineOutlined,
|
|
667
|
-
handler: (v) =>
|
|
2164
|
+
handler: (v) => toggleWrap(v, "<u>", "</u>")
|
|
668
2165
|
},
|
|
669
2166
|
{ separatorBefore: true },
|
|
670
2167
|
{
|
|
671
2168
|
id: "ul",
|
|
672
2169
|
label: "无序列表",
|
|
673
2170
|
icon: _ant_design_icons.UnorderedListOutlined,
|
|
674
|
-
handler: (v) =>
|
|
2171
|
+
handler: (v) => toggleLinePrefix(v, /^(\s*)-(?!\s*\[)\s/, "- ")
|
|
675
2172
|
},
|
|
676
2173
|
{
|
|
677
2174
|
id: "ol",
|
|
678
2175
|
label: "有序列表",
|
|
679
2176
|
icon: _ant_design_icons.OrderedListOutlined,
|
|
680
|
-
handler: (v) =>
|
|
2177
|
+
handler: (v) => toggleLinePrefix(v, /^(\s*)\d+\.\s/, "1. ")
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
id: "checkbox",
|
|
2181
|
+
label: "待办",
|
|
2182
|
+
icon: _ant_design_icons.CheckSquareOutlined,
|
|
2183
|
+
handler: (v) => toggleTaskList(v)
|
|
681
2184
|
},
|
|
682
2185
|
{ separatorBefore: true },
|
|
683
2186
|
{
|
|
@@ -688,19 +2191,15 @@ function createToolbarConfig(options) {
|
|
|
688
2191
|
},
|
|
689
2192
|
{
|
|
690
2193
|
id: "image",
|
|
691
|
-
label:
|
|
2194
|
+
label: "图片",
|
|
692
2195
|
icon: _ant_design_icons.PictureOutlined,
|
|
693
|
-
|
|
694
|
-
handler: hasUploadConfig ? (v) => uploadImage(v, {
|
|
695
|
-
uploadUrl: options?.uploadUrl,
|
|
696
|
-
onUploadImage: options?.onUploadImage
|
|
697
|
-
}) : void 0
|
|
2196
|
+
handler: hasUploadConfig && options?.upload ? (v) => uploadImage(v, options.upload) : () => notify?.("warning", UPLOAD_CONFIG_MISSING_MESSAGE)
|
|
698
2197
|
},
|
|
699
2198
|
{ separatorBefore: true },
|
|
700
2199
|
{
|
|
701
2200
|
id: "code",
|
|
702
2201
|
label: "行内代码",
|
|
703
|
-
icon:
|
|
2202
|
+
icon: InlineCode,
|
|
704
2203
|
handler: (v) => wrapSelection(v, "`", "`")
|
|
705
2204
|
},
|
|
706
2205
|
{
|
|
@@ -721,7 +2220,7 @@ function createToolbarConfig(options) {
|
|
|
721
2220
|
{
|
|
722
2221
|
id: "quote",
|
|
723
2222
|
label: "引用",
|
|
724
|
-
icon:
|
|
2223
|
+
icon: Quote,
|
|
725
2224
|
handler: (v) => insertAtLineStart(v, "> ")
|
|
726
2225
|
},
|
|
727
2226
|
{
|
|
@@ -741,11 +2240,14 @@ function createToolbarConfig(options) {
|
|
|
741
2240
|
//#endregion
|
|
742
2241
|
//#region src/components/Toolbar/hooks/useToolbar.ts
|
|
743
2242
|
function useToolbar(editorView, options) {
|
|
744
|
-
const { extraItems, uploadConfig } = options || {};
|
|
2243
|
+
const { extraItems, uploadConfig, notify } = options || {};
|
|
745
2244
|
return {
|
|
746
2245
|
config: (0, react.useMemo)(() => {
|
|
747
|
-
return createToolbarConfig(
|
|
748
|
-
|
|
2246
|
+
return createToolbarConfig({
|
|
2247
|
+
upload: uploadConfig,
|
|
2248
|
+
notify
|
|
2249
|
+
});
|
|
2250
|
+
}, [uploadConfig, notify]),
|
|
749
2251
|
extraItemsConfig: (0, react.useMemo)(() => {
|
|
750
2252
|
return extraItems || [];
|
|
751
2253
|
}, [extraItems]),
|
|
@@ -765,37 +2267,52 @@ function useToolbar(editorView, options) {
|
|
|
765
2267
|
}
|
|
766
2268
|
//#endregion
|
|
767
2269
|
//#region src/components/Toolbar/renderers/ToolbarItemRenderer.tsx
|
|
2270
|
+
/**
|
|
2271
|
+
* 渲染图标:统一接受组件类型;兼容传入 ReactNode 的旧用法。
|
|
2272
|
+
* 组件类型不仅指函数/class,也包括 forwardRef、memo 包装出的对象
|
|
2273
|
+
* (@ant-design/icons 即为 forwardRef,不能当作普通 child 直接渲染)。
|
|
2274
|
+
*/
|
|
2275
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
2276
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
2277
|
+
function isComponentType(icon) {
|
|
2278
|
+
if (typeof icon === "function") return true;
|
|
2279
|
+
if (typeof icon === "object" && icon !== null) {
|
|
2280
|
+
const t = icon.$$typeof;
|
|
2281
|
+
return t === REACT_FORWARD_REF || t === REACT_MEMO;
|
|
2282
|
+
}
|
|
2283
|
+
return false;
|
|
2284
|
+
}
|
|
2285
|
+
function renderIcon(icon) {
|
|
2286
|
+
if (isComponentType(icon)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icon, {});
|
|
2287
|
+
return icon;
|
|
2288
|
+
}
|
|
768
2289
|
function ToolbarItemRenderer({ item, onClick }) {
|
|
769
|
-
const Icon = item.icon;
|
|
770
2290
|
if (item.children && item.children.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [item.separatorBefore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "toolbar-separator" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
771
2291
|
className: "toolbar-group",
|
|
772
2292
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Tooltip, {
|
|
773
2293
|
title: item.label,
|
|
774
2294
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Dropdown, {
|
|
775
|
-
menu: {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
children: [
|
|
781
|
-
child.icon && (() => {
|
|
782
|
-
const ChildIcon = child.icon;
|
|
783
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChildIcon, {});
|
|
784
|
-
})(),
|
|
2295
|
+
menu: {
|
|
2296
|
+
items: item.children.map((child) => ({
|
|
2297
|
+
key: child.id ?? "",
|
|
2298
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
2299
|
+
child.icon && renderIcon(child.icon),
|
|
785
2300
|
" ",
|
|
786
2301
|
child.label
|
|
787
|
-
]
|
|
788
|
-
|
|
789
|
-
|
|
2302
|
+
] }),
|
|
2303
|
+
disabled: child.disabled
|
|
2304
|
+
})),
|
|
2305
|
+
onClick: ({ key }) => {
|
|
2306
|
+
const child = item.children?.find((c) => c.id === key);
|
|
2307
|
+
if (child && !child.disabled) onClick(child);
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
790
2310
|
placement: "bottomLeft",
|
|
791
2311
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(antd.Button, {
|
|
792
2312
|
className: "toolbar-button",
|
|
793
2313
|
type: "text",
|
|
794
2314
|
size: "small",
|
|
795
|
-
children: [
|
|
796
|
-
marginLeft: 2,
|
|
797
|
-
fontSize: 10
|
|
798
|
-
} })]
|
|
2315
|
+
children: [item.icon && renderIcon(item.icon), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ant_design_icons.DownOutlined, { style: { fontSize: 10 } })]
|
|
799
2316
|
})
|
|
800
2317
|
})
|
|
801
2318
|
})
|
|
@@ -812,7 +2329,7 @@ function ToolbarItemRenderer({ item, onClick }) {
|
|
|
812
2329
|
size: "small",
|
|
813
2330
|
disabled: isDisabled,
|
|
814
2331
|
onClick: () => !isDisabled && onClick(item),
|
|
815
|
-
children:
|
|
2332
|
+
children: item.icon && renderIcon(item.icon)
|
|
816
2333
|
})
|
|
817
2334
|
})
|
|
818
2335
|
})] });
|
|
@@ -830,125 +2347,81 @@ var index_module_default = {
|
|
|
830
2347
|
var MAX_ROW = 8;
|
|
831
2348
|
var MAX_COL = 8;
|
|
832
2349
|
function TablePicker({ onSelect }) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
2350
|
+
/** 当前高亮区域(rows x cols),渲染唯一依赖此状态 */
|
|
2351
|
+
const [size, setSize] = (0, react.useState)({
|
|
2352
|
+
rows: 0,
|
|
2353
|
+
cols: 0
|
|
836
2354
|
});
|
|
837
|
-
|
|
838
|
-
row: 0,
|
|
839
|
-
col: 0
|
|
840
|
-
});
|
|
841
|
-
const maxColRef = (0, react.useRef)(0);
|
|
2355
|
+
/** 鼠标回撤(向上/向左)后需要重置列跟踪,prevRow 与 pending 成对出现,仅事件处理内使用 */
|
|
842
2356
|
const prevRowRef = (0, react.useRef)(0);
|
|
843
|
-
const
|
|
844
|
-
const
|
|
845
|
-
const commitRef = (0, react.useRef)(null);
|
|
846
|
-
const clearTimer = (0, react.useCallback)(() => {
|
|
847
|
-
if (timerIdRef.current) {
|
|
848
|
-
clearTimeout(timerIdRef.current);
|
|
849
|
-
timerIdRef.current = null;
|
|
850
|
-
}
|
|
851
|
-
}, []);
|
|
2357
|
+
const pendingColsRef = (0, react.useRef)(0);
|
|
2358
|
+
const flashTimerRef = (0, react.useRef)(null);
|
|
852
2359
|
const clearFlash = (0, react.useCallback)(() => {
|
|
853
|
-
if (
|
|
854
|
-
clearInterval(
|
|
855
|
-
|
|
2360
|
+
if (flashTimerRef.current) {
|
|
2361
|
+
clearInterval(flashTimerRef.current);
|
|
2362
|
+
flashTimerRef.current = null;
|
|
856
2363
|
}
|
|
857
2364
|
}, []);
|
|
858
2365
|
(0, react.useEffect)(() => () => {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
}, []);
|
|
2366
|
+
clearFlash();
|
|
2367
|
+
}, [clearFlash]);
|
|
862
2368
|
/**
|
|
863
2369
|
* 扩展选中区域至 (col, row)
|
|
864
2370
|
*/
|
|
865
2371
|
function extend(col, row) {
|
|
866
|
-
if (row < prevRowRef.current || col <
|
|
867
|
-
if (col >
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
setConfirmedSize({
|
|
873
|
-
row,
|
|
874
|
-
col: maxColRef.current
|
|
2372
|
+
if (row < prevRowRef.current || col < pendingColsRef.current) pendingColsRef.current = 0;
|
|
2373
|
+
if (col > pendingColsRef.current) pendingColsRef.current = col;
|
|
2374
|
+
const cols = pendingColsRef.current;
|
|
2375
|
+
setSize({
|
|
2376
|
+
rows: row,
|
|
2377
|
+
cols
|
|
875
2378
|
});
|
|
876
|
-
|
|
877
|
-
cols: maxColRef.current,
|
|
878
|
-
rows: 1
|
|
879
|
-
};
|
|
2379
|
+
prevRowRef.current = row;
|
|
880
2380
|
}
|
|
881
2381
|
/**
|
|
882
|
-
*
|
|
2382
|
+
* 跳跃动画效果:逐行推进高亮,结束后落到 (col, limit)
|
|
883
2383
|
*/
|
|
884
|
-
function flash(col, dir, limit
|
|
2384
|
+
function flash(col, dir, limit) {
|
|
2385
|
+
clearFlash();
|
|
885
2386
|
let current = dir === 1 ? 1 : limit;
|
|
886
2387
|
const step = dir === 1 ? 1 : -1;
|
|
887
|
-
|
|
888
|
-
setHoverSize({
|
|
889
|
-
row: current,
|
|
890
|
-
col
|
|
891
|
-
});
|
|
892
|
-
if (current > confirmedSize.row || dir === -1) maxColRef.current = Math.min(MAX_COL, col);
|
|
893
|
-
current += step;
|
|
2388
|
+
flashTimerRef.current = setInterval(() => {
|
|
894
2389
|
if (dir === 1 && current > limit || dir === -1 && current < 1) {
|
|
895
|
-
|
|
896
|
-
refreshTimerRef.current = null;
|
|
2390
|
+
clearFlash();
|
|
897
2391
|
const finalRow = current - step;
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
col
|
|
2392
|
+
setSize({
|
|
2393
|
+
rows: finalRow,
|
|
2394
|
+
cols: col
|
|
901
2395
|
});
|
|
902
|
-
|
|
2396
|
+
return;
|
|
903
2397
|
}
|
|
2398
|
+
setSize({
|
|
2399
|
+
rows: current,
|
|
2400
|
+
cols: col
|
|
2401
|
+
});
|
|
2402
|
+
current += step;
|
|
904
2403
|
}, 50);
|
|
905
2404
|
}
|
|
906
2405
|
/**
|
|
907
2406
|
* 核心逻辑:鼠标进入格子
|
|
908
2407
|
*/
|
|
909
|
-
function
|
|
910
|
-
clearTimer();
|
|
2408
|
+
function onCellEnter(index) {
|
|
911
2409
|
clearFlash();
|
|
912
2410
|
const row = Math.floor(index / MAX_COL) + 1;
|
|
913
2411
|
const col = index % MAX_COL + 1;
|
|
914
|
-
const
|
|
915
|
-
const isJump = Math.abs(row -
|
|
916
|
-
const isDown = row > prevRow;
|
|
2412
|
+
const maxCol = pendingColsRef.current;
|
|
2413
|
+
const isJump = Math.abs(row - prevRowRef.current) > 1;
|
|
917
2414
|
prevRowRef.current = row;
|
|
918
2415
|
if (!isJump) extend(col, row);
|
|
919
|
-
else if (
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
row: r,
|
|
923
|
-
col: c
|
|
924
|
-
});
|
|
925
|
-
});
|
|
926
|
-
else extend(col, row);
|
|
2416
|
+
else if (row > 0 && (col > maxCol || maxCol >= MAX_COL)) {
|
|
2417
|
+
pendingColsRef.current = Math.min(MAX_COL, col);
|
|
2418
|
+
flash(Math.min(MAX_COL, col), 1, Math.min(row, MAX_ROW));
|
|
927
2419
|
} else {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
setConfirmedSize({
|
|
931
|
-
row: r,
|
|
932
|
-
col: c
|
|
933
|
-
});
|
|
934
|
-
if (r === 1) {
|
|
935
|
-
commitRef.current = {
|
|
936
|
-
cols: Math.min(MAX_COL, col),
|
|
937
|
-
rows: 1
|
|
938
|
-
};
|
|
939
|
-
setConfirmedSize({
|
|
940
|
-
row: 1,
|
|
941
|
-
col: Math.min(MAX_COL, col)
|
|
942
|
-
});
|
|
943
|
-
}
|
|
944
|
-
});
|
|
2420
|
+
pendingColsRef.current = 0;
|
|
2421
|
+
extend(col, row);
|
|
945
2422
|
}
|
|
946
2423
|
}
|
|
947
2424
|
function onMouseDown() {
|
|
948
|
-
const size = commitRef.current || {
|
|
949
|
-
cols: maxColRef.current,
|
|
950
|
-
rows: confirmedSize.row
|
|
951
|
-
};
|
|
952
2425
|
if (size.rows > 0 && size.cols > 0) onSelect(size);
|
|
953
2426
|
}
|
|
954
2427
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -960,18 +2433,18 @@ function TablePicker({ onSelect }) {
|
|
|
960
2433
|
children: Array.from({ length: 64 }).map((_, i) => {
|
|
961
2434
|
const row = Math.floor(i / MAX_COL) + 1;
|
|
962
2435
|
const col = i % MAX_COL + 1;
|
|
963
|
-
const isSelected = row <=
|
|
2436
|
+
const isSelected = row <= size.rows && col <= size.cols;
|
|
964
2437
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
965
2438
|
className: `${index_module_default.cell} ${isSelected ? index_module_default.cellActive : ""}`,
|
|
966
|
-
onMouseEnter: () =>
|
|
2439
|
+
onMouseEnter: () => onCellEnter(i)
|
|
967
2440
|
}, i);
|
|
968
2441
|
})
|
|
969
2442
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
970
2443
|
className: index_module_default.label,
|
|
971
2444
|
children: [
|
|
972
|
-
|
|
2445
|
+
size.rows,
|
|
973
2446
|
" x ",
|
|
974
|
-
|
|
2447
|
+
size.cols || 1
|
|
975
2448
|
]
|
|
976
2449
|
})]
|
|
977
2450
|
});
|
|
@@ -979,8 +2452,10 @@ function TablePicker({ onSelect }) {
|
|
|
979
2452
|
//#endregion
|
|
980
2453
|
//#region src/components/Toolbar/renderers/TablePicker/TableDropdown.tsx
|
|
981
2454
|
function TableDropdown({ editorView }) {
|
|
982
|
-
const [open, setOpen] = react.
|
|
983
|
-
const
|
|
2455
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
2456
|
+
const handleOpenChange = (0, react.useCallback)((next) => {
|
|
2457
|
+
setOpen(next);
|
|
2458
|
+
}, []);
|
|
984
2459
|
const handleTableSelect = (0, react.useCallback)((rows, cols) => {
|
|
985
2460
|
if (!editorView || rows <= 0 || cols <= 0) return;
|
|
986
2461
|
editorView.focus();
|
|
@@ -997,18 +2472,15 @@ function TableDropdown({ editorView }) {
|
|
|
997
2472
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Dropdown, {
|
|
998
2473
|
trigger: ["click"],
|
|
999
2474
|
open,
|
|
1000
|
-
onOpenChange:
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
} }, openCountRef.current)
|
|
1010
|
-
});
|
|
1011
|
-
},
|
|
2475
|
+
onOpenChange: handleOpenChange,
|
|
2476
|
+
destroyOnHidden: true,
|
|
2477
|
+
popupRender: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2478
|
+
style: { padding: 4 },
|
|
2479
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TablePicker, { onSelect: (size) => {
|
|
2480
|
+
handleTableSelect(size.rows, size.cols);
|
|
2481
|
+
setOpen(false);
|
|
2482
|
+
} })
|
|
2483
|
+
}),
|
|
1012
2484
|
placement: "bottomLeft",
|
|
1013
2485
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
|
|
1014
2486
|
className: "toolbar-button",
|
|
@@ -1021,10 +2493,11 @@ function TableDropdown({ editorView }) {
|
|
|
1021
2493
|
}
|
|
1022
2494
|
//#endregion
|
|
1023
2495
|
//#region src/components/Toolbar/index.tsx
|
|
1024
|
-
function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems, uploadConfig }) {
|
|
2496
|
+
function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems, uploadConfig, notify }) {
|
|
1025
2497
|
const { config, extraItemsConfig, handleClick } = useToolbar(editorView, {
|
|
1026
2498
|
extraItems,
|
|
1027
|
-
uploadConfig
|
|
2499
|
+
uploadConfig,
|
|
2500
|
+
notify
|
|
1028
2501
|
});
|
|
1029
2502
|
const renderFullscreen = (0, react.useCallback)(() => {
|
|
1030
2503
|
if (!onToggleFullscreen) return null;
|
|
@@ -1064,8 +2537,305 @@ function Toolbar({ editorView, fullscreen = true, onToggleFullscreen, extraItems
|
|
|
1064
2537
|
]
|
|
1065
2538
|
});
|
|
1066
2539
|
}
|
|
2540
|
+
var Toolbar_default = (0, react.memo)(Toolbar);
|
|
1067
2541
|
//#endregion
|
|
1068
2542
|
//#region src/components/Dialog/EditDialog.tsx
|
|
2543
|
+
var import_dayjs_min = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
2544
|
+
(function(t, e) {
|
|
2545
|
+
"object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
|
|
2546
|
+
})(exports, (function() {
|
|
2547
|
+
"use strict";
|
|
2548
|
+
var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = {
|
|
2549
|
+
name: "en",
|
|
2550
|
+
weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
|
|
2551
|
+
months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
|
|
2552
|
+
ordinal: function(t) {
|
|
2553
|
+
var e = [
|
|
2554
|
+
"th",
|
|
2555
|
+
"st",
|
|
2556
|
+
"nd",
|
|
2557
|
+
"rd"
|
|
2558
|
+
], n = t % 100;
|
|
2559
|
+
return "[" + t + (e[(n - 20) % 10] || e[n] || e[0]) + "]";
|
|
2560
|
+
}
|
|
2561
|
+
}, m = function(t, e, n) {
|
|
2562
|
+
var r = String(t);
|
|
2563
|
+
return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t;
|
|
2564
|
+
}, v = {
|
|
2565
|
+
s: m,
|
|
2566
|
+
z: function(t) {
|
|
2567
|
+
var e = -t.utcOffset(), n = Math.abs(e), r = Math.floor(n / 60), i = n % 60;
|
|
2568
|
+
return (e <= 0 ? "+" : "-") + m(r, 2, "0") + ":" + m(i, 2, "0");
|
|
2569
|
+
},
|
|
2570
|
+
m: function t(e, n) {
|
|
2571
|
+
if (e.date() < n.date()) return -t(n, e);
|
|
2572
|
+
var r = 12 * (n.year() - e.year()) + (n.month() - e.month()), i = e.clone().add(r, c), s = n - i < 0, u = e.clone().add(r + (s ? -1 : 1), c);
|
|
2573
|
+
return +(-(r + (n - i) / (s ? i - u : u - i)) || 0);
|
|
2574
|
+
},
|
|
2575
|
+
a: function(t) {
|
|
2576
|
+
return t < 0 ? Math.ceil(t) || 0 : Math.floor(t);
|
|
2577
|
+
},
|
|
2578
|
+
p: function(t) {
|
|
2579
|
+
return {
|
|
2580
|
+
M: c,
|
|
2581
|
+
y: h,
|
|
2582
|
+
w: o,
|
|
2583
|
+
d: a,
|
|
2584
|
+
D: d,
|
|
2585
|
+
h: u,
|
|
2586
|
+
m: s,
|
|
2587
|
+
s: i,
|
|
2588
|
+
ms: r,
|
|
2589
|
+
Q: f
|
|
2590
|
+
}[t] || String(t || "").toLowerCase().replace(/s$/, "");
|
|
2591
|
+
},
|
|
2592
|
+
u: function(t) {
|
|
2593
|
+
return void 0 === t;
|
|
2594
|
+
}
|
|
2595
|
+
}, g = "en", D = {};
|
|
2596
|
+
D[g] = M;
|
|
2597
|
+
var p = "$isDayjsObject", S = function(t) {
|
|
2598
|
+
return t instanceof _ || !(!t || !t[p]);
|
|
2599
|
+
}, w = function t(e, n, r) {
|
|
2600
|
+
var i;
|
|
2601
|
+
if (!e) return g;
|
|
2602
|
+
if ("string" == typeof e) {
|
|
2603
|
+
var s = e.toLowerCase();
|
|
2604
|
+
D[s] && (i = s), n && (D[s] = n, i = s);
|
|
2605
|
+
var u = e.split("-");
|
|
2606
|
+
if (!i && u.length > 1) return t(u[0]);
|
|
2607
|
+
} else {
|
|
2608
|
+
var a = e.name;
|
|
2609
|
+
D[a] = e, i = a;
|
|
2610
|
+
}
|
|
2611
|
+
return !r && i && (g = i), i || !r && g;
|
|
2612
|
+
}, O = function(t, e) {
|
|
2613
|
+
if (S(t)) return t.clone();
|
|
2614
|
+
var n = "object" == typeof e ? e : {};
|
|
2615
|
+
return n.date = t, n.args = arguments, new _(n);
|
|
2616
|
+
}, b = v;
|
|
2617
|
+
b.l = w, b.i = S, b.w = function(t, e) {
|
|
2618
|
+
return O(t, {
|
|
2619
|
+
locale: e.$L,
|
|
2620
|
+
utc: e.$u,
|
|
2621
|
+
x: e.$x,
|
|
2622
|
+
$offset: e.$offset
|
|
2623
|
+
});
|
|
2624
|
+
};
|
|
2625
|
+
var _ = function() {
|
|
2626
|
+
function M(t) {
|
|
2627
|
+
this.$L = w(t.locale, null, !0), this.parse(t), this.$x = this.$x || t.x || {}, this[p] = !0;
|
|
2628
|
+
}
|
|
2629
|
+
var m = M.prototype;
|
|
2630
|
+
return m.parse = function(t) {
|
|
2631
|
+
this.$d = function(t) {
|
|
2632
|
+
var e = t.date, n = t.utc;
|
|
2633
|
+
if (null === e) return /* @__PURE__ */ new Date(NaN);
|
|
2634
|
+
if (b.u(e)) return /* @__PURE__ */ new Date();
|
|
2635
|
+
if (e instanceof Date) return new Date(e);
|
|
2636
|
+
if ("string" == typeof e && !/Z$/i.test(e)) {
|
|
2637
|
+
var r = e.match($);
|
|
2638
|
+
if (r) {
|
|
2639
|
+
var i = r[2] - 1 || 0, s = (r[7] || "0").substring(0, 3);
|
|
2640
|
+
return n ? new Date(Date.UTC(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s)) : new Date(r[1], i, r[3] || 1, r[4] || 0, r[5] || 0, r[6] || 0, s);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
return new Date(e);
|
|
2644
|
+
}(t), this.init();
|
|
2645
|
+
}, m.init = function() {
|
|
2646
|
+
var t = this.$d;
|
|
2647
|
+
this.$y = t.getFullYear(), this.$M = t.getMonth(), this.$D = t.getDate(), this.$W = t.getDay(), this.$H = t.getHours(), this.$m = t.getMinutes(), this.$s = t.getSeconds(), this.$ms = t.getMilliseconds();
|
|
2648
|
+
}, m.$utils = function() {
|
|
2649
|
+
return b;
|
|
2650
|
+
}, m.isValid = function() {
|
|
2651
|
+
return !(this.$d.toString() === l);
|
|
2652
|
+
}, m.isSame = function(t, e) {
|
|
2653
|
+
var n = O(t);
|
|
2654
|
+
return this.startOf(e) <= n && n <= this.endOf(e);
|
|
2655
|
+
}, m.isAfter = function(t, e) {
|
|
2656
|
+
return O(t) < this.startOf(e);
|
|
2657
|
+
}, m.isBefore = function(t, e) {
|
|
2658
|
+
return this.endOf(e) < O(t);
|
|
2659
|
+
}, m.$g = function(t, e, n) {
|
|
2660
|
+
return b.u(t) ? this[e] : this.set(n, t);
|
|
2661
|
+
}, m.unix = function() {
|
|
2662
|
+
return Math.floor(this.valueOf() / 1e3);
|
|
2663
|
+
}, m.valueOf = function() {
|
|
2664
|
+
return this.$d.getTime();
|
|
2665
|
+
}, m.startOf = function(t, e) {
|
|
2666
|
+
var n = this, r = !!b.u(e) || e, f = b.p(t), l = function(t, e) {
|
|
2667
|
+
var i = b.w(n.$u ? Date.UTC(n.$y, e, t) : new Date(n.$y, e, t), n);
|
|
2668
|
+
return r ? i : i.endOf(a);
|
|
2669
|
+
}, $ = function(t, e) {
|
|
2670
|
+
return b.w(n.toDate()[t].apply(n.toDate("s"), (r ? [
|
|
2671
|
+
0,
|
|
2672
|
+
0,
|
|
2673
|
+
0,
|
|
2674
|
+
0
|
|
2675
|
+
] : [
|
|
2676
|
+
23,
|
|
2677
|
+
59,
|
|
2678
|
+
59,
|
|
2679
|
+
999
|
|
2680
|
+
]).slice(e)), n);
|
|
2681
|
+
}, y = this.$W, M = this.$M, m = this.$D, v = "set" + (this.$u ? "UTC" : "");
|
|
2682
|
+
switch (f) {
|
|
2683
|
+
case h: return r ? l(1, 0) : l(31, 11);
|
|
2684
|
+
case c: return r ? l(1, M) : l(0, M + 1);
|
|
2685
|
+
case o:
|
|
2686
|
+
var g = this.$locale().weekStart || 0, D = (y < g ? y + 7 : y) - g;
|
|
2687
|
+
return l(r ? m - D : m + (6 - D), M);
|
|
2688
|
+
case a:
|
|
2689
|
+
case d: return $(v + "Hours", 0);
|
|
2690
|
+
case u: return $(v + "Minutes", 1);
|
|
2691
|
+
case s: return $(v + "Seconds", 2);
|
|
2692
|
+
case i: return $(v + "Milliseconds", 3);
|
|
2693
|
+
default: return this.clone();
|
|
2694
|
+
}
|
|
2695
|
+
}, m.endOf = function(t) {
|
|
2696
|
+
return this.startOf(t, !1);
|
|
2697
|
+
}, m.$set = function(t, e) {
|
|
2698
|
+
var n, o = b.p(t), f = "set" + (this.$u ? "UTC" : ""), l = (n = {}, n[a] = f + "Date", n[d] = f + "Date", n[c] = f + "Month", n[h] = f + "FullYear", n[u] = f + "Hours", n[s] = f + "Minutes", n[i] = f + "Seconds", n[r] = f + "Milliseconds", n)[o], $ = o === a ? this.$D + (e - this.$W) : e;
|
|
2699
|
+
if (o === c || o === h) {
|
|
2700
|
+
var y = this.clone().set(d, 1);
|
|
2701
|
+
y.$d[l]($), y.init(), this.$d = y.set(d, Math.min(this.$D, y.daysInMonth())).$d;
|
|
2702
|
+
} else l && this.$d[l]($);
|
|
2703
|
+
return this.init(), this;
|
|
2704
|
+
}, m.set = function(t, e) {
|
|
2705
|
+
return this.clone().$set(t, e);
|
|
2706
|
+
}, m.get = function(t) {
|
|
2707
|
+
return this[b.p(t)]();
|
|
2708
|
+
}, m.add = function(r, f) {
|
|
2709
|
+
var d, l = this;
|
|
2710
|
+
r = Number(r);
|
|
2711
|
+
var $ = b.p(f), y = function(t) {
|
|
2712
|
+
var e = O(l);
|
|
2713
|
+
return b.w(e.date(e.date() + Math.round(t * r)), l);
|
|
2714
|
+
};
|
|
2715
|
+
if ($ === c) return this.set(c, this.$M + r);
|
|
2716
|
+
if ($ === h) return this.set(h, this.$y + r);
|
|
2717
|
+
if ($ === a) return y(1);
|
|
2718
|
+
if ($ === o) return y(7);
|
|
2719
|
+
var M = (d = {}, d[s] = e, d[u] = n, d[i] = t, d)[$] || 1, m = this.$d.getTime() + r * M;
|
|
2720
|
+
return b.w(m, this);
|
|
2721
|
+
}, m.subtract = function(t, e) {
|
|
2722
|
+
return this.add(-1 * t, e);
|
|
2723
|
+
}, m.format = function(t) {
|
|
2724
|
+
var e = this, n = this.$locale();
|
|
2725
|
+
if (!this.isValid()) return n.invalidDate || l;
|
|
2726
|
+
var r = t || "YYYY-MM-DDTHH:mm:ssZ", i = b.z(this), s = this.$H, u = this.$m, a = this.$M, o = n.weekdays, c = n.months, f = n.meridiem, h = function(t, n, i, s) {
|
|
2727
|
+
return t && (t[n] || t(e, r)) || i[n].slice(0, s);
|
|
2728
|
+
}, d = function(t) {
|
|
2729
|
+
return b.s(s % 12 || 12, t, "0");
|
|
2730
|
+
}, $ = f || function(t, e, n) {
|
|
2731
|
+
var r = t < 12 ? "AM" : "PM";
|
|
2732
|
+
return n ? r.toLowerCase() : r;
|
|
2733
|
+
};
|
|
2734
|
+
return r.replace(y, (function(t, r) {
|
|
2735
|
+
return r || function(t) {
|
|
2736
|
+
switch (t) {
|
|
2737
|
+
case "YY": return String(e.$y).slice(-2);
|
|
2738
|
+
case "YYYY": return b.s(e.$y, 4, "0");
|
|
2739
|
+
case "M": return a + 1;
|
|
2740
|
+
case "MM": return b.s(a + 1, 2, "0");
|
|
2741
|
+
case "MMM": return h(n.monthsShort, a, c, 3);
|
|
2742
|
+
case "MMMM": return h(c, a);
|
|
2743
|
+
case "D": return e.$D;
|
|
2744
|
+
case "DD": return b.s(e.$D, 2, "0");
|
|
2745
|
+
case "d": return String(e.$W);
|
|
2746
|
+
case "dd": return h(n.weekdaysMin, e.$W, o, 2);
|
|
2747
|
+
case "ddd": return h(n.weekdaysShort, e.$W, o, 3);
|
|
2748
|
+
case "dddd": return o[e.$W];
|
|
2749
|
+
case "H": return String(s);
|
|
2750
|
+
case "HH": return b.s(s, 2, "0");
|
|
2751
|
+
case "h": return d(1);
|
|
2752
|
+
case "hh": return d(2);
|
|
2753
|
+
case "a": return $(s, u, !0);
|
|
2754
|
+
case "A": return $(s, u, !1);
|
|
2755
|
+
case "m": return String(u);
|
|
2756
|
+
case "mm": return b.s(u, 2, "0");
|
|
2757
|
+
case "s": return String(e.$s);
|
|
2758
|
+
case "ss": return b.s(e.$s, 2, "0");
|
|
2759
|
+
case "SSS": return b.s(e.$ms, 3, "0");
|
|
2760
|
+
case "Z": return i;
|
|
2761
|
+
}
|
|
2762
|
+
return null;
|
|
2763
|
+
}(t) || i.replace(":", "");
|
|
2764
|
+
}));
|
|
2765
|
+
}, m.utcOffset = function() {
|
|
2766
|
+
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
|
|
2767
|
+
}, m.diff = function(r, d, l) {
|
|
2768
|
+
var $, y = this, M = b.p(d), m = O(r), v = (m.utcOffset() - this.utcOffset()) * e, g = this - m, D = function() {
|
|
2769
|
+
return b.m(y, m);
|
|
2770
|
+
};
|
|
2771
|
+
switch (M) {
|
|
2772
|
+
case h:
|
|
2773
|
+
$ = D() / 12;
|
|
2774
|
+
break;
|
|
2775
|
+
case c:
|
|
2776
|
+
$ = D();
|
|
2777
|
+
break;
|
|
2778
|
+
case f:
|
|
2779
|
+
$ = D() / 3;
|
|
2780
|
+
break;
|
|
2781
|
+
case o:
|
|
2782
|
+
$ = (g - v) / 6048e5;
|
|
2783
|
+
break;
|
|
2784
|
+
case a:
|
|
2785
|
+
$ = (g - v) / 864e5;
|
|
2786
|
+
break;
|
|
2787
|
+
case u:
|
|
2788
|
+
$ = g / n;
|
|
2789
|
+
break;
|
|
2790
|
+
case s:
|
|
2791
|
+
$ = g / e;
|
|
2792
|
+
break;
|
|
2793
|
+
case i:
|
|
2794
|
+
$ = g / t;
|
|
2795
|
+
break;
|
|
2796
|
+
default: $ = g;
|
|
2797
|
+
}
|
|
2798
|
+
return l ? $ : b.a($);
|
|
2799
|
+
}, m.daysInMonth = function() {
|
|
2800
|
+
return this.endOf(c).$D;
|
|
2801
|
+
}, m.$locale = function() {
|
|
2802
|
+
return D[this.$L];
|
|
2803
|
+
}, m.locale = function(t, e) {
|
|
2804
|
+
if (!t) return this.$L;
|
|
2805
|
+
var n = this.clone(), r = w(t, e, !0);
|
|
2806
|
+
return r && (n.$L = r), n;
|
|
2807
|
+
}, m.clone = function() {
|
|
2808
|
+
return b.w(this.$d, this);
|
|
2809
|
+
}, m.toDate = function() {
|
|
2810
|
+
return new Date(this.valueOf());
|
|
2811
|
+
}, m.toJSON = function() {
|
|
2812
|
+
return this.isValid() ? this.toISOString() : null;
|
|
2813
|
+
}, m.toISOString = function() {
|
|
2814
|
+
return this.$d.toISOString();
|
|
2815
|
+
}, m.toString = function() {
|
|
2816
|
+
return this.$d.toUTCString();
|
|
2817
|
+
}, M;
|
|
2818
|
+
}(), Y = _.prototype;
|
|
2819
|
+
return O.prototype = Y, [
|
|
2820
|
+
["$ms", r],
|
|
2821
|
+
["$s", i],
|
|
2822
|
+
["$m", s],
|
|
2823
|
+
["$H", u],
|
|
2824
|
+
["$W", a],
|
|
2825
|
+
["$M", c],
|
|
2826
|
+
["$y", h],
|
|
2827
|
+
["$D", d]
|
|
2828
|
+
].forEach((function(t) {
|
|
2829
|
+
Y[t[1]] = function(e) {
|
|
2830
|
+
return this.$g(e, t[0], t[1]);
|
|
2831
|
+
};
|
|
2832
|
+
})), O.extend = function(t, e) {
|
|
2833
|
+
return t.$i || (t(e, _, O), t.$i = !0), O;
|
|
2834
|
+
}, O.locale = w, O.isDayjs = S, O.unix = function(t) {
|
|
2835
|
+
return O(1e3 * t);
|
|
2836
|
+
}, O.en = D[g], O.Ls = D, O.p = {}, O;
|
|
2837
|
+
}));
|
|
2838
|
+
})))(), 1);
|
|
1069
2839
|
/**
|
|
1070
2840
|
* 组件类型到 antd 表单组件的映射
|
|
1071
2841
|
*/
|
|
@@ -1082,7 +2852,7 @@ var FormComponents = {
|
|
|
1082
2852
|
dateRange: antd.DatePicker.RangePicker
|
|
1083
2853
|
};
|
|
1084
2854
|
/**
|
|
1085
|
-
* 渲染对应类型的 antd
|
|
2855
|
+
* 渲染对应类型的 antd 表单组件(仅接收 componentProps,不再与 Form.Item props 混用)
|
|
1086
2856
|
*/
|
|
1087
2857
|
function renderFormItemComponent(field) {
|
|
1088
2858
|
const props = field.componentProps || {};
|
|
@@ -1097,13 +2867,14 @@ function renderAutoForm(form, fields) {
|
|
|
1097
2867
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Form, {
|
|
1098
2868
|
form,
|
|
1099
2869
|
layout: "vertical",
|
|
2870
|
+
preserve: false,
|
|
1100
2871
|
children: fields.map((field) => {
|
|
1101
2872
|
if (!field.componentType) return null;
|
|
1102
2873
|
const formItemProps = {
|
|
1103
2874
|
name: field.key,
|
|
1104
2875
|
label: field.name || field.key,
|
|
1105
2876
|
valuePropName: field.componentType === "switch" ? "checked" : void 0,
|
|
1106
|
-
...field.
|
|
2877
|
+
...field.formItemProps
|
|
1107
2878
|
};
|
|
1108
2879
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Form.Item, {
|
|
1109
2880
|
...formItemProps,
|
|
@@ -1112,6 +2883,39 @@ function renderAutoForm(form, fields) {
|
|
|
1112
2883
|
})
|
|
1113
2884
|
});
|
|
1114
2885
|
}
|
|
2886
|
+
/** 字符串形式的历史属性值('true'/'false')还原为布尔,供 Switch 初始化 */
|
|
2887
|
+
function toFormInitialValue(field, value) {
|
|
2888
|
+
if (value === void 0) return field.defaultValue ?? (field.componentType === "switch" ? false : void 0);
|
|
2889
|
+
if (field.componentType === "switch") {
|
|
2890
|
+
if (typeof value === "boolean") return value;
|
|
2891
|
+
return value === "true" || value === 1 || value === "1";
|
|
2892
|
+
}
|
|
2893
|
+
if (field.componentType === "number" || field.componentType === "slider" || field.componentType === "rate") {
|
|
2894
|
+
const num = Number(value);
|
|
2895
|
+
return Number.isNaN(num) ? void 0 : num;
|
|
2896
|
+
}
|
|
2897
|
+
if (field.componentType === "date") {
|
|
2898
|
+
const d = (0, import_dayjs_min.default)(typeof value === "boolean" ? String(value) : value);
|
|
2899
|
+
return d.isValid() ? d : void 0;
|
|
2900
|
+
}
|
|
2901
|
+
if (field.componentType === "dateRange") {
|
|
2902
|
+
const parts = String(value).split(",").map((s) => s.trim()).filter(Boolean);
|
|
2903
|
+
if (parts.length !== 2) return void 0;
|
|
2904
|
+
const [start, end] = parts.map((p) => (0, import_dayjs_min.default)(p));
|
|
2905
|
+
return start.isValid() && end.isValid() ? [start, end] : void 0;
|
|
2906
|
+
}
|
|
2907
|
+
return value;
|
|
2908
|
+
}
|
|
2909
|
+
/** 表单控件值归一化为容器属性可存储的字符串(容器语法仅支持扁平原始值) */
|
|
2910
|
+
function normalizeValue(field, value) {
|
|
2911
|
+
if (value === null || value === void 0) return "";
|
|
2912
|
+
if (field?.componentType === "date" && import_dayjs_min.default.isDayjs(value)) return value.format("YYYY-MM-DD");
|
|
2913
|
+
if (field?.componentType === "dateRange" && Array.isArray(value)) return value.filter((v) => import_dayjs_min.default.isDayjs(v)).map((v) => v.format("YYYY-MM-DD")).join(", ");
|
|
2914
|
+
const colorLike = value;
|
|
2915
|
+
if (colorLike && typeof colorLike === "object" && typeof colorLike.toHexString === "function") return colorLike.toHexString();
|
|
2916
|
+
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
2917
|
+
return String(value);
|
|
2918
|
+
}
|
|
1115
2919
|
/**
|
|
1116
2920
|
* 属性编辑弹窗组件
|
|
1117
2921
|
* 根据组件 schema 的 renderDialog 函数渲染弹窗内容
|
|
@@ -1120,55 +2924,79 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
|
|
|
1120
2924
|
const schema = componentRegistry.get(typeName);
|
|
1121
2925
|
const [formProps, setFormProps] = (0, react.useState)({});
|
|
1122
2926
|
const [form] = antd.Form.useForm();
|
|
2927
|
+
const onSaveRef = (0, react.useRef)(onSave);
|
|
2928
|
+
onSaveRef.current = onSave;
|
|
2929
|
+
const dirtyRef = (0, react.useRef)(false);
|
|
1123
2930
|
const mergedProps = (0, react.useMemo)(() => {
|
|
1124
2931
|
if (!schema) return currentProps;
|
|
1125
|
-
const
|
|
1126
|
-
for (const field of schema.fields || [])
|
|
2932
|
+
const merged = {};
|
|
2933
|
+
for (const field of schema.fields || []) if (field.defaultValue !== void 0) merged[field.key] = field.defaultValue;
|
|
1127
2934
|
return {
|
|
1128
|
-
...
|
|
2935
|
+
...merged,
|
|
1129
2936
|
...currentProps
|
|
1130
2937
|
};
|
|
1131
2938
|
}, [schema, currentProps]);
|
|
1132
2939
|
(0, react.useEffect)(() => {
|
|
1133
2940
|
if (visible) {
|
|
1134
|
-
form.setFieldsValue(mergedProps);
|
|
1135
2941
|
setFormProps({});
|
|
2942
|
+
const initial = {};
|
|
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);
|
|
2949
|
+
dirtyRef.current = false;
|
|
1136
2950
|
}
|
|
1137
|
-
}, [
|
|
1138
|
-
visible,
|
|
1139
|
-
mergedProps,
|
|
1140
|
-
form
|
|
1141
|
-
]);
|
|
2951
|
+
}, [visible, form]);
|
|
1142
2952
|
const handleDialogChange = (key, value) => {
|
|
1143
2953
|
setFormProps((prev) => ({
|
|
1144
2954
|
...prev,
|
|
1145
2955
|
[key]: value
|
|
1146
2956
|
}));
|
|
2957
|
+
dirtyRef.current = true;
|
|
1147
2958
|
};
|
|
1148
2959
|
const handleOk = async () => {
|
|
1149
|
-
let finalProps = visible ? {
|
|
1150
|
-
...mergedProps,
|
|
1151
|
-
...formProps
|
|
1152
|
-
} : mergedProps;
|
|
1153
2960
|
try {
|
|
1154
2961
|
const formValues = await form.validateFields();
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
2962
|
+
for (const [key, value] of Object.entries(formValues)) formProps[key] = value;
|
|
2963
|
+
} catch {
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2966
|
+
const finalProps = {};
|
|
2967
|
+
for (const [key, value] of Object.entries({
|
|
2968
|
+
...mergedProps,
|
|
2969
|
+
...formProps
|
|
2970
|
+
})) {
|
|
2971
|
+
const field = schema?.fields?.find((f) => f.key === key);
|
|
2972
|
+
finalProps[key] = normalizeValue(field, value);
|
|
2973
|
+
}
|
|
2974
|
+
onSaveRef.current(finalProps);
|
|
2975
|
+
dirtyRef.current = false;
|
|
2976
|
+
onClose();
|
|
1161
2977
|
};
|
|
1162
2978
|
const handleClose = () => {
|
|
2979
|
+
if (dirtyRef.current && !window.confirm("属性修改尚未保存,确定关闭吗?")) return;
|
|
1163
2980
|
setFormProps({});
|
|
2981
|
+
dirtyRef.current = false;
|
|
1164
2982
|
onClose();
|
|
1165
2983
|
};
|
|
1166
2984
|
if (!schema) return null;
|
|
2985
|
+
const contextSave = (props) => {
|
|
2986
|
+
setFormProps((prev) => ({
|
|
2987
|
+
...prev,
|
|
2988
|
+
...props
|
|
2989
|
+
}));
|
|
2990
|
+
dirtyRef.current = true;
|
|
2991
|
+
};
|
|
1167
2992
|
const context = {
|
|
1168
|
-
props:
|
|
2993
|
+
props: {
|
|
2994
|
+
...mergedProps,
|
|
2995
|
+
...formProps
|
|
2996
|
+
},
|
|
1169
2997
|
form,
|
|
1170
2998
|
onChange: handleDialogChange,
|
|
1171
|
-
onSave
|
|
2999
|
+
onSave: contextSave
|
|
1172
3000
|
};
|
|
1173
3001
|
const renderDialogContent = () => {
|
|
1174
3002
|
if (schema.renderDialog) return schema.renderDialog(context);
|
|
@@ -1188,36 +3016,46 @@ function EditDialog({ visible, typeName, currentProps, onSave, onClose }) {
|
|
|
1188
3016
|
//#endregion
|
|
1189
3017
|
//#region src/utils/writeContainer.ts
|
|
1190
3018
|
/**
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
3019
|
+
* 从属性对象生成属性行。
|
|
3020
|
+
* 使用 JSON5 序列化:单引号风格与旧格式兼容,特殊字符会被正确转义,
|
|
3021
|
+
* 配合 parseContainerProps 保证读写往返无损。
|
|
1193
3022
|
*/
|
|
1194
3023
|
function writeContainerProps(props) {
|
|
1195
|
-
|
|
1196
|
-
return entries ? `{ ${entries} }` : "{}";
|
|
3024
|
+
return import_dist.default.stringify(props) ?? "{}";
|
|
1197
3025
|
}
|
|
1198
3026
|
/**
|
|
1199
3027
|
* 更新编辑器文档中的容器属性。
|
|
1200
|
-
*
|
|
3028
|
+
* 已有属性行则整行替换;没有属性行则在容器头行后插入一行。
|
|
3029
|
+
* @param headerPos 容器头行(:::type)任意位置,用于无属性行时定位插入点
|
|
1201
3030
|
*/
|
|
1202
|
-
function updateContainerProps(view, propsLineFrom, propsLineTo, newProps) {
|
|
3031
|
+
function updateContainerProps(view, headerPos, propsLineFrom, propsLineTo, newProps) {
|
|
1203
3032
|
const newPropsLine = writeContainerProps(newProps);
|
|
1204
|
-
view.dispatch({ changes: {
|
|
3033
|
+
if (propsLineTo > propsLineFrom) view.dispatch({ changes: {
|
|
1205
3034
|
from: propsLineFrom,
|
|
1206
3035
|
to: propsLineTo,
|
|
1207
3036
|
insert: newPropsLine
|
|
1208
3037
|
} });
|
|
3038
|
+
else {
|
|
3039
|
+
const headerLine = view.state.doc.lineAt(headerPos);
|
|
3040
|
+
view.dispatch({ changes: {
|
|
3041
|
+
from: headerLine.to,
|
|
3042
|
+
insert: `\n${newPropsLine}`
|
|
3043
|
+
} });
|
|
3044
|
+
}
|
|
1209
3045
|
}
|
|
1210
3046
|
/**
|
|
1211
3047
|
* 在当前光标位置插入新容器。
|
|
1212
|
-
* 创建 :::type 打开行 +
|
|
3048
|
+
* 创建 :::type 打开行 + 属性行 + ::: 关闭行的结构。
|
|
1213
3049
|
*/
|
|
1214
3050
|
function insertContainer(view, typeName, defaultProps) {
|
|
1215
3051
|
const { from } = view.state.selection.main;
|
|
1216
|
-
const
|
|
3052
|
+
const propsLine = writeContainerProps(defaultProps);
|
|
3053
|
+
const container = `\n:::${typeName}\n${propsLine}\n:::\n`;
|
|
1217
3054
|
view.dispatch({ changes: {
|
|
1218
3055
|
from,
|
|
1219
3056
|
insert: container
|
|
1220
3057
|
} });
|
|
3058
|
+
view.dispatch({ selection: { anchor: from + `\n:::${typeName}\n${propsLine}\n`.length } });
|
|
1221
3059
|
}
|
|
1222
3060
|
//#endregion
|
|
1223
3061
|
//#region src/hooks/useFullscreen.ts
|
|
@@ -1254,145 +3092,190 @@ function useFullscreen() {
|
|
|
1254
3092
|
//#endregion
|
|
1255
3093
|
//#region src/hooks/useScrollSync.ts
|
|
1256
3094
|
/**
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
3095
|
+
* 双向滚动同步 Hook
|
|
3096
|
+
* 编辑器与预览区互相同步滚动位置(基于比例)
|
|
3097
|
+
* 使用 syncing 锁防止双向循环触发
|
|
3098
|
+
*
|
|
3099
|
+
* 直接接收滚动容器元素(而非 ref):元素变化时 effect 重新执行并重新绑定监听,
|
|
3100
|
+
* 避免"挂载时容器尚未就绪 / 编辑器 view 被重建"导致监听永久失效或绑到旧节点。
|
|
1259
3101
|
*/
|
|
1260
|
-
function useScrollSync(
|
|
3102
|
+
function useScrollSync(source, target) {
|
|
1261
3103
|
const rafIdRef = (0, react.useRef)(null);
|
|
3104
|
+
const syncingRef = (0, react.useRef)(null);
|
|
3105
|
+
const syncScroll = (from, fromEl, toEl) => {
|
|
3106
|
+
if (rafIdRef.current) return;
|
|
3107
|
+
rafIdRef.current = requestAnimationFrame(() => {
|
|
3108
|
+
const fromScrollHeight = fromEl.scrollHeight - fromEl.clientHeight;
|
|
3109
|
+
if (fromScrollHeight <= 0) {
|
|
3110
|
+
rafIdRef.current = null;
|
|
3111
|
+
syncingRef.current = null;
|
|
3112
|
+
return;
|
|
3113
|
+
}
|
|
3114
|
+
const ratio = fromEl.scrollTop / fromScrollHeight;
|
|
3115
|
+
const toScrollHeight = toEl.scrollHeight - toEl.clientHeight;
|
|
3116
|
+
if (toScrollHeight > 0) {
|
|
3117
|
+
syncingRef.current = from;
|
|
3118
|
+
toEl.scrollTop = ratio * toScrollHeight;
|
|
3119
|
+
requestAnimationFrame(() => {
|
|
3120
|
+
syncingRef.current = null;
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3123
|
+
rafIdRef.current = null;
|
|
3124
|
+
});
|
|
3125
|
+
};
|
|
1262
3126
|
(0, react.useEffect)(() => {
|
|
1263
|
-
const source = sourceRef.current;
|
|
1264
|
-
const target = targetRef.current;
|
|
1265
3127
|
if (!source || !target) return;
|
|
1266
|
-
const
|
|
1267
|
-
if (
|
|
1268
|
-
|
|
1269
|
-
const s = sourceRef.current;
|
|
1270
|
-
const t = targetRef.current;
|
|
1271
|
-
if (!s || !t) {
|
|
1272
|
-
rafIdRef.current = null;
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
const sourceScrollHeight = s.scrollHeight - s.clientHeight;
|
|
1276
|
-
if (sourceScrollHeight <= 0) {
|
|
1277
|
-
rafIdRef.current = null;
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
const ratio = s.scrollTop / sourceScrollHeight;
|
|
1281
|
-
const targetScrollHeight = t.scrollHeight - t.clientHeight;
|
|
1282
|
-
if (targetScrollHeight > 0) t.scrollTop = ratio * targetScrollHeight;
|
|
1283
|
-
rafIdRef.current = null;
|
|
1284
|
-
});
|
|
3128
|
+
const onSourceScroll = () => {
|
|
3129
|
+
if (syncingRef.current !== null) return;
|
|
3130
|
+
syncScroll("source", source, target);
|
|
1285
3131
|
};
|
|
1286
|
-
|
|
3132
|
+
const onTargetScroll = () => {
|
|
3133
|
+
if (syncingRef.current !== null) return;
|
|
3134
|
+
syncScroll("target", target, source);
|
|
3135
|
+
};
|
|
3136
|
+
source.addEventListener("scroll", onSourceScroll, { passive: true });
|
|
3137
|
+
target.addEventListener("scroll", onTargetScroll, { passive: true });
|
|
1287
3138
|
return () => {
|
|
1288
|
-
source.removeEventListener("scroll",
|
|
1289
|
-
|
|
3139
|
+
source.removeEventListener("scroll", onSourceScroll);
|
|
3140
|
+
target.removeEventListener("scroll", onTargetScroll);
|
|
3141
|
+
if (rafIdRef.current) {
|
|
3142
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
3143
|
+
rafIdRef.current = null;
|
|
3144
|
+
}
|
|
3145
|
+
syncingRef.current = null;
|
|
1290
3146
|
};
|
|
1291
|
-
}, [
|
|
3147
|
+
}, [source, target]);
|
|
1292
3148
|
}
|
|
1293
3149
|
//#endregion
|
|
1294
3150
|
//#region src/MarkdownEditor.tsx
|
|
1295
|
-
|
|
3151
|
+
/** 订阅注册中心版本,注册变化时触发重渲染 */
|
|
3152
|
+
function useRegistryVersion() {
|
|
3153
|
+
const subscribe = (0, react.useCallback)((onChange) => componentRegistry.subscribe(onChange), []);
|
|
3154
|
+
const getSnapshot = (0, react.useCallback)(() => componentRegistry.getVersion(), []);
|
|
3155
|
+
return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
3156
|
+
}
|
|
3157
|
+
var MarkdownEditorInner = ({ defaultValue = "", value, onChange, showPreview = true, fullscreen: fullscreenProp = true, previewOptions, uploadConfig, schemas, onNotify }, ref) => {
|
|
1296
3158
|
const [content, setContent] = (0, react.useState)(value ?? defaultValue);
|
|
1297
3159
|
const [editorView, setEditorView] = (0, react.useState)(null);
|
|
1298
|
-
const
|
|
1299
|
-
const
|
|
3160
|
+
const [scrollDOM, setScrollDOM] = (0, react.useState)(null);
|
|
3161
|
+
const [previewEl, setPreviewEl] = (0, react.useState)(null);
|
|
1300
3162
|
const { fullscreen, toggleFullscreen } = useFullscreen();
|
|
1301
|
-
useScrollSync(
|
|
3163
|
+
useScrollSync(scrollDOM, previewEl);
|
|
1302
3164
|
const [dialogVisible, setDialogVisible] = (0, react.useState)(false);
|
|
1303
3165
|
const [dialogTypeName, setDialogTypeName] = (0, react.useState)("");
|
|
1304
|
-
const [
|
|
1305
|
-
const
|
|
3166
|
+
const [dialogContainer, setDialogContainer] = (0, react.useState)(null);
|
|
3167
|
+
const app = antd.App.useApp();
|
|
3168
|
+
const notify = (0, react.useCallback)((type, text) => {
|
|
3169
|
+
if (onNotify) {
|
|
3170
|
+
onNotify(type, text);
|
|
3171
|
+
return;
|
|
3172
|
+
}
|
|
3173
|
+
(app?.message ?? antd.message)[type](text);
|
|
3174
|
+
}, [onNotify, app]);
|
|
3175
|
+
const lastEmittedRef = (0, react.useRef)(void 0);
|
|
1306
3176
|
(0, react.useEffect)(() => {
|
|
1307
|
-
if (value !== void 0) setContent(value);
|
|
3177
|
+
if (value !== void 0 && value !== lastEmittedRef.current) setContent(value);
|
|
1308
3178
|
}, [value]);
|
|
1309
3179
|
const internalSetContent = (0, react.useCallback)((newContent) => {
|
|
1310
3180
|
setContent(newContent);
|
|
3181
|
+
lastEmittedRef.current = newContent;
|
|
1311
3182
|
onChange?.(newContent);
|
|
1312
3183
|
}, [onChange]);
|
|
1313
3184
|
(0, react.useImperativeHandle)(ref, () => ({ getContent: () => content }), [content]);
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
3185
|
+
const registryVersion = useRegistryVersion();
|
|
3186
|
+
const extraToolbarItems = (0, react.useMemo)(() => {
|
|
3187
|
+
const merged = /* @__PURE__ */ new Map();
|
|
3188
|
+
for (const schema of componentRegistry.getAll()) merged.set(schema.name, schema);
|
|
3189
|
+
for (const schema of schemas ?? []) merged.set(schema.name, schema);
|
|
3190
|
+
return [...merged.values()].flatMap((schema) => {
|
|
3191
|
+
if (schema.wrapTags) return {
|
|
3192
|
+
id: `wrap-${schema.name}`,
|
|
3193
|
+
label: schema.label,
|
|
3194
|
+
icon: schema.icon ?? _ant_design_icons.ReadOutlined,
|
|
3195
|
+
wrapTags: schema.wrapTags
|
|
3196
|
+
};
|
|
3197
|
+
const defaultProps = {};
|
|
3198
|
+
for (const field of schema.fields ?? []) if (field.defaultValue !== void 0) defaultProps[field.key] = field.defaultValue;
|
|
3199
|
+
return {
|
|
3200
|
+
id: `container-${schema.name}`,
|
|
3201
|
+
label: schema.label,
|
|
3202
|
+
icon: schema.icon ?? _ant_design_icons.ReadOutlined,
|
|
3203
|
+
handler: (view) => insertContainer(view, schema.name, defaultProps)
|
|
3204
|
+
};
|
|
3205
|
+
});
|
|
3206
|
+
}, [registryVersion, schemas]);
|
|
3207
|
+
const handleScrollReady = (0, react.useCallback)((dom) => {
|
|
3208
|
+
setScrollDOM(dom);
|
|
1332
3209
|
}, []);
|
|
1333
3210
|
const handlePreviewRef = (0, react.useCallback)((node) => {
|
|
1334
|
-
|
|
3211
|
+
setPreviewEl(node);
|
|
1335
3212
|
}, []);
|
|
1336
3213
|
const handleViewReady = (0, react.useCallback)((view) => {
|
|
1337
3214
|
setEditorView(view);
|
|
1338
3215
|
}, []);
|
|
1339
|
-
const handleEditContainer = (0, react.useCallback)((_view,
|
|
1340
|
-
setDialogTypeName(typeName);
|
|
1341
|
-
|
|
1342
|
-
setDialogPropsRange([propsLineFrom, propsLineTo]);
|
|
3216
|
+
const handleEditContainer = (0, react.useCallback)((_view, container) => {
|
|
3217
|
+
setDialogTypeName(container.typeName);
|
|
3218
|
+
setDialogContainer(container);
|
|
1343
3219
|
setDialogVisible(true);
|
|
1344
3220
|
}, []);
|
|
1345
3221
|
const handleDialogSave = (0, react.useCallback)((newProps) => {
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}, [editorView, dialogPropsRange]);
|
|
3222
|
+
if (editorView && dialogContainer) updateContainerProps(editorView, dialogContainer.startPos, dialogContainer.propsLineFrom, dialogContainer.propsLineTo, newProps);
|
|
3223
|
+
}, [editorView, dialogContainer]);
|
|
1349
3224
|
const handleDialogClose = (0, react.useCallback)(() => {
|
|
1350
3225
|
setDialogVisible(false);
|
|
1351
3226
|
}, []);
|
|
3227
|
+
const editorNode = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Editor, {
|
|
3228
|
+
value: content,
|
|
3229
|
+
onChange: internalSetContent,
|
|
3230
|
+
onScrollReady: handleScrollReady,
|
|
3231
|
+
onViewReady: handleViewReady,
|
|
3232
|
+
onEditContainer: handleEditContainer,
|
|
3233
|
+
uploadConfig,
|
|
3234
|
+
onMessageNoUploadConfig: () => notify("warning", "请先配置图片上传功能")
|
|
3235
|
+
});
|
|
1352
3236
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1353
3237
|
className: fullscreen ? "markdown-editor-app fullscreen" : "markdown-editor-app",
|
|
1354
3238
|
children: [
|
|
1355
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3239
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toolbar_default, {
|
|
1356
3240
|
editorView,
|
|
1357
3241
|
fullscreen,
|
|
1358
3242
|
onToggleFullscreen: fullscreenProp ? toggleFullscreen : void 0,
|
|
1359
3243
|
extraItems: extraToolbarItems,
|
|
1360
|
-
uploadConfig
|
|
3244
|
+
uploadConfig,
|
|
3245
|
+
notify
|
|
1361
3246
|
}),
|
|
1362
3247
|
showPreview ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SplitPanels, {
|
|
1363
|
-
leftPanel:
|
|
1364
|
-
|
|
1365
|
-
onChange: internalSetContent,
|
|
1366
|
-
onScrollReady: handleScrollReady,
|
|
1367
|
-
onViewReady: handleViewReady,
|
|
1368
|
-
onEditContainer: handleEditContainer,
|
|
1369
|
-
uploadConfig,
|
|
1370
|
-
onMessageNoUploadConfig: () => antd.message.warning("请先配置图片上传功能")
|
|
1371
|
-
}),
|
|
1372
|
-
rightPanel: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Preview, {
|
|
3248
|
+
leftPanel: editorNode,
|
|
3249
|
+
rightPanel: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Preview_default, {
|
|
1373
3250
|
content,
|
|
1374
3251
|
ref: handlePreviewRef,
|
|
1375
3252
|
previewOptions
|
|
1376
3253
|
})
|
|
1377
|
-
}) :
|
|
1378
|
-
value: content,
|
|
1379
|
-
onChange: internalSetContent,
|
|
1380
|
-
onScrollReady: handleScrollReady,
|
|
1381
|
-
onViewReady: handleViewReady,
|
|
1382
|
-
onEditContainer: handleEditContainer,
|
|
1383
|
-
uploadConfig,
|
|
1384
|
-
onMessageNoUploadConfig: () => antd.message.warning("请先配置图片上传功能")
|
|
1385
|
-
}),
|
|
3254
|
+
}) : editorNode,
|
|
1386
3255
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditDialog, {
|
|
1387
3256
|
visible: dialogVisible,
|
|
1388
3257
|
typeName: dialogTypeName,
|
|
1389
|
-
currentProps:
|
|
3258
|
+
currentProps: dialogContainer?.props ?? {},
|
|
1390
3259
|
onSave: handleDialogSave,
|
|
1391
3260
|
onClose: handleDialogClose
|
|
1392
3261
|
})
|
|
1393
3262
|
]
|
|
1394
3263
|
});
|
|
1395
|
-
}
|
|
3264
|
+
};
|
|
3265
|
+
var MarkdownEditor = (0, react.forwardRef)(MarkdownEditorInner);
|
|
3266
|
+
/**
|
|
3267
|
+
* 包一层 antd App:为库内部的 message 等反馈组件提供上下文;
|
|
3268
|
+
* 宿主已有 App 包裹时内层仅作兜底(component={false} 不额外渲染 DOM)。
|
|
3269
|
+
*/
|
|
3270
|
+
function MarkdownEditorWithApp({ ref, ...props }) {
|
|
3271
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.App, {
|
|
3272
|
+
component: false,
|
|
3273
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownEditor, {
|
|
3274
|
+
...props,
|
|
3275
|
+
ref
|
|
3276
|
+
})
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
1396
3279
|
//#endregion
|
|
1397
3280
|
//#region src/hooks/useRegisterToolbar.ts
|
|
1398
3281
|
/**
|
|
@@ -1489,14 +3372,17 @@ var MarkdownEditor_default = (0, react.forwardRef)(function MarkdownEditor({ def
|
|
|
1489
3372
|
* @example 批量注册
|
|
1490
3373
|
* ```tsx
|
|
1491
3374
|
* function MyPage() {
|
|
3375
|
+
* // 注意:schema 需声明为稳定引用(组件外常量或 useMemo),
|
|
3376
|
+
* // 否则每次渲染都会重新注册;多实例互不干扰的场景请改用
|
|
3377
|
+
* // <MarkdownEditor schemas={[...]} /> 局部注册
|
|
1492
3378
|
* useRegisterToolbar([schema1, schema2, schema3])
|
|
1493
3379
|
* return <MarkdownEditor />
|
|
1494
3380
|
* }
|
|
1495
3381
|
* ```
|
|
1496
3382
|
*/
|
|
1497
3383
|
function useRegisterToolbar(schemas) {
|
|
1498
|
-
const schemaList = Array.isArray(schemas) ? schemas : [schemas];
|
|
1499
3384
|
(0, react.useEffect)(() => {
|
|
3385
|
+
const schemaList = Array.isArray(schemas) ? schemas : [schemas];
|
|
1500
3386
|
schemaList.forEach((schema) => {
|
|
1501
3387
|
componentRegistry.register(schema.name, schema);
|
|
1502
3388
|
});
|
|
@@ -1505,10 +3391,12 @@ function useRegisterToolbar(schemas) {
|
|
|
1505
3391
|
componentRegistry.unregister(schema.name);
|
|
1506
3392
|
});
|
|
1507
3393
|
};
|
|
1508
|
-
}, [
|
|
3394
|
+
}, [schemas]);
|
|
1509
3395
|
}
|
|
1510
3396
|
//#endregion
|
|
1511
|
-
exports.MarkdownEditor =
|
|
3397
|
+
exports.MarkdownEditor = MarkdownEditorWithApp;
|
|
3398
|
+
exports.getIconfontScriptUrl = getIconfontScriptUrl;
|
|
3399
|
+
exports.setIconfontScriptUrl = setIconfontScriptUrl;
|
|
1512
3400
|
exports.useRegisterToolbar = useRegisterToolbar;
|
|
1513
3401
|
|
|
1514
3402
|
//# sourceMappingURL=index.cjs.map
|