x-star-editor 0.3.0 → 0.3.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.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export type { ToolbarItem } from './components/Toolbar';
2
2
  export { createSelection, getRange } from './utils/container';
3
- export { insertHandler, redoHandler, selectHandler, setHandler, toggleHandler, undoHandler, } from './utils/handler';
3
+ export { batchHandler, insertHandler, redoHandler, selectHandler, setHandler, toggleHandler, undoHandler, } from './utils/handler';
4
4
  export type { Executor, Handler, KeyboardEventHandler } from './utils/handler';
5
5
  export { toHTML, toMarkdown, toText } from './utils/markdown';
6
6
  export { default as XStarEditor, useEditorRef } from './x-star-editor';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createSelection, getRange } from "./utils/container";
2
- export { insertHandler, redoHandler, selectHandler, setHandler, toggleHandler, undoHandler } from "./utils/handler";
2
+ export { batchHandler, insertHandler, redoHandler, selectHandler, setHandler, toggleHandler, undoHandler } from "./utils/handler";
3
3
  export { toHTML, toMarkdown, toText } from "./utils/markdown";
4
4
  export { default as XStarEditor, useEditorRef } from "./x-star-editor";
5
5
  export { default as XStarMdEditor, useMdEditorRef } from "./x-star-md-editor";
@@ -1,5 +1,5 @@
1
1
  import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
2
- import { useRef } from 'react';
2
+ import { useEffect, useRef } from 'react';
3
3
  import { editorRender } from "./markdown";
4
4
 
5
5
  /**
@@ -304,6 +304,42 @@ export var useContainer = function useContainer(ref) {
304
304
  ref.current.scrollTop += bottomOffset;
305
305
  }
306
306
  };
307
+
308
+ // 确保光标不在零宽空格后
309
+ useEffect(function () {
310
+ var listener = function listener() {
311
+ var _ref$current, _anchorNode$nodeValue, _focusNode$nodeValue;
312
+ var selection = window.getSelection();
313
+ if (!selection || !selection.anchorNode || !selection.focusNode || !((_ref$current = ref.current) !== null && _ref$current !== void 0 && _ref$current.contains(selection.anchorNode))) {
314
+ return;
315
+ }
316
+ var update = false;
317
+ var anchorNode = selection.anchorNode,
318
+ anchorOffset = selection.anchorOffset,
319
+ focusNode = selection.focusNode,
320
+ focusOffset = selection.focusOffset;
321
+ if (anchorNode.nodeType === Node.TEXT_NODE && ((_anchorNode$nodeValue = anchorNode.nodeValue) === null || _anchorNode$nodeValue === void 0 ? void 0 : _anchorNode$nodeValue[anchorOffset - 1]) === "\u200B") {
322
+ update = true;
323
+ anchorOffset--;
324
+ }
325
+ if (focusNode.nodeType === Node.TEXT_NODE && ((_focusNode$nodeValue = focusNode.nodeValue) === null || _focusNode$nodeValue === void 0 ? void 0 : _focusNode$nodeValue[focusOffset - 1]) === "\u200B") {
326
+ update = true;
327
+ focusOffset--;
328
+ }
329
+ if (update) {
330
+ selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
331
+ }
332
+ };
333
+ document.addEventListener('selectionchange', listener, {
334
+ capture: true,
335
+ passive: true
336
+ });
337
+ return function () {
338
+ return document.removeEventListener('selectionchange', listener, {
339
+ capture: true
340
+ });
341
+ };
342
+ }, []);
307
343
  return useRef({
308
344
  getText: getText,
309
345
  setText: setText,
@@ -15,6 +15,7 @@ export declare const toggleHandler: (payload: ToggleAction['payload']) => Handle
15
15
  export declare const setHandler: (payload: SetAction['payload']) => Handler;
16
16
  export declare const undoHandler: () => Handler;
17
17
  export declare const redoHandler: () => Handler;
18
+ export declare const batchHandler: () => Handler;
18
19
  export declare const selectHandler: (selection: SelectAction['selection']) => Handler;
19
20
  /**
20
21
  * 执行函数
@@ -1,6 +1,6 @@
1
1
  import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
2
2
  import { createKeybindingsHandler } from 'tinykeys';
3
- import { createSelection, getRange } from "./container";
3
+ import { createSelection } from "./container";
4
4
 
5
5
  /**
6
6
  * 处理函数上下文
@@ -59,9 +59,17 @@ export var redoHandler = function redoHandler() {
59
59
  });
60
60
  };
61
61
  };
62
- export var selectHandler = function selectHandler(selection) {
62
+ export var batchHandler = function batchHandler() {
63
63
  return function (_ref6) {
64
64
  var dispatch = _ref6.dispatch;
65
+ return dispatch({
66
+ type: 'batch'
67
+ });
68
+ };
69
+ };
70
+ export var selectHandler = function selectHandler(selection) {
71
+ return function (_ref7) {
72
+ var dispatch = _ref7.dispatch;
65
73
  return dispatch({
66
74
  type: 'select',
67
75
  selection: selection
@@ -80,11 +88,11 @@ export var selectHandler = function selectHandler(selection) {
80
88
  */
81
89
 
82
90
  export var getDefaultKeyboardEventHandlers = function getDefaultKeyboardEventHandlers() {
83
- return [function (_ref7) {
84
- var sourceCode = _ref7.sourceCode,
85
- selection = _ref7.selection,
86
- dispatch = _ref7.dispatch,
87
- e = _ref7.e;
91
+ return [function (_ref8) {
92
+ var sourceCode = _ref8.sourceCode,
93
+ selection = _ref8.selection,
94
+ dispatch = _ref8.dispatch,
95
+ e = _ref8.e;
88
96
  return createKeybindingsHandler({
89
97
  Tab: function Tab(e) {
90
98
  e.preventDefault();
@@ -108,56 +116,22 @@ export var getDefaultKeyboardEventHandlers = function getDefaultKeyboardEventHan
108
116
  type: 'redo'
109
117
  });
110
118
  },
111
- ArrowLeft: function ArrowLeft(e) {
112
- e.preventDefault();
113
- var _getRange = getRange(selection),
114
- startOffset = _getRange.startOffset,
115
- endOffset = _getRange.endOffset;
116
- if (startOffset < endOffset) {
117
- dispatch({
118
- type: 'select',
119
- selection: createSelection(startOffset)
120
- });
121
- } else if (startOffset) {
122
- dispatch({
123
- type: 'select',
124
- selection: createSelection(startOffset - 1)
125
- });
126
- }
127
- },
128
- 'Shift+ArrowLeft': function ShiftArrowLeft(e) {
129
- e.preventDefault();
119
+ ArrowRight: function ArrowRight(e) {
130
120
  var anchorOffset = selection.anchorOffset,
131
121
  focusOffset = selection.focusOffset;
132
- if (focusOffset) {
133
- dispatch({
134
- type: 'select',
135
- selection: createSelection(anchorOffset, focusOffset - 1)
136
- });
137
- }
138
- },
139
- ArrowRight: function ArrowRight(e) {
140
- e.preventDefault();
141
- var _getRange2 = getRange(selection),
142
- startOffset = _getRange2.startOffset,
143
- endOffset = _getRange2.endOffset;
144
- if (startOffset < endOffset) {
122
+ if (anchorOffset === focusOffset && sourceCode[focusOffset] === '\n') {
123
+ e.preventDefault();
145
124
  dispatch({
146
125
  type: 'select',
147
- selection: createSelection(endOffset)
148
- });
149
- } else if (startOffset < sourceCode.length) {
150
- dispatch({
151
- type: 'select',
152
- selection: createSelection(startOffset + 1)
126
+ selection: createSelection(focusOffset + 1)
153
127
  });
154
128
  }
155
129
  },
156
130
  'Shift+ArrowRight': function ShiftArrowRight(e) {
157
- e.preventDefault();
158
131
  var anchorOffset = selection.anchorOffset,
159
132
  focusOffset = selection.focusOffset;
160
- if (focusOffset < sourceCode.length) {
133
+ if (sourceCode[focusOffset] === '\n') {
134
+ e.preventDefault();
161
135
  dispatch({
162
136
  type: 'select',
163
137
  selection: createSelection(anchorOffset, focusOffset + 1)
@@ -44,7 +44,9 @@ type StateAction = InsertAction | ToggleAction | SetAction;
44
44
  */
45
45
  interface History {
46
46
  states: (State & {
47
- action: StateAction;
47
+ action: StateAction & {
48
+ batch?: boolean;
49
+ };
48
50
  })[];
49
51
  index: number;
50
52
  selection: ContainerSelection;
@@ -55,15 +57,21 @@ export interface UndoAction {
55
57
  export interface RedoAction {
56
58
  type: 'redo';
57
59
  }
60
+ export interface BatchAction {
61
+ type: 'batch';
62
+ selection?: ContainerSelection;
63
+ }
58
64
  export interface SelectAction {
59
65
  type: 'select';
60
66
  selection: ContainerSelection;
61
67
  }
62
- type HistoryAction = UndoAction | RedoAction | SelectAction;
68
+ type HistoryAction = UndoAction | RedoAction | BatchAction | SelectAction;
63
69
  export declare const useHistory: (initialSourceCode: string) => {
64
70
  history: History;
65
71
  sourceCode: string;
66
72
  selection: ContainerSelection;
67
- dispatch: import("react").Dispatch<StateAction | HistoryAction>;
73
+ dispatch: import("react").Dispatch<HistoryAction | (StateAction & {
74
+ batch?: boolean | undefined;
75
+ })>;
68
76
  };
69
77
  export {};
@@ -132,8 +132,8 @@ var stateReducer = function stateReducer(_ref, action) {
132
132
  url = _action$payload2.url,
133
133
  description = _action$payload2.description;
134
134
  return {
135
- sourceCode: "".concat(before).concat(_type === 'link' ? '' : '!', "[").concat(description, "](").concat(url, ")").concat(after),
136
- selection: createSelection(startOffset + url.length + description.length + 4 + (_type === 'link' ? 0 : 1))
135
+ sourceCode: "".concat(before).concat(_type === 'image' ? '!' : '', "[").concat(description, "](").concat(url, ")").concat(after),
136
+ selection: createSelection(startOffset + url.length + description.length + 4 + (_type === 'image' ? 1 : 0))
137
137
  };
138
138
  }
139
139
  case 'math':
@@ -214,6 +214,20 @@ var historyReducer = function historyReducer(_ref2, action) {
214
214
  selection: states[index + 1].selection
215
215
  };
216
216
  }
217
+ case 'batch':
218
+ {
219
+ var _action$selection2, _action$selection3;
220
+ return {
221
+ states: [].concat(_toConsumableArray(states.slice(0, index)), [_objectSpread(_objectSpread({}, states[index]), {}, {
222
+ selection: (_action$selection2 = action.selection) !== null && _action$selection2 !== void 0 ? _action$selection2 : states[index].selection,
223
+ action: _objectSpread(_objectSpread({}, states[index].action), {}, {
224
+ batch: false
225
+ })
226
+ })]),
227
+ index: index,
228
+ selection: (_action$selection3 = action.selection) !== null && _action$selection3 !== void 0 ? _action$selection3 : selection
229
+ };
230
+ }
217
231
  case 'select':
218
232
  {
219
233
  return {
@@ -233,8 +247,19 @@ var historyReducer = function historyReducer(_ref2, action) {
233
247
  selection: selection
234
248
  };
235
249
  }
250
+ if (states[index].action.batch && action.batch) {
251
+ return {
252
+ states: [].concat(_toConsumableArray(states.slice(0, index)), [_objectSpread(_objectSpread({}, states[index]), state)]),
253
+ index: index,
254
+ selection: state.selection
255
+ };
256
+ }
236
257
  return {
237
- states: [].concat(_toConsumableArray(states.slice(index < 100 ? 0 : index - 99, index + 1)), [_objectSpread(_objectSpread({}, state), {}, {
258
+ states: [].concat(_toConsumableArray(states.slice(index < 100 ? 0 : index - 99, index)), [_objectSpread(_objectSpread({}, states[index]), {}, {
259
+ action: _objectSpread(_objectSpread({}, states[index].action), {}, {
260
+ batch: false
261
+ })
262
+ }), _objectSpread(_objectSpread({}, state), {}, {
238
263
  action: action
239
264
  })]),
240
265
  index: index < 100 ? index + 1 : 100,
@@ -3,7 +3,6 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3
3
  import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
4
4
  import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
5
5
  import _createForOfIteratorHelper from "@babel/runtime/helpers/esm/createForOfIteratorHelper";
6
- import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
7
6
  import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
8
7
  import { toText as hastToText } from 'hast-util-to-text';
9
8
  import { Fragment, jsx, jsxs } from 'react/jsx-runtime';
@@ -32,20 +31,6 @@ import rehypeRawPositions from "./rehype/rehype-raw-positions";
32
31
  */
33
32
  var toMdastProcessor = unified().use(remarkParse).use(remarkGfm).use(remarkMath).freeze();
34
33
 
35
- /**
36
- * 带缓存的解析函数
37
- *
38
- * @param sourceCode Markdown 文本
39
- * @returns Mdast 树
40
- */
41
- var cachedParse = function () {
42
- var cache = {};
43
- return function (sourceCode) {
44
- var _cache$sourceCode;
45
- return (_cache$sourceCode = cache[sourceCode]) !== null && _cache$sourceCode !== void 0 ? _cache$sourceCode : (cache = _defineProperty({}, sourceCode, toMdastProcessor.parse(sourceCode)))[sourceCode];
46
- };
47
- }();
48
-
49
34
  /**
50
35
  * 将 Markdown 文本映射到 DOM 树,第一层为 `<div>` 块元素,第二层为 `<div>` 行元素,之后均为 `<span>` 元素
51
36
  *
@@ -243,7 +228,7 @@ export var editorRender = function editorRender(sourceCode) {
243
228
  }
244
229
  addText(sourceCode.slice(scanOffset, parentEndOffset), true);
245
230
  };
246
- getChildren(cachedParse(sourceCode).children, sourceCode.length);
231
+ getChildren(toMdastProcessor.parse(sourceCode).children, sourceCode.length);
247
232
  if (scanOffset <= sourceCode.length) {
248
233
  // 添加最后一行文本
249
234
  block.append(createLine(sourceCode.slice(scanOffset)));
@@ -289,7 +274,7 @@ export var preViewerRender = /*#__PURE__*/function () {
289
274
  while (1) switch (_context.prev = _context.next) {
290
275
  case 0:
291
276
  _context.next = 2;
292
- return toHastProcessor.run(cachedParse(sourceCode));
277
+ return toHastProcessor.run(toMdastProcessor.parse(sourceCode));
293
278
  case 2:
294
279
  return _context.abrupt("return", _context.sent);
295
280
  case 3:
@@ -346,6 +331,9 @@ export var viewerRender = function viewerRender(root, schema) {
346
331
  */
347
332
  export var postViewerRender = function postViewerRender(root, options) {
348
333
  var components = _objectSpread(_objectSpread({}, options.customHTMLElements), {}, {
334
+ input: function input(props) {
335
+ return jsx('input', props);
336
+ },
349
337
  custom: function custom(props) {
350
338
  var _options$customBlocks;
351
339
  return jsx((_options$customBlocks = options.customBlocks[props.meta]) !== null && _options$customBlocks !== void 0 ? _options$customBlocks : 'div', {
@@ -37,6 +37,10 @@ export interface XStarEditorProps {
37
37
  * 查看器属性
38
38
  */
39
39
  viewerProps?: Omit<XStarMdViewerProps, 'height' | 'value' | 'enableWebWorker'>;
40
+ /**
41
+ * 自定义查看器渲染函数
42
+ */
43
+ viewerRender?: (value: string) => React.ReactNode;
40
44
  /**
41
45
  * 文本变化回调函数
42
46
  */
@@ -6,17 +6,40 @@ import React, { useEffect, useImperativeHandle, useRef, useState } from 'react';
6
6
  import { prefix } from "../utils/global";
7
7
  import XStarMdEditor, { useMdEditorRef } from "../x-star-md-editor";
8
8
  import XStarMdViewer, { useMdViewerRef } from "../x-star-md-viewer";
9
- var XStarEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
10
- var className = _ref.className,
9
+ var ViewerRenderWrapper = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
10
+ var children = _ref.children,
11
+ className = _ref.className,
11
12
  style = _ref.style,
12
- height = _ref.height,
13
- locale = _ref.locale,
14
- initialValue = _ref.initialValue,
15
- enableWebWorker = _ref.enableWebWorker,
16
- editorProps = _ref.editorProps,
17
- viewerProps = _ref.viewerProps,
18
- _onChange = _ref.onChange,
19
- onInsertFile = _ref.onInsertFile;
13
+ height = _ref.height;
14
+ var containerRef = useRef(null);
15
+ useImperativeHandle(ref, function () {
16
+ return {
17
+ getViewerContainer: function getViewerContainer() {
18
+ return containerRef.current;
19
+ }
20
+ };
21
+ }, []);
22
+ return /*#__PURE__*/React.createElement("div", {
23
+ ref: containerRef,
24
+ className: classNames("".concat(prefix, "md-viewer"), className),
25
+ style: _objectSpread(_objectSpread({}, style), {}, {
26
+ height: height
27
+ })
28
+ }, children);
29
+ });
30
+ var XStarEditor = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
31
+ var className = _ref2.className,
32
+ style = _ref2.style,
33
+ height = _ref2.height,
34
+ locale = _ref2.locale,
35
+ _ref2$initialValue = _ref2.initialValue,
36
+ initialValue = _ref2$initialValue === void 0 ? '' : _ref2$initialValue,
37
+ enableWebWorker = _ref2.enableWebWorker,
38
+ editorProps = _ref2.editorProps,
39
+ viewerProps = _ref2.viewerProps,
40
+ viewerRender = _ref2.viewerRender,
41
+ _onChange = _ref2.onChange,
42
+ onInsertFile = _ref2.onInsertFile;
20
43
  var editorRef = useMdEditorRef();
21
44
  var viewerRef = useMdViewerRef();
22
45
  var containerRef = useRef(null);
@@ -94,10 +117,10 @@ var XStarEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
94
117
  if (ignore || !editor || !viewer) {
95
118
  return;
96
119
  }
97
- var _ref2 = e.currentTarget === editor ? [editor, viewer] : [viewer, editor],
98
- _ref3 = _slicedToArray(_ref2, 2),
99
- fromElement = _ref3[0],
100
- toElement = _ref3[1];
120
+ var _ref3 = e.currentTarget === editor ? [editor, viewer] : [viewer, editor],
121
+ _ref4 = _slicedToArray(_ref3, 2),
122
+ fromElement = _ref4[0],
123
+ toElement = _ref4[1];
101
124
  var _getOffsetTops = getOffsetTops(fromElement, toElement),
102
125
  _getOffsetTops2 = _slicedToArray(_getOffsetTops, 2),
103
126
  fromOffsetTops = _getOffsetTops2[0],
@@ -149,7 +172,12 @@ var XStarEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
149
172
  _onChange === null || _onChange === void 0 ? void 0 : _onChange(value);
150
173
  },
151
174
  onInsertFile: onInsertFile
152
- })), /*#__PURE__*/React.createElement(XStarMdViewer, _extends({
175
+ })), viewerRender ? /*#__PURE__*/React.createElement(ViewerRenderWrapper, {
176
+ ref: viewerRef,
177
+ className: viewerProps === null || viewerProps === void 0 ? void 0 : viewerProps.className,
178
+ style: viewerProps === null || viewerProps === void 0 ? void 0 : viewerProps.style,
179
+ height: height
180
+ }, viewerRender(value)) : /*#__PURE__*/React.createElement(XStarMdViewer, _extends({
153
181
  ref: viewerRef
154
182
  }, viewerProps, {
155
183
  height: height,
@@ -93,6 +93,7 @@ var XStarMdEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
93
93
  case 'copy':
94
94
  case 'cut':
95
95
  {
96
+ // 防止传输其他类型数据
96
97
  e.preventDefault();
97
98
  if (startOffset < endOffset) {
98
99
  e.clipboardData.setData('text/plain', sourceCode.slice(startOffset, endOffset));
@@ -114,9 +115,13 @@ var XStarMdEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
114
115
  switch (e.type) {
115
116
  case 'compositionend':
116
117
  {
118
+ // 组合时不更新 DOM,组合结束统一更新
117
119
  var _selection = getSelection();
118
120
  container.setText(sourceCodeLatest.current);
119
121
  container.setSelection(_selection);
122
+ dispatch({
123
+ type: 'batch'
124
+ });
120
125
  break;
121
126
  }
122
127
  }
@@ -130,6 +135,7 @@ var XStarMdEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
130
135
  case 'dragstart':
131
136
  {
132
137
  if (startOffset < endOffset) {
138
+ // 防止传输其他类型数据
133
139
  e.dataTransfer.clearData();
134
140
  e.dataTransfer.setData('text/plain', sourceCode.slice(startOffset, endOffset));
135
141
  }
@@ -162,6 +168,7 @@ var XStarMdEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
162
168
  switch (e.type) {
163
169
  case 'keydown':
164
170
  {
171
+ // 组合时不触发快捷键
165
172
  if (!e.nativeEvent.isComposing) {
166
173
  composeHandlers(options.keyboardEventHandlers)({
167
174
  history: history,
@@ -178,163 +185,165 @@ var XStarMdEditor = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
178
185
  useEffect(function () {
179
186
  var _containerRef$current;
180
187
  var listener = function listener(e) {
181
- switch (e.type) {
182
- case 'beforeinput':
188
+ var targetRange = e.getTargetRanges()[0];
189
+ if (!containerRef.current || !targetRange) {
190
+ return;
191
+ }
192
+ var startOffset = container.getOffset(containerRef.current, targetRange.startContainer, targetRange.startOffset);
193
+ var endOffset = container.getOffset(containerRef.current, targetRange.endContainer, targetRange.endOffset);
194
+ var selection = createSelection(startOffset, endOffset);
195
+ switch (e.inputType) {
196
+ case 'insertText':
197
+ {
198
+ e.preventDefault();
199
+ if (e.data !== null) {
200
+ dispatch({
201
+ type: 'insert',
202
+ payload: {
203
+ text: e.data
204
+ },
205
+ selection: selection
206
+ });
207
+ }
208
+ break;
209
+ }
210
+ case 'insertReplacementText':
211
+ case 'insertFromDrop':
212
+ case 'insertFromPaste':
213
+ {
214
+ var _e$dataTransfer, _e$dataTransfer2;
215
+ e.preventDefault();
216
+ if ((_e$dataTransfer = e.dataTransfer) !== null && _e$dataTransfer !== void 0 && _e$dataTransfer.types.includes('text/plain')) {
217
+ dispatch({
218
+ type: 'insert',
219
+ payload: {
220
+ text: e.dataTransfer.getData('text/plain')
221
+ },
222
+ selection: selection,
223
+ batch: true
224
+ });
225
+ dispatch({
226
+ type: 'batch'
227
+ });
228
+ } else if ((_e$dataTransfer2 = e.dataTransfer) !== null && _e$dataTransfer2 !== void 0 && _e$dataTransfer2.types.includes('Files')) {
229
+ var _file = e.dataTransfer.files[0];
230
+ onInsertFile === null || onInsertFile === void 0 ? void 0 : onInsertFile(_file, {
231
+ description: _file.name,
232
+ image: _file.type.startsWith('image/')
233
+ });
234
+ }
235
+ break;
236
+ }
237
+ case 'insertLineBreak':
238
+ case 'insertParagraph':
183
239
  {
184
- var targetRange = e.getTargetRanges()[0];
185
- if (containerRef.current && targetRange) {
186
- var startOffset = container.getOffset(containerRef.current, targetRange.startContainer, targetRange.startOffset);
187
- var endOffset = container.getOffset(containerRef.current, targetRange.endContainer, targetRange.endOffset);
188
- var _selection2 = createSelection(startOffset, endOffset);
189
- switch (e.inputType) {
190
- case 'insertText':
191
- {
192
- e.preventDefault();
193
- if (e.data !== null) {
194
- dispatch({
195
- type: 'insert',
196
- payload: {
197
- text: e.data
198
- },
199
- selection: _selection2
200
- });
201
- }
202
- break;
203
- }
204
- case 'insertReplacementText':
205
- case 'insertFromDrop':
206
- case 'insertFromPaste':
207
- {
208
- var _e$dataTransfer, _e$dataTransfer2;
209
- e.preventDefault();
210
- if ((_e$dataTransfer = e.dataTransfer) !== null && _e$dataTransfer !== void 0 && _e$dataTransfer.types.includes('text/plain')) {
211
- dispatch({
212
- type: 'insert',
213
- payload: {
214
- text: e.dataTransfer.getData('text/plain')
215
- },
216
- selection: _selection2
217
- });
218
- } else if ((_e$dataTransfer2 = e.dataTransfer) !== null && _e$dataTransfer2 !== void 0 && _e$dataTransfer2.types.includes('Files')) {
219
- var _file = e.dataTransfer.files[0];
220
- onInsertFile === null || onInsertFile === void 0 ? void 0 : onInsertFile(_file, {
221
- description: _file.name,
222
- image: _file.type.startsWith('image/')
223
- });
224
- }
225
- break;
226
- }
227
- case 'insertLineBreak':
228
- case 'insertParagraph':
229
- {
230
- e.preventDefault();
231
- dispatch({
232
- type: 'insert',
233
- payload: {
234
- text: '\n'
235
- },
236
- selection: _selection2
237
- });
238
- break;
239
- }
240
- case 'insertCompositionText':
241
- case 'insertFromComposition':
242
- {
243
- if (e.data !== null) {
244
- ignoreNext.current = true;
245
- dispatch({
246
- type: 'insert',
247
- payload: {
248
- text: e.data
249
- },
250
- selection: _selection2
251
- });
252
- }
253
- break;
254
- }
255
- case 'deleteWordBackward':
256
- case 'deleteWordForward':
257
- case 'deleteContentBackward':
258
- case 'deleteContentForward':
259
- {
260
- e.preventDefault();
261
- if (startOffset < endOffset) {
262
- dispatch({
263
- type: 'insert',
264
- payload: {
265
- text: ''
266
- },
267
- selection: _selection2
268
- });
269
- } else if (e.inputType.endsWith('Backward')) {
270
- if (startOffset) {
271
- dispatch({
272
- type: 'insert',
273
- payload: {
274
- text: ''
275
- },
276
- selection: createSelection(startOffset - 1, endOffset)
277
- });
278
- }
279
- } else {
280
- if (endOffset < sourceCodeLatest.current.length - 1) {
281
- dispatch({
282
- type: 'insert',
283
- payload: {
284
- text: ''
285
- },
286
- selection: createSelection(startOffset, endOffset + 1)
287
- });
288
- }
289
- }
290
- break;
291
- }
292
- case 'deleteByDrag':
293
- case 'deleteCompositionText':
294
- {
295
- ignoreNext.current = true;
296
- dispatch({
297
- type: 'insert',
298
- payload: {
299
- text: ''
300
- },
301
- selection: _selection2
302
- });
303
- break;
304
- }
305
- case 'formatBold':
306
- {
307
- e.preventDefault();
308
- dispatch({
309
- type: 'toggle',
310
- payload: {
311
- type: 'strong'
312
- },
313
- selection: _selection2
314
- });
315
- break;
316
- }
317
- case 'formatItalic':
318
- {
319
- e.preventDefault();
320
- dispatch({
321
- type: 'toggle',
322
- payload: {
323
- type: 'emphasis'
324
- },
325
- selection: _selection2
326
- });
327
- break;
328
- }
329
- default:
330
- {
331
- e.preventDefault();
332
- break;
333
- }
240
+ e.preventDefault();
241
+ dispatch({
242
+ type: 'insert',
243
+ payload: {
244
+ text: '\n'
245
+ },
246
+ selection: selection
247
+ });
248
+ break;
249
+ }
250
+ case 'insertCompositionText':
251
+ case 'insertFromComposition':
252
+ {
253
+ // 避免 DOM 更新扰乱组合
254
+ ignoreNext.current = true;
255
+ if (e.data !== null) {
256
+ dispatch({
257
+ type: 'insert',
258
+ payload: {
259
+ text: e.data
260
+ },
261
+ selection: selection,
262
+ batch: true
263
+ });
264
+ }
265
+ break;
266
+ }
267
+ case 'deleteWordBackward':
268
+ case 'deleteWordForward':
269
+ case 'deleteContentBackward':
270
+ case 'deleteContentForward':
271
+ {
272
+ e.preventDefault();
273
+ if (startOffset < endOffset) {
274
+ dispatch({
275
+ type: 'insert',
276
+ payload: {
277
+ text: ''
278
+ },
279
+ selection: selection
280
+ });
281
+ } else if (e.inputType.endsWith('Backward')) {
282
+ if (startOffset) {
283
+ dispatch({
284
+ type: 'insert',
285
+ payload: {
286
+ text: ''
287
+ },
288
+ selection: createSelection(startOffset - 1, endOffset)
289
+ });
290
+ }
291
+ } else {
292
+ if (endOffset < sourceCodeLatest.current.length) {
293
+ dispatch({
294
+ type: 'insert',
295
+ payload: {
296
+ text: ''
297
+ },
298
+ selection: createSelection(startOffset, endOffset + 1)
299
+ });
334
300
  }
335
301
  }
336
302
  break;
337
303
  }
304
+ case 'deleteByDrag':
305
+ case 'deleteCompositionText':
306
+ {
307
+ ignoreNext.current = true;
308
+ dispatch({
309
+ type: 'insert',
310
+ payload: {
311
+ text: ''
312
+ },
313
+ selection: selection,
314
+ batch: true
315
+ });
316
+ break;
317
+ }
318
+ case 'formatBold':
319
+ {
320
+ e.preventDefault();
321
+ dispatch({
322
+ type: 'toggle',
323
+ payload: {
324
+ type: 'strong'
325
+ },
326
+ selection: selection
327
+ });
328
+ break;
329
+ }
330
+ case 'formatItalic':
331
+ {
332
+ e.preventDefault();
333
+ dispatch({
334
+ type: 'toggle',
335
+ payload: {
336
+ type: 'emphasis'
337
+ },
338
+ selection: selection
339
+ });
340
+ break;
341
+ }
342
+ default:
343
+ {
344
+ e.preventDefault();
345
+ break;
346
+ }
338
347
  }
339
348
  };
340
349
  (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.addEventListener('beforeinput', listener);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x-star-editor",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "An editor developed by turingstar",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",