@dxos/react-ui-editor 0.7.5-main.499c70c → 0.7.5-main.6a330ac

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 (87) hide show
  1. package/dist/lib/browser/index.mjs +1125 -1137
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +1145 -1171
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +1125 -1137
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/InputMode.stories.d.ts +3 -4
  11. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  12. package/dist/types/src/TextEditor.stories.d.ts +34 -35
  13. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +3 -0
  15. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -0
  16. package/dist/types/src/components/EditorToolbar/blocks.d.ts +18 -0
  17. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -0
  18. package/dist/types/src/components/EditorToolbar/comment.d.ts +17 -0
  19. package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -0
  20. package/dist/types/src/components/EditorToolbar/formatting.d.ts +18 -0
  21. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -0
  22. package/dist/types/src/components/EditorToolbar/headings.d.ts +18 -0
  23. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -0
  24. package/dist/types/src/components/EditorToolbar/index.d.ts +3 -0
  25. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -0
  26. package/dist/types/src/components/EditorToolbar/lists.d.ts +18 -0
  27. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
  28. package/dist/types/src/components/EditorToolbar/util.d.ts +58 -0
  29. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -0
  30. package/dist/types/src/components/EditorToolbar/viewMode.d.ts +18 -0
  31. package/dist/types/src/components/EditorToolbar/viewMode.d.ts.map +1 -0
  32. package/dist/types/src/components/index.d.ts +1 -1
  33. package/dist/types/src/components/index.d.ts.map +1 -1
  34. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +5 -6
  35. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  36. package/dist/types/src/extensions/comments.d.ts +3 -4
  37. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  38. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/editorAction.d.ts +12 -0
  40. package/dist/types/src/extensions/markdown/editorAction.d.ts.map +1 -0
  41. package/dist/types/src/extensions/markdown/formatting.d.ts +14 -12
  42. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/index.d.ts +1 -1
  44. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  45. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useActionHandler.d.ts +2 -2
  47. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  48. package/dist/types/src/index.d.ts +1 -0
  49. package/dist/types/src/index.d.ts.map +1 -1
  50. package/dist/types/src/styles/stack-item-content-class-names.d.ts +3 -0
  51. package/dist/types/src/styles/stack-item-content-class-names.d.ts.map +1 -0
  52. package/dist/types/src/styles/theme.d.ts.map +1 -1
  53. package/dist/types/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +31 -29
  55. package/src/InputMode.stories.tsx +7 -10
  56. package/src/components/EditorToolbar/EditorToolbar.tsx +106 -0
  57. package/src/components/EditorToolbar/blocks.ts +41 -0
  58. package/src/components/EditorToolbar/comment.ts +23 -0
  59. package/src/components/EditorToolbar/formatting.ts +41 -0
  60. package/src/components/EditorToolbar/headings.ts +59 -0
  61. package/src/components/EditorToolbar/index.ts +6 -0
  62. package/src/components/EditorToolbar/lists.ts +40 -0
  63. package/src/components/EditorToolbar/util.ts +65 -0
  64. package/src/components/EditorToolbar/viewMode.ts +48 -0
  65. package/src/components/index.ts +1 -1
  66. package/src/extensions/automerge/automerge.stories.tsx +2 -2
  67. package/src/extensions/comments.ts +12 -19
  68. package/src/extensions/factories.ts +11 -5
  69. package/src/extensions/markdown/decorate.ts +1 -1
  70. package/src/extensions/markdown/{action.ts → editorAction.ts} +22 -20
  71. package/src/extensions/markdown/formatting.test.ts +7 -6
  72. package/src/extensions/markdown/formatting.ts +20 -24
  73. package/src/extensions/markdown/index.ts +1 -1
  74. package/src/extensions/markdown/styles.ts +21 -0
  75. package/src/hooks/useActionHandler.ts +4 -4
  76. package/src/index.ts +4 -0
  77. package/src/styles/markdown.ts +1 -1
  78. package/src/styles/stack-item-content-class-names.ts +17 -0
  79. package/src/styles/theme.ts +2 -3
  80. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -34
  81. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  82. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  83. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  84. package/dist/types/src/extensions/markdown/action.d.ts +0 -9
  85. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  86. package/src/components/Toolbar/Toolbar.tsx +0 -522
  87. package/src/components/Toolbar/index.ts +0 -5
@@ -39,261 +39,862 @@ import { EditorView as EditorView21, keymap as keymap11 } from "@codemirror/view
39
39
  import { tags as tags2 } from "@lezer/highlight";
40
40
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
41
41
 
42
- // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
43
- import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, CaretDown, Check, PencilSimpleSlash, MarkdownLogo, PencilSimple } from "@phosphor-icons/react";
44
- import { createContext } from "@radix-ui/react-context";
45
- import React3, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
46
- import { useDropzone } from "react-dropzone";
47
- import { Button, DropdownMenu, ElevationProvider, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
48
- import { getSize } from "@dxos/react-ui-theme";
42
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/EditorToolbar.tsx
43
+ import React, { useCallback } from "react";
44
+ import { ElevationProvider } from "@dxos/react-ui";
45
+ import { ToolbarMenu, MenuProvider, useMenuActions, createGapSeparator } from "@dxos/react-ui-menu";
46
+ import { textBlockWidth } from "@dxos/react-ui-theme";
49
47
 
50
- // packages/ui/react-ui-editor/src/extensions/annotations.ts
51
- import { StateField } from "@codemirror/state";
52
- import { Decoration, EditorView } from "@codemirror/view";
53
- import { isNotFalsy } from "@dxos/util";
54
-
55
- // packages/ui/react-ui-editor/src/util/facet.ts
56
- import { Facet } from "@codemirror/state";
57
- var singleValueFacet = (defaultValue) => Facet.define({
58
- // Called immediately.
59
- combine: (providers) => {
60
- return providers[0] ?? defaultValue;
48
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/util.ts
49
+ import { useMemo } from "react";
50
+ import { create } from "@dxos/live-object";
51
+ import { createMenuAction, createMenuItemGroup } from "@dxos/react-ui-menu";
52
+ var useEditorToolbarState = (initialState = {}) => {
53
+ return useMemo(() => create(initialState), []);
54
+ };
55
+ var createEditorAction = (payload, icon, label = [
56
+ `${payload.type} label`,
57
+ {
58
+ ns: translationKey
61
59
  }
60
+ ], id = payload.type) => createMenuAction(id, {
61
+ icon,
62
+ label,
63
+ ...payload
64
+ });
65
+ var createEditorActionGroup = (id, props, icon) => createMenuItemGroup(id, {
66
+ icon,
67
+ iconOnly: true,
68
+ ...props
62
69
  });
70
+ var editorToolbarSearch = createEditorAction({
71
+ type: "search"
72
+ }, "ph--magnifying-glass--regular");
63
73
 
64
- // packages/ui/react-ui-editor/src/util/cursor.ts
65
- var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
66
- var defaultCursorConverter = {
67
- toCursor: (position) => position.toString(),
68
- fromCursor: (cursor) => parseInt(cursor)
69
- };
70
- var Cursor = class _Cursor {
71
- static {
72
- this.converter = singleValueFacet(defaultCursorConverter);
73
- }
74
- static {
75
- this.getCursorFromRange = (state, range) => {
76
- const cursorConverter2 = state.facet(_Cursor.converter);
77
- const from = cursorConverter2.toCursor(range.from);
78
- const to = cursorConverter2.toCursor(range.to, -1);
79
- return [
80
- from,
81
- to
82
- ].join(":");
83
- };
84
- }
85
- static {
86
- this.getRangeFromCursor = (state, cursor) => {
87
- const cursorConverter2 = state.facet(_Cursor.converter);
88
- const parts = cursor.split(":");
89
- const from = cursorConverter2.fromCursor(parts[0]);
90
- const to = cursorConverter2.fromCursor(parts[1]);
91
- return from !== void 0 && to !== void 0 ? {
92
- from,
93
- to
94
- } : void 0;
95
- };
96
- }
74
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/blocks.ts
75
+ var createBlockGroupAction = (value) => createEditorActionGroup("block", {
76
+ variant: "toggleGroup",
77
+ selectCardinality: "single",
78
+ value
79
+ });
80
+ var createBlockActions = (value, blankLine) => Object.entries({
81
+ blockquote: "ph--quotes--regular",
82
+ codeblock: "ph--code-block--regular",
83
+ table: "ph--table--regular"
84
+ }).map(([type, icon]) => {
85
+ return createEditorAction({
86
+ type,
87
+ checked: type === value,
88
+ ...type === "table" && {
89
+ disabled: !!blankLine
90
+ }
91
+ }, icon);
92
+ });
93
+ var createBlocks = (state) => {
94
+ const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
95
+ const blockGroupAction = createBlockGroupAction(value);
96
+ const blockActions = createBlockActions(value, state.blankLine);
97
+ return {
98
+ nodes: [
99
+ blockGroupAction,
100
+ ...blockActions
101
+ ],
102
+ edges: [
103
+ {
104
+ source: "root",
105
+ target: "block"
106
+ },
107
+ ...blockActions.map(({ id }) => ({
108
+ source: blockGroupAction.id,
109
+ target: id
110
+ }))
111
+ ]
112
+ };
97
113
  };
98
114
 
99
- // packages/ui/react-ui-editor/src/util/debug.ts
100
- import { log } from "@dxos/log";
101
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
102
- var wrapWithCatch = (fn) => {
103
- return (...args) => {
104
- try {
105
- return fn(...args);
106
- } catch (err) {
107
- log.catch(err, void 0, {
108
- F: __dxlog_file,
109
- L: 15,
110
- S: void 0,
111
- C: (f, a) => f(...a)
112
- });
115
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/comment.ts
116
+ var commentLabel = (comment, selection) => comment ? "selection overlaps existing comment label" : selection === false ? "select text to comment label" : "comment label";
117
+ var createCommentAction = (label) => createEditorAction({
118
+ type: "comment",
119
+ testId: "editor.toolbar.comment"
120
+ }, "ph--chat-text--regular", label);
121
+ var createComment = (state) => ({
122
+ nodes: [
123
+ createCommentAction([
124
+ commentLabel(state.comment, state.selection),
125
+ {
126
+ ns: translationKey
127
+ }
128
+ ])
129
+ ],
130
+ edges: [
131
+ {
132
+ source: "root",
133
+ target: "comment"
113
134
  }
135
+ ]
136
+ });
137
+
138
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/formatting.ts
139
+ var formats = {
140
+ strong: "ph--text-b--regular",
141
+ emphasis: "ph--text-italic--regular",
142
+ strikethrough: "ph--text-strikethrough--regular",
143
+ code: "ph--code--regular",
144
+ link: "ph--link--regular"
145
+ };
146
+ var createFormattingGroup = (formatting) => createEditorActionGroup("formatting", {
147
+ variant: "toggleGroup",
148
+ selectCardinality: "multiple",
149
+ value: Object.keys(formats).filter((key) => !!formatting[key])
150
+ });
151
+ var createFormattingActions = (formatting) => Object.entries(formats).map(([type, icon]) => createEditorAction({
152
+ type,
153
+ checked: !!formatting[type]
154
+ }, icon));
155
+ var createFormatting = (state) => {
156
+ const formattingGroupAction = createFormattingGroup(state);
157
+ const formattingActions = createFormattingActions(state);
158
+ return {
159
+ nodes: [
160
+ formattingGroupAction,
161
+ ...formattingActions
162
+ ],
163
+ edges: [
164
+ {
165
+ source: "root",
166
+ target: "formatting"
167
+ },
168
+ ...formattingActions.map(({ id }) => ({
169
+ source: formattingGroupAction.id,
170
+ target: id
171
+ }))
172
+ ]
114
173
  };
115
174
  };
116
- var callbackWrapper = (fn) => (...args) => {
117
- try {
118
- return fn(...args);
119
- } catch (err) {
120
- log.catch(err, void 0, {
121
- F: __dxlog_file,
122
- L: 29,
123
- S: void 0,
124
- C: (f, a) => f(...a)
125
- });
126
- }
175
+
176
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/headings.ts
177
+ var createHeadingGroupAction = (value) => createEditorActionGroup("heading", {
178
+ variant: "dropdownMenu",
179
+ applyActive: true,
180
+ selectCardinality: "single",
181
+ value
182
+ }, "ph--text-h--regular");
183
+ var createHeadingActions = (value) => Object.entries({
184
+ "0": "ph--paragraph--regular",
185
+ "1": "ph--text-h-one--regular",
186
+ "2": "ph--text-h-two--regular",
187
+ "3": "ph--text-h-three--regular",
188
+ "4": "ph--text-h-four--regular",
189
+ "5": "ph--text-h-five--regular",
190
+ "6": "ph--text-h-six--regular"
191
+ }).map(([levelStr, icon]) => {
192
+ const level = parseInt(levelStr);
193
+ return createEditorAction({
194
+ type: "heading",
195
+ data: level,
196
+ checked: value === levelStr
197
+ }, icon, [
198
+ "heading level label",
199
+ {
200
+ count: level,
201
+ ns: translationKey
202
+ }
203
+ ], `heading--${levelStr}`);
204
+ });
205
+ var computeHeadingValue = (state) => {
206
+ const blockType = state ? state.blockType : "paragraph";
207
+ const header = blockType && /heading(\d)/.exec(blockType);
208
+ return header ? header[1] : blockType === "paragraph" || !blockType ? "0" : "";
127
209
  };
128
- var debugDispatcher = (trs, view) => {
129
- logChanges(trs);
130
- view.update(trs);
210
+ var createHeadings = (state) => {
211
+ const headingValue = computeHeadingValue(state);
212
+ const headingGroupAction = createHeadingGroupAction(headingValue);
213
+ const headingActions = createHeadingActions(headingValue);
214
+ return {
215
+ nodes: [
216
+ headingGroupAction,
217
+ ...headingActions
218
+ ],
219
+ edges: [
220
+ {
221
+ source: "root",
222
+ target: "heading"
223
+ },
224
+ ...headingActions.map(({ id }) => ({
225
+ source: headingGroupAction.id,
226
+ target: id
227
+ }))
228
+ ]
229
+ };
131
230
  };
132
- var logChanges = (trs) => {
133
- const changes = trs.flatMap((tr) => {
134
- if (tr.changes.empty) {
135
- return void 0;
231
+
232
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/lists.ts
233
+ var listStyles = {
234
+ bullet: "ph--list-bullets--regular",
235
+ ordered: "ph--list-numbers--regular",
236
+ task: "ph--list-checks--regular"
237
+ };
238
+ var createListGroupAction = (value) => createEditorActionGroup("list", {
239
+ variant: "toggleGroup",
240
+ selectCardinality: "single",
241
+ value
242
+ });
243
+ var createListActions = (value) => Object.entries(listStyles).map(([listStyle, icon]) => createEditorAction({
244
+ type: `list-${listStyle}`,
245
+ checked: value === listStyle
246
+ }, icon));
247
+ var createLists = (state) => {
248
+ const value = state.listStyle ?? "";
249
+ const listGroupAction = createListGroupAction(value);
250
+ const listActionsMap = createListActions(value);
251
+ return {
252
+ nodes: [
253
+ listGroupAction,
254
+ ...listActionsMap
255
+ ],
256
+ edges: [
257
+ {
258
+ source: "root",
259
+ target: "list"
260
+ },
261
+ ...listActionsMap.map(({ id }) => ({
262
+ source: listGroupAction.id,
263
+ target: id
264
+ }))
265
+ ]
266
+ };
267
+ };
268
+
269
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/viewMode.ts
270
+ var createViewModeGroupAction = (value) => createEditorActionGroup("viewMode", {
271
+ variant: "dropdownMenu",
272
+ applyActive: true,
273
+ selectCardinality: "single",
274
+ value
275
+ }, "ph--eye--regular");
276
+ var createViewModeActions = (value) => Object.entries({
277
+ preview: "ph--eye--regular",
278
+ source: "ph--pencil-simple--regular",
279
+ readonly: "ph--pencil-slash--regular"
280
+ }).map(([viewMode, icon]) => {
281
+ return createEditorAction({
282
+ type: "view-mode",
283
+ data: viewMode,
284
+ checked: viewMode === value
285
+ }, icon, [
286
+ `${viewMode} mode label`,
287
+ {
288
+ ns: translationKey
136
289
  }
137
- const changes2 = [];
138
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
139
- fromA,
140
- toA,
141
- fromB,
142
- toB,
143
- inserted: inserted.toString()
144
- })));
145
- return changes2;
146
- }).filter(Boolean);
147
- if (changes.length) {
148
- log.info("changes", {
149
- changes
150
- }, {
151
- F: __dxlog_file,
152
- L: 62,
153
- S: void 0,
154
- C: (f, a) => f(...a)
155
- });
156
- }
290
+ ], `view-mode--${viewMode}`);
291
+ });
292
+ var createViewMode = (state) => {
293
+ const value = state.viewMode ?? "source";
294
+ const viewModeGroupAction = createViewModeGroupAction(value);
295
+ const viewModeActions = createViewModeActions(value);
296
+ return {
297
+ nodes: [
298
+ viewModeGroupAction,
299
+ ...viewModeActions
300
+ ],
301
+ edges: [
302
+ {
303
+ source: "root",
304
+ target: "viewMode"
305
+ },
306
+ ...viewModeActions.map(({ id }) => ({
307
+ source: viewModeGroupAction.id,
308
+ target: id
309
+ }))
310
+ ]
311
+ };
157
312
  };
158
313
 
159
- // packages/ui/react-ui-editor/src/util/dom.ts
160
- var flattenRect = (rect, left) => {
161
- const x = left ? rect.left : rect.right;
314
+ // packages/ui/react-ui-editor/src/styles/stack-item-content-class-names.ts
315
+ import { mx } from "@dxos/react-ui-theme";
316
+ var stackItemContentEditorClassNames = (role) => mx("dx-focus-ring-inset data-[toolbar=disabled]:pbs-2 attention-surface", role === "article" ? "min-bs-0" : "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24");
317
+ var stackItemContentToolbarClassNames = (role) => mx("attention-surface is-full border-be !border-separator", role === "section" && "sticky block-start-0 z-[1] -mbe-px min-is-0");
318
+
319
+ // packages/ui/react-ui-editor/src/components/EditorToolbar/EditorToolbar.tsx
320
+ var createToolbar = ({ state, customActions, ...features }) => {
321
+ const nodes = [];
322
+ const edges = [];
323
+ if (features.headings ?? true) {
324
+ const headings2 = createHeadings(state);
325
+ nodes.push(...headings2.nodes);
326
+ edges.push(...headings2.edges);
327
+ }
328
+ if (features.formatting ?? true) {
329
+ const formatting = createFormatting(state);
330
+ nodes.push(...formatting.nodes);
331
+ edges.push(...formatting.edges);
332
+ }
333
+ if (features.lists ?? true) {
334
+ const lists = createLists(state);
335
+ nodes.push(...lists.nodes);
336
+ edges.push(...lists.edges);
337
+ }
338
+ if (features.blocks ?? true) {
339
+ const blocks = createBlocks(state);
340
+ nodes.push(...blocks.nodes);
341
+ edges.push(...blocks.edges);
342
+ }
343
+ if (customActions) {
344
+ const custom = customActions();
345
+ nodes.push(...custom.nodes);
346
+ edges.push(...custom.edges);
347
+ }
348
+ const editorToolbarGap = createGapSeparator();
349
+ nodes.push(...editorToolbarGap.nodes);
350
+ edges.push(...editorToolbarGap.edges);
351
+ if (features.comment ?? true) {
352
+ const comment = createComment(state);
353
+ nodes.push(...comment.nodes);
354
+ edges.push(...comment.edges);
355
+ }
356
+ if (features.search ?? true) {
357
+ nodes.push(editorToolbarSearch);
358
+ edges.push({
359
+ source: "root",
360
+ target: editorToolbarSearch.id
361
+ });
362
+ }
363
+ if (features.viewMode ?? true) {
364
+ const viewMode = createViewMode(state);
365
+ nodes.push(...viewMode.nodes);
366
+ edges.push(...viewMode.edges);
367
+ }
162
368
  return {
163
- left: x,
164
- right: x,
165
- top: rect.top,
166
- bottom: rect.bottom
369
+ nodes,
370
+ edges
167
371
  };
168
372
  };
169
- var scratchRange;
170
- var textRange = (node, from, to = from) => {
171
- const range = scratchRange || (scratchRange = document.createRange());
172
- range.setEnd(node, to);
173
- range.setStart(node, from);
174
- return range;
373
+ var useEditorToolbarActionGraph = ({ onAction, ...props }) => {
374
+ const menuCreator = useCallback(() => createToolbar(props), [
375
+ props
376
+ ]);
377
+ const { resolveGroupItems } = useMenuActions(menuCreator);
378
+ return {
379
+ resolveGroupItems,
380
+ onAction
381
+ };
175
382
  };
176
- var clientRectsFor = (dom) => {
177
- if (dom.nodeType === 3) {
178
- return textRange(dom, 0, dom.nodeValue.length).getClientRects();
179
- } else if (dom.nodeType === 1) {
180
- return dom.getClientRects();
181
- } else {
182
- return [];
183
- }
383
+ var EditorToolbar = ({ classNames, attendableId, role, ...props }) => {
384
+ const menuProps = useEditorToolbarActionGraph(props);
385
+ return /* @__PURE__ */ React.createElement("div", {
386
+ role: "none",
387
+ className: stackItemContentToolbarClassNames(role)
388
+ }, /* @__PURE__ */ React.createElement(ElevationProvider, {
389
+ elevation: role === "section" ? "positioned" : "base"
390
+ }, /* @__PURE__ */ React.createElement(MenuProvider, {
391
+ ...menuProps,
392
+ attendableId
393
+ }, /* @__PURE__ */ React.createElement(ToolbarMenu, {
394
+ classNames: [
395
+ textBlockWidth,
396
+ "!bg-transparent",
397
+ classNames
398
+ ]
399
+ }))));
184
400
  };
185
401
 
186
- // packages/ui/react-ui-editor/src/util/react.tsx
187
- import React from "react";
188
- import { createRoot } from "react-dom/client";
189
- import { ThemeProvider } from "@dxos/react-ui";
190
- import { defaultTx } from "@dxos/react-ui-theme";
191
- var createElement = (tag, options, children) => {
192
- const el = document.createElement(tag);
193
- if (options?.className) {
194
- el.className = options.className;
195
- }
196
- if (children) {
197
- el.append(...Array.isArray(children) ? children : [
198
- children
199
- ]);
402
+ // packages/ui/react-ui-editor/src/defaults.ts
403
+ import { EditorView } from "@codemirror/view";
404
+ import { mx as mx3 } from "@dxos/react-ui-theme";
405
+
406
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
407
+ import { mx as mx2 } from "@dxos/react-ui-theme";
408
+ var headings = {
409
+ 1: "text-4xl",
410
+ 2: "text-3xl",
411
+ 3: "text-2xl",
412
+ 4: "text-xl",
413
+ 5: "text-lg",
414
+ 6: ""
415
+ };
416
+ var theme = {
417
+ code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
418
+ codeMark: "font-mono text-primary-500",
419
+ mark: "opacity-50",
420
+ heading: (level) => {
421
+ return mx2(headings[level], "dark:text-primary-400");
200
422
  }
201
- return el;
202
423
  };
203
- var renderRoot = (root, node) => {
204
- createRoot(root).render(/* @__PURE__ */ React.createElement(ThemeProvider, {
205
- tx: defaultTx
206
- }, node));
207
- return root;
424
+
425
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
426
+ import get from "lodash.get";
427
+ import { tokens } from "@dxos/react-ui-theme";
428
+ var getToken = (path, defaultValue) => {
429
+ const value = get(tokens, path, defaultValue);
430
+ return value?.toString() ?? "";
208
431
  };
432
+ var fontBody = getToken("fontFamily.body");
433
+ var fontMono = getToken("fontFamily.mono");
209
434
 
210
- // packages/ui/react-ui-editor/src/extensions/annotations.ts
211
- var annotationMark = Decoration.mark({
212
- class: "cm-annotation"
213
- });
214
- var annotations = (options = {}) => {
215
- const match = (state) => {
216
- const annotations2 = [];
217
- const text = state.doc.toString();
218
- if (options.match) {
219
- const matches = text.matchAll(options.match);
220
- for (const match2 of matches) {
221
- const from = match2.index;
222
- const to = from + match2[0].length;
223
- const cursor = Cursor.getCursorFromRange(state, {
224
- from,
225
- to
226
- });
227
- annotations2.push({
228
- cursor
229
- });
230
- }
231
- }
232
- return annotations2;
233
- };
234
- const annotationsState = StateField.define({
235
- create: (state) => {
236
- return match(state);
237
- },
238
- update: (value, tr) => {
239
- if (!tr.changes.empty) {
240
- return match(tr.state);
241
- }
242
- return value;
435
+ // packages/ui/react-ui-editor/src/styles/theme.ts
436
+ var defaultTheme = {
437
+ "&": {},
438
+ "&.cm-focused": {
439
+ outline: "none"
440
+ },
441
+ /**
442
+ * Scroller
443
+ */
444
+ ".cm-scroller": {
445
+ overflowY: "auto"
446
+ },
447
+ /**
448
+ * Content
449
+ * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
450
+ */
451
+ ".cm-content": {
452
+ padding: "unset",
453
+ fontFamily: fontBody,
454
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
455
+ fontSize: "16px",
456
+ lineHeight: 1.5,
457
+ color: "unset"
458
+ },
459
+ /**
460
+ * Gutters
461
+ * NOTE: Gutters should have the same top margin as the content.
462
+ */
463
+ ".cm-gutters": {
464
+ borderRight: "none",
465
+ background: "transparent"
466
+ },
467
+ ".cm-gutter": {},
468
+ ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
469
+ minWidth: "40px",
470
+ alignContent: "center"
471
+ },
472
+ /**
473
+ * Height is set to match the corresponding line.
474
+ */
475
+ ".cm-gutterElement": {
476
+ alignItems: "center",
477
+ fontSize: "16px"
478
+ },
479
+ /**
480
+ * Line.
481
+ */
482
+ ".cm-line": {
483
+ paddingInline: 0
484
+ },
485
+ ".cm-activeLine": {
486
+ background: "var(--dx-cmActiveLine)"
487
+ },
488
+ /**
489
+ * Cursor (layer).
490
+ */
491
+ ".cm-cursor, .cm-dropCursor": {
492
+ borderLeft: "2px solid var(--dx-cmCursor)"
493
+ },
494
+ ".cm-placeholder": {
495
+ color: "var(--dx-subdued)"
496
+ },
497
+ /**
498
+ * Selection (layer).
499
+ */
500
+ ".cm-selectionBackground": {
501
+ background: "var(--dx-cmSelection)"
502
+ },
503
+ /**
504
+ * Search.
505
+ * NOTE: Matches comment.
506
+ */
507
+ ".cm-searchMatch": {
508
+ margin: "0 -3px",
509
+ padding: "3px",
510
+ borderRadius: "3px",
511
+ background: "var(--dx-cmHighlightSurface)",
512
+ color: "var(--dx-cmHighlight)"
513
+ },
514
+ ".cm-searchMatch-selected": {
515
+ textDecoration: "underline"
516
+ },
517
+ /**
518
+ * Link.
519
+ */
520
+ ".cm-link": {
521
+ textDecorationLine: "underline",
522
+ textDecorationThickness: "1px",
523
+ textUnderlineOffset: "2px",
524
+ borderRadius: ".125rem"
525
+ },
526
+ ".cm-link > span": {
527
+ color: "var(--dx-accentText)"
528
+ },
529
+ /**
530
+ * Tooltip.
531
+ */
532
+ ".cm-tooltip": {
533
+ background: "var(--dx-baseSurface)"
534
+ },
535
+ ".cm-tooltip-below": {},
536
+ /**
537
+ * Autocomplete.
538
+ * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
539
+ */
540
+ ".cm-tooltip.cm-tooltip-autocomplete": {
541
+ marginTop: "4px",
542
+ marginLeft: "-3px"
543
+ },
544
+ ".cm-tooltip.cm-tooltip-autocomplete > ul": {
545
+ maxHeight: "20em"
546
+ },
547
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
548
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
549
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
550
+ paddingLeft: "4px !important",
551
+ borderBottom: "none !important",
552
+ color: "var(--dx-accentText)"
553
+ },
554
+ ".cm-tooltip.cm-completionInfo": {
555
+ width: "360px !important",
556
+ margin: "-10px 1px 0 1px",
557
+ padding: "8px !important",
558
+ borderColor: "var(--dx-separator)"
559
+ },
560
+ ".cm-completionIcon": {
561
+ display: "none"
562
+ },
563
+ ".cm-completionLabel": {
564
+ fontFamily: fontBody
565
+ },
566
+ ".cm-completionMatchedText": {
567
+ textDecoration: "none !important",
568
+ opacity: 0.5
569
+ },
570
+ /**
571
+ * Panels
572
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
573
+ *
574
+ * Find/replace panel.
575
+ * <div class="cm-announced">...</div>
576
+ * <div class="cm-scroller">...</div>
577
+ * <div class="cm-panels cm-panels-bottom">
578
+ * <div class="cm-search cm-panel">
579
+ * <input class="cm-textfield" />
580
+ * <button class="cm-button">...</button>
581
+ * <label><input type="checkbox" />...</label>
582
+ * </div>
583
+ * </div
584
+ */
585
+ // TODO(burdon): Implement custom panel (with icon buttons).
586
+ ".cm-panels": {},
587
+ ".cm-panel": {
588
+ fontFamily: fontBody,
589
+ backgroundColor: "var(--surface-bg)"
590
+ },
591
+ ".cm-panel input, .cm-panel button, .cm-panel label": {
592
+ color: "var(--dx-subdued)",
593
+ fontFamily: fontBody,
594
+ fontSize: "14px",
595
+ all: "unset",
596
+ margin: "3px !important",
597
+ padding: "2px 6px !important",
598
+ outline: "1px solid transparent"
599
+ },
600
+ ".cm-panel input, .cm-panel button": {
601
+ backgroundColor: "var(--dx-input)"
602
+ },
603
+ ".cm-panel input:focus, .cm-panel button:focus": {
604
+ outline: "1px solid var(--dx-accentFocusIndicator)"
605
+ },
606
+ ".cm-panel label": {
607
+ display: "inline-flex",
608
+ alignItems: "center",
609
+ cursor: "pointer"
610
+ },
611
+ ".cm-panel input.cm-textfield": {},
612
+ ".cm-panel input[type=checkbox]": {
613
+ width: "8px",
614
+ height: "8px",
615
+ marginRight: "6px !important",
616
+ padding: "2px !important",
617
+ color: "var(--dx-accentFocusIndicator)"
618
+ },
619
+ ".cm-panel button": {
620
+ "&:hover": {
621
+ backgroundColor: "var(--dx-accentSurfaceHover) !important"
622
+ },
623
+ "&:active": {
624
+ backgroundColor: "var(--dx-accentSurfaceHover)"
243
625
  }
244
- });
245
- return [
246
- annotationsState,
247
- EditorView.decorations.compute([
248
- annotationsState
249
- ], (state) => {
250
- const annotations2 = state.field(annotationsState);
251
- const decorations = annotations2.map((annotation) => {
252
- const range = Cursor.getRangeFromCursor(state, annotation.cursor);
253
- return range && annotationMark.range(range.from, range.to);
254
- }).filter(isNotFalsy);
255
- return Decoration.set(decorations);
256
- }),
257
- styles
258
- ];
626
+ },
627
+ ".cm-panel.cm-search": {
628
+ padding: "4px",
629
+ borderTop: "1px solid var(--dx-separator)"
630
+ }
259
631
  };
260
- var styles = EditorView.theme({
261
- ".cm-annotation": {
262
- textDecoration: "underline",
263
- textDecorationStyle: "wavy",
264
- textDecorationColor: "var(--dx-error)"
632
+
633
+ // packages/ui/react-ui-editor/src/defaults.ts
634
+ var margin = "!mt-[1rem]";
635
+ var editorContent = mx3(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
636
+ var editorFullWidth = mx3(margin);
637
+ var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
638
+ var editorGutter = EditorView.theme({
639
+ // Match margin from content.
640
+ ".cm-gutters": {
641
+ marginTop: "16px",
642
+ paddingRight: "1rem"
643
+ }
644
+ });
645
+ var editorMonospace = EditorView.theme({
646
+ ".cm-content": {
647
+ fontFamily: fontMono
265
648
  }
266
649
  });
267
650
 
268
- // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
269
- import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
270
- import { markdownLanguage } from "@codemirror/lang-markdown";
271
- import { keymap } from "@codemirror/view";
272
- var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
273
- const extensions = [
274
- // https://codemirror.net/docs/ref/#view.keymap
275
- // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
276
- // TODO(burdon): Set custom keymap.
277
- keymap.of(completionKeymap),
278
- // https://codemirror.net/examples/autocompletion
279
- // https://codemirror.net/docs/ref/#autocomplete.autocompletion
280
- autocompletion({
281
- activateOnTyping,
282
- override,
283
- closeOnBlur: !debug,
284
- tooltipClass: () => "shadow rounded"
285
- })
286
- ];
287
- if (onSearch) {
288
- extensions.push(
289
- // TODO(burdon): Optional decoration via addToOptions
290
- markdownLanguage.data.of({
291
- autocomplete: (context) => {
292
- const match = context.matchBefore(/\w*/);
293
- if (!match || match.from === match.to && !context.explicit) {
294
- return null;
295
- }
296
- return {
651
+ // packages/ui/react-ui-editor/src/extensions/annotations.ts
652
+ import { StateField } from "@codemirror/state";
653
+ import { Decoration, EditorView as EditorView2 } from "@codemirror/view";
654
+ import { isNotFalsy } from "@dxos/util";
655
+
656
+ // packages/ui/react-ui-editor/src/util/facet.ts
657
+ import { Facet } from "@codemirror/state";
658
+ var singleValueFacet = (defaultValue) => Facet.define({
659
+ // Called immediately.
660
+ combine: (providers) => {
661
+ return providers[0] ?? defaultValue;
662
+ }
663
+ });
664
+
665
+ // packages/ui/react-ui-editor/src/util/cursor.ts
666
+ var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
667
+ var defaultCursorConverter = {
668
+ toCursor: (position) => position.toString(),
669
+ fromCursor: (cursor) => parseInt(cursor)
670
+ };
671
+ var Cursor = class _Cursor {
672
+ static {
673
+ this.converter = singleValueFacet(defaultCursorConverter);
674
+ }
675
+ static {
676
+ this.getCursorFromRange = (state, range) => {
677
+ const cursorConverter2 = state.facet(_Cursor.converter);
678
+ const from = cursorConverter2.toCursor(range.from);
679
+ const to = cursorConverter2.toCursor(range.to, -1);
680
+ return [
681
+ from,
682
+ to
683
+ ].join(":");
684
+ };
685
+ }
686
+ static {
687
+ this.getRangeFromCursor = (state, cursor) => {
688
+ const cursorConverter2 = state.facet(_Cursor.converter);
689
+ const parts = cursor.split(":");
690
+ const from = cursorConverter2.fromCursor(parts[0]);
691
+ const to = cursorConverter2.fromCursor(parts[1]);
692
+ return from !== void 0 && to !== void 0 ? {
693
+ from,
694
+ to
695
+ } : void 0;
696
+ };
697
+ }
698
+ };
699
+
700
+ // packages/ui/react-ui-editor/src/util/debug.ts
701
+ import { log } from "@dxos/log";
702
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
703
+ var wrapWithCatch = (fn) => {
704
+ return (...args) => {
705
+ try {
706
+ return fn(...args);
707
+ } catch (err) {
708
+ log.catch(err, void 0, {
709
+ F: __dxlog_file,
710
+ L: 15,
711
+ S: void 0,
712
+ C: (f, a) => f(...a)
713
+ });
714
+ }
715
+ };
716
+ };
717
+ var callbackWrapper = (fn) => (...args) => {
718
+ try {
719
+ return fn(...args);
720
+ } catch (err) {
721
+ log.catch(err, void 0, {
722
+ F: __dxlog_file,
723
+ L: 29,
724
+ S: void 0,
725
+ C: (f, a) => f(...a)
726
+ });
727
+ }
728
+ };
729
+ var debugDispatcher = (trs, view) => {
730
+ logChanges(trs);
731
+ view.update(trs);
732
+ };
733
+ var logChanges = (trs) => {
734
+ const changes = trs.flatMap((tr) => {
735
+ if (tr.changes.empty) {
736
+ return void 0;
737
+ }
738
+ const changes2 = [];
739
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
740
+ fromA,
741
+ toA,
742
+ fromB,
743
+ toB,
744
+ inserted: inserted.toString()
745
+ })));
746
+ return changes2;
747
+ }).filter(Boolean);
748
+ if (changes.length) {
749
+ log.info("changes", {
750
+ changes
751
+ }, {
752
+ F: __dxlog_file,
753
+ L: 62,
754
+ S: void 0,
755
+ C: (f, a) => f(...a)
756
+ });
757
+ }
758
+ };
759
+
760
+ // packages/ui/react-ui-editor/src/util/dom.ts
761
+ var flattenRect = (rect, left) => {
762
+ const x = left ? rect.left : rect.right;
763
+ return {
764
+ left: x,
765
+ right: x,
766
+ top: rect.top,
767
+ bottom: rect.bottom
768
+ };
769
+ };
770
+ var scratchRange;
771
+ var textRange = (node, from, to = from) => {
772
+ const range = scratchRange || (scratchRange = document.createRange());
773
+ range.setEnd(node, to);
774
+ range.setStart(node, from);
775
+ return range;
776
+ };
777
+ var clientRectsFor = (dom) => {
778
+ if (dom.nodeType === 3) {
779
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
780
+ } else if (dom.nodeType === 1) {
781
+ return dom.getClientRects();
782
+ } else {
783
+ return [];
784
+ }
785
+ };
786
+
787
+ // packages/ui/react-ui-editor/src/util/react.tsx
788
+ import React2 from "react";
789
+ import { createRoot } from "react-dom/client";
790
+ import { ThemeProvider } from "@dxos/react-ui";
791
+ import { defaultTx } from "@dxos/react-ui-theme";
792
+ var createElement = (tag, options, children) => {
793
+ const el = document.createElement(tag);
794
+ if (options?.className) {
795
+ el.className = options.className;
796
+ }
797
+ if (children) {
798
+ el.append(...Array.isArray(children) ? children : [
799
+ children
800
+ ]);
801
+ }
802
+ return el;
803
+ };
804
+ var renderRoot = (root, node) => {
805
+ createRoot(root).render(/* @__PURE__ */ React2.createElement(ThemeProvider, {
806
+ tx: defaultTx
807
+ }, node));
808
+ return root;
809
+ };
810
+
811
+ // packages/ui/react-ui-editor/src/extensions/annotations.ts
812
+ var annotationMark = Decoration.mark({
813
+ class: "cm-annotation"
814
+ });
815
+ var annotations = (options = {}) => {
816
+ const match = (state) => {
817
+ const annotations2 = [];
818
+ const text = state.doc.toString();
819
+ if (options.match) {
820
+ const matches = text.matchAll(options.match);
821
+ for (const match2 of matches) {
822
+ const from = match2.index;
823
+ const to = from + match2[0].length;
824
+ const cursor = Cursor.getCursorFromRange(state, {
825
+ from,
826
+ to
827
+ });
828
+ annotations2.push({
829
+ cursor
830
+ });
831
+ }
832
+ }
833
+ return annotations2;
834
+ };
835
+ const annotationsState = StateField.define({
836
+ create: (state) => {
837
+ return match(state);
838
+ },
839
+ update: (value, tr) => {
840
+ if (!tr.changes.empty) {
841
+ return match(tr.state);
842
+ }
843
+ return value;
844
+ }
845
+ });
846
+ return [
847
+ annotationsState,
848
+ EditorView2.decorations.compute([
849
+ annotationsState
850
+ ], (state) => {
851
+ const annotations2 = state.field(annotationsState);
852
+ const decorations = annotations2.map((annotation) => {
853
+ const range = Cursor.getRangeFromCursor(state, annotation.cursor);
854
+ return range && annotationMark.range(range.from, range.to);
855
+ }).filter(isNotFalsy);
856
+ return Decoration.set(decorations);
857
+ }),
858
+ styles
859
+ ];
860
+ };
861
+ var styles = EditorView2.theme({
862
+ ".cm-annotation": {
863
+ textDecoration: "underline",
864
+ textDecorationStyle: "wavy",
865
+ textDecorationColor: "var(--dx-error)"
866
+ }
867
+ });
868
+
869
+ // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
870
+ import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
871
+ import { markdownLanguage } from "@codemirror/lang-markdown";
872
+ import { keymap } from "@codemirror/view";
873
+ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
874
+ const extensions = [
875
+ // https://codemirror.net/docs/ref/#view.keymap
876
+ // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
877
+ // TODO(burdon): Set custom keymap.
878
+ keymap.of(completionKeymap),
879
+ // https://codemirror.net/examples/autocompletion
880
+ // https://codemirror.net/docs/ref/#autocomplete.autocompletion
881
+ autocompletion({
882
+ activateOnTyping,
883
+ override,
884
+ closeOnBlur: !debug,
885
+ tooltipClass: () => "shadow rounded"
886
+ })
887
+ ];
888
+ if (onSearch) {
889
+ extensions.push(
890
+ // TODO(burdon): Optional decoration via addToOptions
891
+ markdownLanguage.data.of({
892
+ autocomplete: (context) => {
893
+ const match = context.matchBefore(/\w*/);
894
+ if (!match || match.from === match.to && !context.explicit) {
895
+ return null;
896
+ }
897
+ return {
297
898
  from: match.from,
298
899
  options: onSearch(match.text.toLowerCase())
299
900
  };
@@ -306,7 +907,7 @@ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
306
907
 
307
908
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
308
909
  import { StateField as StateField2 } from "@codemirror/state";
309
- import { EditorView as EditorView2, ViewPlugin } from "@codemirror/view";
910
+ import { EditorView as EditorView3, ViewPlugin } from "@codemirror/view";
310
911
  import { next as A3 } from "@dxos/automerge/automerge";
311
912
 
312
913
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
@@ -590,7 +1191,7 @@ var automerge = (accessor) => {
590
1191
  }
591
1192
  }),
592
1193
  // Reconcile local updates.
593
- EditorView2.updateListener.of(({ view, changes }) => {
1194
+ EditorView3.updateListener.of(({ view, changes }) => {
594
1195
  if (!changes.empty) {
595
1196
  syncer.reconcile(view, true);
596
1197
  }
@@ -600,7 +1201,7 @@ var automerge = (accessor) => {
600
1201
 
601
1202
  // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
602
1203
  import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
603
- import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
1204
+ import { Decoration as Decoration2, EditorView as EditorView4, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
604
1205
  import { Event } from "@dxos/async";
605
1206
  import { Context } from "@dxos/context";
606
1207
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts";
@@ -774,7 +1375,7 @@ var RemoteCaretWidget = class extends WidgetType {
774
1375
  return true;
775
1376
  }
776
1377
  };
777
- var styles2 = EditorView3.theme({
1378
+ var styles2 = EditorView4.theme({
778
1379
  ".cm-collab-selection": {},
779
1380
  ".cm-collab-selectionLine": {
780
1381
  padding: 0,
@@ -940,7 +1541,7 @@ var SpaceAwarenessProvider = class {
940
1541
  };
941
1542
 
942
1543
  // packages/ui/react-ui-editor/src/extensions/blast.ts
943
- import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
1544
+ import { EditorView as EditorView5, keymap as keymap2 } from "@codemirror/view";
944
1545
  import defaultsDeep from "lodash.defaultsdeep";
945
1546
  import { invariant as invariant2 } from "@dxos/invariant";
946
1547
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
@@ -988,7 +1589,7 @@ var blast = (options = defaultOptions) => {
988
1589
  };
989
1590
  return [
990
1591
  // Cursor moved.
991
- EditorView4.updateListener.of((update2) => {
1592
+ EditorView5.updateListener.of((update2) => {
992
1593
  if (blaster?.node !== update2.view.scrollDOM) {
993
1594
  if (blaster) {
994
1595
  blaster.destroy();
@@ -1250,11 +1851,11 @@ var random = (min, max) => {
1250
1851
  };
1251
1852
 
1252
1853
  // packages/ui/react-ui-editor/src/extensions/command/command.ts
1253
- import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
1854
+ import { EditorView as EditorView7, keymap as keymap3 } from "@codemirror/view";
1254
1855
 
1255
1856
  // packages/ui/react-ui-editor/src/extensions/command/hint.ts
1256
1857
  import { RangeSetBuilder } from "@codemirror/state";
1257
- import { Decoration as Decoration3, EditorView as EditorView5, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1858
+ import { Decoration as Decoration3, EditorView as EditorView6, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1258
1859
 
1259
1860
  // packages/ui/react-ui-editor/src/extensions/command/state.ts
1260
1861
  import { StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
@@ -1420,7 +2021,7 @@ var hintViewPlugin = ({ onHint }) => ViewPlugin3.fromClass(class {
1420
2021
  }
1421
2022
  }, {
1422
2023
  provide: (plugin) => [
1423
- EditorView5.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration3.none)
2024
+ EditorView6.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration3.none)
1424
2025
  ]
1425
2026
  });
1426
2027
 
@@ -1431,7 +2032,7 @@ var command = (options) => {
1431
2032
  commandState,
1432
2033
  keymap3.of(commandKeyBindings),
1433
2034
  hintViewPlugin(options),
1434
- EditorView6.focusChangeEffect.of((_, focusing) => {
2035
+ EditorView7.focusChangeEffect.of((_, focusing) => {
1435
2036
  return focusing ? closeEffect.of(null) : null;
1436
2037
  })
1437
2038
  ];
@@ -1440,16 +2041,16 @@ var command = (options) => {
1440
2041
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1441
2042
  import { invertedEffects } from "@codemirror/commands";
1442
2043
  import { StateEffect as StateEffect3, StateField as StateField4 } from "@codemirror/state";
1443
- import { hoverTooltip, keymap as keymap5, Decoration as Decoration4, EditorView as EditorView8, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2044
+ import { hoverTooltip, keymap as keymap5, Decoration as Decoration4, EditorView as EditorView9, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1444
2045
  import sortBy from "lodash.sortby";
1445
- import { useEffect, useMemo, useState } from "react";
2046
+ import { useEffect, useMemo as useMemo2 } from "react";
1446
2047
  import { debounce as debounce2 } from "@dxos/async";
1447
2048
  import { log as log4 } from "@dxos/log";
1448
- import { nonNullable } from "@dxos/util";
2049
+ import { isNonNullable } from "@dxos/util";
1449
2050
 
1450
2051
  // packages/ui/react-ui-editor/src/extensions/selection.ts
1451
2052
  import { Transaction } from "@codemirror/state";
1452
- import { EditorView as EditorView7, keymap as keymap4 } from "@codemirror/view";
2053
+ import { EditorView as EditorView8, keymap as keymap4 } from "@codemirror/view";
1453
2054
  import { debounce } from "@dxos/async";
1454
2055
  import { invariant as invariant3 } from "@dxos/invariant";
1455
2056
  import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
@@ -1460,7 +2061,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1460
2061
  return {
1461
2062
  selection,
1462
2063
  scrollIntoView: !scrollTo,
1463
- effects: scrollTo ? EditorView7.scrollIntoView(scrollTo, {
2064
+ effects: scrollTo ? EditorView8.scrollIntoView(scrollTo, {
1464
2065
  yMargin: 96
1465
2066
  }) : void 0,
1466
2067
  annotations: Transaction.userEvent.of(stateRestoreAnnotation)
@@ -1502,7 +2103,7 @@ var selectionState = ({ getState, setState } = {}) => {
1502
2103
  // setStateDebounced(id, {});
1503
2104
  // },
1504
2105
  // }),
1505
- EditorView7.updateListener.of(({ view, transactions }) => {
2106
+ EditorView8.updateListener.of(({ view, transactions }) => {
1506
2107
  const id = view.state.facet(documentId);
1507
2108
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
1508
2109
  return;
@@ -1570,7 +2171,7 @@ var commentsState = StateField4.define({
1570
2171
  comment,
1571
2172
  range
1572
2173
  };
1573
- }).filter(nonNullable);
2174
+ }).filter(isNonNullable);
1574
2175
  return {
1575
2176
  ...value,
1576
2177
  comments: commentStates
@@ -1583,7 +2184,7 @@ var commentsState = StateField4.define({
1583
2184
  return value;
1584
2185
  }
1585
2186
  });
1586
- var styles3 = EditorView8.theme({
2187
+ var styles3 = EditorView9.theme({
1587
2188
  ".cm-comment, .cm-comment-current": {
1588
2189
  margin: "0 -3px",
1589
2190
  padding: "3px",
@@ -1603,7 +2204,7 @@ var createCommentMark = (id, isCurrent) => Decoration4.mark({
1603
2204
  "data-comment-id": id
1604
2205
  }
1605
2206
  });
1606
- var commentsDecorations = EditorView8.decorations.compute([
2207
+ var commentsDecorations = EditorView9.decorations.compute([
1607
2208
  commentsState
1608
2209
  ], (state) => {
1609
2210
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
@@ -1612,7 +2213,7 @@ var commentsDecorations = EditorView8.decorations.compute([
1612
2213
  if (!range) {
1613
2214
  log4.warn("Invalid range:", range, {
1614
2215
  F: __dxlog_file7,
1615
- L: 142,
2216
+ L: 144,
1616
2217
  S: void 0,
1617
2218
  C: (f, a) => f(...a)
1618
2219
  });
@@ -1622,11 +2223,11 @@ var commentsDecorations = EditorView8.decorations.compute([
1622
2223
  }
1623
2224
  const mark = createCommentMark(comment.comment.id, comment.comment.id === current);
1624
2225
  return mark.range(range.from, range.to);
1625
- }).filter(nonNullable);
2226
+ }).filter(isNonNullable);
1626
2227
  return Decoration4.set(decorations);
1627
2228
  });
1628
2229
  var commentClickedEffect = StateEffect3.define();
1629
- var handleCommentClick = EditorView8.domEventHandlers({
2230
+ var handleCommentClick = EditorView9.domEventHandlers({
1630
2231
  click: (event, view) => {
1631
2232
  let target = event.target;
1632
2233
  const editorRoot = view.dom;
@@ -1665,7 +2266,7 @@ var trackPastedComments = (onUpdate) => {
1665
2266
  }
1666
2267
  };
1667
2268
  return [
1668
- EditorView8.domEventHandlers({
2269
+ EditorView9.domEventHandlers({
1669
2270
  cut: handleTrack,
1670
2271
  copy: handleTrack
1671
2272
  }),
@@ -1687,7 +2288,7 @@ var trackPastedComments = (onUpdate) => {
1687
2288
  return effects;
1688
2289
  }),
1689
2290
  // Handle paste or the undo of comment deletion.
1690
- EditorView8.updateListener.of((update2) => {
2291
+ EditorView9.updateListener.of((update2) => {
1691
2292
  const restore = [];
1692
2293
  for (let i = 0; i < update2.transactions.length; i++) {
1693
2294
  const tr = update2.transactions[i];
@@ -1746,7 +2347,7 @@ var mapTrackedComment = (comment, changes) => ({
1746
2347
  var restoreCommentEffect = StateEffect3.define({
1747
2348
  map: mapTrackedComment
1748
2349
  });
1749
- var createComment = (view) => {
2350
+ var createComment2 = (view) => {
1750
2351
  const options = view.state.facet(optionsFacet);
1751
2352
  const { from, to } = view.state.selection.main;
1752
2353
  if (from === to) {
@@ -1791,7 +2392,7 @@ var comments = (options = {}) => {
1791
2392
  options.onCreate && keymap5.of([
1792
2393
  {
1793
2394
  key: shortcut,
1794
- run: callbackWrapper(createComment)
2395
+ run: callbackWrapper(createComment2)
1795
2396
  }
1796
2397
  ]),
1797
2398
  //
@@ -1827,7 +2428,7 @@ var comments = (options = {}) => {
1827
2428
  //
1828
2429
  // Track deleted ranges and update ranges for decorations.
1829
2430
  //
1830
- EditorView8.updateListener.of(({ view, state, changes }) => {
2431
+ EditorView9.updateListener.of(({ view, state, changes }) => {
1831
2432
  let mod = false;
1832
2433
  const { comments: comments2, ...value } = state.field(commentsState);
1833
2434
  changes.iterChanges((from, to, from2, to2) => {
@@ -1859,7 +2460,7 @@ var comments = (options = {}) => {
1859
2460
  //
1860
2461
  // Track selection/proximity.
1861
2462
  //
1862
- EditorView8.updateListener.of(({ view, state }) => {
2463
+ EditorView9.updateListener.of(({ view, state }) => {
1863
2464
  let min = Infinity;
1864
2465
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1865
2466
  const { head } = state.selection.main;
@@ -1893,7 +2494,7 @@ var comments = (options = {}) => {
1893
2494
  }
1894
2495
  }),
1895
2496
  options.onUpdate && trackPastedComments(options.onUpdate)
1896
- ].filter(nonNullable);
2497
+ ].filter(isNonNullable);
1897
2498
  };
1898
2499
  var scrollThreadIntoView = (view, id, center = true) => {
1899
2500
  const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
@@ -1913,7 +2514,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
1913
2514
  anchor: range.from
1914
2515
  } : void 0,
1915
2516
  effects: [
1916
- needsScroll ? EditorView8.scrollIntoView(range.from, center ? {
2517
+ needsScroll ? EditorView9.scrollIntoView(range.from, center ? {
1917
2518
  y: "center"
1918
2519
  } : void 0) : [],
1919
2520
  needsSelectionUpdate ? setSelection.of({
@@ -1925,414 +2526,177 @@ var scrollThreadIntoView = (view, id, center = true) => {
1925
2526
  }
1926
2527
  };
1927
2528
  var selectionOverlapsComment = (state) => {
1928
- const commentState = state.field(commentsState, false);
1929
- if (commentState === void 0) {
1930
- return false;
1931
- }
1932
- const { selection } = state;
1933
- for (const range of selection.ranges) {
1934
- if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
1935
- return true;
1936
- }
1937
- }
1938
- return false;
1939
- };
1940
- var hasActiveSelection = (state) => {
1941
- return state.selection.ranges.some((range) => !range.empty);
1942
- };
1943
- var ExternalCommentSync = class {
1944
- constructor(view, id, subscribe, getComments) {
1945
- this.destroy = () => {
1946
- this.unsubscribe();
1947
- };
1948
- const updateComments = () => {
1949
- const comments2 = getComments();
1950
- if (id === view.state.facet(documentId)) {
1951
- queueMicrotask(() => view.dispatch({
1952
- effects: setComments.of({
1953
- id,
1954
- comments: comments2
1955
- })
1956
- }));
1957
- }
1958
- };
1959
- this.unsubscribe = subscribe(updateComments);
1960
- }
1961
- };
1962
- var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin4.fromClass(class {
1963
- constructor(view) {
1964
- return new ExternalCommentSync(view, id, subscribe, getComments);
1965
- }
1966
- });
1967
- var useCommentState = () => {
1968
- const [state, setState] = useState({
1969
- comment: false,
1970
- selection: false
1971
- });
1972
- const observer = useMemo(() => EditorView8.updateListener.of((update2) => {
1973
- if (update2.docChanged || update2.selectionSet) {
1974
- setState({
1975
- comment: selectionOverlapsComment(update2.state),
1976
- selection: hasActiveSelection(update2.state)
1977
- });
1978
- }
1979
- }), []);
1980
- return [
1981
- state,
1982
- observer
1983
- ];
1984
- };
1985
- var useComments = (view, id, comments2) => {
1986
- useEffect(() => {
1987
- if (view) {
1988
- if (id === view.state.facet(documentId)) {
1989
- view.dispatch({
1990
- effects: setComments.of({
1991
- id,
1992
- comments: comments2 ?? []
1993
- })
1994
- });
1995
- }
1996
- }
1997
- });
1998
- };
1999
- var useCommentClickListener = (onCommentClick) => {
2000
- return useMemo(() => EditorView8.updateListener.of((update2) => {
2001
- update2.transactions.forEach((transaction) => {
2002
- transaction.effects.forEach((effect) => {
2003
- if (effect.is(commentClickedEffect)) {
2004
- onCommentClick(effect.value);
2005
- }
2006
- });
2007
- });
2008
- }), [
2009
- onCommentClick
2010
- ]);
2011
- };
2012
-
2013
- // packages/ui/react-ui-editor/src/extensions/debug.ts
2014
- import { syntaxTree } from "@codemirror/language";
2015
- import { StateField as StateField5 } from "@codemirror/state";
2016
- var debugNodeLogger = (log8 = console.log) => {
2017
- const logTokens = (state) => syntaxTree(state).iterate({
2018
- enter: (node) => log8(node.type)
2019
- });
2020
- return StateField5.define({
2021
- create: (state) => logTokens(state),
2022
- update: (_, tr) => logTokens(tr.state)
2023
- });
2024
- };
2025
-
2026
- // packages/ui/react-ui-editor/src/extensions/dnd.ts
2027
- import { dropCursor, EditorView as EditorView9 } from "@codemirror/view";
2028
- var styles4 = EditorView9.theme({
2029
- ".cm-dropCursor": {
2030
- borderLeft: "2px solid var(--dx-accentText)",
2031
- color: "var(--dx-accentText)",
2032
- padding: "0 4px"
2033
- },
2034
- ".cm-dropCursor:after": {
2035
- content: '"\u2190"'
2036
- }
2037
- });
2038
- var dropFile = (options = {}) => {
2039
- return [
2040
- styles4,
2041
- dropCursor(),
2042
- EditorView9.domEventHandlers({
2043
- drop: (event, view) => {
2044
- event.preventDefault();
2045
- const files = event.dataTransfer?.files;
2046
- const pos = view.posAtCoords(event);
2047
- if (files?.length && pos !== null) {
2048
- view.dispatch({
2049
- selection: {
2050
- anchor: pos
2051
- }
2052
- });
2053
- options.onDrop?.(view, {
2054
- files
2055
- });
2056
- }
2057
- }
2058
- })
2059
- ];
2060
- };
2061
-
2062
- // packages/ui/react-ui-editor/src/extensions/factories.ts
2063
- import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
2064
- import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
2065
- import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
2066
- import { searchKeymap } from "@codemirror/search";
2067
- import { EditorState } from "@codemirror/state";
2068
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2069
- import { EditorView as EditorView11, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap6, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2070
- import defaultsDeep2 from "lodash.defaultsdeep";
2071
- import merge from "lodash.merge";
2072
- import { generateName } from "@dxos/display-name";
2073
- import { log as log5 } from "@dxos/log";
2074
- import { hueTokens } from "@dxos/react-ui-theme";
2075
- import { hexToHue, isNotFalsy as isNotFalsy3 } from "@dxos/util";
2076
-
2077
- // packages/ui/react-ui-editor/src/extensions/focus.ts
2078
- import { StateEffect as StateEffect4, StateField as StateField6 } from "@codemirror/state";
2079
- import { EditorView as EditorView10 } from "@codemirror/view";
2080
- var focusEffect = StateEffect4.define();
2081
- var focusField = StateField6.define({
2082
- create: () => false,
2083
- update: (value, tr) => {
2084
- for (const effect of tr.effects) {
2085
- if (effect.is(focusEffect)) {
2086
- return effect.value;
2087
- }
2088
- }
2089
- return value;
2090
- }
2091
- });
2092
- var focus = [
2093
- focusField,
2094
- EditorView10.domEventHandlers({
2095
- focus: (event, view) => {
2096
- setTimeout(() => view.dispatch({
2097
- effects: focusEffect.of(true)
2098
- }));
2099
- },
2100
- blur: (event, view) => {
2101
- setTimeout(() => view.dispatch({
2102
- effects: focusEffect.of(false)
2103
- }));
2104
- }
2105
- })
2106
- ];
2107
-
2108
- // packages/ui/react-ui-editor/src/styles/markdown.ts
2109
- import { mx } from "@dxos/react-ui-theme";
2110
- var headings = {
2111
- 1: "text-4xl",
2112
- 2: "text-3xl",
2113
- 3: "text-2xl",
2114
- 4: "text-xl",
2115
- 5: "text-lg",
2116
- 6: "text-md"
2117
- };
2118
- var theme = {
2119
- code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
2120
- codeMark: "font-mono text-primary-500",
2121
- mark: "opacity-50",
2122
- heading: (level) => {
2123
- return mx(headings[level], "dark:text-primary-400");
2124
- }
2125
- };
2126
-
2127
- // packages/ui/react-ui-editor/src/styles/tokens.ts
2128
- import get from "lodash.get";
2129
- import { tokens } from "@dxos/react-ui-theme";
2130
- var getToken = (path, defaultValue) => {
2131
- const value = get(tokens, path, defaultValue);
2132
- return value?.toString() ?? "";
2133
- };
2134
- var fontBody = getToken("fontFamily.body");
2135
- var fontMono = getToken("fontFamily.mono");
2136
-
2137
- // packages/ui/react-ui-editor/src/styles/theme.ts
2138
- var defaultTheme = {
2139
- "&": {},
2140
- "&.cm-focused": {
2141
- outline: "none"
2142
- },
2143
- /**
2144
- * Scroller
2145
- */
2146
- ".cm-scroller": {
2147
- overflowY: "auto"
2148
- },
2149
- /**
2150
- * Content
2151
- * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
2152
- */
2153
- ".cm-content": {
2154
- padding: "unset",
2155
- fontFamily: fontBody,
2156
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2157
- fontSize: "16px",
2158
- lineHeight: 1.5,
2159
- color: "unset"
2160
- },
2161
- /**
2162
- * Gutters
2163
- * NOTE: Gutters should have the same top margin as the content.
2164
- * NOTE: They can't be transparent since the content needs to scroll below.
2165
- */
2166
- ".cm-gutters": {
2167
- background: "var(--surface-bg)",
2168
- borderRight: "none"
2169
- },
2170
- ".cm-gutter": {},
2171
- ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
2172
- minWidth: "40px",
2173
- alignContent: "center"
2174
- },
2175
- /**
2176
- * Height is set to match the corresponding line.
2177
- */
2178
- ".cm-gutterElement": {
2179
- alignItems: "center",
2180
- fontSize: "16px"
2181
- },
2182
- /**
2183
- * Line.
2184
- */
2185
- ".cm-line": {
2186
- paddingInline: 0
2187
- },
2188
- ".cm-activeLine": {
2189
- background: "var(--dx-cmActiveLine)"
2190
- },
2191
- /**
2192
- * Cursor (layer).
2193
- */
2194
- ".cm-cursor, .cm-dropCursor": {
2195
- borderLeft: "2px solid var(--dx-cmCursor)"
2196
- },
2197
- ".cm-placeholder": {
2198
- color: "var(--dx-subdued)"
2199
- },
2200
- /**
2201
- * Selection (layer).
2202
- */
2203
- ".cm-selectionBackground": {
2204
- background: "var(--dx-cmSelection)"
2205
- },
2206
- /**
2207
- * Search.
2208
- * NOTE: Matches comment.
2209
- */
2210
- ".cm-searchMatch": {
2211
- margin: "0 -3px",
2212
- padding: "3px",
2213
- borderRadius: "3px",
2214
- background: "var(--dx-cmHighlightSurface)",
2215
- color: "var(--dx-cmHighlight)"
2216
- },
2217
- ".cm-searchMatch-selected": {
2218
- textDecoration: "underline"
2219
- },
2220
- /**
2221
- * Link.
2222
- */
2223
- ".cm-link": {
2224
- textDecorationLine: "underline",
2225
- textDecorationThickness: "1px",
2226
- textUnderlineOffset: "2px",
2227
- borderRadius: ".125rem"
2228
- },
2229
- ".cm-link > span": {
2230
- color: "var(--dx-accentText)"
2231
- },
2232
- /**
2233
- * Tooltip.
2234
- */
2235
- ".cm-tooltip": {
2236
- background: "var(--dx-base)"
2237
- },
2238
- ".cm-tooltip-below": {},
2239
- /**
2240
- * Autocomplete.
2241
- * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
2242
- */
2243
- ".cm-tooltip.cm-tooltip-autocomplete": {
2244
- marginTop: "4px",
2245
- marginLeft: "-3px"
2246
- },
2247
- ".cm-tooltip.cm-tooltip-autocomplete > ul": {
2248
- maxHeight: "20em"
2249
- },
2250
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
2251
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
2252
- ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2253
- paddingLeft: "4px !important",
2254
- borderBottom: "none !important",
2255
- color: "var(--dx-accentText)"
2256
- },
2257
- ".cm-tooltip.cm-completionInfo": {
2258
- width: "360px !important",
2259
- margin: "-10px 1px 0 1px",
2260
- padding: "8px !important",
2261
- borderColor: "var(--dx-separator)"
2262
- },
2263
- ".cm-completionIcon": {
2264
- display: "none"
2265
- },
2266
- ".cm-completionLabel": {
2267
- fontFamily: fontBody
2268
- },
2269
- ".cm-completionMatchedText": {
2270
- textDecoration: "none !important",
2271
- opacity: 0.5
2272
- },
2273
- /**
2274
- * Panels
2275
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2276
- *
2277
- * Find/replace panel.
2278
- * <div class="cm-announced">...</div>
2279
- * <div class="cm-scroller">...</div>
2280
- * <div class="cm-panels cm-panels-bottom">
2281
- * <div class="cm-search cm-panel">
2282
- * <input class="cm-textfield" />
2283
- * <button class="cm-button">...</button>
2284
- * <label><input type="checkbox" />...</label>
2285
- * </div>
2286
- * </div
2287
- */
2288
- // TODO(burdon): Implement custom panel (with icon buttons).
2289
- ".cm-panels": {},
2290
- ".cm-panel": {
2291
- fontFamily: fontBody,
2292
- backgroundColor: "var(--surface-bg)"
2293
- },
2294
- ".cm-panel input, .cm-panel button, .cm-panel label": {
2295
- color: "var(--dx-subdued)",
2296
- fontFamily: fontBody,
2297
- fontSize: "14px",
2298
- all: "unset",
2299
- margin: "3px !important",
2300
- padding: "2px 6px !important",
2301
- outline: "1px solid transparent"
2302
- },
2303
- ".cm-panel input, .cm-panel button": {
2304
- backgroundColor: "var(--dx-input)"
2305
- },
2306
- ".cm-panel input:focus, .cm-panel button:focus": {
2307
- outline: "1px solid var(--dx-accentFocusIndicator)"
2308
- },
2309
- ".cm-panel label": {
2310
- display: "inline-flex",
2311
- alignItems: "center",
2312
- cursor: "pointer"
2313
- },
2314
- ".cm-panel input.cm-textfield": {},
2315
- ".cm-panel input[type=checkbox]": {
2316
- width: "8px",
2317
- height: "8px",
2318
- marginRight: "6px !important",
2319
- padding: "2px !important",
2320
- color: "var(--dx-accentFocusIndicator)"
2321
- },
2322
- ".cm-panel button": {
2323
- "&:hover": {
2324
- backgroundColor: "var(--dx-accentSurfaceHover) !important"
2325
- },
2326
- "&:active": {
2327
- backgroundColor: "var(--dx-accentSurfaceHover)"
2529
+ const commentState = state.field(commentsState, false);
2530
+ if (commentState === void 0) {
2531
+ return false;
2532
+ }
2533
+ const { selection } = state;
2534
+ for (const range of selection.ranges) {
2535
+ if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
2536
+ return true;
2537
+ }
2538
+ }
2539
+ return false;
2540
+ };
2541
+ var hasActiveSelection = (state) => {
2542
+ return state.selection.ranges.some((range) => !range.empty);
2543
+ };
2544
+ var ExternalCommentSync = class {
2545
+ constructor(view, id, subscribe, getComments) {
2546
+ this.destroy = () => {
2547
+ this.unsubscribe();
2548
+ };
2549
+ const updateComments = () => {
2550
+ const comments2 = getComments();
2551
+ if (id === view.state.facet(documentId)) {
2552
+ queueMicrotask(() => view.dispatch({
2553
+ effects: setComments.of({
2554
+ id,
2555
+ comments: comments2
2556
+ })
2557
+ }));
2558
+ }
2559
+ };
2560
+ this.unsubscribe = subscribe(updateComments);
2561
+ }
2562
+ };
2563
+ var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin4.fromClass(class {
2564
+ constructor(view) {
2565
+ return new ExternalCommentSync(view, id, subscribe, getComments);
2566
+ }
2567
+ });
2568
+ var useCommentState = (state) => {
2569
+ return useMemo2(() => EditorView9.updateListener.of((update2) => {
2570
+ if (update2.docChanged || update2.selectionSet) {
2571
+ state.comment = selectionOverlapsComment(update2.state);
2572
+ state.selection = hasActiveSelection(update2.state);
2573
+ }
2574
+ }), [
2575
+ state
2576
+ ]);
2577
+ };
2578
+ var useComments = (view, id, comments2) => {
2579
+ useEffect(() => {
2580
+ if (view) {
2581
+ if (id === view.state.facet(documentId)) {
2582
+ view.dispatch({
2583
+ effects: setComments.of({
2584
+ id,
2585
+ comments: comments2 ?? []
2586
+ })
2587
+ });
2588
+ }
2328
2589
  }
2590
+ });
2591
+ };
2592
+ var useCommentClickListener = (onCommentClick) => {
2593
+ return useMemo2(() => EditorView9.updateListener.of((update2) => {
2594
+ update2.transactions.forEach((transaction) => {
2595
+ transaction.effects.forEach((effect) => {
2596
+ if (effect.is(commentClickedEffect)) {
2597
+ onCommentClick(effect.value);
2598
+ }
2599
+ });
2600
+ });
2601
+ }), [
2602
+ onCommentClick
2603
+ ]);
2604
+ };
2605
+
2606
+ // packages/ui/react-ui-editor/src/extensions/debug.ts
2607
+ import { syntaxTree } from "@codemirror/language";
2608
+ import { StateField as StateField5 } from "@codemirror/state";
2609
+ var debugNodeLogger = (log8 = console.log) => {
2610
+ const logTokens = (state) => syntaxTree(state).iterate({
2611
+ enter: (node) => log8(node.type)
2612
+ });
2613
+ return StateField5.define({
2614
+ create: (state) => logTokens(state),
2615
+ update: (_, tr) => logTokens(tr.state)
2616
+ });
2617
+ };
2618
+
2619
+ // packages/ui/react-ui-editor/src/extensions/dnd.ts
2620
+ import { dropCursor, EditorView as EditorView10 } from "@codemirror/view";
2621
+ var styles4 = EditorView10.theme({
2622
+ ".cm-dropCursor": {
2623
+ borderLeft: "2px solid var(--dx-accentText)",
2624
+ color: "var(--dx-accentText)",
2625
+ padding: "0 4px"
2329
2626
  },
2330
- ".cm-panel.cm-search": {
2331
- padding: "4px",
2332
- borderTop: "1px solid var(--dx-separator)"
2627
+ ".cm-dropCursor:after": {
2628
+ content: '"\u2190"'
2333
2629
  }
2630
+ });
2631
+ var dropFile = (options = {}) => {
2632
+ return [
2633
+ styles4,
2634
+ dropCursor(),
2635
+ EditorView10.domEventHandlers({
2636
+ drop: (event, view) => {
2637
+ event.preventDefault();
2638
+ const files = event.dataTransfer?.files;
2639
+ const pos = view.posAtCoords(event);
2640
+ if (files?.length && pos !== null) {
2641
+ view.dispatch({
2642
+ selection: {
2643
+ anchor: pos
2644
+ }
2645
+ });
2646
+ options.onDrop?.(view, {
2647
+ files
2648
+ });
2649
+ }
2650
+ }
2651
+ })
2652
+ ];
2334
2653
  };
2335
2654
 
2655
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
2656
+ import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
2657
+ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
2658
+ import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
2659
+ import { searchKeymap } from "@codemirror/search";
2660
+ import { EditorState } from "@codemirror/state";
2661
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2662
+ import { EditorView as EditorView12, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap6, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2663
+ import defaultsDeep2 from "lodash.defaultsdeep";
2664
+ import merge from "lodash.merge";
2665
+ import { generateName } from "@dxos/display-name";
2666
+ import { log as log5 } from "@dxos/log";
2667
+ import { hexToHue, isNotFalsy as isNotFalsy3 } from "@dxos/util";
2668
+
2669
+ // packages/ui/react-ui-editor/src/extensions/focus.ts
2670
+ import { StateEffect as StateEffect4, StateField as StateField6 } from "@codemirror/state";
2671
+ import { EditorView as EditorView11 } from "@codemirror/view";
2672
+ var focusEffect = StateEffect4.define();
2673
+ var focusField = StateField6.define({
2674
+ create: () => false,
2675
+ update: (value, tr) => {
2676
+ for (const effect of tr.effects) {
2677
+ if (effect.is(focusEffect)) {
2678
+ return effect.value;
2679
+ }
2680
+ }
2681
+ return value;
2682
+ }
2683
+ });
2684
+ var focus = [
2685
+ focusField,
2686
+ EditorView11.domEventHandlers({
2687
+ focus: (event, view) => {
2688
+ setTimeout(() => view.dispatch({
2689
+ effects: focusEffect.of(true)
2690
+ }));
2691
+ },
2692
+ blur: (event, view) => {
2693
+ setTimeout(() => view.dispatch({
2694
+ effects: focusEffect.of(false)
2695
+ }));
2696
+ }
2697
+ })
2698
+ ];
2699
+
2336
2700
  // packages/ui/react-ui-editor/src/extensions/factories.ts
2337
2701
  var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2338
2702
  var preventNewline = EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
@@ -2358,7 +2722,7 @@ var createBasicExtensions = (_props) => {
2358
2722
  const props = defaultsDeep2({}, _props, defaultBasicOptions);
2359
2723
  return [
2360
2724
  // NOTE: Doesn't catch errors in keymap functions.
2361
- EditorView11.exceptionSink.of((err) => {
2725
+ EditorView12.exceptionSink.of((err) => {
2362
2726
  log5.catch(err, void 0, {
2363
2727
  F: __dxlog_file8,
2364
2728
  L: 96,
@@ -2377,11 +2741,11 @@ var createBasicExtensions = (_props) => {
2377
2741
  props.highlightActiveLine && highlightActiveLine(),
2378
2742
  props.history && history(),
2379
2743
  props.lineNumbers && lineNumbers(),
2380
- props.lineWrapping && EditorView11.lineWrapping,
2744
+ props.lineWrapping && EditorView12.lineWrapping,
2381
2745
  props.placeholder && placeholder(props.placeholder),
2382
2746
  props.readonly && [
2383
2747
  EditorState.readOnly.of(true),
2384
- EditorView11.editable.of(false)
2748
+ EditorView12.editable.of(false)
2385
2749
  ],
2386
2750
  props.scrollPastEnd && scrollPastEnd(),
2387
2751
  props.tabSize && EditorState.tabSize.of(props.tabSize),
@@ -2398,7 +2762,14 @@ var createBasicExtensions = (_props) => {
2398
2762
  // https://codemirror.net/docs/ref/#commands.historyKeymap
2399
2763
  ...props.history ? historyKeymap : [],
2400
2764
  // https://codemirror.net/docs/ref/#search.searchKeymap
2401
- ...props.search ? searchKeymap : []
2765
+ ...props.search ? searchKeymap : [],
2766
+ // Disable bindings that conflict with system shortcuts.
2767
+ // TODO(burdon): Catalog global shortcuts.
2768
+ {
2769
+ key: "Mod-Shift-k",
2770
+ preventDefault: true,
2771
+ run: () => true
2772
+ }
2402
2773
  ].filter(isNotFalsy3))
2403
2774
  ].filter(isNotFalsy3);
2404
2775
  };
@@ -2410,14 +2781,14 @@ var defaultThemeSlots = {
2410
2781
  var createThemeExtensions = ({ themeMode, styles: styles5, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2411
2782
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2412
2783
  return [
2413
- EditorView11.darkTheme.of(themeMode === "dark"),
2414
- EditorView11.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2784
+ EditorView12.darkTheme.of(themeMode === "dark"),
2785
+ EditorView12.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2415
2786
  // https://github.com/codemirror/theme-one-dark
2416
2787
  _syntaxHighlighting && (themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
2417
- slots.editor?.className && EditorView11.editorAttributes.of({
2788
+ slots.editor?.className && EditorView12.editorAttributes.of({
2418
2789
  class: slots.editor.className
2419
2790
  }),
2420
- slots.content?.className && EditorView11.contentAttributes.of({
2791
+ slots.content?.className && EditorView12.contentAttributes.of({
2421
2792
  class: slots.content.className
2422
2793
  })
2423
2794
  ].filter(isNotFalsy3);
@@ -2429,15 +2800,15 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2429
2800
  }
2430
2801
  if (space && identity) {
2431
2802
  const peerId = identity?.identityKey.toHex();
2432
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
2803
+ const hue = identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0");
2433
2804
  extensions.push(awareness(new SpaceAwarenessProvider({
2434
2805
  space,
2435
2806
  channel: `awareness.${id}`,
2436
2807
  peerId: identity.identityKey.toHex(),
2437
2808
  info: {
2438
2809
  displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
2439
- darkColor: cursorDarkValue,
2440
- lightColor: cursorLightValue
2810
+ darkColor: `var(--dx-${hue}Cursor)`,
2811
+ lightColor: `var(--dx-${hue}Cursor)`
2441
2812
  }
2442
2813
  })));
2443
2814
  }
@@ -2446,8 +2817,8 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2446
2817
 
2447
2818
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2448
2819
  import { codeFolding, foldGutter } from "@codemirror/language";
2449
- import { EditorView as EditorView12 } from "@codemirror/view";
2450
- import React2 from "react";
2820
+ import { EditorView as EditorView13 } from "@codemirror/view";
2821
+ import React3 from "react";
2451
2822
  import { Icon } from "@dxos/react-ui";
2452
2823
  var folding = (_props = {}) => [
2453
2824
  codeFolding({
@@ -2460,7 +2831,7 @@ var folding = (_props = {}) => [
2460
2831
  const el = createElement("div", {
2461
2832
  className: "flex h-full items-center"
2462
2833
  });
2463
- return renderRoot(el, /* @__PURE__ */ React2.createElement(Icon, {
2834
+ return renderRoot(el, /* @__PURE__ */ React3.createElement(Icon, {
2464
2835
  icon: "ph--caret-right--regular",
2465
2836
  size: 3,
2466
2837
  classNames: [
@@ -2470,7 +2841,7 @@ var folding = (_props = {}) => [
2470
2841
  }));
2471
2842
  }
2472
2843
  }),
2473
- EditorView12.theme({
2844
+ EditorView13.theme({
2474
2845
  ".cm-foldGutter": {
2475
2846
  opacity: 0.3,
2476
2847
  transition: "opacity 0.3s",
@@ -2483,14 +2854,14 @@ var folding = (_props = {}) => [
2483
2854
  ];
2484
2855
 
2485
2856
  // packages/ui/react-ui-editor/src/extensions/listener.ts
2486
- import { EditorView as EditorView13 } from "@codemirror/view";
2857
+ import { EditorView as EditorView14 } from "@codemirror/view";
2487
2858
  var listener = ({ onFocus, onChange }) => {
2488
2859
  const extensions = [];
2489
- onFocus && extensions.push(EditorView13.focusChangeEffect.of((_, focusing) => {
2860
+ onFocus && extensions.push(EditorView14.focusChangeEffect.of((_, focusing) => {
2490
2861
  onFocus(focusing);
2491
2862
  return null;
2492
2863
  }));
2493
- onChange && extensions.push(EditorView13.updateListener.of((update2) => {
2864
+ onChange && extensions.push(EditorView14.updateListener.of((update2) => {
2494
2865
  onChange(update2.state.doc.toString(), update2.state.facet(documentId));
2495
2866
  }));
2496
2867
  return extensions;
@@ -2500,8 +2871,8 @@ var listener = ({ onFocus, onChange }) => {
2500
2871
  import { snippet } from "@codemirror/autocomplete";
2501
2872
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2502
2873
  import { EditorSelection } from "@codemirror/state";
2503
- import { EditorView as EditorView14, keymap as keymap7 } from "@codemirror/view";
2504
- import { useMemo as useMemo2, useState as useState2 } from "react";
2874
+ import { EditorView as EditorView15, keymap as keymap7 } from "@codemirror/view";
2875
+ import { useMemo as useMemo3 } from "react";
2505
2876
  var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2506
2877
  var Inline;
2507
2878
  (function(Inline2) {
@@ -3588,65 +3959,56 @@ var getFormatting = (state) => {
3588
3959
  listStyle: listStyle || null
3589
3960
  };
3590
3961
  };
3591
- var useFormattingState = () => {
3592
- const [state, setState] = useState2();
3593
- const observer = useMemo2(() => EditorView14.updateListener.of((update2) => {
3962
+ var useFormattingState = (state) => {
3963
+ return useMemo3(() => EditorView15.updateListener.of((update2) => {
3594
3964
  if (update2.docChanged || update2.selectionSet) {
3595
- setState((prevState) => {
3596
- const newState = getFormatting(update2.state);
3597
- if (!prevState || !formattingEquals(prevState, newState)) {
3598
- return newState;
3599
- }
3600
- return prevState;
3965
+ Object.entries(getFormatting(update2.state)).forEach(([key, active]) => {
3966
+ state[key] = active;
3601
3967
  });
3602
3968
  }
3603
3969
  }), []);
3604
- return [
3605
- state,
3606
- observer
3607
- ];
3608
3970
  };
3609
3971
 
3610
- // packages/ui/react-ui-editor/src/extensions/markdown/action.ts
3611
- var processAction = (view, action) => {
3972
+ // packages/ui/react-ui-editor/src/extensions/markdown/editorAction.ts
3973
+ var processEditorPayload = (view, { type, data }) => {
3612
3974
  let inlineType, listType;
3613
- switch (action.type) {
3975
+ switch (type) {
3614
3976
  case "heading":
3615
- setHeading(parseInt(action.data))(view);
3977
+ setHeading(parseInt(data))(view);
3616
3978
  break;
3617
3979
  case "strong":
3618
3980
  case "emphasis":
3619
3981
  case "strikethrough":
3620
3982
  case "code":
3621
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3622
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3983
+ inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3984
+ (typeof data === "boolean" ? setStyle(inlineType, data) : toggleStyle(inlineType))(view);
3623
3985
  break;
3624
3986
  case "list-ordered":
3625
3987
  case "list-bullet":
3626
3988
  case "list-task":
3627
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3628
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3989
+ listType = type === "list-ordered" ? List.Ordered : type === "list-bullet" ? List.Bullet : List.Task;
3990
+ (data === false ? removeList(listType) : data === true ? addList(listType) : toggleList(listType))(view);
3629
3991
  break;
3630
3992
  case "blockquote":
3631
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3993
+ (data === false ? removeBlockquote : data === true ? addBlockquote : toggleBlockquote)(view);
3632
3994
  break;
3633
3995
  case "codeblock":
3634
- (action.data === false ? removeCodeblock : addCodeblock)(view);
3996
+ (data === false ? removeCodeblock : addCodeblock)(view);
3635
3997
  break;
3636
3998
  case "table":
3637
3999
  insertTable(view);
3638
4000
  break;
3639
4001
  case "link":
3640
- (action.data === false ? removeLink : addLink())(view);
4002
+ (data === false ? removeLink : addLink())(view);
3641
4003
  break;
3642
4004
  case "image":
3643
4005
  addLink({
3644
- url: action.data,
4006
+ url: data,
3645
4007
  image: true
3646
4008
  })(view);
3647
4009
  break;
3648
4010
  case "comment":
3649
- createComment(view);
4011
+ createComment2(view);
3650
4012
  break;
3651
4013
  }
3652
4014
  requestAnimationFrame(() => {
@@ -3910,9 +4272,9 @@ var convertTreeToJson = (state) => {
3910
4272
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3911
4273
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3912
4274
  import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect5 } from "@codemirror/state";
3913
- import { EditorView as EditorView18, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
4275
+ import { EditorView as EditorView19, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
3914
4276
  import { invariant as invariant4 } from "@dxos/invariant";
3915
- import { mx as mx2 } from "@dxos/react-ui-theme";
4277
+ import { mx as mx4 } from "@dxos/react-ui-theme";
3916
4278
 
3917
4279
  // packages/ui/react-ui-editor/src/extensions/markdown/changes.ts
3918
4280
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
@@ -4061,7 +4423,7 @@ var getValidUrl = (str) => {
4061
4423
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
4062
4424
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4063
4425
  import { StateField as StateField8 } from "@codemirror/state";
4064
- import { Decoration as Decoration5, EditorView as EditorView15, WidgetType as WidgetType3 } from "@codemirror/view";
4426
+ import { Decoration as Decoration5, EditorView as EditorView16, WidgetType as WidgetType3 } from "@codemirror/view";
4065
4427
  var image = (_options = {}) => {
4066
4428
  return [
4067
4429
  StateField8.define({
@@ -4089,7 +4451,7 @@ var image = (_options = {}) => {
4089
4451
  add: buildDecorations(from, to, tr.state)
4090
4452
  });
4091
4453
  },
4092
- provide: (field) => EditorView15.decorations.from(field)
4454
+ provide: (field) => EditorView16.decorations.from(field)
4093
4455
  })
4094
4456
  ];
4095
4457
  };
@@ -4149,10 +4511,10 @@ var ImageWidget = class extends WidgetType3 {
4149
4511
  };
4150
4512
 
4151
4513
  // packages/ui/react-ui-editor/src/extensions/markdown/styles.ts
4152
- import { EditorView as EditorView16 } from "@codemirror/view";
4514
+ import { EditorView as EditorView17 } from "@codemirror/view";
4153
4515
  var bulletListIndentationWidth = 24;
4154
4516
  var orderedListIndentationWidth = 36;
4155
- var formattingStyles = EditorView16.theme({
4517
+ var formattingStyles = EditorView17.theme({
4156
4518
  /**
4157
4519
  * Horizontal rule.
4158
4520
  */
@@ -4246,18 +4608,39 @@ var formattingStyles = EditorView16.theme({
4246
4608
  height: "auto",
4247
4609
  borderTop: "0.5rem solid transparent",
4248
4610
  borderBottom: "0.5rem solid transparent"
4611
+ },
4612
+ ".cm-image-with-loader": {
4613
+ display: "block",
4614
+ opacity: "0",
4615
+ transitionDuration: "350ms",
4616
+ transitionProperty: "opacity"
4617
+ },
4618
+ ".cm-image-with-loader.cm-loaded-image": {
4619
+ opacity: "1"
4620
+ },
4621
+ ".cm-image-wrapper": {
4622
+ "grid-template-columns": "1fr",
4623
+ display: "grid",
4624
+ margin: "0.5rem 0",
4625
+ overflow: "hidden",
4626
+ transitionDuration: "350ms",
4627
+ transitionProperty: "height",
4628
+ "& > *": {
4629
+ "grid-row-start": 1,
4630
+ "grid-column-start": 1
4631
+ }
4249
4632
  }
4250
4633
  });
4251
4634
 
4252
4635
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4253
4636
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4254
4637
  import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField9 } from "@codemirror/state";
4255
- import { Decoration as Decoration6, EditorView as EditorView17, WidgetType as WidgetType4 } from "@codemirror/view";
4638
+ import { Decoration as Decoration6, EditorView as EditorView18, WidgetType as WidgetType4 } from "@codemirror/view";
4256
4639
  var table = (options = {}) => {
4257
4640
  return StateField9.define({
4258
4641
  create: (state) => update(state, options),
4259
4642
  update: (_, tr) => update(tr.state, options),
4260
- provide: (field) => EditorView17.decorations.from(field)
4643
+ provide: (field) => EditorView18.decorations.from(field)
4261
4644
  });
4262
4645
  };
4263
4646
  var update = (state, _options) => {
@@ -4389,7 +4772,7 @@ var CheckboxWidget = class extends WidgetType5 {
4389
4772
  }
4390
4773
  toDOM(view) {
4391
4774
  const input = document.createElement("input");
4392
- input.className = "cm-task-checkbox ch-checkbox";
4775
+ input.className = "cm-task-checkbox dx-checkbox";
4393
4776
  input.type = "checkbox";
4394
4777
  input.tabIndex = -1;
4395
4778
  input.checked = this._checked;
@@ -4441,16 +4824,16 @@ var TextWidget = class extends WidgetType5 {
4441
4824
  };
4442
4825
  var hide = Decoration7.replace({});
4443
4826
  var blockQuote = Decoration7.line({
4444
- class: mx2("cm-blockquote")
4827
+ class: mx4("cm-blockquote")
4445
4828
  });
4446
4829
  var fencedCodeLine = Decoration7.line({
4447
- class: mx2("cm-code cm-codeblock-line")
4830
+ class: mx4("cm-code cm-codeblock-line")
4448
4831
  });
4449
4832
  var fencedCodeLineFirst = Decoration7.line({
4450
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
4833
+ class: mx4("cm-code cm-codeblock-line", "cm-codeblock-first")
4451
4834
  });
4452
4835
  var fencedCodeLineLast = Decoration7.line({
4453
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
4836
+ class: mx4("cm-code cm-codeblock-line", "cm-codeblock-last")
4454
4837
  });
4455
4838
  var commentBlockLine = fencedCodeLine;
4456
4839
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -4791,9 +5174,9 @@ var decorateMarkdown = (options = {}) => {
4791
5174
  }
4792
5175
  }, {
4793
5176
  provide: (plugin) => [
4794
- EditorView18.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4795
- EditorView18.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4796
- EditorView18.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
5177
+ EditorView19.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
5178
+ EditorView19.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
5179
+ EditorView19.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
4797
5180
  ]
4798
5181
  }),
4799
5182
  image(),
@@ -4980,428 +5363,29 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4980
5363
  ];
4981
5364
  };
4982
5365
 
4983
- // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4984
- var iconStyles = getSize(5);
4985
- var buttonStyles = "min-bs-0 p-1";
4986
- var tooltipProps = {
4987
- side: "top",
4988
- classNames: "z-10"
4989
- };
4990
- var ToolbarSeparator = () => /* @__PURE__ */ React3.createElement("div", {
4991
- role: "separator",
4992
- className: "grow"
4993
- });
4994
- var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
4995
- var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4996
- return /* @__PURE__ */ React3.createElement(ToolbarContextProvider, {
4997
- onAction,
4998
- state
4999
- }, /* @__PURE__ */ React3.createElement(ElevationProvider, {
5000
- elevation: "positioned"
5001
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
5002
- classNames: [
5003
- "p-1 is-full shrink-0 overflow-x-auto overflow-y-hidden",
5004
- classNames
5005
- ],
5006
- style: {
5007
- contain: "layout"
5008
- }
5009
- }, children)));
5010
- };
5011
- var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
5012
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
5013
- asChild: true
5014
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, {
5015
- variant: "ghost",
5016
- ...props,
5017
- classNames: buttonStyles
5018
- }, /* @__PURE__ */ React3.createElement(Icon2, {
5019
- className: iconStyles
5020
- }), /* @__PURE__ */ React3.createElement("span", {
5021
- className: "sr-only"
5022
- }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5023
- };
5024
- var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
5025
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
5026
- asChild: true
5027
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
5028
- variant: "ghost",
5029
- ...props,
5030
- classNames: buttonStyles
5031
- }, /* @__PURE__ */ React3.createElement(Icon2, {
5032
- className: iconStyles
5033
- }), /* @__PURE__ */ React3.createElement("span", {
5034
- className: "sr-only"
5035
- }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5036
- };
5037
- var HeadingIcons = {
5038
- "0": Paragraph,
5039
- "1": TextHOne,
5040
- "2": TextHTwo,
5041
- "3": TextHThree,
5042
- "4": TextHFour,
5043
- "5": TextHFive,
5044
- "6": TextHSix
5045
- };
5046
- var MarkdownHeading = () => {
5047
- const { t } = useTranslation(translationKey);
5048
- const { onAction, state } = useToolbarContext("MarkdownFormatting");
5049
- const blockType = state ? state.blockType : "paragraph";
5050
- const header = blockType && /heading(\d)/.exec(blockType);
5051
- const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
5052
- const HeadingIcon = HeadingIcons[value ?? "0"];
5053
- const suppressNextTooltip = useRef(false);
5054
- const [tooltipOpen, setTooltipOpen] = useState3(false);
5055
- const [selectOpen, setSelectOpen] = useState3(false);
5056
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
5057
- open: tooltipOpen,
5058
- onOpenChange: (nextOpen) => {
5059
- if (nextOpen && suppressNextTooltip.current) {
5060
- suppressNextTooltip.current = false;
5061
- return setTooltipOpen(false);
5062
- } else {
5063
- return setTooltipOpen(nextOpen);
5064
- }
5065
- }
5066
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
5067
- open: selectOpen,
5068
- onOpenChange: (nextOpen) => {
5069
- if (!nextOpen) {
5070
- suppressNextTooltip.current = true;
5071
- }
5072
- return setSelectOpen(nextOpen);
5073
- }
5074
- }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
5075
- asChild: true
5076
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
5077
- asChild: true
5078
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
5079
- asChild: true
5080
- }, /* @__PURE__ */ React3.createElement(Button, {
5081
- variant: "ghost",
5082
- classNames: buttonStyles,
5083
- disabled: value === null
5084
- }, /* @__PURE__ */ React3.createElement("span", {
5085
- className: "sr-only"
5086
- }, t("heading label")), /* @__PURE__ */ React3.createElement(HeadingIcon, {
5087
- className: iconStyles
5088
- }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
5089
- classNames: "is-min md:is-min",
5090
- onCloseAutoFocus: (e) => e.preventDefault()
5091
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, Object.keys(HeadingIcons).map((level) => {
5092
- const Icon2 = HeadingIcons[level];
5093
- return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5094
- key: level,
5095
- checked: value === level,
5096
- onClick: () => onAction?.({
5097
- type: "heading",
5098
- data: level
5099
- })
5100
- }, /* @__PURE__ */ React3.createElement("span", {
5101
- className: "sr-only"
5102
- }, t("heading level label", {
5103
- count: parseInt(level)
5104
- })), /* @__PURE__ */ React3.createElement(Icon2, {
5105
- className: iconStyles
5106
- }), /* @__PURE__ */ React3.createElement(DropdownMenu.ItemIndicator, null, /* @__PURE__ */ React3.createElement(Check, null)));
5107
- })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5108
- };
5109
- var markdownStyles = [
5110
- {
5111
- type: "strong",
5112
- Icon: TextB,
5113
- getState: (state) => !!state?.strong
5114
- },
5115
- {
5116
- type: "emphasis",
5117
- Icon: TextItalic,
5118
- getState: (state) => !!state?.emphasis
5119
- },
5120
- {
5121
- type: "strikethrough",
5122
- Icon: TextStrikethrough,
5123
- getState: (state) => !!state?.strikethrough
5124
- },
5125
- {
5126
- type: "code",
5127
- Icon: Code,
5128
- getState: (state) => !!state?.code
5129
- },
5130
- {
5131
- type: "link",
5132
- Icon: Link,
5133
- getState: (state) => !!state?.link
5134
- }
5135
- ];
5136
- var MarkdownStyles = () => {
5137
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5138
- const { t } = useTranslation(translationKey);
5139
- return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5140
- type: "multiple",
5141
- value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
5142
- }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5143
- key: type,
5144
- value: type,
5145
- Icon: Icon2,
5146
- disabled: state?.blockType === "codeblock",
5147
- onClick: state ? () => onAction?.({
5148
- type,
5149
- data: !getState(state)
5150
- }) : void 0
5151
- }, t(`${type} label`))));
5152
- };
5153
- var markdownLists = [
5154
- {
5155
- type: "list-bullet",
5156
- Icon: ListBullets,
5157
- getState: (state) => state.listStyle === "bullet"
5158
- },
5159
- {
5160
- type: "list-ordered",
5161
- Icon: ListNumbers,
5162
- getState: (state) => state.listStyle === "ordered"
5163
- },
5164
- {
5165
- type: "list-task",
5166
- Icon: ListChecks,
5167
- getState: (state) => state.listStyle === "task"
5168
- }
5169
- ];
5170
- var MarkdownLists = () => {
5171
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5172
- const { t } = useTranslation(translationKey);
5173
- return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5174
- type: "single",
5175
- value: state?.listStyle ? `list-${state.listStyle}` : ""
5176
- }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5177
- key: type,
5178
- value: type,
5179
- Icon: Icon2,
5180
- onClick: state ? () => onAction?.({
5181
- type,
5182
- data: !getState(state)
5183
- }) : void 0
5184
- }, t(`${type} label`))));
5185
- };
5186
- var markdownBlocks = [
5187
- {
5188
- type: "blockquote",
5189
- Icon: Quotes,
5190
- getState: (state) => !!state?.blockQuote
5191
- },
5192
- {
5193
- type: "codeblock",
5194
- Icon: CodeBlock,
5195
- getState: (state) => state.blockType === "codeblock"
5196
- },
5197
- {
5198
- type: "table",
5199
- Icon: Table2,
5200
- getState: (state) => state.blockType === "tablecell",
5201
- disabled: (state) => !state.blankLine
5202
- }
5203
- ];
5204
- var MarkdownBlocks = () => {
5205
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5206
- const { t } = useTranslation(translationKey);
5207
- const value = markdownBlocks.find(({ getState }) => state && getState(state));
5208
- return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5209
- type: "single",
5210
- value: value?.type ?? ""
5211
- }, markdownBlocks.map(({ type, disabled, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5212
- key: type,
5213
- value: type,
5214
- Icon: Icon2,
5215
- disabled: !state || disabled?.(state),
5216
- onClick: state ? () => onAction?.({
5217
- type,
5218
- data: !getState(state)
5219
- }) : void 0
5220
- }, t(`${type} label`))));
5221
- };
5222
- var MarkdownStandard = () => /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(MarkdownHeading, null), /* @__PURE__ */ React3.createElement(MarkdownStyles, null), /* @__PURE__ */ React3.createElement(MarkdownLists, null), /* @__PURE__ */ React3.createElement(MarkdownBlocks, null));
5223
- var MarkdownCustom = ({ onUpload } = {}) => {
5224
- const { onAction } = useToolbarContext("MarkdownStyles");
5225
- const { t } = useTranslation(translationKey);
5226
- const { acceptedFiles, getInputProps, open } = useDropzone({
5227
- multiple: false,
5228
- noDrag: true,
5229
- accept: {
5230
- "image/*": [
5231
- ".jpg",
5232
- ".jpeg",
5233
- ".png",
5234
- ".gif"
5235
- ]
5236
- }
5237
- });
5238
- useEffect2(() => {
5239
- if (onUpload && acceptedFiles.length) {
5240
- requestAnimationFrame(async () => {
5241
- const f = acceptedFiles[0];
5242
- const file = new File([
5243
- f
5244
- ], f.name, {
5245
- type: f.type,
5246
- lastModified: f.lastModified
5247
- });
5248
- const info = await onUpload(file);
5249
- if (info) {
5250
- onAction?.({
5251
- type: "image",
5252
- data: info.url
5253
- });
5254
- }
5255
- });
5256
- }
5257
- }, [
5258
- acceptedFiles
5259
- ]);
5260
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("input", getInputProps()), /* @__PURE__ */ React3.createElement(ToolbarButton, {
5261
- value: "image",
5262
- Icon: Image,
5263
- onClick: () => open()
5264
- }, t("image label")));
5265
- };
5266
- var ViewModeIcons = {
5267
- preview: PencilSimple,
5268
- readonly: PencilSimpleSlash,
5269
- source: MarkdownLogo
5270
- };
5271
- var MarkdownView = ({ mode }) => {
5272
- const { t } = useTranslation(translationKey);
5273
- const { onAction } = useToolbarContext("ViewMode");
5274
- const ModeIcon = ViewModeIcons[mode ?? "preview"];
5275
- const suppressNextTooltip = useRef(false);
5276
- const [tooltipOpen, setTooltipOpen] = useState3(false);
5277
- const [selectOpen, setSelectOpen] = useState3(false);
5278
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
5279
- open: tooltipOpen,
5280
- onOpenChange: (nextOpen) => {
5281
- if (nextOpen && suppressNextTooltip.current) {
5282
- suppressNextTooltip.current = false;
5283
- return setTooltipOpen(false);
5284
- } else {
5285
- return setTooltipOpen(nextOpen);
5286
- }
5287
- }
5288
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
5289
- open: selectOpen,
5290
- onOpenChange: (nextOpen) => {
5291
- if (!nextOpen) {
5292
- suppressNextTooltip.current = true;
5293
- }
5294
- return setSelectOpen(nextOpen);
5295
- }
5296
- }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
5297
- asChild: true
5298
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
5299
- asChild: true
5300
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
5301
- asChild: true
5302
- }, /* @__PURE__ */ React3.createElement(Button, {
5303
- variant: "ghost",
5304
- classNames: buttonStyles
5305
- }, /* @__PURE__ */ React3.createElement("span", {
5306
- className: "sr-only"
5307
- }, t("mode label")), /* @__PURE__ */ React3.createElement(ModeIcon, {
5308
- className: iconStyles
5309
- }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
5310
- classNames: "is-min md:is-min",
5311
- onCloseAutoFocus: (e) => e.preventDefault()
5312
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
5313
- const Icon2 = ViewModeIcons[value];
5314
- return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5315
- key: value,
5316
- checked: value === mode,
5317
- onClick: () => onAction?.({
5318
- type: "view-mode",
5319
- data: value
5320
- })
5321
- }, /* @__PURE__ */ React3.createElement(Icon2, {
5322
- className: iconStyles
5323
- }), /* @__PURE__ */ React3.createElement("span", {
5324
- className: "whitespace-nowrap grow"
5325
- }, t(`${value} mode label`)), /* @__PURE__ */ React3.createElement(Check, {
5326
- className: value === mode ? "visible" : "invisible"
5327
- }));
5328
- })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("view mode label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5329
- };
5330
- var MarkdownActions = () => {
5331
- const { onAction, state } = useToolbarContext("MarkdownActions");
5332
- const { t } = useTranslation(translationKey);
5333
- let commentToolTipKey = "comment label";
5334
- if (state?.comment) {
5335
- commentToolTipKey = "selection overlaps existing comment label";
5336
- } else if (state?.selection === false) {
5337
- commentToolTipKey = "select text to comment label";
5338
- }
5339
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ToolbarButton, {
5340
- value: "search",
5341
- Icon: MagnifyingGlass,
5342
- onClick: () => onAction?.({
5343
- type: "search"
5344
- })
5345
- }, t("search label")), /* @__PURE__ */ React3.createElement(ToolbarButton, {
5346
- value: "comment",
5347
- Icon: ChatText,
5348
- "data-testid": "editor.toolbar.comment",
5349
- onClick: () => onAction?.({
5350
- type: "comment"
5351
- }),
5352
- disabled: !state || state.comment || !state.selection
5353
- }, t(commentToolTipKey)));
5354
- };
5355
- var Toolbar = {
5356
- Root: ToolbarRoot,
5357
- Button: ToolbarToggleButton,
5358
- Separator: ToolbarSeparator,
5359
- View: MarkdownView,
5360
- Markdown: MarkdownStandard,
5361
- Custom: MarkdownCustom,
5362
- Actions: MarkdownActions
5363
- };
5364
-
5365
- // packages/ui/react-ui-editor/src/defaults.ts
5366
- import { EditorView as EditorView19 } from "@codemirror/view";
5367
- import { mx as mx3 } from "@dxos/react-ui-theme";
5368
- var margin = "!mt-[1rem]";
5369
- var editorContent = mx3(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
5370
- var editorFullWidth = mx3(margin);
5371
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5372
- var editorGutter = EditorView19.theme({
5373
- // Match margin from content.
5374
- ".cm-gutters": {
5375
- marginTop: "16px",
5376
- paddingRight: "1rem"
5377
- }
5378
- });
5379
- var editorMonospace = EditorView19.theme({
5380
- ".cm-content": {
5381
- fontFamily: fontMono
5382
- }
5383
- });
5384
-
5385
5366
  // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
5367
+ import { useCallback as useCallback2 } from "react";
5386
5368
  var useActionHandler = (view) => {
5387
- return (action) => view && processAction(view, action);
5369
+ return useCallback2((action) => view && processEditorPayload(view, action.properties), [
5370
+ view
5371
+ ]);
5388
5372
  };
5389
5373
 
5390
5374
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5391
5375
  import { EditorState as EditorState2 } from "@codemirror/state";
5392
5376
  import { EditorView as EditorView20 } from "@codemirror/view";
5393
5377
  import { useFocusableGroup } from "@fluentui/react-tabster";
5394
- import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
5378
+ import { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo4, useRef, useState } from "react";
5395
5379
  import { log as log7 } from "@dxos/log";
5396
5380
  import { getProviderValue, isNotFalsy as isNotFalsy4 } from "@dxos/util";
5397
5381
  var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5398
5382
  var instanceCount = 0;
5399
5383
  var useTextEditor = (props = {}, deps = []) => {
5400
- const { id, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = useMemo3(() => getProviderValue(props), deps ?? []);
5401
- const [instanceId] = useState4(() => `text-editor-${++instanceCount}`);
5402
- const [view, setView] = useState4();
5403
- const parentRef = useRef2(null);
5404
- useEffect3(() => {
5384
+ const { id, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = useMemo4(() => getProviderValue(props), deps ?? []);
5385
+ const [instanceId] = useState(() => `text-editor-${++instanceCount}`);
5386
+ const [view, setView] = useState();
5387
+ const parentRef = useRef(null);
5388
+ useEffect2(() => {
5405
5389
  let view2;
5406
5390
  if (parentRef.current) {
5407
5391
  log7("create", {
@@ -5475,7 +5459,7 @@ var useTextEditor = (props = {}, deps = []) => {
5475
5459
  view2?.destroy();
5476
5460
  };
5477
5461
  }, deps);
5478
- useEffect3(() => {
5462
+ useEffect2(() => {
5479
5463
  if (view) {
5480
5464
  if (scrollTo || selection) {
5481
5465
  if (selection && selection.anchor > view.state.doc.length) {
@@ -5502,7 +5486,7 @@ var useTextEditor = (props = {}, deps = []) => {
5502
5486
  scrollTo,
5503
5487
  selection
5504
5488
  ]);
5505
- useEffect3(() => {
5489
+ useEffect2(() => {
5506
5490
  if (view && autoFocus) {
5507
5491
  view.focus();
5508
5492
  }
@@ -5516,7 +5500,7 @@ var useTextEditor = (props = {}, deps = []) => {
5516
5500
  Escape: view?.state.facet(editorInputMode).noTabster
5517
5501
  }
5518
5502
  });
5519
- const handleKeyUp = useCallback((event) => {
5503
+ const handleKeyUp = useCallback3((event) => {
5520
5504
  const { key, target, currentTarget } = event;
5521
5505
  if (target === currentTarget) {
5522
5506
  switch (key) {
@@ -5545,6 +5529,7 @@ export {
5545
5529
  EditorInputMode,
5546
5530
  EditorInputModes,
5547
5531
  EditorState3 as EditorState,
5532
+ EditorToolbar,
5548
5533
  EditorView21 as EditorView,
5549
5534
  EditorViewMode,
5550
5535
  EditorViewModes,
@@ -5554,7 +5539,6 @@ export {
5554
5539
  RemoteSelectionsDecorator,
5555
5540
  SpaceAwarenessProvider,
5556
5541
  TextKind,
5557
- Toolbar,
5558
5542
  addBlockquote,
5559
5543
  addCodeblock,
5560
5544
  addLink,
@@ -5573,8 +5557,10 @@ export {
5573
5557
  commentsState,
5574
5558
  convertTreeToJson,
5575
5559
  createBasicExtensions,
5576
- createComment,
5560
+ createComment2 as createComment,
5577
5561
  createDataExtensions,
5562
+ createEditorAction,
5563
+ createEditorActionGroup,
5578
5564
  createEditorStateStore,
5579
5565
  createEditorStateTransaction,
5580
5566
  createElement,
@@ -5613,7 +5599,7 @@ export {
5613
5599
  mention,
5614
5600
  overlap,
5615
5601
  preventNewline,
5616
- processAction,
5602
+ processEditorPayload,
5617
5603
  removeBlockquote,
5618
5604
  removeCodeblock,
5619
5605
  removeLink,
@@ -5629,6 +5615,8 @@ export {
5629
5615
  setSelection,
5630
5616
  setStyle,
5631
5617
  singleValueFacet,
5618
+ stackItemContentEditorClassNames,
5619
+ stackItemContentToolbarClassNames,
5632
5620
  table,
5633
5621
  tags2 as tags,
5634
5622
  textRange,
@@ -5646,9 +5634,9 @@ export {
5646
5634
  useCommentClickListener,
5647
5635
  useCommentState,
5648
5636
  useComments,
5637
+ useEditorToolbarState,
5649
5638
  useFormattingState,
5650
5639
  useTextEditor,
5651
- useToolbarContext,
5652
5640
  wrapWithCatch
5653
5641
  };
5654
5642
  //# sourceMappingURL=index.mjs.map