@brainfish-ai/components 0.27.1 → 0.28.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.
@@ -1,18 +1,18 @@
1
- import*as e from"react";import t,{useCallback as n,useEffect as r,useRef as a,useState as l,useImperativeHandle as s}from"react";import{u as o,E as i,b as c,R as m}from"../chunks/review-list.Cn5bw-lP.js";import d from"html-react-parser";import{CaretDown as u,CaretUp as f,Lightbulb as g,Backspace as p,CheckCircle as h,HandsClapping as b}from"@phosphor-icons/react";import{Card as E,CardHeader as A,CardTitle as v,CardContent as x}from"../components/ui/card.js";import{ScrollArea as N}from"../components/ui/scroll-area.js";import{Spinner as k}from"../components/ui/spinner.js";import{B as w,a as S}from"../chunks/button.D_2SonNs.js";import{Tooltip as y,TooltipTrigger as C,TooltipContent as j}from"../components/ui/tooltip.js";import{Popover as R,PopoverTrigger as I,PopoverContent as L}from"../components/ui/popover.js";import{DropdownMenu as z,DropdownMenuTrigger as B,DropdownMenuContent as D,DropdownMenuItem as O}from"../components/ui/dropdown-menu.js";import{ButtonGroup as P}from"../components/ui/button-group.js";import{c as T}from"../chunks/utils.C6Qu-kwd.js";import{S as F}from"../chunks/status-badge.BLB0pWDn.js";import '../knowledge-review.css';function $({fetchDiffForItem:e}){const{selectedItem:t,setLoadedDiffDoc:a,setLoadingDiff:l}=o(),s=n(async(t,n)=>{l(!0),a(null);try{const r=await e(t);if(n.aborted)return;a(r)}catch(r){if(n.aborted)return;console.error("Failed to fetch diff:",r),a(null)}finally{n.aborted||l(!1)}},[e,a,l]),i=t?.id;return r(()=>{if(!i)return a(null),void l(!1);const e=new AbortController;return s(i,e.signal),()=>{e.abort()}},[i,s]),null}const _="Why is Brainfish suggesting this?",q=e.forwardRef(function({title:t,isNew:n,suggestionsCount:r,sourceIcon:a,sourceDescription:l,currentArticleIndex:s,totalArticles:o,displayTotalArticles:c,showActionButtons:m=!0,onNextArticle:d,onPreviousArticle:b,onRejectAllSuggestions:E,onAcceptAllSuggestions:A,onAcceptAndPublish:v,breadcrumb:x,onOpenArticleLink:N,onSourceLinkClick:k,suggestionReasonBody:$,className:q,...M},W){const G=e.useRef(null),[K,H]=e.useState(!1),J=o>0&&s<o-1,Q=s>0,U=0===o?0:s+1,V=c??o,X=V>0;let Y;return n?Y=/* @__PURE__ */e.createElement(F,{variant:"success"},"New"):r&&(Y=/* @__PURE__ */e.createElement(i,{count:r})),/* @__PURE__ */e.createElement("div",{ref:W,className:T("flex flex-col gap-4",q),...M},/* @__PURE__ */e.createElement("div",{className:"flex justify-between items-center"},/* @__PURE__ */e.createElement("h1",{className:"heading-lg"},t,N&&x&&/* @__PURE__ */e.createElement(w,{variant:"link",size:"sm",onClick:N,"aria-label":"Open article",className:"block px-0 text-subtle text-xs"},x)),/* @__PURE__ */e.createElement("div",{className:"flex items-center"},/* @__PURE__ */e.createElement("p",{className:"text-xs text-foreground"},/* @__PURE__ */e.createElement("span",{"aria-hidden":"true"},X?`${U}/${V}`:"0"),/* @__PURE__ */e.createElement("span",{className:"sr-only","aria-live":"polite"},X?`Article ${U} of ${V}`:"No articles")),/* @__PURE__ */e.createElement(y,null,/* @__PURE__ */e.createElement(C,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",disabled:!J,onClick:d,"aria-label":"Go to next article"},
2
- /* @__PURE__ */e.createElement(u,{"aria-hidden":"true"}))),/* @__PURE__ */e.createElement(j,{side:"bottom",bgColor:"--bfc-foreground",className:"text-background"},"Next Article")),/* @__PURE__ */e.createElement(y,null,/* @__PURE__ */e.createElement(C,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",disabled:!Q,onClick:b,"aria-label":"Go to previous article"},
3
- /* @__PURE__ */e.createElement(f,{"aria-hidden":"true"}))),/* @__PURE__ */e.createElement(j,{side:"top",bgColor:"--bfc-foreground",className:"text-background"},"Previous Article")))),/* @__PURE__ */e.createElement("div",{className:"flex-1 px-2 pb-2 flex justify-between items-center"},/* @__PURE__ */e.createElement("div",{className:"flex items-center gap-2"},Y,l&&(k?/* @__PURE__ */e.createElement(w,{variant:"link",onClick:k,"aria-label":"Open source",className:"[&_svg]:size-4 text-xs text-subtle gap-1"},a&&/* @__PURE__ */e.createElement("span",{className:"shrink-0 flex items-center"},a),
4
- /* @__PURE__ */e.createElement("span",null,l)):/* @__PURE__ */e.createElement("span",{className:"[&_svg]:size-4 flex items-center gap-1 text-xs text-subtle"},a&&/* @__PURE__ */e.createElement("span",{className:"shrink-0 flex items-center"},a),l))),m&&/* @__PURE__ */e.createElement(P,{orientation:"horizontal",rounded:!1,"aria-label":"Suggestion actions",className:"gap-1"},$&&/* @__PURE__ */e.createElement(R,{open:K,onOpenChange:H},/* @__PURE__ */e.createElement(I,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost","aria-label":_},/* @__PURE__ */e.createElement(g,{"aria-hidden":"true"}),"Why")),/* @__PURE__ */e.createElement(L,{align:"start",side:"bottom",className:"z-above-modal shadow-md dark:shadow-md-invert border-dark-300"},
5
- /* @__PURE__ */e.createElement("div",{className:"font-bold text-sm"},_),
6
- /* @__PURE__ */e.createElement("div",{className:"text-sm text-subtle mt-1"},$))),/* @__PURE__ */e.createElement(w,{variant:"ghost",onClick:E},/* @__PURE__ */e.createElement(p,{"aria-hidden":"true"}),"Reject"),v?/* @__PURE__ */e.createElement(z,null,/* @__PURE__ */e.createElement("div",{ref:G,className:T("flex items-center rounded border border-border bg-primary",S)},
1
+ import*as e from"react";import t,{useCallback as n,useEffect as r,useRef as s,useState as a,useImperativeHandle as l}from"react";import{u as o,E as i,b as c,R as m}from"../chunks/suggestion-card.C9UnMOjp.js";import '../knowledge-review.css';export{S as SuggestionCard}from"../chunks/suggestion-card.C9UnMOjp.js";import d from"html-react-parser";import{CaretDown as u,CaretUp as g,Lightbulb as f,Backspace as p,CheckCircle as h,HandsClapping as b}from"@phosphor-icons/react";import{Card as E,CardHeader as A,CardTitle as x,CardContent as v}from"../components/ui/card.js";import{ScrollArea as N}from"../components/ui/scroll-area.js";import{Spinner as k}from"../components/ui/spinner.js";import{B as w,a as y}from"../chunks/button.D_2SonNs.js";import{Tooltip as C,TooltipTrigger as j,TooltipContent as R}from"../components/ui/tooltip.js";import{Popover as I,PopoverTrigger as L,PopoverContent as z}from"../components/ui/popover.js";import{DropdownMenu as B,DropdownMenuTrigger as D,DropdownMenuContent as O,DropdownMenuItem as P}from"../components/ui/dropdown-menu.js";import{ButtonGroup as T}from"../components/ui/button-group.js";import{c as F}from"../chunks/utils.C6Qu-kwd.js";import{S as $}from"../chunks/status-badge.BLB0pWDn.js";function _({fetchDiffForItem:e}){const{selectedItem:t,setLoadedDiffDoc:s,setLoadingDiff:a}=o(),l=n(async(t,n)=>{a(!0),s(null);try{const r=await e(t);if(n.aborted)return;s(r)}catch(r){if(n.aborted)return;console.error("Failed to fetch diff:",r),s(null)}finally{n.aborted||a(!1)}},[e,s,a]),i=t?.id;return r(()=>{if(!i)return s(null),void a(!1);const e=new AbortController;return l(i,e.signal),()=>{e.abort()}},[i,l]),null}const q="Why is Brainfish suggesting this?",M=e.forwardRef(function({title:t,isNew:n,suggestionsCount:r,sourceIcon:s,sourceDescription:a,currentArticleIndex:l,totalArticles:o,displayTotalArticles:c,showActionButtons:m=!0,onNextArticle:d,onPreviousArticle:b,onRejectAllSuggestions:E,onAcceptAllSuggestions:A,onAcceptAndPublish:x,breadcrumb:v,onOpenArticleLink:N,onSourceLinkClick:k,suggestionReasonBody:S,className:_,...M},W){const G=e.useRef(null),[K,H]=e.useState(!1),J=o>0&&l<o-1,Q=l>0,U=0===o?0:l+1,V=c??o,X=V>0;let Y;return n?Y=/* @__PURE__ */e.createElement($,{variant:"success"},"New"):r&&(Y=/* @__PURE__ */e.createElement(i,{count:r})),/* @__PURE__ */e.createElement("div",{ref:W,className:F("flex flex-col gap-4",_),...M},/* @__PURE__ */e.createElement("div",{className:"flex justify-between items-center"},/* @__PURE__ */e.createElement("h1",{className:"heading-lg"},t,N&&v&&/* @__PURE__ */e.createElement(w,{variant:"link",size:"sm",onClick:N,"aria-label":"Open article",className:"block px-0 text-subtle text-xs"},v)),/* @__PURE__ */e.createElement("div",{className:"flex items-center"},/* @__PURE__ */e.createElement("p",{className:"text-xs text-foreground"},/* @__PURE__ */e.createElement("span",{"aria-hidden":"true"},X?`${U}/${V}`:"0"),/* @__PURE__ */e.createElement("span",{className:"sr-only","aria-live":"polite"},X?`Article ${U} of ${V}`:"No articles")),/* @__PURE__ */e.createElement(C,null,/* @__PURE__ */e.createElement(j,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",disabled:!J,onClick:d,"aria-label":"Go to next article"},
2
+ /* @__PURE__ */e.createElement(u,{"aria-hidden":"true"}))),/* @__PURE__ */e.createElement(R,{side:"bottom",bgColor:"--bfc-foreground",className:"text-background"},"Next Article")),/* @__PURE__ */e.createElement(C,null,/* @__PURE__ */e.createElement(j,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",disabled:!Q,onClick:b,"aria-label":"Go to previous article"},
3
+ /* @__PURE__ */e.createElement(g,{"aria-hidden":"true"}))),/* @__PURE__ */e.createElement(R,{side:"top",bgColor:"--bfc-foreground",className:"text-background"},"Previous Article")))),/* @__PURE__ */e.createElement("div",{className:"flex-1 px-2 pb-2 flex justify-between items-center"},/* @__PURE__ */e.createElement("div",{className:"flex items-center gap-2"},Y,a&&(k?/* @__PURE__ */e.createElement(w,{variant:"link",onClick:k,"aria-label":"Open source",className:"[&_svg]:size-4 text-xs text-subtle gap-1"},s&&/* @__PURE__ */e.createElement("span",{className:"shrink-0 flex items-center"},s),
4
+ /* @__PURE__ */e.createElement("span",null,a)):/* @__PURE__ */e.createElement("span",{className:"[&_svg]:size-4 flex items-center gap-1 text-xs text-subtle"},s&&/* @__PURE__ */e.createElement("span",{className:"shrink-0 flex items-center"},s),a))),m&&/* @__PURE__ */e.createElement(T,{orientation:"horizontal",rounded:!1,"aria-label":"Suggestion actions",className:"gap-1"},S&&/* @__PURE__ */e.createElement(I,{open:K,onOpenChange:H},/* @__PURE__ */e.createElement(L,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost","aria-label":q},/* @__PURE__ */e.createElement(f,{"aria-hidden":"true"}),"Why")),/* @__PURE__ */e.createElement(z,{align:"start",side:"bottom",className:"z-above-modal shadow-md dark:shadow-md-invert border-dark-300"},
5
+ /* @__PURE__ */e.createElement("div",{className:"font-bold text-sm"},q),
6
+ /* @__PURE__ */e.createElement("div",{className:"text-sm text-subtle mt-1"},S))),/* @__PURE__ */e.createElement(w,{variant:"ghost",onClick:E},/* @__PURE__ */e.createElement(p,{"aria-hidden":"true"}),"Reject"),x?/* @__PURE__ */e.createElement(B,null,/* @__PURE__ */e.createElement("div",{ref:G,className:F("flex items-center rounded border border-border bg-primary",y)},
7
7
  /* @__PURE__ */e.createElement(w,{variant:"ghost",className:"gap-1 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200",onClick:A},
8
8
  /* @__PURE__ */e.createElement(h,{"aria-hidden":"true"}),"Accept as draft"),
9
9
  /* @__PURE__ */e.createElement("span",{className:"h-full w-px self-stretch bg-foreground","aria-hidden":"true"}),
10
- /* @__PURE__ */e.createElement(B,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",className:"size-9 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200","aria-label":"More accept options"},
11
- /* @__PURE__ */e.createElement(u,{className:"size-4","aria-hidden":"true"})))),/* @__PURE__ */e.createElement(D,{align:"end",className:"z-above-modal border-none shadow-md dark:shadow-md-invert"},/* @__PURE__ */e.createElement(O,{onClick:v},/* @__PURE__ */e.createElement(h,{"aria-hidden":"true"}),"Accept & publish"))):/* @__PURE__ */e.createElement(w,{variant:"default",elevation:"shadow",onClick:A},/* @__PURE__ */e.createElement(h,{"aria-hidden":"true"}),"Accept as draft"))))});function M(e){const t=e.querySelectorAll("del + ins"),n=e.querySelectorAll("ins:not(del + ins)"),r=e.querySelectorAll("del"),a=Array.from(r).filter(e=>"INS"!==e.nextElementSibling?.tagName);return t.length+n.length+a.length}function W({diffTitle:e,items:s,isLoading:i,totalItemsCount:c,showActionButtons:m=!0,children:u,sourceIcon:f,sourceDescription:g}){const{selectedItem:p,setSelectedItem:h,loadedDiffDoc:w,loadingDiff:S,onApproveAllSuggestions:y,onRejectAllSuggestions:C,onAcceptAndPublish:j,onOpenArticleLink:R,onSourceLinkClick:I,breadcrumb:L,suggestionReasonBody:z}=o(),B=s.length>0,D=i??!B,O=D&&!B,P=!D&&!B,T=S?"":d(w?.diffTitle??e??""),F=S?/* @__PURE__ */t.createElement("div",{className:"text-muted-foreground"},"Loading diff…"):w?.diffContent,$=S?0:(_=w?.diffTitle??e)&&"undefined"!=typeof DOMParser?M((new DOMParser).parseFromString(_,"text/html")):0;var _;const W=a(null),[G,K]=l(0);r(()=>{if(S||!w)return void K(0);const e=W.current;if(!e)return;const t=requestAnimationFrame(()=>{var t;K((t=e)?M(t):0)});return()=>cancelAnimationFrame(t)},[S,w]);const H=$+G,J=s.length,Q=c??J,U=p?Math.max(0,s.findIndex(e=>e.id===p.id)):0,V=n(()=>{U<J-1&&h(s[U+1]??null)},[U,s,h,J]),X=n(()=>{U>0&&h(s[U-1]??null)},[U,s,h]),Y=p?.icon??f,Z=p?.description??g;/* @__PURE__ */
12
- return t.createElement(E,{className:"py-6 pl-4","data-name":"knowledge-reviews"},/* @__PURE__ */t.createElement(N,{className:"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8"},/* @__PURE__ */t.createElement(A,{className:"p-0"},B&&/* @__PURE__ */t.createElement(v,{className:"border-b border-dark-300 mb-6 pb-2 font-normal"},/* @__PURE__ */t.createElement(q,{title:T,isNew:w?.isNew??!1,suggestionsCount:H,sourceIcon:Y,sourceDescription:Z,currentArticleIndex:U,totalArticles:J,displayTotalArticles:Q,showActionButtons:m,onNextArticle:V,onPreviousArticle:X,onRejectAllSuggestions:C,onAcceptAllSuggestions:y,onAcceptAndPublish:j,onOpenArticleLink:R,onSourceLinkClick:I,breadcrumb:L,suggestionReasonBody:z}))),/* @__PURE__ */t.createElement(x,{className:"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16"},/* @__PURE__ */t.createElement("div",{"aria-hidden":"true",className:"sr-only",hidden:!0},u),O?/* @__PURE__ */t.createElement("div",{className:"flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground"},/* @__PURE__ */t.createElement(k,{className:"size-8"}),/* @__PURE__ */t.createElement("p",{className:"text-base font-medium"},"Loading suggestions...")):P?/* @__PURE__ */t.createElement("div",{className:"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]"},/* @__PURE__ */t.createElement(b,{className:"text-muted-foreground",size:32,weight:"fill"}),/* @__PURE__ */t.createElement("p",{className:"text-base font-medium text-foreground"},"All up to date. Well done, mate.")):/* @__PURE__ */t.createElement("div",{ref:W},F))))}const G="--knowledge-review-scroll-height",K=t.forwardRef(function({diffTitle:e="Knowledge Review",children:n,items:l,isLoading:i,totalItemsCount:c,showActionButtons:d=!0,className:u,onApproveAllSuggestions:f,onRejectAllSuggestions:g,onOpenArticleLink:p,onAcceptAndPublish:h,onSourceLinkClick:b,breadcrumb:A,sourceIcon:v,sourceDescription:w,suggestionReasonBody:S,...y},C){const j=a(null),{selectedItem:R,setSelectedItem:I}=o();s(C,()=>({selectedItem:R,setSelectedItem:I}),[R,I]),r(()=>{const e=j.current;if(!e)return;const t=()=>{const{height:t}=e.getBoundingClientRect();e.style.setProperty(G,`${t}px`)};if(t(),"function"!=typeof ResizeObserver)return;const n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[]);const L=i??0===l.length,z=L&&0===l.length;/* @__PURE__ */
13
- return t.createElement(E,{className:T("h-full",u)},/* @__PURE__ */t.createElement(x,{className:"p-4 lg:p-8 h-full"},/* @__PURE__ */t.createElement("div",{ref:j,className:"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full",style:{[G]:"100px"},...y},
14
- /* @__PURE__ */t.createElement(N,{className:"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden"},z?/* @__PURE__ */t.createElement("div",{className:"flex h-full min-h-96 items-center justify-center text-muted-foreground"},/* @__PURE__ */t.createElement(k,{className:"size-6"})):/* @__PURE__ */t.createElement(m,{items:l})),
15
- /* @__PURE__ */t.createElement(W,{diffTitle:e,items:l,isLoading:L,totalItemsCount:c,showActionButtons:d,sourceIcon:v,sourceDescription:w},n))))}),H=t.forwardRef(function(e,n){const{items:r,onApproveAllSuggestions:a,onRejectAllSuggestions:l,onAcceptAndPublish:s,onOpenArticleLink:o,onSourceLinkClick:i,breadcrumb:m,suggestionReasonBody:d}=e;/* @__PURE__ */
16
- return t.createElement(c,{defaultSelectedItem:r.find(e=>e.isSelected)??null,onApproveAllSuggestions:a,onRejectAllSuggestions:l,onAcceptAndPublish:s,onOpenArticleLink:o,onSourceLinkClick:i,breadcrumb:m,suggestionReasonBody:d},
17
- /* @__PURE__ */t.createElement(K,{...e,ref:n}))});export{$ as KnowledgeReviewDiffLoader,W as KnowledgeReviewPanel,H as KnowledgeReviewScene,c as ReviewsSelectionProvider,o as useReviewsSelection};
10
+ /* @__PURE__ */e.createElement(D,{asChild:!0},/* @__PURE__ */e.createElement(w,{variant:"ghost",size:"icon",className:"size-9 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200","aria-label":"More accept options"},
11
+ /* @__PURE__ */e.createElement(u,{className:"size-4","aria-hidden":"true"})))),/* @__PURE__ */e.createElement(O,{align:"end",className:"z-above-modal border-none shadow-md dark:shadow-md-invert"},/* @__PURE__ */e.createElement(P,{onClick:x},/* @__PURE__ */e.createElement(h,{"aria-hidden":"true"}),"Accept & publish"))):/* @__PURE__ */e.createElement(w,{variant:"default",elevation:"shadow",onClick:A},/* @__PURE__ */e.createElement(h,{"aria-hidden":"true"}),"Accept as draft"))))});function W(e){const t=e.querySelectorAll("del + ins"),n=e.querySelectorAll("ins:not(del + ins)"),r=e.querySelectorAll("del"),s=Array.from(r).filter(e=>"INS"!==e.nextElementSibling?.tagName);return t.length+n.length+s.length}function G({diffTitle:e,items:l,isLoading:i,totalItemsCount:c,showActionButtons:m=!0,children:u,sourceIcon:g,sourceDescription:f}){const{selectedItem:p,setSelectedItem:h,loadedDiffDoc:w,loadingDiff:S,onApproveAllSuggestions:y,onRejectAllSuggestions:C,onAcceptAndPublish:j,onOpenArticleLink:R,onSourceLinkClick:I,breadcrumb:L,suggestionReasonBody:z}=o(),B=l.length>0,D=i??!B,O=D&&!B,P=!D&&!B,T=S?"":d(w?.diffTitle??e??""),F=S?/* @__PURE__ */t.createElement("div",{className:"text-muted-foreground"},"Loading diff…"):w?.diffContent,$=S?0:(_=w?.diffTitle??e)&&"undefined"!=typeof DOMParser?W((new DOMParser).parseFromString(_,"text/html")):0;var _;const q=s(null),[G,K]=a(0);r(()=>{if(S||!w)return void K(0);const e=q.current;if(!e)return;const t=requestAnimationFrame(()=>{var t;K((t=e)?W(t):0)});return()=>cancelAnimationFrame(t)},[S,w]);const H=$+G,J=l.length,Q=c??J,U=p?Math.max(0,l.findIndex(e=>e.id===p.id)):0,V=n(()=>{U<J-1&&h(l[U+1]??null)},[U,l,h,J]),X=n(()=>{U>0&&h(l[U-1]??null)},[U,l,h]),Y=p?.icon??g,Z=p?.description??f;/* @__PURE__ */
12
+ return t.createElement(E,{className:"py-6 pl-4","data-name":"knowledge-reviews"},/* @__PURE__ */t.createElement(N,{className:"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8"},/* @__PURE__ */t.createElement(A,{className:"p-0"},B&&/* @__PURE__ */t.createElement(x,{className:"border-b border-dark-300 mb-6 pb-2 font-normal"},/* @__PURE__ */t.createElement(M,{title:T,isNew:w?.isNew??!1,suggestionsCount:H,sourceIcon:Y,sourceDescription:Z,currentArticleIndex:U,totalArticles:J,displayTotalArticles:Q,showActionButtons:m,onNextArticle:V,onPreviousArticle:X,onRejectAllSuggestions:C,onAcceptAllSuggestions:y,onAcceptAndPublish:j,onOpenArticleLink:R,onSourceLinkClick:I,breadcrumb:L,suggestionReasonBody:z}))),/* @__PURE__ */t.createElement(v,{className:"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16"},/* @__PURE__ */t.createElement("div",{"aria-hidden":"true",className:"sr-only",hidden:!0},u),O?/* @__PURE__ */t.createElement("div",{className:"flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground"},/* @__PURE__ */t.createElement(k,{className:"size-8"}),/* @__PURE__ */t.createElement("p",{className:"text-base font-medium"},"Loading suggestions...")):P?/* @__PURE__ */t.createElement("div",{className:"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]"},/* @__PURE__ */t.createElement(b,{className:"text-muted-foreground",size:32,weight:"fill"}),/* @__PURE__ */t.createElement("p",{className:"text-base font-medium text-foreground"},"All up to date. Well done, mate.")):/* @__PURE__ */t.createElement("div",{ref:q},F))))}const K="--knowledge-review-scroll-height",H=t.forwardRef(function({diffTitle:e="Knowledge Review",children:n,items:a,isLoading:i,totalItemsCount:c,showActionButtons:d=!0,className:u,onApproveAllSuggestions:g,onRejectAllSuggestions:f,onOpenArticleLink:p,onAcceptAndPublish:h,onSourceLinkClick:b,breadcrumb:A,sourceIcon:x,sourceDescription:w,suggestionReasonBody:S,...y},C){const j=s(null),{selectedItem:R,setSelectedItem:I}=o();l(C,()=>({selectedItem:R,setSelectedItem:I}),[R,I]),r(()=>{const e=j.current;if(!e)return;const t=()=>{const{height:t}=e.getBoundingClientRect();e.style.setProperty(K,`${t}px`)};if(t(),"function"!=typeof ResizeObserver)return;const n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[]);const L=i??0===a.length,z=L&&0===a.length;/* @__PURE__ */
13
+ return t.createElement(E,{className:F("h-full",u)},/* @__PURE__ */t.createElement(v,{className:"p-4 lg:p-8 h-full"},/* @__PURE__ */t.createElement("div",{ref:j,className:"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full",style:{[K]:"100px"},...y},
14
+ /* @__PURE__ */t.createElement(N,{className:"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden"},z?/* @__PURE__ */t.createElement("div",{className:"flex h-full min-h-96 items-center justify-center text-muted-foreground"},/* @__PURE__ */t.createElement(k,{className:"size-6"})):/* @__PURE__ */t.createElement(m,{items:a})),
15
+ /* @__PURE__ */t.createElement(G,{diffTitle:e,items:a,isLoading:L,totalItemsCount:c,showActionButtons:d,sourceIcon:x,sourceDescription:w},n))))}),J=t.forwardRef(function(e,n){const{items:r,onApproveAllSuggestions:s,onRejectAllSuggestions:a,onAcceptAndPublish:l,onOpenArticleLink:o,onSourceLinkClick:i,breadcrumb:m,suggestionReasonBody:d}=e;/* @__PURE__ */
16
+ return t.createElement(c,{defaultSelectedItem:r.find(e=>e.isSelected)??null,onApproveAllSuggestions:s,onRejectAllSuggestions:a,onAcceptAndPublish:l,onOpenArticleLink:o,onSourceLinkClick:i,breadcrumb:m,suggestionReasonBody:d},
17
+ /* @__PURE__ */t.createElement(H,{...e,ref:n}))});export{_ as KnowledgeReviewDiffLoader,G as KnowledgeReviewPanel,J as KnowledgeReviewScene,c as ReviewsSelectionProvider,o as useReviewsSelection};
18
18
  //# sourceMappingURL=knowledge-review.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"knowledge-review.js","sources":["../../../src/scenes/knowledge-review/diff-loader.tsx","../../../src/scenes/knowledge-review/suggestions-header/suggestions-header.tsx","../../../src/lib/countSuggestions.ts","../../../src/scenes/knowledge-review/knowledge-review-panel.tsx","../../../src/scenes/knowledge-review/scene.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport type { LoadedDiffDoc } from './context';\nimport { useReviewsSelection } from './context';\n\nexport type KnowledgeReviewDiffLoaderProps = {\n /** Called when selectedItem changes. Return diff payload or null. */\n fetchDiffForItem: (itemId: string) => Promise<LoadedDiffDoc | null>;\n};\n\n/**\n * Listens to selectedItem from context and fetches diff via the provided callback.\n * Owns loading state and context updates; host (Storybook or Platform) supplies fetch logic.\n */\nexport function KnowledgeReviewDiffLoader({ fetchDiffForItem }: KnowledgeReviewDiffLoaderProps) {\n const { selectedItem, setLoadedDiffDoc, setLoadingDiff } = useReviewsSelection();\n\n const loadDiffForItem = useCallback(\n async (itemId: string, signal: AbortSignal) => {\n setLoadingDiff(true);\n setLoadedDiffDoc(null);\n\n try {\n const doc = await fetchDiffForItem(itemId);\n if (signal.aborted) return;\n setLoadedDiffDoc(doc);\n } catch (error) {\n if (signal.aborted) return;\n console.error('Failed to fetch diff:', error);\n setLoadedDiffDoc(null);\n } finally {\n if (!signal.aborted) {\n setLoadingDiff(false);\n }\n }\n },\n [fetchDiffForItem, setLoadedDiffDoc, setLoadingDiff],\n );\n\n const selectedId = selectedItem?.id;\n\n useEffect(() => {\n if (!selectedId) {\n setLoadedDiffDoc(null);\n setLoadingDiff(false);\n\n return;\n }\n\n const abortController = new AbortController();\n void loadDiffForItem(selectedId, abortController.signal);\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedId, loadDiffForItem]);\n\n return null;\n}\n","import { CaretDown, CaretUp, Backspace, CheckCircle, Lightbulb } from '@phosphor-icons/react';\nimport * as React from 'react';\n\nimport { EditCount } from '../review-list/edit-count';\n\nimport { Button } from '@/components/ui/button';\nimport { brandShadowEffect } from '@/lib/styles';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { ButtonGroup } from '@/components/ui/button-group';\nimport { cn } from '@/lib/utils';\nimport { StatusBadge } from '@/components/convos/status-badge';\n\nexport interface SuggestionsHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n title: React.ReactNode;\n isNew: boolean;\n suggestionsCount: number;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n currentArticleIndex: number;\n totalArticles: number;\n displayTotalArticles?: number;\n showActionButtons?: boolean;\n onNextArticle: () => void;\n onPreviousArticle: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAllSuggestions: () => void;\n onAcceptAndPublish?: () => void;\n breadcrumb?: string;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n suggestionReasonBody?: string;\n}\n\nexport const REASON_TITLE = 'Why is Brainfish suggesting this?';\n\nexport const SuggestionsHeader = React.forwardRef<HTMLDivElement, SuggestionsHeaderProps>(function SuggestionsHeader(\n {\n title,\n isNew,\n suggestionsCount,\n sourceIcon,\n sourceDescription,\n currentArticleIndex,\n totalArticles,\n displayTotalArticles,\n showActionButtons = true,\n onNextArticle,\n onPreviousArticle,\n onRejectAllSuggestions,\n onAcceptAllSuggestions,\n onAcceptAndPublish,\n breadcrumb,\n onOpenArticleLink,\n onSourceLinkClick,\n suggestionReasonBody,\n className,\n ...props\n },\n ref,\n) {\n const splitButtonRef = React.useRef<HTMLDivElement>(null);\n const [whyOpen, setWhyOpen] = React.useState(false);\n const hasNextArticle = totalArticles > 0 && currentArticleIndex < totalArticles - 1;\n const hasPreviousArticle = currentArticleIndex > 0;\n const currentArticle = totalArticles === 0 ? 0 : currentArticleIndex + 1;\n const totalArticlesForDisplay = displayTotalArticles ?? totalArticles;\n const hasDisplayArticles = totalArticlesForDisplay > 0;\n\n let status: React.ReactNode | undefined;\n if (isNew) {\n status = <StatusBadge variant=\"success\">New</StatusBadge>;\n } else if (suggestionsCount) {\n status = <EditCount count={suggestionsCount} />;\n }\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-4', className)} {...props}>\n {/* Header + Navigation */}\n <div className=\"flex justify-between items-center\">\n <h1 className=\"heading-lg\">\n {title}\n {/* Breadcrumbs */}\n {onOpenArticleLink && breadcrumb && (\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={onOpenArticleLink}\n aria-label=\"Open article\"\n className=\"block px-0 text-subtle text-xs\"\n >\n {breadcrumb}\n </Button>\n )}\n </h1>\n {/* up/down carets */}\n <div className=\"flex items-center\">\n <p className=\"text-xs text-foreground\">\n <span aria-hidden=\"true\">{hasDisplayArticles ? `${currentArticle}/${totalArticlesForDisplay}` : '0'}</span>\n <span className=\"sr-only\" aria-live=\"polite\">\n {hasDisplayArticles ? `Article ${currentArticle} of ${totalArticlesForDisplay}` : 'No articles'}\n </span>\n </p>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasNextArticle}\n onClick={onNextArticle}\n aria-label=\"Go to next article\"\n >\n <CaretDown aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" bgColor=\"--bfc-foreground\" className=\"text-background\">\n Next Article\n </TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasPreviousArticle}\n onClick={onPreviousArticle}\n aria-label=\"Go to previous article\"\n >\n <CaretUp aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" bgColor=\"--bfc-foreground\" className=\"text-background\">\n Previous Article\n </TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Status, Source + Actions */}\n <div className=\"flex-1 px-2 pb-2 flex justify-between items-center\">\n <div className=\"flex items-center gap-2\">\n {status}\n {sourceDescription &&\n (onSourceLinkClick ? (\n <Button\n variant=\"link\"\n onClick={onSourceLinkClick}\n aria-label=\"Open source\"\n className=\"[&_svg]:size-4 text-xs text-subtle gap-1\"\n >\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n <span>{sourceDescription}</span>\n </Button>\n ) : (\n <span className=\"[&_svg]:size-4 flex items-center gap-1 text-xs text-subtle\">\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n {sourceDescription}\n </span>\n ))}\n </div>\n {showActionButtons && (\n <ButtonGroup orientation=\"horizontal\" rounded={false} aria-label=\"Suggestion actions\" className=\"gap-1\">\n {suggestionReasonBody && (\n <Popover open={whyOpen} onOpenChange={setWhyOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" aria-label={REASON_TITLE}>\n <Lightbulb aria-hidden=\"true\" />\n Why\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n side=\"bottom\"\n className=\"z-above-modal shadow-md dark:shadow-md-invert border-dark-300\"\n >\n <div className=\"font-bold text-sm\">{REASON_TITLE}</div>\n <div className=\"text-sm text-subtle mt-1\">{suggestionReasonBody}</div>\n </PopoverContent>\n </Popover>\n )}\n <Button variant=\"ghost\" onClick={onRejectAllSuggestions}>\n <Backspace aria-hidden=\"true\" />\n Reject\n </Button>\n {onAcceptAndPublish ? (\n <DropdownMenu>\n <div\n ref={splitButtonRef}\n className={cn('flex items-center rounded border border-border bg-primary', brandShadowEffect)}\n >\n <Button\n variant=\"ghost\"\n className=\"gap-1 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200\"\n onClick={onAcceptAllSuggestions}\n >\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n <span className=\"h-full w-px self-stretch bg-foreground\" aria-hidden=\"true\" />\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200\"\n aria-label=\"More accept options\"\n >\n <CaretDown className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n </div>\n <DropdownMenuContent align=\"end\" className=\"z-above-modal border-none shadow-md dark:shadow-md-invert\">\n <DropdownMenuItem onClick={onAcceptAndPublish}>\n <CheckCircle aria-hidden=\"true\" />\n Accept & publish\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : (\n <Button variant=\"default\" elevation=\"shadow\" onClick={onAcceptAllSuggestions}>\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n )}\n </ButtonGroup>\n )}\n </div>\n </div>\n );\n});\n","function countSuggestionsInRoot(root: Document | Element): number {\n const adjacentPairs = root.querySelectorAll('del + ins');\n const standaloneIns = root.querySelectorAll('ins:not(del + ins)');\n const allDel = root.querySelectorAll('del');\n const standaloneDel = Array.from(allDel).filter((del) => del.nextElementSibling?.tagName !== 'INS');\n\n return adjacentPairs.length + standaloneIns.length + standaloneDel.length;\n}\n\n/** Count suggestions in an HTML string (for title or raw HTML content). */\nexport const countSuggestions = (htmlString: string) => {\n if (!htmlString || typeof DOMParser === 'undefined') {\n return 0;\n }\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, 'text/html');\n\n return countSuggestionsInRoot(doc);\n};\n\n/** Count suggestions inside a DOM element (for rendered ReactNode body content). */\nexport const countSuggestionsInElement = (element: Element | null) => {\n if (!element) return 0;\n\n return countSuggestionsInRoot(element);\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport parse from 'html-react-parser';\nimport { HandsClapping } from '@phosphor-icons/react';\n\nimport { useReviewsSelection } from './context';\nimport { SuggestionsHeader } from './suggestions-header';\nimport type { ReviewListItemProps } from './review-list';\n\nimport { countSuggestions, countSuggestionsInElement } from '@/lib/countSuggestions';\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport type KnowledgeReviewPanelProps = {\n diffTitle: string;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n totalItemsCount?: number;\n showActionButtons?: boolean;\n children?: React.ReactNode;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\n/**\n * Panel that shows the selected diff (title + content), suggestion count, and article nav.\n * Must be used inside ReviewsSelectionProvider. Expects --knowledge-review-scroll-height\n * to be set by a parent for ScrollArea height.\n */\nexport function KnowledgeReviewPanel({\n diffTitle,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n children,\n sourceIcon,\n sourceDescription,\n}: KnowledgeReviewPanelProps) {\n const {\n selectedItem,\n setSelectedItem,\n loadedDiffDoc,\n loadingDiff,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onAcceptAndPublish,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n suggestionReasonBody,\n } = useReviewsSelection();\n\n const hasItems = items.length > 0;\n const resolvedIsLoading = isLoading ?? !hasItems;\n const isLoadingState = resolvedIsLoading && !hasItems;\n const isEmptyState = !resolvedIsLoading && !hasItems;\n\n const title = loadingDiff ? '' : parse(loadedDiffDoc?.diffTitle ?? diffTitle ?? '');\n const body = loadingDiff ? <div className=\"text-muted-foreground\">Loading diff…</div> : loadedDiffDoc?.diffContent;\n\n const titleSuggestionsCount = loadingDiff ? 0 : countSuggestions(loadedDiffDoc?.diffTitle ?? diffTitle);\n\n const bodyRef = useRef<HTMLDivElement>(null);\n const [bodySuggestionsCount, setBodySuggestionsCount] = useState(0);\n useEffect(() => {\n if (loadingDiff || !loadedDiffDoc) {\n setBodySuggestionsCount(0);\n\n return;\n }\n const el = bodyRef.current;\n if (!el) return;\n const id = requestAnimationFrame(() => {\n setBodySuggestionsCount(countSuggestionsInElement(el));\n });\n\n return () => cancelAnimationFrame(id);\n }, [loadingDiff, loadedDiffDoc]);\n\n const suggestionsCount = titleSuggestionsCount + bodySuggestionsCount;\n\n const totalArticles = items.length;\n const totalArticlesForDisplay = totalItemsCount ?? totalArticles;\n const currentArticleIndex = selectedItem\n ? Math.max(\n 0,\n items.findIndex((i) => i.id === selectedItem.id),\n )\n : 0;\n\n const onNextArticle = useCallback(() => {\n if (currentArticleIndex < totalArticles - 1) {\n setSelectedItem(items[currentArticleIndex + 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem, totalArticles]);\n\n const onPreviousArticle = useCallback(() => {\n if (currentArticleIndex > 0) {\n setSelectedItem(items[currentArticleIndex - 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem]);\n\n const headerSourceIcon = selectedItem?.icon ?? sourceIcon;\n const headerSourceDescription = selectedItem?.description ?? sourceDescription;\n\n return (\n <Card className=\"py-6 pl-4\" data-name=\"knowledge-reviews\">\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8\">\n <CardHeader className=\"p-0\">\n {hasItems && (\n <CardTitle className=\"border-b border-dark-300 mb-6 pb-2 font-normal\">\n <SuggestionsHeader\n title={title}\n isNew={loadedDiffDoc?.isNew ?? false}\n suggestionsCount={suggestionsCount}\n sourceIcon={headerSourceIcon}\n sourceDescription={headerSourceDescription}\n currentArticleIndex={currentArticleIndex}\n totalArticles={totalArticles}\n displayTotalArticles={totalArticlesForDisplay}\n showActionButtons={showActionButtons}\n onNextArticle={onNextArticle}\n onPreviousArticle={onPreviousArticle}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAllSuggestions={onApproveAllSuggestions}\n onAcceptAndPublish={onAcceptAndPublish}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n suggestionReasonBody={suggestionReasonBody}\n />\n </CardTitle>\n )}\n </CardHeader>\n <CardContent className=\"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16\">\n {/* Mount point for children (e.g. KnowledgeReviewDiffLoader). Kept in DOM so its effects run; hidden because it has no UI. */}\n <div aria-hidden=\"true\" className=\"sr-only\" hidden>\n {children}\n </div>\n {isLoadingState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground\">\n <Spinner className=\"size-8\" />\n <p className=\"text-base font-medium\">Loading suggestions...</p>\n </div>\n ) : isEmptyState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]\">\n <HandsClapping className=\"text-muted-foreground\" size={32} weight=\"fill\" />\n <p className=\"text-base font-medium text-foreground\">All up to date. Well done, mate.</p>\n </div>\n ) : (\n <div ref={bodyRef}>{body}</div>\n )}\n </CardContent>\n </ScrollArea>\n </Card>\n );\n}\n","import React, { useEffect, useImperativeHandle, useRef } from 'react';\n\nimport { useReviewsSelection } from './context';\nimport { ReviewList, ReviewListItemProps, ReviewsSelectionProvider } from './review-list';\nimport { KnowledgeReviewPanel } from './knowledge-review-panel';\n\nimport { Card, CardContent } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nimport './knowledge-review.css';\n\nconst SCROLL_HEIGHT_VAR = '--knowledge-review-scroll-height';\n\nexport type KnowledgeReviewSceneHandle = {\n selectedItem: ReviewListItemProps | null;\n setSelectedItem: (item: ReviewListItemProps | null) => void;\n};\n\nexport type KnowledgeReviewSceneProps = {\n diffTitle?: string;\n children: React.ReactNode;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n /** Total number of review list items available (can exceed currently loaded `items.length`). */\n totalItemsCount?: number;\n /** Controls visibility of the Reject / Accept action buttons in the review header. */\n showActionButtons?: boolean;\n className?: string;\n onApproveAllSuggestions: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAndPublish?: () => void;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n breadcrumb?: string;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n suggestionReasonBody?: string;\n};\n\nconst KnowledgeReviewSceneInner = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewSceneInner(\n {\n diffTitle = 'Knowledge Review',\n children,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n className,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onAcceptAndPublish,\n onSourceLinkClick,\n breadcrumb,\n sourceIcon,\n sourceDescription,\n suggestionReasonBody,\n ...props\n },\n ref,\n ) {\n const innerRef = useRef<HTMLDivElement>(null);\n const { selectedItem, setSelectedItem } = useReviewsSelection();\n\n useImperativeHandle(\n ref,\n () => ({\n selectedItem,\n setSelectedItem,\n }),\n [selectedItem, setSelectedItem],\n );\n\n useEffect(() => {\n const cardEl = innerRef.current;\n if (!cardEl) return;\n\n const updateHeight = () => {\n const { height } = cardEl.getBoundingClientRect();\n cardEl.style.setProperty(SCROLL_HEIGHT_VAR, `${height}px`);\n };\n\n updateHeight();\n\n if (typeof ResizeObserver !== 'function') {\n return;\n }\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(cardEl);\n\n return () => observer.disconnect();\n }, []);\n\n const resolvedIsLoading = isLoading ?? items.length === 0;\n const isLoadingItems = resolvedIsLoading && items.length === 0;\n\n return (\n <Card className={cn('h-full', className)}>\n <CardContent className=\"p-4 lg:p-8 h-full\">\n <div\n ref={innerRef}\n className=\"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full\"\n style={{ [SCROLL_HEIGHT_VAR]: '100px' } as React.CSSProperties}\n {...props}\n >\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden\">\n {isLoadingItems ? (\n <div className=\"flex h-full min-h-96 items-center justify-center text-muted-foreground\">\n <Spinner className=\"size-6\" />\n </div>\n ) : (\n <ReviewList items={items} />\n )}\n </ScrollArea>\n <KnowledgeReviewPanel\n diffTitle={diffTitle}\n items={items}\n isLoading={resolvedIsLoading}\n totalItemsCount={totalItemsCount}\n showActionButtons={showActionButtons}\n sourceIcon={sourceIcon}\n sourceDescription={sourceDescription}\n >\n {children}\n </KnowledgeReviewPanel>\n </div>\n </CardContent>\n </Card>\n );\n },\n);\n\nexport const KnowledgeReviewScene = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewScene(props, ref) {\n const {\n items,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onAcceptAndPublish,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n suggestionReasonBody,\n } = props;\n\n return (\n <ReviewsSelectionProvider\n defaultSelectedItem={items.find((m) => m.isSelected) ?? null}\n onApproveAllSuggestions={onApproveAllSuggestions}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAndPublish={onAcceptAndPublish}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n suggestionReasonBody={suggestionReasonBody}\n >\n <KnowledgeReviewSceneInner {...props} ref={ref} />\n </ReviewsSelectionProvider>\n );\n },\n);\n"],"names":["KnowledgeReviewDiffLoader","fetchDiffForItem","selectedItem","setLoadedDiffDoc","setLoadingDiff","useReviewsSelection","loadDiffForItem","useCallback","async","itemId","signal","doc","aborted","error","console","selectedId","id","useEffect","abortController","AbortController","abort","REASON_TITLE","SuggestionsHeader","React","forwardRef","title","isNew","suggestionsCount","sourceIcon","sourceDescription","currentArticleIndex","totalArticles","displayTotalArticles","showActionButtons","onNextArticle","onPreviousArticle","onRejectAllSuggestions","onAcceptAllSuggestions","onAcceptAndPublish","breadcrumb","onOpenArticleLink","onSourceLinkClick","suggestionReasonBody","className","props","ref","splitButtonRef","useRef","whyOpen","setWhyOpen","useState","hasNextArticle","hasPreviousArticle","currentArticle","totalArticlesForDisplay","hasDisplayArticles","status","createElement","StatusBadge","variant","EditCount","count","cn","Button","size","onClick","Tooltip","TooltipTrigger","asChild","disabled","CaretDown","TooltipContent","side","bgColor","CaretUp","ButtonGroup","orientation","rounded","Popover","open","onOpenChange","PopoverTrigger","Lightbulb","PopoverContent","align","Backspace","DropdownMenu","brandShadowEffect","CheckCircle","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","elevation","countSuggestionsInRoot","root","adjacentPairs","querySelectorAll","standaloneIns","allDel","standaloneDel","Array","from","filter","del","nextElementSibling","tagName","length","KnowledgeReviewPanel","diffTitle","items","isLoading","totalItemsCount","children","setSelectedItem","loadedDiffDoc","loadingDiff","onApproveAllSuggestions","hasItems","resolvedIsLoading","isLoadingState","isEmptyState","parse","body","diffContent","titleSuggestionsCount","htmlString","DOMParser","parseFromString","bodyRef","bodySuggestionsCount","setBodySuggestionsCount","el","current","requestAnimationFrame","element","cancelAnimationFrame","Math","max","findIndex","i","headerSourceIcon","icon","headerSourceDescription","description","Card","ScrollArea","CardHeader","CardTitle","CardContent","hidden","Spinner","HandsClapping","weight","SCROLL_HEIGHT_VAR","KnowledgeReviewSceneInner","innerRef","useImperativeHandle","cardEl","updateHeight","height","getBoundingClientRect","style","setProperty","ResizeObserver","observer","observe","disconnect","isLoadingItems","ReviewList","KnowledgeReviewScene","ReviewsSelectionProvider","defaultSelectedItem","find","m","isSelected"],"mappings":"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"}
1
+ {"version":3,"file":"knowledge-review.js","sources":["../../../src/scenes/knowledge-review/diff-loader.tsx","../../../src/scenes/knowledge-review/suggestions-header/suggestions-header.tsx","../../../src/lib/countSuggestions.ts","../../../src/scenes/knowledge-review/knowledge-review-panel.tsx","../../../src/scenes/knowledge-review/scene.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport type { LoadedDiffDoc } from './context';\nimport { useReviewsSelection } from './context';\n\nexport type KnowledgeReviewDiffLoaderProps = {\n /** Called when selectedItem changes. Return diff payload or null. */\n fetchDiffForItem: (itemId: string) => Promise<LoadedDiffDoc | null>;\n};\n\n/**\n * Listens to selectedItem from context and fetches diff via the provided callback.\n * Owns loading state and context updates; host (Storybook or Platform) supplies fetch logic.\n */\nexport function KnowledgeReviewDiffLoader({ fetchDiffForItem }: KnowledgeReviewDiffLoaderProps) {\n const { selectedItem, setLoadedDiffDoc, setLoadingDiff } = useReviewsSelection();\n\n const loadDiffForItem = useCallback(\n async (itemId: string, signal: AbortSignal) => {\n setLoadingDiff(true);\n setLoadedDiffDoc(null);\n\n try {\n const doc = await fetchDiffForItem(itemId);\n if (signal.aborted) return;\n setLoadedDiffDoc(doc);\n } catch (error) {\n if (signal.aborted) return;\n console.error('Failed to fetch diff:', error);\n setLoadedDiffDoc(null);\n } finally {\n if (!signal.aborted) {\n setLoadingDiff(false);\n }\n }\n },\n [fetchDiffForItem, setLoadedDiffDoc, setLoadingDiff],\n );\n\n const selectedId = selectedItem?.id;\n\n useEffect(() => {\n if (!selectedId) {\n setLoadedDiffDoc(null);\n setLoadingDiff(false);\n\n return;\n }\n\n const abortController = new AbortController();\n void loadDiffForItem(selectedId, abortController.signal);\n\n return () => {\n abortController.abort();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedId, loadDiffForItem]);\n\n return null;\n}\n","import { CaretDown, CaretUp, Backspace, CheckCircle, Lightbulb } from '@phosphor-icons/react';\nimport * as React from 'react';\n\nimport { EditCount } from '../review-list/edit-count';\n\nimport { Button } from '@/components/ui/button';\nimport { brandShadowEffect } from '@/lib/styles';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { ButtonGroup } from '@/components/ui/button-group';\nimport { cn } from '@/lib/utils';\nimport { StatusBadge } from '@/components/convos/status-badge';\n\nexport interface SuggestionsHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n title: React.ReactNode;\n isNew: boolean;\n suggestionsCount: number;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n currentArticleIndex: number;\n totalArticles: number;\n displayTotalArticles?: number;\n showActionButtons?: boolean;\n onNextArticle: () => void;\n onPreviousArticle: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAllSuggestions: () => void;\n onAcceptAndPublish?: () => void;\n breadcrumb?: string;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n suggestionReasonBody?: string;\n}\n\nexport const REASON_TITLE = 'Why is Brainfish suggesting this?';\n\nexport const SuggestionsHeader = React.forwardRef<HTMLDivElement, SuggestionsHeaderProps>(function SuggestionsHeader(\n {\n title,\n isNew,\n suggestionsCount,\n sourceIcon,\n sourceDescription,\n currentArticleIndex,\n totalArticles,\n displayTotalArticles,\n showActionButtons = true,\n onNextArticle,\n onPreviousArticle,\n onRejectAllSuggestions,\n onAcceptAllSuggestions,\n onAcceptAndPublish,\n breadcrumb,\n onOpenArticleLink,\n onSourceLinkClick,\n suggestionReasonBody,\n className,\n ...props\n },\n ref,\n) {\n const splitButtonRef = React.useRef<HTMLDivElement>(null);\n const [whyOpen, setWhyOpen] = React.useState(false);\n const hasNextArticle = totalArticles > 0 && currentArticleIndex < totalArticles - 1;\n const hasPreviousArticle = currentArticleIndex > 0;\n const currentArticle = totalArticles === 0 ? 0 : currentArticleIndex + 1;\n const totalArticlesForDisplay = displayTotalArticles ?? totalArticles;\n const hasDisplayArticles = totalArticlesForDisplay > 0;\n\n let status: React.ReactNode | undefined;\n if (isNew) {\n status = <StatusBadge variant=\"success\">New</StatusBadge>;\n } else if (suggestionsCount) {\n status = <EditCount count={suggestionsCount} />;\n }\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-4', className)} {...props}>\n {/* Header + Navigation */}\n <div className=\"flex justify-between items-center\">\n <h1 className=\"heading-lg\">\n {title}\n {/* Breadcrumbs */}\n {onOpenArticleLink && breadcrumb && (\n <Button\n variant=\"link\"\n size=\"sm\"\n onClick={onOpenArticleLink}\n aria-label=\"Open article\"\n className=\"block px-0 text-subtle text-xs\"\n >\n {breadcrumb}\n </Button>\n )}\n </h1>\n {/* up/down carets */}\n <div className=\"flex items-center\">\n <p className=\"text-xs text-foreground\">\n <span aria-hidden=\"true\">{hasDisplayArticles ? `${currentArticle}/${totalArticlesForDisplay}` : '0'}</span>\n <span className=\"sr-only\" aria-live=\"polite\">\n {hasDisplayArticles ? `Article ${currentArticle} of ${totalArticlesForDisplay}` : 'No articles'}\n </span>\n </p>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasNextArticle}\n onClick={onNextArticle}\n aria-label=\"Go to next article\"\n >\n <CaretDown aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" bgColor=\"--bfc-foreground\" className=\"text-background\">\n Next Article\n </TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n disabled={!hasPreviousArticle}\n onClick={onPreviousArticle}\n aria-label=\"Go to previous article\"\n >\n <CaretUp aria-hidden=\"true\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" bgColor=\"--bfc-foreground\" className=\"text-background\">\n Previous Article\n </TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Status, Source + Actions */}\n <div className=\"flex-1 px-2 pb-2 flex justify-between items-center\">\n <div className=\"flex items-center gap-2\">\n {status}\n {sourceDescription &&\n (onSourceLinkClick ? (\n <Button\n variant=\"link\"\n onClick={onSourceLinkClick}\n aria-label=\"Open source\"\n className=\"[&_svg]:size-4 text-xs text-subtle gap-1\"\n >\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n <span>{sourceDescription}</span>\n </Button>\n ) : (\n <span className=\"[&_svg]:size-4 flex items-center gap-1 text-xs text-subtle\">\n {sourceIcon && <span className=\"shrink-0 flex items-center\">{sourceIcon}</span>}\n {sourceDescription}\n </span>\n ))}\n </div>\n {showActionButtons && (\n <ButtonGroup orientation=\"horizontal\" rounded={false} aria-label=\"Suggestion actions\" className=\"gap-1\">\n {suggestionReasonBody && (\n <Popover open={whyOpen} onOpenChange={setWhyOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" aria-label={REASON_TITLE}>\n <Lightbulb aria-hidden=\"true\" />\n Why\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n side=\"bottom\"\n className=\"z-above-modal shadow-md dark:shadow-md-invert border-dark-300\"\n >\n <div className=\"font-bold text-sm\">{REASON_TITLE}</div>\n <div className=\"text-sm text-subtle mt-1\">{suggestionReasonBody}</div>\n </PopoverContent>\n </Popover>\n )}\n <Button variant=\"ghost\" onClick={onRejectAllSuggestions}>\n <Backspace aria-hidden=\"true\" />\n Reject\n </Button>\n {onAcceptAndPublish ? (\n <DropdownMenu>\n <div\n ref={splitButtonRef}\n className={cn('flex items-center rounded border border-border bg-primary', brandShadowEffect)}\n >\n <Button\n variant=\"ghost\"\n className=\"gap-1 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200\"\n onClick={onAcceptAllSuggestions}\n >\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n <span className=\"h-full w-px self-stretch bg-foreground\" aria-hidden=\"true\" />\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9 rounded-none border-0 bg-transparent shadow-none hover:bg-dark-200\"\n aria-label=\"More accept options\"\n >\n <CaretDown className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n </div>\n <DropdownMenuContent align=\"end\" className=\"z-above-modal border-none shadow-md dark:shadow-md-invert\">\n <DropdownMenuItem onClick={onAcceptAndPublish}>\n <CheckCircle aria-hidden=\"true\" />\n Accept & publish\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : (\n <Button variant=\"default\" elevation=\"shadow\" onClick={onAcceptAllSuggestions}>\n <CheckCircle aria-hidden=\"true\" />\n Accept as draft\n </Button>\n )}\n </ButtonGroup>\n )}\n </div>\n </div>\n );\n});\n","function countSuggestionsInRoot(root: Document | Element): number {\n const adjacentPairs = root.querySelectorAll('del + ins');\n const standaloneIns = root.querySelectorAll('ins:not(del + ins)');\n const allDel = root.querySelectorAll('del');\n const standaloneDel = Array.from(allDel).filter((del) => del.nextElementSibling?.tagName !== 'INS');\n\n return adjacentPairs.length + standaloneIns.length + standaloneDel.length;\n}\n\n/** Count suggestions in an HTML string (for title or raw HTML content). */\nexport const countSuggestions = (htmlString: string) => {\n if (!htmlString || typeof DOMParser === 'undefined') {\n return 0;\n }\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, 'text/html');\n\n return countSuggestionsInRoot(doc);\n};\n\n/** Count suggestions inside a DOM element (for rendered ReactNode body content). */\nexport const countSuggestionsInElement = (element: Element | null) => {\n if (!element) return 0;\n\n return countSuggestionsInRoot(element);\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport parse from 'html-react-parser';\nimport { HandsClapping } from '@phosphor-icons/react';\n\nimport { useReviewsSelection } from './context';\nimport { SuggestionsHeader } from './suggestions-header';\nimport type { ReviewListItemProps } from './review-list';\n\nimport { countSuggestions, countSuggestionsInElement } from '@/lib/countSuggestions';\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport type KnowledgeReviewPanelProps = {\n diffTitle: string;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n totalItemsCount?: number;\n showActionButtons?: boolean;\n children?: React.ReactNode;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n};\n\n/**\n * Panel that shows the selected diff (title + content), suggestion count, and article nav.\n * Must be used inside ReviewsSelectionProvider. Expects --knowledge-review-scroll-height\n * to be set by a parent for ScrollArea height.\n */\nexport function KnowledgeReviewPanel({\n diffTitle,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n children,\n sourceIcon,\n sourceDescription,\n}: KnowledgeReviewPanelProps) {\n const {\n selectedItem,\n setSelectedItem,\n loadedDiffDoc,\n loadingDiff,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onAcceptAndPublish,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n suggestionReasonBody,\n } = useReviewsSelection();\n\n const hasItems = items.length > 0;\n const resolvedIsLoading = isLoading ?? !hasItems;\n const isLoadingState = resolvedIsLoading && !hasItems;\n const isEmptyState = !resolvedIsLoading && !hasItems;\n\n const title = loadingDiff ? '' : parse(loadedDiffDoc?.diffTitle ?? diffTitle ?? '');\n const body = loadingDiff ? <div className=\"text-muted-foreground\">Loading diff…</div> : loadedDiffDoc?.diffContent;\n\n const titleSuggestionsCount = loadingDiff ? 0 : countSuggestions(loadedDiffDoc?.diffTitle ?? diffTitle);\n\n const bodyRef = useRef<HTMLDivElement>(null);\n const [bodySuggestionsCount, setBodySuggestionsCount] = useState(0);\n useEffect(() => {\n if (loadingDiff || !loadedDiffDoc) {\n setBodySuggestionsCount(0);\n\n return;\n }\n const el = bodyRef.current;\n if (!el) return;\n const id = requestAnimationFrame(() => {\n setBodySuggestionsCount(countSuggestionsInElement(el));\n });\n\n return () => cancelAnimationFrame(id);\n }, [loadingDiff, loadedDiffDoc]);\n\n const suggestionsCount = titleSuggestionsCount + bodySuggestionsCount;\n\n const totalArticles = items.length;\n const totalArticlesForDisplay = totalItemsCount ?? totalArticles;\n const currentArticleIndex = selectedItem\n ? Math.max(\n 0,\n items.findIndex((i) => i.id === selectedItem.id),\n )\n : 0;\n\n const onNextArticle = useCallback(() => {\n if (currentArticleIndex < totalArticles - 1) {\n setSelectedItem(items[currentArticleIndex + 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem, totalArticles]);\n\n const onPreviousArticle = useCallback(() => {\n if (currentArticleIndex > 0) {\n setSelectedItem(items[currentArticleIndex - 1] ?? null);\n }\n }, [currentArticleIndex, items, setSelectedItem]);\n\n const headerSourceIcon = selectedItem?.icon ?? sourceIcon;\n const headerSourceDescription = selectedItem?.description ?? sourceDescription;\n\n return (\n <Card className=\"py-6 pl-4\" data-name=\"knowledge-reviews\">\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height)-50px)] pr-8\">\n <CardHeader className=\"p-0\">\n {hasItems && (\n <CardTitle className=\"border-b border-dark-300 mb-6 pb-2 font-normal\">\n <SuggestionsHeader\n title={title}\n isNew={loadedDiffDoc?.isNew ?? false}\n suggestionsCount={suggestionsCount}\n sourceIcon={headerSourceIcon}\n sourceDescription={headerSourceDescription}\n currentArticleIndex={currentArticleIndex}\n totalArticles={totalArticles}\n displayTotalArticles={totalArticlesForDisplay}\n showActionButtons={showActionButtons}\n onNextArticle={onNextArticle}\n onPreviousArticle={onPreviousArticle}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAllSuggestions={onApproveAllSuggestions}\n onAcceptAndPublish={onAcceptAndPublish}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n suggestionReasonBody={suggestionReasonBody}\n />\n </CardTitle>\n )}\n </CardHeader>\n <CardContent className=\"p-0 [&_ol]:!pl-16 [&_ul]:!pl-16\">\n {/* Mount point for children (e.g. KnowledgeReviewDiffLoader). Kept in DOM so its effects run; hidden because it has no UI. */}\n <div aria-hidden=\"true\" className=\"sr-only\" hidden>\n {children}\n </div>\n {isLoadingState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh] text-muted-foreground\">\n <Spinner className=\"size-8\" />\n <p className=\"text-base font-medium\">Loading suggestions...</p>\n </div>\n ) : isEmptyState ? (\n <div className=\"flex flex-col items-center justify-center gap-4 text-center h-[50dvh]\">\n <HandsClapping className=\"text-muted-foreground\" size={32} weight=\"fill\" />\n <p className=\"text-base font-medium text-foreground\">All up to date. Well done, mate.</p>\n </div>\n ) : (\n <div ref={bodyRef}>{body}</div>\n )}\n </CardContent>\n </ScrollArea>\n </Card>\n );\n}\n","import React, { useEffect, useImperativeHandle, useRef } from 'react';\n\nimport { useReviewsSelection } from './context';\nimport { ReviewList, ReviewListItemProps, ReviewsSelectionProvider } from './review-list';\nimport { KnowledgeReviewPanel } from './knowledge-review-panel';\n\nimport { Card, CardContent } from '@/components/ui/card';\nimport { ScrollArea } from '@/components/ui/scroll-area';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nimport './knowledge-review.css';\n\nconst SCROLL_HEIGHT_VAR = '--knowledge-review-scroll-height';\n\nexport type KnowledgeReviewSceneHandle = {\n selectedItem: ReviewListItemProps | null;\n setSelectedItem: (item: ReviewListItemProps | null) => void;\n};\n\nexport type KnowledgeReviewSceneProps = {\n diffTitle?: string;\n children: React.ReactNode;\n items: ReviewListItemProps[];\n isLoading?: boolean;\n /** Total number of review list items available (can exceed currently loaded `items.length`). */\n totalItemsCount?: number;\n /** Controls visibility of the Reject / Accept action buttons in the review header. */\n showActionButtons?: boolean;\n className?: string;\n onApproveAllSuggestions: () => void;\n onRejectAllSuggestions: () => void;\n onAcceptAndPublish?: () => void;\n onOpenArticleLink?: () => void;\n onSourceLinkClick?: () => void;\n breadcrumb?: string;\n sourceIcon: React.ReactNode;\n sourceDescription: string | null;\n suggestionReasonBody?: string;\n};\n\nconst KnowledgeReviewSceneInner = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewSceneInner(\n {\n diffTitle = 'Knowledge Review',\n children,\n items,\n isLoading,\n totalItemsCount,\n showActionButtons = true,\n className,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onOpenArticleLink,\n onAcceptAndPublish,\n onSourceLinkClick,\n breadcrumb,\n sourceIcon,\n sourceDescription,\n suggestionReasonBody,\n ...props\n },\n ref,\n ) {\n const innerRef = useRef<HTMLDivElement>(null);\n const { selectedItem, setSelectedItem } = useReviewsSelection();\n\n useImperativeHandle(\n ref,\n () => ({\n selectedItem,\n setSelectedItem,\n }),\n [selectedItem, setSelectedItem],\n );\n\n useEffect(() => {\n const cardEl = innerRef.current;\n if (!cardEl) return;\n\n const updateHeight = () => {\n const { height } = cardEl.getBoundingClientRect();\n cardEl.style.setProperty(SCROLL_HEIGHT_VAR, `${height}px`);\n };\n\n updateHeight();\n\n if (typeof ResizeObserver !== 'function') {\n return;\n }\n\n const observer = new ResizeObserver(updateHeight);\n observer.observe(cardEl);\n\n return () => observer.disconnect();\n }, []);\n\n const resolvedIsLoading = isLoading ?? items.length === 0;\n const isLoadingItems = resolvedIsLoading && items.length === 0;\n\n return (\n <Card className={cn('h-full', className)}>\n <CardContent className=\"p-4 lg:p-8 h-full\">\n <div\n ref={innerRef}\n className=\"grid xs:max-lg:grid-cols-1 lg:grid-cols-[1fr_4fr] gap-6 min-h-96 h-full\"\n style={{ [SCROLL_HEIGHT_VAR]: '100px' } as React.CSSProperties}\n {...props}\n >\n <ScrollArea className=\"h-[calc(var(--knowledge-review-scroll-height))] min-w-80 lg:block hidden\">\n {isLoadingItems ? (\n <div className=\"flex h-full min-h-96 items-center justify-center text-muted-foreground\">\n <Spinner className=\"size-6\" />\n </div>\n ) : (\n <ReviewList items={items} />\n )}\n </ScrollArea>\n <KnowledgeReviewPanel\n diffTitle={diffTitle}\n items={items}\n isLoading={resolvedIsLoading}\n totalItemsCount={totalItemsCount}\n showActionButtons={showActionButtons}\n sourceIcon={sourceIcon}\n sourceDescription={sourceDescription}\n >\n {children}\n </KnowledgeReviewPanel>\n </div>\n </CardContent>\n </Card>\n );\n },\n);\n\nexport const KnowledgeReviewScene = React.forwardRef<KnowledgeReviewSceneHandle, KnowledgeReviewSceneProps>(\n function KnowledgeReviewScene(props, ref) {\n const {\n items,\n onApproveAllSuggestions,\n onRejectAllSuggestions,\n onAcceptAndPublish,\n onOpenArticleLink,\n onSourceLinkClick,\n breadcrumb,\n suggestionReasonBody,\n } = props;\n\n return (\n <ReviewsSelectionProvider\n defaultSelectedItem={items.find((m) => m.isSelected) ?? null}\n onApproveAllSuggestions={onApproveAllSuggestions}\n onRejectAllSuggestions={onRejectAllSuggestions}\n onAcceptAndPublish={onAcceptAndPublish}\n onOpenArticleLink={onOpenArticleLink}\n onSourceLinkClick={onSourceLinkClick}\n breadcrumb={breadcrumb}\n suggestionReasonBody={suggestionReasonBody}\n >\n <KnowledgeReviewSceneInner {...props} ref={ref} />\n </ReviewsSelectionProvider>\n );\n },\n);\n"],"names":["KnowledgeReviewDiffLoader","fetchDiffForItem","selectedItem","setLoadedDiffDoc","setLoadingDiff","useReviewsSelection","loadDiffForItem","useCallback","async","itemId","signal","doc","aborted","error","console","selectedId","id","useEffect","abortController","AbortController","abort","REASON_TITLE","SuggestionsHeader","React","forwardRef","title","isNew","suggestionsCount","sourceIcon","sourceDescription","currentArticleIndex","totalArticles","displayTotalArticles","showActionButtons","onNextArticle","onPreviousArticle","onRejectAllSuggestions","onAcceptAllSuggestions","onAcceptAndPublish","breadcrumb","onOpenArticleLink","onSourceLinkClick","suggestionReasonBody","className","props","ref","splitButtonRef","useRef","whyOpen","setWhyOpen","useState","hasNextArticle","hasPreviousArticle","currentArticle","totalArticlesForDisplay","hasDisplayArticles","status","createElement","StatusBadge","variant","EditCount","count","cn","Button","size","onClick","Tooltip","TooltipTrigger","asChild","disabled","CaretDown","TooltipContent","side","bgColor","CaretUp","ButtonGroup","orientation","rounded","Popover","open","onOpenChange","PopoverTrigger","Lightbulb","PopoverContent","align","Backspace","DropdownMenu","brandShadowEffect","CheckCircle","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","elevation","countSuggestionsInRoot","root","adjacentPairs","querySelectorAll","standaloneIns","allDel","standaloneDel","Array","from","filter","del","nextElementSibling","tagName","length","KnowledgeReviewPanel","diffTitle","items","isLoading","totalItemsCount","children","setSelectedItem","loadedDiffDoc","loadingDiff","onApproveAllSuggestions","hasItems","resolvedIsLoading","isLoadingState","isEmptyState","parse","body","diffContent","titleSuggestionsCount","htmlString","DOMParser","parseFromString","bodyRef","bodySuggestionsCount","setBodySuggestionsCount","el","current","requestAnimationFrame","element","cancelAnimationFrame","Math","max","findIndex","i","headerSourceIcon","icon","headerSourceDescription","description","Card","ScrollArea","CardHeader","CardTitle","CardContent","hidden","Spinner","HandsClapping","weight","SCROLL_HEIGHT_VAR","KnowledgeReviewSceneInner","innerRef","useImperativeHandle","cardEl","updateHeight","height","getBoundingClientRect","style","setProperty","ResizeObserver","observer","observe","disconnect","isLoadingItems","ReviewList","KnowledgeReviewScene","ReviewsSelectionProvider","defaultSelectedItem","find","m","isSelected"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2068,6 +2068,95 @@ declare interface Suggestion_2 {
2068
2068
  messageCount?: number;
2069
2069
  }
2070
2070
 
2071
+ /**
2072
+ * Floating card that displays a single review suggestion with its source,
2073
+ * accept/reject actions, and an optional paginator for navigating within-article
2074
+ * suggestions. Purely presentational — the host wires callbacks to the
2075
+ * reviewSuggestions plugin / API layer.
2076
+ */
2077
+ export declare const SuggestionCard: React_2.ForwardRefExoticComponent<SuggestionCardProps & React_2.RefAttributes<HTMLDivElement>>;
2078
+
2079
+ /**
2080
+ * Visual diff shown between the source row and the reason. Renders as a
2081
+ * single bordered row with the old text struck-through in destructive color
2082
+ * and the new text in link color.
2083
+ *
2084
+ * - For replace ops, set both `oldText` and `newText`.
2085
+ * - For delete ops, set only `oldText`.
2086
+ * - For insert ops, set only `newText`.
2087
+ *
2088
+ * When both fields are empty/undefined the diff row is not rendered.
2089
+ */
2090
+ export declare interface SuggestionCardDiff {
2091
+ /** Original text being removed. Strikethrough + destructive. */
2092
+ oldText?: string;
2093
+ /** Proposed replacement / insertion. Link color. */
2094
+ newText?: string;
2095
+ }
2096
+
2097
+ /**
2098
+ * Pagination state for the side paginator column. When omitted, the paginator
2099
+ * column (and its divider) is not rendered at all.
2100
+ */
2101
+ export declare interface SuggestionCardPagination {
2102
+ /** 1-based index of this suggestion within the set. */
2103
+ currentIndex: number;
2104
+ /** Total number of suggestions in the set. */
2105
+ totalCount: number;
2106
+ /** Fires when the user navigates to the previous suggestion. Omit to hide the button. */
2107
+ onPrevious?: () => void;
2108
+ /** Fires when the user navigates to the next suggestion. Omit to hide the button. */
2109
+ onNext?: () => void;
2110
+ }
2111
+
2112
+ export declare interface SuggestionCardProps extends Omit<React_2.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
2113
+ /**
2114
+ * Source metadata shown at the top of the card. Omit to skip the source
2115
+ * row entirely — useful when the host doesn't have source info to surface.
2116
+ */
2117
+ source?: SuggestionCardSource;
2118
+ /**
2119
+ * Old vs. new text for the suggestion. Renders the bordered diff row
2120
+ * between the source and the reason. Omit to skip the diff row entirely.
2121
+ */
2122
+ diff?: SuggestionCardDiff;
2123
+ /**
2124
+ * Host-provided explanation for why this suggestion was raised. Renders
2125
+ * as the body paragraph below the diff. Omit to skip the reason line.
2126
+ */
2127
+ reason?: string;
2128
+ /**
2129
+ * Fires when the user accepts this suggestion. When omitted, the accept
2130
+ * button is rendered disabled (so the affordance is visible but inert).
2131
+ */
2132
+ onAccept?: () => void;
2133
+ /**
2134
+ * Fires when the user rejects this suggestion. When omitted, the reject
2135
+ * button is rendered disabled.
2136
+ */
2137
+ onReject?: () => void;
2138
+ /** Disable the accept button while an accept is in-flight. */
2139
+ acceptDisabled?: boolean;
2140
+ /** Disable the reject button while a reject is in-flight. */
2141
+ rejectDisabled?: boolean;
2142
+ /**
2143
+ * Paginator state. When omitted, the whole paginator column (and its
2144
+ * dividing border) is not rendered.
2145
+ */
2146
+ pagination?: SuggestionCardPagination;
2147
+ }
2148
+
2149
+ export declare interface SuggestionCardSource {
2150
+ /** Eyebrow label, e.g. "1 day ago from" — rendered uppercase by the card. */
2151
+ label: string;
2152
+ /** Display name of the source, e.g. "team-meetingFEB.mp4". */
2153
+ name: string;
2154
+ /**
2155
+ * Optional icon next to the source name. Pass a `@phosphor-icons/react` icon.
2156
+ */
2157
+ icon?: React_2.ReactNode;
2158
+ }
2159
+
2071
2160
  export declare const Switch: React_2.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React_2.RefAttributes<HTMLButtonElement>, "ref"> & React_2.RefAttributes<HTMLButtonElement>>;
2072
2161
 
2073
2162
  export declare const Table: React_2.ForwardRefExoticComponent<React_2.HTMLAttributes<HTMLTableElement> & React_2.RefAttributes<HTMLTableElement>>;
@@ -116,6 +116,95 @@ declare type ReviewsSelectionValue = {
116
116
  suggestionReasonBody?: string;
117
117
  };
118
118
 
119
+ /**
120
+ * Floating card that displays a single review suggestion with its source,
121
+ * accept/reject actions, and an optional paginator for navigating within-article
122
+ * suggestions. Purely presentational — the host wires callbacks to the
123
+ * reviewSuggestions plugin / API layer.
124
+ */
125
+ export declare const SuggestionCard: React_2.ForwardRefExoticComponent<SuggestionCardProps & React_2.RefAttributes<HTMLDivElement>>;
126
+
127
+ /**
128
+ * Visual diff shown between the source row and the reason. Renders as a
129
+ * single bordered row with the old text struck-through in destructive color
130
+ * and the new text in link color.
131
+ *
132
+ * - For replace ops, set both `oldText` and `newText`.
133
+ * - For delete ops, set only `oldText`.
134
+ * - For insert ops, set only `newText`.
135
+ *
136
+ * When both fields are empty/undefined the diff row is not rendered.
137
+ */
138
+ export declare interface SuggestionCardDiff {
139
+ /** Original text being removed. Strikethrough + destructive. */
140
+ oldText?: string;
141
+ /** Proposed replacement / insertion. Link color. */
142
+ newText?: string;
143
+ }
144
+
145
+ /**
146
+ * Pagination state for the side paginator column. When omitted, the paginator
147
+ * column (and its divider) is not rendered at all.
148
+ */
149
+ export declare interface SuggestionCardPagination {
150
+ /** 1-based index of this suggestion within the set. */
151
+ currentIndex: number;
152
+ /** Total number of suggestions in the set. */
153
+ totalCount: number;
154
+ /** Fires when the user navigates to the previous suggestion. Omit to hide the button. */
155
+ onPrevious?: () => void;
156
+ /** Fires when the user navigates to the next suggestion. Omit to hide the button. */
157
+ onNext?: () => void;
158
+ }
159
+
160
+ export declare interface SuggestionCardProps extends Omit<React_2.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
161
+ /**
162
+ * Source metadata shown at the top of the card. Omit to skip the source
163
+ * row entirely — useful when the host doesn't have source info to surface.
164
+ */
165
+ source?: SuggestionCardSource;
166
+ /**
167
+ * Old vs. new text for the suggestion. Renders the bordered diff row
168
+ * between the source and the reason. Omit to skip the diff row entirely.
169
+ */
170
+ diff?: SuggestionCardDiff;
171
+ /**
172
+ * Host-provided explanation for why this suggestion was raised. Renders
173
+ * as the body paragraph below the diff. Omit to skip the reason line.
174
+ */
175
+ reason?: string;
176
+ /**
177
+ * Fires when the user accepts this suggestion. When omitted, the accept
178
+ * button is rendered disabled (so the affordance is visible but inert).
179
+ */
180
+ onAccept?: () => void;
181
+ /**
182
+ * Fires when the user rejects this suggestion. When omitted, the reject
183
+ * button is rendered disabled.
184
+ */
185
+ onReject?: () => void;
186
+ /** Disable the accept button while an accept is in-flight. */
187
+ acceptDisabled?: boolean;
188
+ /** Disable the reject button while a reject is in-flight. */
189
+ rejectDisabled?: boolean;
190
+ /**
191
+ * Paginator state. When omitted, the whole paginator column (and its
192
+ * dividing border) is not rendered.
193
+ */
194
+ pagination?: SuggestionCardPagination;
195
+ }
196
+
197
+ export declare interface SuggestionCardSource {
198
+ /** Eyebrow label, e.g. "1 day ago from" — rendered uppercase by the card. */
199
+ label: string;
200
+ /** Display name of the source, e.g. "team-meetingFEB.mp4". */
201
+ name: string;
202
+ /**
203
+ * Optional icon next to the source name. Pass a `@phosphor-icons/react` icon.
204
+ */
205
+ icon?: React_2.ReactNode;
206
+ }
207
+
119
208
  export declare function useReviewsSelection(): ReviewsSelectionValue;
120
209
 
121
210
  export { }