@coze-editor/react-components 0.1.0-alpha.02803c

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.js ADDED
@@ -0,0 +1,1621 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.ts
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ ActiveLinePlaceholder: () => ActiveLinePlaceholder,
33
+ CursorInlayHint: () => CursorInlayHint,
34
+ CursorMirror: () => CursorMirror,
35
+ DiagnosticMarkers: () => DiagnosticMarkers,
36
+ DiffView: () => DiffView,
37
+ EmbededLineView: () => EmbededLineView,
38
+ EmbededLineViewSide: () => EmbededLineViewSide,
39
+ FoldGutter: () => FoldGutter,
40
+ Gutter: () => Gutter,
41
+ GutterLineMarker: () => GutterLineMarker,
42
+ GutterPlacement: () => GutterPlacement,
43
+ LineWidget: () => LineWidget,
44
+ Markers: () => Markers,
45
+ Mention: () => Mention,
46
+ Placeholder: () => Placeholder,
47
+ PositionMirror: () => PositionMirror,
48
+ PrefixElement: () => PrefixElement,
49
+ RefElement: () => RefElement,
50
+ SelectionSide: () => import_extensions.SelectionSide,
51
+ ValueSync: () => ValueSync,
52
+ getCurrentMentionReplaceRange: () => getCurrentMentionReplaceRange
53
+ });
54
+ module.exports = __toCommonJS(index_exports);
55
+
56
+ // src/cursor-mirror/index.tsx
57
+ var import_react = require("react");
58
+ var import_dom = require("@floating-ui/dom");
59
+ var import_react2 = require("@coze-editor/react");
60
+ var import_extensions = require("@coze-editor/extensions");
61
+ var CursorMirror = (0, import_react.forwardRef)(function CursorMirror2({ side, onChange, onVisibleChange }, ref) {
62
+ const injector = (0, import_react2.useInjector)();
63
+ const editor = (0, import_react2.useEditor)();
64
+ const [dom] = (0, import_react.useState)(() => document.createElement("div"));
65
+ const domRef = (0, import_react.useRef)(dom);
66
+ domRef.current = dom;
67
+ const onChangeRef = (0, import_react.useRef)(onChange);
68
+ onChangeRef.current = onChange;
69
+ const onVisibleChangeRef = (0, import_react.useRef)(onVisibleChange);
70
+ onVisibleChangeRef.current = onVisibleChange;
71
+ (0, import_react.useImperativeHandle)(ref, () => domRef.current);
72
+ (0, import_react.useLayoutEffect)(
73
+ () => injector.inject([
74
+ import_extensions.elementAtPosition.of({
75
+ dom: domRef.current,
76
+ pos: side
77
+ }),
78
+ import_extensions.positionElementLayer
79
+ ]),
80
+ [injector, side]
81
+ );
82
+ (0, import_react.useEffect)(() => {
83
+ const floating = document.createElement("div");
84
+ document.body.appendChild(floating);
85
+ const dispose = (0, import_dom.autoUpdate)(
86
+ domRef.current,
87
+ floating,
88
+ () => {
89
+ if (typeof onChangeRef.current === "function") {
90
+ onChangeRef.current();
91
+ }
92
+ },
93
+ { animationFrame: true }
94
+ );
95
+ return () => {
96
+ document.body.removeChild(floating);
97
+ dispose();
98
+ };
99
+ }, []);
100
+ (0, import_react.useEffect)(() => {
101
+ if (!editor) {
102
+ return;
103
+ }
104
+ const view = editor.$view;
105
+ const observer = new IntersectionObserver(
106
+ (entries) => {
107
+ entries.forEach((entry) => {
108
+ if (typeof onVisibleChangeRef.current === "function") {
109
+ onVisibleChangeRef.current(entry.isIntersecting);
110
+ }
111
+ });
112
+ },
113
+ {
114
+ root: view.scrollDOM,
115
+ threshold: 0
116
+ }
117
+ );
118
+ observer.observe(domRef.current);
119
+ return () => {
120
+ observer.disconnect();
121
+ };
122
+ }, [editor]);
123
+ return null;
124
+ });
125
+
126
+ // src/position-mirror/index.tsx
127
+ var import_react3 = require("react");
128
+ var import_dom2 = require("@floating-ui/dom");
129
+ var import_react4 = require("@coze-editor/react");
130
+ var import_extensions2 = require("@coze-editor/extensions");
131
+ var PositionMirror = (0, import_react3.forwardRef)(function CursorMirror3({ position, onChange, onVisibleChange }, ref) {
132
+ const injector = (0, import_react4.useInjector)();
133
+ const editor = (0, import_react4.useEditor)();
134
+ const [dom] = (0, import_react3.useState)(() => {
135
+ const el = document.createElement("div");
136
+ el.classList.add("cm-position-mirror");
137
+ return el;
138
+ });
139
+ const domRef = (0, import_react3.useRef)(dom);
140
+ domRef.current = dom;
141
+ const onChangeRef = (0, import_react3.useRef)(onChange);
142
+ onChangeRef.current = onChange;
143
+ const onVisibleChangeRef = (0, import_react3.useRef)(onVisibleChange);
144
+ onVisibleChangeRef.current = onVisibleChange;
145
+ (0, import_react3.useImperativeHandle)(ref, () => domRef.current);
146
+ (0, import_react3.useLayoutEffect)(
147
+ () => injector.inject([
148
+ import_extensions2.elementAtPosition.of({
149
+ dom: domRef.current,
150
+ pos: position
151
+ }),
152
+ import_extensions2.positionElementLayer
153
+ ]),
154
+ [injector, position]
155
+ );
156
+ (0, import_react3.useEffect)(() => {
157
+ const floating = document.createElement("div");
158
+ document.body.appendChild(floating);
159
+ const dispose = (0, import_dom2.autoUpdate)(
160
+ domRef.current,
161
+ floating,
162
+ () => {
163
+ if (typeof onChangeRef.current === "function") {
164
+ onChangeRef.current();
165
+ }
166
+ },
167
+ { animationFrame: true }
168
+ );
169
+ return () => {
170
+ document.body.removeChild(floating);
171
+ dispose();
172
+ };
173
+ }, []);
174
+ (0, import_react3.useEffect)(() => {
175
+ if (!editor) {
176
+ return;
177
+ }
178
+ const view = editor.$view;
179
+ const observer = new IntersectionObserver(
180
+ (entries) => {
181
+ entries.forEach((entry) => {
182
+ if (typeof onVisibleChangeRef.current === "function") {
183
+ onVisibleChangeRef.current(entry.isIntersecting);
184
+ }
185
+ });
186
+ },
187
+ {
188
+ root: view.scrollDOM,
189
+ threshold: 0
190
+ }
191
+ );
192
+ observer.observe(domRef.current);
193
+ return () => {
194
+ observer.disconnect();
195
+ };
196
+ }, [editor]);
197
+ return null;
198
+ });
199
+
200
+ // src/cursor-inlay-hint/index.tsx
201
+ var import_react_dom = require("react-dom");
202
+ var import_react5 = require("react");
203
+ var import_react_hooks = require("@coze-editor/react-hooks");
204
+ var import_react6 = require("@coze-editor/react");
205
+ var import_view = require("@codemirror/view");
206
+ var InlayHintWidget = class extends import_view.WidgetType {
207
+ constructor(element) {
208
+ super();
209
+ this.element = element;
210
+ }
211
+ eq(other) {
212
+ return this.element === other.element;
213
+ }
214
+ toDOM() {
215
+ return this.element;
216
+ }
217
+ };
218
+ function CursorInlayHint({ children }) {
219
+ const injector = (0, import_react6.useInjector)();
220
+ const element = (0, import_react_hooks.useHTMLElement)("span");
221
+ (0, import_react5.useLayoutEffect)(
222
+ () => injector.inject([
223
+ import_view.EditorView.decorations.compute(
224
+ ["selection"],
225
+ (state) => import_view.Decoration.set([
226
+ import_view.Decoration.widget({
227
+ widget: new InlayHintWidget(element),
228
+ side: 1
229
+ }).range(state.selection.main.head)
230
+ ])
231
+ )
232
+ ]),
233
+ [injector]
234
+ );
235
+ return (0, import_react_dom.createPortal)(children, element);
236
+ }
237
+
238
+ // src/markers/markers.tsx
239
+ var import_react7 = require("react");
240
+ var import_react_hooks2 = require("@coze-editor/react-hooks");
241
+ var import_react8 = require("@coze-editor/react");
242
+ var import_extensions3 = require("@coze-editor/extensions");
243
+ function Markers({ markers }) {
244
+ const injector = (0, import_react8.useInjector)();
245
+ const field = (0, import_react_hooks2.useStateField)((0, import_react7.useCallback)(() => markers, [markers]));
246
+ (0, import_react7.useLayoutEffect)(
247
+ () => injector.inject([field, import_extensions3.mergeableMarkers.from(field)]),
248
+ [injector, field]
249
+ );
250
+ return null;
251
+ }
252
+
253
+ // src/markers/diagnostic-markers.tsx
254
+ var import_react9 = __toESM(require("react"));
255
+ var import_hash_sum = __toESM(require("hash-sum"));
256
+ var import_react10 = require("@coze-editor/react");
257
+ var import_view2 = require("@codemirror/view");
258
+ function DiagnosticMarkers({ markers }) {
259
+ const theme = (0, import_react9.useMemo)(() => {
260
+ const colors = getColors(markers);
261
+ return colors.reduce((memo, color) => {
262
+ const className = getClassNameFromColor(color);
263
+ memo[`& .${className}`] = {
264
+ backgroundPosition: "left bottom",
265
+ backgroundRepeat: "repeat-x",
266
+ paddingBottom: "0.7px",
267
+ backgroundImage: underline(color)
268
+ };
269
+ return memo;
270
+ }, {});
271
+ }, [markers]);
272
+ const injector = (0, import_react10.useInjector)();
273
+ (0, import_react9.useLayoutEffect)(
274
+ () => injector.inject([import_view2.EditorView.theme(theme)]),
275
+ [injector, theme]
276
+ );
277
+ const finalMarkers = (0, import_react9.useMemo)(
278
+ () => markers.map((marker) => {
279
+ const className = getClassNameFromColor(marker.color ?? "red");
280
+ return {
281
+ from: marker.from,
282
+ to: marker.to,
283
+ className
284
+ };
285
+ }),
286
+ [markers]
287
+ );
288
+ return /* @__PURE__ */ import_react9.default.createElement(Markers, { markers: finalMarkers });
289
+ }
290
+ var isString = (v) => Boolean(v);
291
+ function getColors(markers) {
292
+ return [
293
+ .../* @__PURE__ */ new Set([
294
+ ...markers.map((marker) => marker.color).filter((v) => isString(v)),
295
+ "red"
296
+ ])
297
+ ];
298
+ }
299
+ function getClassNameFromColor(color) {
300
+ return `cm-sdk-diagnostic-marker-${(0, import_hash_sum.default)(color)}`;
301
+ }
302
+ function svg(content, attrs) {
303
+ return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
304
+ }
305
+ function underline(color) {
306
+ return svg(
307
+ `<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`,
308
+ 'width="6" height="3"'
309
+ );
310
+ }
311
+
312
+ // src/gutter/gutter.tsx
313
+ var import_react_dom2 = require("react-dom");
314
+ var import_react11 = __toESM(require("react"));
315
+ var import_utils = require("jotai/utils");
316
+ var import_jotai2 = require("jotai");
317
+ var import_react_hooks3 = require("@coze-editor/react-hooks");
318
+ var import_react12 = require("@coze-editor/react");
319
+ var import_view4 = require("@codemirror/view");
320
+ var import_state3 = require("@codemirror/state");
321
+
322
+ // src/gutter/right-gutter.ts
323
+ var import_state = require("@codemirror/state");
324
+ var import_view3 = require("@codemirror/view");
325
+ var GutterMarker = class extends import_state.RangeValue {
326
+ /// @internal
327
+ compare(other) {
328
+ return this == other || this.constructor == other.constructor && this.eq(other);
329
+ }
330
+ /// Compare this marker to another marker of the same type.
331
+ eq(other) {
332
+ return false;
333
+ }
334
+ /// This property can be used to add CSS classes to the gutter
335
+ /// element that contains this marker.
336
+ elementClass;
337
+ /// Called if the marker has a `toDOM` method and its representation
338
+ /// was removed from a gutter.
339
+ destroy(dom) {
340
+ }
341
+ };
342
+ GutterMarker.prototype.elementClass = "";
343
+ GutterMarker.prototype.toDOM = void 0;
344
+ GutterMarker.prototype.mapMode = import_state.MapMode.TrackBefore;
345
+ GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
346
+ GutterMarker.prototype.point = true;
347
+ var gutterLineClass = import_state.Facet.define();
348
+ var gutterWidgetClass = import_state.Facet.define();
349
+ var defaults = {
350
+ class: "",
351
+ renderEmptyElements: false,
352
+ elementStyle: "",
353
+ markers: () => import_state.RangeSet.empty,
354
+ lineMarker: () => null,
355
+ widgetMarker: () => null,
356
+ lineMarkerChange: null,
357
+ initialSpacer: null,
358
+ updateSpacer: null,
359
+ domEventHandlers: {}
360
+ };
361
+ var activeGutters = import_state.Facet.define();
362
+ function gutter(config) {
363
+ return [gutters(), activeGutters.of({ ...defaults, ...config })];
364
+ }
365
+ var unfixGutters = import_state.Facet.define({
366
+ combine: (values) => values.some((x) => x)
367
+ });
368
+ function gutters(config) {
369
+ const result = [
370
+ gutterView,
371
+ // right gutter theme
372
+ import_view3.EditorView.baseTheme({
373
+ ".cm-right-gutters": {
374
+ flexShrink: 0,
375
+ display: "flex",
376
+ height: "100%",
377
+ boxSizing: "border-box",
378
+ insetInlineStart: 0,
379
+ zIndex: 200
380
+ },
381
+ ".cm-right-gutter": {
382
+ display: "flex !important",
383
+ // Necessary -- prevents margin collapsing
384
+ flexDirection: "column",
385
+ flexShrink: 0,
386
+ boxSizing: "border-box",
387
+ minHeight: "100%",
388
+ overflow: "hidden"
389
+ },
390
+ ".cm-rightGutterElement": {
391
+ boxSizing: "border-box"
392
+ }
393
+ })
394
+ ];
395
+ if (config && config.fixed === false) result.push(unfixGutters.of(true));
396
+ return result;
397
+ }
398
+ var gutterView = import_view3.ViewPlugin.fromClass(class {
399
+ constructor(view) {
400
+ this.view = view;
401
+ this.prevViewport = view.viewport;
402
+ this.dom = document.createElement("div");
403
+ this.dom.className = "cm-right-gutters";
404
+ this.dom.setAttribute("aria-hidden", "true");
405
+ this.dom.style.minHeight = this.view.contentHeight / this.view.scaleY + "px";
406
+ this.gutters = view.state.facet(activeGutters).map((conf) => new SingleGutterView(view, conf));
407
+ for (const gutter2 of this.gutters) this.dom.appendChild(gutter2.dom);
408
+ this.fixed = !view.state.facet(unfixGutters);
409
+ if (this.fixed) {
410
+ this.dom.style.position = "sticky";
411
+ }
412
+ this.syncGutters(false);
413
+ view.scrollDOM.appendChild(this.dom);
414
+ }
415
+ gutters;
416
+ dom;
417
+ fixed;
418
+ prevViewport;
419
+ update(update) {
420
+ if (this.updateGutters(update)) {
421
+ const vpA = this.prevViewport, vpB = update.view.viewport;
422
+ const vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
423
+ this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
424
+ }
425
+ if (update.geometryChanged) {
426
+ this.dom.style.minHeight = this.view.contentHeight / this.view.scaleY + "px";
427
+ }
428
+ if (this.view.state.facet(unfixGutters) != !this.fixed) {
429
+ this.fixed = !this.fixed;
430
+ this.dom.style.position = this.fixed ? "sticky" : "";
431
+ }
432
+ this.prevViewport = update.view.viewport;
433
+ }
434
+ syncGutters(detach) {
435
+ const before = this.dom.previousSibling;
436
+ if (detach) this.dom.remove();
437
+ const lineClasses = import_state.RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
438
+ let classSet = [];
439
+ const contexts = this.gutters.map((gutter2) => new UpdateContext(gutter2, this.view.viewport, -this.view.documentPadding.top));
440
+ for (const line of this.view.viewportLineBlocks) {
441
+ if (classSet.length) classSet = [];
442
+ if (Array.isArray(line.type)) {
443
+ let first = true;
444
+ for (const b of line.type) {
445
+ if (b.type == import_view3.BlockType.Text && first) {
446
+ advanceCursor(lineClasses, classSet, b.from);
447
+ for (const cx of contexts) cx.line(this.view, b, classSet);
448
+ first = false;
449
+ } else if (b.widget) {
450
+ for (const cx of contexts) cx.widget(this.view, b);
451
+ }
452
+ }
453
+ } else if (line.type == import_view3.BlockType.Text) {
454
+ advanceCursor(lineClasses, classSet, line.from);
455
+ for (const cx of contexts) cx.line(this.view, line, classSet);
456
+ } else if (line.widget) {
457
+ for (const cx of contexts) cx.widget(this.view, line);
458
+ }
459
+ }
460
+ for (const cx of contexts) cx.finish();
461
+ if (detach) {
462
+ this.view.scrollDOM.insertBefore(this.dom, (before == null ? void 0 : before.nextSibling) ?? null);
463
+ }
464
+ }
465
+ updateGutters(update) {
466
+ const prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
467
+ let change = update.docChanged || update.heightChanged || update.viewportChanged || !import_state.RangeSet.eq(
468
+ update.startState.facet(gutterLineClass),
469
+ update.state.facet(gutterLineClass),
470
+ update.view.viewport.from,
471
+ update.view.viewport.to
472
+ );
473
+ if (prev == cur) {
474
+ for (const gutter2 of this.gutters) if (gutter2.update(update)) change = true;
475
+ } else {
476
+ change = true;
477
+ const gutters2 = [];
478
+ for (const conf of cur) {
479
+ const known = prev.indexOf(conf);
480
+ if (known < 0) {
481
+ gutters2.push(new SingleGutterView(this.view, conf));
482
+ } else {
483
+ this.gutters[known].update(update);
484
+ gutters2.push(this.gutters[known]);
485
+ }
486
+ }
487
+ for (const g of this.gutters) {
488
+ g.dom.remove();
489
+ if (gutters2.indexOf(g) < 0) g.destroy();
490
+ }
491
+ for (const g of gutters2) this.dom.appendChild(g.dom);
492
+ this.gutters = gutters2;
493
+ }
494
+ return change;
495
+ }
496
+ destroy() {
497
+ for (const view of this.gutters) view.destroy();
498
+ this.dom.remove();
499
+ }
500
+ }, {
501
+ provide: (plugin) => import_view3.EditorView.scrollMargins.of((view) => {
502
+ const value = view.plugin(plugin);
503
+ if (!value || value.gutters.length == 0 || !value.fixed) return null;
504
+ return view.textDirection == import_view3.Direction.LTR ? { left: value.dom.offsetWidth * view.scaleX } : { right: value.dom.offsetWidth * view.scaleX };
505
+ })
506
+ });
507
+ function asArray(val) {
508
+ return Array.isArray(val) ? val : [val];
509
+ }
510
+ function advanceCursor(cursor, collect, pos) {
511
+ while (cursor.value && cursor.from <= pos) {
512
+ if (cursor.from == pos) collect.push(cursor.value);
513
+ cursor.next();
514
+ }
515
+ }
516
+ var UpdateContext = class {
517
+ constructor(gutter2, viewport, height) {
518
+ this.gutter = gutter2;
519
+ this.height = height;
520
+ this.cursor = import_state.RangeSet.iter(gutter2.markers, viewport.from);
521
+ }
522
+ cursor;
523
+ i = 0;
524
+ addElement(view, block, markers) {
525
+ const { gutter: gutter2 } = this, above = (block.top - this.height) / view.scaleY, height = block.height / view.scaleY;
526
+ if (this.i == gutter2.elements.length) {
527
+ const newElt = new GutterElement(view, height, above, markers);
528
+ gutter2.elements.push(newElt);
529
+ gutter2.dom.appendChild(newElt.dom);
530
+ } else {
531
+ gutter2.elements[this.i].update(view, height, above, markers);
532
+ }
533
+ this.height = block.bottom;
534
+ this.i++;
535
+ }
536
+ line(view, line, extraMarkers) {
537
+ let localMarkers = [];
538
+ advanceCursor(this.cursor, localMarkers, line.from);
539
+ if (extraMarkers.length) localMarkers = localMarkers.concat(extraMarkers);
540
+ const forLine = this.gutter.config.lineMarker(view, line, localMarkers);
541
+ if (forLine) localMarkers.unshift(forLine);
542
+ const gutter2 = this.gutter;
543
+ if (localMarkers.length == 0 && !gutter2.config.renderEmptyElements) return;
544
+ this.addElement(view, line, localMarkers);
545
+ }
546
+ widget(view, block) {
547
+ const marker = this.gutter.config.widgetMarker(view, block.widget, block);
548
+ let markers = marker ? [marker] : null;
549
+ for (const cls of view.state.facet(gutterWidgetClass)) {
550
+ const marker2 = cls(view, block.widget, block);
551
+ if (marker2) (markers || (markers = [])).push(marker2);
552
+ }
553
+ if (markers) this.addElement(view, block, markers);
554
+ }
555
+ finish() {
556
+ const gutter2 = this.gutter;
557
+ while (gutter2.elements.length > this.i) {
558
+ const last = gutter2.elements.pop();
559
+ gutter2.dom.removeChild(last.dom);
560
+ last.destroy();
561
+ }
562
+ }
563
+ };
564
+ var SingleGutterView = class {
565
+ constructor(view, config) {
566
+ this.view = view;
567
+ this.config = config;
568
+ this.dom = document.createElement("div");
569
+ this.dom.className = "cm-right-gutter" + (this.config.class ? " " + this.config.class : "");
570
+ for (const prop in config.domEventHandlers) {
571
+ this.dom.addEventListener(prop, (event) => {
572
+ let target = event.target, y;
573
+ if (target != this.dom && this.dom.contains(target)) {
574
+ while (target.parentNode != this.dom) target = target.parentNode;
575
+ const rect = target.getBoundingClientRect();
576
+ y = (rect.top + rect.bottom) / 2;
577
+ } else {
578
+ y = event.clientY;
579
+ }
580
+ const line = view.lineBlockAtHeight(y - view.documentTop);
581
+ if (config.domEventHandlers[prop](view, line, event)) event.preventDefault();
582
+ });
583
+ }
584
+ this.markers = asArray(config.markers(view));
585
+ if (config.initialSpacer) {
586
+ this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
587
+ this.dom.appendChild(this.spacer.dom);
588
+ this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
589
+ }
590
+ }
591
+ dom;
592
+ elements = [];
593
+ markers;
594
+ spacer = null;
595
+ update(update) {
596
+ const prevMarkers = this.markers;
597
+ this.markers = asArray(this.config.markers(update.view));
598
+ if (this.spacer && this.config.updateSpacer) {
599
+ const updated = this.config.updateSpacer(this.spacer.markers[0], update);
600
+ if (updated != this.spacer.markers[0]) this.spacer.update(update.view, 0, 0, [updated]);
601
+ }
602
+ const vp = update.view.viewport;
603
+ return !import_state.RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) || (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
604
+ }
605
+ destroy() {
606
+ for (const elt of this.elements) elt.destroy();
607
+ }
608
+ };
609
+ var GutterElement = class {
610
+ dom;
611
+ height = -1;
612
+ above = 0;
613
+ markers = [];
614
+ constructor(view, height, above, markers) {
615
+ this.dom = document.createElement("div");
616
+ this.dom.className = "cm-rightGutterElement";
617
+ this.update(view, height, above, markers);
618
+ }
619
+ update(view, height, above, markers) {
620
+ if (this.height != height) {
621
+ this.height = height;
622
+ this.dom.style.height = height + "px";
623
+ }
624
+ if (this.above != above)
625
+ this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
626
+ if (!sameMarkers(this.markers, markers)) this.setMarkers(view, markers);
627
+ }
628
+ setMarkers(view, markers) {
629
+ let cls = "cm-rightGutterElement", domPos = this.dom.firstChild;
630
+ for (let iNew = 0, iOld = 0; ; ) {
631
+ let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
632
+ if (marker) {
633
+ const c = marker.elementClass;
634
+ if (c) cls += " " + c;
635
+ for (let i = iOld; i < this.markers.length; i++)
636
+ if (this.markers[i].compare(marker)) {
637
+ skipTo = i;
638
+ matched = true;
639
+ break;
640
+ }
641
+ } else {
642
+ skipTo = this.markers.length;
643
+ }
644
+ while (iOld < skipTo) {
645
+ const next = this.markers[iOld++];
646
+ if (next.toDOM) {
647
+ next.destroy(domPos);
648
+ const after = domPos.nextSibling;
649
+ domPos.remove();
650
+ domPos = after;
651
+ }
652
+ }
653
+ if (!marker) break;
654
+ if (marker.toDOM) {
655
+ if (matched) domPos = domPos.nextSibling;
656
+ else this.dom.insertBefore(marker.toDOM(view), domPos);
657
+ }
658
+ if (matched) iOld++;
659
+ }
660
+ this.dom.className = cls;
661
+ this.markers = markers;
662
+ }
663
+ destroy() {
664
+ this.setMarkers(null, []);
665
+ }
666
+ };
667
+ function sameMarkers(a, b) {
668
+ if (a.length != b.length) return false;
669
+ for (let i = 0; i < a.length; i++) if (!a[i].compare(b[i])) return false;
670
+ return true;
671
+ }
672
+ var activeLineGutterMarker = new class extends GutterMarker {
673
+ elementClass = "cm-activeLineRightGutter";
674
+ }();
675
+ var activeLineGutterHighlighter = gutterLineClass.compute(["selection"], (state) => {
676
+ const marks = [];
677
+ let last = -1;
678
+ for (const range of state.selection.ranges) {
679
+ const linePos = state.doc.lineAt(range.head).from;
680
+ if (linePos > last) {
681
+ last = linePos;
682
+ marks.push(activeLineGutterMarker.range(linePos));
683
+ }
684
+ }
685
+ return import_state.RangeSet.of(marks);
686
+ });
687
+
688
+ // src/gutter/atoms.ts
689
+ var import_jotai = require("jotai");
690
+ var import_state2 = require("@codemirror/state");
691
+ var facetAtom = (0, import_jotai.atom)(import_state2.Facet.define());
692
+
693
+ // src/gutter/gutter.tsx
694
+ var DOMGutterLineMarker = class extends GutterMarker {
695
+ constructor(dom) {
696
+ super();
697
+ this.dom = dom;
698
+ }
699
+ eq(other) {
700
+ return this.dom === other.dom;
701
+ }
702
+ toDOM() {
703
+ return this.dom;
704
+ }
705
+ };
706
+ function HydrateAtoms({ markers, children }) {
707
+ (0, import_utils.useHydrateAtoms)([[facetAtom, markers]]);
708
+ return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, children);
709
+ }
710
+ var GutterPlacement = /* @__PURE__ */ ((GutterPlacement2) => {
711
+ GutterPlacement2["Left"] = "left";
712
+ GutterPlacement2["Right"] = "right";
713
+ return GutterPlacement2;
714
+ })(GutterPlacement || {});
715
+ function Gutter({
716
+ defaultClassName,
717
+ placement = "left" /* Left */,
718
+ children
719
+ }) {
720
+ const [markersFacet] = (0, import_react11.useState)(
721
+ () => import_state3.Facet.define()
722
+ );
723
+ (0, import_react_hooks3.useInjectorEffect)(
724
+ (injector) => {
725
+ const gutter2 = placement === "right" /* Right */ ? gutter : import_view4.gutter;
726
+ return injector.inject([
727
+ gutter2({
728
+ class: defaultClassName ?? "",
729
+ markers(view) {
730
+ const specs = view.state.facet(markersFacet);
731
+ const { lines } = view.state.doc;
732
+ let markers = import_state3.RangeSet.empty;
733
+ for (const spec of specs) {
734
+ const { lineNumber } = spec;
735
+ if (lineNumber < 1 || lineNumber > lines) {
736
+ continue;
737
+ }
738
+ const line = view.state.doc.line(spec.lineNumber);
739
+ markers = markers.update({
740
+ add: [new DOMGutterLineMarker(spec.dom).range(line.from)],
741
+ sort: true
742
+ });
743
+ }
744
+ return markers;
745
+ }
746
+ })
747
+ ]);
748
+ },
749
+ [placement]
750
+ );
751
+ return /* @__PURE__ */ import_react11.default.createElement(import_jotai2.Provider, null, /* @__PURE__ */ import_react11.default.createElement(HydrateAtoms, { markers: markersFacet }, children));
752
+ }
753
+ function GutterLineMarker({
754
+ lineNumber,
755
+ children
756
+ }) {
757
+ const facet = (0, import_jotai2.useAtomValue)(facetAtom);
758
+ const editor = (0, import_react12.useEditor)();
759
+ const compartment = (0, import_react_hooks3.useCompartment)();
760
+ const elementRef = (0, import_react_hooks3.useLatest)((0, import_react_hooks3.useHTMLElement)());
761
+ (0, import_react_hooks3.useInjectorEffect)((injector) => injector.inject([compartment.of([])]), []);
762
+ (0, import_react11.useEffect)(() => {
763
+ if (!editor) {
764
+ return;
765
+ }
766
+ editor.$view.dispatch({
767
+ effects: compartment.reconfigure(
768
+ facet.of({
769
+ lineNumber,
770
+ dom: elementRef.current
771
+ })
772
+ )
773
+ });
774
+ }, [editor, compartment, lineNumber]);
775
+ return (0, import_react_dom2.createPortal)(children, elementRef.current);
776
+ }
777
+
778
+ // src/fold-gutter/index.tsx
779
+ var import_react_dom3 = require("react-dom");
780
+ var import_react13 = __toESM(require("react"));
781
+ var import_uuid = require("@lukeed/uuid");
782
+ var import_utils2 = require("@coze-editor/utils");
783
+ var import_react_hooks4 = require("@coze-editor/react-hooks");
784
+ var import_react14 = require("@coze-editor/react");
785
+ var import_view5 = require("@codemirror/view");
786
+ var import_state4 = require("@codemirror/state");
787
+ var import_language = require("@codemirror/language");
788
+ function FluentTriangleDown12Filled(props) {
789
+ return /* @__PURE__ */ import_react13.default.createElement(
790
+ "svg",
791
+ {
792
+ xmlns: "http://www.w3.org/2000/svg",
793
+ width: "8px",
794
+ height: "8px",
795
+ viewBox: "0 0 12 12",
796
+ ...props
797
+ },
798
+ /* @__PURE__ */ import_react13.default.createElement(
799
+ "path",
800
+ {
801
+ fill: "currentColor",
802
+ d: "M5.214 10.541a.903.903 0 0 0 1.572 0l4.092-7.169C11.226 2.762 10.789 2 10.09 2H1.91c-.698 0-1.135.762-.787 1.372z"
803
+ }
804
+ )
805
+ );
806
+ }
807
+ function FluentTriangleRight12Filled(props) {
808
+ return /* @__PURE__ */ import_react13.default.createElement(
809
+ "svg",
810
+ {
811
+ xmlns: "http://www.w3.org/2000/svg",
812
+ width: "8px",
813
+ height: "8px",
814
+ viewBox: "0 0 12 12",
815
+ ...props
816
+ },
817
+ /* @__PURE__ */ import_react13.default.createElement(
818
+ "path",
819
+ {
820
+ fill: "currentColor",
821
+ d: "M10.541 6.786a.903.903 0 0 0 0-1.572L3.372 1.122C2.762.774 2 1.211 2 1.91v8.182c0 .698.762 1.135 1.372.787z"
822
+ }
823
+ )
824
+ );
825
+ }
826
+ function defaultRenderMarker(open) {
827
+ return open ? /* @__PURE__ */ import_react13.default.createElement(FluentTriangleDown12Filled, null) : /* @__PURE__ */ import_react13.default.createElement(FluentTriangleRight12Filled, null);
828
+ }
829
+ function defaultRenderPlaceholder() {
830
+ return null;
831
+ }
832
+ function FoldGutter({
833
+ renderMarker = defaultRenderMarker,
834
+ renderPlaceholder = defaultRenderPlaceholder,
835
+ opacityTransition = false,
836
+ opacityTransitionDuration = 300
837
+ }) {
838
+ const connector = (0, import_react_hooks4.usePortalConnector)({ sync: true });
839
+ const connectorRef = (0, import_react_hooks4.useLatest)(connector);
840
+ const renderMarkerRef = (0, import_react_hooks4.useLatest)(renderMarker);
841
+ const renderPlaceholderRef = (0, import_react_hooks4.useLatest)(renderPlaceholder);
842
+ const [opacity, setOpacity] = (0, import_react13.useState)(0);
843
+ const setOpacityRef = (0, import_react_hooks4.useLatest)(setOpacity);
844
+ const injector = (0, import_react14.useInjector)();
845
+ const { Portal } = connector;
846
+ (0, import_react13.useEffect)(() => {
847
+ if (!opacityTransition || !opacityTransitionDuration) {
848
+ return;
849
+ }
850
+ return injector.inject([
851
+ import_view5.EditorView.theme({
852
+ ".cm-foldGutter": {
853
+ transition: `opacity ${opacityTransitionDuration / 1e3}s ease`
854
+ }
855
+ })
856
+ ]);
857
+ }, [injector, opacityTransition, opacityTransitionDuration]);
858
+ (0, import_react_hooks4.useInjectorEffect)(
859
+ (injector2) => {
860
+ if (!opacityTransition) {
861
+ return;
862
+ }
863
+ return injector2.inject([
864
+ import_state4.Prec.lowest(
865
+ import_view5.EditorView.theme({
866
+ ".cm-foldGutter": {
867
+ opacity
868
+ }
869
+ })
870
+ )
871
+ ]);
872
+ },
873
+ [opacityTransition, opacity]
874
+ );
875
+ (0, import_react_hooks4.useInjectorEffect)((injector2) => {
876
+ const disposes = [];
877
+ return (0, import_utils2.disposeAll)([
878
+ injector2.inject([
879
+ import_state4.Prec.low(
880
+ import_view5.EditorView.theme({
881
+ ".cm-foldGutter .cm-gutterElement": {
882
+ display: "flex",
883
+ alignItems: "center",
884
+ cursor: "pointer"
885
+ }
886
+ })
887
+ ),
888
+ (0, import_language.foldGutter)({
889
+ markerDOM(open) {
890
+ const dom = document.createElement("span");
891
+ dom.setAttribute("aria-expanded", open ? "true" : "false");
892
+ const id = (0, import_uuid.v4)();
893
+ connectorRef.current.connect(
894
+ id,
895
+ (0, import_react_dom3.createPortal)(renderMarkerRef.current(open), dom)
896
+ );
897
+ disposes.push(() => {
898
+ connectorRef.current.disconnect(id);
899
+ });
900
+ return dom;
901
+ },
902
+ domEventHandlers: {
903
+ mouseenter() {
904
+ setOpacityRef.current(1);
905
+ return true;
906
+ },
907
+ mouseleave() {
908
+ setOpacityRef.current(0);
909
+ return true;
910
+ }
911
+ }
912
+ }),
913
+ (0, import_language.codeFolding)({
914
+ placeholderDOM(view, onclick) {
915
+ const dom = document.createElement("span");
916
+ const id = (0, import_uuid.v4)();
917
+ connectorRef.current.connect(
918
+ id,
919
+ (0, import_react_dom3.createPortal)(renderPlaceholderRef.current(), dom)
920
+ );
921
+ disposes.push(() => {
922
+ connectorRef.current.disconnect(id);
923
+ });
924
+ dom.addEventListener("click", onclick, false);
925
+ disposes.push(() => {
926
+ dom.removeEventListener("click", onclick, false);
927
+ });
928
+ return dom;
929
+ }
930
+ })
931
+ ]),
932
+ ...disposes
933
+ ]);
934
+ }, []);
935
+ return /* @__PURE__ */ import_react13.default.createElement(Portal, null);
936
+ }
937
+
938
+ // src/placeholder/index.tsx
939
+ var import_react_dom4 = require("react-dom");
940
+ var import_react_hooks5 = require("@coze-editor/react-hooks");
941
+ var import_extension_placeholder = require("@coze-editor/extension-placeholder");
942
+ function Placeholder({ children }) {
943
+ const element = (0, import_react_hooks5.useHTMLElement)("span");
944
+ (0, import_react_hooks5.useInjectorEffect)(
945
+ (injector) => injector.inject([(0, import_extension_placeholder.placeholder)(() => element)]),
946
+ []
947
+ );
948
+ return (0, import_react_dom4.createPortal)(children, element);
949
+ }
950
+ function ActiveLinePlaceholder({
951
+ children
952
+ }) {
953
+ const element = (0, import_react_hooks5.useHTMLElement)("span");
954
+ (0, import_react_hooks5.useInjectorEffect)(
955
+ (injector) => injector.inject([(0, import_extension_placeholder.activeLinePlaceholder)(() => element)]),
956
+ []
957
+ );
958
+ return (0, import_react_dom4.createPortal)(children, element);
959
+ }
960
+
961
+ // src/ref-element/index.tsx
962
+ var import_react15 = require("react");
963
+ var import_react_hooks6 = require("@coze-editor/react-hooks");
964
+ var RefElement = (0, import_react15.forwardRef)(({ element }, ref) => {
965
+ const domRef = (0, import_react_hooks6.useLatest)(element);
966
+ (0, import_react15.useImperativeHandle)(ref, () => domRef.current);
967
+ return null;
968
+ });
969
+ RefElement.displayName = "RefElement";
970
+
971
+ // src/line-widget/index.tsx
972
+ var import_react_dom5 = require("react-dom");
973
+ var import_react16 = require("react");
974
+ var import_react_hooks7 = require("@coze-editor/react-hooks");
975
+ var import_react17 = require("@coze-editor/react");
976
+
977
+ // src/line-widget/cursor-widget/state.ts
978
+ var import_view7 = require("@codemirror/view");
979
+ var import_state5 = require("@codemirror/state");
980
+
981
+ // src/line-widget/cursor-widget/widget-decoration.ts
982
+ var import_view6 = require("@codemirror/view");
983
+ var CustomDivWidget = class extends import_view6.WidgetType {
984
+ customDOM;
985
+ constructor(customDOM) {
986
+ super();
987
+ this.customDOM = customDOM;
988
+ }
989
+ toDOM() {
990
+ const div = document.createElement("div");
991
+ div.className = "cursor-widget-wrapper";
992
+ div.setAttribute("style", "caret-color: initial;");
993
+ if (this.customDOM) {
994
+ div.appendChild(this.customDOM);
995
+ }
996
+ return div;
997
+ }
998
+ eq(widget) {
999
+ return widget.customDOM === this.customDOM;
1000
+ }
1001
+ };
1002
+ var createBlockWidget = (config, pos) => {
1003
+ if (typeof pos !== "number") {
1004
+ return import_view6.Decoration.none;
1005
+ }
1006
+ return import_view6.Decoration.set(
1007
+ import_view6.Decoration.widget({
1008
+ widget: new CustomDivWidget(config.createDOM()),
1009
+ side: config.side,
1010
+ block: true,
1011
+ config
1012
+ }).range(pos)
1013
+ );
1014
+ };
1015
+
1016
+ // src/line-widget/cursor-widget/state.ts
1017
+ var setWidgetEffect = import_state5.StateEffect.define();
1018
+ var getPos = (state, num) => state.doc.line(num).from;
1019
+ var cursorWidgetState = (facet) => import_state5.StateField.define({
1020
+ create(state) {
1021
+ return createBlockWidget(
1022
+ facet.config,
1023
+ typeof facet.config.lineNumber === "number" ? getPos(state, facet.config.lineNumber) : void 0
1024
+ );
1025
+ },
1026
+ update(widget, tr) {
1027
+ tr.effects.forEach((effect) => {
1028
+ if (effect.is(setWidgetEffect) && effect.value.id === facet.id) {
1029
+ widget = createBlockWidget(
1030
+ {
1031
+ ...facet.config,
1032
+ side: effect.value.side,
1033
+ lineNumber: effect.value.lineNumber
1034
+ },
1035
+ typeof effect.value.lineNumber === "number" ? getPos(tr.state, effect.value.lineNumber) : void 0
1036
+ );
1037
+ }
1038
+ });
1039
+ return widget.update({
1040
+ filter: (from, to) => 0 <= from && to <= tr.state.doc.length
1041
+ });
1042
+ },
1043
+ provide: (f) => import_view7.EditorView.decorations.from(f)
1044
+ });
1045
+ var setWidgetLineNumber = (id, lineNumber, side) => ({
1046
+ effects: [setWidgetEffect.of({ lineNumber, id, side })]
1047
+ });
1048
+
1049
+ // src/line-widget/cursor-widget/common.ts
1050
+ var nextID = 1;
1051
+ var ConfigFacet = class {
1052
+ constructor(config) {
1053
+ this.config = config;
1054
+ }
1055
+ id = nextID++;
1056
+ };
1057
+
1058
+ // src/line-widget/cursor-widget/index.ts
1059
+ var cursorBlockWidget = (config) => {
1060
+ const facet = new ConfigFacet(config);
1061
+ return {
1062
+ setWidgetLineNumber: (lineNumber, side) => setWidgetLineNumber(facet.id, lineNumber, side),
1063
+ extension: [cursorWidgetState(facet)]
1064
+ };
1065
+ };
1066
+
1067
+ // src/line-widget/index.tsx
1068
+ function LineWidget({ children, lineNumber, side }) {
1069
+ const setWidgetLineNumberRef = (0, import_react16.useRef)(null);
1070
+ const injector = (0, import_react17.useInjector)();
1071
+ const editor = (0, import_react17.useEditor)();
1072
+ (0, import_react16.useEffect)(() => {
1073
+ var _a;
1074
+ if (setWidgetLineNumberRef.current && (editor == null ? void 0 : editor.$view)) {
1075
+ (_a = editor.$view) == null ? void 0 : _a.dispatch(setWidgetLineNumberRef.current(lineNumber, side));
1076
+ }
1077
+ }, [lineNumber, side]);
1078
+ const element = (0, import_react_hooks7.useHTMLElement)("span");
1079
+ (0, import_react16.useLayoutEffect)(() => {
1080
+ const { extension, setWidgetLineNumber: setWidgetLineNumber2 } = cursorBlockWidget({
1081
+ side,
1082
+ lineNumber,
1083
+ createDOM: () => element
1084
+ });
1085
+ setWidgetLineNumberRef.current = setWidgetLineNumber2;
1086
+ return injector.inject(extension);
1087
+ }, [injector]);
1088
+ return (0, import_react_dom5.createPortal)(children, element);
1089
+ }
1090
+
1091
+ // src/diff-view/index.tsx
1092
+ var import_react18 = require("react");
1093
+ var import_react19 = require("@coze-editor/react");
1094
+
1095
+ // src/diff-view/extension.ts
1096
+ var import_view8 = require("@codemirror/view");
1097
+ var import_state7 = require("@codemirror/state");
1098
+ var import_merge = require("@codemirror/merge");
1099
+ var diffView = (props) => {
1100
+ const { original = "" } = props;
1101
+ return [
1102
+ (0, import_merge.unifiedMergeView)({
1103
+ original,
1104
+ gutter: false
1105
+ }),
1106
+ import_state7.EditorState.phrases.of({
1107
+ Accept: "^Y",
1108
+ Reject: "^N"
1109
+ }),
1110
+ import_view8.EditorView.theme({
1111
+ ".cm-deletedChunk": {
1112
+ paddingLeft: "2px",
1113
+ backgroundColor: "rgba(220, 68, 50, 0.2)"
1114
+ },
1115
+ ".cm-deletedChunk .cm-chunkButtons": {
1116
+ position: "static",
1117
+ display: "flex"
1118
+ },
1119
+ ".cm-deletedChunk .cm-chunkButtons button": {
1120
+ flex: "1",
1121
+ margin: "0px"
1122
+ },
1123
+ ".cm-deletedChunk .cm-chunkButtons button:first-child": {
1124
+ marginRight: "2px"
1125
+ },
1126
+ ".cm-deletedChunk del": {
1127
+ textDecoration: "none",
1128
+ backgroundColor: "rgba(220, 68, 50, 0.4)"
1129
+ },
1130
+ "&.cm-merge-b .cm-changedLine": {
1131
+ backgroundColor: "rgba(33, 170, 33, 0.2)"
1132
+ },
1133
+ ".cm-insertedLine .cm-changedText": {
1134
+ background: "none",
1135
+ backgroundColor: "rgba(33, 170, 33, 0.4)"
1136
+ }
1137
+ })
1138
+ ];
1139
+ };
1140
+
1141
+ // src/diff-view/index.tsx
1142
+ function DiffView({ original }) {
1143
+ const injector = (0, import_react19.useInjector)();
1144
+ (0, import_react18.useLayoutEffect)(() => injector.inject(diffView({ original })), []);
1145
+ return null;
1146
+ }
1147
+
1148
+ // src/mention/extension.ts
1149
+ var import_utils3 = require("@coze-editor/utils");
1150
+ var import_state8 = require("@codemirror/state");
1151
+
1152
+ // src/mention/is.ts
1153
+ function hasTriggerCharacters(options) {
1154
+ return Array.isArray(options.triggerCharacters);
1155
+ }
1156
+ function hasTrigger(options) {
1157
+ return typeof options.trigger === "function";
1158
+ }
1159
+
1160
+ // src/mention/extension.ts
1161
+ var validForReg = /^[\u4e00-\u9fa5a-zA-Z0-9_']*$/;
1162
+ function defaultValidFor(text) {
1163
+ return validForReg.test(text);
1164
+ }
1165
+ var fields = import_state8.Facet.define();
1166
+ function mention(options) {
1167
+ const mentionConfig = import_state8.Facet.define({
1168
+ combine: import_utils3.FacetCombineStrategy.Last
1169
+ });
1170
+ const field = import_state8.StateField.define({
1171
+ create() {
1172
+ return {
1173
+ show: false,
1174
+ triggerContext: void 0
1175
+ };
1176
+ },
1177
+ update(value, tr) {
1178
+ const options2 = tr.startState.facet(mentionConfig);
1179
+ if (!options2) {
1180
+ return value;
1181
+ }
1182
+ const { search = true, onOpenChange, onSearch, onTrigger } = options2;
1183
+ let { show } = value;
1184
+ let triggerContext = void 0;
1185
+ if (tr.docChanged) {
1186
+ if (hasTriggerCharacters(options2)) {
1187
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
1188
+ const insertString = inserted.toString();
1189
+ if (fromA === toA && options2.triggerCharacters.includes(insertString)) {
1190
+ triggerContext = {
1191
+ from: fromB,
1192
+ to: toB,
1193
+ triggerCharacter: insertString,
1194
+ cursorPosition: tr.state.selection.main.head
1195
+ };
1196
+ }
1197
+ });
1198
+ } else if (hasTrigger(options2)) {
1199
+ triggerContext = options2.trigger(tr);
1200
+ }
1201
+ if (triggerContext && typeof onTrigger === "function") {
1202
+ onTrigger({
1203
+ triggerContext: {
1204
+ from: triggerContext.from,
1205
+ to: triggerContext.to,
1206
+ triggerCharacter: triggerContext.triggerCharacter
1207
+ }
1208
+ });
1209
+ }
1210
+ }
1211
+ const isSelectUserEvent = tr.isUserEvent("select");
1212
+ const newValue = {
1213
+ show: value.show,
1214
+ triggerContext: value.triggerContext ? { ...value.triggerContext } : void 0
1215
+ };
1216
+ if (triggerContext) {
1217
+ newValue.triggerContext = triggerContext;
1218
+ show = true;
1219
+ if (typeof onSearch === "function") {
1220
+ onSearch({
1221
+ value: ""
1222
+ });
1223
+ }
1224
+ } else if (tr.docChanged && value.triggerContext && search) {
1225
+ if (newValue.triggerContext) {
1226
+ const newFrom = tr.changes.mapPos(
1227
+ value.triggerContext.from,
1228
+ 1,
1229
+ import_state8.MapMode.TrackAfter
1230
+ );
1231
+ const newTo = tr.changes.mapPos(
1232
+ value.triggerContext.to,
1233
+ 1,
1234
+ import_state8.MapMode.Simple
1235
+ );
1236
+ if (typeof newFrom === "number" && typeof newTo === "number") {
1237
+ newValue.triggerContext.from = newFrom;
1238
+ newValue.triggerContext.to = newTo;
1239
+ } else {
1240
+ show = false;
1241
+ }
1242
+ }
1243
+ if (show === true) {
1244
+ const validFor = typeof search === "object" ? search.validFor : defaultValidFor;
1245
+ const from = value.triggerContext.cursorPosition;
1246
+ const to = tr.state.selection.main.head;
1247
+ if (to >= from) {
1248
+ const text = tr.state.sliceDoc(from, to);
1249
+ if (validFor(text, from, to, tr.state)) {
1250
+ show = true;
1251
+ if (typeof onSearch === "function") {
1252
+ onSearch({
1253
+ value: text
1254
+ });
1255
+ }
1256
+ } else {
1257
+ show = false;
1258
+ }
1259
+ } else {
1260
+ show = false;
1261
+ }
1262
+ }
1263
+ } else if (isSelectUserEvent) {
1264
+ show = false;
1265
+ }
1266
+ if (show === false) {
1267
+ newValue.triggerContext = void 0;
1268
+ }
1269
+ if (show !== value.show) {
1270
+ newValue.show = show;
1271
+ if (typeof onOpenChange === "function") {
1272
+ onOpenChange({
1273
+ value: show,
1274
+ state: tr.state,
1275
+ triggerContext: newValue.triggerContext ? {
1276
+ from: newValue.triggerContext.from,
1277
+ to: newValue.triggerContext.to,
1278
+ triggerCharacter: newValue.triggerContext.triggerCharacter
1279
+ } : void 0
1280
+ });
1281
+ }
1282
+ }
1283
+ return newValue;
1284
+ }
1285
+ });
1286
+ return [mentionConfig.of(options), field, fields.of(field)];
1287
+ }
1288
+ function getCurrentMentionReplaceRange(state) {
1289
+ const allFields = state.facet(fields);
1290
+ for (const field of allFields) {
1291
+ const fieldState = state.field(field, false);
1292
+ if (fieldState && fieldState.triggerContext && typeof fieldState.triggerContext.from === "number" && typeof fieldState.triggerContext.to === "number") {
1293
+ return {
1294
+ from: fieldState.triggerContext.from,
1295
+ to: fieldState.triggerContext.to
1296
+ };
1297
+ }
1298
+ }
1299
+ }
1300
+
1301
+ // src/mention/react.tsx
1302
+ var import_react_hooks8 = require("@coze-editor/react-hooks");
1303
+ function Mention(props) {
1304
+ const propsRef = (0, import_react_hooks8.useLatest)(props);
1305
+ (0, import_react_hooks8.useInjectorEffect)((injector) => {
1306
+ const sharedOptions = {
1307
+ search: props.search,
1308
+ onOpenChange(...args) {
1309
+ if (typeof propsRef.current.onOpenChange === "function") {
1310
+ return propsRef.current.onOpenChange(...args);
1311
+ }
1312
+ },
1313
+ onSearch(...args) {
1314
+ if (typeof propsRef.current.onSearch === "function") {
1315
+ return propsRef.current.onSearch(...args);
1316
+ }
1317
+ },
1318
+ onTrigger(...args) {
1319
+ if (typeof propsRef.current.onTrigger === "function") {
1320
+ return propsRef.current.onTrigger(...args);
1321
+ }
1322
+ }
1323
+ };
1324
+ return injector.inject([
1325
+ mention(
1326
+ hasTrigger(props) ? {
1327
+ ...sharedOptions,
1328
+ trigger(tr) {
1329
+ if (hasTrigger(propsRef.current)) {
1330
+ return propsRef.current.trigger(tr);
1331
+ }
1332
+ }
1333
+ } : {
1334
+ ...sharedOptions,
1335
+ triggerCharacters: props.triggerCharacters ?? []
1336
+ }
1337
+ )
1338
+ ]);
1339
+ });
1340
+ return null;
1341
+ }
1342
+
1343
+ // src/embeded-line-view/react.tsx
1344
+ var import_react_dom6 = require("react-dom");
1345
+ var import_react21 = require("react");
1346
+ var import_react_hooks9 = require("@coze-editor/react-hooks");
1347
+ var import_react22 = require("@coze-editor/react");
1348
+ var import_view9 = require("@codemirror/view");
1349
+ var import_state9 = require("@codemirror/state");
1350
+ var DOMWidget = class extends import_view9.WidgetType {
1351
+ constructor(options) {
1352
+ super();
1353
+ this.options = options;
1354
+ }
1355
+ toDOM() {
1356
+ return this.options.dom;
1357
+ }
1358
+ eq(other) {
1359
+ return this.options.dom === other.options.dom;
1360
+ }
1361
+ };
1362
+ var EmbededLineViewSide = /* @__PURE__ */ ((EmbededLineViewSide2) => {
1363
+ EmbededLineViewSide2["Before"] = "before";
1364
+ EmbededLineViewSide2["After"] = "after";
1365
+ return EmbededLineViewSide2;
1366
+ })(EmbededLineViewSide || {});
1367
+ var updateEffect = import_state9.StateEffect.define();
1368
+ var EmbededLineView = (0, import_react21.forwardRef)(function EmbededLineView2({ children }, ref) {
1369
+ const dom = (0, import_react_hooks9.useHTMLElement)("div");
1370
+ const domRef = (0, import_react_hooks9.useLatest)(dom);
1371
+ const editor = (0, import_react22.useEditor)();
1372
+ const editorRef = (0, import_react_hooks9.useLatest)(editor);
1373
+ (0, import_react21.useImperativeHandle)(ref, () => ({
1374
+ update({ visible, line, side }) {
1375
+ var _a;
1376
+ (_a = editorRef.current) == null ? void 0 : _a.$view.dispatch({
1377
+ effects: updateEffect.of({
1378
+ visible,
1379
+ line: line ?? 1,
1380
+ side: side ?? "before" /* Before */
1381
+ })
1382
+ });
1383
+ }
1384
+ }));
1385
+ (0, import_react_hooks9.useInjectorEffect)((injector) => {
1386
+ const field = import_state9.StateField.define({
1387
+ create() {
1388
+ return {
1389
+ position: 0,
1390
+ side: "before" /* Before */,
1391
+ decorations: import_view9.Decoration.none
1392
+ };
1393
+ },
1394
+ update(value, tr) {
1395
+ const newPosition = tr.changes.mapPos(
1396
+ value.position,
1397
+ -1,
1398
+ import_state9.MapMode.Simple
1399
+ );
1400
+ let newValue = value;
1401
+ if (typeof newPosition === "number" && newPosition !== value.position) {
1402
+ const docLine = tr.state.doc.lineAt(newPosition);
1403
+ let decoPos = 0;
1404
+ if (value.side === "after" /* After */) {
1405
+ decoPos = docLine.to;
1406
+ } else {
1407
+ decoPos = docLine.from;
1408
+ }
1409
+ newValue = {
1410
+ ...value,
1411
+ position: newPosition,
1412
+ decorations: import_view9.Decoration.set([
1413
+ import_view9.Decoration.widget({
1414
+ widget: new DOMWidget({
1415
+ dom: domRef.current
1416
+ }),
1417
+ block: true,
1418
+ side: value.side === "after" /* After */ ? 1 : -1
1419
+ }).range(decoPos)
1420
+ ])
1421
+ };
1422
+ }
1423
+ for (const effect of tr.effects) {
1424
+ if (effect.is(updateEffect)) {
1425
+ const { visible, line, side } = effect.value;
1426
+ if (!visible) {
1427
+ return {
1428
+ position: newValue.position,
1429
+ side,
1430
+ decorations: import_view9.Decoration.none
1431
+ };
1432
+ }
1433
+ if (line < 1 || line > tr.startState.doc.lines) {
1434
+ continue;
1435
+ }
1436
+ const docLine = tr.startState.doc.line(line);
1437
+ let decoPos = 0;
1438
+ if (side === "after" /* After */) {
1439
+ decoPos = docLine.to;
1440
+ } else {
1441
+ decoPos = docLine.from;
1442
+ }
1443
+ return {
1444
+ position: decoPos,
1445
+ side,
1446
+ decorations: import_view9.Decoration.set([
1447
+ import_view9.Decoration.widget({
1448
+ widget: new DOMWidget({
1449
+ dom: domRef.current
1450
+ }),
1451
+ block: true,
1452
+ side: newValue.side === "after" /* After */ ? 1 : -1
1453
+ }).range(decoPos)
1454
+ ])
1455
+ };
1456
+ }
1457
+ }
1458
+ return newValue;
1459
+ },
1460
+ provide(f) {
1461
+ return import_view9.EditorView.decorations.compute(
1462
+ [f],
1463
+ (state) => state.field(f).decorations
1464
+ );
1465
+ }
1466
+ });
1467
+ return injector.inject([field]);
1468
+ }, []);
1469
+ return (0, import_react_dom6.createPortal)(children, dom);
1470
+ });
1471
+
1472
+ // src/prefix-element/react.tsx
1473
+ var import_react_dom7 = require("react-dom");
1474
+ var import_react23 = require("react");
1475
+ var import_react_hooks10 = require("@coze-editor/react-hooks");
1476
+ var import_react24 = require("@coze-editor/react");
1477
+ var import_view10 = require("@codemirror/view");
1478
+
1479
+ // src/prefix-element/dom.ts
1480
+ var scratchRange;
1481
+ function textRange(node, from, to = from) {
1482
+ const range = scratchRange || (scratchRange = document.createRange());
1483
+ range.setEnd(node, to);
1484
+ range.setStart(node, from);
1485
+ return range;
1486
+ }
1487
+ function flattenRect(rect, left) {
1488
+ const x = left ? rect.left : rect.right;
1489
+ return { left: x, right: x, top: rect.top, bottom: rect.bottom };
1490
+ }
1491
+ function clientRectsFor(dom) {
1492
+ if (dom.nodeType == 3) {
1493
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
1494
+ } else if (dom.nodeType == 1) {
1495
+ return dom.getClientRects();
1496
+ } else {
1497
+ return [];
1498
+ }
1499
+ }
1500
+
1501
+ // src/prefix-element/react.tsx
1502
+ var PrefixElementWidget = class extends import_view10.WidgetType {
1503
+ constructor(content) {
1504
+ super();
1505
+ this.content = content;
1506
+ }
1507
+ toDOM(view) {
1508
+ const wrap = document.createElement("span");
1509
+ wrap.className = "cm-prefix-element";
1510
+ wrap.style.cssText = "height: 0;";
1511
+ wrap.appendChild(
1512
+ typeof this.content === "string" ? document.createTextNode(this.content) : typeof this.content === "function" ? this.content(view) : this.content
1513
+ );
1514
+ if (typeof this.content === "string") {
1515
+ wrap.setAttribute("aria-label", `prefix ${this.content}`);
1516
+ } else {
1517
+ wrap.setAttribute("aria-hidden", "true");
1518
+ }
1519
+ return wrap;
1520
+ }
1521
+ coordsAt(dom) {
1522
+ const rects = dom.firstChild ? clientRectsFor(dom.firstChild) : [];
1523
+ if (!rects.length) {
1524
+ return null;
1525
+ }
1526
+ const style = window.getComputedStyle(dom.parentNode);
1527
+ const rect = flattenRect(rects[0], style.direction != "rtl");
1528
+ const lineHeight = parseInt(style.lineHeight);
1529
+ if (rect.bottom - rect.top > lineHeight * 1.5) {
1530
+ return {
1531
+ left: rect.left,
1532
+ right: rect.right,
1533
+ top: rect.top,
1534
+ bottom: rect.top + lineHeight
1535
+ };
1536
+ }
1537
+ return rect;
1538
+ }
1539
+ ignoreEvent() {
1540
+ return false;
1541
+ }
1542
+ };
1543
+ function PrefixElement({ deletable, onDelete, children }) {
1544
+ const element = (0, import_react_hooks10.useHTMLElement)("span");
1545
+ const latestElement = (0, import_react_hooks10.useLatest)(element);
1546
+ const latestDeletable = (0, import_react_hooks10.useLatest)(deletable);
1547
+ const latestOnDelete = (0, import_react_hooks10.useLatest)(onDelete);
1548
+ const injector = (0, import_react24.useInjector)();
1549
+ (0, import_react23.useLayoutEffect)(() => {
1550
+ function run(view) {
1551
+ if (view.state.selection.main.empty && view.state.selection.main.head === 0 && latestDeletable.current === true && typeof latestOnDelete.current === "function") {
1552
+ latestOnDelete.current();
1553
+ }
1554
+ return false;
1555
+ }
1556
+ return injector.inject([
1557
+ import_view10.EditorView.decorations.of(
1558
+ import_view10.Decoration.set([
1559
+ import_view10.Decoration.widget({
1560
+ side: -100,
1561
+ block: false,
1562
+ widget: new PrefixElementWidget(() => latestElement.current)
1563
+ }).range(0)
1564
+ ])
1565
+ ),
1566
+ import_view10.keymap.of([
1567
+ { key: "Backspace", shift: run, run },
1568
+ { key: "Meta-Backspace", shift: run, run }
1569
+ ])
1570
+ ]);
1571
+ }, []);
1572
+ return (0, import_react_dom7.createPortal)(children, element);
1573
+ }
1574
+
1575
+ // src/value-sync.tsx
1576
+ var import_react26 = require("react");
1577
+ var import_react27 = require("@coze-editor/react");
1578
+ function ValueSync({ value }) {
1579
+ const editor = (0, import_react27.useEditor)();
1580
+ (0, import_react26.useEffect)(() => {
1581
+ if (!editor) {
1582
+ return;
1583
+ }
1584
+ const { doc } = editor.$view.state;
1585
+ if (typeof value === "string" && value !== doc.toString()) {
1586
+ editor.$view.dispatch({
1587
+ changes: {
1588
+ from: 0,
1589
+ to: doc.length,
1590
+ insert: value
1591
+ }
1592
+ });
1593
+ }
1594
+ }, [editor, value]);
1595
+ return null;
1596
+ }
1597
+ // Annotate the CommonJS export names for ESM import in node:
1598
+ 0 && (module.exports = {
1599
+ ActiveLinePlaceholder,
1600
+ CursorInlayHint,
1601
+ CursorMirror,
1602
+ DiagnosticMarkers,
1603
+ DiffView,
1604
+ EmbededLineView,
1605
+ EmbededLineViewSide,
1606
+ FoldGutter,
1607
+ Gutter,
1608
+ GutterLineMarker,
1609
+ GutterPlacement,
1610
+ LineWidget,
1611
+ Markers,
1612
+ Mention,
1613
+ Placeholder,
1614
+ PositionMirror,
1615
+ PrefixElement,
1616
+ RefElement,
1617
+ SelectionSide,
1618
+ ValueSync,
1619
+ getCurrentMentionReplaceRange
1620
+ });
1621
+ //# sourceMappingURL=index.js.map