@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,16 +1,15 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var reactDom = require('@floating-ui/react-dom');
5
4
  var core = require('@liveblocks/core');
6
5
  var _private = require('@liveblocks/react/_private');
7
6
  var reactSlot = require('@radix-ui/react-slot');
7
+ var TogglePrimitive = require('@radix-ui/react-toggle');
8
8
  var React = require('react');
9
9
  var slate = require('slate');
10
10
  var slateHistory = require('slate-history');
11
11
  var slateReact = require('slate-react');
12
12
  var config = require('../../config.js');
13
- var constants = require('../../constants.js');
14
13
  var autoFormatting = require('../../slate/plugins/auto-formatting.js');
15
14
  var autoLinks = require('../../slate/plugins/auto-links.js');
16
15
  var customLinks = require('../../slate/plugins/custom-links.js');
@@ -29,14 +28,36 @@ var useId = require('../../utils/use-id.js');
29
28
  var useIndex = require('../../utils/use-index.js');
30
29
  var useInitial = require('../../utils/use-initial.js');
31
30
  var useLayoutEffect = require('../../utils/use-layout-effect.js');
31
+ var useObservable = require('../../utils/use-observable.js');
32
32
  var useRefs = require('../../utils/use-refs.js');
33
33
  var utils$1 = require('../Comment/utils.js');
34
34
  var contexts = require('./contexts.js');
35
35
  var utils = require('./utils.js');
36
36
 
37
+ function _interopNamespaceDefault(e) {
38
+ var n = Object.create(null);
39
+ if (e) {
40
+ Object.keys(e).forEach(function (k) {
41
+ if (k !== 'default') {
42
+ var d = Object.getOwnPropertyDescriptor(e, k);
43
+ Object.defineProperty(n, k, d.get ? d : {
44
+ enumerable: true,
45
+ get: function () { return e[k]; }
46
+ });
47
+ }
48
+ });
49
+ }
50
+ n.default = e;
51
+ return Object.freeze(n);
52
+ }
53
+
54
+ var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(TogglePrimitive);
55
+
37
56
  const MENTION_SUGGESTIONS_POSITION = "top";
57
+ const FLOATING_TOOLBAR_POSITION = "top";
38
58
  const COMPOSER_MENTION_NAME = "ComposerMention";
39
59
  const COMPOSER_LINK_NAME = "ComposerLink";
60
+ const COMPOSER_FLOATING_TOOLBAR_NAME = "ComposerFloatingToolbar";
40
61
  const COMPOSER_SUGGESTIONS_NAME = "ComposerSuggestions";
41
62
  const COMPOSER_SUGGESTIONS_LIST_NAME = "ComposerSuggestionsList";
42
63
  const COMPOSER_SUGGESTIONS_LIST_ITEM_NAME = "ComposerSuggestionsListItem";
@@ -44,6 +65,7 @@ const COMPOSER_SUBMIT_NAME = "ComposerSubmit";
44
65
  const COMPOSER_EDITOR_NAME = "ComposerEditor";
45
66
  const COMPOSER_ATTACH_FILES_NAME = "ComposerAttachFiles";
46
67
  const COMPOSER_ATTACHMENTS_DROP_AREA_NAME = "ComposerAttachmentsDropArea";
68
+ const COMPOSER_MARK_TOGGLE_NAME = "ComposerMarkToggle";
47
69
  const COMPOSER_FORM_NAME = "ComposerForm";
48
70
  const emptyCommentBody = {
49
71
  version: 1,
@@ -107,52 +129,18 @@ function ComposerEditorMentionSuggestionsWrapper({
107
129
  selectedUserId,
108
130
  setSelectedUserId,
109
131
  mentionDraft,
132
+ setMentionDraft,
110
133
  onItemSelect,
111
134
  position = MENTION_SUGGESTIONS_POSITION,
112
135
  dir,
113
136
  MentionSuggestions
114
137
  }) {
115
138
  const editor = slateReact.useSlateStatic();
139
+ const { onEditorChange } = contexts.useComposerEditorContext();
116
140
  const { isFocused } = contexts.useComposer();
117
- const [content, setContent] = React.useState(null);
118
- const [contentZIndex, setContentZIndex] = React.useState();
119
- const contentRef = React.useCallback(setContent, [setContent]);
120
141
  const { portalContainer } = config.useLiveblocksUIConfig();
121
- const floatingOptions = React.useMemo(() => {
122
- const detectOverflowOptions = {
123
- padding: constants.FLOATING_ELEMENT_COLLISION_PADDING
124
- };
125
- return {
126
- strategy: "fixed",
127
- placement: utils.getPlacementFromPosition(position, dir),
128
- middleware: [
129
- reactDom.flip({ ...detectOverflowOptions, crossAxis: false }),
130
- reactDom.hide(detectOverflowOptions),
131
- reactDom.shift({
132
- ...detectOverflowOptions,
133
- limiter: reactDom.limitShift()
134
- }),
135
- reactDom.size({
136
- ...detectOverflowOptions,
137
- apply({ availableWidth, availableHeight, elements }) {
138
- elements.floating.style.setProperty(
139
- "--lb-composer-suggestions-available-width",
140
- `${availableWidth}px`
141
- );
142
- elements.floating.style.setProperty(
143
- "--lb-composer-suggestions-available-height",
144
- `${availableHeight}px`
145
- );
146
- }
147
- })
148
- ],
149
- whileElementsMounted: (...args) => {
150
- return reactDom.autoUpdate(...args, {
151
- animationFrame: true
152
- });
153
- }
154
- };
155
- }, [position, dir]);
142
+ const [contentRef, contentZIndex] = utils.useContentZIndex();
143
+ const isOpen = isFocused && mentionDraft?.range !== void 0 && userIds !== void 0;
156
144
  const {
157
145
  refs: { setReference, setFloating },
158
146
  strategy,
@@ -160,25 +148,24 @@ function ComposerEditorMentionSuggestionsWrapper({
160
148
  placement,
161
149
  x,
162
150
  y
163
- } = reactDom.useFloating(floatingOptions);
164
- useLayoutEffect.useLayoutEffect(() => {
165
- if (content) {
166
- setContentZIndex(window.getComputedStyle(content).zIndex);
167
- }
168
- }, [content]);
151
+ } = utils.useFloatingWithOptions({
152
+ position,
153
+ dir,
154
+ alignment: "start",
155
+ open: isOpen
156
+ });
157
+ useObservable.useObservable(onEditorChange, () => {
158
+ setMentionDraft(mentions.getMentionDraftAtSelection(editor));
159
+ });
169
160
  useLayoutEffect.useLayoutEffect(() => {
170
161
  if (!mentionDraft) {
162
+ setReference(null);
171
163
  return;
172
164
  }
173
165
  const domRange = getDomRange.getDOMRange(editor, mentionDraft.range);
174
- if (domRange) {
175
- setReference({
176
- getBoundingClientRect: () => domRange.getBoundingClientRect(),
177
- getClientRects: () => domRange.getClientRects()
178
- });
179
- }
166
+ setReference(domRange ?? null);
180
167
  }, [setReference, editor, mentionDraft]);
181
- return /* @__PURE__ */ React.createElement(Persist.Persist, null, mentionDraft?.range && isFocused && userIds ? /* @__PURE__ */ React.createElement(contexts.ComposerSuggestionsContext.Provider, {
168
+ return /* @__PURE__ */ React.createElement(Persist.Persist, null, isOpen ? /* @__PURE__ */ React.createElement(contexts.ComposerSuggestionsContext.Provider, {
182
169
  value: {
183
170
  id,
184
171
  itemId,
@@ -205,6 +192,126 @@ function ComposerEditorMentionSuggestionsWrapper({
205
192
  selectedUserId
206
193
  }))) : null);
207
194
  }
195
+ function ComposerEditorFloatingToolbarWrapper({
196
+ id,
197
+ position = FLOATING_TOOLBAR_POSITION,
198
+ dir,
199
+ FloatingToolbar,
200
+ hasFloatingToolbarRange,
201
+ setHasFloatingToolbarRange
202
+ }) {
203
+ const editor = slateReact.useSlateStatic();
204
+ const { onEditorChange } = contexts.useComposerEditorContext();
205
+ const { isFocused } = contexts.useComposer();
206
+ const { portalContainer } = config.useLiveblocksUIConfig();
207
+ const [contentRef, contentZIndex] = utils.useContentZIndex();
208
+ const [isPointerDown, setPointerDown] = React.useState(false);
209
+ const isOpen = isFocused && !isPointerDown && hasFloatingToolbarRange;
210
+ const {
211
+ refs: { setReference, setFloating },
212
+ strategy,
213
+ isPositioned,
214
+ placement,
215
+ x,
216
+ y
217
+ } = utils.useFloatingWithOptions({
218
+ type: "range",
219
+ position,
220
+ dir,
221
+ alignment: "center",
222
+ open: isOpen
223
+ });
224
+ useLayoutEffect.useLayoutEffect(() => {
225
+ if (!isFocused) {
226
+ return;
227
+ }
228
+ const handlePointerDown = () => setPointerDown(true);
229
+ const handlePointerUp = () => setPointerDown(false);
230
+ document.addEventListener("pointerdown", handlePointerDown);
231
+ document.addEventListener("pointerup", handlePointerUp);
232
+ return () => {
233
+ document.removeEventListener("pointerdown", handlePointerDown);
234
+ document.removeEventListener("pointerup", handlePointerUp);
235
+ };
236
+ }, [isFocused]);
237
+ useObservable.useObservable(onEditorChange, () => {
238
+ setReference(null);
239
+ requestAnimationFrame(() => {
240
+ const domSelection = window.getSelection();
241
+ if (!editor.selection || slate.Range.isCollapsed(editor.selection) || !domSelection || !domSelection.rangeCount) {
242
+ setHasFloatingToolbarRange(false);
243
+ setReference(null);
244
+ } else {
245
+ setHasFloatingToolbarRange(true);
246
+ const domRange = domSelection.getRangeAt(0);
247
+ setReference(domRange);
248
+ }
249
+ });
250
+ });
251
+ return /* @__PURE__ */ React.createElement(Persist.Persist, null, isOpen ? /* @__PURE__ */ React.createElement(contexts.ComposerFloatingToolbarContext.Provider, {
252
+ value: {
253
+ id,
254
+ placement,
255
+ dir,
256
+ ref: contentRef
257
+ }
258
+ }, /* @__PURE__ */ React.createElement(Portal.Portal, {
259
+ ref: setFloating,
260
+ container: portalContainer,
261
+ style: {
262
+ position: strategy,
263
+ top: 0,
264
+ left: 0,
265
+ transform: isPositioned ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)` : "translate3d(0, -200%, 0)",
266
+ minWidth: "max-content",
267
+ zIndex: contentZIndex
268
+ }
269
+ }, /* @__PURE__ */ React.createElement(FloatingToolbar, null))) : null);
270
+ }
271
+ const ComposerFloatingToolbar = React.forwardRef(({ children, onPointerDown, style, asChild, ...props }, forwardedRef) => {
272
+ const [isPresent] = Persist.usePersist();
273
+ const ref = React.useRef(null);
274
+ const {
275
+ id,
276
+ ref: contentRef,
277
+ placement,
278
+ dir
279
+ } = contexts.useComposerFloatingToolbarContext(COMPOSER_FLOATING_TOOLBAR_NAME);
280
+ const mergedRefs = useRefs.useRefs(forwardedRef, contentRef, ref);
281
+ const [side, align] = React.useMemo(
282
+ () => utils.getSideAndAlignFromFloatingPlacement(placement),
283
+ [placement]
284
+ );
285
+ const Component = asChild ? reactSlot.Slot : "div";
286
+ Persist.useAnimationPersist(ref);
287
+ const handlePointerDown = React.useCallback(
288
+ (event) => {
289
+ onPointerDown?.(event);
290
+ event.preventDefault();
291
+ event.stopPropagation();
292
+ },
293
+ [onPointerDown]
294
+ );
295
+ return /* @__PURE__ */ React.createElement(Component, {
296
+ dir,
297
+ role: "toolbar",
298
+ id,
299
+ "aria-label": "Floating toolbar",
300
+ ...props,
301
+ onPointerDown: handlePointerDown,
302
+ "data-state": isPresent ? "open" : "closed",
303
+ "data-side": side,
304
+ "data-align": align,
305
+ style: {
306
+ display: "flex",
307
+ flexDirection: "row",
308
+ maxWidth: "var(--lb-composer-floating-available-width)",
309
+ overflowX: "auto",
310
+ ...style
311
+ },
312
+ ref: mergedRefs
313
+ }, children);
314
+ });
208
315
  function ComposerEditorElement({
209
316
  Mention,
210
317
  Link,
@@ -292,7 +399,7 @@ const ComposerSuggestions = React.forwardRef(({ children, style, asChild, ...pro
292
399
  } = contexts.useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_NAME);
293
400
  const mergedRefs = useRefs.useRefs(forwardedRef, contentRef, ref);
294
401
  const [side, align] = React.useMemo(
295
- () => utils.getSideAndAlignFromPlacement(placement),
402
+ () => utils.getSideAndAlignFromFloatingPlacement(placement),
296
403
  [placement]
297
404
  );
298
405
  const Component = asChild ? reactSlot.Slot : "div";
@@ -306,7 +413,7 @@ const ComposerSuggestions = React.forwardRef(({ children, style, asChild, ...pro
306
413
  style: {
307
414
  display: "flex",
308
415
  flexDirection: "column",
309
- maxHeight: "var(--lb-composer-suggestions-available-height)",
416
+ maxHeight: "var(--lb-composer-floating-available-height)",
310
417
  overflowY: "auto",
311
418
  ...style
312
419
  },
@@ -418,10 +525,12 @@ const ComposerEditor = React.forwardRef(
418
525
  dir,
419
526
  ...props
420
527
  }, forwardedRef) => {
421
- const { editor, validate, setFocused, roomId } = contexts.useComposerEditorContext();
528
+ const client = _private.useClientOrNull();
529
+ const { editor, validate, setFocused, onEditorChange, roomId } = contexts.useComposerEditorContext();
422
530
  const {
423
531
  submit,
424
532
  focus,
533
+ blur,
425
534
  select,
426
535
  canSubmit,
427
536
  isDisabled: isComposerDisabled,
@@ -432,10 +541,12 @@ const ComposerEditor = React.forwardRef(
432
541
  const initialEditorValue = React.useMemo(() => {
433
542
  return utils.commentBodyToComposerBody(initialBody);
434
543
  }, [initialBody]);
435
- const { Link, Mention, MentionSuggestions } = React.useMemo(
544
+ const { Link, Mention, MentionSuggestions, FloatingToolbar } = React.useMemo(
436
545
  () => ({ ...defaultEditorComponents, ...components }),
437
546
  [components]
438
547
  );
548
+ const [hasFloatingToolbarRange, setHasFloatingToolbarRange] = React.useState(false);
549
+ const hasResolveMentionSuggestions = client ? client[core.kInternal].resolveMentionSuggestions !== void 0 : true;
439
550
  const [mentionDraft, setMentionDraft] = React.useState();
440
551
  const mentionSuggestions = _private.useMentionSuggestions(
441
552
  roomId,
@@ -448,6 +559,10 @@ const ComposerEditor = React.forwardRef(
448
559
  setSelectedMentionSuggestionIndex
449
560
  ] = useIndex.useIndex(0, mentionSuggestions?.length ?? 0);
450
561
  const id = useId.useId();
562
+ const floatingToolbarId = React.useMemo(
563
+ () => `liveblocks-floating-toolbar-${id}`,
564
+ [id]
565
+ );
451
566
  const suggestionsListId = React.useMemo(
452
567
  () => `liveblocks-suggestions-list-${id}`,
453
568
  [id]
@@ -469,9 +584,9 @@ const ComposerEditor = React.forwardRef(
469
584
  const handleChange = React.useCallback(
470
585
  (value) => {
471
586
  validate(value);
472
- setMentionDraft(mentions.getMentionDraftAtSelection(editor));
587
+ onEditorChange.notify();
473
588
  },
474
- [editor, validate]
589
+ [validate, onEditorChange]
475
590
  );
476
591
  const createMention = React.useCallback(
477
592
  (userId) => {
@@ -517,9 +632,15 @@ const ComposerEditor = React.forwardRef(
517
632
  setSelectedMentionSuggestionIndex(0);
518
633
  }
519
634
  } else {
635
+ if (hasFloatingToolbarRange) {
636
+ if (isKey.isKey(event, "Escape")) {
637
+ event.preventDefault();
638
+ setHasFloatingToolbarRange(false);
639
+ }
640
+ }
520
641
  if (isKey.isKey(event, "Escape")) {
521
642
  event.preventDefault();
522
- slateReact.ReactEditor.blur(editor);
643
+ blur();
523
644
  }
524
645
  if (isKey.isKey(event, "Enter", { shift: false })) {
525
646
  event.preventDefault();
@@ -550,16 +671,18 @@ const ComposerEditor = React.forwardRef(
550
671
  }
551
672
  },
552
673
  [
553
- createMention,
554
- editor,
555
- canSubmit,
674
+ onKeyDown,
556
675
  mentionDraft,
557
676
  mentionSuggestions,
558
- selectedMentionSuggestionIndex,
559
- onKeyDown,
677
+ hasFloatingToolbarRange,
678
+ editor,
560
679
  setNextSelectedMentionSuggestionIndex,
561
680
  setPreviousSelectedMentionSuggestionIndex,
681
+ selectedMentionSuggestionIndex,
682
+ createMention,
562
683
  setSelectedMentionSuggestionIndex,
684
+ blur,
685
+ canSubmit,
563
686
  submit
564
687
  ]
565
688
  );
@@ -594,7 +717,7 @@ const ComposerEditor = React.forwardRef(
594
717
  },
595
718
  [setSelectedMentionSuggestionIndex, mentionSuggestions]
596
719
  );
597
- const propsWhileSuggesting = React.useMemo(
720
+ const additionalProps = React.useMemo(
598
721
  () => mentionDraft ? {
599
722
  role: "combobox",
600
723
  "aria-autocomplete": "list",
@@ -603,23 +726,28 @@ const ComposerEditor = React.forwardRef(
603
726
  "aria-activedescendant": suggestionsListItemId(
604
727
  selectedMentionSuggestionUserId
605
728
  )
729
+ } : hasFloatingToolbarRange ? {
730
+ "aria-haspopup": true,
731
+ "aria-controls": floatingToolbarId
606
732
  } : {},
607
733
  [
608
734
  mentionDraft,
609
735
  suggestionsListId,
610
736
  suggestionsListItemId,
611
- selectedMentionSuggestionUserId
737
+ selectedMentionSuggestionUserId,
738
+ hasFloatingToolbarRange,
739
+ floatingToolbarId
612
740
  ]
613
741
  );
614
742
  React.useImperativeHandle(forwardedRef, () => {
615
743
  return slateReact.ReactEditor.toDOMNode(editor, editor);
616
744
  }, [editor]);
617
- React.useEffect(() => {
745
+ useLayoutEffect.useLayoutEffect(() => {
618
746
  if (autoFocus) {
619
747
  focus();
620
748
  }
621
749
  }, [autoFocus, editor, focus]);
622
- React.useEffect(() => {
750
+ useLayoutEffect.useLayoutEffect(() => {
623
751
  if (isFocused && editor.selection === null) {
624
752
  select();
625
753
  }
@@ -635,7 +763,7 @@ const ComposerEditor = React.forwardRef(
635
763
  "aria-label": "Composer editor",
636
764
  "data-focused": isFocused || void 0,
637
765
  "data-disabled": isDisabled || void 0,
638
- ...propsWhileSuggesting,
766
+ ...additionalProps,
639
767
  ...props,
640
768
  readOnly: isDisabled,
641
769
  disabled: isDisabled,
@@ -645,9 +773,10 @@ const ComposerEditor = React.forwardRef(
645
773
  renderElement,
646
774
  renderLeaf: ComposerEditorLeaf,
647
775
  renderPlaceholder: ComposerEditorPlaceholder
648
- }), /* @__PURE__ */ React.createElement(ComposerEditorMentionSuggestionsWrapper, {
776
+ }), hasResolveMentionSuggestions && /* @__PURE__ */ React.createElement(ComposerEditorMentionSuggestionsWrapper, {
649
777
  dir,
650
778
  mentionDraft,
779
+ setMentionDraft,
651
780
  selectedUserId: selectedMentionSuggestionUserId,
652
781
  setSelectedUserId: setSelectedMentionSuggestionUserId,
653
782
  userIds: mentionSuggestions,
@@ -655,6 +784,12 @@ const ComposerEditor = React.forwardRef(
655
784
  itemId: suggestionsListItemId,
656
785
  onItemSelect: createMention,
657
786
  MentionSuggestions
787
+ }), FloatingToolbar && /* @__PURE__ */ React.createElement(ComposerEditorFloatingToolbarWrapper, {
788
+ dir,
789
+ id: floatingToolbarId,
790
+ hasFloatingToolbarRange,
791
+ setHasFloatingToolbarRange,
792
+ FloatingToolbar
658
793
  }));
659
794
  }
660
795
  );
@@ -713,6 +848,7 @@ const ComposerForm = React.forwardRef(
713
848
  const canSubmit = React.useMemo(() => {
714
849
  return !isEmpty$1 && !isUploadingAttachments;
715
850
  }, [isEmpty$1, isUploadingAttachments]);
851
+ const [marks$1, setMarks] = React.useState(marks.getMarks);
716
852
  const ref = React.useRef(null);
717
853
  const mergedRefs = useRefs.useRefs(forwardedRef, ref);
718
854
  const fileInputRef = React.useRef(null);
@@ -751,6 +887,7 @@ const ComposerForm = React.forwardRef(
751
887
  pasteFilesAsAttachments
752
888
  })
753
889
  );
890
+ const onEditorChange = useInitial.useInitial(core.makeEventSource);
754
891
  const validate = React.useCallback(
755
892
  (value) => {
756
893
  setEmpty(isEmpty.isEmpty(editor, value));
@@ -776,10 +913,7 @@ const ComposerForm = React.forwardRef(
776
913
  });
777
914
  }, [editor]);
778
915
  const select = React.useCallback(() => {
779
- slate.Transforms.select(editor, {
780
- anchor: slate.Editor.end(editor, []),
781
- focus: slate.Editor.end(editor, [])
782
- });
916
+ slate.Transforms.select(editor, slate.Editor.end(editor, []));
783
917
  }, [editor]);
784
918
  const focus = React.useCallback(
785
919
  (resetSelection = true) => {
@@ -885,11 +1019,21 @@ const ComposerForm = React.forwardRef(
885
1019
  const stopPropagation = React.useCallback((event) => {
886
1020
  event.stopPropagation();
887
1021
  }, []);
1022
+ const toggleMark = React.useCallback(
1023
+ (mark) => {
1024
+ marks.toggleMark(editor, mark);
1025
+ },
1026
+ [editor]
1027
+ );
1028
+ useObservable.useObservable(onEditorChange, () => {
1029
+ setMarks(marks.getMarks(editor));
1030
+ });
888
1031
  return /* @__PURE__ */ React.createElement(contexts.ComposerEditorContext.Provider, {
889
1032
  value: {
890
1033
  editor,
891
1034
  validate,
892
1035
  setFocused,
1036
+ onEditorChange,
893
1037
  roomId
894
1038
  }
895
1039
  }, /* @__PURE__ */ React.createElement(contexts.ComposerAttachmentsContext.Provider, {
@@ -915,7 +1059,9 @@ const ComposerForm = React.forwardRef(
915
1059
  insertText,
916
1060
  attachments,
917
1061
  attachFiles,
918
- removeAttachment
1062
+ removeAttachment,
1063
+ toggleMark,
1064
+ marks: marks$1
919
1065
  }
920
1066
  }, /* @__PURE__ */ React.createElement(Component, {
921
1067
  ...props,
@@ -995,10 +1141,36 @@ const ComposerAttachmentsDropArea = React.forwardRef(
995
1141
  });
996
1142
  }
997
1143
  );
1144
+ const ComposerMarkToggle = React.forwardRef(
1145
+ ({ children, mark, onValueChange, onClick, asChild, ...props }, forwardedRef) => {
1146
+ const Component = asChild ? reactSlot.Slot : "button";
1147
+ const { marks, toggleMark } = contexts.useComposer();
1148
+ const handleClick = React.useCallback(
1149
+ (event) => {
1150
+ onClick?.(event);
1151
+ if (!event.isDefaultPrevented()) {
1152
+ toggleMark(mark);
1153
+ onValueChange?.(mark);
1154
+ }
1155
+ },
1156
+ [mark, onClick, onValueChange, toggleMark]
1157
+ );
1158
+ return /* @__PURE__ */ React.createElement(TogglePrimitive__namespace.Root, {
1159
+ asChild: true,
1160
+ pressed: marks[mark],
1161
+ onClick: handleClick,
1162
+ ...props
1163
+ }, /* @__PURE__ */ React.createElement(Component, {
1164
+ ...props,
1165
+ ref: forwardedRef
1166
+ }, children));
1167
+ }
1168
+ );
998
1169
  if (process.env.NODE_ENV !== "production") {
999
1170
  ComposerAttachFiles.displayName = COMPOSER_ATTACH_FILES_NAME;
1000
1171
  ComposerAttachmentsDropArea.displayName = COMPOSER_ATTACHMENTS_DROP_AREA_NAME;
1001
1172
  ComposerEditor.displayName = COMPOSER_EDITOR_NAME;
1173
+ ComposerFloatingToolbar.displayName = COMPOSER_FLOATING_TOOLBAR_NAME;
1002
1174
  ComposerForm.displayName = COMPOSER_FORM_NAME;
1003
1175
  ComposerMention.displayName = COMPOSER_MENTION_NAME;
1004
1176
  ComposerLink.displayName = COMPOSER_LINK_NAME;
@@ -1006,13 +1178,16 @@ if (process.env.NODE_ENV !== "production") {
1006
1178
  ComposerSuggestions.displayName = COMPOSER_SUGGESTIONS_NAME;
1007
1179
  ComposerSuggestionsList.displayName = COMPOSER_SUGGESTIONS_LIST_NAME;
1008
1180
  ComposerSuggestionsListItem.displayName = COMPOSER_SUGGESTIONS_LIST_ITEM_NAME;
1181
+ ComposerMarkToggle.displayName = COMPOSER_MARK_TOGGLE_NAME;
1009
1182
  }
1010
1183
 
1011
1184
  exports.AttachFiles = ComposerAttachFiles;
1012
1185
  exports.AttachmentsDropArea = ComposerAttachmentsDropArea;
1013
1186
  exports.Editor = ComposerEditor;
1187
+ exports.FloatingToolbar = ComposerFloatingToolbar;
1014
1188
  exports.Form = ComposerForm;
1015
1189
  exports.Link = ComposerLink;
1190
+ exports.MarkToggle = ComposerMarkToggle;
1016
1191
  exports.Mention = ComposerMention;
1017
1192
  exports.Submit = ComposerSubmit;
1018
1193
  exports.Suggestions = ComposerSuggestions;