@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.
- package/dist/_private/index.d.mts +1 -1
- package/dist/_private/index.d.ts +1 -1
- package/dist/components/Comment.js +2 -0
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Comment.mjs +2 -0
- package/dist/components/Comment.mjs.map +1 -1
- package/dist/components/Composer.js +74 -6
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/Composer.mjs +77 -9
- package/dist/components/Composer.mjs.map +1 -1
- package/dist/components/HistoryVersionSummary.js +1 -0
- package/dist/components/HistoryVersionSummary.js.map +1 -1
- package/dist/components/HistoryVersionSummary.mjs +1 -0
- package/dist/components/HistoryVersionSummary.mjs.map +1 -1
- package/dist/components/Thread.js +3 -0
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/Thread.mjs +3 -0
- package/dist/components/Thread.mjs.map +1 -1
- package/dist/components/internal/Button.js.map +1 -1
- package/dist/components/internal/Button.mjs.map +1 -1
- package/dist/icons/Bold.js +15 -0
- package/dist/icons/Bold.js.map +1 -0
- package/dist/icons/Bold.mjs +13 -0
- package/dist/icons/Bold.mjs.map +1 -0
- package/dist/icons/Code.js +15 -0
- package/dist/icons/Code.js.map +1 -0
- package/dist/icons/Code.mjs +13 -0
- package/dist/icons/Code.mjs.map +1 -0
- package/dist/icons/Italic.js +15 -0
- package/dist/icons/Italic.js.map +1 -0
- package/dist/icons/Italic.mjs +13 -0
- package/dist/icons/Italic.mjs.map +1 -0
- package/dist/icons/Strikethrough.js +15 -0
- package/dist/icons/Strikethrough.js.map +1 -0
- package/dist/icons/Strikethrough.mjs +13 -0
- package/dist/icons/Strikethrough.mjs.map +1 -0
- package/dist/index.d.mts +94 -103
- package/dist/index.d.ts +94 -103
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/overrides.js +15 -0
- package/dist/overrides.js.map +1 -1
- package/dist/overrides.mjs +15 -0
- package/dist/overrides.mjs.map +1 -1
- package/dist/primitives/Composer/contexts.js +12 -0
- package/dist/primitives/Composer/contexts.js.map +1 -1
- package/dist/primitives/Composer/contexts.mjs +11 -1
- package/dist/primitives/Composer/contexts.mjs.map +1 -1
- package/dist/primitives/Composer/index.js +251 -76
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/index.mjs +239 -85
- package/dist/primitives/Composer/index.mjs.map +1 -1
- package/dist/primitives/Composer/utils.js +94 -21
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Composer/utils.mjs +91 -20
- package/dist/primitives/Composer/utils.mjs.map +1 -1
- package/dist/primitives/index.d.mts +57 -1
- package/dist/primitives/index.d.ts +57 -1
- package/dist/slate/plugins/auto-formatting.js +1 -2
- package/dist/slate/plugins/auto-formatting.js.map +1 -1
- package/dist/slate/plugins/auto-formatting.mjs +1 -2
- package/dist/slate/plugins/auto-formatting.mjs.map +1 -1
- package/dist/slate/plugins/auto-links.js +3 -2
- package/dist/slate/plugins/auto-links.js.map +1 -1
- package/dist/slate/plugins/auto-links.mjs +2 -1
- package/dist/slate/plugins/auto-links.mjs.map +1 -1
- package/dist/slate/plugins/custom-links.js +3 -2
- package/dist/slate/plugins/custom-links.js.map +1 -1
- package/dist/slate/plugins/custom-links.mjs +2 -1
- package/dist/slate/plugins/custom-links.mjs.map +1 -1
- package/dist/slate/plugins/mentions.js +3 -4
- package/dist/slate/plugins/mentions.js.map +1 -1
- package/dist/slate/plugins/mentions.mjs +4 -5
- package/dist/slate/plugins/mentions.mjs.map +1 -1
- package/dist/slate/utils/marks.js +27 -8
- package/dist/slate/utils/marks.js.map +1 -1
- package/dist/slate/utils/marks.mjs +27 -10
- package/dist/slate/utils/marks.mjs.map +1 -1
- package/dist/utils/use-observable.js +15 -0
- package/dist/utils/use-observable.js.map +1 -0
- package/dist/utils/use-observable.mjs +13 -0
- package/dist/utils/use-observable.mjs.map +1 -0
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +4 -4
- package/src/styles/constants.css +1 -1
- package/src/styles/index.css +70 -9
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/slate/utils/is-selection-collapsed.js +0 -10
- package/dist/slate/utils/is-selection-collapsed.js.map +0 -1
- package/dist/slate/utils/is-selection-collapsed.mjs +0 -8
- package/dist/slate/utils/is-selection-collapsed.mjs.map +0 -1
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
|
7
|
-
import {
|
|
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 {
|
|
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 {
|
|
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
|
|
120
|
-
|
|
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
|
-
} =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
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
|
-
|
|
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,
|
|
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
|
-
() =>
|
|
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-
|
|
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
|
|
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
|
-
|
|
566
|
+
onEditorChange.notify();
|
|
471
567
|
},
|
|
472
|
-
[
|
|
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
|
-
|
|
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
|
-
|
|
552
|
-
editor,
|
|
553
|
-
canSubmit,
|
|
653
|
+
onKeyDown,
|
|
554
654
|
mentionDraft,
|
|
555
655
|
mentionSuggestions,
|
|
556
|
-
|
|
557
|
-
|
|
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
|
|
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
|
-
|
|
724
|
+
useLayoutEffect(() => {
|
|
616
725
|
if (autoFocus) {
|
|
617
726
|
focus();
|
|
618
727
|
}
|
|
619
728
|
}, [autoFocus, editor, focus]);
|
|
620
|
-
|
|
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
|
-
...
|
|
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
|