@edifice.io/react 2.2.2 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/components/Avatar/Avatar.d.ts +21 -0
  2. package/dist/components/Avatar/Avatar.js +15 -2
  3. package/dist/components/AvatarGroup/AvatarGroup.d.ts +24 -0
  4. package/dist/components/AvatarGroup/AvatarGroup.js +24 -0
  5. package/dist/components/AvatarGroup/index.d.ts +2 -0
  6. package/dist/components/Card/Card.d.ts +3 -1
  7. package/dist/components/Card/CardBody.d.ts +3 -1
  8. package/dist/components/Card/CardBody.js +4 -2
  9. package/dist/components/Dropdown/Dropdown.d.ts +6 -2
  10. package/dist/components/Dropdown/Dropdown.js +2 -0
  11. package/dist/components/Dropdown/DropdownItem.d.ts +5 -1
  12. package/dist/components/Dropdown/DropdownItem.js +7 -2
  13. package/dist/components/Dropdown/DropdownTrigger.d.ts +31 -2
  14. package/dist/components/Dropdown/DropdownTrigger.js +23 -3
  15. package/dist/components/PreventPropagation/PreventPropagation.d.ts +10 -0
  16. package/dist/components/PreventPropagation/PreventPropagation.js +9 -0
  17. package/dist/components/PreventPropagation/index.d.ts +2 -0
  18. package/dist/components/StackedGroup/StackedGroup.d.ts +23 -0
  19. package/dist/components/StackedGroup/StackedGroup.js +21 -0
  20. package/dist/components/StackedGroup/index.d.ts +1 -0
  21. package/dist/components/Switch/Switch.d.ts +29 -0
  22. package/dist/components/Switch/Switch.js +27 -0
  23. package/dist/components/Switch/index.d.ts +2 -0
  24. package/dist/components/index.d.ts +4 -0
  25. package/dist/editor.js +16 -12
  26. package/dist/hooks/useConf/useConf.d.ts +1 -1
  27. package/dist/hooks/useSession/useSession.d.ts +1 -1
  28. package/dist/icons.js +178 -176
  29. package/dist/index.js +154 -146
  30. package/dist/modules/comments/components/Comment.js +49 -34
  31. package/dist/modules/comments/components/CommentDeleted.d.ts +1 -0
  32. package/dist/modules/comments/components/CommentDeleted.js +11 -0
  33. package/dist/modules/comments/components/CommentForm.d.ts +2 -1
  34. package/dist/modules/comments/components/CommentForm.js +12 -8
  35. package/dist/modules/comments/components/CommentList.js +3 -3
  36. package/dist/modules/comments/components/CommentReplies.d.ts +4 -0
  37. package/dist/modules/comments/components/CommentReplies.js +33 -0
  38. package/dist/modules/comments/constants.d.ts +4 -0
  39. package/dist/modules/comments/constants.js +2 -1
  40. package/dist/modules/comments/context/Context.d.ts +6 -4
  41. package/dist/modules/comments/hooks/useCommentReplies.d.ts +12 -0
  42. package/dist/modules/comments/hooks/useCommentReplies.js +36 -0
  43. package/dist/modules/comments/hooks/useComments.d.ts +7 -7
  44. package/dist/modules/comments/hooks/useComments.js +24 -19
  45. package/dist/modules/comments/hooks/useCommentsContext.d.ts +6 -4
  46. package/dist/modules/comments/provider/CommentProvider.js +16 -13
  47. package/dist/modules/comments/types.d.ts +14 -1
  48. package/dist/modules/editor/components/BubbleMenuEditInformationPane/BubbleMenuEditInformationPane.d.ts +6 -0
  49. package/dist/modules/editor/components/BubbleMenuEditInformationPane/BubbleMenuEditInformationPane.js +136 -0
  50. package/dist/modules/editor/components/BubbleMenuEditInformationPane/index.d.ts +1 -0
  51. package/dist/modules/editor/components/Editor/Editor.js +6 -2
  52. package/dist/modules/editor/components/EditorToolbar/EditorToolbar.js +12 -0
  53. package/dist/modules/editor/components/NodeView/InformationPaneNodeView.d.ts +2 -0
  54. package/dist/modules/editor/components/NodeView/InformationPaneNodeView.js +10 -0
  55. package/dist/modules/editor/components/NodeView/index.d.ts +1 -0
  56. package/dist/modules/editor/components/Renderer/InformationPaneRenderer.d.ts +3 -0
  57. package/dist/modules/editor/components/Renderer/InformationPaneRenderer.js +33 -0
  58. package/dist/modules/editor/components/Renderer/index.d.ts +1 -0
  59. package/dist/modules/editor/hooks/useTipTapEditor.js +3 -1
  60. package/dist/modules/icons/components/IconInfoRectangle.d.ts +7 -0
  61. package/dist/modules/icons/components/IconInfoRectangle.js +13 -0
  62. package/dist/modules/icons/components/index.d.ts +1 -0
  63. package/dist/modules/modals/ResourceModal/ResourceModal.d.ts +1 -1
  64. package/dist/modules/modals/ResourceModal/hooks/useUpdateMutation.d.ts +1 -1
  65. package/dist/modules/modals/ShareModal/ShareModal.d.ts +1 -1
  66. package/dist/modules/modals/ShareModal/apps/ShareBlog.d.ts +1 -1
  67. package/dist/modules/modals/ShareModal/hooks/useShareMutation.d.ts +1 -1
  68. package/dist/providers/EdificeClientProvider/EdificeClientProvider.context.d.ts +1 -1
  69. package/dist/types/index.d.ts +1 -0
  70. package/package.json +6 -6
@@ -1,18 +1,20 @@
1
1
  import { RightRole } from '@edifice.io/client';
2
2
  import { CommentOptions, CommentProps, CommentType, UserProfileResult } from '../types';
3
3
  export declare const CommentContext: import('react').Context<{
4
- comments: CommentProps[] | undefined;
5
- content: string;
4
+ displayedComments: CommentProps[] | undefined;
5
+ defaultComments: CommentProps[] | undefined;
6
6
  editCommentId: string | null;
7
+ replyToCommentId: string | null;
7
8
  profiles: (UserProfileResult | undefined)[];
8
9
  options: Partial<CommentOptions>;
9
10
  type: CommentType;
10
11
  userRights?: Record<RightRole, boolean>;
11
12
  setEditCommentId: (value: string | null) => void;
13
+ setReplyToCommentId: (value: string | null) => void;
12
14
  handleModifyComment: (commentId: string) => void;
13
- handleChangeContent: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
14
- handleCreateComment: (content: string) => void;
15
+ handleCreateComment: (content: string, replyTo?: string) => void;
15
16
  handleUpdateComment: (comment: string) => void;
16
17
  handleDeleteComment: (id: string) => void;
18
+ handleReplyToComment: (commentId: string) => void;
17
19
  handleReset: () => void;
18
20
  } | null>;
@@ -0,0 +1,12 @@
1
+ import { CommentProps } from '../types';
2
+ export declare const useCommentReplies: ({ parentComment, }: {
3
+ parentComment: CommentProps;
4
+ }) => {
5
+ t: import('i18next').TFunction<"translation", undefined>;
6
+ profiles: (import('../types').UserProfileResult | undefined)[];
7
+ user: import('@edifice.io/client').IUserInfo | undefined;
8
+ showCommentForm: boolean;
9
+ displayedReplies: CommentProps[];
10
+ showMoreReplies: boolean;
11
+ handleMoreReplies: () => void;
12
+ };
@@ -0,0 +1,36 @@
1
+ import { useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { useEdificeClient } from "../../../providers/EdificeClientProvider/EdificeClientProvider.hook.js";
4
+ import { useCommentsContext } from "./useCommentsContext.js";
5
+ const useCommentReplies = ({
6
+ parentComment
7
+ }) => {
8
+ const {
9
+ profiles,
10
+ options,
11
+ replyToCommentId,
12
+ defaultComments
13
+ } = useCommentsContext(), {
14
+ maxReplies,
15
+ additionalReplies
16
+ } = options, [repliesLimit, setRepliesLimit] = useState(maxReplies), {
17
+ user
18
+ } = useEdificeClient(), {
19
+ t
20
+ } = useTranslation(), showCommentForm = replyToCommentId === parentComment.id && !parentComment.deleted, defaultReplies = (defaultComments == null ? void 0 : defaultComments.filter((comment) => comment.replyTo === parentComment.id && !comment.deleted)) ?? [], displayedReplies = (defaultReplies == null ? void 0 : defaultReplies.sort((a, b) => a.createdAt - b.createdAt).slice(0, repliesLimit)) ?? [], showMoreReplies = displayedReplies.length < defaultReplies.length;
21
+ return {
22
+ t,
23
+ profiles,
24
+ user,
25
+ showCommentForm,
26
+ displayedReplies,
27
+ showMoreReplies,
28
+ handleMoreReplies: () => {
29
+ const newLimit = displayedReplies.length + (additionalReplies ?? 2);
30
+ newLimit !== displayedReplies.length && setRepliesLimit(newLimit);
31
+ }
32
+ };
33
+ };
34
+ export {
35
+ useCommentReplies
36
+ };
@@ -5,6 +5,7 @@ export declare const useComments: ({ defaultComments, options, type, callbacks,
5
5
  type: CommentType;
6
6
  callbacks: CommentCallbacks | null;
7
7
  }) => {
8
+ t: import('i18next').TFunction<"translation", undefined>;
8
9
  profilesQueries: {
9
10
  data: ({
10
11
  userId: string;
@@ -12,21 +13,20 @@ export declare const useComments: ({ defaultComments, options, type, callbacks,
12
13
  } | undefined)[];
13
14
  isLoading: boolean;
14
15
  };
15
- content: string;
16
16
  title: string;
17
17
  user: import('@edifice.io/client').IUserInfo | undefined;
18
18
  emptyscreenPath: string;
19
- defaultCommentsCount: number;
20
- comments: CommentProps[];
19
+ displayedComments: CommentProps[];
20
+ showMoreComments: boolean;
21
21
  editCommentId: string | null;
22
22
  setEditCommentId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
23
- commentsCount: number;
24
- t: import('i18next').TFunction<"translation", undefined>;
23
+ replyToCommentId: string | null;
24
+ setReplyToCommentId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
25
25
  handleMoreComments: () => void;
26
- handleChangeContent: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
27
26
  handleDeleteComment: (id: string) => void;
28
- handleCreateComment: (content: string) => void;
27
+ handleCreateComment: (content: string, replyTo?: string) => void;
29
28
  handleModifyComment: (commentId: string) => void;
30
29
  handleUpdateComment: (comment: string) => Promise<void>;
30
+ handleReplyToComment: (commentId: string) => void;
31
31
  handleReset: () => void;
32
32
  };
@@ -9,43 +9,45 @@ const useComments = ({
9
9
  type,
10
10
  callbacks
11
11
  }) => {
12
- const [content, setContent] = useState(""), [editCommentId, setEditCommentId] = useState(null), [commentLimit, setCommentLimit] = useState(options.maxComments), {
12
+ var _a, _b;
13
+ const [editCommentId, setEditCommentId] = useState(null), [replyToCommentId, setReplyToCommentId] = useState(null), [commentLimit, setCommentLimit] = useState(options.maxComments), {
13
14
  t
14
15
  } = useTranslation(), {
15
16
  user
16
- } = useEdificeClient(), usersIds = Array.from(new Set(defaultComments == null ? void 0 : defaultComments.map((comment) => comment.authorId))), profilesQueries = useProfileQueries(usersIds), comments = useMemo(
17
- () => type === "edit" ? (defaultComments == null ? void 0 : defaultComments.sort((a, b) => b.createdAt - a.createdAt).slice(0, commentLimit)) ?? [] : (defaultComments == null ? void 0 : defaultComments.sort((a, b) => b.createdAt - a.createdAt)) ?? [],
17
+ } = useEdificeClient(), usersIds = Array.from(new Set(defaultComments == null ? void 0 : defaultComments.map((comment) => comment.authorId))), profilesQueries = useProfileQueries(usersIds), idsOfDeletedCommentWithNoReply = useMemo(() => (defaultComments == null ? void 0 : defaultComments.filter((comment) => comment.deleted && !defaultComments.some((c) => c.replyTo === comment.id)).map((comment) => comment.id)) ?? [], [defaultComments]), displayedComments = useMemo(
18
+ () => {
19
+ var _a2;
20
+ const result = ((_a2 = defaultComments == null ? void 0 : defaultComments.filter((comment) => !comment.replyTo && !idsOfDeletedCommentWithNoReply.includes(comment.id))) == null ? void 0 : _a2.sort((a, b) => b.createdAt - a.createdAt)) ?? [];
21
+ return type === "edit" ? result.slice(0, commentLimit) ?? [] : result;
22
+ },
18
23
  // eslint-disable-next-line react-hooks/exhaustive-deps
19
24
  [commentLimit, defaultComments]
20
- ), commentsCount = (comments == null ? void 0 : comments.length) ?? 0, defaultCommentsCount = (defaultComments == null ? void 0 : defaultComments.length) ?? 0, title = defaultCommentsCount && defaultCommentsCount > 1 ? t("comment.several", {
21
- number: defaultCommentsCount
25
+ ), showMoreComments = (displayedComments == null ? void 0 : displayedComments.length) < (((_a = defaultComments == null ? void 0 : defaultComments.filter((comment) => !comment.replyTo && !idsOfDeletedCommentWithNoReply.includes(comment.id))) == null ? void 0 : _a.length) ?? 0), titleCommentsCount = ((_b = defaultComments == null ? void 0 : defaultComments.filter((comment) => !comment.deleted)) == null ? void 0 : _b.length) ?? 0, title = titleCommentsCount > 1 ? t("comment.several", {
26
+ number: titleCommentsCount
22
27
  }) : t("comment.little", {
23
- number: defaultCommentsCount
28
+ number: titleCommentsCount
24
29
  });
25
30
  return {
31
+ t,
26
32
  profilesQueries,
27
- content,
28
33
  title,
29
34
  user,
30
35
  emptyscreenPath: illuPad,
31
- defaultCommentsCount,
32
- comments,
36
+ displayedComments,
37
+ showMoreComments,
33
38
  editCommentId,
34
39
  setEditCommentId,
35
- commentsCount,
36
- t,
40
+ replyToCommentId,
41
+ setReplyToCommentId,
37
42
  handleMoreComments: () => {
38
- const newLimit = (comments == null ? void 0 : comments.length) + (options.additionalComments ?? 5);
39
- newLimit !== comments.length && setCommentLimit(newLimit);
40
- },
41
- handleChangeContent: (event) => {
42
- setContent(event.target.value);
43
+ const newLimit = displayedComments.length + (options.additionalComments ?? 5);
44
+ newLimit !== displayedComments.length && setCommentLimit(newLimit);
43
45
  },
44
46
  handleDeleteComment: (id) => {
45
47
  type === "edit" && (callbacks == null || callbacks.delete(id));
46
48
  },
47
- handleCreateComment: (content2) => {
48
- type === "edit" && (callbacks == null || callbacks.post(content2)), setContent("");
49
+ handleCreateComment: (content, replyTo) => {
50
+ type === "edit" && (callbacks == null || callbacks.post(content, replyTo)), replyTo && setReplyToCommentId(null);
49
51
  },
50
52
  handleModifyComment: (commentId) => {
51
53
  setEditCommentId(commentId);
@@ -56,8 +58,11 @@ const useComments = ({
56
58
  commentId: editCommentId
57
59
  })), setEditCommentId(null));
58
60
  },
61
+ handleReplyToComment: (commentId) => {
62
+ setReplyToCommentId(commentId);
63
+ },
59
64
  handleReset: () => {
60
- setContent(""), editCommentId && setEditCommentId(null);
65
+ editCommentId && setEditCommentId(null);
61
66
  }
62
67
  };
63
68
  };
@@ -1,16 +1,18 @@
1
1
  export declare const useCommentsContext: () => {
2
- comments: import('../types').CommentProps[] | undefined;
3
- content: string;
2
+ displayedComments: import('../types').CommentProps[] | undefined;
3
+ defaultComments: import('../types').CommentProps[] | undefined;
4
4
  editCommentId: string | null;
5
+ replyToCommentId: string | null;
5
6
  profiles: (import('../types').UserProfileResult | undefined)[];
6
7
  options: Partial<import('../types').CommentOptions>;
7
8
  type: import('../types').CommentType;
8
9
  userRights?: Record<import('@edifice.io/client').RightRole, boolean>;
9
10
  setEditCommentId: (value: string | null) => void;
11
+ setReplyToCommentId: (value: string | null) => void;
10
12
  handleModifyComment: (commentId: string) => void;
11
- handleChangeContent: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
12
- handleCreateComment: (content: string) => void;
13
+ handleCreateComment: (content: string, replyTo?: string) => void;
13
14
  handleUpdateComment: (comment: string) => void;
14
15
  handleDeleteComment: (id: string) => void;
16
+ handleReplyToComment: (commentId: string) => void;
15
17
  handleReset: () => void;
16
18
  };
@@ -3,7 +3,7 @@ import { useMemo } from "react";
3
3
  import { CommentForm } from "../components/CommentForm.js";
4
4
  import { CommentHeader } from "../components/CommentHeader.js";
5
5
  import { CommentList } from "../components/CommentList.js";
6
- import { DEFAULT_MAX_REPLIES, DEFAULT_ADD_COMMENTS, DEFAULT_MAX_COMMENTS, DEFAULT_MAX_REPLY_LENGTH, DEFAULT_MAX_COMMENT_LENGTH } from "../constants.js";
6
+ import { DEFAULT_ADD_REPLIES, DEFAULT_MAX_REPLIES, DEFAULT_ADD_COMMENTS, DEFAULT_MAX_COMMENTS, DEFAULT_MAX_REPLY_LENGTH, DEFAULT_MAX_COMMENT_LENGTH } from "../constants.js";
7
7
  import { CommentContext } from "../context/Context.js";
8
8
  import { useComments } from "../hooks/useComments.js";
9
9
  import Button from "../../../components/Button/Button.js";
@@ -19,27 +19,28 @@ const CommentProvider = ({
19
19
  maxComments: DEFAULT_MAX_COMMENTS,
20
20
  additionalComments: DEFAULT_ADD_COMMENTS,
21
21
  maxReplies: DEFAULT_MAX_REPLIES,
22
+ additionalReplies: DEFAULT_ADD_REPLIES,
22
23
  ...commentOptions
23
24
  }, {
24
25
  type
25
26
  } = props, {
26
27
  profilesQueries,
27
- content,
28
28
  title,
29
29
  user,
30
30
  emptyscreenPath,
31
- defaultCommentsCount,
32
- comments,
31
+ displayedComments,
32
+ showMoreComments,
33
33
  editCommentId,
34
34
  setEditCommentId,
35
- commentsCount,
35
+ replyToCommentId,
36
+ setReplyToCommentId,
36
37
  t,
37
38
  handleMoreComments,
38
- handleChangeContent,
39
39
  handleDeleteComment,
40
40
  handleCreateComment,
41
41
  handleModifyComment,
42
42
  handleUpdateComment,
43
+ handleReplyToComment,
43
44
  handleReset
44
45
  } = useComments({
45
46
  type,
@@ -48,23 +49,25 @@ const CommentProvider = ({
48
49
  options
49
50
  }), userRights = type === "edit" ? props.rights : void 0, values = useMemo(
50
51
  () => ({
51
- comments,
52
- content,
52
+ displayedComments,
53
+ defaultComments,
53
54
  profiles: profilesQueries.data,
54
55
  editCommentId,
56
+ replyToCommentId,
55
57
  options,
56
58
  type,
57
59
  userRights,
58
60
  setEditCommentId,
61
+ setReplyToCommentId,
59
62
  handleCreateComment,
60
63
  handleModifyComment,
61
64
  handleUpdateComment,
62
65
  handleDeleteComment,
63
- handleReset,
64
- handleChangeContent
66
+ handleReplyToComment,
67
+ handleReset
65
68
  }),
66
69
  // eslint-disable-next-line react-hooks/exhaustive-deps
67
- [comments, content, editCommentId, profilesQueries, options]
70
+ [displayedComments, editCommentId, profilesQueries, options]
68
71
  );
69
72
  return /* @__PURE__ */ jsx(CommentContext.Provider, { value: values, children: /* @__PURE__ */ jsxs("div", { className: "my-24", children: [
70
73
  /* @__PURE__ */ jsx(CommentHeader, { title }),
@@ -72,10 +75,10 @@ const CommentProvider = ({
72
75
  user && /* @__PURE__ */ jsx(CommentForm, { userId: user.userId }),
73
76
  profilesQueries.isLoading ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
74
77
  /* @__PURE__ */ jsx(CommentList, {}),
75
- commentsCount !== defaultCommentsCount && /* @__PURE__ */ jsx(Button, { variant: "ghost", color: "tertiary", onClick: handleMoreComments, className: "my-16", children: t("comment.more") })
78
+ showMoreComments && /* @__PURE__ */ jsx(Button, { variant: "ghost", color: "tertiary", onClick: handleMoreComments, className: "my-16", children: t("comment.more") })
76
79
  ] })
77
80
  ] }),
78
- !commentsCount && type === "edit" && /* @__PURE__ */ jsxs("div", { className: "comments-emptyscreen", children: [
81
+ !displayedComments.length && type === "edit" && /* @__PURE__ */ jsxs("div", { className: "comments-emptyscreen", children: [
79
82
  /* @__PURE__ */ jsx("div", { className: "comments-emptyscreen-wrapper", children: /* @__PURE__ */ jsx(EmptyScreen, { imageSrc: emptyscreenPath, size: 150 }) }),
80
83
  /* @__PURE__ */ jsx("p", { children: t("comment.emptyscreen") })
81
84
  ] })
@@ -24,13 +24,22 @@ export interface CommentProps {
24
24
  * Date when comment was updated
25
25
  */
26
26
  updatedAt?: number;
27
+ /**
28
+ * The comment parent ID.
29
+ */
30
+ replyTo?: string;
31
+ /**
32
+ * If the comment is deleted.
33
+ */
34
+ deleted?: boolean;
27
35
  }
28
36
  export interface CommentCallbacks {
29
37
  /**
30
38
  * Method to create a new comment
31
39
  * Get the new comment in the callback function
40
+ * If replyTo is provided, it is a reply to a comment
32
41
  */
33
- post: (comment: string) => Promise<void>;
42
+ post: (comment: string, replyTo?: string) => Promise<void>;
34
43
  /**
35
44
  * Method to update a comment
36
45
  * Get the comment and commentId in the callback function
@@ -91,6 +100,10 @@ export type CommentOptions = {
91
100
  * Limit on displaying replies to a comment
92
101
  */
93
102
  maxReplies: number;
103
+ /**
104
+ * Number of replies to load additionally in the limited list
105
+ */
106
+ additionalReplies: number;
94
107
  };
95
108
  export interface UserProfileResult {
96
109
  /**
@@ -0,0 +1,6 @@
1
+ import { Editor } from '@tiptap/react';
2
+ declare const BubbleMenuEditInformationPane: ({ editor, editable, }: {
3
+ editor: Editor;
4
+ editable: boolean;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ export default BubbleMenuEditInformationPane;
@@ -0,0 +1,136 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { BubbleMenu } from "@tiptap/react";
4
+ import { useTranslation } from "react-i18next";
5
+ import { Toolbar } from "../../../../components/Toolbar/Toolbar.js";
6
+ import SvgIconAlertTriangle from "../../../icons/components/IconAlertTriangle.js";
7
+ import SvgIconDelete from "../../../icons/components/IconDelete.js";
8
+ import SvgIconInfoCircle from "../../../icons/components/IconInfoCircle.js";
9
+ import SvgIconQuestion from "../../../icons/components/IconQuestion.js";
10
+ import SvgIconSuccessOutline from "../../../icons/components/IconSuccessOutline.js";
11
+ const BubbleMenuEditInformationPane = ({
12
+ editor,
13
+ editable
14
+ }) => {
15
+ const {
16
+ t
17
+ } = useTranslation(), {
18
+ selection
19
+ } = editor.view.state, selectedNode = selection.$from.node(1), InformationPaneTypeItems = useMemo(() => {
20
+ var _a, _b, _c, _d;
21
+ return [{
22
+ type: "icon",
23
+ name: "info",
24
+ props: {
25
+ size: "lg",
26
+ leftIcon: /* @__PURE__ */ jsx(SvgIconInfoCircle, {}),
27
+ "aria-label": t("tiptap.tooltip.bubblemenu.information.pane.info"),
28
+ className: ((_a = selectedNode == null ? void 0 : selectedNode.attrs) == null ? void 0 : _a.type) === "info" ? "is-selected" : "",
29
+ onClick: () => editor.chain().focus().updateAttributes("information-pane", {
30
+ type: "info"
31
+ }).run()
32
+ },
33
+ tooltip: {
34
+ message: t("tiptap.tooltip.bubblemenu.information.pane.info"),
35
+ position: "top"
36
+ }
37
+ }, {
38
+ type: "icon",
39
+ name: "success",
40
+ props: {
41
+ size: "lg",
42
+ leftIcon: /* @__PURE__ */ jsx(SvgIconSuccessOutline, {}),
43
+ "aria-label": t("tiptap.tooltip.bubblemenu.information.pane.success"),
44
+ className: ((_b = selectedNode == null ? void 0 : selectedNode.attrs) == null ? void 0 : _b.type) === "success" ? "is-selected" : "",
45
+ onClick: () => editor.chain().focus().updateAttributes("information-pane", {
46
+ type: "success"
47
+ }).run()
48
+ },
49
+ tooltip: {
50
+ message: t("tiptap.tooltip.bubblemenu.information.pane.success"),
51
+ position: "top"
52
+ }
53
+ }, {
54
+ type: "icon",
55
+ name: "warning",
56
+ props: {
57
+ size: "lg",
58
+ leftIcon: /* @__PURE__ */ jsx(SvgIconAlertTriangle, {}),
59
+ "aria-label": t("tiptap.tooltip.bubblemenu.information.pane.warning"),
60
+ className: ((_c = selectedNode == null ? void 0 : selectedNode.attrs) == null ? void 0 : _c.type) === "warning" ? "is-selected" : "",
61
+ onClick: () => editor.chain().focus().updateAttributes("information-pane", {
62
+ type: "warning"
63
+ }).run()
64
+ },
65
+ tooltip: {
66
+ message: t("tiptap.tooltip.bubblemenu.information.pane.warning"),
67
+ position: "top"
68
+ }
69
+ }, {
70
+ type: "icon",
71
+ name: "question",
72
+ props: {
73
+ size: "lg",
74
+ leftIcon: /* @__PURE__ */ jsx(SvgIconQuestion, {}),
75
+ "aria-label": t("tiptap.tooltip.bubblemenu.information.pane.question"),
76
+ className: ((_d = selectedNode == null ? void 0 : selectedNode.attrs) == null ? void 0 : _d.type) === "question" ? "is-selected" : "",
77
+ onClick: () => editor.chain().focus().updateAttributes("information-pane", {
78
+ type: "question"
79
+ }).run()
80
+ },
81
+ tooltip: {
82
+ message: t("tiptap.tooltip.bubblemenu.information.pane.question"),
83
+ position: "top"
84
+ }
85
+ }, {
86
+ type: "divider",
87
+ name: "div-4"
88
+ }, {
89
+ type: "button",
90
+ name: "delete",
91
+ props: {
92
+ size: "lg",
93
+ leftIcon: /* @__PURE__ */ jsx(SvgIconDelete, {}),
94
+ "aria-label": t("tiptap.bubblemenu.delete"),
95
+ children: t("tiptap.bubblemenu.delete"),
96
+ onClick: () => editor.chain().focus().deleteNode("information-pane").run()
97
+ },
98
+ tooltip: {
99
+ message: t("tiptap.bubblemenu.delete"),
100
+ position: "top"
101
+ }
102
+ }];
103
+ }, [t, selectedNode]), tippyOptions = useMemo(() => ({
104
+ placement: "bottom",
105
+ offset: [0, 0],
106
+ zIndex: 999,
107
+ duration: 100,
108
+ getReferenceClientRect: () => {
109
+ const {
110
+ state
111
+ } = editor, {
112
+ $anchor
113
+ } = state.selection;
114
+ let informationPanePos = null;
115
+ for (let depth = $anchor.depth; depth >= 0; depth--)
116
+ if ($anchor.node(depth).type.name === "information-pane") {
117
+ informationPanePos = $anchor.before(depth);
118
+ break;
119
+ }
120
+ if (informationPanePos !== null) {
121
+ let domNode = editor.view.nodeDOM(informationPanePos);
122
+ for (; domNode && domNode instanceof HTMLElement && !domNode.classList.contains("information-pane"); )
123
+ domNode = domNode.children[0];
124
+ if (domNode instanceof HTMLElement)
125
+ return domNode.getBoundingClientRect();
126
+ }
127
+ return new DOMRect(0, 0, 0, 0);
128
+ }
129
+ }), [editor]);
130
+ return /* @__PURE__ */ jsx(BubbleMenu, { shouldShow: ({
131
+ editor: editor2
132
+ }) => editor2.isActive("information-pane"), editor, tippyOptions, children: editable && /* @__PURE__ */ jsx(Toolbar, { className: "p-8", items: InformationPaneTypeItems }) });
133
+ };
134
+ export {
135
+ BubbleMenuEditInformationPane as default
136
+ };
@@ -0,0 +1 @@
1
+ export { default as BubbleMenuEditInformationPane } from './BubbleMenuEditInformationPane';
@@ -1,4 +1,4 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { forwardRef, useId, useImperativeHandle, Suspense, lazy } from "react";
3
3
  import { EditorContent } from "@tiptap/react";
4
4
  import clsx from "clsx";
@@ -16,6 +16,7 @@ import { EditorToolbar } from "../EditorToolbar/EditorToolbar.js";
16
16
  import LinkToolbar from "../Toolbar/LinkToolbar.js";
17
17
  import TableToolbar from "../Toolbar/TableToolbar.js";
18
18
  import BubbleMenuEditImage from "../BubbleMenuEditImage/BubbleMenuEditImage.js";
19
+ import BubbleMenuEditInformationPane from "../BubbleMenuEditInformationPane/BubbleMenuEditInformationPane.js";
19
20
  import MediaLibrary from "../../../multimedia/MediaLibrary/MediaLibrary.js";
20
21
  import LoadingScreen from "../../../../components/LoadingScreen/LoadingScreen.js";
21
22
  const MathsModal = /* @__PURE__ */ lazy(async () => await import("../MathsModal/MathsModal.js")), ImageEditor = /* @__PURE__ */ lazy(async () => await import("../../../multimedia/ImageEditor/components/ImageEditor.js")), Editor = /* @__PURE__ */ forwardRef(({
@@ -70,7 +71,10 @@ const MathsModal = /* @__PURE__ */ lazy(async () => await import("../MathsModal/
70
71
  ] }),
71
72
  /* @__PURE__ */ jsx(LinkToolbar, { editor, ...linkToolbarHandlers }),
72
73
  /* @__PURE__ */ jsx(TableToolbar, { editor }),
73
- editor && /* @__PURE__ */ jsx(BubbleMenuEditImage, { editor, onEditImage: imageModal.handleEdit, openEditImage: imageModal.isOpen, editable }),
74
+ editor && /* @__PURE__ */ jsxs(Fragment, { children: [
75
+ /* @__PURE__ */ jsx(BubbleMenuEditImage, { editor, onEditImage: imageModal.handleEdit, openEditImage: imageModal.isOpen, editable }),
76
+ /* @__PURE__ */ jsx(BubbleMenuEditInformationPane, { editor, editable })
77
+ ] }),
74
78
  /* @__PURE__ */ jsxs(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingScreen, {}), children: [
75
79
  editable && /* @__PURE__ */ jsx(MediaLibrary, { appCode, visibility, multiple: !0, ref: mediaLibraryModalRef, ...mediaLibraryModalHandlers }),
76
80
  editable && mathsModalHandlers.isOpen && /* @__PURE__ */ jsx(MathsModal, { ...mathsModalHandlers }),
@@ -5,6 +5,7 @@ import "@tiptap/react";
5
5
  import "@tiptap/starter-kit";
6
6
  import SvgIconAlignLeft from "../../../icons/components/IconAlignLeft.js";
7
7
  import SvgIconBulletList from "../../../icons/components/IconBulletList.js";
8
+ import SvgIconInfoRectangle from "../../../icons/components/IconInfoRectangle.js";
8
9
  import SvgIconLandscape from "../../../icons/components/IconLandscape.js";
9
10
  import SvgIconLink from "../../../icons/components/IconLink.js";
10
11
  import SvgIconMic from "../../../icons/components/IconMic.js";
@@ -213,6 +214,17 @@ const EditorToolbar = ({
213
214
  visibility: showIf(hasMark("customHighlight", editor)),
214
215
  tooltip: t("tiptap.toolbar.highlight.back")
215
216
  },
217
+ //--------------- INFORMATION PANE ---------------//
218
+ {
219
+ type: "icon",
220
+ props: {
221
+ icon: /* @__PURE__ */ jsx(SvgIconInfoRectangle, {}),
222
+ "aria-label": t("tiptap.toolbar.information.pane"),
223
+ onClick: () => editor == null ? void 0 : editor.chain().focus().setInformationPane("info").run()
224
+ },
225
+ name: "information-pane",
226
+ tooltip: t("tiptap.toolbar.information.pane")
227
+ },
216
228
  //-------------------------------------//
217
229
  {
218
230
  type: "divider",
@@ -0,0 +1,2 @@
1
+ declare const InformationPaneNodeView: (Component: any) => import('@tiptap/core').Node<any, any>;
2
+ export default InformationPaneNodeView;
@@ -0,0 +1,10 @@
1
+ import { InformationPane } from "@edifice.io/tiptap-extensions/information-pane";
2
+ import { ReactNodeViewRenderer } from "@tiptap/react";
3
+ const InformationPaneNodeView = (Component) => InformationPane.extend({
4
+ addNodeView() {
5
+ return ReactNodeViewRenderer(Component);
6
+ }
7
+ });
8
+ export {
9
+ InformationPaneNodeView as default
10
+ };
@@ -3,3 +3,4 @@ export { default as AttachmentNodeView } from './AttachmentNodeView';
3
3
  export { default as ImageNodeView } from './ImageNodeView';
4
4
  export { default as LinkerNodeView } from './LinkerNodeView';
5
5
  export { default as VideoNodeView } from './VideoNodeView';
6
+ export { default as InformationPaneNodeView } from './InformationPaneNodeView';
@@ -0,0 +1,3 @@
1
+ import { MediaResizeProps } from '../../hooks';
2
+ declare const InformationPaneRenderer: (props: MediaResizeProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default InformationPaneRenderer;
@@ -0,0 +1,33 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import SvgIconAlertTriangle from "../../../icons/components/IconAlertTriangle.js";
3
+ import SvgIconInfoCircle from "../../../icons/components/IconInfoCircle.js";
4
+ import SvgIconQuestion from "../../../icons/components/IconQuestion.js";
5
+ import SvgIconSuccessOutline from "../../../icons/components/IconSuccessOutline.js";
6
+ import { NodeViewWrapper, NodeViewContent } from "@tiptap/react";
7
+ const InformationPaneRenderer = (props) => {
8
+ const {
9
+ node
10
+ } = props, getIconByType = (type) => {
11
+ switch (type) {
12
+ case "warning":
13
+ return /* @__PURE__ */ jsx(SvgIconAlertTriangle, { color: "#F59700" });
14
+ case "success":
15
+ return /* @__PURE__ */ jsx(SvgIconSuccessOutline, { color: "#7DBF85" });
16
+ case "info":
17
+ return /* @__PURE__ */ jsx(SvgIconInfoCircle, { color: "#2A9CC8" });
18
+ case "question":
19
+ return /* @__PURE__ */ jsx(SvgIconQuestion, { color: "#823AA1" });
20
+ default:
21
+ return /* @__PURE__ */ jsx(SvgIconInfoCircle, { color: "#2A9CC8" });
22
+ }
23
+ };
24
+ return /* @__PURE__ */ jsx(NodeViewWrapper, { node, className: "react-component", children: /* @__PURE__ */ jsxs("div", { className: `information-pane information-pane-${node.attrs.type}`, "data-information-pane": !0, "data-type": node.attrs.type, children: [
25
+ /* @__PURE__ */ jsx("span", { className: "information-pane-icon", children: getIconByType(node.attrs.type) }),
26
+ /* @__PURE__ */ jsx(NodeViewContent, { style: {
27
+ width: "100%"
28
+ } })
29
+ ] }) });
30
+ };
31
+ export {
32
+ InformationPaneRenderer as default
33
+ };
@@ -2,3 +2,4 @@ export { default as AudioRenderer } from './AudioRenderer';
2
2
  export { default as AttachmentRenderer } from './AttachmentRenderer';
3
3
  export { default as LinkerRenderer } from './LinkerRenderer';
4
4
  export { default as MediaRenderer } from './MediaRenderer';
5
+ export { default as InformationPaneRenderer } from './InformationPaneRenderer';
@@ -32,10 +32,12 @@ import AudioNodeView from "../components/NodeView/AudioNodeView.js";
32
32
  import LinkerNodeView from "../components/NodeView/LinkerNodeView.js";
33
33
  import ImageNodeView from "../components/NodeView/ImageNodeView.js";
34
34
  import AttachmentNodeView from "../components/NodeView/AttachmentNodeView.js";
35
+ import InformationPaneNodeView from "../components/NodeView/InformationPaneNodeView.js";
35
36
  import MediaRenderer from "../components/Renderer/MediaRenderer.js";
36
37
  import AudioRenderer from "../components/Renderer/AudioRenderer.js";
37
38
  import LinkerRenderer from "../components/Renderer/LinkerRenderer.js";
38
39
  import AttachmentRenderer from "../components/Renderer/AttachmentRenderer.js";
40
+ import InformationPaneRenderer from "../components/Renderer/InformationPaneRenderer.js";
39
41
  const useTipTapEditor = (editable, content, focus, placeholder, onContentChange, visibility = "protected") => {
40
42
  const {
41
43
  currentLanguage
@@ -63,7 +65,7 @@ const useTipTapEditor = (editable, content, focus, placeholder, onContentChange,
63
65
  levels: [1, 2]
64
66
  }), Typography, FontSize, SpeechRecognition, SpeechSynthesis.configure({
65
67
  lang: (currentLanguage == null ? void 0 : currentLanguage.length) === 2 ? `${currentLanguage}-${currentLanguage.toUpperCase()}` : "fr-FR"
66
- }), Iframe, Hyperlink, FontFamily, Mathematics, Alert, VideoNodeView(MediaRenderer), AudioNodeView(AudioRenderer), LinkerNodeView(LinkerRenderer), ImageNodeView(MediaRenderer, uploadFile), AttachmentNodeView(AttachmentRenderer)],
68
+ }), Iframe, Hyperlink, FontFamily, Mathematics, Alert, VideoNodeView(MediaRenderer), AudioNodeView(AudioRenderer), LinkerNodeView(LinkerRenderer), ImageNodeView(MediaRenderer, uploadFile), AttachmentNodeView(AttachmentRenderer), InformationPaneNodeView(InformationPaneRenderer)],
67
69
  content,
68
70
  // If the onContentChange callback is provided, we call it on every content change.
69
71
  ...onContentChange ? {
@@ -0,0 +1,7 @@
1
+ import { SVGProps } from 'react';
2
+ interface SVGRProps {
3
+ title?: string;
4
+ titleId?: string;
5
+ }
6
+ declare const SvgIconInfoRectangle: ({ title, titleId, ...props }: SVGProps<SVGSVGElement> & SVGRProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default SvgIconInfoRectangle;