@liveblocks/react-ui 2.12.2 → 2.13.0

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 (95) hide show
  1. package/dist/_private/index.d.mts +1 -1
  2. package/dist/_private/index.d.ts +1 -1
  3. package/dist/components/Comment.js +2 -0
  4. package/dist/components/Comment.js.map +1 -1
  5. package/dist/components/Comment.mjs +2 -0
  6. package/dist/components/Comment.mjs.map +1 -1
  7. package/dist/components/Composer.js +74 -6
  8. package/dist/components/Composer.js.map +1 -1
  9. package/dist/components/Composer.mjs +77 -9
  10. package/dist/components/Composer.mjs.map +1 -1
  11. package/dist/components/HistoryVersionSummary.js +1 -0
  12. package/dist/components/HistoryVersionSummary.js.map +1 -1
  13. package/dist/components/HistoryVersionSummary.mjs +1 -0
  14. package/dist/components/HistoryVersionSummary.mjs.map +1 -1
  15. package/dist/components/Thread.js +3 -0
  16. package/dist/components/Thread.js.map +1 -1
  17. package/dist/components/Thread.mjs +3 -0
  18. package/dist/components/Thread.mjs.map +1 -1
  19. package/dist/components/internal/Button.js.map +1 -1
  20. package/dist/components/internal/Button.mjs.map +1 -1
  21. package/dist/icons/Bold.js +15 -0
  22. package/dist/icons/Bold.js.map +1 -0
  23. package/dist/icons/Bold.mjs +13 -0
  24. package/dist/icons/Bold.mjs.map +1 -0
  25. package/dist/icons/Code.js +15 -0
  26. package/dist/icons/Code.js.map +1 -0
  27. package/dist/icons/Code.mjs +13 -0
  28. package/dist/icons/Code.mjs.map +1 -0
  29. package/dist/icons/Italic.js +15 -0
  30. package/dist/icons/Italic.js.map +1 -0
  31. package/dist/icons/Italic.mjs +13 -0
  32. package/dist/icons/Italic.mjs.map +1 -0
  33. package/dist/icons/Strikethrough.js +15 -0
  34. package/dist/icons/Strikethrough.js.map +1 -0
  35. package/dist/icons/Strikethrough.mjs +13 -0
  36. package/dist/icons/Strikethrough.mjs.map +1 -0
  37. package/dist/index.d.mts +94 -103
  38. package/dist/index.d.ts +94 -103
  39. package/dist/index.js +0 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +0 -1
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/overrides.js +15 -0
  44. package/dist/overrides.js.map +1 -1
  45. package/dist/overrides.mjs +15 -0
  46. package/dist/overrides.mjs.map +1 -1
  47. package/dist/primitives/Composer/contexts.js +12 -0
  48. package/dist/primitives/Composer/contexts.js.map +1 -1
  49. package/dist/primitives/Composer/contexts.mjs +11 -1
  50. package/dist/primitives/Composer/contexts.mjs.map +1 -1
  51. package/dist/primitives/Composer/index.js +251 -76
  52. package/dist/primitives/Composer/index.js.map +1 -1
  53. package/dist/primitives/Composer/index.mjs +239 -85
  54. package/dist/primitives/Composer/index.mjs.map +1 -1
  55. package/dist/primitives/Composer/utils.js +94 -21
  56. package/dist/primitives/Composer/utils.js.map +1 -1
  57. package/dist/primitives/Composer/utils.mjs +91 -20
  58. package/dist/primitives/Composer/utils.mjs.map +1 -1
  59. package/dist/primitives/index.d.mts +57 -1
  60. package/dist/primitives/index.d.ts +57 -1
  61. package/dist/slate/plugins/auto-formatting.js +1 -2
  62. package/dist/slate/plugins/auto-formatting.js.map +1 -1
  63. package/dist/slate/plugins/auto-formatting.mjs +1 -2
  64. package/dist/slate/plugins/auto-formatting.mjs.map +1 -1
  65. package/dist/slate/plugins/auto-links.js +3 -2
  66. package/dist/slate/plugins/auto-links.js.map +1 -1
  67. package/dist/slate/plugins/auto-links.mjs +2 -1
  68. package/dist/slate/plugins/auto-links.mjs.map +1 -1
  69. package/dist/slate/plugins/custom-links.js +3 -2
  70. package/dist/slate/plugins/custom-links.js.map +1 -1
  71. package/dist/slate/plugins/custom-links.mjs +2 -1
  72. package/dist/slate/plugins/custom-links.mjs.map +1 -1
  73. package/dist/slate/plugins/mentions.js +3 -4
  74. package/dist/slate/plugins/mentions.js.map +1 -1
  75. package/dist/slate/plugins/mentions.mjs +4 -5
  76. package/dist/slate/plugins/mentions.mjs.map +1 -1
  77. package/dist/slate/utils/marks.js +27 -8
  78. package/dist/slate/utils/marks.js.map +1 -1
  79. package/dist/slate/utils/marks.mjs +27 -10
  80. package/dist/slate/utils/marks.mjs.map +1 -1
  81. package/dist/utils/use-observable.js +15 -0
  82. package/dist/utils/use-observable.js.map +1 -0
  83. package/dist/utils/use-observable.mjs +13 -0
  84. package/dist/utils/use-observable.mjs.map +1 -0
  85. package/dist/version.js +1 -1
  86. package/dist/version.mjs +1 -1
  87. package/package.json +4 -4
  88. package/src/styles/constants.css +1 -1
  89. package/src/styles/index.css +70 -9
  90. package/styles.css +1 -1
  91. package/styles.css.map +1 -1
  92. package/dist/slate/utils/is-selection-collapsed.js +0 -10
  93. package/dist/slate/utils/is-selection-collapsed.js.map +0 -1
  94. package/dist/slate/utils/is-selection-collapsed.mjs +0 -8
  95. package/dist/slate/utils/is-selection-collapsed.mjs.map +0 -1
@@ -1,24 +1,23 @@
1
1
  'use client';
2
- import { flip, hide, shift, limitShift, size, autoUpdate, useFloating } from '@floating-ui/react-dom';
3
- import { createCommentAttachmentId } from '@liveblocks/core';
4
- import { useMentionSuggestions, useRoomOrNull, useSyncSource } from '@liveblocks/react/_private';
2
+ import { kInternal, createCommentAttachmentId, makeEventSource } from '@liveblocks/core';
3
+ import { useClientOrNull, useMentionSuggestions, useRoomOrNull, useSyncSource } from '@liveblocks/react/_private';
5
4
  import { Slottable, Slot } from '@radix-ui/react-slot';
6
- import React__default, { forwardRef, useRef, useMemo, useEffect, useCallback, useState, useImperativeHandle } from 'react';
7
- import { Transforms, Editor, insertText, createEditor } from 'slate';
5
+ import * as TogglePrimitive from '@radix-ui/react-toggle';
6
+ import React__default, { forwardRef, useRef, useMemo, useCallback, useEffect, useState, useImperativeHandle } from 'react';
7
+ import { Transforms, Editor, insertText, createEditor, Range } from 'slate';
8
8
  import { withHistory } from 'slate-history';
9
9
  import { useSelected, ReactEditor, Slate, Editable, useSlateStatic, withReact } from 'slate-react';
10
10
  import { useLiveblocksUIConfig } from '../../config.mjs';
11
- import { FLOATING_ELEMENT_COLLISION_PADDING } from '../../constants.mjs';
12
11
  import { withAutoFormatting } from '../../slate/plugins/auto-formatting.mjs';
13
12
  import { withAutoLinks } from '../../slate/plugins/auto-links.mjs';
14
13
  import { withCustomLinks } from '../../slate/plugins/custom-links.mjs';
15
14
  import { withEmptyClearFormatting } from '../../slate/plugins/empty-clear-formatting.mjs';
16
- import { getMentionDraftAtSelection, insertMention, insertMentionCharacter, MENTION_CHARACTER, withMentions } from '../../slate/plugins/mentions.mjs';
15
+ import { insertMention, insertMentionCharacter, MENTION_CHARACTER, withMentions, getMentionDraftAtSelection } from '../../slate/plugins/mentions.mjs';
17
16
  import { withNormalize } from '../../slate/plugins/normalize.mjs';
18
17
  import { withPaste } from '../../slate/plugins/paste.mjs';
19
18
  import { getDOMRange } from '../../slate/utils/get-dom-range.mjs';
20
19
  import { isEmpty } from '../../slate/utils/is-empty.mjs';
21
- import { leaveMarkEdge, toggleMark } from '../../slate/utils/marks.mjs';
20
+ import { leaveMarkEdge, toggleMark, getMarks } from '../../slate/utils/marks.mjs';
22
21
  import { isKey } from '../../utils/is-key.mjs';
23
22
  import { usePersist, useAnimationPersist, Persist } from '../../utils/Persist.mjs';
24
23
  import { Portal } from '../../utils/Portal.mjs';
@@ -27,14 +26,17 @@ import { useId } from '../../utils/use-id.mjs';
27
26
  import { useIndex } from '../../utils/use-index.mjs';
28
27
  import { useInitial } from '../../utils/use-initial.mjs';
29
28
  import { useLayoutEffect } from '../../utils/use-layout-effect.mjs';
29
+ import { useObservable } from '../../utils/use-observable.mjs';
30
30
  import { useRefs } from '../../utils/use-refs.mjs';
31
31
  import { toAbsoluteUrl } from '../Comment/utils.mjs';
32
- import { useComposerSuggestionsContext, useComposerEditorContext, useComposer, ComposerEditorContext, ComposerAttachmentsContext, ComposerContext, useComposerAttachmentsContext, ComposerSuggestionsContext } from './contexts.mjs';
33
- import { getSideAndAlignFromPlacement, commentBodyToComposerBody, useComposerAttachmentsManager, composerBodyToCommentBody, useComposerAttachmentsDropArea, getPlacementFromPosition } from './utils.mjs';
32
+ import { useComposerFloatingToolbarContext, useComposerSuggestionsContext, useComposerEditorContext, useComposer, ComposerEditorContext, ComposerAttachmentsContext, ComposerContext, useComposerAttachmentsContext, ComposerSuggestionsContext, ComposerFloatingToolbarContext } from './contexts.mjs';
33
+ import { getSideAndAlignFromFloatingPlacement, commentBodyToComposerBody, useComposerAttachmentsManager, composerBodyToCommentBody, useComposerAttachmentsDropArea, useContentZIndex, useFloatingWithOptions } from './utils.mjs';
34
34
 
35
35
  const MENTION_SUGGESTIONS_POSITION = "top";
36
+ const FLOATING_TOOLBAR_POSITION = "top";
36
37
  const COMPOSER_MENTION_NAME = "ComposerMention";
37
38
  const COMPOSER_LINK_NAME = "ComposerLink";
39
+ const COMPOSER_FLOATING_TOOLBAR_NAME = "ComposerFloatingToolbar";
38
40
  const COMPOSER_SUGGESTIONS_NAME = "ComposerSuggestions";
39
41
  const COMPOSER_SUGGESTIONS_LIST_NAME = "ComposerSuggestionsList";
40
42
  const COMPOSER_SUGGESTIONS_LIST_ITEM_NAME = "ComposerSuggestionsListItem";
@@ -42,6 +44,7 @@ const COMPOSER_SUBMIT_NAME = "ComposerSubmit";
42
44
  const COMPOSER_EDITOR_NAME = "ComposerEditor";
43
45
  const COMPOSER_ATTACH_FILES_NAME = "ComposerAttachFiles";
44
46
  const COMPOSER_ATTACHMENTS_DROP_AREA_NAME = "ComposerAttachmentsDropArea";
47
+ const COMPOSER_MARK_TOGGLE_NAME = "ComposerMarkToggle";
45
48
  const COMPOSER_FORM_NAME = "ComposerForm";
46
49
  const emptyCommentBody = {
47
50
  version: 1,
@@ -105,52 +108,18 @@ function ComposerEditorMentionSuggestionsWrapper({
105
108
  selectedUserId,
106
109
  setSelectedUserId,
107
110
  mentionDraft,
111
+ setMentionDraft,
108
112
  onItemSelect,
109
113
  position = MENTION_SUGGESTIONS_POSITION,
110
114
  dir,
111
115
  MentionSuggestions
112
116
  }) {
113
117
  const editor = useSlateStatic();
118
+ const { onEditorChange } = useComposerEditorContext();
114
119
  const { isFocused } = useComposer();
115
- const [content, setContent] = useState(null);
116
- const [contentZIndex, setContentZIndex] = useState();
117
- const contentRef = useCallback(setContent, [setContent]);
118
120
  const { portalContainer } = useLiveblocksUIConfig();
119
- const floatingOptions = useMemo(() => {
120
- const detectOverflowOptions = {
121
- padding: FLOATING_ELEMENT_COLLISION_PADDING
122
- };
123
- return {
124
- strategy: "fixed",
125
- placement: getPlacementFromPosition(position, dir),
126
- middleware: [
127
- flip({ ...detectOverflowOptions, crossAxis: false }),
128
- hide(detectOverflowOptions),
129
- shift({
130
- ...detectOverflowOptions,
131
- limiter: limitShift()
132
- }),
133
- size({
134
- ...detectOverflowOptions,
135
- apply({ availableWidth, availableHeight, elements }) {
136
- elements.floating.style.setProperty(
137
- "--lb-composer-suggestions-available-width",
138
- `${availableWidth}px`
139
- );
140
- elements.floating.style.setProperty(
141
- "--lb-composer-suggestions-available-height",
142
- `${availableHeight}px`
143
- );
144
- }
145
- })
146
- ],
147
- whileElementsMounted: (...args) => {
148
- return autoUpdate(...args, {
149
- animationFrame: true
150
- });
151
- }
152
- };
153
- }, [position, dir]);
121
+ const [contentRef, contentZIndex] = useContentZIndex();
122
+ const isOpen = isFocused && mentionDraft?.range !== void 0 && userIds !== void 0;
154
123
  const {
155
124
  refs: { setReference, setFloating },
156
125
  strategy,
@@ -158,25 +127,24 @@ function ComposerEditorMentionSuggestionsWrapper({
158
127
  placement,
159
128
  x,
160
129
  y
161
- } = useFloating(floatingOptions);
162
- useLayoutEffect(() => {
163
- if (content) {
164
- setContentZIndex(window.getComputedStyle(content).zIndex);
165
- }
166
- }, [content]);
130
+ } = useFloatingWithOptions({
131
+ position,
132
+ dir,
133
+ alignment: "start",
134
+ open: isOpen
135
+ });
136
+ useObservable(onEditorChange, () => {
137
+ setMentionDraft(getMentionDraftAtSelection(editor));
138
+ });
167
139
  useLayoutEffect(() => {
168
140
  if (!mentionDraft) {
141
+ setReference(null);
169
142
  return;
170
143
  }
171
144
  const domRange = getDOMRange(editor, mentionDraft.range);
172
- if (domRange) {
173
- setReference({
174
- getBoundingClientRect: () => domRange.getBoundingClientRect(),
175
- getClientRects: () => domRange.getClientRects()
176
- });
177
- }
145
+ setReference(domRange ?? null);
178
146
  }, [setReference, editor, mentionDraft]);
179
- return /* @__PURE__ */ React__default.createElement(Persist, null, mentionDraft?.range && isFocused && userIds ? /* @__PURE__ */ React__default.createElement(ComposerSuggestionsContext.Provider, {
147
+ return /* @__PURE__ */ React__default.createElement(Persist, null, isOpen ? /* @__PURE__ */ React__default.createElement(ComposerSuggestionsContext.Provider, {
180
148
  value: {
181
149
  id,
182
150
  itemId,
@@ -203,6 +171,126 @@ function ComposerEditorMentionSuggestionsWrapper({
203
171
  selectedUserId
204
172
  }))) : null);
205
173
  }
174
+ function ComposerEditorFloatingToolbarWrapper({
175
+ id,
176
+ position = FLOATING_TOOLBAR_POSITION,
177
+ dir,
178
+ FloatingToolbar,
179
+ hasFloatingToolbarRange,
180
+ setHasFloatingToolbarRange
181
+ }) {
182
+ const editor = useSlateStatic();
183
+ const { onEditorChange } = useComposerEditorContext();
184
+ const { isFocused } = useComposer();
185
+ const { portalContainer } = useLiveblocksUIConfig();
186
+ const [contentRef, contentZIndex] = useContentZIndex();
187
+ const [isPointerDown, setPointerDown] = useState(false);
188
+ const isOpen = isFocused && !isPointerDown && hasFloatingToolbarRange;
189
+ const {
190
+ refs: { setReference, setFloating },
191
+ strategy,
192
+ isPositioned,
193
+ placement,
194
+ x,
195
+ y
196
+ } = useFloatingWithOptions({
197
+ type: "range",
198
+ position,
199
+ dir,
200
+ alignment: "center",
201
+ open: isOpen
202
+ });
203
+ useLayoutEffect(() => {
204
+ if (!isFocused) {
205
+ return;
206
+ }
207
+ const handlePointerDown = () => setPointerDown(true);
208
+ const handlePointerUp = () => setPointerDown(false);
209
+ document.addEventListener("pointerdown", handlePointerDown);
210
+ document.addEventListener("pointerup", handlePointerUp);
211
+ return () => {
212
+ document.removeEventListener("pointerdown", handlePointerDown);
213
+ document.removeEventListener("pointerup", handlePointerUp);
214
+ };
215
+ }, [isFocused]);
216
+ useObservable(onEditorChange, () => {
217
+ setReference(null);
218
+ requestAnimationFrame(() => {
219
+ const domSelection = window.getSelection();
220
+ if (!editor.selection || Range.isCollapsed(editor.selection) || !domSelection || !domSelection.rangeCount) {
221
+ setHasFloatingToolbarRange(false);
222
+ setReference(null);
223
+ } else {
224
+ setHasFloatingToolbarRange(true);
225
+ const domRange = domSelection.getRangeAt(0);
226
+ setReference(domRange);
227
+ }
228
+ });
229
+ });
230
+ return /* @__PURE__ */ React__default.createElement(Persist, null, isOpen ? /* @__PURE__ */ React__default.createElement(ComposerFloatingToolbarContext.Provider, {
231
+ value: {
232
+ id,
233
+ placement,
234
+ dir,
235
+ ref: contentRef
236
+ }
237
+ }, /* @__PURE__ */ React__default.createElement(Portal, {
238
+ ref: setFloating,
239
+ container: portalContainer,
240
+ style: {
241
+ position: strategy,
242
+ top: 0,
243
+ left: 0,
244
+ transform: isPositioned ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)` : "translate3d(0, -200%, 0)",
245
+ minWidth: "max-content",
246
+ zIndex: contentZIndex
247
+ }
248
+ }, /* @__PURE__ */ React__default.createElement(FloatingToolbar, null))) : null);
249
+ }
250
+ const ComposerFloatingToolbar = forwardRef(({ children, onPointerDown, style, asChild, ...props }, forwardedRef) => {
251
+ const [isPresent] = usePersist();
252
+ const ref = useRef(null);
253
+ const {
254
+ id,
255
+ ref: contentRef,
256
+ placement,
257
+ dir
258
+ } = useComposerFloatingToolbarContext(COMPOSER_FLOATING_TOOLBAR_NAME);
259
+ const mergedRefs = useRefs(forwardedRef, contentRef, ref);
260
+ const [side, align] = useMemo(
261
+ () => getSideAndAlignFromFloatingPlacement(placement),
262
+ [placement]
263
+ );
264
+ const Component = asChild ? Slot : "div";
265
+ useAnimationPersist(ref);
266
+ const handlePointerDown = useCallback(
267
+ (event) => {
268
+ onPointerDown?.(event);
269
+ event.preventDefault();
270
+ event.stopPropagation();
271
+ },
272
+ [onPointerDown]
273
+ );
274
+ return /* @__PURE__ */ React__default.createElement(Component, {
275
+ dir,
276
+ role: "toolbar",
277
+ id,
278
+ "aria-label": "Floating toolbar",
279
+ ...props,
280
+ onPointerDown: handlePointerDown,
281
+ "data-state": isPresent ? "open" : "closed",
282
+ "data-side": side,
283
+ "data-align": align,
284
+ style: {
285
+ display: "flex",
286
+ flexDirection: "row",
287
+ maxWidth: "var(--lb-composer-floating-available-width)",
288
+ overflowX: "auto",
289
+ ...style
290
+ },
291
+ ref: mergedRefs
292
+ }, children);
293
+ });
206
294
  function ComposerEditorElement({
207
295
  Mention,
208
296
  Link,
@@ -290,7 +378,7 @@ const ComposerSuggestions = forwardRef(({ children, style, asChild, ...props },
290
378
  } = useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_NAME);
291
379
  const mergedRefs = useRefs(forwardedRef, contentRef, ref);
292
380
  const [side, align] = useMemo(
293
- () => getSideAndAlignFromPlacement(placement),
381
+ () => getSideAndAlignFromFloatingPlacement(placement),
294
382
  [placement]
295
383
  );
296
384
  const Component = asChild ? Slot : "div";
@@ -304,7 +392,7 @@ const ComposerSuggestions = forwardRef(({ children, style, asChild, ...props },
304
392
  style: {
305
393
  display: "flex",
306
394
  flexDirection: "column",
307
- maxHeight: "var(--lb-composer-suggestions-available-height)",
395
+ maxHeight: "var(--lb-composer-floating-available-height)",
308
396
  overflowY: "auto",
309
397
  ...style
310
398
  },
@@ -416,10 +504,12 @@ const ComposerEditor = forwardRef(
416
504
  dir,
417
505
  ...props
418
506
  }, forwardedRef) => {
419
- const { editor, validate, setFocused, roomId } = useComposerEditorContext();
507
+ const client = useClientOrNull();
508
+ const { editor, validate, setFocused, onEditorChange, roomId } = useComposerEditorContext();
420
509
  const {
421
510
  submit,
422
511
  focus,
512
+ blur,
423
513
  select,
424
514
  canSubmit,
425
515
  isDisabled: isComposerDisabled,
@@ -430,10 +520,12 @@ const ComposerEditor = forwardRef(
430
520
  const initialEditorValue = useMemo(() => {
431
521
  return commentBodyToComposerBody(initialBody);
432
522
  }, [initialBody]);
433
- const { Link, Mention, MentionSuggestions } = useMemo(
523
+ const { Link, Mention, MentionSuggestions, FloatingToolbar } = useMemo(
434
524
  () => ({ ...defaultEditorComponents, ...components }),
435
525
  [components]
436
526
  );
527
+ const [hasFloatingToolbarRange, setHasFloatingToolbarRange] = useState(false);
528
+ const hasResolveMentionSuggestions = client ? client[kInternal].resolveMentionSuggestions !== void 0 : true;
437
529
  const [mentionDraft, setMentionDraft] = useState();
438
530
  const mentionSuggestions = useMentionSuggestions(
439
531
  roomId,
@@ -446,6 +538,10 @@ const ComposerEditor = forwardRef(
446
538
  setSelectedMentionSuggestionIndex
447
539
  ] = useIndex(0, mentionSuggestions?.length ?? 0);
448
540
  const id = useId();
541
+ const floatingToolbarId = useMemo(
542
+ () => `liveblocks-floating-toolbar-${id}`,
543
+ [id]
544
+ );
449
545
  const suggestionsListId = useMemo(
450
546
  () => `liveblocks-suggestions-list-${id}`,
451
547
  [id]
@@ -467,9 +563,9 @@ const ComposerEditor = forwardRef(
467
563
  const handleChange = useCallback(
468
564
  (value) => {
469
565
  validate(value);
470
- setMentionDraft(getMentionDraftAtSelection(editor));
566
+ onEditorChange.notify();
471
567
  },
472
- [editor, validate]
568
+ [validate, onEditorChange]
473
569
  );
474
570
  const createMention = useCallback(
475
571
  (userId) => {
@@ -515,9 +611,15 @@ const ComposerEditor = forwardRef(
515
611
  setSelectedMentionSuggestionIndex(0);
516
612
  }
517
613
  } else {
614
+ if (hasFloatingToolbarRange) {
615
+ if (isKey(event, "Escape")) {
616
+ event.preventDefault();
617
+ setHasFloatingToolbarRange(false);
618
+ }
619
+ }
518
620
  if (isKey(event, "Escape")) {
519
621
  event.preventDefault();
520
- ReactEditor.blur(editor);
622
+ blur();
521
623
  }
522
624
  if (isKey(event, "Enter", { shift: false })) {
523
625
  event.preventDefault();
@@ -548,16 +650,18 @@ const ComposerEditor = forwardRef(
548
650
  }
549
651
  },
550
652
  [
551
- createMention,
552
- editor,
553
- canSubmit,
653
+ onKeyDown,
554
654
  mentionDraft,
555
655
  mentionSuggestions,
556
- selectedMentionSuggestionIndex,
557
- onKeyDown,
656
+ hasFloatingToolbarRange,
657
+ editor,
558
658
  setNextSelectedMentionSuggestionIndex,
559
659
  setPreviousSelectedMentionSuggestionIndex,
660
+ selectedMentionSuggestionIndex,
661
+ createMention,
560
662
  setSelectedMentionSuggestionIndex,
663
+ blur,
664
+ canSubmit,
561
665
  submit
562
666
  ]
563
667
  );
@@ -592,7 +696,7 @@ const ComposerEditor = forwardRef(
592
696
  },
593
697
  [setSelectedMentionSuggestionIndex, mentionSuggestions]
594
698
  );
595
- const propsWhileSuggesting = useMemo(
699
+ const additionalProps = useMemo(
596
700
  () => mentionDraft ? {
597
701
  role: "combobox",
598
702
  "aria-autocomplete": "list",
@@ -601,23 +705,28 @@ const ComposerEditor = forwardRef(
601
705
  "aria-activedescendant": suggestionsListItemId(
602
706
  selectedMentionSuggestionUserId
603
707
  )
708
+ } : hasFloatingToolbarRange ? {
709
+ "aria-haspopup": true,
710
+ "aria-controls": floatingToolbarId
604
711
  } : {},
605
712
  [
606
713
  mentionDraft,
607
714
  suggestionsListId,
608
715
  suggestionsListItemId,
609
- selectedMentionSuggestionUserId
716
+ selectedMentionSuggestionUserId,
717
+ hasFloatingToolbarRange,
718
+ floatingToolbarId
610
719
  ]
611
720
  );
612
721
  useImperativeHandle(forwardedRef, () => {
613
722
  return ReactEditor.toDOMNode(editor, editor);
614
723
  }, [editor]);
615
- useEffect(() => {
724
+ useLayoutEffect(() => {
616
725
  if (autoFocus) {
617
726
  focus();
618
727
  }
619
728
  }, [autoFocus, editor, focus]);
620
- useEffect(() => {
729
+ useLayoutEffect(() => {
621
730
  if (isFocused && editor.selection === null) {
622
731
  select();
623
732
  }
@@ -633,7 +742,7 @@ const ComposerEditor = forwardRef(
633
742
  "aria-label": "Composer editor",
634
743
  "data-focused": isFocused || void 0,
635
744
  "data-disabled": isDisabled || void 0,
636
- ...propsWhileSuggesting,
745
+ ...additionalProps,
637
746
  ...props,
638
747
  readOnly: isDisabled,
639
748
  disabled: isDisabled,
@@ -643,9 +752,10 @@ const ComposerEditor = forwardRef(
643
752
  renderElement,
644
753
  renderLeaf: ComposerEditorLeaf,
645
754
  renderPlaceholder: ComposerEditorPlaceholder
646
- }), /* @__PURE__ */ React__default.createElement(ComposerEditorMentionSuggestionsWrapper, {
755
+ }), hasResolveMentionSuggestions && /* @__PURE__ */ React__default.createElement(ComposerEditorMentionSuggestionsWrapper, {
647
756
  dir,
648
757
  mentionDraft,
758
+ setMentionDraft,
649
759
  selectedUserId: selectedMentionSuggestionUserId,
650
760
  setSelectedUserId: setSelectedMentionSuggestionUserId,
651
761
  userIds: mentionSuggestions,
@@ -653,6 +763,12 @@ const ComposerEditor = forwardRef(
653
763
  itemId: suggestionsListItemId,
654
764
  onItemSelect: createMention,
655
765
  MentionSuggestions
766
+ }), FloatingToolbar && /* @__PURE__ */ React__default.createElement(ComposerEditorFloatingToolbarWrapper, {
767
+ dir,
768
+ id: floatingToolbarId,
769
+ hasFloatingToolbarRange,
770
+ setHasFloatingToolbarRange,
771
+ FloatingToolbar
656
772
  }));
657
773
  }
658
774
  );
@@ -711,6 +827,7 @@ const ComposerForm = forwardRef(
711
827
  const canSubmit = useMemo(() => {
712
828
  return !isEmpty$1 && !isUploadingAttachments;
713
829
  }, [isEmpty$1, isUploadingAttachments]);
830
+ const [marks, setMarks] = useState(getMarks);
714
831
  const ref = useRef(null);
715
832
  const mergedRefs = useRefs(forwardedRef, ref);
716
833
  const fileInputRef = useRef(null);
@@ -749,6 +866,7 @@ const ComposerForm = forwardRef(
749
866
  pasteFilesAsAttachments
750
867
  })
751
868
  );
869
+ const onEditorChange = useInitial(makeEventSource);
752
870
  const validate = useCallback(
753
871
  (value) => {
754
872
  setEmpty(isEmpty(editor, value));
@@ -774,10 +892,7 @@ const ComposerForm = forwardRef(
774
892
  });
775
893
  }, [editor]);
776
894
  const select = useCallback(() => {
777
- Transforms.select(editor, {
778
- anchor: Editor.end(editor, []),
779
- focus: Editor.end(editor, [])
780
- });
895
+ Transforms.select(editor, Editor.end(editor, []));
781
896
  }, [editor]);
782
897
  const focus = useCallback(
783
898
  (resetSelection = true) => {
@@ -883,11 +998,21 @@ const ComposerForm = forwardRef(
883
998
  const stopPropagation = useCallback((event) => {
884
999
  event.stopPropagation();
885
1000
  }, []);
1001
+ const toggleMark$1 = useCallback(
1002
+ (mark) => {
1003
+ toggleMark(editor, mark);
1004
+ },
1005
+ [editor]
1006
+ );
1007
+ useObservable(onEditorChange, () => {
1008
+ setMarks(getMarks(editor));
1009
+ });
886
1010
  return /* @__PURE__ */ React__default.createElement(ComposerEditorContext.Provider, {
887
1011
  value: {
888
1012
  editor,
889
1013
  validate,
890
1014
  setFocused,
1015
+ onEditorChange,
891
1016
  roomId
892
1017
  }
893
1018
  }, /* @__PURE__ */ React__default.createElement(ComposerAttachmentsContext.Provider, {
@@ -913,7 +1038,9 @@ const ComposerForm = forwardRef(
913
1038
  insertText: insertText$1,
914
1039
  attachments,
915
1040
  attachFiles,
916
- removeAttachment
1041
+ removeAttachment,
1042
+ toggleMark: toggleMark$1,
1043
+ marks
917
1044
  }
918
1045
  }, /* @__PURE__ */ React__default.createElement(Component, {
919
1046
  ...props,
@@ -993,10 +1120,36 @@ const ComposerAttachmentsDropArea = forwardRef(
993
1120
  });
994
1121
  }
995
1122
  );
1123
+ const ComposerMarkToggle = forwardRef(
1124
+ ({ children, mark, onValueChange, onClick, asChild, ...props }, forwardedRef) => {
1125
+ const Component = asChild ? Slot : "button";
1126
+ const { marks, toggleMark } = useComposer();
1127
+ const handleClick = useCallback(
1128
+ (event) => {
1129
+ onClick?.(event);
1130
+ if (!event.isDefaultPrevented()) {
1131
+ toggleMark(mark);
1132
+ onValueChange?.(mark);
1133
+ }
1134
+ },
1135
+ [mark, onClick, onValueChange, toggleMark]
1136
+ );
1137
+ return /* @__PURE__ */ React__default.createElement(TogglePrimitive.Root, {
1138
+ asChild: true,
1139
+ pressed: marks[mark],
1140
+ onClick: handleClick,
1141
+ ...props
1142
+ }, /* @__PURE__ */ React__default.createElement(Component, {
1143
+ ...props,
1144
+ ref: forwardedRef
1145
+ }, children));
1146
+ }
1147
+ );
996
1148
  if (process.env.NODE_ENV !== "production") {
997
1149
  ComposerAttachFiles.displayName = COMPOSER_ATTACH_FILES_NAME;
998
1150
  ComposerAttachmentsDropArea.displayName = COMPOSER_ATTACHMENTS_DROP_AREA_NAME;
999
1151
  ComposerEditor.displayName = COMPOSER_EDITOR_NAME;
1152
+ ComposerFloatingToolbar.displayName = COMPOSER_FLOATING_TOOLBAR_NAME;
1000
1153
  ComposerForm.displayName = COMPOSER_FORM_NAME;
1001
1154
  ComposerMention.displayName = COMPOSER_MENTION_NAME;
1002
1155
  ComposerLink.displayName = COMPOSER_LINK_NAME;
@@ -1004,7 +1157,8 @@ if (process.env.NODE_ENV !== "production") {
1004
1157
  ComposerSuggestions.displayName = COMPOSER_SUGGESTIONS_NAME;
1005
1158
  ComposerSuggestionsList.displayName = COMPOSER_SUGGESTIONS_LIST_NAME;
1006
1159
  ComposerSuggestionsListItem.displayName = COMPOSER_SUGGESTIONS_LIST_ITEM_NAME;
1160
+ ComposerMarkToggle.displayName = COMPOSER_MARK_TOGGLE_NAME;
1007
1161
  }
1008
1162
 
1009
- export { ComposerAttachFiles as AttachFiles, ComposerAttachmentsDropArea as AttachmentsDropArea, ComposerEditor as Editor, ComposerForm as Form, ComposerLink as Link, ComposerMention as Mention, ComposerSubmit as Submit, ComposerSuggestions as Suggestions, ComposerSuggestionsList as SuggestionsList, ComposerSuggestionsListItem as SuggestionsListItem };
1163
+ export { ComposerAttachFiles as AttachFiles, ComposerAttachmentsDropArea as AttachmentsDropArea, ComposerEditor as Editor, ComposerFloatingToolbar as FloatingToolbar, ComposerForm as Form, ComposerLink as Link, ComposerMarkToggle as MarkToggle, ComposerMention as Mention, ComposerSubmit as Submit, ComposerSuggestions as Suggestions, ComposerSuggestionsList as SuggestionsList, ComposerSuggestionsListItem as SuggestionsListItem };
1010
1164
  //# sourceMappingURL=index.mjs.map