x-star-editor 0.0.2

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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -0
  3. package/dist/XStarEditor/index.d.ts +12 -0
  4. package/dist/XStarEditor/index.js +114 -0
  5. package/dist/XStarEditor/index.module.css +19 -0
  6. package/dist/XStarMdEditor/index.d.ts +31 -0
  7. package/dist/XStarMdEditor/index.js +263 -0
  8. package/dist/XStarMdEditor/index.module.css +13 -0
  9. package/dist/XStarMdViewer/index.d.ts +18 -0
  10. package/dist/XStarMdViewer/index.js +33 -0
  11. package/dist/XStarMdViewer/index.module.css +10 -0
  12. package/dist/components/FileInput.d.ts +15 -0
  13. package/dist/components/FileInput.js +107 -0
  14. package/dist/components/FileInput.module.css +81 -0
  15. package/dist/components/Toolbar.d.ts +22 -0
  16. package/dist/components/Toolbar.js +294 -0
  17. package/dist/components/Toolbar.module.css +116 -0
  18. package/dist/components/icons/bold.svg +1 -0
  19. package/dist/components/icons/code-library.svg +1 -0
  20. package/dist/components/icons/code.svg +1 -0
  21. package/dist/components/icons/image.svg +1 -0
  22. package/dist/components/icons/italic.svg +1 -0
  23. package/dist/components/icons/link.svg +1 -0
  24. package/dist/components/icons/strikethrough.svg +1 -0
  25. package/dist/index.d.ts +9 -0
  26. package/dist/index.js +5 -0
  27. package/dist/styles/fonts/KaTeX_AMS-Regular.ttf +0 -0
  28. package/dist/styles/fonts/KaTeX_AMS-Regular.woff +0 -0
  29. package/dist/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  30. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  31. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  32. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  33. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  34. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  35. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  36. package/dist/styles/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  37. package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  38. package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  39. package/dist/styles/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  40. package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  41. package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  42. package/dist/styles/fonts/KaTeX_Main-Bold.ttf +0 -0
  43. package/dist/styles/fonts/KaTeX_Main-Bold.woff +0 -0
  44. package/dist/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  45. package/dist/styles/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  46. package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  47. package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  48. package/dist/styles/fonts/KaTeX_Main-Italic.ttf +0 -0
  49. package/dist/styles/fonts/KaTeX_Main-Italic.woff +0 -0
  50. package/dist/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  51. package/dist/styles/fonts/KaTeX_Main-Regular.ttf +0 -0
  52. package/dist/styles/fonts/KaTeX_Main-Regular.woff +0 -0
  53. package/dist/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  54. package/dist/styles/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  55. package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  56. package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  57. package/dist/styles/fonts/KaTeX_Math-Italic.ttf +0 -0
  58. package/dist/styles/fonts/KaTeX_Math-Italic.woff +0 -0
  59. package/dist/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  60. package/dist/styles/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  61. package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  62. package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  63. package/dist/styles/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  64. package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  65. package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  66. package/dist/styles/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  67. package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  68. package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  69. package/dist/styles/fonts/KaTeX_Script-Regular.ttf +0 -0
  70. package/dist/styles/fonts/KaTeX_Script-Regular.woff +0 -0
  71. package/dist/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  72. package/dist/styles/fonts/KaTeX_Size1-Regular.ttf +0 -0
  73. package/dist/styles/fonts/KaTeX_Size1-Regular.woff +0 -0
  74. package/dist/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  75. package/dist/styles/fonts/KaTeX_Size2-Regular.ttf +0 -0
  76. package/dist/styles/fonts/KaTeX_Size2-Regular.woff +0 -0
  77. package/dist/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  78. package/dist/styles/fonts/KaTeX_Size3-Regular.ttf +0 -0
  79. package/dist/styles/fonts/KaTeX_Size3-Regular.woff +0 -0
  80. package/dist/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  81. package/dist/styles/fonts/KaTeX_Size4-Regular.ttf +0 -0
  82. package/dist/styles/fonts/KaTeX_Size4-Regular.woff +0 -0
  83. package/dist/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  84. package/dist/styles/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  85. package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  86. package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  87. package/dist/styles/katex.css +1120 -0
  88. package/dist/styles/markdown.css +129 -0
  89. package/dist/styles/prism.css +182 -0
  90. package/dist/utils/container.d.ts +45 -0
  91. package/dist/utils/container.js +366 -0
  92. package/dist/utils/handler.d.ts +44 -0
  93. package/dist/utils/handler.js +227 -0
  94. package/dist/utils/history.d.ts +59 -0
  95. package/dist/utils/history.js +305 -0
  96. package/dist/utils/jsx-runtime.d.ts +7 -0
  97. package/dist/utils/markdown.d.ts +38 -0
  98. package/dist/utils/markdown.js +292 -0
  99. package/dist/utils/module-css.d.ts +3 -0
  100. package/package.json +88 -0
@@ -0,0 +1,129 @@
1
+ .x-star-md-editor-block {
2
+ margin: 0.2em;
3
+ padding: 0.2em;
4
+ border-radius: 0.2em;
5
+ }
6
+
7
+ .x-star-md-editor-block:hover {
8
+ background-color: #f8f8f8;
9
+ }
10
+
11
+ .x-star-md-editor-delimiter,
12
+ .x-star-md-editor-break {
13
+ color: #f5771280;
14
+ }
15
+
16
+ .x-star-md-editor-heading {
17
+ font-weight: bold;
18
+ }
19
+
20
+ .x-star-md-editor-heading1 {
21
+ font-size: 1.6em;
22
+ }
23
+
24
+ .x-star-md-editor-heading2 {
25
+ font-size: 1.3em;
26
+ }
27
+
28
+ .x-star-md-editor-heading3 {
29
+ font-size: 1.2em;
30
+ }
31
+
32
+ .x-star-md-editor-heading4 {
33
+ font-size: 1.1em;
34
+ }
35
+
36
+ .x-star-md-editor-heading5 {
37
+ font-size: 1em;
38
+ }
39
+
40
+ .x-star-md-editor-heading6 {
41
+ font-size: 0.9em;
42
+ }
43
+
44
+ .x-star-md-editor-thematicBreak,
45
+ .x-star-md-editor-listItem > .x-star-md-editor-delimiter,
46
+ .x-star-md-editor-definition,
47
+ .x-star-md-editor-link,
48
+ .x-star-md-editor-image,
49
+ .x-star-md-editor-linkReference,
50
+ .x-star-md-editor-imageReference,
51
+ .x-star-md-editor-footnoteDefinition,
52
+ .x-star-md-editor-footnoteReference {
53
+ color: #f57712;
54
+ }
55
+
56
+ .x-star-md-editor-html,
57
+ .x-star-md-editor-code {
58
+ padding: 0 0.2em;
59
+ tab-size: 4;
60
+ font-family: Consolas;
61
+ color: #022679;
62
+ background-color: #02267910;
63
+ border-right: 1px solid #02267920;
64
+ border-left: 1px solid #02267920;
65
+ }
66
+
67
+ :is(.x-star-md-editor-html, .x-star-md-editor-code).x-star-md-editor-first {
68
+ border-top: 1px solid #02267920;
69
+ border-top-left-radius: 0.2em;
70
+ border-top-right-radius: 0.2em;
71
+ }
72
+
73
+ :is(.x-star-md-editor-html, .x-star-md-editor-code).x-star-md-editor-last {
74
+ border-bottom: 1px solid #02267920;
75
+ border-bottom-right-radius: 0.2em;
76
+ border-bottom-left-radius: 0.2em;
77
+ }
78
+
79
+ .x-star-md-editor-inlineCode {
80
+ margin: 0 0.2em;
81
+ padding: 0 0.2em;
82
+ tab-size: 4;
83
+ font-family: Consolas;
84
+ color: #022679;
85
+ background-color: #02267910;
86
+ border: 1px solid #02267920;
87
+ border-radius: 0.2em;
88
+ }
89
+
90
+ .x-star-md-editor-emphasis {
91
+ font-style: italic;
92
+ }
93
+
94
+ .x-star-md-editor-strong {
95
+ font-weight: bold;
96
+ }
97
+
98
+ .x-star-md-editor-delete > :not(.x-star-md-editor-delimiter) {
99
+ text-decoration: line-through;
100
+ }
101
+
102
+ .x-star-md-editor-math {
103
+ padding: 0 0.2em;
104
+ color: #f57712;
105
+ background-color: #f5771210;
106
+ border-right: 1px solid #f5771220;
107
+ border-left: 1px solid #f5771220;
108
+ }
109
+
110
+ .x-star-md-editor-math.x-star-md-editor-first {
111
+ border-top: 1px solid #f5771220;
112
+ border-top-left-radius: 0.2em;
113
+ border-top-right-radius: 0.2em;
114
+ }
115
+
116
+ .x-star-md-editor-math.x-star-md-editor-last {
117
+ border-bottom: 1px solid #f5771220;
118
+ border-bottom-right-radius: 0.2em;
119
+ border-bottom-left-radius: 0.2em;
120
+ }
121
+
122
+ .x-star-md-editor-inlineMath {
123
+ margin: 0 0.2em;
124
+ padding: 0 0.2em;
125
+ color: #f57712;
126
+ background-color: #f5771210;
127
+ border: 1px solid #f5771220;
128
+ border-radius: 0.2em;
129
+ }
@@ -0,0 +1,182 @@
1
+ /**
2
+ * VS theme by Andrew Lock (https://andrewlock.net)
3
+ * Inspired by Visual Studio syntax coloring
4
+ */
5
+
6
+ .x-star-md-viewer.x-star-md-viewer code,
7
+ .x-star-md-viewer.x-star-md-viewer pre {
8
+ margin: 0.2em;
9
+ color: #f57712;
10
+ border-radius: 0.2em;
11
+ font-family: 'Consolas', 'Bitstream Vera Sans Mono', 'Courier New', Courier,
12
+ monospace;
13
+ direction: ltr;
14
+ text-align: left;
15
+ white-space: pre;
16
+ word-spacing: normal;
17
+ word-break: normal;
18
+ font-size: 0.9em;
19
+ line-height: 1.2em;
20
+
21
+ -moz-tab-size: 4;
22
+ -o-tab-size: 4;
23
+ tab-size: 4;
24
+
25
+ -webkit-hyphens: none;
26
+ -moz-hyphens: none;
27
+ -ms-hyphens: none;
28
+ hyphens: none;
29
+ }
30
+
31
+ .x-star-md-viewer.x-star-md-viewer pre > code {
32
+ margin: 0;
33
+ color: #393a34;
34
+ font-size: 1em;
35
+ }
36
+
37
+ .x-star-md-viewer.x-star-md-viewer pre::-moz-selection,
38
+ .x-star-md-viewer.x-star-md-viewer pre ::-moz-selection,
39
+ .x-star-md-viewer.x-star-md-viewer code::-moz-selection,
40
+ .x-star-md-viewer.x-star-md-viewer code ::-moz-selection {
41
+ background-color: #c1def1;
42
+ }
43
+
44
+ .x-star-md-viewer.x-star-md-viewer pre::selection,
45
+ .x-star-md-viewer.x-star-md-viewer pre ::selection,
46
+ .x-star-md-viewer.x-star-md-viewer code::selection,
47
+ .x-star-md-viewer.x-star-md-viewer code ::selection {
48
+ background-color: #c1def1;
49
+ }
50
+
51
+ /* Code blocks */
52
+ .x-star-md-viewer.x-star-md-viewer pre {
53
+ padding: 1em;
54
+ margin: 0.5em 0;
55
+ overflow: auto;
56
+ border: 1px solid #dddddd;
57
+ background-color: white;
58
+ }
59
+
60
+ /* Inline code */
61
+ .x-star-md-viewer.x-star-md-viewer :not(pre) > code {
62
+ padding: 0.2em;
63
+ padding-top: 1px;
64
+ padding-bottom: 1px;
65
+ background-color: #f8f8f8;
66
+ border: 1px solid #dddddd;
67
+ }
68
+
69
+ .x-star-md-viewer .token.comment,
70
+ .x-star-md-viewer .token.prolog,
71
+ .x-star-md-viewer .token.doctype,
72
+ .x-star-md-viewer .token.cdata {
73
+ color: #008000;
74
+ font-style: italic;
75
+ }
76
+
77
+ .x-star-md-viewer .token.namespace {
78
+ opacity: 0.7;
79
+ }
80
+
81
+ .x-star-md-viewer .token.string {
82
+ color: #a31515;
83
+ }
84
+
85
+ .x-star-md-viewer .token.punctuation,
86
+ .x-star-md-viewer .token.operator {
87
+ color: #393a34; /* no highlight */
88
+ }
89
+
90
+ .x-star-md-viewer .token.url,
91
+ .x-star-md-viewer .token.symbol,
92
+ .x-star-md-viewer .token.number,
93
+ .x-star-md-viewer .token.boolean,
94
+ .x-star-md-viewer .token.variable,
95
+ .x-star-md-viewer .token.constant,
96
+ .x-star-md-viewer .token.inserted {
97
+ color: #36acaa;
98
+ }
99
+
100
+ .x-star-md-viewer .token.atrule,
101
+ .x-star-md-viewer .token.keyword,
102
+ .x-star-md-viewer .token.attr-value,
103
+ .x-star-md-viewer .language-autohotkey .token.selector,
104
+ .x-star-md-viewer .language-json .token.boolean,
105
+ .x-star-md-viewer .language-json .token.number,
106
+ .x-star-md-viewer code[class*='language-css'] {
107
+ color: #0000ff;
108
+ }
109
+
110
+ .x-star-md-viewer .token.function {
111
+ color: #393a34;
112
+ }
113
+
114
+ .x-star-md-viewer .token.deleted,
115
+ .x-star-md-viewer .language-autohotkey .token.tag {
116
+ color: #9a050f;
117
+ }
118
+
119
+ .x-star-md-viewer .token.selector,
120
+ .x-star-md-viewer .language-autohotkey .token.keyword {
121
+ color: #00009f;
122
+ }
123
+
124
+ .x-star-md-viewer .token.important {
125
+ color: #e90;
126
+ }
127
+
128
+ .x-star-md-viewer .token.important,
129
+ .x-star-md-viewer .token.bold {
130
+ font-weight: bold;
131
+ }
132
+
133
+ .x-star-md-viewer .token.italic {
134
+ font-style: italic;
135
+ }
136
+
137
+ .x-star-md-viewer .token.class-name,
138
+ .x-star-md-viewer .language-json .token.property {
139
+ color: #2b91af;
140
+ }
141
+
142
+ .x-star-md-viewer .token.tag,
143
+ .x-star-md-viewer .token.selector {
144
+ color: #800000;
145
+ }
146
+
147
+ .x-star-md-viewer .token.attr-name,
148
+ .x-star-md-viewer .token.property,
149
+ .x-star-md-viewer .token.regex,
150
+ .x-star-md-viewer .token.entity {
151
+ color: #ff0000;
152
+ }
153
+
154
+ .x-star-md-viewer .token.directive.tag .tag {
155
+ background-color: #ffff00;
156
+ color: #393a34;
157
+ }
158
+
159
+ .x-star-md-viewer .line-number::before {
160
+ width: 2em;
161
+ margin-right: 16px;
162
+ margin-left: -8px;
163
+ display: inline-block;
164
+ text-align: right;
165
+ color: #2b91af;
166
+ content: attr(line);
167
+ }
168
+
169
+ .x-star-md-viewer .highlight-line {
170
+ display: block;
171
+ background-color: rgba(193, 222, 241, 0.2);
172
+ background-image: -webkit-linear-gradient(
173
+ left,
174
+ rgba(193, 222, 241, 0.2) 70%,
175
+ rgba(221, 222, 241, 0)
176
+ );
177
+ background-image: linear-gradient(
178
+ to right,
179
+ rgba(193, 222, 241, 0.2) 70%,
180
+ rgba(221, 222, 241, 0)
181
+ );
182
+ }
@@ -0,0 +1,45 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * 容器选区,表示从锚点到焦点的文本
4
+ */
5
+ export interface ContainerSelection {
6
+ /**
7
+ * 锚点偏移量
8
+ */
9
+ anchorOffset: number;
10
+ /**
11
+ * 焦点偏移量
12
+ */
13
+ focusOffset: number;
14
+ }
15
+ /**
16
+ * 创建容器选区
17
+ *
18
+ * @param anchorOffset 锚点偏移量
19
+ * @param focusOffset 焦点偏移量,默认与锚点偏移量相同
20
+ * @returns 容器选区
21
+ */
22
+ export declare const createSelection: (anchorOffset: number, focusOffset?: number) => ContainerSelection;
23
+ /**
24
+ * 根据容器选区获取容器范围
25
+ *
26
+ * @param selection 容器选区
27
+ * @returns 容器范围
28
+ */
29
+ export declare const getRange: ({ anchorOffset, focusOffset, }: ContainerSelection) => {
30
+ startOffset: number;
31
+ endOffset: number;
32
+ };
33
+ /**
34
+ * 获取一个可以设置文本和选区的容器
35
+ *
36
+ * @returns 容器
37
+ */
38
+ export declare const useContainer: () => {
39
+ ref: import("react").RefObject<HTMLDivElement>;
40
+ normalize: () => void;
41
+ getText: () => string;
42
+ setText: (text: string) => void;
43
+ getSelection: () => ContainerSelection;
44
+ setSelection: ({ anchorOffset, focusOffset }: ContainerSelection) => void;
45
+ };
@@ -0,0 +1,366 @@
1
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
2
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
3
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
4
+ import { useEffect, useRef } from 'react';
5
+ import { editorRender } from "./markdown";
6
+
7
+ /**
8
+ * 容器选区,表示从锚点到焦点的文本
9
+ */
10
+
11
+ /**
12
+ * 创建容器选区
13
+ *
14
+ * @param anchorOffset 锚点偏移量
15
+ * @param focusOffset 焦点偏移量,默认与锚点偏移量相同
16
+ * @returns 容器选区
17
+ */
18
+ export var createSelection = function createSelection(anchorOffset) {
19
+ var focusOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : anchorOffset;
20
+ return {
21
+ anchorOffset: anchorOffset,
22
+ focusOffset: focusOffset
23
+ };
24
+ };
25
+
26
+ /**
27
+ * 根据容器选区获取容器范围
28
+ *
29
+ * @param selection 容器选区
30
+ * @returns 容器范围
31
+ */
32
+ export var getRange = function getRange(_ref) {
33
+ var anchorOffset = _ref.anchorOffset,
34
+ focusOffset = _ref.focusOffset;
35
+ return {
36
+ startOffset: anchorOffset < focusOffset ? anchorOffset : focusOffset,
37
+ endOffset: anchorOffset < focusOffset ? focusOffset : anchorOffset
38
+ };
39
+ };
40
+
41
+ /**
42
+ * 获取一个可以设置文本和选区的容器
43
+ *
44
+ * @returns 容器
45
+ */
46
+ export var useContainer = function useContainer() {
47
+ /**
48
+ * 容器挂载的 DOM 节点
49
+ */
50
+ var ref = useRef(null);
51
+
52
+ /**
53
+ * 将 DOM 树规范化
54
+ *
55
+ * 检查每个行节点的末尾是否为零宽空格,如果不是,则删除行中的零宽空格并在末尾添加零宽空格
56
+ */
57
+ var normalize = function normalize() {
58
+ if (!ref.current) {
59
+ return;
60
+ }
61
+ var traverse = function traverse(node, depth) {
62
+ if (depth === 2) {
63
+ var _node$lastChild;
64
+ // 检查行节点的末尾
65
+ if (((_node$lastChild = node.lastChild) === null || _node$lastChild === void 0 ? void 0 : _node$lastChild.nodeType) === Node.TEXT_NODE) {
66
+ var _node$lastChild$nodeV;
67
+ if ((_node$lastChild$nodeV = node.lastChild.nodeValue) !== null && _node$lastChild$nodeV !== void 0 && _node$lastChild$nodeV.endsWith("\u200B")) {
68
+ return;
69
+ }
70
+ }
71
+ } else if (depth > 2) {
72
+ // 删除行中的零宽空格
73
+ if (node.nodeType === Node.TEXT_NODE) {
74
+ var _node$nodeValue;
75
+ if ((_node$nodeValue = node.nodeValue) !== null && _node$nodeValue !== void 0 && _node$nodeValue.includes("\u200B")) {
76
+ node.nodeValue = node.nodeValue.replace(/\u200B/g, '');
77
+ }
78
+ return;
79
+ }
80
+ }
81
+ for (var i = 0; i < node.childNodes.length; i++) {
82
+ traverse(node.childNodes[i], depth + 1);
83
+ }
84
+ if (depth === 2) {
85
+ // 添加零宽空格
86
+ node.appendChild(document.createTextNode("\u200B"));
87
+ }
88
+ };
89
+ traverse(ref.current, 0);
90
+ };
91
+
92
+ /**
93
+ * 获取容器文本
94
+ *
95
+ * 在 DOM 树上遍历,将文本节点的值连接起来
96
+ *
97
+ * @returns 容器文本
98
+ */
99
+ var getText = function getText() {
100
+ if (!ref.current) {
101
+ return '';
102
+ }
103
+ var text = '';
104
+ var traverse = function traverse(node) {
105
+ if (node.nodeType === Node.TEXT_NODE) {
106
+ if (node.nodeValue) {
107
+ text += node.nodeValue;
108
+ }
109
+ } else {
110
+ for (var i = 0; i < node.childNodes.length; i++) {
111
+ traverse(node.childNodes[i]);
112
+ }
113
+ }
114
+ };
115
+ traverse(ref.current);
116
+ return text.slice(0, -1).replace(/\u200B/g, '\n');
117
+ };
118
+
119
+ /**
120
+ * 设置容器文本
121
+ *
122
+ * 将文本映射到 DOM 树,用 diff 算法更新 DOM 树
123
+ *
124
+ * @param text 容器文本
125
+ */
126
+ var setText = function setText(text) {
127
+ if (!ref.current) {
128
+ return;
129
+ }
130
+
131
+ /**
132
+ * 将一棵 DOM 树更新为另一棵 DOM 树
133
+ *
134
+ * @param newNode 新节点
135
+ * @param oldNode 旧节点
136
+ */
137
+ var diff = function diff(newNode, oldNode) {
138
+ var newChild = newNode.firstChild;
139
+ var oldChild = oldNode.firstChild;
140
+
141
+ // 依次更新子节点
142
+ for (; newChild && oldChild;) {
143
+ var newNext = newChild.nextSibling;
144
+ var oldNext = oldChild.nextSibling;
145
+ if (newChild.nodeName !== oldChild.nodeName) {
146
+ // 节点名称不同,直接替换
147
+ oldChild.replaceWith(newChild);
148
+ } else if (newChild.nodeType === Node.TEXT_NODE) {
149
+ // 节点均为文本类型,更新文本内容
150
+ if (newChild.nodeValue !== oldChild.nodeValue) {
151
+ oldChild.nodeValue = newChild.nodeValue;
152
+ }
153
+ } else {
154
+ // 节点名称相同,更新属性和子节点
155
+ if (newChild instanceof Element && oldChild instanceof Element) {
156
+ var _iterator = _createForOfIteratorHelper(oldChild.getAttributeNames()),
157
+ _step;
158
+ try {
159
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
160
+ var oldAttrName = _step.value;
161
+ if (!newChild.hasAttribute(oldAttrName)) {
162
+ // 移除新节点没有的属性
163
+ oldChild.removeAttribute(oldAttrName);
164
+ }
165
+ }
166
+ } catch (err) {
167
+ _iterator.e(err);
168
+ } finally {
169
+ _iterator.f();
170
+ }
171
+ var _iterator2 = _createForOfIteratorHelper(newChild.getAttributeNames()),
172
+ _step2;
173
+ try {
174
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
175
+ var newAttrName = _step2.value;
176
+ var newAttrValue = newChild.getAttribute(newAttrName);
177
+ var oldAttrValue = oldChild.getAttribute(newAttrName);
178
+ if (newAttrValue !== null && newAttrValue !== oldAttrValue) {
179
+ oldChild.setAttribute(newAttrName, newAttrValue);
180
+ }
181
+ }
182
+ } catch (err) {
183
+ _iterator2.e(err);
184
+ } finally {
185
+ _iterator2.f();
186
+ }
187
+ }
188
+ diff(newChild, oldChild);
189
+ }
190
+ newChild = newNext;
191
+ oldChild = oldNext;
192
+ }
193
+
194
+ // 移除节点
195
+ for (; oldChild;) {
196
+ var _oldNext = oldChild.nextSibling;
197
+ oldChild.remove();
198
+ oldChild = _oldNext;
199
+ }
200
+
201
+ // 添加节点
202
+ for (; newChild;) {
203
+ var _newNext = newChild.nextSibling;
204
+ oldNode.appendChild(newChild);
205
+ newChild = _newNext;
206
+ }
207
+ };
208
+ diff(editorRender(text), ref.current);
209
+ };
210
+
211
+ /**
212
+ * 获取容器选区
213
+ *
214
+ * 用 Selection API 获取选中的 DOM 节点和节点内偏移量,在 DOM 树上遍历获取对应的容器内偏移量
215
+ *
216
+ * @returns 容器选区
217
+ */
218
+ var getSelection = function getSelection() {
219
+ var selection = window.getSelection();
220
+ if (!selection || !selection.anchorNode || !selection.focusNode) {
221
+ return createSelection(-1);
222
+ }
223
+
224
+ /**
225
+ * 根据节点和节点内偏移量获取容器内偏移量
226
+ *
227
+ * @param targetNode 节点
228
+ * @param targetOffset 节点内偏移量
229
+ * @returns 容器内偏移量
230
+ */
231
+ var getOffset = function getOffset(targetNode, targetOffset) {
232
+ if (!ref.current) {
233
+ return -1;
234
+ }
235
+ var offset = 0;
236
+ var traverse = function traverse(node) {
237
+ if (node === targetNode) {
238
+ if (node.nodeType === Node.TEXT_NODE) {
239
+ if (node.nodeValue) {
240
+ offset += targetOffset;
241
+ if (node.nodeValue[targetOffset - 1] === "\u200B") {
242
+ offset--;
243
+ }
244
+ }
245
+ } else {
246
+ for (var i = 0; i < targetOffset; i++) {
247
+ traverse(node.childNodes[i]);
248
+ }
249
+ }
250
+ return true;
251
+ }
252
+ if (node.nodeType === Node.TEXT_NODE) {
253
+ if (node.nodeValue) {
254
+ offset += node.nodeValue.length;
255
+ }
256
+ } else {
257
+ for (var _i = 0; _i < node.childNodes.length; _i++) {
258
+ if (traverse(node.childNodes[_i])) {
259
+ return true;
260
+ }
261
+ }
262
+ }
263
+ };
264
+ return traverse(ref.current) ? offset : -1;
265
+ };
266
+ return createSelection(getOffset(selection.anchorNode, selection.anchorOffset), getOffset(selection.focusNode, selection.focusOffset));
267
+ };
268
+
269
+ /**
270
+ * 设置容器选区
271
+ *
272
+ * 根据容器内偏移量,在 DOM 树上遍历获取对应的 DOM 节点和节点内偏移量,用 Selection API 选中
273
+ *
274
+ * @param selection 容器选区
275
+ */
276
+ var setSelection = function setSelection(_ref2) {
277
+ var anchorOffset = _ref2.anchorOffset,
278
+ focusOffset = _ref2.focusOffset;
279
+ var selection = window.getSelection();
280
+ if (!selection || anchorOffset === -1 || focusOffset === -1) {
281
+ return;
282
+ }
283
+
284
+ /**
285
+ * 根据容器内偏移量获取节点和节点内偏移量
286
+ *
287
+ * @param targetOffset 容器内偏移量
288
+ * @returns 节点和节点内偏移量
289
+ */
290
+ var getNodeOffset = function getNodeOffset(targetOffset) {
291
+ if (!ref.current) {
292
+ return {
293
+ node: undefined,
294
+ offset: 0
295
+ };
296
+ }
297
+ var offset = targetOffset;
298
+ var traverse = function traverse(node) {
299
+ if (node.nodeType === Node.TEXT_NODE) {
300
+ if (node.nodeValue) {
301
+ if (offset < node.nodeValue.length) {
302
+ return node;
303
+ }
304
+ offset -= node.nodeValue.length;
305
+ }
306
+ } else {
307
+ for (var i = 0; i < node.childNodes.length; i++) {
308
+ var result = traverse(node.childNodes[i]);
309
+ if (result) {
310
+ return result;
311
+ }
312
+ }
313
+ }
314
+ };
315
+ return {
316
+ node: traverse(ref.current),
317
+ offset: offset
318
+ };
319
+ };
320
+ var anchor = getNodeOffset(anchorOffset);
321
+ var focus = getNodeOffset(focusOffset);
322
+ if (!anchor.node || !focus.node) {
323
+ return;
324
+ }
325
+ selection.setBaseAndExtent(anchor.node, anchor.offset, focus.node, focus.offset);
326
+ };
327
+
328
+ // 容器选区改变后将光标滚动到视口内
329
+ useEffect(function () {
330
+ var listener = function listener() {
331
+ var selection = window.getSelection();
332
+ if (!selection || !selection.focusNode || !ref.current || !ref.current.contains(selection.focusNode)) {
333
+ return;
334
+ }
335
+ var range = document.createRange();
336
+ range.setStart(selection.focusNode, selection.focusOffset);
337
+ range.setEnd(selection.focusNode, selection.focusOffset);
338
+ var rangeRect = range.getBoundingClientRect();
339
+ var containerRect = ref.current.getBoundingClientRect();
340
+ var topOffset = rangeRect.top - containerRect.top;
341
+ var bottomOffset = rangeRect.bottom - containerRect.bottom;
342
+ if (topOffset < 10) {
343
+ ref.current.scrollTop += topOffset - 10;
344
+ } else if (bottomOffset > -10) {
345
+ ref.current.scrollTop += bottomOffset + 10;
346
+ }
347
+ };
348
+ document.addEventListener('selectionchange', listener, {
349
+ capture: true,
350
+ passive: true
351
+ });
352
+ return function () {
353
+ return document.removeEventListener('selectionchange', listener, {
354
+ capture: true
355
+ });
356
+ };
357
+ }, []);
358
+ return useRef({
359
+ ref: ref,
360
+ normalize: normalize,
361
+ getText: getText,
362
+ setText: setText,
363
+ getSelection: getSelection,
364
+ setSelection: setSelection
365
+ }).current;
366
+ };