@dxos/react-ui-editor 0.3.3-main.1b7ca63

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 (81) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +21 -0
  3. package/dist/lib/browser/index.mjs +883 -0
  4. package/dist/lib/browser/index.mjs.map +7 -0
  5. package/dist/lib/browser/meta.json +1 -0
  6. package/dist/types/src/components/Composer/Composer.d.ts +15 -0
  7. package/dist/types/src/components/Composer/Composer.d.ts.map +1 -0
  8. package/dist/types/src/components/Composer/Composer.stories.d.ts +28 -0
  9. package/dist/types/src/components/Composer/Composer.stories.d.ts.map +1 -0
  10. package/dist/types/src/components/Composer/index.d.ts +2 -0
  11. package/dist/types/src/components/Composer/index.d.ts.map +1 -0
  12. package/dist/types/src/components/Markdown/Markdown.d.ts +19 -0
  13. package/dist/types/src/components/Markdown/Markdown.d.ts.map +1 -0
  14. package/dist/types/src/components/Markdown/Markdown.stories.d.ts +19 -0
  15. package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +1 -0
  16. package/dist/types/src/components/Markdown/index.d.ts +2 -0
  17. package/dist/types/src/components/Markdown/index.d.ts.map +1 -0
  18. package/dist/types/src/components/Markdown/markdownTags.d.ts +17 -0
  19. package/dist/types/src/components/Markdown/markdownTags.d.ts.map +1 -0
  20. package/dist/types/src/components/Markdown/markdownTheme.d.ts +93 -0
  21. package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +1 -0
  22. package/dist/types/src/components/RichText/RichText.d.ts +20 -0
  23. package/dist/types/src/components/RichText/RichText.d.ts.map +1 -0
  24. package/dist/types/src/components/RichText/RichText.stories.d.ts +26 -0
  25. package/dist/types/src/components/RichText/RichText.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/RichText/index.d.ts +2 -0
  27. package/dist/types/src/components/RichText/index.d.ts.map +1 -0
  28. package/dist/types/src/components/index.d.ts +4 -0
  29. package/dist/types/src/components/index.d.ts.map +1 -0
  30. package/dist/types/src/index.d.ts +5 -0
  31. package/dist/types/src/index.d.ts.map +1 -0
  32. package/dist/types/src/model.d.ts +37 -0
  33. package/dist/types/src/model.d.ts.map +1 -0
  34. package/dist/types/src/styles/index.d.ts +3 -0
  35. package/dist/types/src/styles/index.d.ts.map +1 -0
  36. package/dist/types/src/styles/markdown.d.ts +17 -0
  37. package/dist/types/src/styles/markdown.d.ts.map +1 -0
  38. package/dist/types/src/styles/tokens.d.ts +3 -0
  39. package/dist/types/src/styles/tokens.d.ts.map +1 -0
  40. package/dist/types/src/testing/index.d.ts +3 -0
  41. package/dist/types/src/testing/index.d.ts.map +1 -0
  42. package/dist/types/src/testing/proto/gen/schema.d.ts +15 -0
  43. package/dist/types/src/testing/proto/gen/schema.d.ts.map +1 -0
  44. package/dist/types/src/testing/proto/index.d.ts +2 -0
  45. package/dist/types/src/testing/proto/index.d.ts.map +1 -0
  46. package/dist/types/src/testing/replicator.d.ts +45 -0
  47. package/dist/types/src/testing/replicator.d.ts.map +1 -0
  48. package/dist/types/src/yjs/cursors.d.ts +5 -0
  49. package/dist/types/src/yjs/cursors.d.ts.map +1 -0
  50. package/dist/types/src/yjs/index.d.ts +3 -0
  51. package/dist/types/src/yjs/index.d.ts.map +1 -0
  52. package/dist/types/src/yjs/space-provider.d.ts +27 -0
  53. package/dist/types/src/yjs/space-provider.d.ts.map +1 -0
  54. package/dist/types/stories/html/code-mirror.stories.d.ts +12 -0
  55. package/dist/types/stories/html/code-mirror.stories.d.ts.map +1 -0
  56. package/package.json +82 -0
  57. package/src/components/Composer/Composer.stories.tsx +80 -0
  58. package/src/components/Composer/Composer.tsx +33 -0
  59. package/src/components/Composer/index.ts +5 -0
  60. package/src/components/Markdown/Markdown.stories.tsx +56 -0
  61. package/src/components/Markdown/Markdown.tsx +240 -0
  62. package/src/components/Markdown/index.ts +5 -0
  63. package/src/components/Markdown/markdownTags.ts +38 -0
  64. package/src/components/Markdown/markdownTheme.ts +236 -0
  65. package/src/components/RichText/RichText.stories.tsx +68 -0
  66. package/src/components/RichText/RichText.tsx +181 -0
  67. package/src/components/RichText/index.ts +5 -0
  68. package/src/components/index.ts +7 -0
  69. package/src/index.ts +9 -0
  70. package/src/model.ts +72 -0
  71. package/src/styles/index.ts +6 -0
  72. package/src/styles/markdown.ts +46 -0
  73. package/src/styles/tokens.ts +8 -0
  74. package/src/testing/index.ts +6 -0
  75. package/src/testing/proto/gen/schema.ts +47 -0
  76. package/src/testing/proto/index.ts +5 -0
  77. package/src/testing/proto/schema.proto +15 -0
  78. package/src/testing/replicator.ts +191 -0
  79. package/src/yjs/cursors.ts +21 -0
  80. package/src/yjs/index.ts +6 -0
  81. package/src/yjs/space-provider.ts +126 -0
@@ -0,0 +1,883 @@
1
+ // packages/ui/react-ui-editor/src/components/Composer/Composer.tsx
2
+ import React3, { forwardRef as forwardRef3, memo } from "react";
3
+ import { YXmlFragment } from "@dxos/text-model";
4
+
5
+ // packages/ui/react-ui-editor/src/model.ts
6
+ import { useMemo } from "react";
7
+
8
+ // packages/ui/react-ui-editor/src/yjs/cursors.ts
9
+ import * as random from "lib0/random";
10
+ var cursorColors = [
11
+ {
12
+ color: "#30bced",
13
+ light: "#30bced33"
14
+ },
15
+ {
16
+ color: "#6eeb83",
17
+ light: "#6eeb8333"
18
+ },
19
+ {
20
+ color: "#ffbc42",
21
+ light: "#ffbc4233"
22
+ },
23
+ {
24
+ color: "#ecd444",
25
+ light: "#ecd44433"
26
+ },
27
+ {
28
+ color: "#ee6352",
29
+ light: "#ee635233"
30
+ },
31
+ {
32
+ color: "#9ac2c9",
33
+ light: "#9ac2c933"
34
+ },
35
+ {
36
+ color: "#8acb88",
37
+ light: "#8acb8833"
38
+ },
39
+ {
40
+ color: "#1be7ff",
41
+ light: "#1be7ff33"
42
+ }
43
+ ];
44
+ var cursorColor = cursorColors[random.uint32() % cursorColors.length];
45
+
46
+ // packages/ui/react-ui-editor/src/yjs/space-provider.ts
47
+ import * as decoding from "lib0/decoding";
48
+ import * as encoding from "lib0/encoding";
49
+ import { Observable } from "lib0/observable";
50
+ import * as awarenessProtocol from "y-protocols/awareness";
51
+ import { log } from "@dxos/log";
52
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/yjs/space-provider.ts";
53
+ var messageAwareness = 1;
54
+ var messageQueryAwareness = 3;
55
+ var SpaceAwarenessProvider = class extends Observable {
56
+ constructor({ space, doc, channel, awareness }) {
57
+ super();
58
+ this._space = space;
59
+ this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
60
+ this._channel = channel;
61
+ this._clientId = doc.clientID;
62
+ this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
63
+ this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
64
+ if (typeof window !== "undefined") {
65
+ window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
66
+ } else if (typeof process !== "undefined") {
67
+ process.on("exit", this._handleBeforeUnload.bind(this));
68
+ }
69
+ const encoderAwarenessQuery = encoding.createEncoder();
70
+ encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
71
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
72
+ const encoderAwarenessState = encoding.createEncoder();
73
+ encoding.writeVarUint(encoderAwarenessState, messageAwareness);
74
+ encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
75
+ this._clientId
76
+ ]));
77
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
78
+ }
79
+ get awareness() {
80
+ return this._awareness;
81
+ }
82
+ _handleAwarenessUpdate({ added, updated, removed }, origin) {
83
+ log("awareness update", {
84
+ added,
85
+ updated,
86
+ removed,
87
+ origin
88
+ }, {
89
+ F: __dxlog_file,
90
+ L: 67,
91
+ S: this,
92
+ C: (f, a) => f(...a)
93
+ });
94
+ const changedClients = added.concat(updated).concat(removed);
95
+ const encoderAwareness = encoding.createEncoder();
96
+ encoding.writeVarUint(encoderAwareness, messageAwareness);
97
+ encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
98
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
99
+ }
100
+ _handleSpaceMessage({ payload }) {
101
+ log("space message", payload, {
102
+ F: __dxlog_file,
103
+ L: 79,
104
+ S: this,
105
+ C: (f, a) => f(...a)
106
+ });
107
+ const data = new Uint8Array(Array.from(Object.values(payload)));
108
+ const encoder = this._readMessage(data);
109
+ if (encoder) {
110
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
111
+ }
112
+ }
113
+ _readMessage(message) {
114
+ const decoder = decoding.createDecoder(message);
115
+ const encoder = encoding.createEncoder();
116
+ const messageType = decoding.readVarUint(decoder);
117
+ let sendReply = false;
118
+ switch (messageType) {
119
+ case messageAwareness: {
120
+ awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
121
+ break;
122
+ }
123
+ case messageQueryAwareness: {
124
+ encoding.writeVarUint(encoder, messageAwareness);
125
+ encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
126
+ sendReply = true;
127
+ break;
128
+ }
129
+ default: {
130
+ console.error("Invalid message:", messageType);
131
+ return encoder;
132
+ }
133
+ }
134
+ if (!sendReply) {
135
+ return null;
136
+ }
137
+ return encoder;
138
+ }
139
+ _handleBeforeUnload() {
140
+ awarenessProtocol.removeAwarenessStates(this._awareness, [
141
+ this._clientId
142
+ ], "window unload");
143
+ }
144
+ };
145
+
146
+ // packages/ui/react-ui-editor/src/model.ts
147
+ var useTextModel = ({ identity, space, text }) => {
148
+ const provider = useMemo(() => {
149
+ if (!space || !text?.doc) {
150
+ return void 0;
151
+ }
152
+ return new SpaceAwarenessProvider({
153
+ space,
154
+ doc: text.doc,
155
+ channel: `yjs.awareness.${text.id}`
156
+ });
157
+ }, [
158
+ identity,
159
+ space,
160
+ text?.doc
161
+ ]);
162
+ if (!text?.doc || !text?.content) {
163
+ return void 0;
164
+ }
165
+ return {
166
+ id: text.doc.guid,
167
+ content: text.content,
168
+ provider,
169
+ peer: identity ? {
170
+ id: identity.identityKey.toHex(),
171
+ name: identity.profile?.displayName
172
+ } : void 0
173
+ };
174
+ };
175
+
176
+ // packages/ui/react-ui-editor/src/components/Markdown/Markdown.tsx
177
+ import { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
178
+ import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
179
+ import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
180
+ import { bracketMatching, defaultHighlightStyle, foldKeymap, indentOnInput, syntaxHighlighting } from "@codemirror/language";
181
+ import { languages } from "@codemirror/language-data";
182
+ import { lintKeymap } from "@codemirror/lint";
183
+ import { searchKeymap, highlightSelectionMatches } from "@codemirror/search";
184
+ import { EditorState, StateField } from "@codemirror/state";
185
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
186
+ import { keymap, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, placeholder, rectangularSelection, EditorView } from "@codemirror/view";
187
+ import { useFocusableGroup } from "@fluentui/react-tabster";
188
+ import { vim } from "@replit/codemirror-vim";
189
+ import React, { forwardRef, useEffect, useImperativeHandle, useState, useMemo as useMemo2, useCallback } from "react";
190
+ import { yCollab } from "y-codemirror.next";
191
+ import { generateName } from "@dxos/display-name";
192
+ import { useThemeContext } from "@dxos/react-ui";
193
+ import { configColors } from "@dxos/react-ui-theme";
194
+ import { YText } from "@dxos/text-model";
195
+
196
+ // packages/ui/react-ui-editor/src/components/Markdown/markdownTags.ts
197
+ import { styleTags, Tag } from "@lezer/highlight";
198
+ var markdownTags = {
199
+ headingMark: Tag.define(),
200
+ quoteMark: Tag.define(),
201
+ listMark: Tag.define(),
202
+ linkMark: Tag.define(),
203
+ emphasisMark: Tag.define(),
204
+ codeMark: Tag.define(),
205
+ codeText: Tag.define(),
206
+ inlineCode: Tag.define(),
207
+ url: Tag.define(),
208
+ linkReference: Tag.define(),
209
+ linkLabel: Tag.define()
210
+ };
211
+ var markdownTagsExtension = {
212
+ props: [
213
+ styleTags({
214
+ HeaderMark: markdownTags.headingMark,
215
+ QuoteMark: markdownTags.quoteMark,
216
+ ListMark: markdownTags.listMark,
217
+ LinkMark: markdownTags.linkMark,
218
+ EmphasisMark: markdownTags.emphasisMark,
219
+ CodeMark: markdownTags.codeMark,
220
+ CodeText: markdownTags.codeText,
221
+ InlineCode: markdownTags.inlineCode,
222
+ URL: markdownTags.url,
223
+ LinkReference: markdownTags.linkReference,
224
+ LinkLabel: markdownTags.linkLabel
225
+ })
226
+ ]
227
+ };
228
+
229
+ // packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
230
+ import { markdownLanguage } from "@codemirror/lang-markdown";
231
+ import { HighlightStyle } from "@codemirror/language";
232
+ import { tags } from "@lezer/highlight";
233
+ import get from "lodash.get";
234
+
235
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
236
+ import { mx } from "@dxos/react-ui-theme";
237
+ var heading = {
238
+ 1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
239
+ 2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
240
+ 3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
241
+ 4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
242
+ 5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
243
+ 6: "mbs-4 mbe-2 font-black text-inherit no-underline"
244
+ };
245
+ var blockquote = "mlb-2 border-is-4 border-neutral-500/50 pis-5";
246
+ var unorderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[attr(marker)] [&>li:before]:mlb-1 [&>li:before]:mie-2";
247
+ var orderedList = 'mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[counters(section,_".")_"._"] [counter-reset:section] [&>li:before]:mlb-1';
248
+ var listItem = "contents before:[counter-increment:section]";
249
+ var codeBlock = "mlb-2 font-mono bg-neutral-500/10 p-3 rounded";
250
+ var horizontalRule = "mlb-4 border-neutral-500/50";
251
+ var paragraph = "mlb-1";
252
+ var bold = "font-bold";
253
+ var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
254
+ var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
255
+ var italic = "italic";
256
+ var strikethrough = "line-through";
257
+ var mark = "!font-normal !no-underline !text-inherit opacity-40";
258
+
259
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
260
+ import { tailwindConfig } from "@dxos/react-ui-theme";
261
+ var tokens = tailwindConfig({}).theme;
262
+
263
+ // packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
264
+ var ivory = "#abb2bf";
265
+ var malibu = "#61afef";
266
+ var highlightBackground = "#2c313a";
267
+ var tooltipBackground = "#353a42";
268
+ var cursor = "#ffffff";
269
+ var monospace = get(tokens, "fontFamily.mono", [
270
+ "monospace"
271
+ ]).join(",");
272
+ var markdownTheme = {
273
+ // TODO(thure): consider whether these commented-out rules from one-dark-theme should be integrated.
274
+ // '&': {
275
+ // color: ivory,
276
+ // backgroundColor: background
277
+ // },
278
+ // '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor },
279
+ // '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
280
+ // backgroundColor: selection
281
+ // },
282
+ // '.cm-panels': { backgroundColor: darkBackground, color: ivory },
283
+ // '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' },
284
+ // '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' },
285
+ // '.cm-searchMatch': {
286
+ // backgroundColor: '#72a1ff59',
287
+ // outline: '1px solid #457dff'
288
+ // },
289
+ // '.cm-searchMatch.cm-searchMatch-selected': {
290
+ // backgroundColor: '#6199ff2f'
291
+ // },
292
+ // '.cm-activeLine': { backgroundColor: '#6699ff0b' },
293
+ // '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
294
+ // '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
295
+ // backgroundColor: '#bad0f847'
296
+ // },
297
+ // '.cm-gutters': {
298
+ // backgroundColor: background,
299
+ // color: stone,
300
+ // border: 'none'
301
+ // },
302
+ // '.cm-activeLineGutter': {
303
+ // backgroundColor: highlightBackground
304
+ // },
305
+ // '.cm-foldPlaceholder': {
306
+ // backgroundColor: 'transparent',
307
+ // border: 'none',
308
+ // color: '#ddd'
309
+ // },
310
+ ".dark & .cm-tooltip": {
311
+ border: "none",
312
+ backgroundColor: tooltipBackground
313
+ },
314
+ ".dark & .cm-tooltip .cm-tooltip-arrow:before": {
315
+ borderTopColor: "transparent",
316
+ borderBottomColor: "transparent"
317
+ },
318
+ ".dark & .cm-tooltip .cm-tooltip-arrow:after": {
319
+ borderTopColor: tooltipBackground,
320
+ borderBottomColor: tooltipBackground
321
+ },
322
+ ".dark & .cm-tooltip-autocomplete": {
323
+ "& > ul > li[aria-selected]": {
324
+ backgroundColor: highlightBackground,
325
+ color: ivory
326
+ }
327
+ },
328
+ "&.cm-focused": {
329
+ outline: "none"
330
+ },
331
+ "& .cm-line": {
332
+ paddingInline: 0
333
+ },
334
+ "& .cm-line *": {
335
+ lineHeight: 1.6
336
+ },
337
+ "& .cm-selectionBackground": {
338
+ background: get(tokens, "extend.colors.primary.150", "#00ffff") + "aa"
339
+ },
340
+ ".dark & .cm-selectionBackground": {
341
+ background: get(tokens, "extend.colors.primary.500", "#00ffff") + "aa"
342
+ },
343
+ "& .cm-selectionMatch": {
344
+ background: get(tokens, "extend.colors.primary.100", "#00ffff") + "44"
345
+ },
346
+ ".dark & .cm-selectionMatch": {
347
+ background: get(tokens, "extend.colors.primary.400", "#00ffff") + "44"
348
+ },
349
+ "& .cm-content": {
350
+ caretColor: "black"
351
+ },
352
+ ".dark & .cm-content": {
353
+ caretColor: cursor
354
+ },
355
+ "& .cm-cursor": {
356
+ borderLeftColor: "black"
357
+ },
358
+ ".dark & .cm-cursor": {
359
+ borderLeftColor: cursor
360
+ },
361
+ ".cm-placeholder": {
362
+ fontFamily: get(tokens, "fontFamily.body", []).join(",")
363
+ },
364
+ "& .cm-scroller": {
365
+ fontFamily: get(tokens, "fontFamily.mono", []).join(",")
366
+ },
367
+ "& .cm-activeLine": {
368
+ backgroundColor: "transparent"
369
+ },
370
+ ".dark & .cm-activeLine": {
371
+ backgroundColor: "transparent"
372
+ },
373
+ "& .cm-ySelectionInfo": {
374
+ fontFamily: get(tokens, "fontFamily.body", []).join(","),
375
+ padding: "2px 4px",
376
+ marginBlockStart: "-4px"
377
+ },
378
+ "& .cm-ySelection": {
379
+ display: "inline-block"
380
+ },
381
+ "& .cm-ySelectionCaret": {
382
+ display: "inline-block",
383
+ verticalAlign: "top"
384
+ },
385
+ ...Object.keys(get(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
386
+ const height = get(tokens, [
387
+ "extend",
388
+ "fontSize",
389
+ fontSize,
390
+ 1,
391
+ "lineHeight"
392
+ ]);
393
+ acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
394
+ height
395
+ };
396
+ acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
397
+ height
398
+ };
399
+ acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
400
+ height
401
+ };
402
+ return acc;
403
+ }, {})
404
+ };
405
+ var markdownDarkHighlighting = HighlightStyle.define([
406
+ {
407
+ tag: [
408
+ tags.keyword,
409
+ tags.name,
410
+ tags.deleted,
411
+ tags.character,
412
+ tags.propertyName,
413
+ tags.macroName,
414
+ tags.color,
415
+ tags.constant(tags.name),
416
+ tags.standard(tags.name),
417
+ tags.definition(tags.name),
418
+ tags.separator,
419
+ tags.typeName,
420
+ tags.className,
421
+ tags.number,
422
+ tags.changed,
423
+ tags.annotation,
424
+ tags.modifier,
425
+ tags.self,
426
+ tags.namespace,
427
+ tags.operator,
428
+ tags.operatorKeyword,
429
+ tags.escape,
430
+ tags.regexp,
431
+ tags.special(tags.string),
432
+ tags.meta,
433
+ tags.comment,
434
+ tags.atom,
435
+ tags.bool,
436
+ tags.special(tags.variableName),
437
+ tags.processingInstruction,
438
+ tags.string,
439
+ tags.inserted,
440
+ tags.invalid
441
+ ],
442
+ color: "inherit !important"
443
+ },
444
+ {
445
+ tag: [
446
+ tags.link,
447
+ tags.url
448
+ ],
449
+ color: "inherit !important",
450
+ textDecoration: "none !important"
451
+ },
452
+ {
453
+ tag: [
454
+ tags.function(tags.variableName),
455
+ tags.labelName
456
+ ],
457
+ color: malibu,
458
+ fontFamily: monospace
459
+ },
460
+ {
461
+ tag: [
462
+ markdownTags.codeMark,
463
+ markdownTags.emphasisMark,
464
+ markdownTags.headingMark,
465
+ markdownTags.linkLabel,
466
+ markdownTags.linkReference,
467
+ markdownTags.listMark,
468
+ markdownTags.quoteMark,
469
+ markdownTags.url,
470
+ tags.meta,
471
+ tags.processingInstruction
472
+ ],
473
+ class: mark
474
+ },
475
+ {
476
+ tag: [
477
+ markdownTags.codeText,
478
+ markdownTags.inlineCode
479
+ ],
480
+ class: "font-mono"
481
+ },
482
+ {
483
+ tag: tags.emphasis,
484
+ class: italic
485
+ },
486
+ {
487
+ tag: tags.heading1,
488
+ class: heading[1]
489
+ },
490
+ {
491
+ tag: tags.heading2,
492
+ class: heading[2]
493
+ },
494
+ {
495
+ tag: tags.heading3,
496
+ class: heading[3]
497
+ },
498
+ {
499
+ tag: tags.heading4,
500
+ class: heading[4]
501
+ },
502
+ {
503
+ tag: tags.heading5,
504
+ class: heading[5]
505
+ },
506
+ {
507
+ tag: tags.heading6,
508
+ class: heading[6]
509
+ },
510
+ {
511
+ tag: tags.strikethrough,
512
+ class: strikethrough
513
+ },
514
+ {
515
+ tag: tags.strong,
516
+ class: bold
517
+ }
518
+ ], {
519
+ scope: markdownLanguage,
520
+ all: {
521
+ fontFamily: get(tokens, "fontFamily.body", []).join(",")
522
+ }
523
+ });
524
+
525
+ // packages/ui/react-ui-editor/src/components/Markdown/Markdown.tsx
526
+ var EditorModes = [
527
+ "default",
528
+ "vim"
529
+ ];
530
+ var hexadecimalPaletteSeries = [
531
+ "red",
532
+ "orange",
533
+ "amber",
534
+ "yellow",
535
+ "lime",
536
+ "green",
537
+ "emerald",
538
+ "teal",
539
+ "cyan",
540
+ "sky",
541
+ "indigo",
542
+ "violet",
543
+ "purple",
544
+ "fuchsia",
545
+ "pink",
546
+ "rose"
547
+ ];
548
+ var shadeKeys = {
549
+ color: "450",
550
+ highlightDark: "800",
551
+ highlightLight: "100"
552
+ };
553
+ var MarkdownComposer = /* @__PURE__ */ forwardRef(({ model, slots = {}, onChange, editorMode }, forwardedRef) => {
554
+ const { id, content, provider, peer } = model ?? {};
555
+ const { themeMode } = useThemeContext();
556
+ const tabsterDOMAttribute = useFocusableGroup({
557
+ tabBehavior: "limited"
558
+ });
559
+ const [parent, setParent] = useState(null);
560
+ const [state, setState] = useState();
561
+ const [view, setView] = useState();
562
+ useImperativeHandle(forwardedRef, () => ({
563
+ editor: parent,
564
+ state,
565
+ view
566
+ }));
567
+ const listenChangesExtension = useMemo2(() => StateField.define({
568
+ create: () => null,
569
+ update: (_value, transaction) => {
570
+ if (transaction.docChanged && onChange) {
571
+ onChange(transaction.newDoc);
572
+ }
573
+ return null;
574
+ }
575
+ }), [
576
+ onChange
577
+ ]);
578
+ useEffect(() => {
579
+ if (provider && peer) {
580
+ let peerColorDigit = Math.floor(16 * Math.random());
581
+ try {
582
+ peerColorDigit = parseInt(peer.id.slice(-1), 16);
583
+ } catch (_) {
584
+ }
585
+ provider.awareness.setLocalStateField("user", {
586
+ name: peer.name ?? generateName(peer.id),
587
+ color: configColors[hexadecimalPaletteSeries[peerColorDigit]][shadeKeys.color],
588
+ colorLight: configColors[hexadecimalPaletteSeries[peerColorDigit]][shadeKeys[themeMode === "dark" ? "highlightDark" : "highlightLight"]]
589
+ });
590
+ }
591
+ }, [
592
+ provider,
593
+ peer,
594
+ themeMode
595
+ ]);
596
+ useEffect(() => {
597
+ if (!parent) {
598
+ return;
599
+ }
600
+ const state2 = EditorState.create({
601
+ doc: content?.toString(),
602
+ extensions: [
603
+ // Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799.
604
+ listenChangesExtension,
605
+ ...editorMode === "vim" ? [
606
+ vim()
607
+ ] : [],
608
+ // All of https://github.com/codemirror/basic-setup minus line numbers and fold gutter.
609
+ highlightActiveLineGutter(),
610
+ highlightSpecialChars(),
611
+ history(),
612
+ drawSelection(),
613
+ dropCursor(),
614
+ EditorState.allowMultipleSelections.of(true),
615
+ indentOnInput(),
616
+ syntaxHighlighting(defaultHighlightStyle, {
617
+ fallback: true
618
+ }),
619
+ bracketMatching(),
620
+ closeBrackets(),
621
+ autocompletion(),
622
+ rectangularSelection(),
623
+ crosshairCursor(),
624
+ highlightActiveLine(),
625
+ highlightSelectionMatches(),
626
+ placeholder(slots.editor?.placeholder ?? ""),
627
+ keymap.of([
628
+ ...closeBracketsKeymap,
629
+ ...defaultKeymap,
630
+ ...searchKeymap,
631
+ ...historyKeymap,
632
+ ...foldKeymap,
633
+ ...completionKeymap,
634
+ ...lintKeymap,
635
+ indentWithTab
636
+ ]),
637
+ EditorView.lineWrapping,
638
+ // Theme
639
+ markdown({
640
+ base: markdownLanguage2,
641
+ codeLanguages: languages,
642
+ extensions: [
643
+ markdownTagsExtension
644
+ ]
645
+ }),
646
+ EditorView.theme({
647
+ ...markdownTheme,
648
+ ...slots.editor?.markdownTheme
649
+ }),
650
+ ...themeMode === "dark" ? [
651
+ syntaxHighlighting(oneDarkHighlightStyle)
652
+ ] : [
653
+ syntaxHighlighting(defaultHighlightStyle)
654
+ ],
655
+ // TODO(thure): All but one rule here apply to both themes; rename or refactor.
656
+ syntaxHighlighting(markdownDarkHighlighting),
657
+ // Collaboration
658
+ ...content instanceof YText ? [
659
+ yCollab(content, provider?.awareness)
660
+ ] : []
661
+ ]
662
+ });
663
+ setState(state2);
664
+ view?.destroy();
665
+ setView(new EditorView({
666
+ state: state2,
667
+ parent
668
+ }));
669
+ return () => {
670
+ view?.destroy();
671
+ setView(void 0);
672
+ setState(void 0);
673
+ };
674
+ }, [
675
+ parent,
676
+ content,
677
+ provider?.awareness,
678
+ themeMode,
679
+ editorMode
680
+ ]);
681
+ const handleKeyUp = useCallback(({ key, altKey, shiftKey, metaKey, ctrlKey }) => {
682
+ switch (key) {
683
+ case "Enter":
684
+ view?.contentDOM.focus();
685
+ break;
686
+ case "Escape":
687
+ editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && parent?.focus();
688
+ break;
689
+ }
690
+ }, [
691
+ view,
692
+ editorMode
693
+ ]);
694
+ return /* @__PURE__ */ React.createElement("div", {
695
+ tabIndex: 0,
696
+ key: id,
697
+ ...slots.root,
698
+ onKeyUp: handleKeyUp,
699
+ ...editorMode !== "vim" ? tabsterDOMAttribute : {},
700
+ ref: setParent
701
+ });
702
+ });
703
+
704
+ // packages/ui/react-ui-editor/src/components/RichText/RichText.tsx
705
+ import { mergeAttributes } from "@tiptap/core";
706
+ import Collaboration from "@tiptap/extension-collaboration";
707
+ import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
708
+ import Heading from "@tiptap/extension-heading";
709
+ import ListItem from "@tiptap/extension-list-item";
710
+ import Placeholder from "@tiptap/extension-placeholder";
711
+ import { EditorContent, useEditor as useNaturalEditor } from "@tiptap/react";
712
+ import StarterKit from "@tiptap/starter-kit";
713
+ import React2, { forwardRef as forwardRef2, useImperativeHandle as useImperativeHandle2, useMemo as useMemo3 } from "react";
714
+ import { generateName as generateName2 } from "@dxos/display-name";
715
+ import { mx as mx2 } from "@dxos/react-ui-theme";
716
+ var useEditor = ({ model, placeholder: placeholder2 = "Enter text\u2026", slots = {} }) => {
717
+ const extensions = useMemo3(() => [
718
+ StarterKit.configure({
719
+ // Extensions
720
+ history: false,
721
+ // Nodes
722
+ blockquote: {
723
+ HTMLAttributes: {
724
+ class: blockquote
725
+ }
726
+ },
727
+ bulletList: {
728
+ HTMLAttributes: {
729
+ class: unorderedList
730
+ }
731
+ },
732
+ codeBlock: {
733
+ HTMLAttributes: {
734
+ class: codeBlock
735
+ }
736
+ },
737
+ heading: false,
738
+ horizontalRule: {
739
+ HTMLAttributes: {
740
+ class: horizontalRule
741
+ }
742
+ },
743
+ listItem: false,
744
+ orderedList: {
745
+ HTMLAttributes: {
746
+ class: orderedList
747
+ }
748
+ },
749
+ paragraph: {
750
+ HTMLAttributes: {
751
+ class: paragraph
752
+ }
753
+ },
754
+ // Marks
755
+ bold: {
756
+ HTMLAttributes: {
757
+ class: bold
758
+ }
759
+ },
760
+ code: {
761
+ HTMLAttributes: {
762
+ class: codeWithoutMarks
763
+ }
764
+ },
765
+ italic: {
766
+ HTMLAttributes: {
767
+ class: italic
768
+ }
769
+ },
770
+ strike: {
771
+ HTMLAttributes: {
772
+ class: strikethrough
773
+ }
774
+ }
775
+ }),
776
+ Heading.extend({
777
+ renderHTML({ node, HTMLAttributes }) {
778
+ const hasLevel = this.options.levels.includes(node.attrs.level);
779
+ const level = hasLevel ? node.attrs.level : this.options.levels[0];
780
+ return [
781
+ `h${level}`,
782
+ mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
783
+ class: heading[level]
784
+ }),
785
+ 0
786
+ ];
787
+ }
788
+ }),
789
+ ListItem.extend({
790
+ renderHTML: ({ HTMLAttributes }) => [
791
+ "li",
792
+ mergeAttributes(HTMLAttributes, {
793
+ marker: "\u2022 ",
794
+ class: listItem
795
+ }),
796
+ [
797
+ "div",
798
+ {
799
+ role: "none"
800
+ },
801
+ 0
802
+ ]
803
+ ]
804
+ }),
805
+ // https://github.com/ueberdosis/tiptap/tree/main/packages/extension-collaboration
806
+ ...model && typeof model.content !== "string" ? [
807
+ Collaboration.configure({
808
+ fragment: model.content
809
+ })
810
+ ] : [],
811
+ ...model?.provider ? [
812
+ CollaborationCursor.configure({
813
+ provider: model.provider,
814
+ user: model.peer && {
815
+ name: model.peer.name ?? generateName2(model.peer.id),
816
+ color: cursorColor.color
817
+ }
818
+ })
819
+ ] : [],
820
+ Placeholder.configure({
821
+ placeholder: placeholder2,
822
+ emptyEditorClass: "before:content-[attr(data-placeholder)] before:absolute opacity-50 cursor-text"
823
+ })
824
+ ], [
825
+ model?.id
826
+ ]);
827
+ return useNaturalEditor({
828
+ extensions,
829
+ editorProps: {
830
+ attributes: {
831
+ class: mx2("focus:outline-none focus-visible:outline-none", slots.editor?.className),
832
+ spellcheck: slots.editor?.spellCheck === false ? "false" : "true",
833
+ tabindex: slots.editor?.tabIndex ? String(slots.editor?.tabIndex) : "0"
834
+ }
835
+ }
836
+ }, [
837
+ extensions
838
+ ]);
839
+ };
840
+ var RichTextComposer = /* @__PURE__ */ forwardRef2((props, ref) => {
841
+ const editor = useEditor(props);
842
+ useImperativeHandle2(ref, () => editor, [
843
+ editor
844
+ ]);
845
+ return /* @__PURE__ */ React2.createElement(EditorContent, {
846
+ ...props.slots?.root,
847
+ editor
848
+ });
849
+ });
850
+
851
+ // packages/ui/react-ui-editor/src/components/Composer/Composer.tsx
852
+ var Composer = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef3(({ slots, ...options }, forwardedRef) => {
853
+ const model = useTextModel(options);
854
+ if (model?.content instanceof YXmlFragment) {
855
+ return /* @__PURE__ */ React3.createElement(RichTextComposer, {
856
+ ref: forwardedRef,
857
+ model,
858
+ slots
859
+ });
860
+ } else {
861
+ return /* @__PURE__ */ React3.createElement(MarkdownComposer, {
862
+ ref: forwardedRef,
863
+ model,
864
+ slots
865
+ });
866
+ }
867
+ }));
868
+
869
+ // packages/ui/react-ui-editor/src/index.ts
870
+ import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
871
+ import { Doc, YText as YText2, YXmlFragment as YXmlFragment2 } from "@dxos/text-model";
872
+ export {
873
+ Composer,
874
+ Doc,
875
+ EditorModes,
876
+ MarkdownComposer,
877
+ RichTextComposer,
878
+ TextKind,
879
+ YText2 as YText,
880
+ YXmlFragment2 as YXmlFragment,
881
+ useTextModel
882
+ };
883
+ //# sourceMappingURL=index.mjs.map