@blocknote/react 0.47.3 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/FloatingComposerController-D4uLQfUX.js +89 -0
  2. package/dist/FloatingComposerController-D4uLQfUX.js.map +1 -0
  3. package/dist/FloatingComposerController-z3al33Dz.cjs +2 -0
  4. package/dist/FloatingComposerController-z3al33Dz.cjs.map +1 -0
  5. package/dist/FloatingThreadController-BMC2B9Lr.cjs +3 -0
  6. package/dist/FloatingThreadController-BMC2B9Lr.cjs.map +1 -0
  7. package/dist/FloatingThreadController-BuzLC5ea.js +398 -0
  8. package/dist/FloatingThreadController-BuzLC5ea.js.map +1 -0
  9. package/dist/blocknote-react.cjs +2 -35
  10. package/dist/blocknote-react.cjs.map +1 -1
  11. package/dist/blocknote-react.js +3244 -5773
  12. package/dist/blocknote-react.js.map +1 -1
  13. package/dist/defaultCommentEditorSchema-Bd70-hG9.js +229 -0
  14. package/dist/defaultCommentEditorSchema-Bd70-hG9.js.map +1 -0
  15. package/dist/defaultCommentEditorSchema-CxYfuFDM.cjs +2 -0
  16. package/dist/defaultCommentEditorSchema-CxYfuFDM.cjs.map +1 -0
  17. package/dist/rolldown-runtime-CAFD8bLK.js +11 -0
  18. package/dist/style.css +2 -1
  19. package/dist/webpack-stats.json +1 -1
  20. package/package.json +6 -6
  21. package/src/blocks/Audio/block.tsx +3 -0
  22. package/src/blocks/File/helpers/render/ResizableFileBlockWrapper.tsx +18 -16
  23. package/src/blocks/Image/block.tsx +4 -0
  24. package/src/blocks/Video/block.tsx +4 -0
  25. package/src/components/Comments/EmojiPicker.tsx +26 -28
  26. package/src/components/Popovers/GenericPopover.tsx +63 -16
  27. package/src/components/SideMenu/SideMenuController.tsx +38 -2
  28. package/src/components/TableHandles/TableHandlesController.tsx +38 -3
  29. package/src/editor/BlockNoteView.tsx +48 -24
  30. package/src/editor/ComponentsContext.tsx +1 -0
  31. package/src/editor/styles.css +7 -8
  32. package/src/hooks/useEditorState.ts +1 -1
  33. package/src/schema/ReactBlockSpec.tsx +3 -0
  34. package/types/src/editor/ComponentsContext.d.ts +1 -0
  35. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,89 @@
1
+ import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
2
+ import { a as t, c as n, d as r, f as i, i as a, n as o, o as s, p as c, r as l, t as u } from "./defaultCommentEditorSchema-Bd70-hG9.js";
3
+ import { useMemo as d } from "react";
4
+ import { CommentsExtension as f } from "@blocknote/core/comments";
5
+ import { flip as p, offset as m, shift as h } from "@floating-ui/react";
6
+ import { mergeCSSClasses as g } from "@blocknote/core";
7
+ import { jsx as _ } from "react/jsx-runtime";
8
+ //#region src/components/Comments/FloatingComposer.tsx
9
+ function v() {
10
+ let e = r(f), t = n(), i = s(), a = l({
11
+ trailingBlock: !1,
12
+ dictionary: {
13
+ ...i,
14
+ placeholders: { emptyDocument: i.placeholders.new_comment }
15
+ },
16
+ schema: e.commentEditorSchema || u
17
+ });
18
+ return /* @__PURE__ */ _(t.Comments.Card, {
19
+ className: "bn-thread",
20
+ children: /* @__PURE__ */ _(o, {
21
+ autoFocus: !0,
22
+ editable: !0,
23
+ editor: a,
24
+ actions: ({ isEmpty: n }) => /* @__PURE__ */ _(t.Generic.Toolbar.Root, {
25
+ className: g("bn-action-toolbar", "bn-comment-actions"),
26
+ variant: "action-toolbar",
27
+ children: /* @__PURE__ */ _(t.Generic.Toolbar.Button, {
28
+ className: "bn-button",
29
+ mainTooltip: "Save",
30
+ variant: "compact",
31
+ isDisabled: n,
32
+ onClick: async () => {
33
+ await e.createThread({ initialComment: { body: a.document } }), e.stopPendingComment();
34
+ },
35
+ children: "Save"
36
+ })
37
+ })
38
+ })
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region src/components/Comments/FloatingComposerController.tsx
43
+ var y = /* @__PURE__ */ e({ default: () => b });
44
+ function b(e) {
45
+ let n = c(), o = r(f), s = i(f, {
46
+ editor: n,
47
+ selector: (e) => e.pendingComment
48
+ }), l = t({
49
+ editor: n,
50
+ selector: ({ editor: e }) => s ? {
51
+ from: e.prosemirrorState.selection.from,
52
+ to: e.prosemirrorState.selection.to
53
+ } : void 0
54
+ }), u = d(() => ({
55
+ ...e.floatingUIOptions,
56
+ useFloatingOptions: {
57
+ open: !!s,
58
+ onOpenChange: (e) => {
59
+ e || (o.stopPendingComment(), n.focus());
60
+ },
61
+ placement: "bottom",
62
+ middleware: [
63
+ m(10),
64
+ h(),
65
+ p()
66
+ ],
67
+ ...e.floatingUIOptions?.useFloatingOptions
68
+ },
69
+ focusManagerProps: { disabled: !1 },
70
+ elementProps: {
71
+ style: { zIndex: 60 },
72
+ ...e.floatingUIOptions?.elementProps
73
+ }
74
+ }), [
75
+ o,
76
+ n,
77
+ s,
78
+ e.floatingUIOptions
79
+ ]), g = e.floatingComposer || v;
80
+ return /* @__PURE__ */ _(a, {
81
+ position: l,
82
+ ...u,
83
+ children: /* @__PURE__ */ _(g, {})
84
+ });
85
+ }
86
+ //#endregion
87
+ export { y as n, v as r, b as t };
88
+
89
+ //# sourceMappingURL=FloatingComposerController-D4uLQfUX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingComposerController-D4uLQfUX.js","names":[],"sources":["../src/components/Comments/FloatingComposer.tsx","../src/components/Comments/FloatingComposerController.tsx"],"sourcesContent":["import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\n\n/**\n * The FloatingComposer component displays a comment editor \"floating\" card.\n *\n * It's used when the user highlights a parts of the document to create a new comment / thread.\n */\nexport function FloatingComposer() {\n const comments = useExtension(CommentsExtension);\n\n const Components = useComponentsContext()!;\n const dict = useDictionary();\n\n const newCommentEditor = useCreateBlockNote({\n trailingBlock: false,\n dictionary: {\n ...dict,\n placeholders: {\n emptyDocument: dict.placeholders.new_comment,\n },\n },\n schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n });\n\n return (\n <Components.Comments.Card className={\"bn-thread\"}>\n <CommentEditor\n autoFocus={true}\n editable={true}\n editor={newCommentEditor}\n actions={({ isEmpty }) => (\n <Components.Generic.Toolbar.Root\n className={mergeCSSClasses(\n \"bn-action-toolbar\",\n \"bn-comment-actions\",\n )}\n variant=\"action-toolbar\"\n >\n <Components.Generic.Toolbar.Button\n className={\"bn-button\"}\n mainTooltip=\"Save\"\n variant=\"compact\"\n isDisabled={isEmpty}\n onClick={async () => {\n // (later) For REST API, we should implement a loading state and error state\n await comments.createThread({\n initialComment: {\n body: newCommentEditor.document,\n },\n });\n comments.stopPendingComment();\n }}\n >\n Save\n </Components.Generic.Toolbar.Button>\n </Components.Generic.Toolbar.Root>\n )}\n />\n </Components.Comments.Card>\n );\n}\n","import {\n BlockSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { flip, offset, shift } from \"@floating-ui/react\";\nimport { ComponentProps, FC, useMemo } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { useEditorState } from \"../../hooks/useEditorState.js\";\nimport { useExtension, useExtensionState } from \"../../hooks/useExtension.js\";\nimport { FloatingUIOptions } from \"../Popovers/FloatingUIOptions.js\";\nimport { PositionPopover } from \"../Popovers/PositionPopover.js\";\nimport { FloatingComposer } from \"./FloatingComposer.js\";\n\nexport default function FloatingComposerController<\n B extends BlockSchema = DefaultBlockSchema,\n I extends InlineContentSchema = DefaultInlineContentSchema,\n S extends StyleSchema = DefaultStyleSchema,\n>(props: {\n floatingComposer?: FC<ComponentProps<typeof FloatingComposer>>;\n floatingUIOptions?: FloatingUIOptions;\n}) {\n const editor = useBlockNoteEditor<B, I, S>();\n\n const comments = useExtension(CommentsExtension);\n\n const pendingComment = useExtensionState(CommentsExtension, {\n editor,\n selector: (state) => state.pendingComment,\n });\n\n const position = useEditorState({\n editor,\n selector: ({ editor }) =>\n pendingComment\n ? {\n from: editor.prosemirrorState.selection.from,\n to: editor.prosemirrorState.selection.to,\n }\n : undefined,\n });\n\n const floatingUIOptions = useMemo<FloatingUIOptions>(\n () => ({\n ...props.floatingUIOptions,\n useFloatingOptions: {\n open: !!pendingComment,\n // Needed as hooks like `useDismiss` call `onOpenChange` to change the\n // open state.\n onOpenChange: (open) => {\n if (!open) {\n comments.stopPendingComment();\n editor.focus();\n }\n },\n placement: \"bottom\",\n middleware: [offset(10), shift(), flip()],\n ...props.floatingUIOptions?.useFloatingOptions,\n },\n focusManagerProps: {\n disabled: false,\n },\n elementProps: {\n style: {\n zIndex: 60,\n },\n ...props.floatingUIOptions?.elementProps,\n },\n }),\n [comments, editor, pendingComment, props.floatingUIOptions],\n );\n\n // nice to have improvements would be:\n // - transition transform property so composer box animates when remote document is changed\n // - fade out on close\n\n const Component = props.floatingComposer || FloatingComposer;\n\n return (\n <PositionPopover position={position} {...floatingUIOptions}>\n <Component />\n </PositionPopover>\n );\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,IAAmB;CACjC,IAAM,IAAW,EAAa,EAAkB,EAE1C,IAAa,GAAsB,EACnC,IAAO,GAAe,EAEtB,IAAmB,EAAmB;EAC1C,eAAe;EACf,YAAY;GACV,GAAG;GACH,cAAc,EACZ,eAAe,EAAK,aAAa,aAClC;GACF;EACD,QAAQ,EAAS,uBAAuB;EACzC,CAAC;AAEF,QACE,kBAAC,EAAW,SAAS,MAArB;EAA0B,WAAW;YACnC,kBAAC,GAAD;GACE,WAAW;GACX,UAAU;GACV,QAAQ;GACR,UAAU,EAAE,iBACV,kBAAC,EAAW,QAAQ,QAAQ,MAA5B;IACE,WAAW,EACT,qBACA,qBACD;IACD,SAAQ;cAER,kBAAC,EAAW,QAAQ,QAAQ,QAA5B;KACE,WAAW;KACX,aAAY;KACZ,SAAQ;KACR,YAAY;KACZ,SAAS,YAAY;AAOnB,MALA,MAAM,EAAS,aAAa,EAC1B,gBAAgB,EACd,MAAM,EAAiB,UACxB,EACF,CAAC,EACF,EAAS,oBAAoB;;eAEhC;KAEmC,CAAA;IACJ,CAAA;GAEpC,CAAA;EACuB,CAAA;;;;;AC/C/B,SAAwB,EAItB,GAGC;CACD,IAAM,IAAS,GAA6B,EAEtC,IAAW,EAAa,EAAkB,EAE1C,IAAiB,EAAkB,GAAmB;EAC1D;EACA,WAAW,MAAU,EAAM;EAC5B,CAAC,EAEI,IAAW,EAAe;EAC9B;EACA,WAAW,EAAE,gBACX,IACI;GACE,MAAM,EAAO,iBAAiB,UAAU;GACxC,IAAI,EAAO,iBAAiB,UAAU;GACvC,GACD,KAAA;EACP,CAAC,EAEI,IAAoB,SACjB;EACL,GAAG,EAAM;EACT,oBAAoB;GAClB,MAAM,CAAC,CAAC;GAGR,eAAe,MAAS;AACtB,IAAK,MACH,EAAS,oBAAoB,EAC7B,EAAO,OAAO;;GAGlB,WAAW;GACX,YAAY;IAAC,EAAO,GAAG;IAAE,GAAO;IAAE,GAAM;IAAC;GACzC,GAAG,EAAM,mBAAmB;GAC7B;EACD,mBAAmB,EACjB,UAAU,IACX;EACD,cAAc;GACZ,OAAO,EACL,QAAQ,IACT;GACD,GAAG,EAAM,mBAAmB;GAC7B;EACF,GACD;EAAC;EAAU;EAAQ;EAAgB,EAAM;EAAkB,CAC5D,EAMK,IAAY,EAAM,oBAAoB;AAE5C,QACE,kBAAC,GAAD;EAA2B;EAAU,GAAI;YACvC,kBAAC,GAAD,EAAa,CAAA;EACG,CAAA"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./defaultCommentEditorSchema-CxYfuFDM.cjs`);let t=require(`react`),n=require(`@blocknote/core/comments`),r=require(`@floating-ui/react`),i=require(`@blocknote/core`),a=require(`react/jsx-runtime`);function o(){let t=e.d(n.CommentsExtension),r=e.c(),o=e.o(),s=e.r({trailingBlock:!1,dictionary:{...o,placeholders:{emptyDocument:o.placeholders.new_comment}},schema:t.commentEditorSchema||e.t});return(0,a.jsx)(r.Comments.Card,{className:`bn-thread`,children:(0,a.jsx)(e.n,{autoFocus:!0,editable:!0,editor:s,actions:({isEmpty:e})=>(0,a.jsx)(r.Generic.Toolbar.Root,{className:(0,i.mergeCSSClasses)(`bn-action-toolbar`,`bn-comment-actions`),variant:`action-toolbar`,children:(0,a.jsx)(r.Generic.Toolbar.Button,{className:`bn-button`,mainTooltip:`Save`,variant:`compact`,isDisabled:e,onClick:async()=>{await t.createThread({initialComment:{body:s.document}}),t.stopPendingComment()},children:`Save`})})})})}var s=e.g({default:()=>c});function c(i){let s=e.p(),c=e.d(n.CommentsExtension),l=e.f(n.CommentsExtension,{editor:s,selector:e=>e.pendingComment}),u=e.a({editor:s,selector:({editor:e})=>l?{from:e.prosemirrorState.selection.from,to:e.prosemirrorState.selection.to}:void 0}),d=(0,t.useMemo)(()=>({...i.floatingUIOptions,useFloatingOptions:{open:!!l,onOpenChange:e=>{e||(c.stopPendingComment(),s.focus())},placement:`bottom`,middleware:[(0,r.offset)(10),(0,r.shift)(),(0,r.flip)()],...i.floatingUIOptions?.useFloatingOptions},focusManagerProps:{disabled:!1},elementProps:{style:{zIndex:60},...i.floatingUIOptions?.elementProps}}),[c,s,l,i.floatingUIOptions]),f=i.floatingComposer||o;return(0,a.jsx)(e.i,{position:u,...d,children:(0,a.jsx)(f,{})})}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return c}});
2
+ //# sourceMappingURL=FloatingComposerController-z3al33Dz.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingComposerController-z3al33Dz.cjs","names":[],"sources":["../src/components/Comments/FloatingComposer.tsx","../src/components/Comments/FloatingComposerController.tsx"],"sourcesContent":["import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\n\n/**\n * The FloatingComposer component displays a comment editor \"floating\" card.\n *\n * It's used when the user highlights a parts of the document to create a new comment / thread.\n */\nexport function FloatingComposer() {\n const comments = useExtension(CommentsExtension);\n\n const Components = useComponentsContext()!;\n const dict = useDictionary();\n\n const newCommentEditor = useCreateBlockNote({\n trailingBlock: false,\n dictionary: {\n ...dict,\n placeholders: {\n emptyDocument: dict.placeholders.new_comment,\n },\n },\n schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n });\n\n return (\n <Components.Comments.Card className={\"bn-thread\"}>\n <CommentEditor\n autoFocus={true}\n editable={true}\n editor={newCommentEditor}\n actions={({ isEmpty }) => (\n <Components.Generic.Toolbar.Root\n className={mergeCSSClasses(\n \"bn-action-toolbar\",\n \"bn-comment-actions\",\n )}\n variant=\"action-toolbar\"\n >\n <Components.Generic.Toolbar.Button\n className={\"bn-button\"}\n mainTooltip=\"Save\"\n variant=\"compact\"\n isDisabled={isEmpty}\n onClick={async () => {\n // (later) For REST API, we should implement a loading state and error state\n await comments.createThread({\n initialComment: {\n body: newCommentEditor.document,\n },\n });\n comments.stopPendingComment();\n }}\n >\n Save\n </Components.Generic.Toolbar.Button>\n </Components.Generic.Toolbar.Root>\n )}\n />\n </Components.Comments.Card>\n );\n}\n","import {\n BlockSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { flip, offset, shift } from \"@floating-ui/react\";\nimport { ComponentProps, FC, useMemo } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { useEditorState } from \"../../hooks/useEditorState.js\";\nimport { useExtension, useExtensionState } from \"../../hooks/useExtension.js\";\nimport { FloatingUIOptions } from \"../Popovers/FloatingUIOptions.js\";\nimport { PositionPopover } from \"../Popovers/PositionPopover.js\";\nimport { FloatingComposer } from \"./FloatingComposer.js\";\n\nexport default function FloatingComposerController<\n B extends BlockSchema = DefaultBlockSchema,\n I extends InlineContentSchema = DefaultInlineContentSchema,\n S extends StyleSchema = DefaultStyleSchema,\n>(props: {\n floatingComposer?: FC<ComponentProps<typeof FloatingComposer>>;\n floatingUIOptions?: FloatingUIOptions;\n}) {\n const editor = useBlockNoteEditor<B, I, S>();\n\n const comments = useExtension(CommentsExtension);\n\n const pendingComment = useExtensionState(CommentsExtension, {\n editor,\n selector: (state) => state.pendingComment,\n });\n\n const position = useEditorState({\n editor,\n selector: ({ editor }) =>\n pendingComment\n ? {\n from: editor.prosemirrorState.selection.from,\n to: editor.prosemirrorState.selection.to,\n }\n : undefined,\n });\n\n const floatingUIOptions = useMemo<FloatingUIOptions>(\n () => ({\n ...props.floatingUIOptions,\n useFloatingOptions: {\n open: !!pendingComment,\n // Needed as hooks like `useDismiss` call `onOpenChange` to change the\n // open state.\n onOpenChange: (open) => {\n if (!open) {\n comments.stopPendingComment();\n editor.focus();\n }\n },\n placement: \"bottom\",\n middleware: [offset(10), shift(), flip()],\n ...props.floatingUIOptions?.useFloatingOptions,\n },\n focusManagerProps: {\n disabled: false,\n },\n elementProps: {\n style: {\n zIndex: 60,\n },\n ...props.floatingUIOptions?.elementProps,\n },\n }),\n [comments, editor, pendingComment, props.floatingUIOptions],\n );\n\n // nice to have improvements would be:\n // - transition transform property so composer box animates when remote document is changed\n // - fade out on close\n\n const Component = props.floatingComposer || FloatingComposer;\n\n return (\n <PositionPopover position={position} {...floatingUIOptions}>\n <Component />\n </PositionPopover>\n );\n}\n"],"mappings":"sNAeA,SAAgB,GAAmB,CACjC,IAAM,EAAW,EAAA,EAAa,EAAA,kBAAkB,CAE1C,EAAa,EAAA,GAAsB,CACnC,EAAO,EAAA,GAAe,CAEtB,EAAmB,EAAA,EAAmB,CAC1C,cAAe,GACf,WAAY,CACV,GAAG,EACH,aAAc,CACZ,cAAe,EAAK,aAAa,YAClC,CACF,CACD,OAAQ,EAAS,qBAAuB,EAAA,EACzC,CAAC,CAEF,OACE,EAAA,EAAA,KAAC,EAAW,SAAS,KAArB,CAA0B,UAAW,sBACnC,EAAA,EAAA,KAAC,EAAA,EAAD,CACE,UAAW,GACX,SAAU,GACV,OAAQ,EACR,SAAU,CAAE,cACV,EAAA,EAAA,KAAC,EAAW,QAAQ,QAAQ,KAA5B,CACE,WAAA,EAAA,EAAA,iBACE,oBACA,qBACD,CACD,QAAQ,2BAER,EAAA,EAAA,KAAC,EAAW,QAAQ,QAAQ,OAA5B,CACE,UAAW,YACX,YAAY,OACZ,QAAQ,UACR,WAAY,EACZ,QAAS,SAAY,CAEnB,MAAM,EAAS,aAAa,CAC1B,eAAgB,CACd,KAAM,EAAiB,SACxB,CACF,CAAC,CACF,EAAS,oBAAoB,WAEhC,OAEmC,CAAA,CACJ,CAAA,CAEpC,CAAA,CACuB,CAAA,4BC/C/B,SAAwB,EAItB,EAGC,CACD,IAAM,EAAS,EAAA,GAA6B,CAEtC,EAAW,EAAA,EAAa,EAAA,kBAAkB,CAE1C,EAAiB,EAAA,EAAkB,EAAA,kBAAmB,CAC1D,SACA,SAAW,GAAU,EAAM,eAC5B,CAAC,CAEI,EAAW,EAAA,EAAe,CAC9B,SACA,UAAW,CAAE,YACX,EACI,CACE,KAAM,EAAO,iBAAiB,UAAU,KACxC,GAAI,EAAO,iBAAiB,UAAU,GACvC,CACD,IAAA,GACP,CAAC,CAEI,GAAA,EAAA,EAAA,cACG,CACL,GAAG,EAAM,kBACT,mBAAoB,CAClB,KAAM,CAAC,CAAC,EAGR,aAAe,GAAS,CACjB,IACH,EAAS,oBAAoB,CAC7B,EAAO,OAAO,GAGlB,UAAW,SACX,WAAY,cAAQ,GAAG,cAAS,aAAQ,CAAC,CACzC,GAAG,EAAM,mBAAmB,mBAC7B,CACD,kBAAmB,CACjB,SAAU,GACX,CACD,aAAc,CACZ,MAAO,CACL,OAAQ,GACT,CACD,GAAG,EAAM,mBAAmB,aAC7B,CACF,EACD,CAAC,EAAU,EAAQ,EAAgB,EAAM,kBAAkB,CAC5D,CAMK,EAAY,EAAM,kBAAoB,EAE5C,OACE,EAAA,EAAA,KAAC,EAAA,EAAD,CAA2B,WAAU,GAAI,YACvC,EAAA,EAAA,KAAC,EAAD,EAAa,CAAA,CACG,CAAA"}
@@ -0,0 +1,3 @@
1
+ const e=require(`./defaultCommentEditorSchema-CxYfuFDM.cjs`);let t=require(`react`);t=e._(t);let n=require(`@blocknote/core/comments`),r=require(`@floating-ui/react`),i=require(`@blocknote/core`),a=require(`react/jsx-runtime`),o=require(`react-icons/ri`);var s;async function c(){return s||(s=(async()=>{let[e,t]=await Promise.all([import(`emoji-mart`),import(`@emoji-mart/data`)]),n=`default`in e?e.default:e,r=`default`in t?t.default:t;return await n.init({data:r}),{emojiMart:n,emojiData:r}})(),s)}function l(e){let n=(0,t.useRef)(null),r=(0,t.useRef)(null);return r.current&&r.current.update(e),(0,t.useEffect)(()=>((async()=>{let{emojiMart:t}=await c();r.current=new t.Picker({...e,ref:n})})(),()=>{r.current=null}),[]),t.default.createElement(`div`,{ref:n})}var u=n=>{let[r,i]=(0,t.useState)(!1),o=e.c(),s=e.h(),c=s.editor?.portalElement;if(!c)throw Error(`Portal root not found`);return(0,a.jsxs)(o.Generic.Popover.Root,{open:r,portalRoot:c,children:[(0,a.jsx)(o.Generic.Popover.Trigger,{children:(0,a.jsx)(`div`,{onClick:e=>{e.preventDefault(),e.stopPropagation(),i(!r),n.onOpenChange?.(!r)},style:{display:`flex`,justifyContent:`center`,alignItems:`center`},children:n.children})}),(0,a.jsx)(o.Generic.Popover.Content,{className:`bn-emoji-picker-popover`,variant:`panel-popover`,children:(0,a.jsx)(l,{perLine:7,onClickOutside:()=>{i(!1),n.onOpenChange?.(!1)},onEmojiSelect:e=>{n.onEmojiSelect(e),i(!1),n.onOpenChange?.(!1)},theme:s?.colorSchemePreference})})]})};function d(e){return f([e]).get(e)}function f(r){let i=e.d(n.CommentsExtension).userStore,a=(0,t.useCallback)(()=>{let e=new Map;for(let t of r){let n=i.getUser(t);n&&e.set(t,n)}return e},[i,r]),o=(0,t.useMemo)(()=>({current:a()}),[a]);return(0,t.useSyncExternalStore)((0,t.useCallback)(e=>{let t=i.subscribe(t=>{o.current=a(),e()});return i.loadUsers(r),t},[i,a,r,o]),()=>o.current)}var p=r=>{let o=e.c(),s=e.o(),c=e.d(n.CommentsExtension),l=r.comment.reactions.find(e=>e.emoji===r.emoji);if(!l)throw Error(`Trying to render reaction badge for non-existing reaction`);let[u,d]=(0,t.useState)([]),p=f(u);return(0,a.jsx)(o.Generic.Badge.Root,{className:(0,i.mergeCSSClasses)(`bn-badge`,`bn-comment-reaction`),text:l.userIds.length.toString(),icon:l.emoji,isSelected:c.threadStore.auth.canDeleteReaction(r.comment,l.emoji),onClick:()=>r.onReactionSelect(l.emoji),onMouseEnter:()=>d(l.userIds),mainTooltip:s.comments.reactions.reacted_by,secondaryTooltip:`${Array.from(p.values()).map(e=>e.username).join(`
2
+ `)}`},l.emoji)},m=({comment:r,thread:s,showResolveButton:c})=>{let l=e.d(n.CommentsExtension),f=e.o(),m=e.r({initialContent:r.body,trailingBlock:!1,dictionary:{...f,placeholders:{emptyDocument:f.placeholders.edit_comment}},schema:l.commentEditorSchema||e.t}),h=e.c(),[g,_]=(0,t.useState)(!1),[v,y]=(0,t.useState)(!1),b=l.threadStore,x=(0,t.useCallback)(()=>{_(!0)},[]),S=(0,t.useCallback)(()=>{m.replaceBlocks(m.document,r.body),_(!1)},[m,r.body]),C=(0,t.useCallback)(async e=>{await b.updateComment({commentId:r.id,comment:{body:m.document},threadId:s.id}),_(!1)},[r,s.id,m,b]),w=(0,t.useCallback)(async()=>{await b.deleteComment({commentId:r.id,threadId:s.id})},[r,s.id,b]),T=(0,t.useCallback)(async e=>{b.auth.canAddReaction(r,e)?await b.addReaction({threadId:s.id,commentId:r.id,emoji:e}):b.auth.canDeleteReaction(r,e)&&await b.deleteReaction({threadId:s.id,commentId:r.id,emoji:e})},[b,r,s.id]),E=(0,t.useCallback)(async()=>{await b.resolveThread({threadId:s.id})},[s.id,b]),D=(0,t.useCallback)(async()=>{await b.unresolveThread({threadId:s.id})},[s.id,b]),O=d(r.userId);if(!r.body)return null;let k,A=b.auth.canAddReaction(r),j=b.auth.canDeleteComment(r),M=b.auth.canUpdateComment(r),N=c&&(s.resolved?b.auth.canUnresolveThread(s):b.auth.canResolveThread(s));g||(k=(0,a.jsxs)(h.Generic.Toolbar.Root,{className:(0,i.mergeCSSClasses)(`bn-action-toolbar`,`bn-comment-actions`),variant:`action-toolbar`,children:[A&&(0,a.jsx)(u,{onEmojiSelect:e=>T(e.native),onOpenChange:y,children:(0,a.jsx)(h.Generic.Toolbar.Button,{mainTooltip:f.comments.actions.add_reaction,variant:`compact`,children:(0,a.jsx)(o.RiEmotionLine,{size:16})},`add-reaction`)}),N&&(s.resolved?(0,a.jsx)(h.Generic.Toolbar.Button,{mainTooltip:`Re-open`,variant:`compact`,onClick:D,children:(0,a.jsx)(o.RiArrowGoBackFill,{size:16})},`reopen`):(0,a.jsx)(h.Generic.Toolbar.Button,{mainTooltip:f.comments.actions.resolve,variant:`compact`,onClick:E,children:(0,a.jsx)(o.RiCheckFill,{size:16})},`resolve`)),(j||M)&&(0,a.jsxs)(h.Generic.Menu.Root,{position:`bottom-start`,children:[(0,a.jsx)(h.Generic.Menu.Trigger,{children:(0,a.jsx)(h.Generic.Toolbar.Button,{mainTooltip:f.comments.actions.more_actions,variant:`compact`,children:(0,a.jsx)(o.RiMoreFill,{size:16})},`more-actions`)}),(0,a.jsxs)(h.Generic.Menu.Dropdown,{className:`bn-menu-dropdown`,children:[M&&(0,a.jsx)(h.Generic.Menu.Item,{icon:(0,a.jsx)(o.RiEditFill,{}),onClick:x,children:f.comments.actions.edit_comment},`edit-comment`),j&&(0,a.jsx)(h.Generic.Menu.Item,{icon:(0,a.jsx)(o.RiDeleteBinFill,{}),onClick:w,children:f.comments.actions.delete_comment},`delete-comment`)]})]})]}));let P=r.createdAt.toLocaleDateString(void 0,{month:`short`,day:`numeric`});if(!r.body)throw Error(`soft deletes are not yet supported`);return(0,a.jsx)(h.Comments.Comment,{authorInfo:O??`loading`,timeString:P,edited:r.updatedAt.getTime()!==r.createdAt.getTime(),showActions:`hover`,actions:k,className:`bn-thread-comment`,emojiPickerOpen:v,children:(0,a.jsx)(e.n,{autoFocus:g,editor:m,editable:g,actions:r.reactions.length>0||g?({isEmpty:e})=>(0,a.jsxs)(a.Fragment,{children:[r.reactions.length>0&&!g&&(0,a.jsxs)(h.Generic.Badge.Group,{className:(0,i.mergeCSSClasses)(`bn-badge-group`,`bn-comment-reactions`),children:[r.reactions.map(e=>(0,a.jsx)(p,{comment:r,emoji:e.emoji,onReactionSelect:T},e.emoji)),A&&(0,a.jsx)(u,{onEmojiSelect:e=>T(e.native),onOpenChange:y,children:(0,a.jsx)(h.Generic.Badge.Root,{className:(0,i.mergeCSSClasses)(`bn-badge`,`bn-comment-add-reaction`),text:`+`,icon:(0,a.jsx)(o.RiEmotionLine,{size:16}),mainTooltip:f.comments.actions.add_reaction})})]}),g&&(0,a.jsxs)(h.Generic.Toolbar.Root,{variant:`action-toolbar`,className:(0,i.mergeCSSClasses)(`bn-action-toolbar`,`bn-comment-actions`),children:[(0,a.jsx)(h.Generic.Toolbar.Button,{mainTooltip:f.comments.save_button_text,variant:`compact`,onClick:C,isDisabled:e,children:f.comments.save_button_text}),(0,a.jsx)(h.Generic.Toolbar.Button,{className:`bn-button`,mainTooltip:f.comments.cancel_button_text,variant:`compact`,onClick:S,children:f.comments.cancel_button_text})]})]}):void 0})})},h=({thread:t,maxCommentsBeforeCollapse:n})=>{let r=e.c(),i=e.o(),o=f(t.resolvedBy?[t.resolvedBy]:[]),s=t.comments.map((e,n)=>(0,a.jsx)(m,{thread:t,comment:e,showResolveButton:n===0},e.id+JSON.stringify(e.body||`{}`)));if(t.resolved&&t.resolvedUpdatedAt&&t.resolvedBy){if(!o.get(t.resolvedBy))throw Error(`User ${t.resolvedBy} resolved thread ${t.id}, but their data could not be found.`);let e=t.comments.findLastIndex(e=>t.resolvedUpdatedAt.getTime()>e.createdAt.getTime())+1;s.splice(e,0,(0,a.jsx)(r.Comments.Comment,{className:`bn-thread-comment`,authorInfo:t.resolvedBy&&o.get(t.resolvedBy)||`loading`,timeString:t.resolvedUpdatedAt.toLocaleDateString(void 0,{month:`short`,day:`numeric`}),edited:!1,showActions:!1,children:(0,a.jsx)(`div`,{className:`bn-resolved-text`,children:i.comments.sidebar.marked_as_resolved})},`resolved-comment`))}return n&&s.length>n&&s.splice(1,s.length-2,(0,a.jsx)(r.Comments.ExpandSectionsPrompt,{className:`bn-thread-expand-prompt`,children:i.comments.sidebar.more_replies(t.comments.length-2)},`expand-prompt`)),s},g=({thread:r,selected:o,referenceText:s,maxCommentsBeforeCollapse:c,onFocus:l,onBlur:u,tabIndex:d})=>{let f=e.c(),p=e.o(),m=e.d(n.CommentsExtension),g=e.r({trailingBlock:!1,dictionary:{...p,placeholders:{emptyDocument:p.placeholders.comment_reply}},schema:m.commentEditorSchema||e.t}),_=(0,t.useCallback)(async()=>{await m.threadStore.addComment({comment:{body:g.document},threadId:r.id}),g.removeBlocks(g.document)},[m,g,r.id]);return(0,a.jsxs)(f.Comments.Card,{className:`bn-thread`,headerText:s,onFocus:l,onBlur:u,selected:o,tabIndex:d,children:[(0,a.jsx)(f.Comments.CardSection,{className:`bn-thread-comments`,children:(0,a.jsx)(h,{thread:r,maxCommentsBeforeCollapse:o?void 0:c||5})}),o&&(0,a.jsx)(f.Comments.CardSection,{className:`bn-thread-composer`,children:(0,a.jsx)(e.n,{autoFocus:!1,editable:!0,editor:g,actions:({isEmpty:e})=>e?null:(0,a.jsx)(f.Generic.Toolbar.Root,{variant:`action-toolbar`,className:(0,i.mergeCSSClasses)(`bn-action-toolbar`,`bn-comment-actions`),children:(0,a.jsx)(f.Generic.Toolbar.Button,{mainTooltip:p.comments.save_button_text,variant:`compact`,isDisabled:e,onClick:_,children:p.comments.save_button_text})})})})]})};function _(){let r=e.d(n.CommentsExtension).threadStore,i=(0,t.useRef)(void 0);return i.current||=r.getThreads(),(0,t.useSyncExternalStore)((0,t.useCallback)(e=>r.subscribe(t=>{i.current=t,e()}),[r]),()=>i.current)}var v=e.g({default:()=>y});function y(i){let o=e.p(),s=e.d(n.CommentsExtension),c=e.f(n.CommentsExtension,{editor:o,selector:e=>e.selectedThreadId?{id:e.selectedThreadId,position:e.threadPositions.get(e.selectedThreadId)}:void 0}),l=_(),u=(0,t.useMemo)(()=>c?l.get(c.id):void 0,[c,l]),d=(0,t.useMemo)(()=>({...i.floatingUIOptions,useFloatingOptions:{open:!!c,onOpenChange:(e,t,n)=>{n===`escape-key`&&o.focus(),e||s.selectThread(void 0)},placement:`bottom`,middleware:[(0,r.offset)(10),(0,r.shift)(),(0,r.flip)()],...i.floatingUIOptions?.useFloatingOptions},focusManagerProps:{disabled:!0,...i.floatingUIOptions?.focusManagerProps},elementProps:{style:{zIndex:30},...i.floatingUIOptions?.elementProps}}),[s,o,i.floatingUIOptions,c]),f=i.floatingThread||g;return(0,a.jsx)(e.i,{position:c?.position,...d,children:u&&(0,a.jsx)(f,{thread:u,selected:!0})})}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}});
3
+ //# sourceMappingURL=FloatingThreadController-BMC2B9Lr.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingThreadController-BMC2B9Lr.cjs","names":[],"sources":["../src/components/Comments/EmojiMartPicker.tsx","../src/components/Comments/EmojiPicker.tsx","../src/components/Comments/useUsers.ts","../src/components/Comments/ReactionBadge.tsx","../src/components/Comments/Comment.tsx","../src/components/Comments/Comments.tsx","../src/components/Comments/Thread.tsx","../src/components/Comments/useThreads.ts","../src/components/Comments/FloatingThreadController.tsx"],"sourcesContent":["// From https://github.com/missive/emoji-mart/blob/main/packages/emoji-mart-react/react.tsx\nimport type { EmojiMartData } from \"@emoji-mart/data\";\nimport React, { useEffect, useRef } from \"react\";\n\n// Temporary fix for https://github.com/missive/emoji-mart/pull/929\nlet emojiLoadingPromise:\n | Promise<{\n emojiMart: typeof import(\"emoji-mart\");\n emojiData: EmojiMartData;\n }>\n | undefined;\n\nasync function loadEmojiMart() {\n if (emojiLoadingPromise) {\n return emojiLoadingPromise;\n }\n\n emojiLoadingPromise = (async () => {\n // load dynamically because emoji-mart doesn't specify type: module and breaks in nodejs\n const [emojiMartModule, emojiDataModule] = await Promise.all([\n import(\"emoji-mart\"),\n // use a dynamic import to encourage bundle-splitting\n // and a smaller initial client bundle size\n import(\"@emoji-mart/data\"),\n ]);\n\n const emojiMart =\n \"default\" in emojiMartModule ? emojiMartModule.default : emojiMartModule;\n const emojiData =\n \"default\" in emojiDataModule\n ? (emojiDataModule.default as EmojiMartData)\n : (emojiDataModule as EmojiMartData);\n\n await emojiMart.init({ data: emojiData });\n\n return { emojiMart, emojiData };\n })();\n\n return emojiLoadingPromise;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function EmojiPicker(props: any) {\n const ref = useRef(null);\n const instance = useRef(null) as any;\n\n if (instance.current) {\n instance.current.update(props);\n }\n\n useEffect(() => {\n (async () => {\n const { emojiMart } = await loadEmojiMart();\n\n instance.current = new emojiMart.Picker({ ...props, ref });\n })();\n\n return () => {\n instance.current = null;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n return React.createElement(\"div\", { ref });\n}\n","import { ReactNode, useState } from \"react\";\n\nimport { useBlockNoteContext } from \"../../editor/BlockNoteContext.js\";\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport Picker from \"./EmojiMartPicker.js\";\n\nexport const EmojiPicker = (props: {\n onEmojiSelect: (emoji: { native: string }) => void;\n onOpenChange?: (open: boolean) => void;\n children: ReactNode;\n}) => {\n const [open, setOpen] = useState(false);\n\n const Components = useComponentsContext()!;\n const blockNoteContext = useBlockNoteContext()!;\n const portalRoot = blockNoteContext.editor?.portalElement;\n\n if (!portalRoot) {\n throw new Error(\"Portal root not found\");\n }\n\n return (\n <Components.Generic.Popover.Root open={open} portalRoot={portalRoot}>\n <Components.Generic.Popover.Trigger>\n <div\n onClick={(event) => {\n // Needed as the Picker component's onClickOutside handler\n // fires immediately after otherwise, preventing the popover\n // from opening.\n event.preventDefault();\n event.stopPropagation();\n setOpen(!open);\n props.onOpenChange?.(!open);\n }}\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n {props.children}\n </div>\n </Components.Generic.Popover.Trigger>\n <Components.Generic.Popover.Content\n className={\"bn-emoji-picker-popover\"}\n variant={\"panel-popover\"}\n >\n <Picker\n perLine={7}\n onClickOutside={() => {\n setOpen(false);\n props.onOpenChange?.(false);\n }}\n onEmojiSelect={(emoji: { native: string }) => {\n props.onEmojiSelect(emoji);\n setOpen(false);\n props.onOpenChange?.(false);\n }}\n theme={blockNoteContext?.colorSchemePreference}\n />\n </Components.Generic.Popover.Content>\n </Components.Generic.Popover.Root>\n );\n};\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { User } from \"@blocknote/core/comments\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\n\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\nexport function useUser(userId: string) {\n return useUsers([userId]).get(userId);\n}\n\n/**\n * Bridges the UserStore to React using useSyncExternalStore.\n */\nexport function useUsers(userIds: string[]) {\n const comments = useExtension(CommentsExtension);\n\n const store = comments.userStore;\n\n const getUpdatedSnapshot = useCallback(() => {\n const map = new Map<string, User>();\n for (const id of userIds) {\n const user = store.getUser(id);\n if (user) {\n map.set(id, user);\n }\n }\n return map;\n }, [store, userIds]);\n\n // this ref / memoworks around this error:\n // https://react.dev/reference/react/useSyncExternalStore#im-getting-an-error-the-result-of-getsnapshot-should-be-cached\n // however, might not be a good practice to work around it this way\n\n // We need to use a memo instead of a ref to make sure the snapshot is updated when the userIds change\n const ref = useMemo(() => {\n return {\n current: getUpdatedSnapshot(),\n };\n }, [getUpdatedSnapshot]);\n\n // note: this is inefficient as it will trigger a re-render even if other users (not in userIds) are updated\n const subscribe = useCallback(\n (cb: () => void) => {\n const ret = store.subscribe((_users) => {\n // update ref when changed\n ref.current = getUpdatedSnapshot();\n\n // calling cb() will make sure `useSyncExternalStore` will fetch the latest snapshot (which is ref.current)\n cb();\n });\n store.loadUsers(userIds);\n return ret;\n },\n [store, getUpdatedSnapshot, userIds, ref],\n );\n\n return useSyncExternalStore(subscribe, () => ref.current!);\n}\n","import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { CommentData } from \"@blocknote/core/comments\";\nimport { useState } from \"react\";\n\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useUsers } from \"./useUsers.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\nexport const ReactionBadge = (props: {\n comment: CommentData;\n emoji: string;\n onReactionSelect: (emoji: string) => void;\n}) => {\n const Components = useComponentsContext()!;\n const dict = useDictionary();\n\n const comments = useExtension(CommentsExtension);\n\n const reaction = props.comment.reactions.find(\n (reaction) => reaction.emoji === props.emoji,\n );\n if (!reaction) {\n throw new Error(\n \"Trying to render reaction badge for non-existing reaction\",\n );\n }\n\n const [userIds, setUserIds] = useState<string[]>([]);\n const users = useUsers(userIds);\n\n return (\n <Components.Generic.Badge.Root\n key={reaction.emoji}\n className={mergeCSSClasses(\"bn-badge\", \"bn-comment-reaction\")}\n text={reaction.userIds.length.toString()}\n icon={reaction.emoji}\n isSelected={comments.threadStore.auth.canDeleteReaction(\n props.comment,\n reaction.emoji,\n )}\n onClick={() => props.onReactionSelect(reaction.emoji)}\n onMouseEnter={() => setUserIds(reaction.userIds)}\n mainTooltip={dict.comments.reactions.reacted_by}\n secondaryTooltip={`${Array.from(users.values())\n .map((user) => user.username)\n .join(\"\\n\")}`}\n />\n );\n};\n","\"use client\";\n\nimport { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport type { CommentData, ThreadData } from \"@blocknote/core/comments\";\nimport { MouseEvent, ReactNode, useCallback, useState } from \"react\";\nimport {\n RiArrowGoBackFill,\n RiCheckFill,\n RiDeleteBinFill,\n RiEditFill,\n RiEmotionLine,\n RiMoreFill,\n} from \"react-icons/ri\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { EmojiPicker } from \"./EmojiPicker.js\";\nimport { ReactionBadge } from \"./ReactionBadge.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\nimport { useUser } from \"./useUsers.js\";\n\nexport type CommentProps = {\n comment: CommentData;\n thread: ThreadData;\n showResolveButton?: boolean;\n};\n\n/**\n * The Comment component displays a single comment with actions,\n * a reaction list and an editor when editing.\n *\n * It's generally used in the `Thread` component for comments that have already been created.\n *\n */\nexport const Comment = ({\n comment,\n thread,\n showResolveButton,\n}: CommentProps) => {\n // TODO: if REST API becomes popular, all interactions (click handlers) should implement a loading state and error state\n // (or optimistic local updates)\n const comments = useExtension(CommentsExtension);\n\n const dict = useDictionary();\n\n const commentEditor = useCreateBlockNote({\n initialContent: comment.body,\n trailingBlock: false,\n dictionary: {\n ...dict,\n placeholders: {\n emptyDocument: dict.placeholders.edit_comment,\n },\n },\n schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n });\n\n const Components = useComponentsContext()!;\n\n const [isEditing, setEditing] = useState(false);\n const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n\n const threadStore = comments.threadStore;\n\n const handleEdit = useCallback(() => {\n setEditing(true);\n }, []);\n\n const onEditCancel = useCallback(() => {\n commentEditor.replaceBlocks(commentEditor.document, comment.body);\n setEditing(false);\n }, [commentEditor, comment.body]);\n\n const onEditSubmit = useCallback(\n async (_event: MouseEvent) => {\n await threadStore.updateComment({\n commentId: comment.id,\n comment: {\n body: commentEditor.document,\n },\n threadId: thread.id,\n });\n\n setEditing(false);\n },\n [comment, thread.id, commentEditor, threadStore],\n );\n\n const onDelete = useCallback(async () => {\n await threadStore.deleteComment({\n commentId: comment.id,\n threadId: thread.id,\n });\n }, [comment, thread.id, threadStore]);\n\n const onReactionSelect = useCallback(\n async (emoji: string) => {\n if (threadStore.auth.canAddReaction(comment, emoji)) {\n await threadStore.addReaction({\n threadId: thread.id,\n commentId: comment.id,\n emoji,\n });\n } else if (threadStore.auth.canDeleteReaction(comment, emoji)) {\n await threadStore.deleteReaction({\n threadId: thread.id,\n commentId: comment.id,\n emoji,\n });\n }\n },\n [threadStore, comment, thread.id],\n );\n\n const onResolve = useCallback(async () => {\n await threadStore.resolveThread({\n threadId: thread.id,\n });\n }, [thread.id, threadStore]);\n\n const onReopen = useCallback(async () => {\n await threadStore.unresolveThread({\n threadId: thread.id,\n });\n }, [thread.id, threadStore]);\n\n const user = useUser(comment.userId);\n\n if (!comment.body) {\n return null;\n }\n\n let actions: ReactNode | undefined = undefined;\n const canAddReaction = threadStore.auth.canAddReaction(comment);\n const canDeleteComment = threadStore.auth.canDeleteComment(comment);\n const canEditComment = threadStore.auth.canUpdateComment(comment);\n\n const showResolveOrReopen =\n showResolveButton &&\n (thread.resolved\n ? threadStore.auth.canUnresolveThread(thread)\n : threadStore.auth.canResolveThread(thread));\n\n if (!isEditing) {\n actions = (\n <Components.Generic.Toolbar.Root\n className={mergeCSSClasses(\"bn-action-toolbar\", \"bn-comment-actions\")}\n variant={\"action-toolbar\"}\n >\n {canAddReaction && (\n <EmojiPicker\n onEmojiSelect={(emoji: { native: string }) =>\n onReactionSelect(emoji.native)\n }\n onOpenChange={setEmojiPickerOpen}\n >\n <Components.Generic.Toolbar.Button\n key={\"add-reaction\"}\n mainTooltip={dict.comments.actions.add_reaction}\n variant=\"compact\"\n >\n <RiEmotionLine size={16} />\n </Components.Generic.Toolbar.Button>\n </EmojiPicker>\n )}\n {showResolveOrReopen &&\n (thread.resolved ? (\n <Components.Generic.Toolbar.Button\n key={\"reopen\"}\n mainTooltip=\"Re-open\"\n variant=\"compact\"\n onClick={onReopen}\n >\n <RiArrowGoBackFill size={16} />\n </Components.Generic.Toolbar.Button>\n ) : (\n <Components.Generic.Toolbar.Button\n key={\"resolve\"}\n mainTooltip={dict.comments.actions.resolve}\n variant=\"compact\"\n onClick={onResolve}\n >\n <RiCheckFill size={16} />\n </Components.Generic.Toolbar.Button>\n ))}\n {(canDeleteComment || canEditComment) && (\n <Components.Generic.Menu.Root position={\"bottom-start\"}>\n <Components.Generic.Menu.Trigger>\n <Components.Generic.Toolbar.Button\n key={\"more-actions\"}\n mainTooltip={dict.comments.actions.more_actions}\n variant=\"compact\"\n >\n <RiMoreFill size={16} />\n </Components.Generic.Toolbar.Button>\n </Components.Generic.Menu.Trigger>\n <Components.Generic.Menu.Dropdown className={\"bn-menu-dropdown\"}>\n {canEditComment && (\n <Components.Generic.Menu.Item\n key={\"edit-comment\"}\n icon={<RiEditFill />}\n onClick={handleEdit}\n >\n {dict.comments.actions.edit_comment}\n </Components.Generic.Menu.Item>\n )}\n {canDeleteComment && (\n <Components.Generic.Menu.Item\n key={\"delete-comment\"}\n icon={<RiDeleteBinFill />}\n onClick={onDelete}\n >\n {dict.comments.actions.delete_comment}\n </Components.Generic.Menu.Item>\n )}\n </Components.Generic.Menu.Dropdown>\n </Components.Generic.Menu.Root>\n )}\n </Components.Generic.Toolbar.Root>\n );\n }\n\n const timeString = comment.createdAt.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n });\n\n if (!comment.body) {\n throw new Error(\"soft deletes are not yet supported\");\n }\n\n return (\n <Components.Comments.Comment\n authorInfo={user ?? \"loading\"}\n timeString={timeString}\n edited={comment.updatedAt.getTime() !== comment.createdAt.getTime()}\n showActions={\"hover\"}\n actions={actions}\n className={\"bn-thread-comment\"}\n emojiPickerOpen={emojiPickerOpen}\n >\n <CommentEditor\n autoFocus={isEditing}\n editor={commentEditor}\n editable={isEditing}\n actions={\n comment.reactions.length > 0 || isEditing\n ? ({ isEmpty }) => (\n <>\n {comment.reactions.length > 0 && !isEditing && (\n <Components.Generic.Badge.Group\n className={mergeCSSClasses(\n \"bn-badge-group\",\n \"bn-comment-reactions\",\n )}\n >\n {comment.reactions.map((reaction) => (\n <ReactionBadge\n key={reaction.emoji}\n comment={comment}\n emoji={reaction.emoji}\n onReactionSelect={onReactionSelect}\n />\n ))}\n {canAddReaction && (\n <EmojiPicker\n onEmojiSelect={(emoji: { native: string }) =>\n onReactionSelect(emoji.native)\n }\n onOpenChange={setEmojiPickerOpen}\n >\n <Components.Generic.Badge.Root\n className={mergeCSSClasses(\n \"bn-badge\",\n \"bn-comment-add-reaction\",\n )}\n text={\"+\"}\n icon={<RiEmotionLine size={16} />}\n mainTooltip={dict.comments.actions.add_reaction}\n />\n </EmojiPicker>\n )}\n </Components.Generic.Badge.Group>\n )}\n {isEditing && (\n <Components.Generic.Toolbar.Root\n variant=\"action-toolbar\"\n className={mergeCSSClasses(\n \"bn-action-toolbar\",\n \"bn-comment-actions\",\n )}\n >\n <Components.Generic.Toolbar.Button\n mainTooltip={dict.comments.save_button_text}\n variant=\"compact\"\n onClick={onEditSubmit}\n isDisabled={isEmpty}\n >\n {dict.comments.save_button_text}\n </Components.Generic.Toolbar.Button>\n <Components.Generic.Toolbar.Button\n className={\"bn-button\"}\n mainTooltip={dict.comments.cancel_button_text}\n variant=\"compact\"\n onClick={onEditCancel}\n >\n {dict.comments.cancel_button_text}\n </Components.Generic.Toolbar.Button>\n </Components.Generic.Toolbar.Root>\n )}\n </>\n )\n : undefined\n }\n />\n </Components.Comments.Comment>\n );\n};\n","import { ThreadData } from \"@blocknote/core/comments\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { Comment } from \"./Comment.js\";\nimport { useUsers } from \"./useUsers.js\";\n\nexport type CommentsProps = {\n thread: ThreadData;\n maxCommentsBeforeCollapse?: number;\n};\n\nexport const Comments = ({\n thread,\n maxCommentsBeforeCollapse,\n}: CommentsProps) => {\n const Components = useComponentsContext()!;\n const dict = useDictionary();\n const users = useUsers(thread.resolvedBy ? [thread.resolvedBy] : []);\n\n // Maps all comments to elements.\n const comments = thread.comments.map((comment, index) => (\n <Comment\n key={comment.id + JSON.stringify(comment.body || \"{}\")}\n thread={thread}\n comment={comment}\n showResolveButton={index === 0}\n />\n ));\n\n // Adds \"resolved by\" comment if needed.\n if (thread.resolved && thread.resolvedUpdatedAt && thread.resolvedBy) {\n const resolvedByUser = users.get(thread.resolvedBy);\n if (!resolvedByUser) {\n throw new Error(\n `User ${thread.resolvedBy} resolved thread ${thread.id}, but their data could not be found.`,\n );\n }\n\n const resolvedCommentIndex =\n thread.comments.findLastIndex(\n (comment) =>\n thread.resolvedUpdatedAt!.getTime() > comment.createdAt.getTime(),\n ) + 1;\n\n comments.splice(\n resolvedCommentIndex,\n 0,\n <Components.Comments.Comment\n key={\"resolved-comment\"}\n className={\"bn-thread-comment\"}\n authorInfo={\n (thread.resolvedBy && users.get(thread.resolvedBy)) || \"loading\"\n }\n timeString={thread.resolvedUpdatedAt.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n })}\n edited={false}\n showActions={false}\n >\n <div className={\"bn-resolved-text\"}>\n {dict.comments.sidebar.marked_as_resolved}\n </div>\n </Components.Comments.Comment>,\n );\n }\n\n // Collapses replies if needed.\n if (\n maxCommentsBeforeCollapse &&\n comments.length > maxCommentsBeforeCollapse\n ) {\n comments.splice(\n 1,\n comments.length - 2,\n <Components.Comments.ExpandSectionsPrompt\n key={\"expand-prompt\"}\n className={\"bn-thread-expand-prompt\"}\n >\n {dict.comments.sidebar.more_replies(thread.comments.length - 2)}\n </Components.Comments.ExpandSectionsPrompt>,\n );\n }\n\n return comments;\n};\n","import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { ThreadData } from \"@blocknote/core/comments\";\nimport { FocusEvent, useCallback } from \"react\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { Comments } from \"./Comments.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\n\nexport type ThreadProps = {\n /**\n * The thread to display - you can use the `useThreads` hook to retrieve a\n * `Map` of all threads in the editor, mapped by their IDs.\n */\n thread: ThreadData;\n /**\n * A boolean flag for whether the thread is selected. Selected threads show an\n * editor for replies, and add a `selected` CSS class to the thread.\n */\n selected?: boolean;\n /**\n * The text in the editor that the thread refers to. See the\n * [`ThreadsSidebar`](https://github.com/TypeCellOS/BlockNote/tree/main/packages/react/src/components/Comments/ThreadsSidebar.tsx#L137)\n * component to find out how to get this.\n */\n referenceText?: string;\n /**\n * The maximum number of comments that can be in a thread before the replies\n * get collapsed.\n */\n maxCommentsBeforeCollapse?: number;\n /**\n * A function to call when the thread is focused.\n */\n onFocus?: (event: FocusEvent) => void;\n /**\n * A function to call when the thread is blurred.\n */\n onBlur?: (event: FocusEvent) => void;\n /**\n * The tab index for the thread.\n */\n tabIndex?: number;\n};\n\n/**\n * The Thread component displays a (main) comment with a list of replies (other comments).\n *\n * It also includes a composer to reply to the thread.\n */\nexport const Thread = ({\n thread,\n selected,\n referenceText,\n maxCommentsBeforeCollapse,\n onFocus,\n onBlur,\n tabIndex,\n}: ThreadProps) => {\n // TODO: if REST API becomes popular, all interactions (click handlers) should implement a loading state and error state\n // (or optimistic local updates)\n\n const Components = useComponentsContext()!;\n const dict = useDictionary();\n\n const comments = useExtension(CommentsExtension);\n\n const newCommentEditor = useCreateBlockNote({\n trailingBlock: false,\n dictionary: {\n ...dict,\n placeholders: {\n emptyDocument: dict.placeholders.comment_reply,\n },\n },\n schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n });\n\n const onNewCommentSave = useCallback(async () => {\n await comments.threadStore.addComment({\n comment: {\n body: newCommentEditor.document,\n },\n threadId: thread.id,\n });\n\n // reset editor\n newCommentEditor.removeBlocks(newCommentEditor.document);\n }, [comments, newCommentEditor, thread.id]);\n\n return (\n <Components.Comments.Card\n className={\"bn-thread\"}\n headerText={referenceText}\n onFocus={onFocus}\n onBlur={onBlur}\n selected={selected}\n tabIndex={tabIndex}\n >\n <Components.Comments.CardSection className=\"bn-thread-comments\">\n <Comments\n thread={thread}\n maxCommentsBeforeCollapse={\n !selected ? maxCommentsBeforeCollapse || 5 : undefined\n }\n />\n </Components.Comments.CardSection>\n {selected && (\n <Components.Comments.CardSection className={\"bn-thread-composer\"}>\n <CommentEditor\n autoFocus={false}\n editable={true}\n editor={newCommentEditor}\n actions={({ isEmpty }) => {\n if (isEmpty) {\n return null;\n }\n\n return (\n <Components.Generic.Toolbar.Root\n variant=\"action-toolbar\"\n className={mergeCSSClasses(\n \"bn-action-toolbar\",\n \"bn-comment-actions\",\n )}\n >\n <Components.Generic.Toolbar.Button\n mainTooltip={dict.comments.save_button_text}\n variant=\"compact\"\n isDisabled={isEmpty}\n onClick={onNewCommentSave}\n >\n {dict.comments.save_button_text}\n </Components.Generic.Toolbar.Button>\n </Components.Generic.Toolbar.Root>\n );\n }}\n />\n </Components.Comments.CardSection>\n )}\n </Components.Comments.Card>\n );\n};\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { ThreadData } from \"@blocknote/core/comments\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\n\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\n/**\n * Bridges the ThreadStore to React using useSyncExternalStore.\n */\nexport function useThreads() {\n const comments = useExtension(CommentsExtension);\n\n const store = comments.threadStore;\n\n // this ref works around this error:\n // https://react.dev/reference/react/useSyncExternalStore#im-getting-an-error-the-result-of-getsnapshot-should-be-cached\n // however, might not be a good practice to work around it this way\n const threadsRef = useRef<Map<string, ThreadData> | undefined>(undefined);\n\n if (!threadsRef.current) {\n threadsRef.current = store.getThreads();\n }\n\n const subscribe = useCallback(\n (cb: () => void) => {\n return store.subscribe((threads) => {\n // update ref when changed\n threadsRef.current = threads;\n cb();\n });\n },\n [store],\n );\n\n return useSyncExternalStore(subscribe, () => threadsRef.current!);\n}\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { flip, offset, shift } from \"@floating-ui/react\";\nimport { ComponentProps, FC, useMemo } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { useExtension, useExtensionState } from \"../../hooks/useExtension.js\";\nimport { FloatingUIOptions } from \"../Popovers/FloatingUIOptions.js\";\nimport { PositionPopover } from \"../Popovers/PositionPopover.js\";\nimport { Thread } from \"./Thread.js\";\nimport { useThreads } from \"./useThreads.js\";\n\n/**\n * This component is used to display a thread in a floating card.\n * It can be used when the user clicks on a thread / comment in the document.\n */\nexport default function FloatingThreadController(props: {\n floatingThread?: FC<ComponentProps<typeof Thread>>;\n floatingUIOptions?: FloatingUIOptions;\n}) {\n const editor = useBlockNoteEditor<any, any, any>();\n\n const comments = useExtension(CommentsExtension);\n const selectedThread = useExtensionState(CommentsExtension, {\n editor,\n selector: (state) =>\n state.selectedThreadId\n ? {\n id: state.selectedThreadId,\n position: state.threadPositions.get(state.selectedThreadId),\n }\n : undefined,\n });\n\n const threads = useThreads();\n\n const thread = useMemo(\n () => (selectedThread ? threads.get(selectedThread.id) : undefined),\n [selectedThread, threads],\n );\n\n const floatingUIOptions = useMemo<FloatingUIOptions>(\n () => ({\n ...props.floatingUIOptions,\n useFloatingOptions: {\n open: !!selectedThread,\n // Needed as hooks like `useDismiss` call `onOpenChange` to change the\n // open state.\n onOpenChange: (open, _event, reason) => {\n if (reason === \"escape-key\") {\n editor.focus();\n }\n\n if (!open) {\n comments.selectThread(undefined);\n }\n },\n placement: \"bottom\",\n middleware: [offset(10), shift(), flip()],\n ...props.floatingUIOptions?.useFloatingOptions,\n },\n focusManagerProps: {\n disabled: true,\n ...props.floatingUIOptions?.focusManagerProps,\n },\n elementProps: {\n style: {\n zIndex: 30,\n },\n ...props.floatingUIOptions?.elementProps,\n },\n }),\n [comments, editor, props.floatingUIOptions, selectedThread],\n );\n\n // nice to have improvements:\n // - transition transform property so composer box animates when remote document is changed\n\n const Component = props.floatingThread || Thread;\n\n return (\n <PositionPopover position={selectedThread?.position} {...floatingUIOptions}>\n {thread && <Component thread={thread} selected={true} />}\n </PositionPopover>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,398 @@
1
+ import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
2
+ import { c as t, d as n, f as r, h as i, i as a, n as o, o as s, p as c, r as l, t as u } from "./defaultCommentEditorSchema-Bd70-hG9.js";
3
+ import d, { useCallback as f, useEffect as p, useMemo as m, useRef as h, useState as g, useSyncExternalStore as _ } from "react";
4
+ import { CommentsExtension as v } from "@blocknote/core/comments";
5
+ import { flip as y, offset as b, shift as x } from "@floating-ui/react";
6
+ import { mergeCSSClasses as S } from "@blocknote/core";
7
+ import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
8
+ import { RiArrowGoBackFill as E, RiCheckFill as D, RiDeleteBinFill as O, RiEditFill as k, RiEmotionLine as A, RiMoreFill as j } from "react-icons/ri";
9
+ //#region src/components/Comments/EmojiMartPicker.tsx
10
+ var M;
11
+ async function N() {
12
+ return M || (M = (async () => {
13
+ let [e, t] = await Promise.all([import("emoji-mart"), import("@emoji-mart/data")]), n = "default" in e ? e.default : e, r = "default" in t ? t.default : t;
14
+ return await n.init({ data: r }), {
15
+ emojiMart: n,
16
+ emojiData: r
17
+ };
18
+ })(), M);
19
+ }
20
+ function P(e) {
21
+ let t = h(null), n = h(null);
22
+ return n.current && n.current.update(e), p(() => ((async () => {
23
+ let { emojiMart: r } = await N();
24
+ n.current = new r.Picker({
25
+ ...e,
26
+ ref: t
27
+ });
28
+ })(), () => {
29
+ n.current = null;
30
+ }), []), d.createElement("div", { ref: t });
31
+ }
32
+ //#endregion
33
+ //#region src/components/Comments/EmojiPicker.tsx
34
+ var F = (e) => {
35
+ let [n, r] = g(!1), a = t(), o = i(), s = o.editor?.portalElement;
36
+ if (!s) throw Error("Portal root not found");
37
+ return /* @__PURE__ */ T(a.Generic.Popover.Root, {
38
+ open: n,
39
+ portalRoot: s,
40
+ children: [/* @__PURE__ */ w(a.Generic.Popover.Trigger, { children: /* @__PURE__ */ w("div", {
41
+ onClick: (t) => {
42
+ t.preventDefault(), t.stopPropagation(), r(!n), e.onOpenChange?.(!n);
43
+ },
44
+ style: {
45
+ display: "flex",
46
+ justifyContent: "center",
47
+ alignItems: "center"
48
+ },
49
+ children: e.children
50
+ }) }), /* @__PURE__ */ w(a.Generic.Popover.Content, {
51
+ className: "bn-emoji-picker-popover",
52
+ variant: "panel-popover",
53
+ children: /* @__PURE__ */ w(P, {
54
+ perLine: 7,
55
+ onClickOutside: () => {
56
+ r(!1), e.onOpenChange?.(!1);
57
+ },
58
+ onEmojiSelect: (t) => {
59
+ e.onEmojiSelect(t), r(!1), e.onOpenChange?.(!1);
60
+ },
61
+ theme: o?.colorSchemePreference
62
+ })
63
+ })]
64
+ });
65
+ };
66
+ //#endregion
67
+ //#region src/components/Comments/useUsers.ts
68
+ function I(e) {
69
+ return L([e]).get(e);
70
+ }
71
+ function L(e) {
72
+ let t = n(v).userStore, r = f(() => {
73
+ let n = /* @__PURE__ */ new Map();
74
+ for (let r of e) {
75
+ let e = t.getUser(r);
76
+ e && n.set(r, e);
77
+ }
78
+ return n;
79
+ }, [t, e]), i = m(() => ({ current: r() }), [r]);
80
+ return _(f((n) => {
81
+ let a = t.subscribe((e) => {
82
+ i.current = r(), n();
83
+ });
84
+ return t.loadUsers(e), a;
85
+ }, [
86
+ t,
87
+ r,
88
+ e,
89
+ i
90
+ ]), () => i.current);
91
+ }
92
+ //#endregion
93
+ //#region src/components/Comments/ReactionBadge.tsx
94
+ var R = (e) => {
95
+ let r = t(), i = s(), a = n(v), o = e.comment.reactions.find((t) => t.emoji === e.emoji);
96
+ if (!o) throw Error("Trying to render reaction badge for non-existing reaction");
97
+ let [c, l] = g([]), u = L(c);
98
+ return /* @__PURE__ */ w(r.Generic.Badge.Root, {
99
+ className: S("bn-badge", "bn-comment-reaction"),
100
+ text: o.userIds.length.toString(),
101
+ icon: o.emoji,
102
+ isSelected: a.threadStore.auth.canDeleteReaction(e.comment, o.emoji),
103
+ onClick: () => e.onReactionSelect(o.emoji),
104
+ onMouseEnter: () => l(o.userIds),
105
+ mainTooltip: i.comments.reactions.reacted_by,
106
+ secondaryTooltip: `${Array.from(u.values()).map((e) => e.username).join("\n")}`
107
+ }, o.emoji);
108
+ }, z = ({ comment: e, thread: r, showResolveButton: i }) => {
109
+ let a = n(v), c = s(), d = l({
110
+ initialContent: e.body,
111
+ trailingBlock: !1,
112
+ dictionary: {
113
+ ...c,
114
+ placeholders: { emptyDocument: c.placeholders.edit_comment }
115
+ },
116
+ schema: a.commentEditorSchema || u
117
+ }), p = t(), [m, h] = g(!1), [_, y] = g(!1), b = a.threadStore, x = f(() => {
118
+ h(!0);
119
+ }, []), M = f(() => {
120
+ d.replaceBlocks(d.document, e.body), h(!1);
121
+ }, [d, e.body]), N = f(async (t) => {
122
+ await b.updateComment({
123
+ commentId: e.id,
124
+ comment: { body: d.document },
125
+ threadId: r.id
126
+ }), h(!1);
127
+ }, [
128
+ e,
129
+ r.id,
130
+ d,
131
+ b
132
+ ]), P = f(async () => {
133
+ await b.deleteComment({
134
+ commentId: e.id,
135
+ threadId: r.id
136
+ });
137
+ }, [
138
+ e,
139
+ r.id,
140
+ b
141
+ ]), L = f(async (t) => {
142
+ b.auth.canAddReaction(e, t) ? await b.addReaction({
143
+ threadId: r.id,
144
+ commentId: e.id,
145
+ emoji: t
146
+ }) : b.auth.canDeleteReaction(e, t) && await b.deleteReaction({
147
+ threadId: r.id,
148
+ commentId: e.id,
149
+ emoji: t
150
+ });
151
+ }, [
152
+ b,
153
+ e,
154
+ r.id
155
+ ]), z = f(async () => {
156
+ await b.resolveThread({ threadId: r.id });
157
+ }, [r.id, b]), B = f(async () => {
158
+ await b.unresolveThread({ threadId: r.id });
159
+ }, [r.id, b]), V = I(e.userId);
160
+ if (!e.body) return null;
161
+ let H, U = b.auth.canAddReaction(e), W = b.auth.canDeleteComment(e), G = b.auth.canUpdateComment(e), K = i && (r.resolved ? b.auth.canUnresolveThread(r) : b.auth.canResolveThread(r));
162
+ m || (H = /* @__PURE__ */ T(p.Generic.Toolbar.Root, {
163
+ className: S("bn-action-toolbar", "bn-comment-actions"),
164
+ variant: "action-toolbar",
165
+ children: [
166
+ U && /* @__PURE__ */ w(F, {
167
+ onEmojiSelect: (e) => L(e.native),
168
+ onOpenChange: y,
169
+ children: /* @__PURE__ */ w(p.Generic.Toolbar.Button, {
170
+ mainTooltip: c.comments.actions.add_reaction,
171
+ variant: "compact",
172
+ children: /* @__PURE__ */ w(A, { size: 16 })
173
+ }, "add-reaction")
174
+ }),
175
+ K && (r.resolved ? /* @__PURE__ */ w(p.Generic.Toolbar.Button, {
176
+ mainTooltip: "Re-open",
177
+ variant: "compact",
178
+ onClick: B,
179
+ children: /* @__PURE__ */ w(E, { size: 16 })
180
+ }, "reopen") : /* @__PURE__ */ w(p.Generic.Toolbar.Button, {
181
+ mainTooltip: c.comments.actions.resolve,
182
+ variant: "compact",
183
+ onClick: z,
184
+ children: /* @__PURE__ */ w(D, { size: 16 })
185
+ }, "resolve")),
186
+ (W || G) && /* @__PURE__ */ T(p.Generic.Menu.Root, {
187
+ position: "bottom-start",
188
+ children: [/* @__PURE__ */ w(p.Generic.Menu.Trigger, { children: /* @__PURE__ */ w(p.Generic.Toolbar.Button, {
189
+ mainTooltip: c.comments.actions.more_actions,
190
+ variant: "compact",
191
+ children: /* @__PURE__ */ w(j, { size: 16 })
192
+ }, "more-actions") }), /* @__PURE__ */ T(p.Generic.Menu.Dropdown, {
193
+ className: "bn-menu-dropdown",
194
+ children: [G && /* @__PURE__ */ w(p.Generic.Menu.Item, {
195
+ icon: /* @__PURE__ */ w(k, {}),
196
+ onClick: x,
197
+ children: c.comments.actions.edit_comment
198
+ }, "edit-comment"), W && /* @__PURE__ */ w(p.Generic.Menu.Item, {
199
+ icon: /* @__PURE__ */ w(O, {}),
200
+ onClick: P,
201
+ children: c.comments.actions.delete_comment
202
+ }, "delete-comment")]
203
+ })]
204
+ })
205
+ ]
206
+ }));
207
+ let q = e.createdAt.toLocaleDateString(void 0, {
208
+ month: "short",
209
+ day: "numeric"
210
+ });
211
+ if (!e.body) throw Error("soft deletes are not yet supported");
212
+ return /* @__PURE__ */ w(p.Comments.Comment, {
213
+ authorInfo: V ?? "loading",
214
+ timeString: q,
215
+ edited: e.updatedAt.getTime() !== e.createdAt.getTime(),
216
+ showActions: "hover",
217
+ actions: H,
218
+ className: "bn-thread-comment",
219
+ emojiPickerOpen: _,
220
+ children: /* @__PURE__ */ w(o, {
221
+ autoFocus: m,
222
+ editor: d,
223
+ editable: m,
224
+ actions: e.reactions.length > 0 || m ? ({ isEmpty: t }) => /* @__PURE__ */ T(C, { children: [e.reactions.length > 0 && !m && /* @__PURE__ */ T(p.Generic.Badge.Group, {
225
+ className: S("bn-badge-group", "bn-comment-reactions"),
226
+ children: [e.reactions.map((t) => /* @__PURE__ */ w(R, {
227
+ comment: e,
228
+ emoji: t.emoji,
229
+ onReactionSelect: L
230
+ }, t.emoji)), U && /* @__PURE__ */ w(F, {
231
+ onEmojiSelect: (e) => L(e.native),
232
+ onOpenChange: y,
233
+ children: /* @__PURE__ */ w(p.Generic.Badge.Root, {
234
+ className: S("bn-badge", "bn-comment-add-reaction"),
235
+ text: "+",
236
+ icon: /* @__PURE__ */ w(A, { size: 16 }),
237
+ mainTooltip: c.comments.actions.add_reaction
238
+ })
239
+ })]
240
+ }), m && /* @__PURE__ */ T(p.Generic.Toolbar.Root, {
241
+ variant: "action-toolbar",
242
+ className: S("bn-action-toolbar", "bn-comment-actions"),
243
+ children: [/* @__PURE__ */ w(p.Generic.Toolbar.Button, {
244
+ mainTooltip: c.comments.save_button_text,
245
+ variant: "compact",
246
+ onClick: N,
247
+ isDisabled: t,
248
+ children: c.comments.save_button_text
249
+ }), /* @__PURE__ */ w(p.Generic.Toolbar.Button, {
250
+ className: "bn-button",
251
+ mainTooltip: c.comments.cancel_button_text,
252
+ variant: "compact",
253
+ onClick: M,
254
+ children: c.comments.cancel_button_text
255
+ })]
256
+ })] }) : void 0
257
+ })
258
+ });
259
+ }, B = ({ thread: e, maxCommentsBeforeCollapse: n }) => {
260
+ let r = t(), i = s(), a = L(e.resolvedBy ? [e.resolvedBy] : []), o = e.comments.map((t, n) => /* @__PURE__ */ w(z, {
261
+ thread: e,
262
+ comment: t,
263
+ showResolveButton: n === 0
264
+ }, t.id + JSON.stringify(t.body || "{}")));
265
+ if (e.resolved && e.resolvedUpdatedAt && e.resolvedBy) {
266
+ if (!a.get(e.resolvedBy)) throw Error(`User ${e.resolvedBy} resolved thread ${e.id}, but their data could not be found.`);
267
+ let t = e.comments.findLastIndex((t) => e.resolvedUpdatedAt.getTime() > t.createdAt.getTime()) + 1;
268
+ o.splice(t, 0, /* @__PURE__ */ w(r.Comments.Comment, {
269
+ className: "bn-thread-comment",
270
+ authorInfo: e.resolvedBy && a.get(e.resolvedBy) || "loading",
271
+ timeString: e.resolvedUpdatedAt.toLocaleDateString(void 0, {
272
+ month: "short",
273
+ day: "numeric"
274
+ }),
275
+ edited: !1,
276
+ showActions: !1,
277
+ children: /* @__PURE__ */ w("div", {
278
+ className: "bn-resolved-text",
279
+ children: i.comments.sidebar.marked_as_resolved
280
+ })
281
+ }, "resolved-comment"));
282
+ }
283
+ return n && o.length > n && o.splice(1, o.length - 2, /* @__PURE__ */ w(r.Comments.ExpandSectionsPrompt, {
284
+ className: "bn-thread-expand-prompt",
285
+ children: i.comments.sidebar.more_replies(e.comments.length - 2)
286
+ }, "expand-prompt")), o;
287
+ }, V = ({ thread: e, selected: r, referenceText: i, maxCommentsBeforeCollapse: a, onFocus: c, onBlur: d, tabIndex: p }) => {
288
+ let m = t(), h = s(), g = n(v), _ = l({
289
+ trailingBlock: !1,
290
+ dictionary: {
291
+ ...h,
292
+ placeholders: { emptyDocument: h.placeholders.comment_reply }
293
+ },
294
+ schema: g.commentEditorSchema || u
295
+ }), y = f(async () => {
296
+ await g.threadStore.addComment({
297
+ comment: { body: _.document },
298
+ threadId: e.id
299
+ }), _.removeBlocks(_.document);
300
+ }, [
301
+ g,
302
+ _,
303
+ e.id
304
+ ]);
305
+ return /* @__PURE__ */ T(m.Comments.Card, {
306
+ className: "bn-thread",
307
+ headerText: i,
308
+ onFocus: c,
309
+ onBlur: d,
310
+ selected: r,
311
+ tabIndex: p,
312
+ children: [/* @__PURE__ */ w(m.Comments.CardSection, {
313
+ className: "bn-thread-comments",
314
+ children: /* @__PURE__ */ w(B, {
315
+ thread: e,
316
+ maxCommentsBeforeCollapse: r ? void 0 : a || 5
317
+ })
318
+ }), r && /* @__PURE__ */ w(m.Comments.CardSection, {
319
+ className: "bn-thread-composer",
320
+ children: /* @__PURE__ */ w(o, {
321
+ autoFocus: !1,
322
+ editable: !0,
323
+ editor: _,
324
+ actions: ({ isEmpty: e }) => e ? null : /* @__PURE__ */ w(m.Generic.Toolbar.Root, {
325
+ variant: "action-toolbar",
326
+ className: S("bn-action-toolbar", "bn-comment-actions"),
327
+ children: /* @__PURE__ */ w(m.Generic.Toolbar.Button, {
328
+ mainTooltip: h.comments.save_button_text,
329
+ variant: "compact",
330
+ isDisabled: e,
331
+ onClick: y,
332
+ children: h.comments.save_button_text
333
+ })
334
+ })
335
+ })
336
+ })]
337
+ });
338
+ };
339
+ //#endregion
340
+ //#region src/components/Comments/useThreads.ts
341
+ function H() {
342
+ let e = n(v).threadStore, t = h(void 0);
343
+ return t.current ||= e.getThreads(), _(f((n) => e.subscribe((e) => {
344
+ t.current = e, n();
345
+ }), [e]), () => t.current);
346
+ }
347
+ //#endregion
348
+ //#region src/components/Comments/FloatingThreadController.tsx
349
+ var U = /* @__PURE__ */ e({ default: () => W });
350
+ function W(e) {
351
+ let t = c(), i = n(v), o = r(v, {
352
+ editor: t,
353
+ selector: (e) => e.selectedThreadId ? {
354
+ id: e.selectedThreadId,
355
+ position: e.threadPositions.get(e.selectedThreadId)
356
+ } : void 0
357
+ }), s = H(), l = m(() => o ? s.get(o.id) : void 0, [o, s]), u = m(() => ({
358
+ ...e.floatingUIOptions,
359
+ useFloatingOptions: {
360
+ open: !!o,
361
+ onOpenChange: (e, n, r) => {
362
+ r === "escape-key" && t.focus(), e || i.selectThread(void 0);
363
+ },
364
+ placement: "bottom",
365
+ middleware: [
366
+ b(10),
367
+ x(),
368
+ y()
369
+ ],
370
+ ...e.floatingUIOptions?.useFloatingOptions
371
+ },
372
+ focusManagerProps: {
373
+ disabled: !0,
374
+ ...e.floatingUIOptions?.focusManagerProps
375
+ },
376
+ elementProps: {
377
+ style: { zIndex: 30 },
378
+ ...e.floatingUIOptions?.elementProps
379
+ }
380
+ }), [
381
+ i,
382
+ t,
383
+ e.floatingUIOptions,
384
+ o
385
+ ]), d = e.floatingThread || V;
386
+ return /* @__PURE__ */ w(a, {
387
+ position: o?.position,
388
+ ...u,
389
+ children: l && /* @__PURE__ */ w(d, {
390
+ thread: l,
391
+ selected: !0
392
+ })
393
+ });
394
+ }
395
+ //#endregion
396
+ export { B as a, L as c, V as i, U as n, z as o, H as r, I as s, W as t };
397
+
398
+ //# sourceMappingURL=FloatingThreadController-BuzLC5ea.js.map