@marimo-team/islands 0.25.3-dev206 → 0.25.3-dev207

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DFynurqb.js → ConnectedDataExplorerComponent-ApTYh0V3.js} +4 -4
  2. package/dist/{ErrorBoundary-DZyGV5dX.js → ErrorBoundary-DV6q3WpD.js} +2 -2
  3. package/dist/{abnfDiagram-VCTEODGH-DGkUyNdz.js → abnfDiagram-VCTEODGH-uo9xhZY0.js} +2 -2
  4. package/dist/{architectureDiagram-5GKGNRK7-Bav9J7uF.js → architectureDiagram-5GKGNRK7-Hz6eyeOD.js} +1 -1
  5. package/dist/assets/__vite-browser-external-CBRgnYY0.js +1 -0
  6. package/dist/assets/{worker-DodjWT_Z.js → worker-DiPNP__U.js} +2 -2
  7. package/dist/{chat-ui-Dorq26Pp.js → chat-ui-BTA1I5i1.js} +7 -7
  8. package/dist/{chunk-IMKFNOWR-1UCTsTqh.js → chunk-IMKFNOWR-DBM2i23k.js} +1 -1
  9. package/dist/{chunk-SHT3W25Y-Bige_rTb.js → chunk-SHT3W25Y-L8KQLLBy.js} +1 -1
  10. package/dist/{chunk-SVP7TREG-Cmr0Anfb.js → chunk-SVP7TREG-BOUJKJEP.js} +1 -1
  11. package/dist/{chunk-TICWLB2K-IWykFldb.js → chunk-TICWLB2K-DY3CzFjX.js} +1 -1
  12. package/dist/{classDiagram-ZZMXUADV-BH73ECRQ.js → classDiagram-ZZMXUADV-s9iwW-q4.js} +2 -2
  13. package/dist/{classDiagram-v2-VYDZK3BY-CCuCgq0H.js → classDiagram-v2-VYDZK3BY-2GI5CjGB.js} +2 -2
  14. package/dist/{code-visibility-CFFYYeyU.js → code-visibility-DLj8SFEM.js} +4 -4
  15. package/dist/{common-B9xea2wZ.js → common-BEiP9-YB.js} +9 -9
  16. package/dist/{cynefinDiagram-5FMLGOSQ-CWtL7MIJ.js → cynefinDiagram-5FMLGOSQ-DOxnhBK2.js} +1 -1
  17. package/dist/{dagre-GXQ25YYZ-DsVO2pVC.js → dagre-GXQ25YYZ-D1AhEfpM.js} +1 -1
  18. package/dist/{data-grid-overlay-editor-De3J2jxB.js → data-grid-overlay-editor-Bt6VgNDi.js} +1 -1
  19. package/dist/{diagram-S7CK7UJ4-BuAktgZv.js → diagram-S7CK7UJ4-DV_GebF_.js} +1 -1
  20. package/dist/{diagram-UQ7AKVKN-DlkAXHu5.js → diagram-UQ7AKVKN-6dNzGFfD.js} +1 -1
  21. package/dist/{diagram-VX7I27RA-B9U9H0E8.js → diagram-VX7I27RA-DUh9jsfi.js} +1 -1
  22. package/dist/{diagram-Z3DM3KII-BqmfxzUL.js → diagram-Z3DM3KII-Cug-qcQ8.js} +1 -1
  23. package/dist/{dropdown-menu-BFQYzWmC.js → dropdown-menu-dlEm41Bt.js} +1 -1
  24. package/dist/{ebnfDiagram-PWID7BFC-CH5t8ATi.js → ebnfDiagram-PWID7BFC-d5LKx7Vb.js} +2 -2
  25. package/dist/{erDiagram-RLTQ6QDP-DdIo2BIb.js → erDiagram-RLTQ6QDP-BwvlkcID.js} +1 -1
  26. package/dist/{error-entries-B0bcEwXm.js → error-entries-CVUHA5r_.js} +3875 -3884
  27. package/dist/{feedback-button-DXpmx6ff.js → feedback-button-Dd87gzc6.js} +5 -5
  28. package/dist/{flowDiagram-HODETNUW-BmYk_-Na.js → flowDiagram-HODETNUW-CJcSoFer.js} +2 -2
  29. package/dist/{formats-DyYnckF5.js → formats-Ry7c-aIV.js} +1 -1
  30. package/dist/{glide-data-editor-BevQ8Zdz.js → glide-data-editor-CW4LOU-D.js} +5 -5
  31. package/dist/{globals-Beuc24As.js → globals-D3AhIN1i.js} +2 -2
  32. package/dist/{html-to-image-BOd7ryZJ.js → html-to-image--E3uFbJ9.js} +5 -5
  33. package/dist/{infoDiagram-27XIBGKW-DvYh-Sbk.js → infoDiagram-27XIBGKW-Cezgppw3.js} +1 -1
  34. package/dist/{ishikawaDiagram-5VMMS53U-BdHnYq8s.js → ishikawaDiagram-5VMMS53U-BahZQwJz.js} +1 -1
  35. package/dist/{kanban-definition-UXKFOSKX-Bf8CT_tU.js → kanban-definition-UXKFOSKX-Cvfn_Obm.js} +1 -1
  36. package/dist/main.js +22 -22
  37. package/dist/{mermaid-DBpOnw8c.js → mermaid-BrdwbArF.js} +34 -34
  38. package/dist/{mindmap-definition-YA3MSWOX-DkYG8ltR.js → mindmap-definition-YA3MSWOX-uB4B2d-J.js} +1 -1
  39. package/dist/{number-overlay-editor-DX_x9WUo.js → number-overlay-editor-klVnf90Q.js} +1 -1
  40. package/dist/{pegDiagram-XKGWAZYB-DM7BQ0ip.js → pegDiagram-XKGWAZYB-CYaIwAmH.js} +2 -2
  41. package/dist/{pieDiagram-E7YTZNPT-CPFGg4YS.js → pieDiagram-E7YTZNPT-BJ1oUxVv.js} +1 -1
  42. package/dist/{process-output-8BbxxGrz.js → process-output-SjJxB1wh.js} +2 -2
  43. package/dist/{railroadDiagram-O6MQD6OU-4rUJlIpQ.js → railroadDiagram-O6MQD6OU-BqKSaBux.js} +2 -2
  44. package/dist/{requirementDiagram-BXWQKSXE-F6ffUUQC.js → requirementDiagram-BXWQKSXE-DwFhgDhH.js} +1 -1
  45. package/dist/{reveal-component-BMw2TipA.js → reveal-component-CS16WNwA.js} +6 -6
  46. package/dist/{sequenceDiagram-WJ2MYXX4-tNU95HVS.js → sequenceDiagram-WJ2MYXX4-L7ENjfKF.js} +1 -1
  47. package/dist/{spec-Alkla7dB.js → spec-BcJ9ncAY.js} +1 -1
  48. package/dist/{stateDiagram-D77RDMKH-BA8Modqv.js → stateDiagram-D77RDMKH-CVf88u-p.js} +2 -2
  49. package/dist/{stateDiagram-v2-MP3YSRHH-CFmickht.js → stateDiagram-v2-MP3YSRHH-DvpkQ1V6.js} +2 -2
  50. package/dist/style.css +1 -1
  51. package/dist/{swimlanes-42K2YHIH-DBiYZZZc.js → swimlanes-42K2YHIH-DIuFHbVE.js} +1 -1
  52. package/dist/{swimlanesDiagram-VR7AAH4N-CsgR851k.js → swimlanesDiagram-VR7AAH4N-CAqHAziW.js} +2 -2
  53. package/dist/{timeline-definition-24CTP7MA-Dfj0CMXY.js → timeline-definition-24CTP7MA-xO4EQqBm.js} +1 -1
  54. package/dist/{toDate-B0-Y0SEW.js → toDate-BZZ64K_m.js} +1 -5
  55. package/dist/{useAsyncData-Phxf6GCd.js → useAsyncData-Dqw22wZQ.js} +1 -1
  56. package/dist/{useDeepCompareMemoize-BXv7DUcU.js → useDeepCompareMemoize-D3gozcjJ.js} +1 -1
  57. package/dist/{useLifecycle-DDDsO4O2.js → useLifecycle-CaZi4wTw.js} +1 -1
  58. package/dist/{useTheme-DbBkeP6Z.js → useTheme-TzPgWXwB.js} +1 -4
  59. package/dist/{vega-component-C_dhEynE.js → vega-component-Blvspl7v.js} +5 -5
  60. package/dist/{vennDiagram-4TSXK5OY-fJ83Z7FE.js → vennDiagram-4TSXK5OY-DzCi-lRh.js} +1 -1
  61. package/dist/{wardleyDiagram-VM6X3IG4-DbO9cD15.js → wardleyDiagram-VM6X3IG4-CW48xa0n.js} +1 -1
  62. package/dist/{xychartDiagram-S5SC5T6Z-DmsdQJG7.js → xychartDiagram-S5SC5T6Z-UPxGGI2B.js} +1 -1
  63. package/package.json +2 -6
  64. package/src/components/app-config/user-config-form.tsx +0 -26
  65. package/src/components/editor/cell/code/cell-editor.tsx +11 -100
  66. package/src/components/editor/chrome/wrapper/footer.tsx +0 -2
  67. package/src/core/cells/__tests__/document.test.ts +0 -18
  68. package/src/core/cells/document.ts +6 -9
  69. package/src/core/codemirror/cells/__tests__/extensions.test.ts +1 -46
  70. package/src/core/codemirror/cells/extensions.ts +1 -19
  71. package/src/core/config/config-schema.ts +0 -1
  72. package/src/core/config/feature-flag.tsx +0 -2
  73. package/src/core/runtime/__tests__/runtime.test.ts +0 -16
  74. package/src/core/runtime/runtime.ts +0 -8
  75. package/src/css/app/codemirror.css +1 -1
  76. package/dist/assets/__vite-browser-external-BCJsx8QS.js +0 -1
  77. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  78. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  79. package/src/core/codemirror/rtc/extension.ts +0 -464
  80. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  81. package/src/core/codemirror/rtc/loro/awareness.ts +0 -546
  82. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  83. package/src/core/codemirror/rtc/loro/sync.ts +0 -169
  84. package/src/core/rtc/state.ts +0 -34
@@ -1,546 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import {
4
- Annotation,
5
- EditorSelection,
6
- type Extension,
7
- type SelectionRange,
8
- StateEffect,
9
- StateField,
10
- } from "@codemirror/state";
11
- import {
12
- Direction,
13
- EditorView,
14
- type LayerMarker,
15
- layer,
16
- type PluginValue,
17
- type Rect,
18
- RectangleMarker,
19
- type ViewUpdate,
20
- } from "@codemirror/view";
21
- import {
22
- type Awareness,
23
- type AwarenessListener,
24
- Cursor,
25
- type LoroDoc,
26
- type LoroText,
27
- type PeerID,
28
- type Subscription,
29
- } from "loro-crdt";
30
- import type { TypedString } from "@/utils/typed";
31
-
32
- export type ScopeId = TypedString<"loro:scope">;
33
- export type Uid = TypedString<"loro:uid"> | PeerID;
34
-
35
- export const loroCursorTheme = EditorView.baseTheme({
36
- ".loro-cursor": {
37
- position: "absolute",
38
- width: "2px",
39
- display: "inline-block",
40
- height: "1.2em",
41
- },
42
- ".loro-cursor::before": {
43
- position: "absolute",
44
- top: "1.3em",
45
- left: "0",
46
- content: "var(--rtc-name)",
47
- padding: "2px 6px",
48
- fontSize: "12px",
49
- borderRadius: "3px",
50
- whiteSpace: "nowrap",
51
- userSelect: "none",
52
- backgroundColor: "inherit",
53
- opacity: "0.7",
54
- },
55
- ".loro-selection": {
56
- opacity: "0.5",
57
- },
58
- });
59
-
60
- export type AwarenessState =
61
- | {
62
- type: "update";
63
- uid: Uid;
64
- scopeId: ScopeId;
65
- cursor: { anchor: Uint8Array; head?: Uint8Array };
66
- user?: {
67
- name: string;
68
- colorClassName: string;
69
- };
70
- }
71
- | {
72
- type: "delete";
73
- uid: Uid;
74
- scopeId: ScopeId;
75
- };
76
-
77
- export interface UserState {
78
- name: string;
79
- colorClassName: string;
80
- }
81
-
82
- type CursorEffect =
83
- | {
84
- type: "update";
85
- peer: Uid;
86
- scopeId: ScopeId;
87
- cursor: { anchor: number; head?: number };
88
- user?: UserState;
89
- }
90
- | {
91
- type: "delete";
92
- peer: Uid;
93
- scopeId: ScopeId;
94
- }
95
- | {
96
- type: "checkout";
97
- checkout: boolean;
98
- };
99
-
100
- // We should use layer https://github.com/codemirror/dev/issues/989
101
- export const remoteAwarenessAnnotation = Annotation.define<undefined>();
102
- export const remoteAwarenessEffect = StateEffect.define<CursorEffect>();
103
- export const remoteAwarenessStateField = StateField.define<{
104
- remoteCursors: Map<string, CursorPosition>;
105
- isCheckout: boolean;
106
- }>({
107
- create() {
108
- return { remoteCursors: new Map(), isCheckout: false };
109
- },
110
- update(value, tr) {
111
- for (const effect of tr.effects) {
112
- if (effect.is(remoteAwarenessEffect)) {
113
- switch (effect.value.type) {
114
- case "update": {
115
- const { peer: uid, user, cursor } = effect.value;
116
- value.remoteCursors.set(uid, {
117
- uid,
118
- cursor,
119
- user,
120
- });
121
- break;
122
- }
123
- case "delete":
124
- value.remoteCursors.delete(effect.value.peer);
125
- break;
126
- case "checkout":
127
- value.isCheckout = effect.value.checkout;
128
- }
129
- }
130
- }
131
- return value;
132
- },
133
- });
134
-
135
- const isRemoteCursorUpdate = (update: ViewUpdate): boolean => {
136
- const effect = update.transactions
137
- .flatMap((transaction) => transaction.effects)
138
- .filter((effect) => effect.is(remoteAwarenessEffect));
139
- return update.docChanged || update.viewportChanged || effect.length > 0;
140
- };
141
-
142
- export const createCursorLayer = (): Extension => {
143
- return layer({
144
- above: true,
145
- class: "loro-cursor-layer",
146
- update: isRemoteCursorUpdate,
147
- markers: (view) => {
148
- const { remoteCursors: remoteStates, isCheckout } = view.state.field(
149
- remoteAwarenessStateField,
150
- );
151
- if (isCheckout) {
152
- return [];
153
- }
154
- return [...remoteStates.values()].flatMap((state) => {
155
- const selectionRange = EditorSelection.cursor(state.cursor.anchor);
156
- return RemoteCursorMarker.createCursor(
157
- view,
158
- selectionRange,
159
- state.user?.name || "unknown",
160
- state.user?.colorClassName || "",
161
- );
162
- });
163
- },
164
- });
165
- };
166
-
167
- export const createSelectionLayer = (): Extension =>
168
- layer({
169
- above: false,
170
- class: "loro-selection-layer",
171
- update: isRemoteCursorUpdate,
172
- markers: (view) => {
173
- const { remoteCursors: remoteStates, isCheckout } = view.state.field(
174
- remoteAwarenessStateField,
175
- );
176
- if (isCheckout) {
177
- return [];
178
- }
179
- return [...remoteStates.entries()]
180
- .filter(
181
- ([, state]) =>
182
- state.cursor.head !== undefined &&
183
- state.cursor.anchor !== state.cursor.head,
184
- )
185
- .flatMap(([, state]) => {
186
- const selectionRange = EditorSelection.range(
187
- state.cursor.anchor,
188
- // oxlint-disable-next-line typescript/no-non-null-assertion
189
- state.cursor.head!,
190
- );
191
- const markers = RectangleMarker.forRange(
192
- view,
193
- `loro-selection ${state.user?.colorClassName || ""}`,
194
- selectionRange,
195
- );
196
- return markers;
197
- });
198
- },
199
- });
200
-
201
- /**
202
- * Renders a blinking cursor to indicate the cursor of another user.
203
- */
204
- export class RemoteCursorMarker implements LayerMarker {
205
- private left: number;
206
- private top: number;
207
- private height: number;
208
- private name: string;
209
- private colorClassName: string;
210
-
211
- public constructor({
212
- left,
213
- top,
214
- height,
215
- name,
216
- colorClassName,
217
- }: {
218
- left: number;
219
- top: number;
220
- height: number;
221
- name: string;
222
- colorClassName: string;
223
- }) {
224
- this.left = left;
225
- this.top = top;
226
- this.height = height;
227
- this.name = name;
228
- this.colorClassName = colorClassName;
229
- }
230
-
231
- public draw(): HTMLElement {
232
- const elt = document.createElement("div");
233
- this.adjust(elt);
234
- return elt;
235
- }
236
-
237
- public update(elt: HTMLElement): boolean {
238
- this.adjust(elt);
239
- return true;
240
- }
241
-
242
- public adjust(element: HTMLElement) {
243
- element.style.left = `${this.left}px`;
244
- element.style.top = `${this.top}px`;
245
- element.style.height = `${this.height}px`;
246
- element.className = `loro-cursor ${this.colorClassName}`;
247
- element.style.setProperty("--rtc-name", `"${this.name}"`);
248
- }
249
-
250
- public eq(other: RemoteCursorMarker): boolean {
251
- return (
252
- this.left === other.left &&
253
- this.top === other.top &&
254
- this.height === other.height &&
255
- this.name === other.name
256
- );
257
- }
258
-
259
- public static createCursor(
260
- view: EditorView,
261
- position: SelectionRange,
262
- displayName: string,
263
- colorClassName: string,
264
- ): RemoteCursorMarker[] {
265
- const absolutePosition = RemoteCursorMarker.calculateAbsoluteCursorPosition(
266
- position,
267
- view,
268
- );
269
- if (!absolutePosition) {
270
- return [];
271
- }
272
- const rect = view.scrollDOM.getBoundingClientRect();
273
- const left =
274
- view.textDirection === Direction.LTR
275
- ? rect.left
276
- : rect.right - view.scrollDOM.clientWidth;
277
- const baseLeft = left - view.scrollDOM.scrollLeft;
278
- const baseTop = rect.top - view.scrollDOM.scrollTop;
279
- return [
280
- new RemoteCursorMarker({
281
- left: absolutePosition.left - baseLeft,
282
- top: absolutePosition.top - baseTop,
283
- height: absolutePosition.bottom - absolutePosition.top,
284
- name: displayName,
285
- colorClassName,
286
- }),
287
- ];
288
- }
289
-
290
- private static calculateAbsoluteCursorPosition(
291
- position: SelectionRange,
292
- view: EditorView,
293
- ): Rect | null {
294
- const cappedPositionHead = Math.max(
295
- 0,
296
- Math.min(view.state.doc.length, position.anchor),
297
- );
298
- return view.coordsAtPos(cappedPositionHead, position.assoc || 1);
299
- }
300
- }
301
-
302
- const parseAwarenessUpdate = (
303
- doc: LoroDoc,
304
- awareness: Awareness<AwarenessState>,
305
- arg: {
306
- updated: PeerID[];
307
- added: PeerID[];
308
- removed: PeerID[];
309
- },
310
- scopeId: ScopeId,
311
- ): StateEffect<CursorEffect>[] => {
312
- const effects = [];
313
- const { updated, added } = arg;
314
- for (const update of [...updated, ...added]) {
315
- const effect = getEffects(doc, awareness, update, scopeId);
316
- if (effect) {
317
- effects.push(effect);
318
- }
319
- }
320
- return effects;
321
- };
322
-
323
- const getEffects = (
324
- doc: LoroDoc,
325
- awareness: Awareness<AwarenessState>,
326
- peer: PeerID,
327
- scopeId: ScopeId,
328
- ): StateEffect<CursorEffect> | undefined => {
329
- const states = awareness.getAllStates();
330
- const state = states[peer];
331
- if (!state) {
332
- return;
333
- }
334
- if (peer === doc.peerIdStr) {
335
- return;
336
- }
337
- if (state.scopeId !== scopeId) {
338
- return;
339
- }
340
-
341
- if (state.type === "delete") {
342
- return remoteAwarenessEffect.of({
343
- type: "delete",
344
- peer: state.uid,
345
- scopeId: state.scopeId,
346
- });
347
- }
348
-
349
- const anchor = Cursor.decode(state.cursor.anchor);
350
- const anchorPos = doc.getCursorPos(anchor)?.offset ?? 0;
351
- let headPos = anchorPos;
352
- if (state.cursor.head) {
353
- // range
354
- const head = Cursor.decode(state.cursor.head);
355
- headPos = doc.getCursorPos(head)?.offset ?? 0;
356
- }
357
- return remoteAwarenessEffect.of({
358
- type: "update",
359
- peer: state.uid,
360
- scopeId: state.scopeId,
361
- cursor: { anchor: anchorPos, head: headPos },
362
- user: state.user,
363
- });
364
- };
365
-
366
- export interface CursorPosition {
367
- uid: string;
368
- cursor: { anchor: number; head?: number };
369
- user?: UserState;
370
- }
371
-
372
- export class AwarenessPlugin implements PluginValue {
373
- public sub: Subscription;
374
- public view: EditorView;
375
- public doc: LoroDoc;
376
- public user: UserState;
377
- public awareness: Awareness<AwarenessState>;
378
- private getTextFromDoc: (doc: LoroDoc) => LoroText;
379
- private scopeId: ScopeId;
380
- private getUserId?: () => Uid;
381
-
382
- public constructor(
383
- view: EditorView,
384
- {
385
- doc,
386
- user,
387
- awareness,
388
- getTextFromDoc,
389
- scopeId,
390
- getUserId,
391
- }: {
392
- doc: LoroDoc;
393
- user: UserState;
394
- awareness: Awareness<AwarenessState>;
395
- getTextFromDoc: (doc: LoroDoc) => LoroText;
396
- scopeId: ScopeId;
397
- getUserId?: () => Uid;
398
- },
399
- ) {
400
- this.view = view;
401
- this.doc = doc;
402
- this.user = user;
403
- this.awareness = awareness;
404
- this.getTextFromDoc = getTextFromDoc;
405
- this.scopeId = scopeId;
406
- this.getUserId = getUserId;
407
- this.sub = this.doc.subscribe((e) => {
408
- if (e.by === "local") {
409
- // update remote cursor position
410
- const effects = [];
411
- for (const peer of this.awareness.peers()) {
412
- const effect = getEffects(
413
- this.doc,
414
- this.awareness,
415
- peer,
416
- this.scopeId,
417
- );
418
- if (effect) {
419
- effects.push(effect);
420
- }
421
- }
422
- this.view.dispatch({
423
- effects,
424
- });
425
- } else if (e.by === "checkout") {
426
- // TODO: better way
427
- this.view.dispatch({
428
- effects: [
429
- remoteAwarenessEffect.of({
430
- type: "checkout",
431
- checkout: this.doc.isDetached(),
432
- }),
433
- ],
434
- });
435
- }
436
- });
437
- }
438
-
439
- public update(update: ViewUpdate): void {
440
- if (!update.selectionSet && !update.focusChanged && !update.docChanged) {
441
- return;
442
- }
443
- const selection = update.state.selection.main;
444
- if (this.view.hasFocus && !this.doc.isDetached()) {
445
- const cursorState = getCursorState({
446
- doc: this.doc,
447
- getTextFromDoc: this.getTextFromDoc,
448
- anchor: selection.anchor,
449
- head: selection.head,
450
- });
451
- this.awareness.setLocalState({
452
- type: "update",
453
- uid: this.getUserId ? this.getUserId() : this.doc.peerIdStr,
454
- scopeId: this.scopeId,
455
- cursor: cursorState,
456
- user: this.user,
457
- });
458
- } else {
459
- // when checkout or blur
460
- this.awareness.setLocalState({
461
- type: "delete",
462
- uid: this.getUserId ? this.getUserId() : this.doc.peerIdStr,
463
- scopeId: this.scopeId,
464
- });
465
- }
466
- }
467
-
468
- public destroy(): void {
469
- this.sub?.();
470
- this.awareness.setLocalState({
471
- type: "delete",
472
- uid: this.getUserId ? this.getUserId() : this.doc.peerIdStr,
473
- scopeId: this.scopeId,
474
- });
475
- }
476
- }
477
- export class RemoteAwarenessPlugin implements PluginValue {
478
- public _awarenessListener?: AwarenessListener;
479
- public view: EditorView;
480
- public doc: LoroDoc;
481
- public awareness: Awareness<AwarenessState>;
482
- private scopeId: ScopeId;
483
-
484
- public constructor(
485
- view: EditorView,
486
- doc: LoroDoc,
487
- awareness: Awareness<AwarenessState>,
488
- scopeId: ScopeId,
489
- ) {
490
- this.view = view;
491
- this.doc = doc;
492
- this.awareness = awareness;
493
- this.scopeId = scopeId;
494
- const listener: AwarenessListener = async (arg, origin) => {
495
- if (origin === "local") {
496
- return;
497
- }
498
- this.view.dispatch({
499
- effects: parseAwarenessUpdate(
500
- this.doc,
501
- this.awareness,
502
- arg,
503
- this.scopeId,
504
- ),
505
- });
506
- };
507
- this._awarenessListener = listener;
508
- this.awareness.addListener(listener);
509
- }
510
-
511
- public destroy(): void {
512
- if (this._awarenessListener) {
513
- this.awareness.removeListener(this._awarenessListener);
514
- }
515
- }
516
- }
517
-
518
- const getCursorState = ({
519
- doc,
520
- getTextFromDoc,
521
- anchor,
522
- head,
523
- }: {
524
- doc: LoroDoc;
525
- getTextFromDoc: (doc: LoroDoc) => LoroText;
526
- anchor: number;
527
- head: number | undefined;
528
- }) => {
529
- if (anchor === head) {
530
- head = undefined;
531
- }
532
- const anchorCursor = getTextFromDoc(doc).getCursor(anchor)?.encode();
533
-
534
- if (!anchorCursor) {
535
- throw new Error("cursor head not found");
536
- }
537
- let headCursor: Uint8Array | undefined;
538
- if (head !== undefined) {
539
- headCursor = getTextFromDoc(doc).getCursor(head)?.encode();
540
- }
541
-
542
- return {
543
- anchor: anchorCursor,
544
- head: headCursor,
545
- };
546
- };
@@ -1,38 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- export const COLORS = [
4
- "bg-(--amber-6)",
5
- "bg-(--blue-6)",
6
- "bg-(--crimson-6)",
7
- "bg-(--cyan-6)",
8
- "bg-(--grass-6)",
9
- "bg-(--gray-6)",
10
- "bg-(--green-6)",
11
- "bg-(--lime-6)",
12
- "bg-(--orange-6)",
13
- "bg-(--purple-6)",
14
- "bg-(--red-6)",
15
- "bg-(--sage-6)",
16
- "bg-(--sky-6)",
17
- "bg-(--slate-6)",
18
- ] as const;
19
-
20
- /**
21
- * Get a deterministic color from a string or number.
22
- * @param input - The input to get a color from.
23
- */
24
- export const getColor = (input: string | number) => {
25
- if (typeof input === "string") {
26
- // Create a simple hash from the string
27
- let hash = 0;
28
- for (let i = 0; i < input.length; i++) {
29
- hash = (hash << 5) - hash + input.charCodeAt(i);
30
- hash = Math.trunc(hash); // Convert to 32bit integer
31
- }
32
- // Use absolute value to ensure positive index
33
- return COLORS[Math.abs(hash) % COLORS.length];
34
- }
35
-
36
- // Fallback for number input
37
- return COLORS[input % COLORS.length];
38
- };