@liveblocks/react-ui 1.12.0-initial1
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/README.md +65 -0
- package/dist/components/Comment.js +473 -0
- package/dist/components/Comment.js.map +1 -0
- package/dist/components/Comment.mjs +447 -0
- package/dist/components/Comment.mjs.map +1 -0
- package/dist/components/Composer.js +299 -0
- package/dist/components/Composer.js.map +1 -0
- package/dist/components/Composer.mjs +297 -0
- package/dist/components/Composer.mjs.map +1 -0
- package/dist/components/InboxNotification.js +374 -0
- package/dist/components/InboxNotification.js.map +1 -0
- package/dist/components/InboxNotification.mjs +372 -0
- package/dist/components/InboxNotification.mjs.map +1 -0
- package/dist/components/InboxNotificationList.js +19 -0
- package/dist/components/InboxNotificationList.js.map +1 -0
- package/dist/components/InboxNotificationList.mjs +17 -0
- package/dist/components/InboxNotificationList.mjs.map +1 -0
- package/dist/components/Thread.js +188 -0
- package/dist/components/Thread.js.map +1 -0
- package/dist/components/Thread.mjs +167 -0
- package/dist/components/Thread.mjs.map +1 -0
- package/dist/components/internal/Attribution.js +26 -0
- package/dist/components/internal/Attribution.js.map +1 -0
- package/dist/components/internal/Attribution.mjs +24 -0
- package/dist/components/internal/Attribution.mjs.map +1 -0
- package/dist/components/internal/Avatar.js +40 -0
- package/dist/components/internal/Avatar.js.map +1 -0
- package/dist/components/internal/Avatar.mjs +38 -0
- package/dist/components/internal/Avatar.mjs.map +1 -0
- package/dist/components/internal/Button.js +24 -0
- package/dist/components/internal/Button.js.map +1 -0
- package/dist/components/internal/Button.mjs +22 -0
- package/dist/components/internal/Button.mjs.map +1 -0
- package/dist/components/internal/Dropdown.js +72 -0
- package/dist/components/internal/Dropdown.js.map +1 -0
- package/dist/components/internal/Dropdown.mjs +47 -0
- package/dist/components/internal/Dropdown.mjs.map +1 -0
- package/dist/components/internal/Emoji.js +18 -0
- package/dist/components/internal/Emoji.js.map +1 -0
- package/dist/components/internal/Emoji.mjs +16 -0
- package/dist/components/internal/Emoji.mjs.map +1 -0
- package/dist/components/internal/EmojiPicker.js +186 -0
- package/dist/components/internal/EmojiPicker.js.map +1 -0
- package/dist/components/internal/EmojiPicker.mjs +162 -0
- package/dist/components/internal/EmojiPicker.mjs.map +1 -0
- package/dist/components/internal/Icon.js +28 -0
- package/dist/components/internal/Icon.js.map +1 -0
- package/dist/components/internal/Icon.mjs +24 -0
- package/dist/components/internal/Icon.mjs.map +1 -0
- package/dist/components/internal/InboxNotificationThread.js +116 -0
- package/dist/components/internal/InboxNotificationThread.js.map +1 -0
- package/dist/components/internal/InboxNotificationThread.mjs +112 -0
- package/dist/components/internal/InboxNotificationThread.mjs.map +1 -0
- package/dist/components/internal/List.js +34 -0
- package/dist/components/internal/List.js.map +1 -0
- package/dist/components/internal/List.mjs +32 -0
- package/dist/components/internal/List.mjs.map +1 -0
- package/dist/components/internal/Room.js +22 -0
- package/dist/components/internal/Room.js.map +1 -0
- package/dist/components/internal/Room.mjs +20 -0
- package/dist/components/internal/Room.mjs.map +1 -0
- package/dist/components/internal/Tooltip.js +91 -0
- package/dist/components/internal/Tooltip.js.map +1 -0
- package/dist/components/internal/Tooltip.mjs +65 -0
- package/dist/components/internal/Tooltip.mjs.map +1 -0
- package/dist/components/internal/User.js +41 -0
- package/dist/components/internal/User.js.map +1 -0
- package/dist/components/internal/User.mjs +39 -0
- package/dist/components/internal/User.mjs.map +1 -0
- package/dist/components.js +64 -0
- package/dist/components.js.map +1 -0
- package/dist/components.mjs +41 -0
- package/dist/components.mjs.map +1 -0
- package/dist/config.js +33 -0
- package/dist/config.js.map +1 -0
- package/dist/config.mjs +30 -0
- package/dist/config.mjs.map +1 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -0
- package/dist/constants.mjs +6 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/icons/ArrowDown.js +15 -0
- package/dist/icons/ArrowDown.js.map +1 -0
- package/dist/icons/ArrowDown.mjs +13 -0
- package/dist/icons/ArrowDown.mjs.map +1 -0
- package/dist/icons/Check.js +15 -0
- package/dist/icons/Check.js.map +1 -0
- package/dist/icons/Check.mjs +13 -0
- package/dist/icons/Check.mjs.map +1 -0
- package/dist/icons/Cross.js +17 -0
- package/dist/icons/Cross.js.map +1 -0
- package/dist/icons/Cross.mjs +15 -0
- package/dist/icons/Cross.mjs.map +1 -0
- package/dist/icons/Delete.js +15 -0
- package/dist/icons/Delete.js.map +1 -0
- package/dist/icons/Delete.mjs +13 -0
- package/dist/icons/Delete.mjs.map +1 -0
- package/dist/icons/Edit.js +15 -0
- package/dist/icons/Edit.js.map +1 -0
- package/dist/icons/Edit.mjs +13 -0
- package/dist/icons/Edit.mjs.map +1 -0
- package/dist/icons/Ellipsis.js +26 -0
- package/dist/icons/Ellipsis.js.map +1 -0
- package/dist/icons/Ellipsis.mjs +24 -0
- package/dist/icons/Ellipsis.mjs.map +1 -0
- package/dist/icons/Emoji.js +27 -0
- package/dist/icons/Emoji.js.map +1 -0
- package/dist/icons/Emoji.mjs +25 -0
- package/dist/icons/Emoji.mjs.map +1 -0
- package/dist/icons/EmojiAdd.js +29 -0
- package/dist/icons/EmojiAdd.js.map +1 -0
- package/dist/icons/EmojiAdd.mjs +27 -0
- package/dist/icons/EmojiAdd.mjs.map +1 -0
- package/dist/icons/Mention.js +17 -0
- package/dist/icons/Mention.js.map +1 -0
- package/dist/icons/Mention.mjs +15 -0
- package/dist/icons/Mention.mjs.map +1 -0
- package/dist/icons/Missing.js +19 -0
- package/dist/icons/Missing.js.map +1 -0
- package/dist/icons/Missing.mjs +17 -0
- package/dist/icons/Missing.mjs.map +1 -0
- package/dist/icons/Resolve.js +19 -0
- package/dist/icons/Resolve.js.map +1 -0
- package/dist/icons/Resolve.mjs +17 -0
- package/dist/icons/Resolve.mjs.map +1 -0
- package/dist/icons/Resolved.js +21 -0
- package/dist/icons/Resolved.js.map +1 -0
- package/dist/icons/Resolved.mjs +19 -0
- package/dist/icons/Resolved.mjs.map +1 -0
- package/dist/icons/Search.js +15 -0
- package/dist/icons/Search.js.map +1 -0
- package/dist/icons/Search.mjs +13 -0
- package/dist/icons/Search.mjs.map +1 -0
- package/dist/icons/Send.js +15 -0
- package/dist/icons/Send.js.map +1 -0
- package/dist/icons/Send.mjs +13 -0
- package/dist/icons/Send.mjs.map +1 -0
- package/dist/icons/Spinner.js +22 -0
- package/dist/icons/Spinner.js.map +1 -0
- package/dist/icons/Spinner.mjs +20 -0
- package/dist/icons/Spinner.mjs.map +1 -0
- package/dist/index.d.mts +476 -0
- package/dist/index.d.ts +476 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +11 -0
- package/dist/index.mjs.map +1 -0
- package/dist/overrides.js +100 -0
- package/dist/overrides.js.map +1 -0
- package/dist/overrides.mjs +77 -0
- package/dist/overrides.mjs.map +1 -0
- package/dist/primitives/Comment/index.js +113 -0
- package/dist/primitives/Comment/index.js.map +1 -0
- package/dist/primitives/Comment/index.mjs +109 -0
- package/dist/primitives/Comment/index.mjs.map +1 -0
- package/dist/primitives/Comment/utils.js +25 -0
- package/dist/primitives/Comment/utils.js.map +1 -0
- package/dist/primitives/Comment/utils.mjs +20 -0
- package/dist/primitives/Comment/utils.mjs.map +1 -0
- package/dist/primitives/Composer/contexts.js +34 -0
- package/dist/primitives/Composer/contexts.js.map +1 -0
- package/dist/primitives/Composer/contexts.mjs +27 -0
- package/dist/primitives/Composer/contexts.mjs.map +1 -0
- package/dist/primitives/Composer/index.js +771 -0
- package/dist/primitives/Composer/index.js.map +1 -0
- package/dist/primitives/Composer/index.mjs +762 -0
- package/dist/primitives/Composer/index.mjs.map +1 -0
- package/dist/primitives/Composer/utils.js +102 -0
- package/dist/primitives/Composer/utils.js.map +1 -0
- package/dist/primitives/Composer/utils.mjs +93 -0
- package/dist/primitives/Composer/utils.mjs.map +1 -0
- package/dist/primitives/EmojiPicker/contexts.js +19 -0
- package/dist/primitives/EmojiPicker/contexts.js.map +1 -0
- package/dist/primitives/EmojiPicker/contexts.mjs +16 -0
- package/dist/primitives/EmojiPicker/contexts.mjs.map +1 -0
- package/dist/primitives/EmojiPicker/index.js +434 -0
- package/dist/primitives/EmojiPicker/index.js.map +1 -0
- package/dist/primitives/EmojiPicker/index.mjs +430 -0
- package/dist/primitives/EmojiPicker/index.mjs.map +1 -0
- package/dist/primitives/EmojiPicker/utils.js +329 -0
- package/dist/primitives/EmojiPicker/utils.js.map +1 -0
- package/dist/primitives/EmojiPicker/utils.mjs +325 -0
- package/dist/primitives/EmojiPicker/utils.mjs.map +1 -0
- package/dist/primitives/Timestamp.js +121 -0
- package/dist/primitives/Timestamp.js.map +1 -0
- package/dist/primitives/Timestamp.mjs +119 -0
- package/dist/primitives/Timestamp.mjs.map +1 -0
- package/dist/primitives/index.d.mts +502 -0
- package/dist/primitives/index.d.ts +502 -0
- package/dist/primitives/index.js +16 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/primitives/index.mjs +9 -0
- package/dist/primitives/index.mjs.map +1 -0
- package/dist/primitives/internal/Emoji.js +30 -0
- package/dist/primitives/internal/Emoji.js.map +1 -0
- package/dist/primitives/internal/Emoji.mjs +28 -0
- package/dist/primitives/internal/Emoji.mjs.map +1 -0
- package/dist/shared.js +21 -0
- package/dist/shared.js.map +1 -0
- package/dist/shared.mjs +19 -0
- package/dist/shared.mjs.map +1 -0
- package/dist/slate/plugins/auto-formatting.js +83 -0
- package/dist/slate/plugins/auto-formatting.js.map +1 -0
- package/dist/slate/plugins/auto-formatting.mjs +81 -0
- package/dist/slate/plugins/auto-formatting.mjs.map +1 -0
- package/dist/slate/plugins/auto-links.js +175 -0
- package/dist/slate/plugins/auto-links.js.map +1 -0
- package/dist/slate/plugins/auto-links.mjs +172 -0
- package/dist/slate/plugins/auto-links.mjs.map +1 -0
- package/dist/slate/plugins/empty-clear-formatting.js +18 -0
- package/dist/slate/plugins/empty-clear-formatting.js.map +1 -0
- package/dist/slate/plugins/empty-clear-formatting.mjs +16 -0
- package/dist/slate/plugins/empty-clear-formatting.mjs.map +1 -0
- package/dist/slate/plugins/mentions.js +112 -0
- package/dist/slate/plugins/mentions.js.map +1 -0
- package/dist/slate/plugins/mentions.mjs +105 -0
- package/dist/slate/plugins/mentions.mjs.map +1 -0
- package/dist/slate/utils/get-character.js +50 -0
- package/dist/slate/utils/get-character.js.map +1 -0
- package/dist/slate/utils/get-character.mjs +47 -0
- package/dist/slate/utils/get-character.mjs.map +1 -0
- package/dist/slate/utils/get-dom-range.js +17 -0
- package/dist/slate/utils/get-dom-range.js.map +1 -0
- package/dist/slate/utils/get-dom-range.mjs +15 -0
- package/dist/slate/utils/get-dom-range.mjs.map +1 -0
- package/dist/slate/utils/get-match-range.js +53 -0
- package/dist/slate/utils/get-match-range.js.map +1 -0
- package/dist/slate/utils/get-match-range.mjs +51 -0
- package/dist/slate/utils/get-match-range.mjs.map +1 -0
- package/dist/slate/utils/is-empty-string.js +8 -0
- package/dist/slate/utils/is-empty-string.js.map +1 -0
- package/dist/slate/utils/is-empty-string.mjs +6 -0
- package/dist/slate/utils/is-empty-string.mjs.map +1 -0
- package/dist/slate/utils/is-empty.js +10 -0
- package/dist/slate/utils/is-empty.js.map +1 -0
- package/dist/slate/utils/is-empty.mjs +8 -0
- package/dist/slate/utils/is-empty.mjs.map +1 -0
- package/dist/slate/utils/is-selection-collapsed.js +10 -0
- package/dist/slate/utils/is-selection-collapsed.js.map +1 -0
- package/dist/slate/utils/is-selection-collapsed.mjs +8 -0
- package/dist/slate/utils/is-selection-collapsed.mjs.map +1 -0
- package/dist/slate/utils/marks.js +43 -0
- package/dist/slate/utils/marks.js.map +1 -0
- package/dist/slate/utils/marks.mjs +38 -0
- package/dist/slate/utils/marks.mjs.map +1 -0
- package/dist/utils/Persist.js +85 -0
- package/dist/utils/Persist.js.map +1 -0
- package/dist/utils/Persist.mjs +81 -0
- package/dist/utils/Persist.mjs.map +1 -0
- package/dist/utils/Portal.js +27 -0
- package/dist/utils/Portal.js.map +1 -0
- package/dist/utils/Portal.mjs +25 -0
- package/dist/utils/Portal.mjs.map +1 -0
- package/dist/utils/capitalize.js +8 -0
- package/dist/utils/capitalize.js.map +1 -0
- package/dist/utils/capitalize.mjs +6 -0
- package/dist/utils/capitalize.mjs.map +1 -0
- package/dist/utils/chunk.js +12 -0
- package/dist/utils/chunk.js.map +1 -0
- package/dist/utils/chunk.mjs +10 -0
- package/dist/utils/chunk.mjs.map +1 -0
- package/dist/utils/clamp.js +8 -0
- package/dist/utils/clamp.js.map +1 -0
- package/dist/utils/clamp.mjs +6 -0
- package/dist/utils/clamp.mjs.map +1 -0
- package/dist/utils/class-names.js +8 -0
- package/dist/utils/class-names.js.map +1 -0
- package/dist/utils/class-names.mjs +6 -0
- package/dist/utils/class-names.mjs.map +1 -0
- package/dist/utils/exists.js +8 -0
- package/dist/utils/exists.js.map +1 -0
- package/dist/utils/exists.mjs +6 -0
- package/dist/utils/exists.mjs.map +1 -0
- package/dist/utils/find-last-index.js +15 -0
- package/dist/utils/find-last-index.js.map +1 -0
- package/dist/utils/find-last-index.mjs +13 -0
- package/dist/utils/find-last-index.mjs.map +1 -0
- package/dist/utils/flush-sync.js +12 -0
- package/dist/utils/flush-sync.js.map +1 -0
- package/dist/utils/flush-sync.mjs +10 -0
- package/dist/utils/flush-sync.mjs.map +1 -0
- package/dist/utils/get-initials.js +13 -0
- package/dist/utils/get-initials.js.map +1 -0
- package/dist/utils/get-initials.mjs +11 -0
- package/dist/utils/get-initials.mjs.map +1 -0
- package/dist/utils/intl.js +24 -0
- package/dist/utils/intl.js.map +1 -0
- package/dist/utils/intl.mjs +20 -0
- package/dist/utils/intl.mjs.map +1 -0
- package/dist/utils/is-apple.js +9 -0
- package/dist/utils/is-apple.js.map +1 -0
- package/dist/utils/is-apple.mjs +7 -0
- package/dist/utils/is-apple.mjs.map +1 -0
- package/dist/utils/is-key.js +26 -0
- package/dist/utils/is-key.js.map +1 -0
- package/dist/utils/is-key.mjs +24 -0
- package/dist/utils/is-key.mjs.map +1 -0
- package/dist/utils/memoize.js +19 -0
- package/dist/utils/memoize.js.map +1 -0
- package/dist/utils/memoize.mjs +17 -0
- package/dist/utils/memoize.mjs.map +1 -0
- package/dist/utils/pluralize.js +8 -0
- package/dist/utils/pluralize.js.map +1 -0
- package/dist/utils/pluralize.mjs +6 -0
- package/dist/utils/pluralize.mjs.map +1 -0
- package/dist/utils/request-idle-callback.js +15 -0
- package/dist/utils/request-idle-callback.js.map +1 -0
- package/dist/utils/request-idle-callback.mjs +12 -0
- package/dist/utils/request-idle-callback.mjs.map +1 -0
- package/dist/utils/request-submit.js +20 -0
- package/dist/utils/request-submit.js.map +1 -0
- package/dist/utils/request-submit.mjs +18 -0
- package/dist/utils/request-submit.mjs.map +1 -0
- package/dist/utils/url.js +22 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/utils/url.mjs +20 -0
- package/dist/utils/url.mjs.map +1 -0
- package/dist/utils/use-controllable-state.js +34 -0
- package/dist/utils/use-controllable-state.js.map +1 -0
- package/dist/utils/use-controllable-state.mjs +32 -0
- package/dist/utils/use-controllable-state.mjs.map +1 -0
- package/dist/utils/use-id.js +29 -0
- package/dist/utils/use-id.js.map +1 -0
- package/dist/utils/use-id.mjs +27 -0
- package/dist/utils/use-id.mjs.map +1 -0
- package/dist/utils/use-index.js +32 -0
- package/dist/utils/use-index.js.map +1 -0
- package/dist/utils/use-index.mjs +30 -0
- package/dist/utils/use-index.mjs.map +1 -0
- package/dist/utils/use-initial.js +10 -0
- package/dist/utils/use-initial.js.map +1 -0
- package/dist/utils/use-initial.mjs +8 -0
- package/dist/utils/use-initial.mjs.map +1 -0
- package/dist/utils/use-interval.js +24 -0
- package/dist/utils/use-interval.js.map +1 -0
- package/dist/utils/use-interval.mjs +22 -0
- package/dist/utils/use-interval.mjs.map +1 -0
- package/dist/utils/use-latest.js +14 -0
- package/dist/utils/use-latest.js.map +1 -0
- package/dist/utils/use-latest.mjs +12 -0
- package/dist/utils/use-latest.mjs.map +1 -0
- package/dist/utils/use-layout-effect.js +8 -0
- package/dist/utils/use-layout-effect.js.map +1 -0
- package/dist/utils/use-layout-effect.mjs +6 -0
- package/dist/utils/use-layout-effect.mjs.map +1 -0
- package/dist/utils/use-refs.js +24 -0
- package/dist/utils/use-refs.js.map +1 -0
- package/dist/utils/use-refs.mjs +22 -0
- package/dist/utils/use-refs.mjs.map +1 -0
- package/dist/utils/use-rerender.js +14 -0
- package/dist/utils/use-rerender.js.map +1 -0
- package/dist/utils/use-rerender.mjs +12 -0
- package/dist/utils/use-rerender.mjs.map +1 -0
- package/dist/utils/use-transition.js +12 -0
- package/dist/utils/use-transition.js.map +1 -0
- package/dist/utils/use-transition.mjs +10 -0
- package/dist/utils/use-transition.mjs.map +1 -0
- package/dist/utils/use-visible.js +48 -0
- package/dist/utils/use-visible.js.map +1 -0
- package/dist/utils/use-visible.mjs +46 -0
- package/dist/utils/use-visible.mjs.map +1 -0
- package/dist/utils/visually-hidden.js +17 -0
- package/dist/utils/visually-hidden.js.map +1 -0
- package/dist/utils/visually-hidden.mjs +15 -0
- package/dist/utils/visually-hidden.mjs.map +1 -0
- package/dist/utils/wrap.js +9 -0
- package/dist/utils/wrap.js.map +1 -0
- package/dist/utils/wrap.mjs +7 -0
- package/dist/utils/wrap.mjs.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/dist/version.mjs +6 -0
- package/dist/version.mjs.map +1 -0
- package/package.json +142 -0
- package/primitives/README.md +5 -0
- package/primitives/package.json +4 -0
- package/src/styles/constants.css +17 -0
- package/src/styles/dark/attributes.css +8 -0
- package/src/styles/dark/index.css +29 -0
- package/src/styles/dark/media-query.css +7 -0
- package/src/styles/index.css +1437 -0
- package/src/styles/utils.css +36 -0
- package/styles/dark/attributes.css +1 -0
- package/styles/dark/attributes.css.d.ts +1 -0
- package/styles/dark/attributes.css.map +1 -0
- package/styles/dark/media-query.css +1 -0
- package/styles/dark/media-query.css.d.ts +1 -0
- package/styles/dark/media-query.css.map +1 -0
- package/styles.css +1 -0
- package/styles.css.d.ts +1 -0
- package/styles.css.map +1 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var core = require('@liveblocks/core');
|
|
5
|
+
var react = require('@liveblocks/react');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var Emoji = require('../icons/Emoji.js');
|
|
8
|
+
var Mention = require('../icons/Mention.js');
|
|
9
|
+
var Send = require('../icons/Send.js');
|
|
10
|
+
var overrides = require('../overrides.js');
|
|
11
|
+
var index = require('../primitives/Composer/index.js');
|
|
12
|
+
var contexts = require('../primitives/Composer/contexts.js');
|
|
13
|
+
var mentions = require('../slate/plugins/mentions.js');
|
|
14
|
+
var classNames = require('../utils/class-names.js');
|
|
15
|
+
var useControllableState = require('../utils/use-controllable-state.js');
|
|
16
|
+
var Attribution = require('./internal/Attribution.js');
|
|
17
|
+
var Avatar = require('./internal/Avatar.js');
|
|
18
|
+
var Button = require('./internal/Button.js');
|
|
19
|
+
var EmojiPicker = require('./internal/EmojiPicker.js');
|
|
20
|
+
var Tooltip = require('./internal/Tooltip.js');
|
|
21
|
+
var User = require('./internal/User.js');
|
|
22
|
+
var TooltipPrimitive = require('@radix-ui/react-tooltip');
|
|
23
|
+
var PopoverPrimitive = require('@radix-ui/react-popover');
|
|
24
|
+
|
|
25
|
+
function ComposerInsertMentionEditorAction({
|
|
26
|
+
label,
|
|
27
|
+
className,
|
|
28
|
+
onClick,
|
|
29
|
+
...props
|
|
30
|
+
}) {
|
|
31
|
+
const { createMention } = contexts.useComposer();
|
|
32
|
+
const preventDefault = React.useCallback((event) => {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
}, []);
|
|
35
|
+
const handleClick = React.useCallback(
|
|
36
|
+
(event) => {
|
|
37
|
+
onClick?.(event);
|
|
38
|
+
if (!event.isDefaultPrevented()) {
|
|
39
|
+
event.stopPropagation();
|
|
40
|
+
createMention();
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
[createMention, onClick]
|
|
44
|
+
);
|
|
45
|
+
return /* @__PURE__ */ React.createElement(Tooltip.Tooltip, {
|
|
46
|
+
content: label
|
|
47
|
+
}, /* @__PURE__ */ React.createElement(Button.Button, {
|
|
48
|
+
className: classNames.classNames("lb-composer-editor-action", className),
|
|
49
|
+
onMouseDown: preventDefault,
|
|
50
|
+
onClick: handleClick,
|
|
51
|
+
"aria-label": label,
|
|
52
|
+
...props
|
|
53
|
+
}, /* @__PURE__ */ React.createElement(Mention.MentionIcon, {
|
|
54
|
+
className: "lb-button-icon"
|
|
55
|
+
})));
|
|
56
|
+
}
|
|
57
|
+
function ComposerInsertEmojiEditorAction({
|
|
58
|
+
label,
|
|
59
|
+
onPickerOpenChange,
|
|
60
|
+
className,
|
|
61
|
+
...props
|
|
62
|
+
}) {
|
|
63
|
+
const { insertText } = contexts.useComposer();
|
|
64
|
+
const preventDefault = React.useCallback((event) => {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
}, []);
|
|
67
|
+
return /* @__PURE__ */ React.createElement(EmojiPicker.EmojiPicker, {
|
|
68
|
+
onEmojiSelect: insertText,
|
|
69
|
+
onOpenChange: onPickerOpenChange
|
|
70
|
+
}, /* @__PURE__ */ React.createElement(Tooltip.Tooltip, {
|
|
71
|
+
content: label
|
|
72
|
+
}, /* @__PURE__ */ React.createElement(PopoverPrimitive.PopoverTrigger, {
|
|
73
|
+
asChild: true
|
|
74
|
+
}, /* @__PURE__ */ React.createElement(Button.Button, {
|
|
75
|
+
className: classNames.classNames("lb-composer-editor-action", className),
|
|
76
|
+
onMouseDown: preventDefault,
|
|
77
|
+
"aria-label": label,
|
|
78
|
+
...props
|
|
79
|
+
}, /* @__PURE__ */ React.createElement(Emoji.EmojiIcon, {
|
|
80
|
+
className: "lb-button-icon"
|
|
81
|
+
})))));
|
|
82
|
+
}
|
|
83
|
+
function ComposerMention({ userId }) {
|
|
84
|
+
return /* @__PURE__ */ React.createElement(index.Mention, {
|
|
85
|
+
className: "lb-composer-mention"
|
|
86
|
+
}, mentions.MENTION_CHARACTER, /* @__PURE__ */ React.createElement(User.User, {
|
|
87
|
+
userId
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
function ComposerMentionSuggestions({
|
|
91
|
+
userIds
|
|
92
|
+
}) {
|
|
93
|
+
return userIds.length > 0 ? /* @__PURE__ */ React.createElement(index.Suggestions, {
|
|
94
|
+
className: "lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions"
|
|
95
|
+
}, /* @__PURE__ */ React.createElement(index.SuggestionsList, {
|
|
96
|
+
className: "lb-composer-suggestions-list lb-composer-mention-suggestions-list"
|
|
97
|
+
}, userIds.map((userId) => /* @__PURE__ */ React.createElement(index.SuggestionsListItem, {
|
|
98
|
+
key: userId,
|
|
99
|
+
className: "lb-composer-suggestions-list-item lb-composer-mention-suggestion",
|
|
100
|
+
value: userId
|
|
101
|
+
}, /* @__PURE__ */ React.createElement(Avatar.Avatar, {
|
|
102
|
+
userId,
|
|
103
|
+
className: "lb-composer-mention-suggestion-avatar"
|
|
104
|
+
}), /* @__PURE__ */ React.createElement(User.User, {
|
|
105
|
+
userId,
|
|
106
|
+
className: "lb-composer-mention-suggestion-user"
|
|
107
|
+
}))))) : null;
|
|
108
|
+
}
|
|
109
|
+
function ComposerLink({ href, children }) {
|
|
110
|
+
return /* @__PURE__ */ React.createElement(index.Link, {
|
|
111
|
+
href,
|
|
112
|
+
className: "lb-composer-link"
|
|
113
|
+
}, children);
|
|
114
|
+
}
|
|
115
|
+
const editorComponents = {
|
|
116
|
+
Mention: ComposerMention,
|
|
117
|
+
MentionSuggestions: ComposerMentionSuggestions,
|
|
118
|
+
Link: ComposerLink
|
|
119
|
+
};
|
|
120
|
+
const ComposerWithContext = React.forwardRef(
|
|
121
|
+
({
|
|
122
|
+
defaultValue,
|
|
123
|
+
disabled,
|
|
124
|
+
autoFocus,
|
|
125
|
+
collapsed: controlledCollapsed,
|
|
126
|
+
defaultCollapsed,
|
|
127
|
+
onCollapsedChange: controlledOnCollapsedChange,
|
|
128
|
+
actions,
|
|
129
|
+
overrides: overrides$1,
|
|
130
|
+
showAttribution,
|
|
131
|
+
onFocus,
|
|
132
|
+
onBlur,
|
|
133
|
+
className,
|
|
134
|
+
...props
|
|
135
|
+
}, forwardedRef) => {
|
|
136
|
+
const client = react.useClient();
|
|
137
|
+
const hasResolveMentionSuggestions = client[core.kInternal].resolveMentionSuggestions !== void 0;
|
|
138
|
+
const { useSelf } = react.useRoomContextBundle();
|
|
139
|
+
const self = useSelf();
|
|
140
|
+
const isDisabled = React.useMemo(
|
|
141
|
+
() => disabled || !self?.canComment,
|
|
142
|
+
[disabled, self?.canComment]
|
|
143
|
+
);
|
|
144
|
+
const { isEmpty } = contexts.useComposer();
|
|
145
|
+
const $ = overrides.useOverrides(overrides$1);
|
|
146
|
+
const [isEmojiPickerOpen, setEmojiPickerOpen] = React.useState(false);
|
|
147
|
+
const [collapsed, onCollapsedChange] = useControllableState.useControllableState(
|
|
148
|
+
controlledCollapsed === void 0 && defaultCollapsed === void 0 ? false : controlledCollapsed,
|
|
149
|
+
controlledOnCollapsedChange,
|
|
150
|
+
defaultCollapsed
|
|
151
|
+
);
|
|
152
|
+
const preventDefault = React.useCallback((event) => {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
}, []);
|
|
155
|
+
const stopPropagation = React.useCallback((event) => {
|
|
156
|
+
event.stopPropagation();
|
|
157
|
+
}, []);
|
|
158
|
+
const handleEditorClick = React.useCallback(
|
|
159
|
+
(event) => {
|
|
160
|
+
event.stopPropagation();
|
|
161
|
+
if (isEmpty) {
|
|
162
|
+
onCollapsedChange?.(false);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
[isEmpty, onCollapsedChange]
|
|
166
|
+
);
|
|
167
|
+
const handleFocus = React.useCallback(
|
|
168
|
+
(event) => {
|
|
169
|
+
onFocus?.(event);
|
|
170
|
+
if (event.isDefaultPrevented()) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (isEmpty) {
|
|
174
|
+
onCollapsedChange?.(false);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
[isEmpty, onCollapsedChange, onFocus]
|
|
178
|
+
);
|
|
179
|
+
const handleBlur = React.useCallback(
|
|
180
|
+
(event) => {
|
|
181
|
+
onBlur?.(event);
|
|
182
|
+
if (event.isDefaultPrevented()) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const isOutside = !event.currentTarget.contains(event.relatedTarget);
|
|
186
|
+
if (isOutside && isEmpty && !isEmojiPickerOpen) {
|
|
187
|
+
onCollapsedChange?.(true);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
[isEmojiPickerOpen, isEmpty, onBlur, onCollapsedChange]
|
|
191
|
+
);
|
|
192
|
+
return /* @__PURE__ */ React.createElement("form", {
|
|
193
|
+
className: classNames.classNames(
|
|
194
|
+
"lb-root lb-composer lb-composer-form",
|
|
195
|
+
className
|
|
196
|
+
),
|
|
197
|
+
dir: $.dir,
|
|
198
|
+
...props,
|
|
199
|
+
ref: forwardedRef,
|
|
200
|
+
"data-collapsed": collapsed ? "" : void 0,
|
|
201
|
+
onFocus: handleFocus,
|
|
202
|
+
onBlur: handleBlur
|
|
203
|
+
}, /* @__PURE__ */ React.createElement(index.Editor, {
|
|
204
|
+
className: "lb-composer-editor",
|
|
205
|
+
onClick: handleEditorClick,
|
|
206
|
+
placeholder: $.COMPOSER_PLACEHOLDER,
|
|
207
|
+
defaultValue,
|
|
208
|
+
disabled: isDisabled,
|
|
209
|
+
autoFocus,
|
|
210
|
+
components: editorComponents,
|
|
211
|
+
dir: $.dir
|
|
212
|
+
}), !collapsed && /* @__PURE__ */ React.createElement("div", {
|
|
213
|
+
className: "lb-composer-footer"
|
|
214
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
215
|
+
className: "lb-composer-editor-actions"
|
|
216
|
+
}, hasResolveMentionSuggestions && /* @__PURE__ */ React.createElement(ComposerInsertMentionEditorAction, {
|
|
217
|
+
label: $.COMPOSER_INSERT_MENTION,
|
|
218
|
+
disabled: isDisabled
|
|
219
|
+
}), /* @__PURE__ */ React.createElement(ComposerInsertEmojiEditorAction, {
|
|
220
|
+
label: $.COMPOSER_INSERT_EMOJI,
|
|
221
|
+
onPickerOpenChange: setEmojiPickerOpen,
|
|
222
|
+
disabled: isDisabled
|
|
223
|
+
})), showAttribution && /* @__PURE__ */ React.createElement(Attribution.Attribution, null), /* @__PURE__ */ React.createElement("div", {
|
|
224
|
+
className: "lb-composer-actions"
|
|
225
|
+
}, actions ?? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Tooltip.ShortcutTooltip, {
|
|
226
|
+
content: $.COMPOSER_SEND,
|
|
227
|
+
shortcut: /* @__PURE__ */ React.createElement(Tooltip.ShortcutTooltipKey, {
|
|
228
|
+
name: "enter"
|
|
229
|
+
})
|
|
230
|
+
}, /* @__PURE__ */ React.createElement(index.Submit, {
|
|
231
|
+
disabled: isDisabled,
|
|
232
|
+
asChild: true
|
|
233
|
+
}, /* @__PURE__ */ React.createElement(Button.Button, {
|
|
234
|
+
onMouseDown: preventDefault,
|
|
235
|
+
onClick: stopPropagation,
|
|
236
|
+
className: "lb-composer-action",
|
|
237
|
+
variant: "primary",
|
|
238
|
+
"aria-label": $.COMPOSER_SEND
|
|
239
|
+
}, /* @__PURE__ */ React.createElement(Send.SendIcon, null))))))));
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
const Composer = React.forwardRef(
|
|
243
|
+
({
|
|
244
|
+
threadId,
|
|
245
|
+
commentId,
|
|
246
|
+
metadata,
|
|
247
|
+
onComposerSubmit,
|
|
248
|
+
...props
|
|
249
|
+
}, forwardedRef) => {
|
|
250
|
+
const { useCreateThread, useCreateComment, useEditComment } = react.useRoomContextBundle();
|
|
251
|
+
const createThread = useCreateThread();
|
|
252
|
+
const createComment = useCreateComment();
|
|
253
|
+
const editComment = useEditComment();
|
|
254
|
+
const handleCommentSubmit = React.useCallback(
|
|
255
|
+
(comment, event) => {
|
|
256
|
+
onComposerSubmit?.(comment, event);
|
|
257
|
+
if (event.isDefaultPrevented()) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (commentId && threadId) {
|
|
261
|
+
editComment({
|
|
262
|
+
commentId,
|
|
263
|
+
threadId,
|
|
264
|
+
body: comment.body
|
|
265
|
+
});
|
|
266
|
+
} else if (threadId) {
|
|
267
|
+
createComment({
|
|
268
|
+
threadId,
|
|
269
|
+
body: comment.body
|
|
270
|
+
});
|
|
271
|
+
} else {
|
|
272
|
+
createThread({
|
|
273
|
+
body: comment.body,
|
|
274
|
+
metadata: metadata ?? {}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
[
|
|
279
|
+
commentId,
|
|
280
|
+
createComment,
|
|
281
|
+
createThread,
|
|
282
|
+
editComment,
|
|
283
|
+
metadata,
|
|
284
|
+
onComposerSubmit,
|
|
285
|
+
threadId
|
|
286
|
+
]
|
|
287
|
+
);
|
|
288
|
+
return /* @__PURE__ */ React.createElement(TooltipPrimitive.TooltipProvider, null, /* @__PURE__ */ React.createElement(index.Form, {
|
|
289
|
+
onComposerSubmit: handleCommentSubmit,
|
|
290
|
+
asChild: true
|
|
291
|
+
}, /* @__PURE__ */ React.createElement(ComposerWithContext, {
|
|
292
|
+
...props,
|
|
293
|
+
ref: forwardedRef
|
|
294
|
+
})));
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
exports.Composer = Composer;
|
|
299
|
+
//# sourceMappingURL=Composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Composer.js","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport { type BaseMetadata, kInternal } from \"@liveblocks/core\";\nimport { useClient, useRoomContextBundle } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport { useComposer } from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { MENTION_CHARACTER } from \"../slate/plugins/mentions\";\nimport type { ThreadMetadata } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport {\n ShortcutTooltip,\n ShortcutTooltipKey,\n Tooltip,\n TooltipProvider,\n} from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ntype ComposerCreateThreadProps<M extends BaseMetadata> = {\n threadId?: never;\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: M;\n};\n\ntype ComposerCreateCommentProps = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n commentId?: never;\n metadata?: never;\n};\n\ntype ComposerEditCommentProps = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n metadata?: never;\n};\n\nexport type ComposerProps<M extends BaseMetadata = ThreadMetadata> = Omit<\n ComponentPropsWithoutRef<\"form\">,\n \"defaultValue\"\n> &\n (\n | ComposerCreateThreadProps<M>\n | ComposerCreateCommentProps\n | ComposerEditCommentProps\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerEditorProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n };\n\nfunction ComposerInsertMentionEditorAction({\n label,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={label}>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onMouseDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n {...props}\n >\n <MentionIcon className=\"lb-button-icon\" />\n </Button>\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onMouseDown={preventDefault}\n aria-label={label}\n {...props}\n >\n <EmojiIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerMention({ userId }: ComposerEditorMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-composer-mention\">\n {MENTION_CHARACTER}\n <User userId={userId} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerMentionSuggestions({\n userIds,\n}: ComposerEditorMentionSuggestionsProps) {\n return userIds.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {userIds.map((userId) => (\n <ComposerPrimitive.SuggestionsListItem\n key={userId}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={userId}\n >\n <Avatar\n userId={userId}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={userId}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </ComposerPrimitive.SuggestionsListItem>\n ))}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\nconst editorComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nconst ComposerWithContext = forwardRef<\n HTMLFormElement,\n Omit<ComposerProps, \"threadId\" | \"commentId\" | \"onComposerSubmit\">\n>(\n (\n {\n defaultValue,\n disabled,\n autoFocus,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n actions,\n overrides,\n showAttribution,\n onFocus,\n onBlur,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const { useSelf } = useRoomContextBundle();\n const self = useSelf();\n const isDisabled = useMemo(\n () => disabled || !self?.canComment,\n [disabled, self?.canComment]\n );\n const { isEmpty } = useComposer();\n const $ = useOverrides(overrides);\n const [isEmojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const [collapsed, onCollapsedChange] = useControllableState(\n // If the composer is neither controlled nor uncontrolled, it defaults to controlled as uncollapsed.\n controlledCollapsed === undefined && defaultCollapsed === undefined\n ? false\n : controlledCollapsed,\n controlledOnCollapsedChange,\n defaultCollapsed\n );\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmpty) {\n onCollapsedChange?.(false);\n }\n },\n [isEmpty, onCollapsedChange]\n );\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmpty) {\n onCollapsedChange?.(false);\n }\n },\n [isEmpty, onCollapsedChange, onFocus]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(event.relatedTarget);\n\n if (isOutside && isEmpty && !isEmojiPickerOpen) {\n onCollapsedChange?.(true);\n }\n },\n [isEmojiPickerOpen, isEmpty, onBlur, onCollapsedChange]\n );\n\n return (\n <form\n className={classNames(\n \"lb-root lb-composer lb-composer-form\",\n className\n )}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={collapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={handleEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n disabled={isDisabled}\n autoFocus={autoFocus}\n components={editorComponents}\n dir={$.dir}\n />\n {!collapsed && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={isDisabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={setEmojiPickerOpen}\n disabled={isDisabled}\n />\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip\n content={$.COMPOSER_SEND}\n shortcut={<ShortcutTooltipKey name=\"enter\" />}\n >\n <ComposerPrimitive.Submit disabled={isDisabled} asChild>\n <Button\n onMouseDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n >\n <SendIcon />\n </Button>\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n </form>\n );\n }\n);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <M extends BaseMetadata = ThreadMetadata>(\n {\n threadId,\n commentId,\n metadata,\n onComposerSubmit,\n ...props\n }: ComposerProps<M>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const { useCreateThread, useCreateComment, useEditComment } =\n useRoomContextBundle();\n const createThread = useCreateThread();\n const createComment = useCreateComment();\n const editComment = useEditComment();\n\n const handleCommentSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n });\n } else {\n createThread({\n body: comment.body,\n metadata: metadata ?? {},\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form onComposerSubmit={handleCommentSubmit} asChild>\n <ComposerWithContext {...props} ref={forwardedRef} />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = ThreadMetadata>(\n props: ComposerProps<M> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuJA;AAA2C;AACzC;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AACG;AAAiB;AACf;AAC6D;AAC/C;AACJ;AACG;AACR;AAEH;AAAsB;AAI/B;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACG;AAA2B;AAA0B;AACnD;AAAiB;AACf;AAA0B;AACxB;AAC6D;AAC/C;AACD;AACR;AAEH;AAAoB;AAMjC;AAEA;AACE;AACG;AAAoC;AAElC;AAAK;AAGZ;AAEA;AAAoC;AAEpC;AACE;AACG;AAAwC;AACtC;AAA4C;AAExC;AACM;AACK;AACH;AAEN;AACC;AACU;AAEX;AACC;AACU;AAOxB;AAEA;AACE;AACG;AAAuB;AAAsB;AAIlD;AAEA;AAAmD;AACxC;AACW;AAEtB;AAEA;AAA4B;AAKxB;AACE;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AAEA;AACA;AACA;AAAmB;AACQ;AACE;AAE7B;AACA;AACA;AACA;AAAuC;AAIjC;AACJ;AACA;AAGF;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC2B;AAG7B;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACoC;AAGtC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAwB;AAC1B;AACF;AACsD;AAGxD;AACG;AACY;AACT;AACA;AACF;AACO;AACH;AACC;AAC4B;AACxB;AACD;AAEP;AACW;AACD;AACM;AACf;AACU;AACV;AACY;AACL;AAGN;AAAc;AACZ;AAAc;AAEV;AACU;AACC;AAGb;AACU;AACW;AACV;AAIb;AAAc;AAGR;AACY;AACA;AAAwB;AAAQ;AAE1C;AAAmC;AAAmB;AACpD;AACc;AACJ;AACC;AACF;AACM;AAWhC;AAGN;AAQO;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACG;AAIL;AAEA;AACA;AACA;AAEA;AAA4B;AAExB;AAEA;AACE;AAAA;AAGF;AACE;AAAY;AACV;AACA;AACc;AACf;AAED;AAAc;AACZ;AACc;AACf;AAED;AAAa;AACG;AACS;AACxB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEK;AAAyC;AAA4B;AACnE;AAAwB;AAAY;AAEzC;AAGN;;"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { kInternal } from '@liveblocks/core';
|
|
3
|
+
import { useClient, useRoomContextBundle } from '@liveblocks/react';
|
|
4
|
+
import React__default, { forwardRef, useMemo, useState, useCallback } from 'react';
|
|
5
|
+
import { EmojiIcon } from '../icons/Emoji.mjs';
|
|
6
|
+
import { MentionIcon } from '../icons/Mention.mjs';
|
|
7
|
+
import { SendIcon } from '../icons/Send.mjs';
|
|
8
|
+
import { useOverrides } from '../overrides.mjs';
|
|
9
|
+
import { Editor as ComposerEditor, Submit as ComposerSubmit, Form as ComposerForm, Mention as ComposerMention$1, Suggestions as ComposerSuggestions, SuggestionsList as ComposerSuggestionsList, SuggestionsListItem as ComposerSuggestionsListItem, Link as ComposerLink$1 } from '../primitives/Composer/index.mjs';
|
|
10
|
+
import { useComposer } from '../primitives/Composer/contexts.mjs';
|
|
11
|
+
import { MENTION_CHARACTER } from '../slate/plugins/mentions.mjs';
|
|
12
|
+
import { classNames } from '../utils/class-names.mjs';
|
|
13
|
+
import { useControllableState } from '../utils/use-controllable-state.mjs';
|
|
14
|
+
import { Attribution } from './internal/Attribution.mjs';
|
|
15
|
+
import { Avatar } from './internal/Avatar.mjs';
|
|
16
|
+
import { Button } from './internal/Button.mjs';
|
|
17
|
+
import { EmojiPicker } from './internal/EmojiPicker.mjs';
|
|
18
|
+
import { ShortcutTooltip, ShortcutTooltipKey, Tooltip } from './internal/Tooltip.mjs';
|
|
19
|
+
import { User } from './internal/User.mjs';
|
|
20
|
+
import { TooltipProvider } from '@radix-ui/react-tooltip';
|
|
21
|
+
import { PopoverTrigger } from '@radix-ui/react-popover';
|
|
22
|
+
|
|
23
|
+
function ComposerInsertMentionEditorAction({
|
|
24
|
+
label,
|
|
25
|
+
className,
|
|
26
|
+
onClick,
|
|
27
|
+
...props
|
|
28
|
+
}) {
|
|
29
|
+
const { createMention } = useComposer();
|
|
30
|
+
const preventDefault = useCallback((event) => {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
}, []);
|
|
33
|
+
const handleClick = useCallback(
|
|
34
|
+
(event) => {
|
|
35
|
+
onClick?.(event);
|
|
36
|
+
if (!event.isDefaultPrevented()) {
|
|
37
|
+
event.stopPropagation();
|
|
38
|
+
createMention();
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
[createMention, onClick]
|
|
42
|
+
);
|
|
43
|
+
return /* @__PURE__ */ React__default.createElement(Tooltip, {
|
|
44
|
+
content: label
|
|
45
|
+
}, /* @__PURE__ */ React__default.createElement(Button, {
|
|
46
|
+
className: classNames("lb-composer-editor-action", className),
|
|
47
|
+
onMouseDown: preventDefault,
|
|
48
|
+
onClick: handleClick,
|
|
49
|
+
"aria-label": label,
|
|
50
|
+
...props
|
|
51
|
+
}, /* @__PURE__ */ React__default.createElement(MentionIcon, {
|
|
52
|
+
className: "lb-button-icon"
|
|
53
|
+
})));
|
|
54
|
+
}
|
|
55
|
+
function ComposerInsertEmojiEditorAction({
|
|
56
|
+
label,
|
|
57
|
+
onPickerOpenChange,
|
|
58
|
+
className,
|
|
59
|
+
...props
|
|
60
|
+
}) {
|
|
61
|
+
const { insertText } = useComposer();
|
|
62
|
+
const preventDefault = useCallback((event) => {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
}, []);
|
|
65
|
+
return /* @__PURE__ */ React__default.createElement(EmojiPicker, {
|
|
66
|
+
onEmojiSelect: insertText,
|
|
67
|
+
onOpenChange: onPickerOpenChange
|
|
68
|
+
}, /* @__PURE__ */ React__default.createElement(Tooltip, {
|
|
69
|
+
content: label
|
|
70
|
+
}, /* @__PURE__ */ React__default.createElement(PopoverTrigger, {
|
|
71
|
+
asChild: true
|
|
72
|
+
}, /* @__PURE__ */ React__default.createElement(Button, {
|
|
73
|
+
className: classNames("lb-composer-editor-action", className),
|
|
74
|
+
onMouseDown: preventDefault,
|
|
75
|
+
"aria-label": label,
|
|
76
|
+
...props
|
|
77
|
+
}, /* @__PURE__ */ React__default.createElement(EmojiIcon, {
|
|
78
|
+
className: "lb-button-icon"
|
|
79
|
+
})))));
|
|
80
|
+
}
|
|
81
|
+
function ComposerMention({ userId }) {
|
|
82
|
+
return /* @__PURE__ */ React__default.createElement(ComposerMention$1, {
|
|
83
|
+
className: "lb-composer-mention"
|
|
84
|
+
}, MENTION_CHARACTER, /* @__PURE__ */ React__default.createElement(User, {
|
|
85
|
+
userId
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
function ComposerMentionSuggestions({
|
|
89
|
+
userIds
|
|
90
|
+
}) {
|
|
91
|
+
return userIds.length > 0 ? /* @__PURE__ */ React__default.createElement(ComposerSuggestions, {
|
|
92
|
+
className: "lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions"
|
|
93
|
+
}, /* @__PURE__ */ React__default.createElement(ComposerSuggestionsList, {
|
|
94
|
+
className: "lb-composer-suggestions-list lb-composer-mention-suggestions-list"
|
|
95
|
+
}, userIds.map((userId) => /* @__PURE__ */ React__default.createElement(ComposerSuggestionsListItem, {
|
|
96
|
+
key: userId,
|
|
97
|
+
className: "lb-composer-suggestions-list-item lb-composer-mention-suggestion",
|
|
98
|
+
value: userId
|
|
99
|
+
}, /* @__PURE__ */ React__default.createElement(Avatar, {
|
|
100
|
+
userId,
|
|
101
|
+
className: "lb-composer-mention-suggestion-avatar"
|
|
102
|
+
}), /* @__PURE__ */ React__default.createElement(User, {
|
|
103
|
+
userId,
|
|
104
|
+
className: "lb-composer-mention-suggestion-user"
|
|
105
|
+
}))))) : null;
|
|
106
|
+
}
|
|
107
|
+
function ComposerLink({ href, children }) {
|
|
108
|
+
return /* @__PURE__ */ React__default.createElement(ComposerLink$1, {
|
|
109
|
+
href,
|
|
110
|
+
className: "lb-composer-link"
|
|
111
|
+
}, children);
|
|
112
|
+
}
|
|
113
|
+
const editorComponents = {
|
|
114
|
+
Mention: ComposerMention,
|
|
115
|
+
MentionSuggestions: ComposerMentionSuggestions,
|
|
116
|
+
Link: ComposerLink
|
|
117
|
+
};
|
|
118
|
+
const ComposerWithContext = forwardRef(
|
|
119
|
+
({
|
|
120
|
+
defaultValue,
|
|
121
|
+
disabled,
|
|
122
|
+
autoFocus,
|
|
123
|
+
collapsed: controlledCollapsed,
|
|
124
|
+
defaultCollapsed,
|
|
125
|
+
onCollapsedChange: controlledOnCollapsedChange,
|
|
126
|
+
actions,
|
|
127
|
+
overrides,
|
|
128
|
+
showAttribution,
|
|
129
|
+
onFocus,
|
|
130
|
+
onBlur,
|
|
131
|
+
className,
|
|
132
|
+
...props
|
|
133
|
+
}, forwardedRef) => {
|
|
134
|
+
const client = useClient();
|
|
135
|
+
const hasResolveMentionSuggestions = client[kInternal].resolveMentionSuggestions !== void 0;
|
|
136
|
+
const { useSelf } = useRoomContextBundle();
|
|
137
|
+
const self = useSelf();
|
|
138
|
+
const isDisabled = useMemo(
|
|
139
|
+
() => disabled || !self?.canComment,
|
|
140
|
+
[disabled, self?.canComment]
|
|
141
|
+
);
|
|
142
|
+
const { isEmpty } = useComposer();
|
|
143
|
+
const $ = useOverrides(overrides);
|
|
144
|
+
const [isEmojiPickerOpen, setEmojiPickerOpen] = useState(false);
|
|
145
|
+
const [collapsed, onCollapsedChange] = useControllableState(
|
|
146
|
+
controlledCollapsed === void 0 && defaultCollapsed === void 0 ? false : controlledCollapsed,
|
|
147
|
+
controlledOnCollapsedChange,
|
|
148
|
+
defaultCollapsed
|
|
149
|
+
);
|
|
150
|
+
const preventDefault = useCallback((event) => {
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
}, []);
|
|
153
|
+
const stopPropagation = useCallback((event) => {
|
|
154
|
+
event.stopPropagation();
|
|
155
|
+
}, []);
|
|
156
|
+
const handleEditorClick = useCallback(
|
|
157
|
+
(event) => {
|
|
158
|
+
event.stopPropagation();
|
|
159
|
+
if (isEmpty) {
|
|
160
|
+
onCollapsedChange?.(false);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
[isEmpty, onCollapsedChange]
|
|
164
|
+
);
|
|
165
|
+
const handleFocus = useCallback(
|
|
166
|
+
(event) => {
|
|
167
|
+
onFocus?.(event);
|
|
168
|
+
if (event.isDefaultPrevented()) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (isEmpty) {
|
|
172
|
+
onCollapsedChange?.(false);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
[isEmpty, onCollapsedChange, onFocus]
|
|
176
|
+
);
|
|
177
|
+
const handleBlur = useCallback(
|
|
178
|
+
(event) => {
|
|
179
|
+
onBlur?.(event);
|
|
180
|
+
if (event.isDefaultPrevented()) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const isOutside = !event.currentTarget.contains(event.relatedTarget);
|
|
184
|
+
if (isOutside && isEmpty && !isEmojiPickerOpen) {
|
|
185
|
+
onCollapsedChange?.(true);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
[isEmojiPickerOpen, isEmpty, onBlur, onCollapsedChange]
|
|
189
|
+
);
|
|
190
|
+
return /* @__PURE__ */ React__default.createElement("form", {
|
|
191
|
+
className: classNames(
|
|
192
|
+
"lb-root lb-composer lb-composer-form",
|
|
193
|
+
className
|
|
194
|
+
),
|
|
195
|
+
dir: $.dir,
|
|
196
|
+
...props,
|
|
197
|
+
ref: forwardedRef,
|
|
198
|
+
"data-collapsed": collapsed ? "" : void 0,
|
|
199
|
+
onFocus: handleFocus,
|
|
200
|
+
onBlur: handleBlur
|
|
201
|
+
}, /* @__PURE__ */ React__default.createElement(ComposerEditor, {
|
|
202
|
+
className: "lb-composer-editor",
|
|
203
|
+
onClick: handleEditorClick,
|
|
204
|
+
placeholder: $.COMPOSER_PLACEHOLDER,
|
|
205
|
+
defaultValue,
|
|
206
|
+
disabled: isDisabled,
|
|
207
|
+
autoFocus,
|
|
208
|
+
components: editorComponents,
|
|
209
|
+
dir: $.dir
|
|
210
|
+
}), !collapsed && /* @__PURE__ */ React__default.createElement("div", {
|
|
211
|
+
className: "lb-composer-footer"
|
|
212
|
+
}, /* @__PURE__ */ React__default.createElement("div", {
|
|
213
|
+
className: "lb-composer-editor-actions"
|
|
214
|
+
}, hasResolveMentionSuggestions && /* @__PURE__ */ React__default.createElement(ComposerInsertMentionEditorAction, {
|
|
215
|
+
label: $.COMPOSER_INSERT_MENTION,
|
|
216
|
+
disabled: isDisabled
|
|
217
|
+
}), /* @__PURE__ */ React__default.createElement(ComposerInsertEmojiEditorAction, {
|
|
218
|
+
label: $.COMPOSER_INSERT_EMOJI,
|
|
219
|
+
onPickerOpenChange: setEmojiPickerOpen,
|
|
220
|
+
disabled: isDisabled
|
|
221
|
+
})), showAttribution && /* @__PURE__ */ React__default.createElement(Attribution, null), /* @__PURE__ */ React__default.createElement("div", {
|
|
222
|
+
className: "lb-composer-actions"
|
|
223
|
+
}, actions ?? /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(ShortcutTooltip, {
|
|
224
|
+
content: $.COMPOSER_SEND,
|
|
225
|
+
shortcut: /* @__PURE__ */ React__default.createElement(ShortcutTooltipKey, {
|
|
226
|
+
name: "enter"
|
|
227
|
+
})
|
|
228
|
+
}, /* @__PURE__ */ React__default.createElement(ComposerSubmit, {
|
|
229
|
+
disabled: isDisabled,
|
|
230
|
+
asChild: true
|
|
231
|
+
}, /* @__PURE__ */ React__default.createElement(Button, {
|
|
232
|
+
onMouseDown: preventDefault,
|
|
233
|
+
onClick: stopPropagation,
|
|
234
|
+
className: "lb-composer-action",
|
|
235
|
+
variant: "primary",
|
|
236
|
+
"aria-label": $.COMPOSER_SEND
|
|
237
|
+
}, /* @__PURE__ */ React__default.createElement(SendIcon, null))))))));
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
const Composer = forwardRef(
|
|
241
|
+
({
|
|
242
|
+
threadId,
|
|
243
|
+
commentId,
|
|
244
|
+
metadata,
|
|
245
|
+
onComposerSubmit,
|
|
246
|
+
...props
|
|
247
|
+
}, forwardedRef) => {
|
|
248
|
+
const { useCreateThread, useCreateComment, useEditComment } = useRoomContextBundle();
|
|
249
|
+
const createThread = useCreateThread();
|
|
250
|
+
const createComment = useCreateComment();
|
|
251
|
+
const editComment = useEditComment();
|
|
252
|
+
const handleCommentSubmit = useCallback(
|
|
253
|
+
(comment, event) => {
|
|
254
|
+
onComposerSubmit?.(comment, event);
|
|
255
|
+
if (event.isDefaultPrevented()) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (commentId && threadId) {
|
|
259
|
+
editComment({
|
|
260
|
+
commentId,
|
|
261
|
+
threadId,
|
|
262
|
+
body: comment.body
|
|
263
|
+
});
|
|
264
|
+
} else if (threadId) {
|
|
265
|
+
createComment({
|
|
266
|
+
threadId,
|
|
267
|
+
body: comment.body
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
createThread({
|
|
271
|
+
body: comment.body,
|
|
272
|
+
metadata: metadata ?? {}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
[
|
|
277
|
+
commentId,
|
|
278
|
+
createComment,
|
|
279
|
+
createThread,
|
|
280
|
+
editComment,
|
|
281
|
+
metadata,
|
|
282
|
+
onComposerSubmit,
|
|
283
|
+
threadId
|
|
284
|
+
]
|
|
285
|
+
);
|
|
286
|
+
return /* @__PURE__ */ React__default.createElement(TooltipProvider, null, /* @__PURE__ */ React__default.createElement(ComposerForm, {
|
|
287
|
+
onComposerSubmit: handleCommentSubmit,
|
|
288
|
+
asChild: true
|
|
289
|
+
}, /* @__PURE__ */ React__default.createElement(ComposerWithContext, {
|
|
290
|
+
...props,
|
|
291
|
+
ref: forwardedRef
|
|
292
|
+
})));
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
export { Composer };
|
|
297
|
+
//# sourceMappingURL=Composer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Composer.mjs","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport { type BaseMetadata, kInternal } from \"@liveblocks/core\";\nimport { useClient, useRoomContextBundle } from \"@liveblocks/react\";\nimport type {\n ComponentPropsWithoutRef,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport React, { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport { useComposer } from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { MENTION_CHARACTER } from \"../slate/plugins/mentions\";\nimport type { ThreadMetadata } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport {\n ShortcutTooltip,\n ShortcutTooltipKey,\n Tooltip,\n TooltipProvider,\n} from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ntype ComposerCreateThreadProps<M extends BaseMetadata> = {\n threadId?: never;\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: M;\n};\n\ntype ComposerCreateCommentProps = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n commentId?: never;\n metadata?: never;\n};\n\ntype ComposerEditCommentProps = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n metadata?: never;\n};\n\nexport type ComposerProps<M extends BaseMetadata = ThreadMetadata> = Omit<\n ComponentPropsWithoutRef<\"form\">,\n \"defaultValue\"\n> &\n (\n | ComposerCreateThreadProps<M>\n | ComposerCreateCommentProps\n | ComposerEditCommentProps\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerEditorProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n };\n\nfunction ComposerInsertMentionEditorAction({\n label,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={label}>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onMouseDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n {...props}\n >\n <MentionIcon className=\"lb-button-icon\" />\n </Button>\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onMouseDown={preventDefault}\n aria-label={label}\n {...props}\n >\n <EmojiIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerMention({ userId }: ComposerEditorMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-composer-mention\">\n {MENTION_CHARACTER}\n <User userId={userId} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerMentionSuggestions({\n userIds,\n}: ComposerEditorMentionSuggestionsProps) {\n return userIds.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {userIds.map((userId) => (\n <ComposerPrimitive.SuggestionsListItem\n key={userId}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={userId}\n >\n <Avatar\n userId={userId}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={userId}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </ComposerPrimitive.SuggestionsListItem>\n ))}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\nconst editorComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nconst ComposerWithContext = forwardRef<\n HTMLFormElement,\n Omit<ComposerProps, \"threadId\" | \"commentId\" | \"onComposerSubmit\">\n>(\n (\n {\n defaultValue,\n disabled,\n autoFocus,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n actions,\n overrides,\n showAttribution,\n onFocus,\n onBlur,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const { useSelf } = useRoomContextBundle();\n const self = useSelf();\n const isDisabled = useMemo(\n () => disabled || !self?.canComment,\n [disabled, self?.canComment]\n );\n const { isEmpty } = useComposer();\n const $ = useOverrides(overrides);\n const [isEmojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const [collapsed, onCollapsedChange] = useControllableState(\n // If the composer is neither controlled nor uncontrolled, it defaults to controlled as uncollapsed.\n controlledCollapsed === undefined && defaultCollapsed === undefined\n ? false\n : controlledCollapsed,\n controlledOnCollapsedChange,\n defaultCollapsed\n );\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmpty) {\n onCollapsedChange?.(false);\n }\n },\n [isEmpty, onCollapsedChange]\n );\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmpty) {\n onCollapsedChange?.(false);\n }\n },\n [isEmpty, onCollapsedChange, onFocus]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(event.relatedTarget);\n\n if (isOutside && isEmpty && !isEmojiPickerOpen) {\n onCollapsedChange?.(true);\n }\n },\n [isEmojiPickerOpen, isEmpty, onBlur, onCollapsedChange]\n );\n\n return (\n <form\n className={classNames(\n \"lb-root lb-composer lb-composer-form\",\n className\n )}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={collapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={handleEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n disabled={isDisabled}\n autoFocus={autoFocus}\n components={editorComponents}\n dir={$.dir}\n />\n {!collapsed && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={isDisabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={setEmojiPickerOpen}\n disabled={isDisabled}\n />\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip\n content={$.COMPOSER_SEND}\n shortcut={<ShortcutTooltipKey name=\"enter\" />}\n >\n <ComposerPrimitive.Submit disabled={isDisabled} asChild>\n <Button\n onMouseDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n >\n <SendIcon />\n </Button>\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n </form>\n );\n }\n);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <M extends BaseMetadata = ThreadMetadata>(\n {\n threadId,\n commentId,\n metadata,\n onComposerSubmit,\n ...props\n }: ComposerProps<M>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const { useCreateThread, useCreateComment, useEditComment } =\n useRoomContextBundle();\n const createThread = useCreateThread();\n const createComment = useCreateComment();\n const editComment = useEditComment();\n\n const handleCommentSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n });\n } else {\n createThread({\n body: comment.body,\n metadata: metadata ?? {},\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form onComposerSubmit={handleCommentSubmit} asChild>\n <ComposerWithContext {...props} ref={forwardedRef} />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = ThreadMetadata>(\n props: ComposerProps<M> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuJA;AAA2C;AACzC;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AACG;AAAiB;AACf;AAC6D;AAC/C;AACJ;AACG;AACR;AAEH;AAAsB;AAI/B;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACG;AAA2B;AAA0B;AACnD;AAAiB;AACf;AAA0B;AACxB;AAC6D;AAC/C;AACD;AACR;AAEH;AAAoB;AAMjC;AAEA;AACE;AACG;AAAoC;AAElC;AAAK;AAGZ;AAEA;AAAoC;AAEpC;AACE;AACG;AAAwC;AACtC;AAA4C;AAExC;AACM;AACK;AACH;AAEN;AACC;AACU;AAEX;AACC;AACU;AAOxB;AAEA;AACE;AACG;AAAuB;AAAsB;AAIlD;AAEA;AAAmD;AACxC;AACW;AAEtB;AAEA;AAA4B;AAKxB;AACE;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AAEA;AACA;AACA;AAAmB;AACQ;AACE;AAE7B;AACA;AACA;AACA;AAAuC;AAIjC;AACJ;AACA;AAGF;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC2B;AAG7B;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACoC;AAGtC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAwB;AAC1B;AACF;AACsD;AAGxD;AACG;AACY;AACT;AACA;AACF;AACO;AACH;AACC;AAC4B;AACxB;AACD;AAEP;AACW;AACD;AACM;AACf;AACU;AACV;AACY;AACL;AAGN;AAAc;AACZ;AAAc;AAEV;AACU;AACC;AAGb;AACU;AACW;AACV;AAIb;AAAc;AAGR;AACY;AACA;AAAwB;AAAQ;AAE1C;AAAmC;AAAmB;AACpD;AACc;AACJ;AACC;AACF;AACM;AAWhC;AAGN;AAQO;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACG;AAIL;AAEA;AACA;AACA;AAEA;AAA4B;AAExB;AAEA;AACE;AAAA;AAGF;AACE;AAAY;AACV;AACA;AACc;AACf;AAED;AAAc;AACZ;AACc;AACf;AAED;AAAa;AACG;AACS;AACxB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEK;AAAyC;AAA4B;AACnE;AAAwB;AAAY;AAEzC;AAGN;;"}
|