@uiw/react-codemirror 4.23.13 → 4.24.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/README.md CHANGED
@@ -388,6 +388,7 @@ import { EditorView, ViewUpdate } from '@codemirror/view';
388
388
  export * from '@codemirror/view';
389
389
  export * from '@codemirror/basic-setup';
390
390
  export * from '@codemirror/state';
391
+ export declare const ExternalChange: import('@codemirror/state').AnnotationType<boolean>;
391
392
  export interface UseCodeMirror extends ReactCodeMirrorProps {
392
393
  container?: HTMLDivElement | null;
393
394
  }
@@ -0,0 +1,22 @@
1
+ export declare class TimeoutLatch {
2
+ private timeLeftMS;
3
+ private timeoutMS;
4
+ private isCancelled;
5
+ private isTimeExhausted;
6
+ private callbacks;
7
+ constructor(callback: Function, timeoutMS: number);
8
+ tick(): void;
9
+ cancel(): void;
10
+ reset(): void;
11
+ get isDone(): boolean;
12
+ }
13
+ declare class Scheduler {
14
+ private interval;
15
+ private latches;
16
+ add(latch: TimeoutLatch): void;
17
+ remove(latch: TimeoutLatch): void;
18
+ private start;
19
+ private stop;
20
+ }
21
+ export declare const getScheduler: () => Scheduler;
22
+ export {};
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getScheduler = exports.TimeoutLatch = void 0;
8
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ // Setting / Unsetting timeouts for every keystroke was a significant overhead
12
+ // Inspired from https://github.com/iostreamer-X/timeout-latch
13
+ var TimeoutLatch = exports.TimeoutLatch = /*#__PURE__*/function () {
14
+ function TimeoutLatch(callback, timeoutMS) {
15
+ (0, _classCallCheck2["default"])(this, TimeoutLatch);
16
+ (0, _defineProperty2["default"])(this, "timeLeftMS", void 0);
17
+ (0, _defineProperty2["default"])(this, "timeoutMS", void 0);
18
+ (0, _defineProperty2["default"])(this, "isCancelled", false);
19
+ (0, _defineProperty2["default"])(this, "isTimeExhausted", false);
20
+ (0, _defineProperty2["default"])(this, "callbacks", []);
21
+ this.timeLeftMS = timeoutMS;
22
+ this.timeoutMS = timeoutMS;
23
+ this.callbacks.push(callback);
24
+ }
25
+ return (0, _createClass2["default"])(TimeoutLatch, [{
26
+ key: "tick",
27
+ value: function tick() {
28
+ if (!this.isCancelled && !this.isTimeExhausted) {
29
+ this.timeLeftMS--;
30
+ if (this.timeLeftMS <= 0) {
31
+ this.isTimeExhausted = true;
32
+ var callbacks = this.callbacks.slice();
33
+ this.callbacks.length = 0;
34
+ callbacks.forEach(function (callback) {
35
+ try {
36
+ callback();
37
+ } catch (error) {
38
+ console.error('TimeoutLatch callback error:', error);
39
+ }
40
+ });
41
+ }
42
+ }
43
+ }
44
+ }, {
45
+ key: "cancel",
46
+ value: function cancel() {
47
+ this.isCancelled = true;
48
+ this.callbacks.length = 0;
49
+ }
50
+ }, {
51
+ key: "reset",
52
+ value: function reset() {
53
+ this.timeLeftMS = this.timeoutMS;
54
+ this.isCancelled = false;
55
+ this.isTimeExhausted = false;
56
+ }
57
+ }, {
58
+ key: "isDone",
59
+ get: function get() {
60
+ return this.isCancelled || this.isTimeExhausted;
61
+ }
62
+ }]);
63
+ }();
64
+ var Scheduler = /*#__PURE__*/function () {
65
+ function Scheduler() {
66
+ (0, _classCallCheck2["default"])(this, Scheduler);
67
+ (0, _defineProperty2["default"])(this, "interval", null);
68
+ (0, _defineProperty2["default"])(this, "latches", new Set());
69
+ }
70
+ return (0, _createClass2["default"])(Scheduler, [{
71
+ key: "add",
72
+ value: function add(latch) {
73
+ this.latches.add(latch);
74
+ this.start();
75
+ }
76
+ }, {
77
+ key: "remove",
78
+ value: function remove(latch) {
79
+ this.latches["delete"](latch);
80
+ if (this.latches.size === 0) {
81
+ this.stop();
82
+ }
83
+ }
84
+ }, {
85
+ key: "start",
86
+ value: function start() {
87
+ var _this = this;
88
+ if (this.interval === null) {
89
+ this.interval = setInterval(function () {
90
+ _this.latches.forEach(function (latch) {
91
+ latch.tick();
92
+ if (latch.isDone) {
93
+ _this.remove(latch);
94
+ }
95
+ });
96
+ }, 1);
97
+ }
98
+ }
99
+ }, {
100
+ key: "stop",
101
+ value: function stop() {
102
+ if (this.interval !== null) {
103
+ clearInterval(this.interval);
104
+ this.interval = null;
105
+ }
106
+ }
107
+ }]);
108
+ }();
109
+ var globalScheduler = null;
110
+ var getScheduler = exports.getScheduler = function getScheduler() {
111
+ if (typeof window === 'undefined') {
112
+ return new Scheduler();
113
+ }
114
+ if (!globalScheduler) {
115
+ globalScheduler = new Scheduler();
116
+ }
117
+ return globalScheduler;
118
+ };
@@ -1,6 +1,7 @@
1
1
  import { EditorState } from '@codemirror/state';
2
2
  import { EditorView } from '@codemirror/view';
3
3
  import { type ReactCodeMirrorProps } from '.';
4
+ export declare const ExternalChange: import("@codemirror/state").AnnotationType<boolean>;
4
5
  export interface UseCodeMirror extends ReactCodeMirrorProps {
5
6
  container?: HTMLDivElement | null;
6
7
  }
@@ -4,6 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
+ exports.ExternalChange = void 0;
7
8
  exports.useCodeMirror = useCodeMirror;
8
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
10
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
@@ -12,7 +13,10 @@ var _state = require("@codemirror/state");
12
13
  var _view = require("@codemirror/view");
13
14
  var _getDefaultExtensions = require("./getDefaultExtensions");
14
15
  var _utils = require("./utils");
15
- var External = _state.Annotation.define();
16
+ var _timeoutLatch = require("./timeoutLatch");
17
+ var ExternalChange = exports.ExternalChange = _state.Annotation.define();
18
+ var TYPING_TIMOUT = 200; // ms
19
+
16
20
  var emptyExtensions = [];
17
21
  function useCodeMirror(props) {
18
22
  var value = props.value,
@@ -62,6 +66,16 @@ function useCodeMirror(props) {
62
66
  _useState6 = (0, _slicedToArray2["default"])(_useState5, 2),
63
67
  state = _useState6[0],
64
68
  setState = _useState6[1];
69
+ var typingLatch = (0, _react.useState)(function () {
70
+ return {
71
+ current: null
72
+ };
73
+ })[0];
74
+ var pendingUpdate = (0, _react.useState)(function () {
75
+ return {
76
+ current: null
77
+ };
78
+ })[0];
65
79
  var defaultThemeOption = _view.EditorView.theme({
66
80
  '&': {
67
81
  height: height,
@@ -80,8 +94,21 @@ function useCodeMirror(props) {
80
94
  // Fix echoing of the remote changes:
81
95
  // If transaction is market as remote we don't have to call `onChange` handler again
82
96
  !vu.transactions.some(function (tr) {
83
- return tr.annotation(External);
97
+ return tr.annotation(ExternalChange);
84
98
  })) {
99
+ if (typingLatch.current) {
100
+ typingLatch.current.reset();
101
+ } else {
102
+ typingLatch.current = new _timeoutLatch.TimeoutLatch(function () {
103
+ if (pendingUpdate.current) {
104
+ var forceUpdate = pendingUpdate.current;
105
+ pendingUpdate.current = null;
106
+ forceUpdate();
107
+ }
108
+ typingLatch.current = null;
109
+ }, TYPING_TIMOUT);
110
+ (0, _timeoutLatch.getScheduler)().add(typingLatch.current);
111
+ }
85
112
  var doc = vu.state.doc;
86
113
  var _value = doc.toString();
87
114
  onChange(_value, vu);
@@ -138,6 +165,10 @@ function useCodeMirror(props) {
138
165
  view.destroy();
139
166
  setView(undefined);
140
167
  }
168
+ if (typingLatch.current) {
169
+ typingLatch.current.cancel();
170
+ typingLatch.current = null;
171
+ }
141
172
  };
142
173
  }, [view]);
143
174
  (0, _react.useEffect)(function () {
@@ -159,14 +190,24 @@ function useCodeMirror(props) {
159
190
  }
160
191
  var currentValue = view ? view.state.doc.toString() : '';
161
192
  if (view && value !== currentValue) {
162
- view.dispatch({
163
- changes: {
164
- from: 0,
165
- to: currentValue.length,
166
- insert: value || ''
167
- },
168
- annotations: [External.of(true)]
169
- });
193
+ var isTyping = typingLatch.current && !typingLatch.current.isDone;
194
+ var forceUpdate = function forceUpdate() {
195
+ if (view && value !== view.state.doc.toString()) {
196
+ view.dispatch({
197
+ changes: {
198
+ from: 0,
199
+ to: view.state.doc.toString().length,
200
+ insert: value || ''
201
+ },
202
+ annotations: [ExternalChange.of(true)]
203
+ });
204
+ }
205
+ };
206
+ if (!isTyping) {
207
+ forceUpdate();
208
+ } else {
209
+ pendingUpdate.current = forceUpdate;
210
+ }
170
211
  }
171
212
  }, [value, view]);
172
213
  return {