@liveblocks/react-ui 2.5.2 → 2.7.0-beta1
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/components/Comment.js +61 -3
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Comment.mjs +62 -5
- package/dist/components/Comment.mjs.map +1 -1
- package/dist/components/Composer.js +217 -101
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/Composer.mjs +220 -104
- package/dist/components/Composer.mjs.map +1 -1
- package/dist/components/InboxNotification.js +17 -4
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotification.mjs +17 -4
- package/dist/components/InboxNotification.mjs.map +1 -1
- package/dist/components/Thread.js +2 -0
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/Thread.mjs +2 -0
- package/dist/components/Thread.mjs.map +1 -1
- package/dist/components/internal/Attachment.js +226 -0
- package/dist/components/internal/Attachment.js.map +1 -0
- package/dist/components/internal/Attachment.mjs +224 -0
- package/dist/components/internal/Attachment.mjs.map +1 -0
- package/dist/components/internal/InboxNotificationThread.js +10 -2
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.mjs +11 -3
- package/dist/components/internal/InboxNotificationThread.mjs.map +1 -1
- package/dist/icons/Attachment.js +15 -0
- package/dist/icons/Attachment.js.map +1 -0
- package/dist/icons/Attachment.mjs +13 -0
- package/dist/icons/Attachment.mjs.map +1 -0
- package/dist/icons/Spinner.js +3 -9
- package/dist/icons/Spinner.js.map +1 -1
- package/dist/icons/Spinner.mjs +4 -10
- package/dist/icons/Spinner.mjs.map +1 -1
- package/dist/icons/{Missing.js → Warning.js} +3 -3
- package/dist/icons/{Missing.js.map → Warning.js.map} +1 -1
- package/dist/icons/{Missing.mjs → Warning.mjs} +3 -3
- package/dist/icons/{Missing.mjs.map → Warning.mjs.map} +1 -1
- package/dist/index.d.mts +70 -4
- package/dist/index.d.ts +70 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/overrides.js +5 -0
- package/dist/overrides.js.map +1 -1
- package/dist/overrides.mjs +5 -0
- package/dist/overrides.mjs.map +1 -1
- package/dist/primitives/Composer/contexts.js +17 -3
- package/dist/primitives/Composer/contexts.js.map +1 -1
- package/dist/primitives/Composer/contexts.mjs +15 -4
- package/dist/primitives/Composer/contexts.mjs.map +1 -1
- package/dist/primitives/Composer/index.js +185 -26
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/index.mjs +188 -31
- package/dist/primitives/Composer/index.mjs.map +1 -1
- package/dist/primitives/Composer/utils.js +224 -0
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Composer/utils.mjs +222 -1
- package/dist/primitives/Composer/utils.mjs.map +1 -1
- package/dist/primitives/EmojiPicker/utils.js +2 -2
- package/dist/primitives/EmojiPicker/utils.js.map +1 -1
- package/dist/primitives/EmojiPicker/utils.mjs +1 -1
- package/dist/primitives/EmojiPicker/utils.mjs.map +1 -1
- package/dist/primitives/FileSize.js +33 -0
- package/dist/primitives/FileSize.js.map +1 -0
- package/dist/primitives/FileSize.mjs +31 -0
- package/dist/primitives/FileSize.mjs.map +1 -0
- package/dist/primitives/index.d.mts +83 -3
- package/dist/primitives/index.d.ts +83 -3
- package/dist/primitives/index.js +4 -0
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/index.mjs +2 -0
- package/dist/primitives/index.mjs.map +1 -1
- package/dist/utils/download.js +14 -0
- package/dist/utils/download.js.map +1 -0
- package/dist/utils/download.mjs +12 -0
- package/dist/utils/download.mjs.map +1 -0
- package/dist/utils/format-file-size.js +45 -0
- package/dist/utils/format-file-size.js.map +1 -0
- package/dist/utils/format-file-size.mjs +43 -0
- package/dist/utils/format-file-size.mjs.map +1 -0
- package/dist/utils/intl.js +6 -0
- package/dist/utils/intl.js.map +1 -1
- package/dist/utils/intl.mjs +6 -1
- package/dist/utils/intl.mjs.map +1 -1
- package/dist/utils/use-initial.js +2 -1
- package/dist/utils/use-initial.js.map +1 -1
- package/dist/utils/use-initial.mjs +3 -2
- package/dist/utils/use-initial.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +4 -4
- package/src/styles/dark/index.css +1 -0
- package/src/styles/index.css +296 -62
- package/src/styles/utils.css +44 -0
- package/styles/dark/attributes.css +1 -1
- package/styles/dark/attributes.css.map +1 -1
- package/styles/dark/media-query.css +1 -1
- package/styles/dark/media-query.css.map +1 -1
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/utils/chunk.js +0 -12
- package/dist/utils/chunk.js.map +0 -1
- package/dist/utils/chunk.mjs +0 -10
- package/dist/utils/chunk.mjs.map +0 -1
package/dist/overrides.mjs
CHANGED
|
@@ -15,8 +15,12 @@ const defaultOverrides = {
|
|
|
15
15
|
EMOJI_PICKER_SEARCH_PLACEHOLDER: "Search\u2026",
|
|
16
16
|
EMOJI_PICKER_EMPTY: "No emoji found.",
|
|
17
17
|
EMOJI_PICKER_ERROR: () => "There was an error while getting the list of emoji.",
|
|
18
|
+
ATTACHMENT_TOO_LARGE: (maxSize) => maxSize ? `The file is larger than ${maxSize}` : "The file is too large",
|
|
19
|
+
ATTACHMENT_ERROR: () => "The file couldn\u2019t be uploaded.",
|
|
18
20
|
COMPOSER_INSERT_MENTION: "Mention someone",
|
|
19
21
|
COMPOSER_INSERT_EMOJI: "Add emoji",
|
|
22
|
+
COMPOSER_ATTACH_FILES: "Attach files",
|
|
23
|
+
COMPOSER_REMOVE_ATTACHMENT: "Remove attachment",
|
|
20
24
|
COMPOSER_PLACEHOLDER: "Write a comment\u2026",
|
|
21
25
|
COMPOSER_SEND: "Send",
|
|
22
26
|
COMMENT_EDITED: "(edited)",
|
|
@@ -27,6 +31,7 @@ const defaultOverrides = {
|
|
|
27
31
|
COMMENT_EDIT_COMPOSER_CANCEL: "Cancel",
|
|
28
32
|
COMMENT_EDIT_COMPOSER_SAVE: "Save",
|
|
29
33
|
COMMENT_DELETE: "Delete comment",
|
|
34
|
+
COMMENT_DELETE_ATTACHMENT: "Delete attachment",
|
|
30
35
|
COMMENT_ADD_REACTION: "Add reaction",
|
|
31
36
|
COMMENT_REACTION_LIST: (list, emoji) => /* @__PURE__ */ React.createElement(React.Fragment, null, list, " reacted with ", /* @__PURE__ */ React.createElement(Emoji, {
|
|
32
37
|
emoji
|
package/dist/overrides.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overrides.mjs","sources":["../src/overrides.tsx"],"sourcesContent":["\"use client\";\n\nimport type { PropsWithChildren, ReactNode } from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport * as React from \"react\";\n\nimport { Emoji } from \"./components/internal/Emoji\";\nimport type { Direction } from \"./types\";\nimport { pluralize } from \"./utils/pluralize\";\n\nexport interface LocalizationOverrides {\n locale: string;\n dir: Direction;\n}\n\nexport interface GlobalOverrides {\n USER_SELF: string;\n USER_UNKNOWN: string;\n LIST_REMAINING: (count: number) => string;\n LIST_REMAINING_USERS: (count: number) => string;\n LIST_REMAINING_COMMENTS: (count: number) => string;\n EMOJI_PICKER_SEARCH_PLACEHOLDER: string;\n EMOJI_PICKER_EMPTY: ReactNode;\n EMOJI_PICKER_ERROR: (error: Error) => ReactNode;\n}\n\nexport interface CommentOverrides {\n COMMENT_EDITED: ReactNode;\n COMMENT_DELETED: ReactNode;\n COMMENT_MORE: string;\n COMMENT_EDIT: string;\n COMMENT_EDIT_COMPOSER_PLACEHOLDER: string;\n COMMENT_EDIT_COMPOSER_CANCEL: string;\n COMMENT_EDIT_COMPOSER_SAVE: string;\n COMMENT_DELETE: string;\n COMMENT_ADD_REACTION: string;\n COMMENT_REACTION_LIST: (\n list: ReactNode,\n emoji: string,\n count: number\n ) => ReactNode;\n COMMENT_REACTION_DESCRIPTION: (emoji: string, count: number) => string;\n}\n\nexport interface ComposerOverrides {\n COMPOSER_INSERT_MENTION: string;\n COMPOSER_INSERT_EMOJI: string;\n COMPOSER_PLACEHOLDER: string;\n COMPOSER_SEND: string;\n}\n\nexport interface ThreadOverrides {\n THREAD_RESOLVE: string;\n THREAD_UNRESOLVE: string;\n THREAD_NEW_INDICATOR: string;\n THREAD_NEW_INDICATOR_DESCRIPTION: string;\n THREAD_COMPOSER_PLACEHOLDER: string;\n THREAD_COMPOSER_SEND: string;\n}\n\nexport interface InboxNotificationOverrides {\n INBOX_NOTIFICATION_MORE: string;\n INBOX_NOTIFICATION_MARK_AS_READ: string;\n INBOX_NOTIFICATION_DELETE: string;\n INBOX_NOTIFICATION_THREAD_COMMENTS_LIST: (\n list: ReactNode,\n room: ReactNode | undefined,\n count: number\n ) => ReactNode;\n INBOX_NOTIFICATION_THREAD_MENTION: (\n user: ReactNode,\n room: ReactNode | undefined\n ) => ReactNode;\n INBOX_NOTIFICATION_TEXT_MENTION: (\n user: ReactNode,\n room: ReactNode | undefined\n ) => ReactNode;\n}\n\nexport type Overrides = LocalizationOverrides &\n GlobalOverrides &\n ComposerOverrides &\n CommentOverrides &\n ThreadOverrides &\n InboxNotificationOverrides;\n\ntype OverridesProviderProps = PropsWithChildren<{\n overrides?: Partial<Overrides>;\n}>;\n\nexport const defaultOverrides: Overrides = {\n locale: \"en\",\n dir: \"ltr\",\n USER_SELF: \"you\",\n USER_UNKNOWN: \"Anonymous\",\n LIST_REMAINING: (count) => `${count} more`,\n LIST_REMAINING_USERS: (count) => `${count} ${pluralize(count, \"other\")}`,\n LIST_REMAINING_COMMENTS: (count) =>\n `${count} more ${pluralize(count, \"comment\")}`,\n EMOJI_PICKER_SEARCH_PLACEHOLDER: \"Search…\",\n EMOJI_PICKER_EMPTY: \"No emoji found.\",\n EMOJI_PICKER_ERROR: () =>\n \"There was an error while getting the list of emoji.\",\n COMPOSER_INSERT_MENTION: \"Mention someone\",\n COMPOSER_INSERT_EMOJI: \"Add emoji\",\n COMPOSER_PLACEHOLDER: \"Write a comment…\",\n COMPOSER_SEND: \"Send\",\n COMMENT_EDITED: \"(edited)\",\n COMMENT_DELETED: \"This comment has been deleted.\",\n COMMENT_MORE: \"More\",\n COMMENT_EDIT: \"Edit comment\",\n COMMENT_EDIT_COMPOSER_PLACEHOLDER: \"Edit comment…\",\n COMMENT_EDIT_COMPOSER_CANCEL: \"Cancel\",\n COMMENT_EDIT_COMPOSER_SAVE: \"Save\",\n COMMENT_DELETE: \"Delete comment\",\n COMMENT_ADD_REACTION: \"Add reaction\",\n COMMENT_REACTION_LIST: (list, emoji) => (\n <>\n {list} reacted with <Emoji emoji={emoji} />\n </>\n ),\n COMMENT_REACTION_DESCRIPTION: (emoji, count) =>\n `${count} ${pluralize(count, \"reaction\")}, react with ${emoji}`,\n THREAD_RESOLVE: \"Resolve thread\",\n THREAD_UNRESOLVE: \"Re-open thread\",\n THREAD_NEW_INDICATOR: \"New\",\n THREAD_NEW_INDICATOR_DESCRIPTION: \"New comments\",\n THREAD_COMPOSER_PLACEHOLDER: \"Reply to thread…\",\n THREAD_COMPOSER_SEND: \"Reply\",\n INBOX_NOTIFICATION_MORE: \"More\",\n INBOX_NOTIFICATION_MARK_AS_READ: \"Mark as read\",\n INBOX_NOTIFICATION_DELETE: \"Delete notification\",\n INBOX_NOTIFICATION_THREAD_COMMENTS_LIST: (\n list: ReactNode,\n room: ReactNode\n ) => (\n <>\n {list} commented\n {room ? <> in {room}</> : <> in a thread</>}\n </>\n ),\n INBOX_NOTIFICATION_THREAD_MENTION: (user: ReactNode, room: ReactNode) => (\n <>\n {user} mentioned you{room ? <> in {room}</> : null}\n </>\n ),\n INBOX_NOTIFICATION_TEXT_MENTION: (user: ReactNode, room: ReactNode) => (\n <>\n {user} mentioned you{room ? <> in {room}</> : null}\n </>\n ),\n};\n\nexport const OverridesContext = createContext<Overrides | undefined>(undefined);\n\nexport function useOverrides(overrides?: Partial<Overrides>): Overrides {\n const contextOverrides = useContext(OverridesContext);\n\n return useMemo(\n () => ({\n ...defaultOverrides,\n ...contextOverrides,\n ...overrides,\n }),\n [contextOverrides, overrides]\n );\n}\n\nexport function OverridesProvider({\n children,\n overrides: providerOverrides,\n}: OverridesProviderProps) {\n const contextOverrides = useContext(OverridesContext);\n const overrides = useMemo(\n () => ({\n ...defaultOverrides,\n ...contextOverrides,\n ...providerOverrides,\n }),\n [contextOverrides, providerOverrides]\n );\n\n return (\n <OverridesContext.Provider value={overrides}>\n {children}\n </OverridesContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"overrides.mjs","sources":["../src/overrides.tsx"],"sourcesContent":["\"use client\";\n\nimport type { PropsWithChildren, ReactNode } from \"react\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport * as React from \"react\";\n\nimport { Emoji } from \"./components/internal/Emoji\";\nimport type { Direction } from \"./types\";\nimport { pluralize } from \"./utils/pluralize\";\n\nexport interface LocalizationOverrides {\n locale: string;\n dir: Direction;\n}\n\nexport interface GlobalOverrides {\n USER_SELF: string;\n USER_UNKNOWN: string;\n LIST_REMAINING: (count: number) => string;\n LIST_REMAINING_USERS: (count: number) => string;\n LIST_REMAINING_COMMENTS: (count: number) => string;\n EMOJI_PICKER_SEARCH_PLACEHOLDER: string;\n EMOJI_PICKER_EMPTY: ReactNode;\n EMOJI_PICKER_ERROR: (error: Error) => ReactNode;\n ATTACHMENT_TOO_LARGE: (maxSize?: string) => string;\n ATTACHMENT_ERROR: (error: Error) => string;\n}\n\nexport interface CommentOverrides {\n COMMENT_EDITED: ReactNode;\n COMMENT_DELETED: ReactNode;\n COMMENT_MORE: string;\n COMMENT_EDIT: string;\n COMMENT_EDIT_COMPOSER_PLACEHOLDER: string;\n COMMENT_EDIT_COMPOSER_CANCEL: string;\n COMMENT_EDIT_COMPOSER_SAVE: string;\n COMMENT_DELETE: string;\n COMMENT_DELETE_ATTACHMENT: string;\n COMMENT_ADD_REACTION: string;\n COMMENT_REACTION_LIST: (\n list: ReactNode,\n emoji: string,\n count: number\n ) => ReactNode;\n COMMENT_REACTION_DESCRIPTION: (emoji: string, count: number) => string;\n}\n\nexport interface ComposerOverrides {\n COMPOSER_INSERT_MENTION: string;\n COMPOSER_INSERT_EMOJI: string;\n COMPOSER_ATTACH_FILES: string;\n COMPOSER_REMOVE_ATTACHMENT: string;\n COMPOSER_PLACEHOLDER: string;\n COMPOSER_SEND: string;\n}\n\nexport interface ThreadOverrides {\n THREAD_RESOLVE: string;\n THREAD_UNRESOLVE: string;\n THREAD_NEW_INDICATOR: string;\n THREAD_NEW_INDICATOR_DESCRIPTION: string;\n THREAD_COMPOSER_PLACEHOLDER: string;\n THREAD_COMPOSER_SEND: string;\n}\n\nexport interface InboxNotificationOverrides {\n INBOX_NOTIFICATION_MORE: string;\n INBOX_NOTIFICATION_MARK_AS_READ: string;\n INBOX_NOTIFICATION_DELETE: string;\n INBOX_NOTIFICATION_THREAD_COMMENTS_LIST: (\n list: ReactNode,\n room: ReactNode | undefined,\n count: number\n ) => ReactNode;\n INBOX_NOTIFICATION_THREAD_MENTION: (\n user: ReactNode,\n room: ReactNode | undefined\n ) => ReactNode;\n INBOX_NOTIFICATION_TEXT_MENTION: (\n user: ReactNode,\n room: ReactNode | undefined\n ) => ReactNode;\n}\n\nexport type Overrides = LocalizationOverrides &\n GlobalOverrides &\n ComposerOverrides &\n CommentOverrides &\n ThreadOverrides &\n InboxNotificationOverrides;\n\ntype OverridesProviderProps = PropsWithChildren<{\n overrides?: Partial<Overrides>;\n}>;\n\nexport const defaultOverrides: Overrides = {\n locale: \"en\",\n dir: \"ltr\",\n USER_SELF: \"you\",\n USER_UNKNOWN: \"Anonymous\",\n LIST_REMAINING: (count) => `${count} more`,\n LIST_REMAINING_USERS: (count) => `${count} ${pluralize(count, \"other\")}`,\n LIST_REMAINING_COMMENTS: (count) =>\n `${count} more ${pluralize(count, \"comment\")}`,\n EMOJI_PICKER_SEARCH_PLACEHOLDER: \"Search…\",\n EMOJI_PICKER_EMPTY: \"No emoji found.\",\n EMOJI_PICKER_ERROR: () =>\n \"There was an error while getting the list of emoji.\",\n ATTACHMENT_TOO_LARGE: (maxSize) =>\n maxSize ? `The file is larger than ${maxSize}` : \"The file is too large\",\n ATTACHMENT_ERROR: () => \"The file couldn’t be uploaded.\",\n COMPOSER_INSERT_MENTION: \"Mention someone\",\n COMPOSER_INSERT_EMOJI: \"Add emoji\",\n COMPOSER_ATTACH_FILES: \"Attach files\",\n COMPOSER_REMOVE_ATTACHMENT: \"Remove attachment\",\n COMPOSER_PLACEHOLDER: \"Write a comment…\",\n COMPOSER_SEND: \"Send\",\n COMMENT_EDITED: \"(edited)\",\n COMMENT_DELETED: \"This comment has been deleted.\",\n COMMENT_MORE: \"More\",\n COMMENT_EDIT: \"Edit comment\",\n COMMENT_EDIT_COMPOSER_PLACEHOLDER: \"Edit comment…\",\n COMMENT_EDIT_COMPOSER_CANCEL: \"Cancel\",\n COMMENT_EDIT_COMPOSER_SAVE: \"Save\",\n COMMENT_DELETE: \"Delete comment\",\n COMMENT_DELETE_ATTACHMENT: \"Delete attachment\",\n COMMENT_ADD_REACTION: \"Add reaction\",\n COMMENT_REACTION_LIST: (list, emoji) => (\n <>\n {list} reacted with <Emoji emoji={emoji} />\n </>\n ),\n COMMENT_REACTION_DESCRIPTION: (emoji, count) =>\n `${count} ${pluralize(count, \"reaction\")}, react with ${emoji}`,\n THREAD_RESOLVE: \"Resolve thread\",\n THREAD_UNRESOLVE: \"Re-open thread\",\n THREAD_NEW_INDICATOR: \"New\",\n THREAD_NEW_INDICATOR_DESCRIPTION: \"New comments\",\n THREAD_COMPOSER_PLACEHOLDER: \"Reply to thread…\",\n THREAD_COMPOSER_SEND: \"Reply\",\n INBOX_NOTIFICATION_MORE: \"More\",\n INBOX_NOTIFICATION_MARK_AS_READ: \"Mark as read\",\n INBOX_NOTIFICATION_DELETE: \"Delete notification\",\n INBOX_NOTIFICATION_THREAD_COMMENTS_LIST: (\n list: ReactNode,\n room: ReactNode\n ) => (\n <>\n {list} commented\n {room ? <> in {room}</> : <> in a thread</>}\n </>\n ),\n INBOX_NOTIFICATION_THREAD_MENTION: (user: ReactNode, room: ReactNode) => (\n <>\n {user} mentioned you{room ? <> in {room}</> : null}\n </>\n ),\n INBOX_NOTIFICATION_TEXT_MENTION: (user: ReactNode, room: ReactNode) => (\n <>\n {user} mentioned you{room ? <> in {room}</> : null}\n </>\n ),\n};\n\nexport const OverridesContext = createContext<Overrides | undefined>(undefined);\n\nexport function useOverrides(overrides?: Partial<Overrides>): Overrides {\n const contextOverrides = useContext(OverridesContext);\n\n return useMemo(\n () => ({\n ...defaultOverrides,\n ...contextOverrides,\n ...overrides,\n }),\n [contextOverrides, overrides]\n );\n}\n\nexport function OverridesProvider({\n children,\n overrides: providerOverrides,\n}: OverridesProviderProps) {\n const contextOverrides = useContext(OverridesContext);\n const overrides = useMemo(\n () => ({\n ...defaultOverrides,\n ...contextOverrides,\n ...providerOverrides,\n }),\n [contextOverrides, providerOverrides]\n );\n\n return (\n <OverridesContext.Provider value={overrides}>\n {children}\n </OverridesContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;;;;AA+FO;AAAoC;AACjC;AACH;AACM;AACG;AACgB;AACuC;AAExB;AACZ;AACb;AAElB;AAEiD;AAC3B;AACC;AACF;AACA;AACK;AACN;AACP;AACC;AACC;AACH;AACA;AACqB;AACL;AACF;AACZ;AACW;AACL;AAGG;AAAM;AAC7B;AAGwD;AAC1C;AACE;AACI;AACY;AACL;AACP;AACG;AACQ;AACN;AAQzB;AAKA;AAOJ;AAEa;AAEN;AACL;AAEA;AAAO;AACE;AACF;AACA;AACA;AACL;AAC4B;AAEhC;AAEO;AAA2B;AAChC;AAEF;AACE;AACA;AAAkB;AACT;AACF;AACA;AACA;AACL;AACoC;AAGtC;AACG;AAAiC;AAItC;;"}
|
|
@@ -5,6 +5,7 @@ var React = require('react');
|
|
|
5
5
|
|
|
6
6
|
const ComposerContext = React.createContext(null);
|
|
7
7
|
const ComposerEditorContext = React.createContext(null);
|
|
8
|
+
const ComposerAttachmentsContext = React.createContext(null);
|
|
8
9
|
const ComposerSuggestionsContext = React.createContext(null);
|
|
9
10
|
function useComposerEditorContext() {
|
|
10
11
|
const composerEditorContext = React.useContext(ComposerEditorContext);
|
|
@@ -13,9 +14,15 @@ function useComposerEditorContext() {
|
|
|
13
14
|
"Composer.Form is missing from the React tree."
|
|
14
15
|
);
|
|
15
16
|
}
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
function useComposerAttachmentsContextOrNull() {
|
|
18
|
+
return React.useContext(ComposerAttachmentsContext);
|
|
19
|
+
}
|
|
20
|
+
function useComposerAttachmentsContext() {
|
|
21
|
+
const composerAttachmentsContext = useComposerAttachmentsContextOrNull();
|
|
22
|
+
return core.nn(
|
|
23
|
+
composerAttachmentsContext,
|
|
24
|
+
"Composer.Form is missing from the React tree."
|
|
25
|
+
);
|
|
19
26
|
}
|
|
20
27
|
function useComposerSuggestionsContext(source = "useComposerSuggestionsContext") {
|
|
21
28
|
const composerSuggestionsContext = React.useContext(ComposerSuggestionsContext);
|
|
@@ -24,11 +31,18 @@ function useComposerSuggestionsContext(source = "useComposerSuggestionsContext")
|
|
|
24
31
|
`${source} can\u2019t be used outside of Composer.Editor.`
|
|
25
32
|
);
|
|
26
33
|
}
|
|
34
|
+
function useComposer() {
|
|
35
|
+
const composerContext = React.useContext(ComposerContext);
|
|
36
|
+
return core.nn(composerContext, "Composer.Form is missing from the React tree.");
|
|
37
|
+
}
|
|
27
38
|
|
|
39
|
+
exports.ComposerAttachmentsContext = ComposerAttachmentsContext;
|
|
28
40
|
exports.ComposerContext = ComposerContext;
|
|
29
41
|
exports.ComposerEditorContext = ComposerEditorContext;
|
|
30
42
|
exports.ComposerSuggestionsContext = ComposerSuggestionsContext;
|
|
31
43
|
exports.useComposer = useComposer;
|
|
44
|
+
exports.useComposerAttachmentsContext = useComposerAttachmentsContext;
|
|
45
|
+
exports.useComposerAttachmentsContextOrNull = useComposerAttachmentsContextOrNull;
|
|
32
46
|
exports.useComposerEditorContext = useComposerEditorContext;
|
|
33
47
|
exports.useComposerSuggestionsContext = useComposerSuggestionsContext;
|
|
34
48
|
//# sourceMappingURL=contexts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contexts.js","sources":["../../../src/primitives/Composer/contexts.ts"],"sourcesContent":["import type { Placement } from \"@floating-ui/react-dom\";\nimport { nn } from \"@liveblocks/core\";\nimport type { Direction } from \"@radix-ui/react-dropdown-menu\";\nimport type { Dispatch, Ref, SetStateAction } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { Editor as SlateEditor, Element as SlateElement } from \"slate\";\n\nexport type ComposerContext = {\n /**\n * Whether the editor is currently focused.\n */\n isFocused: boolean;\n\n /**\n * Whether the editor is currently empty.\n */\n isEmpty: boolean;\n\n /**\n * Submit the composer programmatically.\n */\n submit: () => void;\n\n /**\n * Clear the
|
|
1
|
+
{"version":3,"file":"contexts.js","sources":["../../../src/primitives/Composer/contexts.ts"],"sourcesContent":["import type { Placement } from \"@floating-ui/react-dom\";\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { nn } from \"@liveblocks/core\";\nimport type { Direction } from \"@radix-ui/react-dropdown-menu\";\nimport type { Dispatch, Ref, SetStateAction } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { Editor as SlateEditor, Element as SlateElement } from \"slate\";\n\nexport type ComposerContext = {\n /**\n * Whether the composer is currently disabled.\n */\n isDisabled: boolean;\n\n /**\n * Whether the composer can currently be submitted.\n */\n canSubmit: boolean;\n\n /**\n * Whether the editor is currently focused.\n */\n isFocused: boolean;\n\n /**\n * Whether the editor is currently empty.\n */\n isEmpty: boolean;\n\n /**\n * Submit the composer programmatically.\n */\n submit: () => void;\n\n /**\n * Clear the composer programmatically.\n */\n clear: () => void;\n\n /**\n * Select the editor programmatically.\n */\n select: () => void;\n\n /**\n * Focus the editor programmatically.\n */\n focus: () => void;\n\n /**\n * Blur the editor programmatically.\n */\n blur: () => void;\n\n /**\n * Start creating a mention at the current selection.\n */\n createMention: () => void;\n\n /**\n * Insert text at the current selection.\n */\n insertText: (text: string) => void;\n\n /**\n * Open a file picker programmatically to create attachments.\n */\n attachFiles: () => void;\n\n /**\n * The composer's current attachments.\n */\n attachments: CommentMixedAttachment[];\n\n /**\n * Remove an attachment by its ID.\n */\n removeAttachment: (attachmentId: string) => void;\n};\n\nexport type ComposerEditorContext = {\n validate: (value: SlateElement[]) => void;\n editor: SlateEditor;\n setFocused: Dispatch<SetStateAction<boolean>>;\n};\n\nexport type ComposerAttachmentsContext = {\n canAddAttachments: boolean;\n createAttachments: (files: File[]) => void;\n isUploadingAttachments: boolean;\n maxAttachments: number;\n maxAttachmentSize: number;\n};\n\nexport type ComposerSuggestionsContext = {\n dir?: Direction;\n id: string;\n itemId: (value?: string) => string | undefined;\n placement: Placement;\n selectedValue?: string;\n setSelectedValue: (value: string) => void;\n onItemSelect: (value: string) => void;\n ref: Ref<HTMLDivElement>;\n};\n\nexport const ComposerContext = createContext<ComposerContext | null>(null);\nexport const ComposerEditorContext =\n createContext<ComposerEditorContext | null>(null);\nexport const ComposerAttachmentsContext =\n createContext<ComposerAttachmentsContext | null>(null);\nexport const ComposerSuggestionsContext =\n createContext<ComposerSuggestionsContext | null>(null);\n\nexport function useComposerEditorContext() {\n const composerEditorContext = useContext(ComposerEditorContext);\n\n return nn(\n composerEditorContext,\n \"Composer.Form is missing from the React tree.\"\n );\n}\n\nexport function useComposerAttachmentsContextOrNull() {\n return useContext(ComposerAttachmentsContext);\n}\n\nexport function useComposerAttachmentsContext() {\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n\n return nn(\n composerAttachmentsContext,\n \"Composer.Form is missing from the React tree.\"\n );\n}\n\nexport function useComposerSuggestionsContext(\n source = \"useComposerSuggestionsContext\"\n) {\n const composerSuggestionsContext = useContext(ComposerSuggestionsContext);\n\n return nn(\n composerSuggestionsContext,\n `${source} can’t be used outside of Composer.Editor.`\n );\n}\n\nexport function useComposer(): ComposerContext {\n const composerContext = useContext(ComposerContext);\n\n return nn(composerContext, \"Composer.Form is missing from the React tree.\");\n}\n"],"names":["createContext","useContext","nn"],"mappings":";;;;;AAyGa,MAAA,eAAA,GAAkBA,oBAAsC,IAAI,EAAA;AAC5D,MAAA,qBAAA,GACXA,oBAA4C,IAAI,EAAA;AACrC,MAAA,0BAAA,GACXA,oBAAiD,IAAI,EAAA;AAC1C,MAAA,0BAAA,GACXA,oBAAiD,IAAI,EAAA;AAEhD,SAAS,wBAA2B,GAAA;AACzC,EAAM,MAAA,qBAAA,GAAwBC,iBAAW,qBAAqB,CAAA,CAAA;AAE9D,EAAO,OAAAC,OAAA;AAAA,IACL,qBAAA;AAAA,IACA,+CAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEO,SAAS,mCAAsC,GAAA;AACpD,EAAA,OAAOD,iBAAW,0BAA0B,CAAA,CAAA;AAC9C,CAAA;AAEO,SAAS,6BAAgC,GAAA;AAC9C,EAAA,MAAM,6BAA6B,mCAAoC,EAAA,CAAA;AAEvE,EAAO,OAAAC,OAAA;AAAA,IACL,0BAAA;AAAA,IACA,+CAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,6BAAA,CACd,SAAS,+BACT,EAAA;AACA,EAAM,MAAA,0BAAA,GAA6BD,iBAAW,0BAA0B,CAAA,CAAA;AAExE,EAAO,OAAAC,OAAA;AAAA,IACL,0BAAA;AAAA,IACA,CAAG,EAAA,MAAA,CAAA,+CAAA,CAAA;AAAA,GACL,CAAA;AACF,CAAA;AAEO,SAAS,WAA+B,GAAA;AAC7C,EAAM,MAAA,eAAA,GAAkBD,iBAAW,eAAe,CAAA,CAAA;AAElD,EAAO,OAAAC,OAAA,CAAG,iBAAiB,+CAA+C,CAAA,CAAA;AAC5E;;;;;;;;;;;;"}
|
|
@@ -3,6 +3,7 @@ import { createContext, useContext } from 'react';
|
|
|
3
3
|
|
|
4
4
|
const ComposerContext = createContext(null);
|
|
5
5
|
const ComposerEditorContext = createContext(null);
|
|
6
|
+
const ComposerAttachmentsContext = createContext(null);
|
|
6
7
|
const ComposerSuggestionsContext = createContext(null);
|
|
7
8
|
function useComposerEditorContext() {
|
|
8
9
|
const composerEditorContext = useContext(ComposerEditorContext);
|
|
@@ -11,9 +12,15 @@ function useComposerEditorContext() {
|
|
|
11
12
|
"Composer.Form is missing from the React tree."
|
|
12
13
|
);
|
|
13
14
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
function useComposerAttachmentsContextOrNull() {
|
|
16
|
+
return useContext(ComposerAttachmentsContext);
|
|
17
|
+
}
|
|
18
|
+
function useComposerAttachmentsContext() {
|
|
19
|
+
const composerAttachmentsContext = useComposerAttachmentsContextOrNull();
|
|
20
|
+
return nn(
|
|
21
|
+
composerAttachmentsContext,
|
|
22
|
+
"Composer.Form is missing from the React tree."
|
|
23
|
+
);
|
|
17
24
|
}
|
|
18
25
|
function useComposerSuggestionsContext(source = "useComposerSuggestionsContext") {
|
|
19
26
|
const composerSuggestionsContext = useContext(ComposerSuggestionsContext);
|
|
@@ -22,6 +29,10 @@ function useComposerSuggestionsContext(source = "useComposerSuggestionsContext")
|
|
|
22
29
|
`${source} can\u2019t be used outside of Composer.Editor.`
|
|
23
30
|
);
|
|
24
31
|
}
|
|
32
|
+
function useComposer() {
|
|
33
|
+
const composerContext = useContext(ComposerContext);
|
|
34
|
+
return nn(composerContext, "Composer.Form is missing from the React tree.");
|
|
35
|
+
}
|
|
25
36
|
|
|
26
|
-
export { ComposerContext, ComposerEditorContext, ComposerSuggestionsContext, useComposer, useComposerEditorContext, useComposerSuggestionsContext };
|
|
37
|
+
export { ComposerAttachmentsContext, ComposerContext, ComposerEditorContext, ComposerSuggestionsContext, useComposer, useComposerAttachmentsContext, useComposerAttachmentsContextOrNull, useComposerEditorContext, useComposerSuggestionsContext };
|
|
27
38
|
//# sourceMappingURL=contexts.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contexts.mjs","sources":["../../../src/primitives/Composer/contexts.ts"],"sourcesContent":["import type { Placement } from \"@floating-ui/react-dom\";\nimport { nn } from \"@liveblocks/core\";\nimport type { Direction } from \"@radix-ui/react-dropdown-menu\";\nimport type { Dispatch, Ref, SetStateAction } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { Editor as SlateEditor, Element as SlateElement } from \"slate\";\n\nexport type ComposerContext = {\n /**\n * Whether the editor is currently focused.\n */\n isFocused: boolean;\n\n /**\n * Whether the editor is currently empty.\n */\n isEmpty: boolean;\n\n /**\n * Submit the composer programmatically.\n */\n submit: () => void;\n\n /**\n * Clear the
|
|
1
|
+
{"version":3,"file":"contexts.mjs","sources":["../../../src/primitives/Composer/contexts.ts"],"sourcesContent":["import type { Placement } from \"@floating-ui/react-dom\";\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { nn } from \"@liveblocks/core\";\nimport type { Direction } from \"@radix-ui/react-dropdown-menu\";\nimport type { Dispatch, Ref, SetStateAction } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { Editor as SlateEditor, Element as SlateElement } from \"slate\";\n\nexport type ComposerContext = {\n /**\n * Whether the composer is currently disabled.\n */\n isDisabled: boolean;\n\n /**\n * Whether the composer can currently be submitted.\n */\n canSubmit: boolean;\n\n /**\n * Whether the editor is currently focused.\n */\n isFocused: boolean;\n\n /**\n * Whether the editor is currently empty.\n */\n isEmpty: boolean;\n\n /**\n * Submit the composer programmatically.\n */\n submit: () => void;\n\n /**\n * Clear the composer programmatically.\n */\n clear: () => void;\n\n /**\n * Select the editor programmatically.\n */\n select: () => void;\n\n /**\n * Focus the editor programmatically.\n */\n focus: () => void;\n\n /**\n * Blur the editor programmatically.\n */\n blur: () => void;\n\n /**\n * Start creating a mention at the current selection.\n */\n createMention: () => void;\n\n /**\n * Insert text at the current selection.\n */\n insertText: (text: string) => void;\n\n /**\n * Open a file picker programmatically to create attachments.\n */\n attachFiles: () => void;\n\n /**\n * The composer's current attachments.\n */\n attachments: CommentMixedAttachment[];\n\n /**\n * Remove an attachment by its ID.\n */\n removeAttachment: (attachmentId: string) => void;\n};\n\nexport type ComposerEditorContext = {\n validate: (value: SlateElement[]) => void;\n editor: SlateEditor;\n setFocused: Dispatch<SetStateAction<boolean>>;\n};\n\nexport type ComposerAttachmentsContext = {\n canAddAttachments: boolean;\n createAttachments: (files: File[]) => void;\n isUploadingAttachments: boolean;\n maxAttachments: number;\n maxAttachmentSize: number;\n};\n\nexport type ComposerSuggestionsContext = {\n dir?: Direction;\n id: string;\n itemId: (value?: string) => string | undefined;\n placement: Placement;\n selectedValue?: string;\n setSelectedValue: (value: string) => void;\n onItemSelect: (value: string) => void;\n ref: Ref<HTMLDivElement>;\n};\n\nexport const ComposerContext = createContext<ComposerContext | null>(null);\nexport const ComposerEditorContext =\n createContext<ComposerEditorContext | null>(null);\nexport const ComposerAttachmentsContext =\n createContext<ComposerAttachmentsContext | null>(null);\nexport const ComposerSuggestionsContext =\n createContext<ComposerSuggestionsContext | null>(null);\n\nexport function useComposerEditorContext() {\n const composerEditorContext = useContext(ComposerEditorContext);\n\n return nn(\n composerEditorContext,\n \"Composer.Form is missing from the React tree.\"\n );\n}\n\nexport function useComposerAttachmentsContextOrNull() {\n return useContext(ComposerAttachmentsContext);\n}\n\nexport function useComposerAttachmentsContext() {\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n\n return nn(\n composerAttachmentsContext,\n \"Composer.Form is missing from the React tree.\"\n );\n}\n\nexport function useComposerSuggestionsContext(\n source = \"useComposerSuggestionsContext\"\n) {\n const composerSuggestionsContext = useContext(ComposerSuggestionsContext);\n\n return nn(\n composerSuggestionsContext,\n `${source} can’t be used outside of Composer.Editor.`\n );\n}\n\nexport function useComposer(): ComposerContext {\n const composerContext = useContext(ComposerContext);\n\n return nn(composerContext, \"Composer.Form is missing from the React tree.\");\n}\n"],"names":[],"mappings":";;;AAyGa,MAAA,eAAA,GAAkB,cAAsC,IAAI,EAAA;AAC5D,MAAA,qBAAA,GACX,cAA4C,IAAI,EAAA;AACrC,MAAA,0BAAA,GACX,cAAiD,IAAI,EAAA;AAC1C,MAAA,0BAAA,GACX,cAAiD,IAAI,EAAA;AAEhD,SAAS,wBAA2B,GAAA;AACzC,EAAM,MAAA,qBAAA,GAAwB,WAAW,qBAAqB,CAAA,CAAA;AAE9D,EAAO,OAAA,EAAA;AAAA,IACL,qBAAA;AAAA,IACA,+CAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEO,SAAS,mCAAsC,GAAA;AACpD,EAAA,OAAO,WAAW,0BAA0B,CAAA,CAAA;AAC9C,CAAA;AAEO,SAAS,6BAAgC,GAAA;AAC9C,EAAA,MAAM,6BAA6B,mCAAoC,EAAA,CAAA;AAEvE,EAAO,OAAA,EAAA;AAAA,IACL,0BAAA;AAAA,IACA,+CAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,6BAAA,CACd,SAAS,+BACT,EAAA;AACA,EAAM,MAAA,0BAAA,GAA6B,WAAW,0BAA0B,CAAA,CAAA;AAExE,EAAO,OAAA,EAAA;AAAA,IACL,0BAAA;AAAA,IACA,CAAG,EAAA,MAAA,CAAA,+CAAA,CAAA;AAAA,GACL,CAAA;AACF,CAAA;AAEO,SAAS,WAA+B,GAAA;AAC7C,EAAM,MAAA,eAAA,GAAkB,WAAW,eAAe,CAAA,CAAA;AAElD,EAAO,OAAA,EAAA,CAAG,iBAAiB,+CAA+C,CAAA,CAAA;AAC5E;;;;"}
|
|
@@ -41,6 +41,8 @@ const COMPOSER_SUGGESTIONS_LIST_NAME = "ComposerSuggestionsList";
|
|
|
41
41
|
const COMPOSER_SUGGESTIONS_LIST_ITEM_NAME = "ComposerSuggestionsListItem";
|
|
42
42
|
const COMPOSER_SUBMIT_NAME = "ComposerSubmit";
|
|
43
43
|
const COMPOSER_EDITOR_NAME = "ComposerEditor";
|
|
44
|
+
const COMPOSER_ATTACH_FILES_NAME = "ComposerAttachFiles";
|
|
45
|
+
const COMPOSER_ATTACHMENTS_DROP_AREA_NAME = "ComposerAttachmentsDropArea";
|
|
44
46
|
const COMPOSER_FORM_NAME = "ComposerForm";
|
|
45
47
|
const emptyCommentBody = {
|
|
46
48
|
version: 1,
|
|
@@ -390,13 +392,16 @@ const ComposerEditor = React.forwardRef(
|
|
|
390
392
|
dir,
|
|
391
393
|
...props
|
|
392
394
|
}, forwardedRef) => {
|
|
393
|
-
const self = react.useSelf();
|
|
394
|
-
const isDisabled = React.useMemo(
|
|
395
|
-
() => disabled || (self ? !self.canComment : false),
|
|
396
|
-
[disabled, self?.canComment]
|
|
397
|
-
);
|
|
398
395
|
const { editor, validate, setFocused } = contexts.useComposerEditorContext();
|
|
399
|
-
const {
|
|
396
|
+
const {
|
|
397
|
+
submit,
|
|
398
|
+
focus,
|
|
399
|
+
select,
|
|
400
|
+
canSubmit,
|
|
401
|
+
isDisabled: isComposerDisabled,
|
|
402
|
+
isFocused
|
|
403
|
+
} = contexts.useComposer();
|
|
404
|
+
const isDisabled = isComposerDisabled || disabled;
|
|
400
405
|
const initialBody = useInitial.useInitial(defaultValue ?? emptyCommentBody);
|
|
401
406
|
const initialEditorValue = React.useMemo(() => {
|
|
402
407
|
return utils.commentBodyToComposerBody(initialBody);
|
|
@@ -487,9 +492,11 @@ const ComposerEditor = React.forwardRef(
|
|
|
487
492
|
event.preventDefault();
|
|
488
493
|
slateReact.ReactEditor.blur(editor);
|
|
489
494
|
}
|
|
490
|
-
if (isKey.isKey(event, "Enter", { shift: false })
|
|
495
|
+
if (isKey.isKey(event, "Enter", { shift: false })) {
|
|
491
496
|
event.preventDefault();
|
|
492
|
-
|
|
497
|
+
if (canSubmit) {
|
|
498
|
+
submit();
|
|
499
|
+
}
|
|
493
500
|
}
|
|
494
501
|
if (isKey.isKey(event, "Enter", { shift: true })) {
|
|
495
502
|
event.preventDefault();
|
|
@@ -516,7 +523,7 @@ const ComposerEditor = React.forwardRef(
|
|
|
516
523
|
[
|
|
517
524
|
createMention,
|
|
518
525
|
editor,
|
|
519
|
-
|
|
526
|
+
canSubmit,
|
|
520
527
|
mentionDraft,
|
|
521
528
|
mentionSuggestions,
|
|
522
529
|
selectedMentionSuggestionIndex,
|
|
@@ -622,14 +629,48 @@ const ComposerEditor = React.forwardRef(
|
|
|
622
629
|
}));
|
|
623
630
|
}
|
|
624
631
|
);
|
|
632
|
+
const MAX_ATTACHMENTS = 5;
|
|
633
|
+
const MAX_ATTACHMENT_SIZE = 20 * 1024 * 1024;
|
|
625
634
|
const ComposerForm = React.forwardRef(
|
|
626
|
-
({
|
|
635
|
+
({
|
|
636
|
+
children,
|
|
637
|
+
onSubmit,
|
|
638
|
+
onComposerSubmit,
|
|
639
|
+
defaultAttachments = [],
|
|
640
|
+
disabled,
|
|
641
|
+
asChild,
|
|
642
|
+
...props
|
|
643
|
+
}, forwardedRef) => {
|
|
627
644
|
const Component = asChild ? reactSlot.Slot : "form";
|
|
628
645
|
const editor = useInitial.useInitial(createComposerEditor);
|
|
646
|
+
const room = react.useRoom();
|
|
629
647
|
const [isEmpty$1, setEmpty] = React.useState(true);
|
|
648
|
+
const [isSubmitting, setSubmitting] = React.useState(false);
|
|
630
649
|
const [isFocused, setFocused] = React.useState(false);
|
|
650
|
+
const maxAttachments = MAX_ATTACHMENTS;
|
|
651
|
+
const maxAttachmentSize = MAX_ATTACHMENT_SIZE;
|
|
652
|
+
const {
|
|
653
|
+
attachments,
|
|
654
|
+
isUploadingAttachments,
|
|
655
|
+
addAttachment,
|
|
656
|
+
removeAttachment,
|
|
657
|
+
clearAttachments
|
|
658
|
+
} = utils.useComposerAttachmentsManager(defaultAttachments, {
|
|
659
|
+
maxFileSize: maxAttachmentSize
|
|
660
|
+
});
|
|
661
|
+
const numberOfAttachments = attachments.length;
|
|
662
|
+
const canAddAttachments = numberOfAttachments < maxAttachments;
|
|
663
|
+
const isDisabled = React.useMemo(() => {
|
|
664
|
+
const self = room.getSelf();
|
|
665
|
+
const canComment = self?.canComment ?? true;
|
|
666
|
+
return isSubmitting || disabled || !canComment;
|
|
667
|
+
}, [isSubmitting, disabled, room]);
|
|
668
|
+
const canSubmit = React.useMemo(() => {
|
|
669
|
+
return !isEmpty$1 && !isUploadingAttachments;
|
|
670
|
+
}, [isEmpty$1, isUploadingAttachments]);
|
|
631
671
|
const ref = React.useRef(null);
|
|
632
672
|
const mergedRefs = useRefs.useRefs(forwardedRef, ref);
|
|
673
|
+
const fileInputRef = React.useRef(null);
|
|
633
674
|
const validate = React.useCallback(
|
|
634
675
|
(value) => {
|
|
635
676
|
setEmpty(isEmpty.isEmpty(editor, value));
|
|
@@ -637,12 +678,15 @@ const ComposerForm = React.forwardRef(
|
|
|
637
678
|
[editor]
|
|
638
679
|
);
|
|
639
680
|
const submit = React.useCallback(() => {
|
|
681
|
+
if (!canSubmit) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
640
684
|
requestAnimationFrame(() => {
|
|
641
685
|
if (ref.current) {
|
|
642
686
|
requestSubmit.requestSubmit(ref.current);
|
|
643
687
|
}
|
|
644
688
|
});
|
|
645
|
-
}, []);
|
|
689
|
+
}, [canSubmit]);
|
|
646
690
|
const clear = React.useCallback(() => {
|
|
647
691
|
slate.Transforms.delete(editor, {
|
|
648
692
|
at: {
|
|
@@ -672,10 +716,6 @@ const ComposerForm = React.forwardRef(
|
|
|
672
716
|
const blur = React.useCallback(() => {
|
|
673
717
|
slateReact.ReactEditor.blur(editor);
|
|
674
718
|
}, [editor]);
|
|
675
|
-
const onSubmitEnd = React.useCallback(() => {
|
|
676
|
-
clear();
|
|
677
|
-
blur();
|
|
678
|
-
}, [blur, clear]);
|
|
679
719
|
const createMention = React.useCallback(() => {
|
|
680
720
|
focus();
|
|
681
721
|
mentions.insertMentionCharacter(editor);
|
|
@@ -687,6 +727,42 @@ const ComposerForm = React.forwardRef(
|
|
|
687
727
|
},
|
|
688
728
|
[editor, focus]
|
|
689
729
|
);
|
|
730
|
+
const createAttachments = React.useCallback(
|
|
731
|
+
(files) => {
|
|
732
|
+
if (!files.length) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const numberOfAcceptedFiles = Math.max(
|
|
736
|
+
0,
|
|
737
|
+
maxAttachments - numberOfAttachments
|
|
738
|
+
);
|
|
739
|
+
files.splice(numberOfAcceptedFiles);
|
|
740
|
+
for (const file of files) {
|
|
741
|
+
const attachment = room.prepareAttachment(file);
|
|
742
|
+
addAttachment(attachment);
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
[addAttachment, maxAttachments, numberOfAttachments, room]
|
|
746
|
+
);
|
|
747
|
+
const attachFiles = React.useCallback(() => {
|
|
748
|
+
if (fileInputRef.current) {
|
|
749
|
+
fileInputRef.current.click();
|
|
750
|
+
}
|
|
751
|
+
}, []);
|
|
752
|
+
const handleAttachmentsInputChange = React.useCallback(
|
|
753
|
+
(event) => {
|
|
754
|
+
if (event.target.files) {
|
|
755
|
+
createAttachments(Array.from(event.target.files));
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
[createAttachments]
|
|
759
|
+
);
|
|
760
|
+
const onSubmitEnd = React.useCallback(() => {
|
|
761
|
+
clear();
|
|
762
|
+
blur();
|
|
763
|
+
clearAttachments();
|
|
764
|
+
setSubmitting(false);
|
|
765
|
+
}, [blur, clear, clearAttachments]);
|
|
690
766
|
const handleSubmit = React.useCallback(
|
|
691
767
|
(event) => {
|
|
692
768
|
const isEmpty2 = isEmpty.isEmpty(editor, editor.children);
|
|
@@ -702,16 +778,30 @@ const ComposerForm = React.forwardRef(
|
|
|
702
778
|
const body = utils.composerBodyToCommentBody(
|
|
703
779
|
editor.children
|
|
704
780
|
);
|
|
705
|
-
const
|
|
706
|
-
|
|
781
|
+
const commentAttachments = attachments.filter(
|
|
782
|
+
(attachment) => attachment.type === "attachment" || attachment.type === "localAttachment" && attachment.status === "uploaded"
|
|
783
|
+
).map((attachment) => {
|
|
784
|
+
return {
|
|
785
|
+
id: attachment.id,
|
|
786
|
+
type: "attachment",
|
|
787
|
+
mimeType: attachment.mimeType,
|
|
788
|
+
size: attachment.size,
|
|
789
|
+
name: attachment.name
|
|
790
|
+
};
|
|
791
|
+
});
|
|
792
|
+
const promise = onComposerSubmit(
|
|
793
|
+
{ body, attachments: commentAttachments },
|
|
794
|
+
event
|
|
795
|
+
);
|
|
707
796
|
event.preventDefault();
|
|
708
797
|
if (promise) {
|
|
798
|
+
setSubmitting(true);
|
|
709
799
|
promise.then(onSubmitEnd);
|
|
710
800
|
} else {
|
|
711
801
|
onSubmitEnd();
|
|
712
802
|
}
|
|
713
803
|
},
|
|
714
|
-
[editor, onComposerSubmit, onSubmit, onSubmitEnd]
|
|
804
|
+
[editor, attachments, onComposerSubmit, onSubmit, onSubmitEnd]
|
|
715
805
|
);
|
|
716
806
|
return /* @__PURE__ */ React.createElement(contexts.ComposerEditorContext.Provider, {
|
|
717
807
|
value: {
|
|
@@ -719,34 +809,50 @@ const ComposerForm = React.forwardRef(
|
|
|
719
809
|
validate,
|
|
720
810
|
setFocused
|
|
721
811
|
}
|
|
812
|
+
}, /* @__PURE__ */ React.createElement(contexts.ComposerAttachmentsContext.Provider, {
|
|
813
|
+
value: {
|
|
814
|
+
createAttachments,
|
|
815
|
+
isUploadingAttachments,
|
|
816
|
+
canAddAttachments,
|
|
817
|
+
maxAttachments,
|
|
818
|
+
maxAttachmentSize
|
|
819
|
+
}
|
|
722
820
|
}, /* @__PURE__ */ React.createElement(contexts.ComposerContext.Provider, {
|
|
723
821
|
value: {
|
|
822
|
+
isDisabled,
|
|
724
823
|
isFocused,
|
|
725
824
|
isEmpty: isEmpty$1,
|
|
825
|
+
canSubmit,
|
|
726
826
|
submit,
|
|
727
827
|
clear,
|
|
728
828
|
select,
|
|
729
829
|
focus,
|
|
730
830
|
blur,
|
|
731
831
|
createMention,
|
|
732
|
-
insertText
|
|
832
|
+
insertText,
|
|
833
|
+
attachments,
|
|
834
|
+
attachFiles,
|
|
835
|
+
removeAttachment
|
|
733
836
|
}
|
|
734
837
|
}, /* @__PURE__ */ React.createElement(Component, {
|
|
735
838
|
...props,
|
|
736
839
|
onSubmit: handleSubmit,
|
|
737
840
|
ref: mergedRefs
|
|
738
|
-
},
|
|
841
|
+
}, /* @__PURE__ */ React.createElement("input", {
|
|
842
|
+
type: "file",
|
|
843
|
+
multiple: true,
|
|
844
|
+
ref: fileInputRef,
|
|
845
|
+
onChange: handleAttachmentsInputChange,
|
|
846
|
+
tabIndex: -1,
|
|
847
|
+
style: { display: "none" }
|
|
848
|
+
}), /* @__PURE__ */ React.createElement(reactSlot.Slottable, null, children)))));
|
|
739
849
|
}
|
|
740
850
|
);
|
|
741
851
|
const ComposerSubmit = React.forwardRef(
|
|
742
852
|
({ children, disabled, asChild, ...props }, forwardedRef) => {
|
|
743
853
|
const Component = asChild ? reactSlot.Slot : "button";
|
|
744
|
-
const {
|
|
745
|
-
const
|
|
746
|
-
const isDisabled = React.useMemo(
|
|
747
|
-
() => disabled || isEmpty || (self ? !self.canComment : false),
|
|
748
|
-
[disabled, isEmpty, self?.canComment]
|
|
749
|
-
);
|
|
854
|
+
const { canSubmit, isDisabled: isComposerDisabled } = contexts.useComposer();
|
|
855
|
+
const isDisabled = isComposerDisabled || disabled || !canSubmit;
|
|
750
856
|
return /* @__PURE__ */ React.createElement(Component, {
|
|
751
857
|
type: "submit",
|
|
752
858
|
...props,
|
|
@@ -755,7 +861,58 @@ const ComposerSubmit = React.forwardRef(
|
|
|
755
861
|
}, children);
|
|
756
862
|
}
|
|
757
863
|
);
|
|
864
|
+
const ComposerAttachFiles = React.forwardRef(({ children, onClick, disabled, asChild, ...props }, forwardedRef) => {
|
|
865
|
+
const Component = asChild ? reactSlot.Slot : "button";
|
|
866
|
+
const { canAddAttachments } = contexts.useComposerAttachmentsContext();
|
|
867
|
+
const { isDisabled: isComposerDisabled, attachFiles } = contexts.useComposer();
|
|
868
|
+
const isDisabled = isComposerDisabled || !canAddAttachments || disabled;
|
|
869
|
+
const handleClick = React.useCallback(
|
|
870
|
+
(event) => {
|
|
871
|
+
onClick?.(event);
|
|
872
|
+
if (!event.isDefaultPrevented()) {
|
|
873
|
+
attachFiles();
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
[attachFiles, onClick]
|
|
877
|
+
);
|
|
878
|
+
return /* @__PURE__ */ React.createElement(Component, {
|
|
879
|
+
...props,
|
|
880
|
+
onClick: handleClick,
|
|
881
|
+
ref: forwardedRef,
|
|
882
|
+
disabled: isDisabled
|
|
883
|
+
}, children);
|
|
884
|
+
});
|
|
885
|
+
const ComposerAttachmentsDropArea = React.forwardRef(
|
|
886
|
+
({
|
|
887
|
+
onDragEnter,
|
|
888
|
+
onDragLeave,
|
|
889
|
+
onDragOver,
|
|
890
|
+
onDrop,
|
|
891
|
+
disabled,
|
|
892
|
+
asChild,
|
|
893
|
+
...props
|
|
894
|
+
}, forwardedRef) => {
|
|
895
|
+
const Component = asChild ? reactSlot.Slot : "div";
|
|
896
|
+
const { isDisabled: isComposerDisabled } = contexts.useComposer();
|
|
897
|
+
const isDisabled = isComposerDisabled || disabled;
|
|
898
|
+
const [, dropAreaProps] = utils.useComposerAttachmentsDropArea({
|
|
899
|
+
onDragEnter,
|
|
900
|
+
onDragLeave,
|
|
901
|
+
onDragOver,
|
|
902
|
+
onDrop,
|
|
903
|
+
disabled: isDisabled
|
|
904
|
+
});
|
|
905
|
+
return /* @__PURE__ */ React.createElement(Component, {
|
|
906
|
+
...dropAreaProps,
|
|
907
|
+
"data-disabled": isDisabled ? "" : void 0,
|
|
908
|
+
...props,
|
|
909
|
+
ref: forwardedRef
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
);
|
|
758
913
|
if (process.env.NODE_ENV !== "production") {
|
|
914
|
+
ComposerAttachFiles.displayName = COMPOSER_ATTACH_FILES_NAME;
|
|
915
|
+
ComposerAttachmentsDropArea.displayName = COMPOSER_ATTACHMENTS_DROP_AREA_NAME;
|
|
759
916
|
ComposerEditor.displayName = COMPOSER_EDITOR_NAME;
|
|
760
917
|
ComposerForm.displayName = COMPOSER_FORM_NAME;
|
|
761
918
|
ComposerMention.displayName = COMPOSER_MENTION_NAME;
|
|
@@ -766,6 +923,8 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
766
923
|
ComposerSuggestionsListItem.displayName = COMPOSER_SUGGESTIONS_LIST_ITEM_NAME;
|
|
767
924
|
}
|
|
768
925
|
|
|
926
|
+
exports.AttachFiles = ComposerAttachFiles;
|
|
927
|
+
exports.AttachmentsDropArea = ComposerAttachmentsDropArea;
|
|
769
928
|
exports.Editor = ComposerEditor;
|
|
770
929
|
exports.Form = ComposerForm;
|
|
771
930
|
exports.Link = ComposerLink;
|