UNPKG

@blocknote/core

Version:

A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.

3 lines (2 loc) 11.8 kB
"use strict";var A=Object.defineProperty;var y=(r,d,e)=>d in r?A(r,d,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[d]=e;var o=(r,d,e)=>y(r,typeof d!="symbol"?d+"":d,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("yjs"),g=require("uuid");function C(r){if(r&&typeof r=="object"&&"default"in r)return r;const d=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const t=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(d,e,t.get?t:{enumerable:!0,get:()=>r[e]})}}return d.default=r,Object.freeze(d)}const T=C(v);class f{}class D extends f{constructor(d,e){super(),this.userId=d,this.role=e}canCreateThread(){return!0}canAddComment(d){return!0}canUpdateComment(d){return d.userId===this.userId}canDeleteComment(d){return d.userId===this.userId||this.role==="editor"}canDeleteThread(d){return this.role==="editor"}canResolveThread(d){return!0}canUnresolveThread(d){return!0}canAddReaction(d,e){return e?!d.reactions.some(t=>t.emoji===e&&t.userIds.includes(this.userId)):!0}canDeleteReaction(d,e){return e?d.reactions.some(t=>t.emoji===e&&t.userIds.includes(this.userId)):!0}}class I{constructor(d){o(this,"auth");this.auth=d}}class E extends I{constructor(e,t,a){super(a);o(this,"addThreadToDocument");this.userId=e,this.provider=t}async createThread(e){let t=this.provider.createThread({data:e.metadata});return t=this.provider.addComment(t.id,{content:e.initialComment.body,data:{metadata:e.initialComment.metadata,userId:this.userId}}),this.tiptapThreadToThreadData(t)}async addComment(e){const t=this.provider.addComment(e.threadId,{content:e.comment.body,data:{metadata:e.comment.metadata,userId:this.userId}});return this.tiptapCommentToCommentData(t.comments[t.comments.length-1])}async updateComment(e){const t=this.provider.getThreadComment(e.threadId,e.commentId,!0);if(!t)throw new Error("Comment not found");this.provider.updateComment(e.threadId,e.commentId,{content:e.comment.body,data:{...t.data,metadata:e.comment.metadata}})}tiptapCommentToCommentData(e){var a,s,n;const t=[];for(const h of((a=e.data)==null?void 0:a.reactions)||[]){const i=t.find(m=>m.emoji===h.emoji);i?(i.userIds.push(h.userId),i.createdAt=new Date(Math.min(i.createdAt.getTime(),h.createdAt))):t.push({emoji:h.emoji,createdAt:new Date(h.createdAt),userIds:[h.userId]})}return{type:"comment",id:e.id,body:e.content,metadata:(s=e.data)==null?void 0:s.metadata,userId:(n=e.data)==null?void 0:n.userId,createdAt:new Date(e.createdAt),updatedAt:new Date(e.updatedAt),reactions:t}}tiptapThreadToThreadData(e){var t;return{type:"thread",id:e.id,comments:e.comments.map(a=>this.tiptapCommentToCommentData(a)),resolved:!!e.resolvedAt,metadata:(t=e.data)==null?void 0:t.metadata,createdAt:new Date(e.createdAt),updatedAt:new Date(e.updatedAt)}}async deleteComment(e){this.provider.deleteComment(e.threadId,e.commentId)}async deleteThread(e){this.provider.deleteThread(e.threadId)}async resolveThread(e){this.provider.updateThread(e.threadId,{resolvedAt:new Date().toISOString()})}async unresolveThread(e){this.provider.updateThread(e.threadId,{resolvedAt:null})}async addReaction(e){var a;const t=this.provider.getThreadComment(e.threadId,e.commentId,!0);if(!t)throw new Error("Comment not found");this.provider.updateComment(e.threadId,e.commentId,{data:{...t.data,reactions:[...((a=t.data)==null?void 0:a.reactions)||[],{emoji:e.emoji,createdAt:Date.now(),userId:this.userId}]}})}async deleteReaction(e){var a;const t=this.provider.getThreadComment(e.threadId,e.commentId,!0);if(!t)throw new Error("Comment not found");this.provider.updateComment(e.threadId,e.commentId,{data:{...t.data,reactions:(((a=t.data)==null?void 0:a.reactions)||[]).filter(s=>s.emoji!==e.emoji&&s.userId!==this.userId)}})}getThread(e){const t=this.provider.getThread(e);if(!t)throw new Error("Thread not found");return this.tiptapThreadToThreadData(t)}getThreads(){return new Map(this.provider.getThreads().map(e=>[e.id,this.tiptapThreadToThreadData(e)]))}subscribe(e){const t=()=>{e(this.getThreads())};return this.provider.watchThreads(t),()=>{this.provider.unwatchThreads(t)}}}function p(r){const d=new T.Map;if(d.set("id",r.id),d.set("userId",r.userId),d.set("createdAt",r.createdAt.getTime()),d.set("updatedAt",r.updatedAt.getTime()),r.deletedAt?(d.set("deletedAt",r.deletedAt.getTime()),d.set("body",void 0)):d.set("body",r.body),r.reactions.length>0)throw new Error("Reactions should be empty in commentToYMap");return d.set("reactionsByUser",new T.Map),d.set("metadata",r.metadata),d}function b(r){var t;const d=new T.Map;d.set("id",r.id),d.set("createdAt",r.createdAt.getTime()),d.set("updatedAt",r.updatedAt.getTime());const e=new T.Array;return e.push(r.comments.map(a=>p(a))),d.set("comments",e),d.set("resolved",r.resolved),d.set("resolvedUpdatedAt",(t=r.resolvedUpdatedAt)==null?void 0:t.getTime()),d.set("resolvedBy",r.resolvedBy),d.set("metadata",r.metadata),d}function j(r){return{emoji:r.get("emoji"),createdAt:new Date(r.get("createdAt")),userId:r.get("userId")}}function R(r){return[...r.values()].map(e=>j(e)).reduce((e,t)=>{const a=e.find(s=>s.emoji===t.emoji);return a?(a.userIds.push(t.userId),a.createdAt=new Date(Math.min(a.createdAt.getTime(),t.createdAt.getTime()))):e.push({emoji:t.emoji,createdAt:t.createdAt,userIds:[t.userId]}),e},[])}function u(r){return{type:"comment",id:r.get("id"),userId:r.get("userId"),createdAt:new Date(r.get("createdAt")),updatedAt:new Date(r.get("updatedAt")),deletedAt:r.get("deletedAt")?new Date(r.get("deletedAt")):void 0,reactions:R(r.get("reactionsByUser")),metadata:r.get("metadata"),body:r.get("body")}}function c(r){return{type:"thread",id:r.get("id"),createdAt:new Date(r.get("createdAt")),updatedAt:new Date(r.get("updatedAt")),comments:(r.get("comments")||[]).map(d=>u(d)),resolved:r.get("resolved"),resolvedUpdatedAt:new Date(r.get("resolvedUpdatedAt")),resolvedBy:r.get("resolvedBy"),metadata:r.get("metadata")}}class w extends I{constructor(d,e){super(e),this.threadsYMap=d}getThread(d){const e=this.threadsYMap.get(d);if(!e)throw new Error("Thread not found");return c(e)}getThreads(){const d=new Map;return this.threadsYMap.forEach((e,t)=>{d.set(t,c(e))}),d}subscribe(d){const e=()=>{d(this.getThreads())};return this.threadsYMap.observeDeep(e),()=>{this.threadsYMap.unobserveDeep(e)}}}class S extends w{constructor(e,t,a,s){super(a,s);o(this,"doRequest",async(e,t,a)=>{const s=await fetch(`${this.BASE_URL}${e}`,{method:t,body:JSON.stringify(a),headers:{"Content-Type":"application/json",...this.headers}});if(!s.ok)throw new Error(`Failed to ${t} ${e}: ${s.statusText}`);return s.json()});o(this,"addThreadToDocument",async e=>{const{threadId:t,...a}=e;return this.doRequest(`/${t}/addToDocument`,"POST",a)});o(this,"createThread",async e=>this.doRequest("","POST",e));o(this,"addComment",e=>{const{threadId:t,...a}=e;return this.doRequest(`/${t}/comments`,"POST",a)});o(this,"updateComment",e=>{const{threadId:t,commentId:a,...s}=e;return this.doRequest(`/${t}/comments/${a}`,"PUT",s)});o(this,"deleteComment",e=>{const{threadId:t,commentId:a,...s}=e;return this.doRequest(`/${t}/comments/${a}?soft=${!!s.softDelete}`,"DELETE")});o(this,"deleteThread",e=>this.doRequest(`/${e.threadId}`,"DELETE"));o(this,"resolveThread",e=>this.doRequest(`/${e.threadId}/resolve`,"POST"));o(this,"unresolveThread",e=>this.doRequest(`/${e.threadId}/unresolve`,"POST"));o(this,"addReaction",e=>{const{threadId:t,commentId:a,...s}=e;return this.doRequest(`/${t}/comments/${a}/reactions`,"POST",s)});o(this,"deleteReaction",e=>this.doRequest(`/${e.threadId}/comments/${e.commentId}/reactions/${e.emoji}`,"DELETE"));this.BASE_URL=e,this.headers=t}}class Y extends w{constructor(e,t,a){super(t,a);o(this,"transact",e=>async t=>this.threadsYMap.doc.transact(()=>e(t)));o(this,"createThread",this.transact(e=>{if(!this.auth.canCreateThread())throw new Error("Not authorized");const t=new Date,a={type:"comment",id:g.v4(),userId:this.userId,createdAt:t,updatedAt:t,reactions:[],metadata:e.initialComment.metadata,body:e.initialComment.body},s={type:"thread",id:g.v4(),createdAt:t,updatedAt:t,comments:[a],resolved:!1,metadata:e.metadata};return this.threadsYMap.set(s.id,b(s)),s}));o(this,"addThreadToDocument");o(this,"addComment",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");if(!this.auth.canAddComment(c(t)))throw new Error("Not authorized");const a=new Date,s={type:"comment",id:g.v4(),userId:this.userId,createdAt:a,updatedAt:a,deletedAt:void 0,reactions:[],metadata:e.comment.metadata,body:e.comment.body};return t.get("comments").push([p(s)]),t.set("updatedAt",new Date().getTime()),s}));o(this,"updateComment",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");const a=l(t.get("comments"),n=>n.get("id")===e.commentId);if(a===-1)throw new Error("Comment not found");const s=t.get("comments").get(a);if(!this.auth.canUpdateComment(u(s)))throw new Error("Not authorized");s.set("body",e.comment.body),s.set("updatedAt",new Date().getTime()),s.set("metadata",e.comment.metadata)}));o(this,"deleteComment",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");const a=l(t.get("comments"),n=>n.get("id")===e.commentId);if(a===-1)throw new Error("Comment not found");const s=t.get("comments").get(a);if(!this.auth.canDeleteComment(u(s)))throw new Error("Not authorized");if(s.get("deletedAt"))throw new Error("Comment already deleted");e.softDelete?(s.set("deletedAt",new Date().getTime()),s.set("body",void 0)):t.get("comments").delete(a),t.get("comments").toArray().every(n=>n.get("deletedAt"))&&(e.softDelete?t.set("deletedAt",new Date().getTime()):this.threadsYMap.delete(e.threadId)),t.set("updatedAt",new Date().getTime())}));o(this,"deleteThread",this.transact(e=>{if(!this.auth.canDeleteThread(c(this.threadsYMap.get(e.threadId))))throw new Error("Not authorized");this.threadsYMap.delete(e.threadId)}));o(this,"resolveThread",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");if(!this.auth.canResolveThread(c(t)))throw new Error("Not authorized");t.set("resolved",!0),t.set("resolvedUpdatedAt",new Date().getTime()),t.set("resolvedBy",this.userId)}));o(this,"unresolveThread",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");if(!this.auth.canUnresolveThread(c(t)))throw new Error("Not authorized");t.set("resolved",!1),t.set("resolvedUpdatedAt",new Date().getTime())}));o(this,"addReaction",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");const a=l(t.get("comments"),m=>m.get("id")===e.commentId);if(a===-1)throw new Error("Comment not found");const s=t.get("comments").get(a);if(!this.auth.canAddReaction(u(s),e.emoji))throw new Error("Not authorized");const n=new Date,h=`${this.userId}-${e.emoji}`,i=s.get("reactionsByUser");if(!i.has(h)){const m=new T.Map;m.set("emoji",e.emoji),m.set("createdAt",n.getTime()),m.set("userId",this.userId),i.set(h,m)}}));o(this,"deleteReaction",this.transact(e=>{const t=this.threadsYMap.get(e.threadId);if(!t)throw new Error("Thread not found");const a=l(t.get("comments"),i=>i.get("id")===e.commentId);if(a===-1)throw new Error("Comment not found");const s=t.get("comments").get(a);if(!this.auth.canDeleteReaction(u(s),e.emoji))throw new Error("Not authorized");const n=`${this.userId}-${e.emoji}`;s.get("reactionsByUser").delete(n)}));this.userId=e}}function l(r,d){for(let e=0;e<r.length;e++)if(d(r.get(e)))return e;return-1}exports.DefaultThreadStoreAuth=D;exports.RESTYjsThreadStore=S;exports.ThreadStore=I;exports.ThreadStoreAuth=f;exports.TiptapThreadStore=E;exports.YjsThreadStore=Y;exports.YjsThreadStoreBase=w; //# sourceMappingURL=comments.cjs.map