slate-react 0.72.1 → 0.72.2-20211116213954
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/CHANGELOG.md +6 -0
- package/dist/components/android/android-editable.d.ts +0 -3
- package/dist/components/android/android-editable.d.ts.map +1 -1
- package/dist/components/android/android-input-manager.d.ts.map +1 -1
- package/dist/index.es.js +384 -270
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +391 -273
- package/dist/index.js.map +1 -1
- package/dist/slate-react.js +391 -273
- package/dist/slate-react.min.js +1 -1
- package/dist/utils/weak-maps.d.ts +7 -0
- package/dist/utils/weak-maps.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -172,6 +172,13 @@ var EDITOR_TO_KEY_TO_ELEMENT = new WeakMap();
|
|
|
172
172
|
|
|
173
173
|
var IS_READ_ONLY = new WeakMap();
|
|
174
174
|
var IS_FOCUSED = new WeakMap();
|
|
175
|
+
var IS_COMPOSING = new WeakMap();
|
|
176
|
+
var IS_ON_COMPOSITION_END = new WeakMap();
|
|
177
|
+
/**
|
|
178
|
+
* Weak maps for saving text on composition stage.
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
var EDITOR_ON_COMPOSITION_TEXT = new WeakMap();
|
|
175
182
|
/**
|
|
176
183
|
* Weak map for associating the context `onChange` context with the plugin.
|
|
177
184
|
*/
|
|
@@ -2146,6 +2153,233 @@ var isDOMEventHandled = (event, handler) => {
|
|
|
2146
2153
|
return event.defaultPrevented;
|
|
2147
2154
|
};
|
|
2148
2155
|
|
|
2156
|
+
/**
|
|
2157
|
+
* Returns the number of characters that are the same at the beginning of the
|
|
2158
|
+
* String.
|
|
2159
|
+
*
|
|
2160
|
+
* @param prev the previous text
|
|
2161
|
+
* @param next the next text
|
|
2162
|
+
* @returns the offset of the start of the difference; null if there is no difference
|
|
2163
|
+
*/
|
|
2164
|
+
|
|
2165
|
+
function getDiffStart(prev, next) {
|
|
2166
|
+
var length = Math.min(prev.length, next.length);
|
|
2167
|
+
|
|
2168
|
+
for (var i = 0; i < length; i++) {
|
|
2169
|
+
if (prev.charAt(i) !== next.charAt(i)) return i;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
if (prev.length !== next.length) return length;
|
|
2173
|
+
return null;
|
|
2174
|
+
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Returns the number of characters that are the same at the end of the String
|
|
2177
|
+
* up to `max`. Max prevents double-counting characters when there are
|
|
2178
|
+
* multiple duplicate characters around the diff area.
|
|
2179
|
+
*
|
|
2180
|
+
* @param prev the previous text
|
|
2181
|
+
* @param next the next text
|
|
2182
|
+
* @param max the max length to test.
|
|
2183
|
+
* @returns number of characters that are the same at the end of the string
|
|
2184
|
+
*/
|
|
2185
|
+
|
|
2186
|
+
|
|
2187
|
+
function getDiffEnd(prev, next, max) {
|
|
2188
|
+
var prevLength = prev.length;
|
|
2189
|
+
var nextLength = next.length;
|
|
2190
|
+
var length = Math.min(prevLength, nextLength, max);
|
|
2191
|
+
|
|
2192
|
+
for (var i = 0; i < length; i++) {
|
|
2193
|
+
var prevChar = prev.charAt(prevLength - i - 1);
|
|
2194
|
+
var nextChar = next.charAt(nextLength - i - 1);
|
|
2195
|
+
if (prevChar !== nextChar) return i;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
if (prev.length !== next.length) return length;
|
|
2199
|
+
return null;
|
|
2200
|
+
}
|
|
2201
|
+
/**
|
|
2202
|
+
* Takes two strings and returns an object representing two offsets. The
|
|
2203
|
+
* first, `start` represents the number of characters that are the same at
|
|
2204
|
+
* the front of the String. The `end` represents the number of characters
|
|
2205
|
+
* that are the same at the end of the String.
|
|
2206
|
+
*
|
|
2207
|
+
* Returns null if they are identical.
|
|
2208
|
+
*
|
|
2209
|
+
* @param prev the previous text
|
|
2210
|
+
* @param next the next text
|
|
2211
|
+
* @returns the difference text range; null if there are no differences.
|
|
2212
|
+
*/
|
|
2213
|
+
|
|
2214
|
+
|
|
2215
|
+
function getDiffOffsets(prev, next) {
|
|
2216
|
+
if (prev === next) return null;
|
|
2217
|
+
var start = getDiffStart(prev, next);
|
|
2218
|
+
if (start === null) return null;
|
|
2219
|
+
var maxEnd = Math.min(prev.length - start, next.length - start);
|
|
2220
|
+
var end = getDiffEnd(prev, next, maxEnd);
|
|
2221
|
+
if (end === null) return null;
|
|
2222
|
+
return {
|
|
2223
|
+
start,
|
|
2224
|
+
end
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Takes a text string and returns a slice from the string at the given text range
|
|
2229
|
+
*
|
|
2230
|
+
* @param text the text
|
|
2231
|
+
* @param offsets the text range
|
|
2232
|
+
* @returns the text slice at text range
|
|
2233
|
+
*/
|
|
2234
|
+
|
|
2235
|
+
|
|
2236
|
+
function sliceText(text, offsets) {
|
|
2237
|
+
return text.slice(offsets.start, text.length - offsets.end);
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Takes two strings and returns a smart diff that can be used to describe the
|
|
2241
|
+
* change in a way that can be used as operations like inserting, removing or
|
|
2242
|
+
* replacing text.
|
|
2243
|
+
*
|
|
2244
|
+
* @param prev the previous text
|
|
2245
|
+
* @param next the next text
|
|
2246
|
+
* @returns the text difference
|
|
2247
|
+
*/
|
|
2248
|
+
|
|
2249
|
+
|
|
2250
|
+
function diffText(prev, next) {
|
|
2251
|
+
if (prev === undefined || next === undefined) return null;
|
|
2252
|
+
var offsets = getDiffOffsets(prev, next);
|
|
2253
|
+
if (offsets == null) return null;
|
|
2254
|
+
var insertText = sliceText(next, offsets);
|
|
2255
|
+
var removeText = sliceText(prev, offsets);
|
|
2256
|
+
return {
|
|
2257
|
+
start: offsets.start,
|
|
2258
|
+
end: prev.length - offsets.end,
|
|
2259
|
+
insertText,
|
|
2260
|
+
removeText
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
function combineInsertedText(insertedText) {
|
|
2264
|
+
return insertedText.reduce((acc, _ref) => {
|
|
2265
|
+
var {
|
|
2266
|
+
text
|
|
2267
|
+
} = _ref;
|
|
2268
|
+
return "".concat(acc).concat(text.insertText);
|
|
2269
|
+
}, '');
|
|
2270
|
+
}
|
|
2271
|
+
function getTextInsertion(editor, domNode) {
|
|
2272
|
+
var node = ReactEditor.toSlateNode(editor, domNode);
|
|
2273
|
+
|
|
2274
|
+
if (!Text$1.isText(node)) {
|
|
2275
|
+
return undefined;
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
var prevText = node.text;
|
|
2279
|
+
var nextText = domNode.textContent; // textContent will pad an extra \n when the textContent ends with an \n
|
|
2280
|
+
|
|
2281
|
+
if (nextText.endsWith('\n')) {
|
|
2282
|
+
nextText = nextText.slice(0, nextText.length - 1);
|
|
2283
|
+
} // If the text is no different, there is no diff.
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
if (nextText !== prevText) {
|
|
2287
|
+
var textDiff = diffText(prevText, nextText);
|
|
2288
|
+
|
|
2289
|
+
if (textDiff !== null) {
|
|
2290
|
+
var textPath = ReactEditor.findPath(editor, node);
|
|
2291
|
+
return {
|
|
2292
|
+
text: textDiff,
|
|
2293
|
+
path: textPath
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
return undefined;
|
|
2299
|
+
}
|
|
2300
|
+
function normalizeTextInsertionRange(editor, range, _ref2) {
|
|
2301
|
+
var {
|
|
2302
|
+
path,
|
|
2303
|
+
text
|
|
2304
|
+
} = _ref2;
|
|
2305
|
+
var insertionRange = {
|
|
2306
|
+
anchor: {
|
|
2307
|
+
path,
|
|
2308
|
+
offset: text.start
|
|
2309
|
+
},
|
|
2310
|
+
focus: {
|
|
2311
|
+
path,
|
|
2312
|
+
offset: text.end
|
|
2313
|
+
}
|
|
2314
|
+
};
|
|
2315
|
+
|
|
2316
|
+
if (!range || !Range.isCollapsed(range)) {
|
|
2317
|
+
return insertionRange;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
var {
|
|
2321
|
+
insertText,
|
|
2322
|
+
removeText
|
|
2323
|
+
} = text;
|
|
2324
|
+
var isSingleCharacterInsertion = insertText.length === 1 || removeText.length === 1;
|
|
2325
|
+
/**
|
|
2326
|
+
* This code handles edge cases that arise from text diffing when the
|
|
2327
|
+
* inserted or removed character is a single character, and the character
|
|
2328
|
+
* right before or after the anchor is the same as the one being inserted or
|
|
2329
|
+
* removed.
|
|
2330
|
+
*
|
|
2331
|
+
* Take this example: hello|o
|
|
2332
|
+
*
|
|
2333
|
+
* If another `o` is inserted at the selection's anchor in the example above,
|
|
2334
|
+
* it should be inserted at the anchor, but using text diffing, we actually
|
|
2335
|
+
* detect that the character was inserted after the second `o`:
|
|
2336
|
+
*
|
|
2337
|
+
* helloo[o]|
|
|
2338
|
+
*
|
|
2339
|
+
* Instead, in these very specific edge cases, we assume that the character
|
|
2340
|
+
* needs to be inserted after the anchor rather than where the diff was found:
|
|
2341
|
+
*
|
|
2342
|
+
* hello[o]|o
|
|
2343
|
+
*/
|
|
2344
|
+
|
|
2345
|
+
if (isSingleCharacterInsertion && Path.equals(range.anchor.path, path)) {
|
|
2346
|
+
var [_text] = Array.from(Editor.nodes(editor, {
|
|
2347
|
+
at: range,
|
|
2348
|
+
match: Text$1.isText
|
|
2349
|
+
}));
|
|
2350
|
+
|
|
2351
|
+
if (_text) {
|
|
2352
|
+
var [node] = _text;
|
|
2353
|
+
var {
|
|
2354
|
+
anchor
|
|
2355
|
+
} = range;
|
|
2356
|
+
var characterBeforeAnchor = node.text[anchor.offset - 1];
|
|
2357
|
+
var characterAfterAnchor = node.text[anchor.offset];
|
|
2358
|
+
|
|
2359
|
+
if (insertText.length === 1 && insertText === characterAfterAnchor) {
|
|
2360
|
+
// Assume text should be inserted at the anchor
|
|
2361
|
+
return range;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
if (removeText.length === 1 && removeText === characterBeforeAnchor) {
|
|
2365
|
+
// Assume text should be removed right before the anchor
|
|
2366
|
+
return {
|
|
2367
|
+
anchor: {
|
|
2368
|
+
path,
|
|
2369
|
+
offset: anchor.offset - 1
|
|
2370
|
+
},
|
|
2371
|
+
focus: {
|
|
2372
|
+
path,
|
|
2373
|
+
offset: anchor.offset
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
return insertionRange;
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2149
2383
|
/**
|
|
2150
2384
|
* An auto-incrementing identifier for keys.
|
|
2151
2385
|
*/
|
|
@@ -2715,247 +2949,20 @@ var ReactEditor = {
|
|
|
2715
2949
|
|
|
2716
2950
|
};
|
|
2717
2951
|
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
}
|
|
2733
|
-
|
|
2734
|
-
if (prev.length !== next.length) return length;
|
|
2735
|
-
return null;
|
|
2736
|
-
}
|
|
2737
|
-
/**
|
|
2738
|
-
* Returns the number of characters that are the same at the end of the String
|
|
2739
|
-
* up to `max`. Max prevents double-counting characters when there are
|
|
2740
|
-
* multiple duplicate characters around the diff area.
|
|
2741
|
-
*
|
|
2742
|
-
* @param prev the previous text
|
|
2743
|
-
* @param next the next text
|
|
2744
|
-
* @param max the max length to test.
|
|
2745
|
-
* @returns number of characters that are the same at the end of the string
|
|
2746
|
-
*/
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
function getDiffEnd(prev, next, max) {
|
|
2750
|
-
var prevLength = prev.length;
|
|
2751
|
-
var nextLength = next.length;
|
|
2752
|
-
var length = Math.min(prevLength, nextLength, max);
|
|
2753
|
-
|
|
2754
|
-
for (var i = 0; i < length; i++) {
|
|
2755
|
-
var prevChar = prev.charAt(prevLength - i - 1);
|
|
2756
|
-
var nextChar = next.charAt(nextLength - i - 1);
|
|
2757
|
-
if (prevChar !== nextChar) return i;
|
|
2758
|
-
}
|
|
2759
|
-
|
|
2760
|
-
if (prev.length !== next.length) return length;
|
|
2761
|
-
return null;
|
|
2762
|
-
}
|
|
2763
|
-
/**
|
|
2764
|
-
* Takes two strings and returns an object representing two offsets. The
|
|
2765
|
-
* first, `start` represents the number of characters that are the same at
|
|
2766
|
-
* the front of the String. The `end` represents the number of characters
|
|
2767
|
-
* that are the same at the end of the String.
|
|
2768
|
-
*
|
|
2769
|
-
* Returns null if they are identical.
|
|
2770
|
-
*
|
|
2771
|
-
* @param prev the previous text
|
|
2772
|
-
* @param next the next text
|
|
2773
|
-
* @returns the difference text range; null if there are no differences.
|
|
2774
|
-
*/
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
function getDiffOffsets(prev, next) {
|
|
2778
|
-
if (prev === next) return null;
|
|
2779
|
-
var start = getDiffStart(prev, next);
|
|
2780
|
-
if (start === null) return null;
|
|
2781
|
-
var maxEnd = Math.min(prev.length - start, next.length - start);
|
|
2782
|
-
var end = getDiffEnd(prev, next, maxEnd);
|
|
2783
|
-
if (end === null) return null;
|
|
2784
|
-
return {
|
|
2785
|
-
start,
|
|
2786
|
-
end
|
|
2787
|
-
};
|
|
2788
|
-
}
|
|
2789
|
-
/**
|
|
2790
|
-
* Takes a text string and returns a slice from the string at the given text range
|
|
2791
|
-
*
|
|
2792
|
-
* @param text the text
|
|
2793
|
-
* @param offsets the text range
|
|
2794
|
-
* @returns the text slice at text range
|
|
2795
|
-
*/
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
function sliceText(text, offsets) {
|
|
2799
|
-
return text.slice(offsets.start, text.length - offsets.end);
|
|
2800
|
-
}
|
|
2801
|
-
/**
|
|
2802
|
-
* Takes two strings and returns a smart diff that can be used to describe the
|
|
2803
|
-
* change in a way that can be used as operations like inserting, removing or
|
|
2804
|
-
* replacing text.
|
|
2805
|
-
*
|
|
2806
|
-
* @param prev the previous text
|
|
2807
|
-
* @param next the next text
|
|
2808
|
-
* @returns the text difference
|
|
2809
|
-
*/
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
function diffText(prev, next) {
|
|
2813
|
-
if (prev === undefined || next === undefined) return null;
|
|
2814
|
-
var offsets = getDiffOffsets(prev, next);
|
|
2815
|
-
if (offsets == null) return null;
|
|
2816
|
-
var insertText = sliceText(next, offsets);
|
|
2817
|
-
var removeText = sliceText(prev, offsets);
|
|
2818
|
-
return {
|
|
2819
|
-
start: offsets.start,
|
|
2820
|
-
end: prev.length - offsets.end,
|
|
2821
|
-
insertText,
|
|
2822
|
-
removeText
|
|
2823
|
-
};
|
|
2824
|
-
}
|
|
2825
|
-
function combineInsertedText(insertedText) {
|
|
2826
|
-
return insertedText.reduce((acc, _ref) => {
|
|
2827
|
-
var {
|
|
2828
|
-
text
|
|
2829
|
-
} = _ref;
|
|
2830
|
-
return "".concat(acc).concat(text.insertText);
|
|
2831
|
-
}, '');
|
|
2832
|
-
}
|
|
2833
|
-
function getTextInsertion(editor, domNode) {
|
|
2834
|
-
var node = ReactEditor.toSlateNode(editor, domNode);
|
|
2835
|
-
|
|
2836
|
-
if (!Text$1.isText(node)) {
|
|
2837
|
-
return undefined;
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
var prevText = node.text;
|
|
2841
|
-
var nextText = domNode.textContent; // textContent will pad an extra \n when the textContent ends with an \n
|
|
2842
|
-
|
|
2843
|
-
if (nextText.endsWith('\n')) {
|
|
2844
|
-
nextText = nextText.slice(0, nextText.length - 1);
|
|
2845
|
-
} // If the text is no different, there is no diff.
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
if (nextText !== prevText) {
|
|
2849
|
-
var textDiff = diffText(prevText, nextText);
|
|
2850
|
-
|
|
2851
|
-
if (textDiff !== null) {
|
|
2852
|
-
var textPath = ReactEditor.findPath(editor, node);
|
|
2853
|
-
return {
|
|
2854
|
-
text: textDiff,
|
|
2855
|
-
path: textPath
|
|
2856
|
-
};
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
|
-
return undefined;
|
|
2861
|
-
}
|
|
2862
|
-
function normalizeTextInsertionRange(editor, range, _ref2) {
|
|
2863
|
-
var {
|
|
2864
|
-
path,
|
|
2865
|
-
text
|
|
2866
|
-
} = _ref2;
|
|
2867
|
-
var insertionRange = {
|
|
2868
|
-
anchor: {
|
|
2869
|
-
path,
|
|
2870
|
-
offset: text.start
|
|
2871
|
-
},
|
|
2872
|
-
focus: {
|
|
2873
|
-
path,
|
|
2874
|
-
offset: text.end
|
|
2875
|
-
}
|
|
2876
|
-
};
|
|
2877
|
-
|
|
2878
|
-
if (!range || !Range.isCollapsed(range)) {
|
|
2879
|
-
return insertionRange;
|
|
2880
|
-
}
|
|
2881
|
-
|
|
2882
|
-
var {
|
|
2883
|
-
insertText,
|
|
2884
|
-
removeText
|
|
2885
|
-
} = text;
|
|
2886
|
-
var isSingleCharacterInsertion = insertText.length === 1 || removeText.length === 1;
|
|
2887
|
-
/**
|
|
2888
|
-
* This code handles edge cases that arise from text diffing when the
|
|
2889
|
-
* inserted or removed character is a single character, and the character
|
|
2890
|
-
* right before or after the anchor is the same as the one being inserted or
|
|
2891
|
-
* removed.
|
|
2892
|
-
*
|
|
2893
|
-
* Take this example: hello|o
|
|
2894
|
-
*
|
|
2895
|
-
* If another `o` is inserted at the selection's anchor in the example above,
|
|
2896
|
-
* it should be inserted at the anchor, but using text diffing, we actually
|
|
2897
|
-
* detect that the character was inserted after the second `o`:
|
|
2898
|
-
*
|
|
2899
|
-
* helloo[o]|
|
|
2900
|
-
*
|
|
2901
|
-
* Instead, in these very specific edge cases, we assume that the character
|
|
2902
|
-
* needs to be inserted after the anchor rather than where the diff was found:
|
|
2903
|
-
*
|
|
2904
|
-
* hello[o]|o
|
|
2905
|
-
*/
|
|
2906
|
-
|
|
2907
|
-
if (isSingleCharacterInsertion && Path.equals(range.anchor.path, path)) {
|
|
2908
|
-
var [_text] = Array.from(Editor.nodes(editor, {
|
|
2909
|
-
at: range,
|
|
2910
|
-
match: Text$1.isText
|
|
2911
|
-
}));
|
|
2912
|
-
|
|
2913
|
-
if (_text) {
|
|
2914
|
-
var [node] = _text;
|
|
2915
|
-
var {
|
|
2916
|
-
anchor
|
|
2917
|
-
} = range;
|
|
2918
|
-
var characterBeforeAnchor = node.text[anchor.offset - 1];
|
|
2919
|
-
var characterAfterAnchor = node.text[anchor.offset];
|
|
2920
|
-
|
|
2921
|
-
if (insertText.length === 1 && insertText === characterAfterAnchor) {
|
|
2922
|
-
// Assume text should be inserted at the anchor
|
|
2923
|
-
return range;
|
|
2924
|
-
}
|
|
2925
|
-
|
|
2926
|
-
if (removeText.length === 1 && removeText === characterBeforeAnchor) {
|
|
2927
|
-
// Assume text should be removed right before the anchor
|
|
2928
|
-
return {
|
|
2929
|
-
anchor: {
|
|
2930
|
-
path,
|
|
2931
|
-
offset: anchor.offset - 1
|
|
2932
|
-
},
|
|
2933
|
-
focus: {
|
|
2934
|
-
path,
|
|
2935
|
-
offset: anchor.offset
|
|
2936
|
-
}
|
|
2937
|
-
};
|
|
2938
|
-
}
|
|
2939
|
-
}
|
|
2940
|
-
}
|
|
2941
|
-
|
|
2942
|
-
return insertionRange;
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
function gatherMutationData(editor, mutations) {
|
|
2946
|
-
var addedNodes = [];
|
|
2947
|
-
var removedNodes = [];
|
|
2948
|
-
var insertedText = [];
|
|
2949
|
-
var characterDataMutations = [];
|
|
2950
|
-
mutations.forEach(mutation => {
|
|
2951
|
-
switch (mutation.type) {
|
|
2952
|
-
case 'childList':
|
|
2953
|
-
{
|
|
2954
|
-
if (mutation.addedNodes.length) {
|
|
2955
|
-
mutation.addedNodes.forEach(addedNode => {
|
|
2956
|
-
addedNodes.push(addedNode);
|
|
2957
|
-
});
|
|
2958
|
-
}
|
|
2952
|
+
function gatherMutationData(editor, mutations) {
|
|
2953
|
+
var addedNodes = [];
|
|
2954
|
+
var removedNodes = [];
|
|
2955
|
+
var insertedText = [];
|
|
2956
|
+
var characterDataMutations = [];
|
|
2957
|
+
mutations.forEach(mutation => {
|
|
2958
|
+
switch (mutation.type) {
|
|
2959
|
+
case 'childList':
|
|
2960
|
+
{
|
|
2961
|
+
if (mutation.addedNodes.length) {
|
|
2962
|
+
mutation.addedNodes.forEach(addedNode => {
|
|
2963
|
+
addedNodes.push(addedNode);
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2959
2966
|
|
|
2960
2967
|
mutation.removedNodes.forEach(removedNode => {
|
|
2961
2968
|
removedNodes.push(removedNode);
|
|
@@ -3163,7 +3170,15 @@ class AndroidInputManager {
|
|
|
3163
3170
|
var {
|
|
3164
3171
|
selection,
|
|
3165
3172
|
marks
|
|
3166
|
-
} = this.editor; //
|
|
3173
|
+
} = this.editor; // If it is in composing or after `onCompositionend`, set `EDITOR_ON_COMPOSITION_TEXT` and return.
|
|
3174
|
+
// Text will be inserted on compositionend event.
|
|
3175
|
+
|
|
3176
|
+
if (IS_COMPOSING.get(this.editor) || IS_ON_COMPOSITION_END.get(this.editor)) {
|
|
3177
|
+
EDITOR_ON_COMPOSITION_TEXT.set(this.editor, insertedText);
|
|
3178
|
+
IS_ON_COMPOSITION_END.set(this.editor, false);
|
|
3179
|
+
return;
|
|
3180
|
+
} // Insert the batched text diffs
|
|
3181
|
+
|
|
3167
3182
|
|
|
3168
3183
|
insertedText.forEach(insertion => {
|
|
3169
3184
|
var text = insertion.text.insertText;
|
|
@@ -3420,7 +3435,10 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
3420
3435
|
/**
|
|
3421
3436
|
* Editable.
|
|
3422
3437
|
*/
|
|
3438
|
+
// https://github.com/facebook/draft-js/blob/main/src/component/handlers/composition/DraftEditorCompositionHandler.js#L41
|
|
3439
|
+
// When using keyboard English association function, conpositionEnd triggered too fast, resulting in after `insertText` still maintain association state.
|
|
3423
3440
|
|
|
3441
|
+
var RESOLVE_DELAY = 20;
|
|
3424
3442
|
var AndroidEditable = props => {
|
|
3425
3443
|
var {
|
|
3426
3444
|
autoFocus,
|
|
@@ -3436,13 +3454,16 @@ var AndroidEditable = props => {
|
|
|
3436
3454
|
} = props,
|
|
3437
3455
|
attributes = _objectWithoutProperties(props, _excluded$1);
|
|
3438
3456
|
|
|
3439
|
-
var editor = useSlate();
|
|
3457
|
+
var editor = useSlate(); // Rerender editor when composition status changed
|
|
3458
|
+
|
|
3459
|
+
var [isComposing, setIsComposing] = useState(false);
|
|
3440
3460
|
var ref = useRef(null);
|
|
3441
3461
|
var inputManager = useAndroidInputManager(ref); // Update internal state on each render.
|
|
3442
3462
|
|
|
3443
3463
|
IS_READ_ONLY.set(editor, readOnly); // Keep track of some state for the event handler logic.
|
|
3444
3464
|
|
|
3445
3465
|
var state = useMemo(() => ({
|
|
3466
|
+
isComposing: false,
|
|
3446
3467
|
isUpdatingSelection: false,
|
|
3447
3468
|
latestElement: null
|
|
3448
3469
|
}), []);
|
|
@@ -3469,7 +3490,7 @@ var AndroidEditable = props => {
|
|
|
3469
3490
|
var root = ReactEditor.findDocumentOrShadowRoot(editor);
|
|
3470
3491
|
var domSelection = root.getSelection();
|
|
3471
3492
|
|
|
3472
|
-
if (!domSelection || !ReactEditor.isFocused(editor)) {
|
|
3493
|
+
if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {
|
|
3473
3494
|
return;
|
|
3474
3495
|
}
|
|
3475
3496
|
|
|
@@ -3549,26 +3570,7 @@ var AndroidEditable = props => {
|
|
|
3549
3570
|
if (ref.current && autoFocus) {
|
|
3550
3571
|
ref.current.focus();
|
|
3551
3572
|
}
|
|
3552
|
-
}, [autoFocus]); // Listen on the native `
|
|
3553
|
-
// is required because React's `beforeinput` is fake and never really attaches
|
|
3554
|
-
// to the real event sadly. (2019/11/01)
|
|
3555
|
-
// https://github.com/facebook/react/issues/11211
|
|
3556
|
-
|
|
3557
|
-
var onDOMBeforeInput = useCallback(event => {
|
|
3558
|
-
if (!readOnly && hasEditableTarget(editor, event.target) && !isDOMEventHandled(event, propsOnDOMBeforeInput)) {
|
|
3559
|
-
inputManager.onUserInput();
|
|
3560
|
-
}
|
|
3561
|
-
}, [readOnly, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `beforeinput` events, because React's
|
|
3562
|
-
// built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
|
|
3563
|
-
// real `beforeinput` events sadly... (2019/11/04)
|
|
3564
|
-
|
|
3565
|
-
useIsomorphicLayoutEffect(() => {
|
|
3566
|
-
var node = ref.current; // @ts-ignore The `beforeinput` event isn't recognized.
|
|
3567
|
-
|
|
3568
|
-
node === null || node === void 0 ? void 0 : node.addEventListener('beforeinput', onDOMBeforeInput); // @ts-ignore The `beforeinput` event isn't recognized.
|
|
3569
|
-
|
|
3570
|
-
return () => node === null || node === void 0 ? void 0 : node.removeEventListener('beforeinput', onDOMBeforeInput);
|
|
3571
|
-
}, [contentKey, propsOnDOMBeforeInput]); // Listen on the native `selectionchange` event to be able to update any time
|
|
3573
|
+
}, [autoFocus]); // Listen on the native `selectionchange` event to be able to update any time
|
|
3572
3574
|
// the selection changes. This is required because React's `onSelect` is leaky
|
|
3573
3575
|
// and non-standard so it doesn't fire until after a selection has been
|
|
3574
3576
|
// released. This causes issues in situations where another change happens
|
|
@@ -3576,7 +3578,7 @@ var AndroidEditable = props => {
|
|
|
3576
3578
|
|
|
3577
3579
|
var onDOMSelectionChange = useCallback(throttle(() => {
|
|
3578
3580
|
try {
|
|
3579
|
-
if (!state.isUpdatingSelection && !inputManager.isReconciling.current) {
|
|
3581
|
+
if (!state.isComposing && !state.isUpdatingSelection && !inputManager.isReconciling.current) {
|
|
3580
3582
|
var root = ReactEditor.findDocumentOrShadowRoot(editor);
|
|
3581
3583
|
var {
|
|
3582
3584
|
activeElement
|
|
@@ -3614,7 +3616,31 @@ var AndroidEditable = props => {
|
|
|
3614
3616
|
}
|
|
3615
3617
|
} catch (_unused2) {// Failed to update selection, likely due to reconciliation error
|
|
3616
3618
|
}
|
|
3617
|
-
}, 100), [readOnly]);
|
|
3619
|
+
}, 100), [readOnly]);
|
|
3620
|
+
var scheduleOnDOMSelectionChange = useMemo(() => debounce(onDOMSelectionChange, 0), [onDOMSelectionChange]); // Listen on the native `beforeinput` event to get real "Level 2" events. This
|
|
3621
|
+
// is required because React's `beforeinput` is fake and never really attaches
|
|
3622
|
+
// to the real event sadly. (2019/11/01)
|
|
3623
|
+
// https://github.com/facebook/react/issues/11211
|
|
3624
|
+
|
|
3625
|
+
var onDOMBeforeInput = useCallback(event => {
|
|
3626
|
+
if (!readOnly && hasEditableTarget(editor, event.target) && !isDOMEventHandled(event, propsOnDOMBeforeInput)) {
|
|
3627
|
+
// Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before
|
|
3628
|
+
// triggering a `beforeinput` expecting the change to be applied to the immediately before
|
|
3629
|
+
// set selection.
|
|
3630
|
+
scheduleOnDOMSelectionChange.flush();
|
|
3631
|
+
inputManager.onUserInput();
|
|
3632
|
+
}
|
|
3633
|
+
}, [readOnly, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `beforeinput` events, because React's
|
|
3634
|
+
// built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose
|
|
3635
|
+
// real `beforeinput` events sadly... (2019/11/04)
|
|
3636
|
+
|
|
3637
|
+
useIsomorphicLayoutEffect(() => {
|
|
3638
|
+
var node = ref.current; // @ts-ignore The `beforeinput` event isn't recognized.
|
|
3639
|
+
|
|
3640
|
+
node === null || node === void 0 ? void 0 : node.addEventListener('beforeinput', onDOMBeforeInput); // @ts-ignore The `beforeinput` event isn't recognized.
|
|
3641
|
+
|
|
3642
|
+
return () => node === null || node === void 0 ? void 0 : node.removeEventListener('beforeinput', onDOMBeforeInput);
|
|
3643
|
+
}, [contentKey, propsOnDOMBeforeInput]); // Attach a native DOM event handler for `selectionchange`, because React's
|
|
3618
3644
|
// built-in `onSelect` handler doesn't fire for all selection changes. It's a
|
|
3619
3645
|
// leaky polyfill that only fires on keypresses or clicks. Instead, we want to
|
|
3620
3646
|
// fire for any change to the selection inside the editor. (2019/11/04)
|
|
@@ -3622,14 +3648,14 @@ var AndroidEditable = props => {
|
|
|
3622
3648
|
|
|
3623
3649
|
useIsomorphicLayoutEffect(() => {
|
|
3624
3650
|
var window = ReactEditor.getWindow(editor);
|
|
3625
|
-
window.document.addEventListener('selectionchange',
|
|
3651
|
+
window.document.addEventListener('selectionchange', scheduleOnDOMSelectionChange);
|
|
3626
3652
|
return () => {
|
|
3627
|
-
window.document.removeEventListener('selectionchange',
|
|
3653
|
+
window.document.removeEventListener('selectionchange', scheduleOnDOMSelectionChange);
|
|
3628
3654
|
};
|
|
3629
|
-
});
|
|
3655
|
+
}, [scheduleOnDOMSelectionChange]);
|
|
3630
3656
|
var decorations = decorate([editor, []]);
|
|
3631
3657
|
|
|
3632
|
-
if (placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '') {
|
|
3658
|
+
if (placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '' && !isComposing) {
|
|
3633
3659
|
var start = Editor.start(editor, []);
|
|
3634
3660
|
decorations.push({
|
|
3635
3661
|
[PLACEHOLDER_SYMBOL]: true,
|
|
@@ -3744,6 +3770,94 @@ var AndroidEditable = props => {
|
|
|
3744
3770
|
|
|
3745
3771
|
IS_FOCUSED.delete(editor);
|
|
3746
3772
|
}, [readOnly, attributes.onBlur]),
|
|
3773
|
+
onClick: useCallback(event => {
|
|
3774
|
+
if (!readOnly && hasTarget(editor, event.target) && !isEventHandled(event, attributes.onClick) && isDOMNode(event.target)) {
|
|
3775
|
+
var node = ReactEditor.toSlateNode(editor, event.target);
|
|
3776
|
+
var path = ReactEditor.findPath(editor, node); // At this time, the Slate document may be arbitrarily different,
|
|
3777
|
+
// because onClick handlers can change the document before we get here.
|
|
3778
|
+
// Therefore we must check that this path actually exists,
|
|
3779
|
+
// and that it still refers to the same node.
|
|
3780
|
+
|
|
3781
|
+
if (Editor.hasPath(editor, path)) {
|
|
3782
|
+
var lookupNode = Node.get(editor, path);
|
|
3783
|
+
|
|
3784
|
+
if (lookupNode === node) {
|
|
3785
|
+
var _start = Editor.start(editor, path);
|
|
3786
|
+
|
|
3787
|
+
var end = Editor.end(editor, path);
|
|
3788
|
+
var startVoid = Editor.void(editor, {
|
|
3789
|
+
at: _start
|
|
3790
|
+
});
|
|
3791
|
+
var endVoid = Editor.void(editor, {
|
|
3792
|
+
at: end
|
|
3793
|
+
});
|
|
3794
|
+
|
|
3795
|
+
if (startVoid && endVoid && Path.equals(startVoid[1], endVoid[1])) {
|
|
3796
|
+
var range = Editor.range(editor, _start);
|
|
3797
|
+
Transforms.select(editor, range);
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
}, [readOnly, attributes.onClick]),
|
|
3803
|
+
onCompositionEnd: useCallback(event => {
|
|
3804
|
+
if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionEnd)) {
|
|
3805
|
+
scheduleOnDOMSelectionChange.flush();
|
|
3806
|
+
setTimeout(() => {
|
|
3807
|
+
state.isComposing && setIsComposing(false);
|
|
3808
|
+
state.isComposing = false;
|
|
3809
|
+
IS_COMPOSING.set(editor, false);
|
|
3810
|
+
IS_ON_COMPOSITION_END.set(editor, true);
|
|
3811
|
+
var insertedText = EDITOR_ON_COMPOSITION_TEXT.get(editor) || []; // `insertedText` is set in `MutationObserver` constructor.
|
|
3812
|
+
// If open phone keyboard association function, `CompositionEvent` will be triggered.
|
|
3813
|
+
|
|
3814
|
+
if (!insertedText.length) {
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
EDITOR_ON_COMPOSITION_TEXT.set(editor, []);
|
|
3819
|
+
var {
|
|
3820
|
+
selection,
|
|
3821
|
+
marks
|
|
3822
|
+
} = editor;
|
|
3823
|
+
insertedText.forEach(insertion => {
|
|
3824
|
+
var text = insertion.text.insertText;
|
|
3825
|
+
var at = normalizeTextInsertionRange(editor, selection, insertion);
|
|
3826
|
+
|
|
3827
|
+
if (marks) {
|
|
3828
|
+
var node = _objectSpread({
|
|
3829
|
+
text
|
|
3830
|
+
}, marks);
|
|
3831
|
+
|
|
3832
|
+
Transforms.insertNodes(editor, node, {
|
|
3833
|
+
match: Text$1.isText,
|
|
3834
|
+
at,
|
|
3835
|
+
select: true
|
|
3836
|
+
});
|
|
3837
|
+
editor.marks = null;
|
|
3838
|
+
} else {
|
|
3839
|
+
Transforms.insertText(editor, text, {
|
|
3840
|
+
at
|
|
3841
|
+
});
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
}, RESOLVE_DELAY);
|
|
3845
|
+
}
|
|
3846
|
+
}, [attributes.onCompositionEnd]),
|
|
3847
|
+
onCompositionUpdate: useCallback(event => {
|
|
3848
|
+
if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionUpdate)) {
|
|
3849
|
+
!state.isComposing && setIsComposing(true);
|
|
3850
|
+
state.isComposing = true;
|
|
3851
|
+
IS_COMPOSING.set(editor, true);
|
|
3852
|
+
}
|
|
3853
|
+
}, [attributes.onCompositionUpdate]),
|
|
3854
|
+
onCompositionStart: useCallback(event => {
|
|
3855
|
+
if (hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionStart)) {
|
|
3856
|
+
!state.isComposing && setIsComposing(true);
|
|
3857
|
+
state.isComposing = true;
|
|
3858
|
+
IS_COMPOSING.set(editor, true);
|
|
3859
|
+
}
|
|
3860
|
+
}, [attributes.onCompositionStart]),
|
|
3747
3861
|
onPaste: useCallback(event => {
|
|
3748
3862
|
// this will make application/x-slate-fragment exist when onPaste attributes is passed
|
|
3749
3863
|
event.clipboardData = getClipboardData(event.clipboardData); // This unfortunately needs to be handled with paste events instead.
|