@block-kit/react 1.0.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/es/hooks/use-editor.d.ts +21 -0
- package/dist/es/hooks/use-editor.js +26 -0
- package/dist/es/hooks/use-readonly.d.ts +5 -0
- package/dist/es/hooks/use-readonly.js +6 -0
- package/dist/es/index.d.ts +18 -0
- package/dist/es/index.js +17 -0
- package/dist/es/model/block.d.ts +7 -0
- package/dist/es/model/block.js +142 -0
- package/dist/es/model/eol.d.ts +6 -0
- package/dist/es/model/eol.js +18 -0
- package/dist/es/model/leaf.d.ts +7 -0
- package/dist/es/model/leaf.js +38 -0
- package/dist/es/model/line.d.ts +7 -0
- package/dist/es/model/line.js +152 -0
- package/dist/es/plugin/index.d.ts +25 -0
- package/dist/es/plugin/index.js +3 -0
- package/dist/es/plugin/modules/priority.d.ts +13 -0
- package/dist/es/plugin/modules/priority.js +26 -0
- package/dist/es/plugin/modules/wrap.d.ts +26 -0
- package/dist/es/plugin/modules/wrap.js +72 -0
- package/dist/es/plugin/types/index.d.ts +35 -0
- package/dist/es/plugin/types/index.js +7 -0
- package/dist/es/preset/block-kit.d.ts +6 -0
- package/dist/es/preset/block-kit.js +17 -0
- package/dist/es/preset/editable.d.ts +16 -0
- package/dist/es/preset/editable.js +42 -0
- package/dist/es/preset/embed.d.ts +14 -0
- package/dist/es/preset/embed.js +23 -0
- package/dist/es/preset/isolate.d.ts +12 -0
- package/dist/es/preset/isolate.js +10 -0
- package/dist/es/preset/text.d.ts +9 -0
- package/dist/es/preset/text.js +34 -0
- package/dist/es/preset/void.d.ts +14 -0
- package/dist/es/preset/void.js +23 -0
- package/dist/es/preset/zero.d.ts +23 -0
- package/dist/es/preset/zero.js +20 -0
- package/dist/es/utils/constant.d.ts +2 -0
- package/dist/es/utils/constant.js +6 -0
- package/dist/es/utils/event.d.ts +2 -0
- package/dist/es/utils/event.js +7 -0
- package/dist/es/utils/is.d.ts +2 -0
- package/dist/es/utils/is.js +12 -0
- package/dist/es/utils/weak-map.d.ts +17 -0
- package/dist/es/utils/weak-map.js +15 -0
- package/dist/es/utils/wrapper.d.ts +7 -0
- package/dist/es/utils/wrapper.js +25 -0
- package/dist/lib/hooks/use-editor.d.ts +21 -0
- package/dist/lib/hooks/use-editor.js +53 -0
- package/dist/lib/hooks/use-readonly.d.ts +5 -0
- package/dist/lib/hooks/use-readonly.js +33 -0
- package/dist/lib/index.d.ts +18 -0
- package/dist/lib/index.js +40 -0
- package/dist/lib/model/block.d.ts +7 -0
- package/dist/lib/model/block.js +168 -0
- package/dist/lib/model/eol.d.ts +6 -0
- package/dist/lib/model/eol.js +24 -0
- package/dist/lib/model/leaf.d.ts +7 -0
- package/dist/lib/model/leaf.js +64 -0
- package/dist/lib/model/line.d.ts +7 -0
- package/dist/lib/model/line.js +178 -0
- package/dist/lib/plugin/index.d.ts +25 -0
- package/dist/lib/plugin/index.js +7 -0
- package/dist/lib/plugin/modules/priority.d.ts +13 -0
- package/dist/lib/plugin/modules/priority.js +31 -0
- package/dist/lib/plugin/modules/wrap.d.ts +26 -0
- package/dist/lib/plugin/modules/wrap.js +78 -0
- package/dist/lib/plugin/types/index.d.ts +35 -0
- package/dist/lib/plugin/types/index.js +10 -0
- package/dist/lib/preset/block-kit.d.ts +6 -0
- package/dist/lib/preset/block-kit.js +21 -0
- package/dist/lib/preset/editable.d.ts +16 -0
- package/dist/lib/preset/editable.js +46 -0
- package/dist/lib/preset/embed.d.ts +14 -0
- package/dist/lib/preset/embed.js +30 -0
- package/dist/lib/preset/isolate.d.ts +12 -0
- package/dist/lib/preset/isolate.js +14 -0
- package/dist/lib/preset/text.d.ts +9 -0
- package/dist/lib/preset/text.js +37 -0
- package/dist/lib/preset/void.d.ts +14 -0
- package/dist/lib/preset/void.js +30 -0
- package/dist/lib/preset/zero.d.ts +23 -0
- package/dist/lib/preset/zero.js +23 -0
- package/dist/lib/utils/constant.d.ts +2 -0
- package/dist/lib/utils/constant.js +9 -0
- package/dist/lib/utils/event.d.ts +2 -0
- package/dist/lib/utils/event.js +12 -0
- package/dist/lib/utils/is.d.ts +2 -0
- package/dist/lib/utils/is.js +16 -0
- package/dist/lib/utils/weak-map.d.ts +17 -0
- package/dist/lib/utils/weak-map.js +18 -0
- package/dist/lib/utils/wrapper.d.ts +7 -0
- package/dist/lib/utils/wrapper.js +29 -0
- package/package.json +38 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.BlockModel = void 0;
|
|
27
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
+
const core_1 = require("@block-kit/core");
|
|
29
|
+
const hooks_1 = require("@block-kit/utils/dist/es/hooks");
|
|
30
|
+
const react_1 = __importStar(require("react"));
|
|
31
|
+
const wrap_1 = require("../plugin/modules/wrap");
|
|
32
|
+
const is_1 = require("../utils/is");
|
|
33
|
+
const weak_map_1 = require("../utils/weak-map");
|
|
34
|
+
const wrapper_1 = require("../utils/wrapper");
|
|
35
|
+
const line_1 = require("./line");
|
|
36
|
+
/**
|
|
37
|
+
* Block Model
|
|
38
|
+
* @param props
|
|
39
|
+
*/
|
|
40
|
+
const BlockView = props => {
|
|
41
|
+
const { editor, state } = props;
|
|
42
|
+
const flushing = (0, react_1.useRef)(false);
|
|
43
|
+
const [lines, setLines] = (0, react_1.useState)(() => state.getLines());
|
|
44
|
+
/**
|
|
45
|
+
* 设置行 DOM 节点
|
|
46
|
+
*/
|
|
47
|
+
const setModel = (ref) => {
|
|
48
|
+
if (ref) {
|
|
49
|
+
editor.model.setBlockModel(ref, state);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* 数据同步变更, 异步批量绘制变更
|
|
54
|
+
*/
|
|
55
|
+
const onContentChange = (0, hooks_1.useMemoFn)(() => {
|
|
56
|
+
// 举个例子: 同步等待刷新的队列 => ||||||||
|
|
57
|
+
// 进入更新行为后, 异步行为等待, 同步的队列由于 !flushing 全部被守卫
|
|
58
|
+
// 主线程执行完毕后, 异步队列开始执行, 此时拿到的是最新数据, 以此批量重新渲染
|
|
59
|
+
if (flushing.current)
|
|
60
|
+
return void 0;
|
|
61
|
+
flushing.current = true;
|
|
62
|
+
Promise.resolve().then(() => {
|
|
63
|
+
flushing.current = false;
|
|
64
|
+
setLines(state.getLines());
|
|
65
|
+
editor.state.set(core_1.EDITOR_STATE.PAINTING, true);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* 监听内容变更事件, 更新当前块视图
|
|
70
|
+
*/
|
|
71
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
72
|
+
editor.event.on(core_1.EDITOR_EVENT.CONTENT_CHANGE, onContentChange);
|
|
73
|
+
return () => {
|
|
74
|
+
editor.event.off(core_1.EDITOR_EVENT.CONTENT_CHANGE, onContentChange);
|
|
75
|
+
};
|
|
76
|
+
}, [editor.event, onContentChange]);
|
|
77
|
+
/**
|
|
78
|
+
* 视图更新需要重新设置选区 无依赖数组
|
|
79
|
+
*/
|
|
80
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
81
|
+
const selection = editor.selection.get();
|
|
82
|
+
if (!editor.state.get(core_1.EDITOR_STATE.COMPOSING) &&
|
|
83
|
+
editor.state.get(core_1.EDITOR_STATE.FOCUS) &&
|
|
84
|
+
selection) {
|
|
85
|
+
// 更新浏览器选区
|
|
86
|
+
editor.logger.debug("UpdateDOMSelection");
|
|
87
|
+
editor.selection.updateDOMSelection(true);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* 视图更新需要触发视图绘制完成事件 无依赖数组
|
|
92
|
+
* state -> parent -> node -> child ->|
|
|
93
|
+
* effect <- parent <- node <- child <-|
|
|
94
|
+
*/
|
|
95
|
+
(0, react_1.useEffect)(() => {
|
|
96
|
+
editor.logger.debug("OnPaint");
|
|
97
|
+
editor.state.set(core_1.EDITOR_STATE.PAINTING, false);
|
|
98
|
+
Promise.resolve().then(() => {
|
|
99
|
+
editor.event.trigger(core_1.EDITOR_EVENT.PAINT, {});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
/**
|
|
103
|
+
* 处理行节点
|
|
104
|
+
*/
|
|
105
|
+
const elements = (0, react_1.useMemo)(() => {
|
|
106
|
+
return lines.map((line, index) => {
|
|
107
|
+
const node = ((0, jsx_runtime_1.jsx)(line_1.LineModel, { editor: editor, lineState: line, index: index }, line.key));
|
|
108
|
+
weak_map_1.JSX_TO_STATE.set(node, line);
|
|
109
|
+
return node;
|
|
110
|
+
});
|
|
111
|
+
}, [editor, lines]);
|
|
112
|
+
/**
|
|
113
|
+
* 将行包装组合 O(N)
|
|
114
|
+
*/
|
|
115
|
+
const children = (0, react_1.useMemo)(() => {
|
|
116
|
+
const wrapped = [];
|
|
117
|
+
const keys = wrap_1.EDITOR_TO_WRAP_LINE_KEYS.get(editor);
|
|
118
|
+
const plugins = wrap_1.EDITOR_TO_WRAP_LINE_PLUGINS.get(editor);
|
|
119
|
+
if (!keys || !plugins)
|
|
120
|
+
return elements;
|
|
121
|
+
const len = elements.length;
|
|
122
|
+
for (let i = 0; i < len; ++i) {
|
|
123
|
+
const element = elements[i];
|
|
124
|
+
const symbol = (0, wrapper_1.getWrapSymbol)(keys, element);
|
|
125
|
+
const line = weak_map_1.JSX_TO_STATE.get(element);
|
|
126
|
+
if (!element || !line || !symbol) {
|
|
127
|
+
wrapped.push(element);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// 执行到此处说明需要包装相关节点(即使仅单个节点)
|
|
131
|
+
const nodes = [element];
|
|
132
|
+
for (let k = i + 1; k < len; ++k) {
|
|
133
|
+
const next = elements[k];
|
|
134
|
+
const nextSymbol = (0, wrapper_1.getWrapSymbol)(keys, next);
|
|
135
|
+
if (!next || !nextSymbol || nextSymbol !== symbol) {
|
|
136
|
+
// 回退到上一个值, 以便下次循环时重新检查
|
|
137
|
+
i = k - 1;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
nodes.push(next);
|
|
141
|
+
i = k;
|
|
142
|
+
}
|
|
143
|
+
// 通过插件渲染包装节点
|
|
144
|
+
let wrapper = nodes;
|
|
145
|
+
const op = line.op;
|
|
146
|
+
for (const plugin of plugins) {
|
|
147
|
+
// 这里的状态以首个节点为准
|
|
148
|
+
const context = {
|
|
149
|
+
lineState: line,
|
|
150
|
+
children: wrapper,
|
|
151
|
+
};
|
|
152
|
+
if (plugin.match(line.op.attributes || {}, op) && plugin.wrapLine) {
|
|
153
|
+
wrapper = plugin.wrapLine(context);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const key = `${i - nodes.length + 1}-${i}`;
|
|
157
|
+
wrapped.push((0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: wrapper }, key));
|
|
158
|
+
}
|
|
159
|
+
return wrapped;
|
|
160
|
+
}, [editor, elements]);
|
|
161
|
+
return ((0, jsx_runtime_1.jsxs)("div", { [core_1.BLOCK_KEY]: true, [core_1.BLOCK_ID_KEY]: state.key, ref: setModel, children: [props.placeholder && lines.length === 1 && (0, is_1.isStrictEmptyLine)(lines[0]) && ((0, jsx_runtime_1.jsx)("div", { [core_1.PLACEHOLDER_KEY]: true, style: {
|
|
162
|
+
position: "absolute",
|
|
163
|
+
opacity: "0.3",
|
|
164
|
+
userSelect: "none",
|
|
165
|
+
pointerEvents: "none",
|
|
166
|
+
}, children: props.placeholder })), children] }));
|
|
167
|
+
};
|
|
168
|
+
exports.BlockModel = react_1.default.memo(BlockView);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EOLModel = void 0;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const core_1 = require("@block-kit/core");
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
10
|
+
const zero_1 = require("../preset/zero");
|
|
11
|
+
/**
|
|
12
|
+
* EOL Model
|
|
13
|
+
* @param props
|
|
14
|
+
*/
|
|
15
|
+
const EOLView = props => {
|
|
16
|
+
const { editor, leafState } = props;
|
|
17
|
+
const setModel = (ref) => {
|
|
18
|
+
if (ref) {
|
|
19
|
+
editor.model.setLeafModel(ref, leafState);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
return ((0, jsx_runtime_1.jsx)("span", { [core_1.LEAF_KEY]: true, ref: setModel, children: (0, jsx_runtime_1.jsx)(zero_1.ZeroSpace, { enter: true }) }));
|
|
23
|
+
};
|
|
24
|
+
exports.EOLModel = react_1.default.memo(EOLView);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.LeafModel = void 0;
|
|
27
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
+
const core_1 = require("@block-kit/core");
|
|
29
|
+
const react_1 = __importStar(require("react"));
|
|
30
|
+
const text_1 = require("../preset/text");
|
|
31
|
+
const weak_map_1 = require("../utils/weak-map");
|
|
32
|
+
/**
|
|
33
|
+
* Leaf Model
|
|
34
|
+
* @param props
|
|
35
|
+
*/
|
|
36
|
+
const LeafView = props => {
|
|
37
|
+
const { editor, leafState } = props;
|
|
38
|
+
const setModel = (ref) => {
|
|
39
|
+
if (ref) {
|
|
40
|
+
editor.model.setLeafModel(ref, leafState);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const runtime = (0, react_1.useMemo)(() => {
|
|
44
|
+
const text = leafState.getText();
|
|
45
|
+
const context = {
|
|
46
|
+
op: leafState.op,
|
|
47
|
+
classList: [],
|
|
48
|
+
lineState: leafState.parent,
|
|
49
|
+
leafState: leafState,
|
|
50
|
+
attributes: leafState.op.attributes,
|
|
51
|
+
style: {},
|
|
52
|
+
children: (0, jsx_runtime_1.jsx)(text_1.Text, { ref: el => weak_map_1.LEAF_TO_TEXT.set(leafState, el), children: text }),
|
|
53
|
+
};
|
|
54
|
+
const plugins = editor.plugin.getPriorityPlugins(core_1.PLUGIN_TYPE.RENDER_LEAF);
|
|
55
|
+
for (const plugin of plugins) {
|
|
56
|
+
if (plugin.match(context.attributes || {}, context.op)) {
|
|
57
|
+
context.children = plugin.renderLeaf(context);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return context;
|
|
61
|
+
}, [editor, leafState]);
|
|
62
|
+
return ((0, jsx_runtime_1.jsx)("span", { [core_1.LEAF_KEY]: true, ref: setModel, className: runtime.classList.join(" "), style: runtime.style, children: runtime.children }));
|
|
63
|
+
};
|
|
64
|
+
exports.LeafModel = react_1.default.memo(LeafView);
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.LineModel = void 0;
|
|
27
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
+
const core_1 = require("@block-kit/core");
|
|
29
|
+
const delta_1 = require("@block-kit/delta");
|
|
30
|
+
const utils_1 = require("@block-kit/utils");
|
|
31
|
+
const hooks_1 = require("@block-kit/utils/dist/es/hooks");
|
|
32
|
+
const react_1 = __importStar(require("react"));
|
|
33
|
+
const wrap_1 = require("../plugin/modules/wrap");
|
|
34
|
+
const weak_map_1 = require("../utils/weak-map");
|
|
35
|
+
const wrapper_1 = require("../utils/wrapper");
|
|
36
|
+
const eol_1 = require("./eol");
|
|
37
|
+
const leaf_1 = require("./leaf");
|
|
38
|
+
/**
|
|
39
|
+
* Line Model
|
|
40
|
+
* @param props
|
|
41
|
+
*/
|
|
42
|
+
const LineView = props => {
|
|
43
|
+
const { editor, lineState } = props;
|
|
44
|
+
/**
|
|
45
|
+
* 设置行 DOM 节点
|
|
46
|
+
*/
|
|
47
|
+
const setModel = (ref) => {
|
|
48
|
+
if (ref) {
|
|
49
|
+
editor.model.setLineModel(ref, lineState);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* 首次处理会将所有 DOM 渲染, 不需要执行脏数据检查
|
|
54
|
+
* 需要 LayoutEffect 以保证 DOM -> Sel 的执行顺序
|
|
55
|
+
*/
|
|
56
|
+
(0, hooks_1.useUpdateLayoutEffect)(() => {
|
|
57
|
+
const leaves = lineState.getLeaves();
|
|
58
|
+
for (const leaf of leaves) {
|
|
59
|
+
const dom = weak_map_1.LEAF_TO_TEXT.get(leaf);
|
|
60
|
+
if (!dom)
|
|
61
|
+
continue;
|
|
62
|
+
const text = leaf.getText();
|
|
63
|
+
// 避免 React 非受控与 IME 造成的 DOM 内容问题
|
|
64
|
+
if (text === dom.textContent)
|
|
65
|
+
continue;
|
|
66
|
+
editor.logger.debug("Correct Text Node", dom);
|
|
67
|
+
const nodes = dom.childNodes;
|
|
68
|
+
for (let i = 1; i < nodes.length; ++i) {
|
|
69
|
+
const node = nodes[i];
|
|
70
|
+
node && node.remove();
|
|
71
|
+
}
|
|
72
|
+
if ((0, utils_1.isDOMText)(dom.firstChild)) {
|
|
73
|
+
dom.firstChild.nodeValue = text;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}, [lineState]);
|
|
77
|
+
/**
|
|
78
|
+
* 处理行内的节点
|
|
79
|
+
*/
|
|
80
|
+
const elements = (0, react_1.useMemo)(() => {
|
|
81
|
+
const leaves = lineState.getLeaves();
|
|
82
|
+
const textLeaves = leaves.slice(0, -1);
|
|
83
|
+
const nodes = textLeaves.map((n, i) => {
|
|
84
|
+
const node = (0, jsx_runtime_1.jsx)(leaf_1.LeafModel, { editor: editor, index: i, leafState: n }, i);
|
|
85
|
+
weak_map_1.JSX_TO_STATE.set(node, n);
|
|
86
|
+
return node;
|
|
87
|
+
});
|
|
88
|
+
// 空行则仅存在一个 Leaf, 此时需要渲染空的占位节点
|
|
89
|
+
if (!nodes.length && leaves[0]) {
|
|
90
|
+
const leaf = leaves[0];
|
|
91
|
+
const node = (0, jsx_runtime_1.jsx)(eol_1.EOLModel, { editor: editor, leafState: leaf }, delta_1.EOL);
|
|
92
|
+
weak_map_1.JSX_TO_STATE.set(node, leaf);
|
|
93
|
+
nodes.push(node);
|
|
94
|
+
return nodes;
|
|
95
|
+
}
|
|
96
|
+
// inline-void(embed) 在行未时需要预设零宽字符来放置光标
|
|
97
|
+
const eolLeaf = leaves[leaves.length - 1];
|
|
98
|
+
const lastLeaf = textLeaves[textLeaves.length - 1];
|
|
99
|
+
if (lastLeaf && eolLeaf && lastLeaf.embed) {
|
|
100
|
+
const node = (0, jsx_runtime_1.jsx)(eol_1.EOLModel, { editor: editor, leafState: eolLeaf }, delta_1.EOL);
|
|
101
|
+
weak_map_1.JSX_TO_STATE.set(node, eolLeaf);
|
|
102
|
+
nodes.push(node);
|
|
103
|
+
return nodes;
|
|
104
|
+
}
|
|
105
|
+
return nodes;
|
|
106
|
+
}, [editor, lineState]);
|
|
107
|
+
/**
|
|
108
|
+
* 将行内节点包装组合 O(N)
|
|
109
|
+
*/
|
|
110
|
+
const children = (0, react_1.useMemo)(() => {
|
|
111
|
+
const wrapped = [];
|
|
112
|
+
const keys = wrap_1.EDITOR_TO_WRAP_LEAF_KEYS.get(editor);
|
|
113
|
+
const plugins = wrap_1.EDITOR_TO_WRAP_LEAF_PLUGINS.get(editor);
|
|
114
|
+
if (!keys || !plugins)
|
|
115
|
+
return elements;
|
|
116
|
+
const len = elements.length;
|
|
117
|
+
for (let i = 0; i < len; ++i) {
|
|
118
|
+
const element = elements[i];
|
|
119
|
+
const symbol = (0, wrapper_1.getWrapSymbol)(keys, element);
|
|
120
|
+
const leaf = weak_map_1.JSX_TO_STATE.get(element);
|
|
121
|
+
if (!element || !leaf || !symbol) {
|
|
122
|
+
wrapped.push(element);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// 执行到此处说明需要包装相关节点(即使仅单个节点)
|
|
126
|
+
const nodes = [element];
|
|
127
|
+
for (let k = i + 1; k < len; ++k) {
|
|
128
|
+
const next = elements[k];
|
|
129
|
+
const nextSymbol = (0, wrapper_1.getWrapSymbol)(keys, next);
|
|
130
|
+
if (!next || !nextSymbol || nextSymbol !== symbol) {
|
|
131
|
+
// 回退到上一个值, 以便下次循环时重新检查
|
|
132
|
+
i = k - 1;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
nodes.push(next);
|
|
136
|
+
i = k;
|
|
137
|
+
}
|
|
138
|
+
// 通过插件渲染包装节点
|
|
139
|
+
let wrapper = nodes;
|
|
140
|
+
const op = leaf.op;
|
|
141
|
+
for (const plugin of plugins) {
|
|
142
|
+
// 这里的状态以首个节点为准
|
|
143
|
+
const context = {
|
|
144
|
+
leafState: leaf,
|
|
145
|
+
children: wrapper,
|
|
146
|
+
};
|
|
147
|
+
if (plugin.match(leaf.op.attributes || {}, op) && plugin.wrapLeaf) {
|
|
148
|
+
wrapper = plugin.wrapLeaf(context);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const key = `${i - nodes.length + 1}-${i}`;
|
|
152
|
+
wrapped.push((0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: wrapper }, key));
|
|
153
|
+
}
|
|
154
|
+
return wrapped;
|
|
155
|
+
}, [editor, elements]);
|
|
156
|
+
/**
|
|
157
|
+
* 处理行级节点的渲染
|
|
158
|
+
*/
|
|
159
|
+
const runtime = (0, react_1.useMemo)(() => {
|
|
160
|
+
const context = {
|
|
161
|
+
classList: [],
|
|
162
|
+
lineState: lineState,
|
|
163
|
+
attributes: lineState.attributes,
|
|
164
|
+
style: {},
|
|
165
|
+
children,
|
|
166
|
+
};
|
|
167
|
+
const plugins = editor.plugin.getPriorityPlugins(core_1.PLUGIN_TYPE.RENDER_LINE);
|
|
168
|
+
for (const plugin of plugins) {
|
|
169
|
+
const op = Object.assign(Object.assign({}, delta_1.EOL_OP), { attributes: context.attributes });
|
|
170
|
+
if (plugin.match(context.attributes, op)) {
|
|
171
|
+
context.children = plugin.renderLine(context);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return context;
|
|
175
|
+
}, [children, editor.plugin, lineState]);
|
|
176
|
+
return ((0, jsx_runtime_1.jsx)("div", { [core_1.NODE_KEY]: true, ref: setModel, dir: "auto", className: (0, utils_1.cs)(runtime.classList), style: runtime.style, children: runtime.children }));
|
|
177
|
+
};
|
|
178
|
+
exports.LineModel = react_1.default.memo(LineView);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CorePlugin } from "@block-kit/core";
|
|
3
|
+
import type { ReactLeafContext, ReactLineContext, ReactWrapLeafContext, ReactWrapLineContext } from "./types";
|
|
4
|
+
export declare abstract class EditorPlugin extends CorePlugin {
|
|
5
|
+
/**
|
|
6
|
+
* 渲染包装行节点
|
|
7
|
+
* - 调度优先级值越大 DOM 结构在越外层
|
|
8
|
+
*/
|
|
9
|
+
wrapLine?(children: ReactWrapLineContext): React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* 渲染包装叶子节点
|
|
12
|
+
* - 调度优先级值越大 DOM 结构在越外层
|
|
13
|
+
*/
|
|
14
|
+
wrapLeaf?(context: ReactWrapLeafContext): React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* 渲染行节点
|
|
17
|
+
* - 调度优先级值越大 DOM 结构在越外层
|
|
18
|
+
*/
|
|
19
|
+
renderLine?(context: ReactLineContext): React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* 渲染块级子节点
|
|
22
|
+
* - 调度优先级值越大 DOM 结构在越外层
|
|
23
|
+
*/
|
|
24
|
+
renderLeaf?(context: ReactLeafContext): React.ReactNode;
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CorePlugin } from "@block-kit/core";
|
|
2
|
+
/**
|
|
3
|
+
* 获取插件的优先级
|
|
4
|
+
* @param key
|
|
5
|
+
* @param plugin
|
|
6
|
+
*/
|
|
7
|
+
export declare const getPluginPriority: (key: string, plugin: CorePlugin) => number;
|
|
8
|
+
/**
|
|
9
|
+
* 优先级定义装饰器
|
|
10
|
+
* - 兼容性实现, 非强制类型检查
|
|
11
|
+
* @param priority
|
|
12
|
+
*/
|
|
13
|
+
export declare function Priority<T>(priority: number): (target: T, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Priority = exports.getPluginPriority = void 0;
|
|
4
|
+
const core_1 = require("@block-kit/core");
|
|
5
|
+
const utils_1 = require("@block-kit/utils");
|
|
6
|
+
/**
|
|
7
|
+
* 获取插件的优先级
|
|
8
|
+
* @param key
|
|
9
|
+
* @param plugin
|
|
10
|
+
*/
|
|
11
|
+
const getPluginPriority = (key, plugin) => {
|
|
12
|
+
const priorityKey = `${core_1.PRIORITY_KEY}${key}`;
|
|
13
|
+
const priorityPlugin = plugin;
|
|
14
|
+
const priority = priorityPlugin[priorityKey];
|
|
15
|
+
return (0, utils_1.isNumber)(priority) ? priority : utils_1.DEFAULT_PRIORITY;
|
|
16
|
+
};
|
|
17
|
+
exports.getPluginPriority = getPluginPriority;
|
|
18
|
+
/**
|
|
19
|
+
* 优先级定义装饰器
|
|
20
|
+
* - 兼容性实现, 非强制类型检查
|
|
21
|
+
* @param priority
|
|
22
|
+
*/
|
|
23
|
+
function Priority(priority) {
|
|
24
|
+
return function (target, key, descriptor) {
|
|
25
|
+
const priorityKey = `${core_1.PRIORITY_KEY}${key}`;
|
|
26
|
+
const plugin = target;
|
|
27
|
+
plugin[priorityKey] = priority;
|
|
28
|
+
return descriptor;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
exports.Priority = Priority;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CorePlugin, Editor } from "@block-kit/core";
|
|
2
|
+
import type { O, P } from "@block-kit/utils/dist/es/types";
|
|
3
|
+
import type { EditorPlugin } from "../index";
|
|
4
|
+
import { WRAP_TYPE } from "../types";
|
|
5
|
+
export declare const EDITOR_TO_WRAP_LINE_KEYS: WeakMap<Editor, string[]>;
|
|
6
|
+
export declare const EDITOR_TO_WRAP_LEAF_KEYS: WeakMap<Editor, string[]>;
|
|
7
|
+
export declare const EDITOR_TO_WRAP_LINE_PLUGINS: WeakMap<Editor, EditorPlugin[]>;
|
|
8
|
+
export declare const EDITOR_TO_WRAP_LEAF_PLUGINS: WeakMap<Editor, EditorPlugin[]>;
|
|
9
|
+
/**
|
|
10
|
+
* 为 WrapNode 定义 Key
|
|
11
|
+
* @param ...keys
|
|
12
|
+
*/
|
|
13
|
+
export declare function InjectWrapKeys<T>(...keys: string[]): (target: T, key: O.Values<typeof WRAP_TYPE>, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
14
|
+
/**
|
|
15
|
+
* 获取插件的 WrapKeys
|
|
16
|
+
* @param key
|
|
17
|
+
* @param plugin
|
|
18
|
+
*/
|
|
19
|
+
export declare const getWrapKeys: (key: string, plugin: CorePlugin) => string[] | P.Undef;
|
|
20
|
+
/**
|
|
21
|
+
* 初始化 Wrap 模式的插件
|
|
22
|
+
* - Wrap 模式的插件化在 React 层面渲染时实现
|
|
23
|
+
* - 其是渲染时调度且不存在 WrapState 的概念
|
|
24
|
+
* @param editor
|
|
25
|
+
*/
|
|
26
|
+
export declare const initWrapPlugins: (editor: Editor) => void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initWrapPlugins = exports.getWrapKeys = exports.InjectWrapKeys = exports.EDITOR_TO_WRAP_LEAF_PLUGINS = exports.EDITOR_TO_WRAP_LINE_PLUGINS = exports.EDITOR_TO_WRAP_LEAF_KEYS = exports.EDITOR_TO_WRAP_LINE_KEYS = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const priority_1 = require("./priority");
|
|
6
|
+
exports.EDITOR_TO_WRAP_LINE_KEYS = new WeakMap();
|
|
7
|
+
exports.EDITOR_TO_WRAP_LEAF_KEYS = new WeakMap();
|
|
8
|
+
exports.EDITOR_TO_WRAP_LINE_PLUGINS = new WeakMap();
|
|
9
|
+
exports.EDITOR_TO_WRAP_LEAF_PLUGINS = new WeakMap();
|
|
10
|
+
/**
|
|
11
|
+
* 为 WrapNode 定义 Key
|
|
12
|
+
* @param ...keys
|
|
13
|
+
*/
|
|
14
|
+
function InjectWrapKeys(...keys) {
|
|
15
|
+
return function (target, key, descriptor) {
|
|
16
|
+
const wrapPluginKey = `${key}Keys`;
|
|
17
|
+
const plugin = target;
|
|
18
|
+
plugin[wrapPluginKey] = keys;
|
|
19
|
+
return descriptor;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
exports.InjectWrapKeys = InjectWrapKeys;
|
|
23
|
+
/**
|
|
24
|
+
* 获取插件的 WrapKeys
|
|
25
|
+
* @param key
|
|
26
|
+
* @param plugin
|
|
27
|
+
*/
|
|
28
|
+
const getWrapKeys = (key, plugin) => {
|
|
29
|
+
const wrapPluginKey = `${key}Keys`;
|
|
30
|
+
const wrapPlugin = plugin;
|
|
31
|
+
const keys = wrapPlugin[wrapPluginKey];
|
|
32
|
+
return keys;
|
|
33
|
+
};
|
|
34
|
+
exports.getWrapKeys = getWrapKeys;
|
|
35
|
+
/**
|
|
36
|
+
* 初始化 Wrap 模式的插件
|
|
37
|
+
* - Wrap 模式的插件化在 React 层面渲染时实现
|
|
38
|
+
* - 其是渲染时调度且不存在 WrapState 的概念
|
|
39
|
+
* @param editor
|
|
40
|
+
*/
|
|
41
|
+
const initWrapPlugins = (editor) => {
|
|
42
|
+
const plugins = editor.plugin.current;
|
|
43
|
+
const wrapLineKeys = [];
|
|
44
|
+
const wrapLeafKeys = [];
|
|
45
|
+
const wrapLinePlugins = [];
|
|
46
|
+
const wrapLeafPlugins = [];
|
|
47
|
+
for (const plugin of plugins) {
|
|
48
|
+
const lineKeys = (0, exports.getWrapKeys)(types_1.WRAP_TYPE.LINE, plugin);
|
|
49
|
+
if (lineKeys) {
|
|
50
|
+
wrapLineKeys.push(...lineKeys);
|
|
51
|
+
}
|
|
52
|
+
const leafKeys = (0, exports.getWrapKeys)(types_1.WRAP_TYPE.LEAF, plugin);
|
|
53
|
+
if (leafKeys) {
|
|
54
|
+
wrapLeafKeys.push(...leafKeys);
|
|
55
|
+
}
|
|
56
|
+
if (plugin.wrapLine) {
|
|
57
|
+
wrapLinePlugins.push(plugin);
|
|
58
|
+
}
|
|
59
|
+
if (plugin.wrapLeaf) {
|
|
60
|
+
wrapLeafPlugins.push(plugin);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
wrapLinePlugins.sort((a, b) => {
|
|
64
|
+
const priorityA = (0, priority_1.getPluginPriority)(types_1.WRAP_TYPE.LINE, a);
|
|
65
|
+
const priorityB = (0, priority_1.getPluginPriority)(types_1.WRAP_TYPE.LINE, b);
|
|
66
|
+
return priorityA - priorityB;
|
|
67
|
+
});
|
|
68
|
+
wrapLeafPlugins.sort((a, b) => {
|
|
69
|
+
const priorityA = (0, priority_1.getPluginPriority)(types_1.WRAP_TYPE.LEAF, a);
|
|
70
|
+
const priorityB = (0, priority_1.getPluginPriority)(types_1.WRAP_TYPE.LEAF, b);
|
|
71
|
+
return priorityA - priorityB;
|
|
72
|
+
});
|
|
73
|
+
wrapLineKeys.length && exports.EDITOR_TO_WRAP_LINE_KEYS.set(editor, wrapLineKeys);
|
|
74
|
+
wrapLeafKeys.length && exports.EDITOR_TO_WRAP_LEAF_KEYS.set(editor, wrapLeafKeys);
|
|
75
|
+
wrapLinePlugins.length && exports.EDITOR_TO_WRAP_LINE_PLUGINS.set(editor, wrapLinePlugins);
|
|
76
|
+
wrapLeafPlugins.length && exports.EDITOR_TO_WRAP_LEAF_PLUGINS.set(editor, wrapLeafPlugins);
|
|
77
|
+
};
|
|
78
|
+
exports.initWrapPlugins = initWrapPlugins;
|