@block-kit/react 1.0.5 → 1.0.7
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.js +1 -0
- package/dist/es/hooks/use-readonly.js +1 -0
- package/dist/es/index.d.ts +1 -0
- package/dist/es/index.js +1 -0
- package/dist/es/model/block.js +8 -0
- package/dist/es/model/leaf.js +1 -1
- package/dist/es/model/line.js +10 -1
- package/dist/es/model/portal.d.ts +5 -0
- package/dist/es/model/portal.js +9 -0
- package/dist/es/preset/block-kit.js +3 -2
- package/dist/es/preset/editable.d.ts +6 -0
- package/dist/es/preset/editable.js +4 -3
- package/dist/es/preset/text.d.ts +3 -2
- package/dist/es/preset/text.js +4 -10
- package/dist/es/preset/void.js +2 -1
- package/dist/es/preset/zero.d.ts +4 -3
- package/dist/es/preset/zero.js +3 -5
- package/dist/es/utils/dom.d.ts +36 -0
- package/dist/es/utils/dom.js +57 -0
- package/dist/lib/hooks/use-editor.js +1 -0
- package/dist/lib/hooks/use-readonly.js +1 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +3 -1
- package/dist/lib/model/block.js +8 -0
- package/dist/lib/model/leaf.js +1 -1
- package/dist/lib/model/line.js +10 -1
- package/dist/lib/model/portal.d.ts +5 -0
- package/dist/lib/model/portal.js +35 -0
- package/dist/lib/preset/block-kit.js +2 -1
- package/dist/lib/preset/editable.d.ts +6 -0
- package/dist/lib/preset/editable.js +4 -3
- package/dist/lib/preset/text.d.ts +3 -2
- package/dist/lib/preset/text.js +4 -9
- package/dist/lib/preset/void.js +2 -1
- package/dist/lib/preset/zero.d.ts +4 -3
- package/dist/lib/preset/zero.js +4 -5
- package/dist/lib/utils/dom.d.ts +36 -0
- package/dist/lib/utils/dom.js +60 -0
- package/package.json +18 -6
package/dist/es/index.d.ts
CHANGED
|
@@ -15,4 +15,5 @@ export { Isolate } from "./preset/isolate";
|
|
|
15
15
|
export { Text } from "./preset/text";
|
|
16
16
|
export { Void } from "./preset/void";
|
|
17
17
|
export { ZeroSpace } from "./preset/zero";
|
|
18
|
+
export { MountNode } from "./utils/dom";
|
|
18
19
|
export { preventNativeEvent, preventReactEvent } from "./utils/event";
|
package/dist/es/index.js
CHANGED
|
@@ -14,4 +14,5 @@ export { Isolate } from "./preset/isolate";
|
|
|
14
14
|
export { Text } from "./preset/text";
|
|
15
15
|
export { Void } from "./preset/void";
|
|
16
16
|
export { ZeroSpace } from "./preset/zero";
|
|
17
|
+
export { MountNode } from "./utils/dom";
|
|
17
18
|
export { preventNativeEvent, preventReactEvent } from "./utils/event";
|
package/dist/es/model/block.js
CHANGED
|
@@ -77,6 +77,14 @@ const BlockView = props => {
|
|
|
77
77
|
* 处理行节点
|
|
78
78
|
*/
|
|
79
79
|
const elements = useMemo(() => {
|
|
80
|
+
// 开发模式严格检查数据准确性
|
|
81
|
+
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
|
82
|
+
for (const line of lines) {
|
|
83
|
+
if (line.length < 0 || line.size < 0 || line.index < 0 || line.start < 0 || !line.key) {
|
|
84
|
+
throw new Error("LineState index, size, start or length is not set");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
80
88
|
return lines.map((line, index) => {
|
|
81
89
|
const node = (_jsx(LineModel, { editor: editor, lineState: line, index: index }, line.key));
|
|
82
90
|
JSX_TO_STATE.set(node, line);
|
package/dist/es/model/leaf.js
CHANGED
|
@@ -23,7 +23,7 @@ const LeafView = props => {
|
|
|
23
23
|
leafState: leafState,
|
|
24
24
|
attributes: leafState.op.attributes,
|
|
25
25
|
style: {},
|
|
26
|
-
children: _jsx(Text, {
|
|
26
|
+
children: _jsx(Text, { onRef: el => LT.set(leafState, el), children: text }),
|
|
27
27
|
};
|
|
28
28
|
const plugins = editor.plugin.getPriorityPlugins(PLUGIN_TYPE.RENDER_LEAF);
|
|
29
29
|
for (const plugin of plugins) {
|
package/dist/es/model/line.js
CHANGED
|
@@ -52,10 +52,19 @@ const LineView = props => {
|
|
|
52
52
|
* 处理行内的节点
|
|
53
53
|
*/
|
|
54
54
|
const elements = useMemo(() => {
|
|
55
|
+
// 开发模式下严格检查数据准确性
|
|
56
|
+
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
|
57
|
+
const leaves = lineState.getLeaves();
|
|
58
|
+
for (const leaf of leaves) {
|
|
59
|
+
if (leaf.index === -1 || leaf.offset === -1 || !leaf.key) {
|
|
60
|
+
throw new Error("LeafState index or offset is not set");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
55
64
|
const leaves = lineState.getLeaves();
|
|
56
65
|
const textLeaves = leaves.slice(0, -1);
|
|
57
66
|
const nodes = textLeaves.map((n, i) => {
|
|
58
|
-
const node = _jsx(LeafModel, { editor: editor, index: i, leafState: n },
|
|
67
|
+
const node = _jsx(LeafModel, { editor: editor, index: i, leafState: n }, n.key);
|
|
59
68
|
JSX_TO_STATE.set(node, n);
|
|
60
69
|
return node;
|
|
61
70
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { Fragment, useState } from "react";
|
|
3
|
+
import { EDITOR_TO_PORTAL } from "../utils/dom";
|
|
4
|
+
const PortalView = props => {
|
|
5
|
+
const [portals, setPortals] = useState({});
|
|
6
|
+
EDITOR_TO_PORTAL.set(props.editor, setPortals);
|
|
7
|
+
return (_jsx(Fragment, { children: Object.entries(portals).map(([key, node]) => (_jsx(Fragment, { children: node }, key))) }));
|
|
8
|
+
};
|
|
9
|
+
export const PortalModel = React.memo(PortalView);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { EDITOR_STATE } from "@block-kit/core";
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import { BlockKitContext } from "../hooks/use-editor";
|
|
5
5
|
import { ReadonlyContext } from "../hooks/use-readonly";
|
|
6
|
+
import { PortalModel } from "../model/portal";
|
|
6
7
|
import { initWrapPlugins } from "../plugin/modules/wrap";
|
|
7
8
|
export const BlockKit = props => {
|
|
8
9
|
const { editor, readonly, children } = props;
|
|
@@ -13,5 +14,5 @@ export const BlockKit = props => {
|
|
|
13
14
|
// 希望在 Editor 初始化后立即执行一次
|
|
14
15
|
initWrapPlugins(editor);
|
|
15
16
|
}, [editor]);
|
|
16
|
-
return (_jsx(BlockKitContext.Provider, { value: editor, children:
|
|
17
|
+
return (_jsx(BlockKitContext.Provider, { value: editor, children: _jsxs(ReadonlyContext.Provider, { value: !!readonly, children: [_jsx(PortalModel, { editor: editor }), children] }) }));
|
|
17
18
|
};
|
|
@@ -10,7 +10,7 @@ import { BlockModel } from "../model/block";
|
|
|
10
10
|
* @param props
|
|
11
11
|
*/
|
|
12
12
|
export const Editable = props => {
|
|
13
|
-
const { className, autoFocus } = props;
|
|
13
|
+
const { className, autoFocus, preventDestroy } = props;
|
|
14
14
|
const { editor } = useEditorStatic();
|
|
15
15
|
const { readonly } = useReadonly();
|
|
16
16
|
const ref = useRef(null);
|
|
@@ -18,9 +18,10 @@ export const Editable = props => {
|
|
|
18
18
|
const el = ref.current;
|
|
19
19
|
el && editor.onMount(el);
|
|
20
20
|
return () => {
|
|
21
|
-
editor.
|
|
21
|
+
editor.onUnmount();
|
|
22
|
+
!preventDestroy && editor.destroy();
|
|
22
23
|
};
|
|
23
|
-
}, [editor]);
|
|
24
|
+
}, [editor, preventDestroy]);
|
|
24
25
|
useEffect(() => {
|
|
25
26
|
// COMPAT: 这里有个奇怪的表现
|
|
26
27
|
// 当自动聚焦时, 必须要先更新浏览器选区再聚焦
|
package/dist/es/preset/text.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { FC } from "react";
|
|
2
2
|
export type TextProps = {
|
|
3
3
|
children: string;
|
|
4
|
+
onRef?: (ref: HTMLSpanElement | null) => void;
|
|
4
5
|
};
|
|
5
6
|
/**
|
|
6
7
|
* 文本节点
|
|
7
8
|
* @param props
|
|
8
9
|
*/
|
|
9
|
-
export declare const Text:
|
|
10
|
+
export declare const Text: FC<TextProps>;
|
package/dist/es/preset/text.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { LEAF_STRING } from "@block-kit/core";
|
|
3
|
-
import { isDOMText
|
|
4
|
-
import { forwardRef } from "react";
|
|
3
|
+
import { isDOMText } from "@block-kit/utils";
|
|
5
4
|
/**
|
|
6
5
|
* 文本节点
|
|
7
6
|
* @param props
|
|
8
7
|
*/
|
|
9
|
-
export const Text =
|
|
8
|
+
export const Text = props => {
|
|
10
9
|
const onRef = (dom) => {
|
|
11
10
|
// 处理外部引用的 ref
|
|
12
|
-
|
|
13
|
-
ref(dom);
|
|
14
|
-
}
|
|
15
|
-
else if (ref) {
|
|
16
|
-
ref.current = dom;
|
|
17
|
-
}
|
|
11
|
+
props.onRef && props.onRef(dom);
|
|
18
12
|
// COMPAT: 避免 React 非受控与 IME 造成的 DOM 内容问题
|
|
19
13
|
if (!dom || props.children === dom.textContent)
|
|
20
14
|
return void 0;
|
|
@@ -31,4 +25,4 @@ export const Text = /*#__PURE__*/ forwardRef((props, ref) => {
|
|
|
31
25
|
}
|
|
32
26
|
};
|
|
33
27
|
return (_jsx("span", { ref: onRef, [LEAF_STRING]: true, children: props.children }));
|
|
34
|
-
}
|
|
28
|
+
};
|
package/dist/es/preset/void.js
CHANGED
|
@@ -13,11 +13,12 @@ export const Void = props => {
|
|
|
13
13
|
const { context, tag: Tag = "span" } = props;
|
|
14
14
|
const { editor } = useEditorStatic();
|
|
15
15
|
const leaf = context.leafState;
|
|
16
|
-
const onMouseDown = () => {
|
|
16
|
+
const onMouseDown = (event) => {
|
|
17
17
|
// FIX: 修复选区偏移量, leaf 的长度可能 > 1, 而 DOM 节点的长度仅为 1
|
|
18
18
|
const point = new Point(leaf.parent.index, leaf.offset + 1);
|
|
19
19
|
const range = new Range(point, point.clone());
|
|
20
20
|
editor.selection.set(range, true);
|
|
21
|
+
event.preventDefault();
|
|
21
22
|
};
|
|
22
23
|
return (_jsxs(React.Fragment, { children: [_jsx(ZeroSpace, { void: true, hide: true, len: leaf.length > 1 ? leaf.length : void 0 }), _jsx(Tag, { className: props.className, style: Object.assign({ userSelect: "none" }, props.style), contentEditable: false, [VOID_KEY]: true, onMouseDown: onMouseDown, children: props.children })] }));
|
|
23
24
|
};
|
package/dist/es/preset/zero.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import type { FC } from "react";
|
|
2
2
|
export type ZeroSpaceProps = {
|
|
3
3
|
/** 隐藏光标 */
|
|
4
4
|
hide?: boolean;
|
|
@@ -10,6 +10,8 @@ export type ZeroSpaceProps = {
|
|
|
10
10
|
enter?: boolean;
|
|
11
11
|
/** 空节点占位长度 */
|
|
12
12
|
len?: number;
|
|
13
|
+
/** 获取 DOM 引用 */
|
|
14
|
+
onRef?: React.MutableRefObject<HTMLDivElement | null>;
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* 零宽字符组件
|
|
@@ -18,6 +20,5 @@ export type ZeroSpaceProps = {
|
|
|
18
20
|
* - enter => 行末尾占位, 保留于 EOLView
|
|
19
21
|
* - len => 空节点占位长度, 配合 Void/Embed
|
|
20
22
|
* @param props
|
|
21
|
-
* @param ref
|
|
22
23
|
*/
|
|
23
|
-
export declare const ZeroSpace:
|
|
24
|
+
export declare const ZeroSpace: FC<ZeroSpaceProps>;
|
package/dist/es/preset/zero.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { VOID_LEN_KEY, ZERO_EMBED_KEY, ZERO_ENTER_KEY, ZERO_SPACE_KEY, ZERO_SYMBOL, ZERO_VOID_KEY, } from "@block-kit/core";
|
|
3
|
-
import { forwardRef } from "react";
|
|
4
3
|
import { NO_CURSOR } from "../utils/constant";
|
|
5
4
|
/**
|
|
6
5
|
* 零宽字符组件
|
|
@@ -9,12 +8,11 @@ import { NO_CURSOR } from "../utils/constant";
|
|
|
9
8
|
* - enter => 行末尾占位, 保留于 EOLView
|
|
10
9
|
* - len => 空节点占位长度, 配合 Void/Embed
|
|
11
10
|
* @param props
|
|
12
|
-
* @param ref
|
|
13
11
|
*/
|
|
14
|
-
export const ZeroSpace =
|
|
15
|
-
return (_jsx("span", { ref:
|
|
12
|
+
export const ZeroSpace = props => {
|
|
13
|
+
return (_jsx("span", { ref: props.onRef, [ZERO_SPACE_KEY]: true,
|
|
16
14
|
[ZERO_VOID_KEY]: props.void,
|
|
17
15
|
[ZERO_ENTER_KEY]: props.enter,
|
|
18
16
|
[ZERO_EMBED_KEY]: props.embed,
|
|
19
17
|
[VOID_LEN_KEY]: props.len, style: props.hide ? NO_CURSOR : void 0, children: ZERO_SYMBOL }));
|
|
20
|
-
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Editor } from "@block-kit/core";
|
|
2
|
+
import type { O } from "@block-kit/utils/dist/es/types";
|
|
3
|
+
import type { ReactPortal } from "react";
|
|
4
|
+
export declare const EDITOR_TO_DOM: WeakMap<Editor, HTMLElement | null>;
|
|
5
|
+
export declare const EDITOR_TO_PORTAL: WeakMap<Editor, import("react").Dispatch<import("react").SetStateAction<O.Map<ReactPortal>>> | null>;
|
|
6
|
+
/**
|
|
7
|
+
* 共享的挂载节点
|
|
8
|
+
*/
|
|
9
|
+
export declare const MountNode: {
|
|
10
|
+
/**
|
|
11
|
+
* 设置挂载 DOM
|
|
12
|
+
* @param editor
|
|
13
|
+
* @param dom
|
|
14
|
+
*/
|
|
15
|
+
set: (editor: Editor, dom: HTMLElement | null) => void;
|
|
16
|
+
/**
|
|
17
|
+
* 获取挂载 DOM
|
|
18
|
+
* @param editor
|
|
19
|
+
* @param dom
|
|
20
|
+
*/
|
|
21
|
+
get: (editor: Editor) => HTMLElement;
|
|
22
|
+
/**
|
|
23
|
+
* 渲染节点
|
|
24
|
+
* @param editor
|
|
25
|
+
* @param key
|
|
26
|
+
* @param node
|
|
27
|
+
* @param dom [?=undef]
|
|
28
|
+
*/
|
|
29
|
+
mount: (editor: Editor, key: string, node: JSX.Element, dom?: HTMLElement) => undefined;
|
|
30
|
+
/**
|
|
31
|
+
* 卸载节点
|
|
32
|
+
* @param editor
|
|
33
|
+
* @param key
|
|
34
|
+
*/
|
|
35
|
+
unmount: (editor: Editor, key: string) => undefined;
|
|
36
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createPortal } from "react-dom";
|
|
2
|
+
export const EDITOR_TO_DOM = new WeakMap();
|
|
3
|
+
export const EDITOR_TO_PORTAL = new WeakMap();
|
|
4
|
+
/**
|
|
5
|
+
* 共享的挂载节点
|
|
6
|
+
*/
|
|
7
|
+
export const MountNode = {
|
|
8
|
+
/**
|
|
9
|
+
* 设置挂载 DOM
|
|
10
|
+
* @param editor
|
|
11
|
+
* @param dom
|
|
12
|
+
*/
|
|
13
|
+
set: (editor, dom) => {
|
|
14
|
+
EDITOR_TO_DOM.set(editor, dom);
|
|
15
|
+
},
|
|
16
|
+
/**
|
|
17
|
+
* 获取挂载 DOM
|
|
18
|
+
* @param editor
|
|
19
|
+
* @param dom
|
|
20
|
+
*/
|
|
21
|
+
get: (editor) => {
|
|
22
|
+
return EDITOR_TO_DOM.get(editor) || document.body;
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* 渲染节点
|
|
26
|
+
* @param editor
|
|
27
|
+
* @param key
|
|
28
|
+
* @param node
|
|
29
|
+
* @param dom [?=undef]
|
|
30
|
+
*/
|
|
31
|
+
mount: (editor, key, node, dom) => {
|
|
32
|
+
const setPortals = EDITOR_TO_PORTAL.get(editor);
|
|
33
|
+
if (!setPortals)
|
|
34
|
+
return void 0;
|
|
35
|
+
const portal = createPortal(node, dom || MountNode.get(editor));
|
|
36
|
+
setPortals(prev => {
|
|
37
|
+
const newNodes = Object.assign({}, prev);
|
|
38
|
+
newNodes[key] = portal;
|
|
39
|
+
return newNodes;
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* 卸载节点
|
|
44
|
+
* @param editor
|
|
45
|
+
* @param key
|
|
46
|
+
*/
|
|
47
|
+
unmount: (editor, key) => {
|
|
48
|
+
const setPortals = EDITOR_TO_PORTAL.get(editor);
|
|
49
|
+
if (!setPortals)
|
|
50
|
+
return void 0;
|
|
51
|
+
setPortals(prev => {
|
|
52
|
+
const newNodes = Object.assign({}, prev);
|
|
53
|
+
delete newNodes[key];
|
|
54
|
+
return newNodes;
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.useEditorStatic = exports.BlockKitContext = void 0;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
exports.BlockKitContext = (0, react_1.createContext)(null);
|
|
29
|
+
exports.BlockKitContext.displayName = "BlockKit";
|
|
29
30
|
const useEditorStatic = () => {
|
|
30
31
|
const editor = react_1.default.useContext(exports.BlockKitContext);
|
|
31
32
|
if (!editor) {
|
|
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.useReadonly = exports.ReadonlyContext = void 0;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
exports.ReadonlyContext = (0, react_1.createContext)(false);
|
|
29
|
+
exports.ReadonlyContext.displayName = "Readonly";
|
|
29
30
|
const useReadonly = () => {
|
|
30
31
|
const readonly = react_1.default.useContext(exports.ReadonlyContext);
|
|
31
32
|
return { readonly };
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -15,4 +15,5 @@ export { Isolate } from "./preset/isolate";
|
|
|
15
15
|
export { Text } from "./preset/text";
|
|
16
16
|
export { Void } from "./preset/void";
|
|
17
17
|
export { ZeroSpace } from "./preset/zero";
|
|
18
|
+
export { MountNode } from "./utils/dom";
|
|
18
19
|
export { preventNativeEvent, preventReactEvent } from "./utils/event";
|
package/dist/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.preventReactEvent = exports.preventNativeEvent = exports.ZeroSpace = exports.Void = exports.Text = exports.Isolate = exports.Embed = exports.Editable = exports.BlockKit = exports.InjectWrapKeys = exports.Priority = exports.EditorPlugin = exports.LineModel = exports.LeafModel = exports.EOLModel = exports.BlockModel = exports.useReadonly = exports.ReadonlyContext = exports.useEditorStatic = exports.BlockKitContext = void 0;
|
|
3
|
+
exports.preventReactEvent = exports.preventNativeEvent = exports.MountNode = exports.ZeroSpace = exports.Void = exports.Text = exports.Isolate = exports.Embed = exports.Editable = exports.BlockKit = exports.InjectWrapKeys = exports.Priority = exports.EditorPlugin = exports.LineModel = exports.LeafModel = exports.EOLModel = exports.BlockModel = exports.useReadonly = exports.ReadonlyContext = exports.useEditorStatic = exports.BlockKitContext = void 0;
|
|
4
4
|
var use_editor_1 = require("./hooks/use-editor");
|
|
5
5
|
Object.defineProperty(exports, "BlockKitContext", { enumerable: true, get: function () { return use_editor_1.BlockKitContext; } });
|
|
6
6
|
Object.defineProperty(exports, "useEditorStatic", { enumerable: true, get: function () { return use_editor_1.useEditorStatic; } });
|
|
@@ -35,6 +35,8 @@ var void_1 = require("./preset/void");
|
|
|
35
35
|
Object.defineProperty(exports, "Void", { enumerable: true, get: function () { return void_1.Void; } });
|
|
36
36
|
var zero_1 = require("./preset/zero");
|
|
37
37
|
Object.defineProperty(exports, "ZeroSpace", { enumerable: true, get: function () { return zero_1.ZeroSpace; } });
|
|
38
|
+
var dom_1 = require("./utils/dom");
|
|
39
|
+
Object.defineProperty(exports, "MountNode", { enumerable: true, get: function () { return dom_1.MountNode; } });
|
|
38
40
|
var event_1 = require("./utils/event");
|
|
39
41
|
Object.defineProperty(exports, "preventNativeEvent", { enumerable: true, get: function () { return event_1.preventNativeEvent; } });
|
|
40
42
|
Object.defineProperty(exports, "preventReactEvent", { enumerable: true, get: function () { return event_1.preventReactEvent; } });
|
package/dist/lib/model/block.js
CHANGED
|
@@ -103,6 +103,14 @@ const BlockView = props => {
|
|
|
103
103
|
* 处理行节点
|
|
104
104
|
*/
|
|
105
105
|
const elements = (0, react_1.useMemo)(() => {
|
|
106
|
+
// 开发模式严格检查数据准确性
|
|
107
|
+
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
if (line.length < 0 || line.size < 0 || line.index < 0 || line.start < 0 || !line.key) {
|
|
110
|
+
throw new Error("LineState index, size, start or length is not set");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
106
114
|
return lines.map((line, index) => {
|
|
107
115
|
const node = ((0, jsx_runtime_1.jsx)(line_1.LineModel, { editor: editor, lineState: line, index: index }, line.key));
|
|
108
116
|
weak_map_1.JSX_TO_STATE.set(node, line);
|
package/dist/lib/model/leaf.js
CHANGED
|
@@ -49,7 +49,7 @@ const LeafView = props => {
|
|
|
49
49
|
leafState: leafState,
|
|
50
50
|
attributes: leafState.op.attributes,
|
|
51
51
|
style: {},
|
|
52
|
-
children: (0, jsx_runtime_1.jsx)(text_1.Text, {
|
|
52
|
+
children: (0, jsx_runtime_1.jsx)(text_1.Text, { onRef: el => weak_map_1.LEAF_TO_TEXT.set(leafState, el), children: text }),
|
|
53
53
|
};
|
|
54
54
|
const plugins = editor.plugin.getPriorityPlugins(core_1.PLUGIN_TYPE.RENDER_LEAF);
|
|
55
55
|
for (const plugin of plugins) {
|
package/dist/lib/model/line.js
CHANGED
|
@@ -78,10 +78,19 @@ const LineView = props => {
|
|
|
78
78
|
* 处理行内的节点
|
|
79
79
|
*/
|
|
80
80
|
const elements = (0, react_1.useMemo)(() => {
|
|
81
|
+
// 开发模式下严格检查数据准确性
|
|
82
|
+
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") {
|
|
83
|
+
const leaves = lineState.getLeaves();
|
|
84
|
+
for (const leaf of leaves) {
|
|
85
|
+
if (leaf.index === -1 || leaf.offset === -1 || !leaf.key) {
|
|
86
|
+
throw new Error("LeafState index or offset is not set");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
81
90
|
const leaves = lineState.getLeaves();
|
|
82
91
|
const textLeaves = leaves.slice(0, -1);
|
|
83
92
|
const nodes = textLeaves.map((n, i) => {
|
|
84
|
-
const node = (0, jsx_runtime_1.jsx)(leaf_1.LeafModel, { editor: editor, index: i, leafState: n },
|
|
93
|
+
const node = (0, jsx_runtime_1.jsx)(leaf_1.LeafModel, { editor: editor, index: i, leafState: n }, n.key);
|
|
85
94
|
weak_map_1.JSX_TO_STATE.set(node, n);
|
|
86
95
|
return node;
|
|
87
96
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
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.PortalModel = void 0;
|
|
27
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
+
const react_1 = __importStar(require("react"));
|
|
29
|
+
const dom_1 = require("../utils/dom");
|
|
30
|
+
const PortalView = props => {
|
|
31
|
+
const [portals, setPortals] = (0, react_1.useState)({});
|
|
32
|
+
dom_1.EDITOR_TO_PORTAL.set(props.editor, setPortals);
|
|
33
|
+
return ((0, jsx_runtime_1.jsx)(react_1.Fragment, { children: Object.entries(portals).map(([key, node]) => ((0, jsx_runtime_1.jsx)(react_1.Fragment, { children: node }, key))) }));
|
|
34
|
+
};
|
|
35
|
+
exports.PortalModel = react_1.default.memo(PortalView);
|
|
@@ -6,6 +6,7 @@ const core_1 = require("@block-kit/core");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const use_editor_1 = require("../hooks/use-editor");
|
|
8
8
|
const use_readonly_1 = require("../hooks/use-readonly");
|
|
9
|
+
const portal_1 = require("../model/portal");
|
|
9
10
|
const wrap_1 = require("../plugin/modules/wrap");
|
|
10
11
|
const BlockKit = props => {
|
|
11
12
|
const { editor, readonly, children } = props;
|
|
@@ -16,6 +17,6 @@ const BlockKit = props => {
|
|
|
16
17
|
// 希望在 Editor 初始化后立即执行一次
|
|
17
18
|
(0, wrap_1.initWrapPlugins)(editor);
|
|
18
19
|
}, [editor]);
|
|
19
|
-
return ((0, jsx_runtime_1.jsx)(use_editor_1.BlockKitContext.Provider, { value: editor, children: (0, jsx_runtime_1.
|
|
20
|
+
return ((0, jsx_runtime_1.jsx)(use_editor_1.BlockKitContext.Provider, { value: editor, children: (0, jsx_runtime_1.jsxs)(use_readonly_1.ReadonlyContext.Provider, { value: !!readonly, children: [(0, jsx_runtime_1.jsx)(portal_1.PortalModel, { editor: editor }), children] }) }));
|
|
20
21
|
};
|
|
21
22
|
exports.BlockKit = BlockKit;
|
|
@@ -13,7 +13,7 @@ const block_1 = require("../model/block");
|
|
|
13
13
|
* @param props
|
|
14
14
|
*/
|
|
15
15
|
const Editable = props => {
|
|
16
|
-
const { className, autoFocus } = props;
|
|
16
|
+
const { className, autoFocus, preventDestroy } = props;
|
|
17
17
|
const { editor } = (0, use_editor_1.useEditorStatic)();
|
|
18
18
|
const { readonly } = (0, use_readonly_1.useReadonly)();
|
|
19
19
|
const ref = (0, react_1.useRef)(null);
|
|
@@ -21,9 +21,10 @@ const Editable = props => {
|
|
|
21
21
|
const el = ref.current;
|
|
22
22
|
el && editor.onMount(el);
|
|
23
23
|
return () => {
|
|
24
|
-
editor.
|
|
24
|
+
editor.onUnmount();
|
|
25
|
+
!preventDestroy && editor.destroy();
|
|
25
26
|
};
|
|
26
|
-
}, [editor]);
|
|
27
|
+
}, [editor, preventDestroy]);
|
|
27
28
|
(0, react_1.useEffect)(() => {
|
|
28
29
|
// COMPAT: 这里有个奇怪的表现
|
|
29
30
|
// 当自动聚焦时, 必须要先更新浏览器选区再聚焦
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { FC } from "react";
|
|
2
2
|
export type TextProps = {
|
|
3
3
|
children: string;
|
|
4
|
+
onRef?: (ref: HTMLSpanElement | null) => void;
|
|
4
5
|
};
|
|
5
6
|
/**
|
|
6
7
|
* 文本节点
|
|
7
8
|
* @param props
|
|
8
9
|
*/
|
|
9
|
-
export declare const Text:
|
|
10
|
+
export declare const Text: FC<TextProps>;
|
package/dist/lib/preset/text.js
CHANGED
|
@@ -4,20 +4,14 @@ exports.Text = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const core_1 = require("@block-kit/core");
|
|
6
6
|
const utils_1 = require("@block-kit/utils");
|
|
7
|
-
const react_1 = require("react");
|
|
8
7
|
/**
|
|
9
8
|
* 文本节点
|
|
10
9
|
* @param props
|
|
11
10
|
*/
|
|
12
|
-
|
|
11
|
+
const Text = props => {
|
|
13
12
|
const onRef = (dom) => {
|
|
14
13
|
// 处理外部引用的 ref
|
|
15
|
-
|
|
16
|
-
ref(dom);
|
|
17
|
-
}
|
|
18
|
-
else if (ref) {
|
|
19
|
-
ref.current = dom;
|
|
20
|
-
}
|
|
14
|
+
props.onRef && props.onRef(dom);
|
|
21
15
|
// COMPAT: 避免 React 非受控与 IME 造成的 DOM 内容问题
|
|
22
16
|
if (!dom || props.children === dom.textContent)
|
|
23
17
|
return void 0;
|
|
@@ -34,4 +28,5 @@ exports.Text = (0, react_1.forwardRef)((props, ref) => {
|
|
|
34
28
|
}
|
|
35
29
|
};
|
|
36
30
|
return ((0, jsx_runtime_1.jsx)("span", { ref: onRef, [core_1.LEAF_STRING]: true, children: props.children }));
|
|
37
|
-
}
|
|
31
|
+
};
|
|
32
|
+
exports.Text = Text;
|
package/dist/lib/preset/void.js
CHANGED
|
@@ -19,11 +19,12 @@ const Void = props => {
|
|
|
19
19
|
const { context, tag: Tag = "span" } = props;
|
|
20
20
|
const { editor } = (0, use_editor_1.useEditorStatic)();
|
|
21
21
|
const leaf = context.leafState;
|
|
22
|
-
const onMouseDown = () => {
|
|
22
|
+
const onMouseDown = (event) => {
|
|
23
23
|
// FIX: 修复选区偏移量, leaf 的长度可能 > 1, 而 DOM 节点的长度仅为 1
|
|
24
24
|
const point = new core_3.Point(leaf.parent.index, leaf.offset + 1);
|
|
25
25
|
const range = new core_2.Range(point, point.clone());
|
|
26
26
|
editor.selection.set(range, true);
|
|
27
|
+
event.preventDefault();
|
|
27
28
|
};
|
|
28
29
|
return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(zero_1.ZeroSpace, { void: true, hide: true, len: leaf.length > 1 ? leaf.length : void 0 }), (0, jsx_runtime_1.jsx)(Tag, { className: props.className, style: Object.assign({ userSelect: "none" }, props.style), contentEditable: false, [core_1.VOID_KEY]: true, onMouseDown: onMouseDown, children: props.children })] }));
|
|
29
30
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import type { FC } from "react";
|
|
2
2
|
export type ZeroSpaceProps = {
|
|
3
3
|
/** 隐藏光标 */
|
|
4
4
|
hide?: boolean;
|
|
@@ -10,6 +10,8 @@ export type ZeroSpaceProps = {
|
|
|
10
10
|
enter?: boolean;
|
|
11
11
|
/** 空节点占位长度 */
|
|
12
12
|
len?: number;
|
|
13
|
+
/** 获取 DOM 引用 */
|
|
14
|
+
onRef?: React.MutableRefObject<HTMLDivElement | null>;
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* 零宽字符组件
|
|
@@ -18,6 +20,5 @@ export type ZeroSpaceProps = {
|
|
|
18
20
|
* - enter => 行末尾占位, 保留于 EOLView
|
|
19
21
|
* - len => 空节点占位长度, 配合 Void/Embed
|
|
20
22
|
* @param props
|
|
21
|
-
* @param ref
|
|
22
23
|
*/
|
|
23
|
-
export declare const ZeroSpace:
|
|
24
|
+
export declare const ZeroSpace: FC<ZeroSpaceProps>;
|
package/dist/lib/preset/zero.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ZeroSpace = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const core_1 = require("@block-kit/core");
|
|
6
|
-
const react_1 = require("react");
|
|
7
6
|
const constant_1 = require("../utils/constant");
|
|
8
7
|
/**
|
|
9
8
|
* 零宽字符组件
|
|
@@ -12,12 +11,12 @@ const constant_1 = require("../utils/constant");
|
|
|
12
11
|
* - enter => 行末尾占位, 保留于 EOLView
|
|
13
12
|
* - len => 空节点占位长度, 配合 Void/Embed
|
|
14
13
|
* @param props
|
|
15
|
-
* @param ref
|
|
16
14
|
*/
|
|
17
|
-
|
|
18
|
-
return ((0, jsx_runtime_1.jsx)("span", { ref:
|
|
15
|
+
const ZeroSpace = props => {
|
|
16
|
+
return ((0, jsx_runtime_1.jsx)("span", { ref: props.onRef, [core_1.ZERO_SPACE_KEY]: true,
|
|
19
17
|
[core_1.ZERO_VOID_KEY]: props.void,
|
|
20
18
|
[core_1.ZERO_ENTER_KEY]: props.enter,
|
|
21
19
|
[core_1.ZERO_EMBED_KEY]: props.embed,
|
|
22
20
|
[core_1.VOID_LEN_KEY]: props.len, style: props.hide ? constant_1.NO_CURSOR : void 0, children: core_1.ZERO_SYMBOL }));
|
|
23
|
-
}
|
|
21
|
+
};
|
|
22
|
+
exports.ZeroSpace = ZeroSpace;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Editor } from "@block-kit/core";
|
|
2
|
+
import type { O } from "@block-kit/utils/dist/es/types";
|
|
3
|
+
import type { ReactPortal } from "react";
|
|
4
|
+
export declare const EDITOR_TO_DOM: WeakMap<Editor, HTMLElement | null>;
|
|
5
|
+
export declare const EDITOR_TO_PORTAL: WeakMap<Editor, import("react").Dispatch<import("react").SetStateAction<O.Map<ReactPortal>>> | null>;
|
|
6
|
+
/**
|
|
7
|
+
* 共享的挂载节点
|
|
8
|
+
*/
|
|
9
|
+
export declare const MountNode: {
|
|
10
|
+
/**
|
|
11
|
+
* 设置挂载 DOM
|
|
12
|
+
* @param editor
|
|
13
|
+
* @param dom
|
|
14
|
+
*/
|
|
15
|
+
set: (editor: Editor, dom: HTMLElement | null) => void;
|
|
16
|
+
/**
|
|
17
|
+
* 获取挂载 DOM
|
|
18
|
+
* @param editor
|
|
19
|
+
* @param dom
|
|
20
|
+
*/
|
|
21
|
+
get: (editor: Editor) => HTMLElement;
|
|
22
|
+
/**
|
|
23
|
+
* 渲染节点
|
|
24
|
+
* @param editor
|
|
25
|
+
* @param key
|
|
26
|
+
* @param node
|
|
27
|
+
* @param dom [?=undef]
|
|
28
|
+
*/
|
|
29
|
+
mount: (editor: Editor, key: string, node: JSX.Element, dom?: HTMLElement) => undefined;
|
|
30
|
+
/**
|
|
31
|
+
* 卸载节点
|
|
32
|
+
* @param editor
|
|
33
|
+
* @param key
|
|
34
|
+
*/
|
|
35
|
+
unmount: (editor: Editor, key: string) => undefined;
|
|
36
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MountNode = exports.EDITOR_TO_PORTAL = exports.EDITOR_TO_DOM = void 0;
|
|
4
|
+
const react_dom_1 = require("react-dom");
|
|
5
|
+
exports.EDITOR_TO_DOM = new WeakMap();
|
|
6
|
+
exports.EDITOR_TO_PORTAL = new WeakMap();
|
|
7
|
+
/**
|
|
8
|
+
* 共享的挂载节点
|
|
9
|
+
*/
|
|
10
|
+
exports.MountNode = {
|
|
11
|
+
/**
|
|
12
|
+
* 设置挂载 DOM
|
|
13
|
+
* @param editor
|
|
14
|
+
* @param dom
|
|
15
|
+
*/
|
|
16
|
+
set: (editor, dom) => {
|
|
17
|
+
exports.EDITOR_TO_DOM.set(editor, dom);
|
|
18
|
+
},
|
|
19
|
+
/**
|
|
20
|
+
* 获取挂载 DOM
|
|
21
|
+
* @param editor
|
|
22
|
+
* @param dom
|
|
23
|
+
*/
|
|
24
|
+
get: (editor) => {
|
|
25
|
+
return exports.EDITOR_TO_DOM.get(editor) || document.body;
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* 渲染节点
|
|
29
|
+
* @param editor
|
|
30
|
+
* @param key
|
|
31
|
+
* @param node
|
|
32
|
+
* @param dom [?=undef]
|
|
33
|
+
*/
|
|
34
|
+
mount: (editor, key, node, dom) => {
|
|
35
|
+
const setPortals = exports.EDITOR_TO_PORTAL.get(editor);
|
|
36
|
+
if (!setPortals)
|
|
37
|
+
return void 0;
|
|
38
|
+
const portal = (0, react_dom_1.createPortal)(node, dom || exports.MountNode.get(editor));
|
|
39
|
+
setPortals(prev => {
|
|
40
|
+
const newNodes = Object.assign({}, prev);
|
|
41
|
+
newNodes[key] = portal;
|
|
42
|
+
return newNodes;
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* 卸载节点
|
|
47
|
+
* @param editor
|
|
48
|
+
* @param key
|
|
49
|
+
*/
|
|
50
|
+
unmount: (editor, key) => {
|
|
51
|
+
const setPortals = exports.EDITOR_TO_PORTAL.get(editor);
|
|
52
|
+
if (!setPortals)
|
|
53
|
+
return void 0;
|
|
54
|
+
setPortals(prev => {
|
|
55
|
+
const newNodes = Object.assign({}, prev);
|
|
56
|
+
delete newNodes[key];
|
|
57
|
+
return newNodes;
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@block-kit/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/lib/index.js",
|
|
6
6
|
"types": "./dist/es/index.d.ts",
|
|
@@ -19,17 +19,29 @@
|
|
|
19
19
|
"lint:ts": "tsc -p tsconfig.build.json --noEmit",
|
|
20
20
|
"lint:circular": "madge --extensions js --circular ./dist"
|
|
21
21
|
},
|
|
22
|
-
"
|
|
23
|
-
"author": "",
|
|
22
|
+
"author": "WindRunnerMax",
|
|
24
23
|
"license": "MIT",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"editor",
|
|
26
|
+
"wysiwyg",
|
|
27
|
+
"rich-text"
|
|
28
|
+
],
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/WindrunnerMax/BlockKit.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/WindrunnerMax/BlockKit",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/WindrunnerMax/BlockKit/issues"
|
|
36
|
+
},
|
|
25
37
|
"peerDependencies": {
|
|
26
38
|
"react": ">=16",
|
|
27
39
|
"react-dom": ">=16"
|
|
28
40
|
},
|
|
29
41
|
"dependencies": {
|
|
30
|
-
"@block-kit/core": "1.0.
|
|
31
|
-
"@block-kit/delta": "1.0.
|
|
32
|
-
"@block-kit/utils": "1.0.
|
|
42
|
+
"@block-kit/core": "1.0.7",
|
|
43
|
+
"@block-kit/delta": "1.0.7",
|
|
44
|
+
"@block-kit/utils": "1.0.7"
|
|
33
45
|
},
|
|
34
46
|
"devDependencies": {
|
|
35
47
|
"@types/react": "17.0.2",
|