@lax-wp/design-system 0.14.56 → 0.14.58

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,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),Y=require("../../../providers/design-system-provider/hooks.cjs.js"),K=require("./copy-text.cjs.js"),O=require("../../../_virtual/index.cjs.js"),o=require("react"),Z=require("react-dom"),T=require("./constants.cjs.js"),L=require("../../icon/icons.generated.cjs.js"),Q=async t=>{try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(t),!0}catch{}try{const i=document.createElement("textarea");i.value=t,i.setAttribute("readonly",""),i.style.position="fixed",i.style.opacity="0",document.body.appendChild(i),i.select();const d=document.execCommand("copy");return document.body.removeChild(i),d}catch{return!1}},ee=t=>{if(!t)return"";try{return new URL(t,window.location.href).href}catch{return""}},S=(t,i,d)=>t===void 0?d:typeof t=="function"?t(i):t,te=({item:t,isDisabled:i,isActive:d,onSelect:w,onHover:y})=>l.jsxs("button",{type:"button",role:"menuitem","data-menu-item":!0,disabled:i,"aria-disabled":i,tabIndex:d?0:-1,className:O("flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",i?"opacity-50 cursor-not-allowed":O("cursor-pointer",t.isDanger?"text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950":"text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600")),onClick:w,onMouseEnter:()=>!i&&y(),children:[t.icon?l.jsx("span",{className:O("flex shrink-0 items-center",t.isDanger?"text-error-600 dark:text-error-400":"text-neutral-500 dark:text-black-300"),children:t.icon}):null,l.jsx("span",{className:"flex-1 truncate",children:t.label}),t.shortcut?l.jsx("span",{className:"shrink-0 text-xs text-neutral-400 dark:text-black-300",children:t.shortcut}):null]}),ne=({state:t,config:i,rowOptions:d,asyncRowOptionsFilter:w,checkedIds:y,rows:P,columns:g,rowLinkConfig:E,onClose:m})=>{const p=Y.useTableConfig(),c=o.useMemo(()=>p?.t??(e=>e),[p]),b=o.useRef(null),[j,B]=o.useState(null),[M,v]=o.useState(-1),[k,U]=o.useState(null),[h,N]=o.useState({status:"off"}),z=o.useRef(),a=o.useMemo(()=>t?{...t.target,close:m}:null,[t,m]),F=o.useCallback(async(e,n,r)=>{if(k)return;const s=await Q(n);s?(i?.onCopy?.(n,r),p?.showNotification?.("success",c("Copied to clipboard"))):p?.showNotification?.("error",c("Could not copy to clipboard")),U({key:e,isCopied:s}),z.current=setTimeout(()=>m(),T.COPY_FEEDBACK_DURATION)},[i,p,c,m,k]),C=o.useCallback((e,n,r,s)=>{const u=k?.key===e;return{key:e,label:u?k?.isCopied?c("Copied"):c("Copy failed"):n,icon:u&&k?.isCopied?l.jsx(L.CheckIcon,{size:16,className:"text-success-600 dark:text-success-400"}):s??l.jsx(L.ContentCopyIcon,{size:16}),isDisabled:!r,keepOpenOnClick:!0,onClick:q=>F(e,r,q)}},[k,F,c]),H=o.useMemo(()=>K.getRowJson(t?.target.rowData,g),[t?.target.rowData,g]),J=o.useMemo(()=>t?K.getSelectedRowsJson(P,g,y):"",[t,P,g,y]),R=y?.length??0,x=o.useMemo(()=>!t||!E?.isEnabled||!E.linkTo||t.target.column?.disableRowClick?"":ee(E.linkTo(String(t.target.rowId),t.target.rowData)),[t,E]),X=o.useCallback(()=>{x&&window.open(x,"_blank","noopener,noreferrer")},[x]),_=o.useMemo(()=>{if(!a)return[];const e=i?.hideDefaultItems?[]:[C("copy-cell",i?.copyLabel??c("Copy Cell"),a.text),C("copy-row",c("Copy Row"),H),...R>0?[C("copy-selected-rows",R===1?c("Copy Selected Row"):`${c("Copy Selected Rows")} (${R})`,J)]:[],...x&&!i?.hideLinkItems?[{...C("copy-link",c("Copy Link"),x,l.jsx(L.LinkIcon,{size:16})),withDividerBefore:!0},{key:"open-in-new-tab",label:c("Open in New Tab"),icon:l.jsx(L.OpenInNewIcon,{size:16}),onClick:X}]:[]],n=typeof i?.items=="function"?i.items(a):i?.items??[];return[...e,...n].filter(r=>S(r.isVisible,a,!0))},[i,a,C,R,H,J,x,X,c]),D=o.useMemo(()=>!t||i?.includeRowOptions===!1||!d?[]:((typeof d=="function"?d(t.target.rowData):d)??[]).filter(n=>n.isVisible!==!1),[t,d,i?.includeRowOptions]),V=D.length>0;o.useEffect(()=>{if(!t||!V||!w){N({status:"off"});return}let e=!1;return N({status:"loading"}),w(String(t.target.rowId)).then(n=>!e&&N({status:"ready",available:n})).catch(()=>!e&&N({status:"failed"})),()=>{e=!0}},[t,V,w]);const A=o.useMemo(()=>{if(h.status==="off")return D;if(h.status!=="ready")return[];const{available:e}=h;return D.filter(n=>e[n.key]??!0)},[D,h]),f=o.useMemo(()=>{const e=_.map(r=>({kind:"item",key:r.key,item:r})),n=e.length>0;return h.status==="loading"?[...e,{kind:"skeleton",key:"row-options-loading",withDividerBefore:n}]:[...e,...A.map((r,s)=>({kind:"node",key:`row-option-${r.key}`,node:r.label,withDividerBefore:n&&s===0}))]},[_,A,h.status]),I=o.useCallback(e=>e.kind==="item"?!(a&&S(e.item.isDisabled,a,!1)):e.kind==="node",[a]),W=o.useMemo(()=>f.findIndex(I),[f,I]);o.useLayoutEffect(()=>{if(!t||!b.current){B(null);return}const{width:e,height:n}=b.current.getBoundingClientRect(),r=T.CELL_CONTEXT_MENU_VIEWPORT_MARGIN,s=T.CELL_CONTEXT_MENU_CURSOR_OFFSET,u=t.x+e+r>window.innerWidth?t.x-e-s:t.x+s,q=t.y+n+r>window.innerHeight?t.y-n-s:t.y+s;B({left:Math.max(r,Math.min(u,window.innerWidth-e-r)),top:Math.max(r,Math.min(q,window.innerHeight-n-r))})},[t,f.length]),o.useEffect(()=>(U(null),()=>clearTimeout(z.current)),[t]),o.useEffect(()=>{if(!t){v(-1);return}v(W)},[t,W]),o.useEffect(()=>{if(!t||M<0)return;const e=b.current?.querySelectorAll("[data-menu-item]")[M];(e?.matches("button")?e:e?.querySelector("button")??e)?.focus({preventScroll:!0})},[t,M]);const $=o.useCallback(e=>{f.length!==0&&v(n=>{let r=n;for(let s=0;s<f.length;s+=1)if(r=(r+e+f.length)%f.length,I(f[r]))return r;return n})},[f,I]);if(o.useEffect(()=>{if(!t)return;const e=u=>{b.current&&!b.current.contains(u.target)&&m()},n=u=>{if(u.key==="Escape"){u.stopPropagation(),m();return}(u.key==="ArrowDown"||u.key==="ArrowUp")&&(u.preventDefault(),$(u.key==="ArrowDown"?1:-1))},r=()=>m(),s=setTimeout(()=>{document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("keydown",n),document.addEventListener("scroll",r,!0),window.addEventListener("resize",r)},0);return()=>{clearTimeout(s),document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("keydown",n),document.removeEventListener("scroll",r,!0),window.removeEventListener("resize",r)}},[t,m,$]),!t||!a||f.length===0)return null;if(p?.renderCellContextMenu)return p.renderCellContextMenu({state:t,context:a,items:_,rowOptions:A,onClose:m});const G=async e=>{S(e.isDisabled,a,!1)||(e.keepOpenOnClick||m(),await e.onClick?.(a))};return Z.createPortal(l.jsx("div",{ref:b,role:"menu","aria-label":c("Cell actions"),"data-testid":"cell-context-menu",className:O("fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter","bg-white dark:bg-black-700","border border-neutral-200 dark:border-black-600","shadow-lg dark:shadow-black/40",i?.className),style:{left:j?.left??t.x,top:j?.top??t.y,zIndex:T.CELL_CONTEXT_MENU_Z_INDEX,visibility:j?"visible":"hidden"},onContextMenu:e=>e.preventDefault(),children:f.map((e,n)=>l.jsxs(o.Fragment,{children:[(e.kind==="item"?e.item.withDividerBefore&&n>0:e.withDividerBefore)?l.jsx("div",{className:"my-1 h-px bg-neutral-200 dark:bg-black-600"}):null,e.kind==="item"?l.jsx(te,{item:e.item,isDisabled:S(e.item.isDisabled,a,!1),isActive:n===M,onSelect:()=>void G(e.item),onHover:()=>v(n)}):e.kind==="skeleton"?l.jsx("div",{className:"px-3 py-2","data-testid":"cell-context-menu-loading",children:l.jsx("div",{className:"h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600"})}):l.jsx("div",{"data-menu-item":!0,tabIndex:-1,className:"outline-none [&_button]:w-full",onClick:m,onMouseEnter:()=>v(n),children:e.node})]},e.key))}),document.body)};exports.CellContextMenuPortal=ne;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),Q=require("../../../providers/design-system-provider/hooks.cjs.js"),Y=require("./copy-text.cjs.js"),O=require("../../../_virtual/index.cjs.js"),o=require("react"),ee=require("react-dom"),te=require("react-router-dom"),T=require("./constants.cjs.js"),L=require("../../icon/icons.generated.cjs.js"),ne=async t=>{try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(t),!0}catch{}try{const i=document.createElement("textarea");i.value=t,i.setAttribute("readonly",""),i.style.position="fixed",i.style.opacity="0",document.body.appendChild(i),i.select();const d=document.execCommand("copy");return document.body.removeChild(i),d}catch{return!1}},re=t=>{if(!t)return"";try{return new URL(t,window.location.origin).href}catch{return""}},S=(t,i,d)=>t===void 0?d:typeof t=="function"?t(i):t,oe=({item:t,isDisabled:i,isActive:d,onSelect:x,onHover:y})=>l.jsxs("button",{type:"button",role:"menuitem","data-menu-item":!0,disabled:i,"aria-disabled":i,tabIndex:d?0:-1,className:O("flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",i?"opacity-50 cursor-not-allowed":O("cursor-pointer",t.isDanger?"text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950":"text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600")),onClick:x,onMouseEnter:()=>!i&&y(),children:[t.icon?l.jsx("span",{className:O("flex shrink-0 items-center",t.isDanger?"text-error-600 dark:text-error-400":"text-neutral-500 dark:text-black-300"),children:t.icon}):null,l.jsx("span",{className:"flex-1 truncate",children:t.label}),t.shortcut?l.jsx("span",{className:"shrink-0 text-xs text-neutral-400 dark:text-black-300",children:t.shortcut}):null]}),ie=({state:t,config:i,rowOptions:d,asyncRowOptionsFilter:x,checkedIds:y,rows:B,columns:C,rowLinkConfig:E,onClose:m})=>{const p=Q.useTableConfig(),c=o.useMemo(()=>p?.t??(e=>e),[p]),b=o.useRef(null),[j,U]=o.useState(null),[M,v]=o.useState(-1),[k,z]=o.useState(null),[h,R]=o.useState({status:"off"}),H=o.useRef(),a=o.useMemo(()=>t?{...t.target,close:m}:null,[t,m]),F=o.useCallback(async(e,n,r)=>{if(k)return;const s=await ne(n);s?(i?.onCopy?.(n,r),p?.showNotification?.("success",c("Copied to clipboard"))):p?.showNotification?.("error",c("Could not copy to clipboard")),z({key:e,isCopied:s}),H.current=setTimeout(()=>m(),T.COPY_FEEDBACK_DURATION)},[i,p,c,m,k]),g=o.useCallback((e,n,r,s)=>{const u=k?.key===e;return{key:e,label:u?k?.isCopied?c("Copied"):c("Copy failed"):n,icon:u&&k?.isCopied?l.jsx(L.CheckIcon,{size:16,className:"text-success-600 dark:text-success-400"}):s??l.jsx(L.ContentCopyIcon,{size:16}),isDisabled:!r,keepOpenOnClick:!0,onClick:P=>F(e,r,P)}},[k,F,c]),J=o.useMemo(()=>Y.getRowJson(t?.target.rowData,C),[t?.target.rowData,C]),X=o.useMemo(()=>t?Y.getSelectedRowsJson(B,C,y):"",[t,B,C,y]),D=y?.length??0,_=o.useMemo(()=>!t||!E?.isEnabled||!E.linkTo||t.target.column?.disableRowClick?"":E.linkTo(String(t.target.rowId),t.target.rowData)||"",[t,E]),V=te.useHref(_||"/"),w=o.useMemo(()=>_?re(V):"",[_,V]),W=o.useCallback(()=>{w&&window.open(w,"_blank","noopener,noreferrer")},[w]),A=o.useMemo(()=>{if(!a)return[];const e=i?.hideDefaultItems?[]:[g("copy-cell",i?.copyLabel??c("Copy Cell"),a.text),g("copy-row",c("Copy Row"),J),...D>0?[g("copy-selected-rows",D===1?c("Copy Selected Row"):`${c("Copy Selected Rows")} (${D})`,X)]:[],...w&&!i?.hideLinkItems?[{...g("copy-link",c("Copy Link"),w,l.jsx(L.LinkIcon,{size:16})),withDividerBefore:!0},{key:"open-in-new-tab",label:c("Open in New Tab"),icon:l.jsx(L.OpenInNewIcon,{size:16}),onClick:W}]:[]],n=typeof i?.items=="function"?i.items(a):i?.items??[];return[...e,...n].filter(r=>S(r.isVisible,a,!0))},[i,a,g,D,J,X,w,W,c]),N=o.useMemo(()=>!t||i?.includeRowOptions===!1||!d?[]:((typeof d=="function"?d(t.target.rowData):d)??[]).filter(n=>n.isVisible!==!1),[t,d,i?.includeRowOptions]),$=N.length>0;o.useEffect(()=>{if(!t||!$||!x){R({status:"off"});return}let e=!1;return R({status:"loading"}),x(String(t.target.rowId)).then(n=>!e&&R({status:"ready",available:n})).catch(()=>!e&&R({status:"failed"})),()=>{e=!0}},[t,$,x]);const q=o.useMemo(()=>{if(h.status==="off")return N;if(h.status!=="ready")return[];const{available:e}=h;return N.filter(n=>e[n.key]??!0)},[N,h]),f=o.useMemo(()=>{const e=A.map(r=>({kind:"item",key:r.key,item:r})),n=e.length>0;return h.status==="loading"?[...e,{kind:"skeleton",key:"row-options-loading",withDividerBefore:n}]:[...e,...q.map((r,s)=>({kind:"node",key:`row-option-${r.key}`,node:r.label,withDividerBefore:n&&s===0}))]},[A,q,h.status]),I=o.useCallback(e=>e.kind==="item"?!(a&&S(e.item.isDisabled,a,!1)):e.kind==="node",[a]),K=o.useMemo(()=>f.findIndex(I),[f,I]);o.useLayoutEffect(()=>{if(!t||!b.current){U(null);return}const{width:e,height:n}=b.current.getBoundingClientRect(),r=T.CELL_CONTEXT_MENU_VIEWPORT_MARGIN,s=T.CELL_CONTEXT_MENU_CURSOR_OFFSET,u=t.x+e+r>window.innerWidth?t.x-e-s:t.x+s,P=t.y+n+r>window.innerHeight?t.y-n-s:t.y+s;U({left:Math.max(r,Math.min(u,window.innerWidth-e-r)),top:Math.max(r,Math.min(P,window.innerHeight-n-r))})},[t,f.length]),o.useEffect(()=>(z(null),()=>clearTimeout(H.current)),[t]),o.useEffect(()=>{if(!t){v(-1);return}v(K)},[t,K]),o.useEffect(()=>{if(!t||M<0)return;const e=b.current?.querySelectorAll("[data-menu-item]")[M];(e?.matches("button")?e:e?.querySelector("button")??e)?.focus({preventScroll:!0})},[t,M]);const G=o.useCallback(e=>{f.length!==0&&v(n=>{let r=n;for(let s=0;s<f.length;s+=1)if(r=(r+e+f.length)%f.length,I(f[r]))return r;return n})},[f,I]);if(o.useEffect(()=>{if(!t)return;const e=u=>{b.current&&!b.current.contains(u.target)&&m()},n=u=>{if(u.key==="Escape"){u.stopPropagation(),m();return}(u.key==="ArrowDown"||u.key==="ArrowUp")&&(u.preventDefault(),G(u.key==="ArrowDown"?1:-1))},r=()=>m(),s=setTimeout(()=>{document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("keydown",n),document.addEventListener("scroll",r,!0),window.addEventListener("resize",r)},0);return()=>{clearTimeout(s),document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("keydown",n),document.removeEventListener("scroll",r,!0),window.removeEventListener("resize",r)}},[t,m,G]),!t||!a||f.length===0)return null;if(p?.renderCellContextMenu)return p.renderCellContextMenu({state:t,context:a,items:A,rowOptions:q,onClose:m});const Z=async e=>{S(e.isDisabled,a,!1)||(e.keepOpenOnClick||m(),await e.onClick?.(a))};return ee.createPortal(l.jsx("div",{ref:b,role:"menu","aria-label":c("Cell actions"),"data-testid":"cell-context-menu",className:O("fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter","bg-white dark:bg-black-700","border border-neutral-200 dark:border-black-600","shadow-lg dark:shadow-black/40",i?.className),style:{left:j?.left??t.x,top:j?.top??t.y,zIndex:T.CELL_CONTEXT_MENU_Z_INDEX,visibility:j?"visible":"hidden"},onContextMenu:e=>e.preventDefault(),children:f.map((e,n)=>l.jsxs(o.Fragment,{children:[(e.kind==="item"?e.item.withDividerBefore&&n>0:e.withDividerBefore)?l.jsx("div",{className:"my-1 h-px bg-neutral-200 dark:bg-black-600"}):null,e.kind==="item"?l.jsx(oe,{item:e.item,isDisabled:S(e.item.isDisabled,a,!1),isActive:n===M,onSelect:()=>void Z(e.item),onHover:()=>v(n)}):e.kind==="skeleton"?l.jsx("div",{className:"px-3 py-2","data-testid":"cell-context-menu-loading",children:l.jsx("div",{className:"h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600"})}):l.jsx("div",{"data-menu-item":!0,tabIndex:-1,className:"outline-none [&_button]:w-full",onClick:m,onMouseEnter:()=>v(n),children:e.node})]},e.key))}),document.body)};exports.CellContextMenuPortal=ie;
2
2
  //# sourceMappingURL=CellContextMenuPortal.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CellContextMenuPortal.cjs.js","sources":["../../../../src/components/data-display/infinite-table/CellContextMenuPortal.tsx"],"sourcesContent":["import { useTableConfig } from '../../../providers/design-system-provider/hooks';\nimport { CheckIcon, ContentCopyIcon, LinkIcon, OpenInNewIcon } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\n IRowLinkConfig,\n} from './types';\nimport { getRowJson, getSelectedRowsJson } from './copy-text';\nimport cn from 'classnames';\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n CELL_CONTEXT_MENU_CURSOR_OFFSET,\n COPY_FEEDBACK_DURATION,\n CELL_CONTEXT_MENU_VIEWPORT_MARGIN,\n CELL_CONTEXT_MENU_Z_INDEX,\n} from './constants';\n\ntype TRowOption = { key: string; label: React.ReactNode; isVisible?: boolean };\n\n/** Result of the per-row availability check for row actions. */\ntype TRowOptionsFilter =\n | { status: 'off' }\n | { status: 'loading' }\n | { status: 'ready'; available: Record<string, boolean> }\n | { status: 'failed' };\n\n/** One rendered menu line: a declared item, a row-action node supplied by the table, or the row-action placeholder. */\ntype TMenuRow =\n | { kind: 'item'; key: string; item: ICellContextMenuItem }\n | { kind: 'node'; key: string; node: React.ReactNode; withDividerBefore?: boolean }\n | { kind: 'skeleton'; key: string; withDividerBefore?: boolean };\n\ninterface CellContextMenuPortalProps {\n state: ICellContextMenuState | null;\n config?: ICellContextMenuConfig | null;\n /** The table's row actions, appended to the menu — same list the three-dot cell renders. */\n rowOptions?: TRowOption[] | ((rowData: Record<string, unknown>) => TRowOption[] | null) | null;\n /** Per-row availability check for `rowOptions`, mirroring the three-dot cell so both menus agree. */\n asyncRowOptionsFilter?: ((rowId: string) => Promise<Record<string, boolean>>) | null;\n /** Checked row ids, enabling the \"Copy selected rows\" item. */\n checkedIds?: (string | number)[];\n /** Table rows, used to build the text for selected rows that are scrolled out of view. */\n rows?: Record<string, unknown>[];\n /** Visible columns in display order, used to order the copied values. */\n columns?: IColumn[];\n /** The table's row link, enabling the \"Copy Link\" / \"Open in New Tab\" items. */\n rowLinkConfig?: IRowLinkConfig | null;\n onClose: () => void;\n}\n\n/** Clipboard write with a fallback for browsers / insecure contexts without the async clipboard API. */\nconst writeToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator?.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // fall through to the textarea fallback\n }\n\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand('copy');\n document.body.removeChild(textarea);\n return copied;\n } catch {\n return false;\n }\n};\n\n/** `linkTo` returns a router path; the clipboard and a new tab both need a full URL. */\nconst toAbsoluteUrl = (path: string): string => {\n if (!path) return '';\n\n try {\n return new URL(path, window.location.href).href;\n } catch {\n return '';\n }\n};\n\nconst resolveFlag = (\n flag: boolean | ((context: ICellContextMenuContext) => boolean) | undefined,\n context: ICellContextMenuContext,\n fallback: boolean,\n): boolean => {\n if (flag === undefined) return fallback;\n return typeof flag === 'function' ? flag(context) : flag;\n};\n\nconst MenuItemButton: React.FC<{\n item: ICellContextMenuItem;\n isDisabled: boolean;\n isActive: boolean;\n onSelect: () => void;\n onHover: () => void;\n}> = ({ item, isDisabled, isActive, onSelect, onHover }) => (\n <button\n type='button'\n role='menuitem'\n data-menu-item\n disabled={isDisabled}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={cn(\n 'flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none',\n isDisabled\n ? 'opacity-50 cursor-not-allowed'\n : cn(\n 'cursor-pointer',\n item.isDanger\n ? 'text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950'\n : 'text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600',\n ),\n )}\n onClick={onSelect}\n onMouseEnter={() => !isDisabled && onHover()}\n >\n {item.icon ? (\n <span className={cn('flex shrink-0 items-center', item.isDanger ? 'text-error-600 dark:text-error-400' : 'text-neutral-500 dark:text-black-300')}>\n {item.icon}\n </span>\n ) : null}\n <span className='flex-1 truncate'>{item.label}</span>\n {item.shortcut ? <span className='shrink-0 text-xs text-neutral-400 dark:text-black-300'>{item.shortcut}</span> : null}\n </button>\n);\n\n/**\n * Right-click menu for data cells. Rendered once per table and positioned at the\n * cursor; `DataCell` opens it through `openCellContextMenu` on the table context.\n */\nexport const CellContextMenuPortal: React.FC<CellContextMenuPortalProps> = ({\n state, config, rowOptions, asyncRowOptionsFilter, checkedIds, rows, columns, rowLinkConfig, onClose,\n}) => {\n const tableConfig = useTableConfig();\n const t = useMemo(() => tableConfig?.t ?? ((key: string) => key), [tableConfig]);\n const menuRef = useRef<HTMLDivElement>(null);\n const [position, setPosition] = useState<{ left: number; top: number } | null>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [copyState, setCopyState] = useState<{ key: string; isCopied: boolean } | null>(null);\n const [rowOptionsFilter, setRowOptionsFilter] = useState<TRowOptionsFilter>({ status: 'off' });\n const closeTimer = useRef<ReturnType<typeof setTimeout>>();\n\n const context = useMemo<ICellContextMenuContext | null>(\n () => (state ? { ...state.target, close: onClose } : null),\n [state, onClose],\n );\n\n const handleCopy = useCallback(\n async (key: string, text: string, menuContext: ICellContextMenuContext) => {\n if (copyState) return;\n\n const isCopied = await writeToClipboard(text);\n\n if (isCopied) {\n config?.onCopy?.(text, menuContext);\n tableConfig?.showNotification?.('success', t('Copied to clipboard'));\n } else {\n tableConfig?.showNotification?.('error', t('Could not copy to clipboard'));\n }\n\n // Confirmed inline instead of with a toast, so the menu owns its own feedback.\n setCopyState({ key, isCopied });\n closeTimer.current = setTimeout(() => onClose(), COPY_FEEDBACK_DURATION);\n },\n [config, tableConfig, t, onClose, copyState],\n );\n\n const buildCopyItem = useCallback(\n (key: string, label: string, text: string, icon?: React.ReactNode): ICellContextMenuItem => {\n const isDone = copyState?.key === key;\n\n return {\n key,\n label: !isDone ? label : copyState?.isCopied ? t('Copied') : t('Copy failed'),\n icon:\n isDone && copyState?.isCopied ? (\n <CheckIcon size={16} className='text-success-600 dark:text-success-400' />\n ) : (\n icon ?? <ContentCopyIcon size={16} />\n ),\n isDisabled: !text,\n keepOpenOnClick: true,\n onClick: (menuContext) => handleCopy(key, text, menuContext),\n };\n },\n [copyState, handleCopy, t],\n );\n\n const rowJson = useMemo(() => getRowJson(state?.target.rowData, columns), [state?.target.rowData, columns]);\n // Only while the menu is open — otherwise every checkbox tick would serialize the selection.\n const selectedRowsJson = useMemo(() => (state ? getSelectedRowsJson(rows, columns, checkedIds) : ''), [state, rows, columns, checkedIds]);\n const selectedCount = checkedIds?.length ?? 0;\n\n /** The row link as an absolute URL — empty unless the table opted in, and never on a cell that opts out of the row link. */\n const rowLinkHref = useMemo(() => {\n if (!state || !rowLinkConfig?.isEnabled || !rowLinkConfig.linkTo || state.target.column?.disableRowClick) return '';\n\n return toAbsoluteUrl(rowLinkConfig.linkTo(String(state.target.rowId), state.target.rowData));\n }, [state, rowLinkConfig]);\n\n const openInNewTab = useCallback(() => {\n if (rowLinkHref) window.open(rowLinkHref, '_blank', 'noopener,noreferrer');\n }, [rowLinkHref]);\n\n const items = useMemo<ICellContextMenuItem[]>(() => {\n if (!context) return [];\n\n const defaultItems: ICellContextMenuItem[] = config?.hideDefaultItems\n ? []\n : [\n buildCopyItem('copy-cell', config?.copyLabel ?? t('Copy Cell'), context.text),\n buildCopyItem('copy-row', t('Copy Row'), rowJson),\n ...(selectedCount > 0\n ? [\n buildCopyItem(\n 'copy-selected-rows',\n selectedCount === 1 ? t('Copy Selected Row') : `${t('Copy Selected Rows')} (${selectedCount})`,\n selectedRowsJson,\n ),\n ]\n : []),\n ...(rowLinkHref && !config?.hideLinkItems\n ? [\n {\n ...buildCopyItem('copy-link', t('Copy Link'), rowLinkHref, <LinkIcon size={16} />),\n withDividerBefore: true,\n },\n {\n key: 'open-in-new-tab',\n label: t('Open in New Tab'),\n icon: <OpenInNewIcon size={16} />,\n onClick: openInNewTab,\n },\n ]\n : []),\n ];\n\n const extraItems = typeof config?.items === 'function' ? config.items(context) : config?.items ?? [];\n\n return [...defaultItems, ...extraItems].filter((item) => resolveFlag(item.isVisible, context, true));\n }, [config, context, buildCopyItem, selectedCount, rowJson, selectedRowsJson, rowLinkHref, openInNewTab, t]);\n\n /** The table's own row actions, resolved for the right-clicked row. */\n const resolvedRowOptions = useMemo<TRowOption[]>(() => {\n if (!state || config?.includeRowOptions === false || !rowOptions) return [];\n\n const list = typeof rowOptions === 'function' ? rowOptions(state.target.rowData) : rowOptions;\n\n return (list ?? []).filter((option) => option.isVisible !== false);\n }, [state, rowOptions, config?.includeRowOptions]);\n\n const hasRowOptions = resolvedRowOptions.length > 0;\n\n /** Row actions can be gated per row by the API — ask before showing them, exactly as the three-dot cell does. */\n useEffect(() => {\n if (!state || !hasRowOptions || !asyncRowOptionsFilter) {\n setRowOptionsFilter({ status: 'off' });\n return;\n }\n\n let isCancelled = false;\n setRowOptionsFilter({ status: 'loading' });\n\n asyncRowOptionsFilter(String(state.target.rowId))\n .then((available) => !isCancelled && setRowOptionsFilter({ status: 'ready', available }))\n .catch(() => !isCancelled && setRowOptionsFilter({ status: 'failed' }));\n\n return () => {\n isCancelled = true;\n };\n }, [state, hasRowOptions, asyncRowOptionsFilter]);\n\n const allowedRowOptions = useMemo<TRowOption[]>(() => {\n if (rowOptionsFilter.status === 'off') return resolvedRowOptions;\n if (rowOptionsFilter.status !== 'ready') return [];\n\n const { available } = rowOptionsFilter;\n\n return resolvedRowOptions.filter((option) => available[option.key] ?? true);\n }, [resolvedRowOptions, rowOptionsFilter]);\n\n const menuRows = useMemo<TMenuRow[]>(() => {\n const itemRows: TMenuRow[] = items.map((item) => ({ kind: 'item', key: item.key, item }));\n const needsDivider = itemRows.length > 0;\n\n if (rowOptionsFilter.status === 'loading') {\n return [...itemRows, { kind: 'skeleton', key: 'row-options-loading', withDividerBefore: needsDivider }];\n }\n\n return [\n ...itemRows,\n ...allowedRowOptions.map<TMenuRow>((option, index) => ({\n kind: 'node',\n key: `row-option-${option.key}`,\n node: option.label,\n withDividerBefore: needsDivider && index === 0,\n })),\n ];\n }, [items, allowedRowOptions, rowOptionsFilter.status]);\n\n const isRowNavigable = useCallback(\n (row: TMenuRow): boolean => (row.kind === 'item' ? !(context && resolveFlag(row.item.isDisabled, context, false)) : row.kind === 'node'),\n [context],\n );\n\n const firstNavigableIndex = useMemo(() => menuRows.findIndex(isRowNavigable), [menuRows, isRowNavigable]);\n\n /** Clamp into the viewport once the menu has been measured; row actions can arrive after the first paint. */\n useLayoutEffect(() => {\n if (!state || !menuRef.current) {\n setPosition(null);\n return;\n }\n\n const { width, height } = menuRef.current.getBoundingClientRect();\n const margin = CELL_CONTEXT_MENU_VIEWPORT_MARGIN;\n const offset = CELL_CONTEXT_MENU_CURSOR_OFFSET;\n\n // Flip to the other side of the cursor when there is no room, then clamp.\n const left = state.x + width + margin > window.innerWidth ? state.x - width - offset : state.x + offset;\n const top = state.y + height + margin > window.innerHeight ? state.y - height - offset : state.y + offset;\n\n setPosition({\n left: Math.max(margin, Math.min(left, window.innerWidth - width - margin)),\n top: Math.max(margin, Math.min(top, window.innerHeight - height - margin)),\n });\n }, [state, menuRows.length]);\n\n useEffect(() => {\n setCopyState(null);\n return () => clearTimeout(closeTimer.current);\n }, [state]);\n\n useEffect(() => {\n if (!state) {\n setActiveIndex(-1);\n return;\n }\n setActiveIndex(firstNavigableIndex);\n }, [state, firstNavigableIndex]);\n\n /** Focus follows the active row so the menu is keyboard operable; row actions bring their own button. */\n useEffect(() => {\n if (!state || activeIndex < 0) return;\n\n const row = menuRef.current?.querySelectorAll<HTMLElement>('[data-menu-item]')[activeIndex];\n const focusTarget = row?.matches('button') ? row : row?.querySelector('button') ?? row;\n\n // preventScroll: a focus-driven scroll would immediately close the menu.\n focusTarget?.focus({ preventScroll: true });\n }, [state, activeIndex]);\n\n const moveActiveIndex = useCallback(\n (direction: 1 | -1) => {\n if (menuRows.length === 0) return;\n setActiveIndex((current) => {\n let next = current;\n for (let step = 0; step < menuRows.length; step += 1) {\n next = (next + direction + menuRows.length) % menuRows.length;\n if (isRowNavigable(menuRows[next])) return next;\n }\n return current;\n });\n },\n [menuRows, isRowNavigable],\n );\n\n useEffect(() => {\n if (!state) return;\n\n const handlePointerDown = (event: MouseEvent | TouchEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) onClose();\n };\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopPropagation();\n onClose();\n return;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n moveActiveIndex(event.key === 'ArrowDown' ? 1 : -1);\n }\n };\n // Any scroll (table viewport included) detaches the menu from its cell, so close it.\n const handleScroll = () => onClose();\n\n // Deferred so the right click that opened the menu does not immediately close it.\n const timeoutId = setTimeout(() => {\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('touchstart', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n window.addEventListener('resize', handleScroll);\n }, 0);\n\n return () => {\n clearTimeout(timeoutId);\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('touchstart', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('resize', handleScroll);\n };\n }, [state, onClose, moveActiveIndex]);\n\n if (!state || !context || menuRows.length === 0) return null;\n\n if (tableConfig?.renderCellContextMenu) {\n return tableConfig.renderCellContextMenu({ state, context, items, rowOptions: allowedRowOptions, onClose }) as JSX.Element;\n }\n\n const handleItemClick = async (item: ICellContextMenuItem): Promise<void> => {\n if (resolveFlag(item.isDisabled, context, false)) return;\n if (!item.keepOpenOnClick) onClose();\n await item.onClick?.(context);\n };\n\n return createPortal(\n <div\n ref={menuRef}\n role='menu'\n aria-label={t('Cell actions')}\n data-testid='cell-context-menu'\n className={cn(\n 'fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter',\n 'bg-white dark:bg-black-700',\n 'border border-neutral-200 dark:border-black-600',\n 'shadow-lg dark:shadow-black/40',\n config?.className,\n )}\n style={{\n left: position?.left ?? state.x,\n top: position?.top ?? state.y,\n zIndex: CELL_CONTEXT_MENU_Z_INDEX,\n // Hidden until measured so the flip/clamp never flashes at the wrong spot.\n visibility: position ? 'visible' : 'hidden',\n }}\n onContextMenu={(event) => event.preventDefault()}\n >\n {menuRows.map((row, index) => (\n <React.Fragment key={row.key}>\n {(row.kind === 'item' ? row.item.withDividerBefore && index > 0 : row.withDividerBefore) ? (\n <div className='my-1 h-px bg-neutral-200 dark:bg-black-600' />\n ) : null}\n {row.kind === 'item' ? (\n <MenuItemButton\n item={row.item}\n isDisabled={resolveFlag(row.item.isDisabled, context, false)}\n isActive={index === activeIndex}\n onSelect={() => void handleItemClick(row.item)}\n onHover={() => setActiveIndex(index)}\n />\n ) : row.kind === 'skeleton' ? (\n <div className='px-3 py-2' data-testid='cell-context-menu-loading'>\n <div className='h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600' />\n </div>\n ) : (\n /* Row actions are rendered as the table supplied them — they carry their own button and handler. */\n <div data-menu-item tabIndex={-1} className='outline-none [&_button]:w-full' onClick={onClose} onMouseEnter={() => setActiveIndex(index)}>\n {row.node}\n </div>\n )}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n );\n};\n"],"names":["writeToClipboard","text","textarea","copied","toAbsoluteUrl","path","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","rowLinkConfig","onClose","tableConfig","useTableConfig","t","useMemo","key","menuRef","useRef","position","setPosition","useState","activeIndex","setActiveIndex","copyState","setCopyState","rowOptionsFilter","setRowOptionsFilter","closeTimer","handleCopy","useCallback","menuContext","isCopied","COPY_FEEDBACK_DURATION","buildCopyItem","label","icon","isDone","CheckIcon","ContentCopyIcon","rowJson","getRowJson","selectedRowsJson","getSelectedRowsJson","selectedCount","rowLinkHref","openInNewTab","items","defaultItems","LinkIcon","OpenInNewIcon","extraItems","resolvedRowOptions","option","hasRowOptions","useEffect","isCancelled","available","allowedRowOptions","menuRows","itemRows","needsDivider","index","isRowNavigable","row","firstNavigableIndex","useLayoutEffect","width","height","margin","CELL_CONTEXT_MENU_VIEWPORT_MARGIN","offset","CELL_CONTEXT_MENU_CURSOR_OFFSET","left","top","moveActiveIndex","direction","current","next","step","handlePointerDown","event","handleKeyDown","handleScroll","timeoutId","handleItemClick","createPortal","CELL_CONTEXT_MENU_Z_INDEX","React"],"mappings":"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"}
1
+ {"version":3,"file":"CellContextMenuPortal.cjs.js","sources":["../../../../src/components/data-display/infinite-table/CellContextMenuPortal.tsx"],"sourcesContent":["import { useTableConfig } from '../../../providers/design-system-provider/hooks';\nimport { CheckIcon, ContentCopyIcon, LinkIcon, OpenInNewIcon } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\n IRowLinkConfig,\n} from './types';\nimport { getRowJson, getSelectedRowsJson } from './copy-text';\nimport cn from 'classnames';\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useHref } from 'react-router-dom';\n\nimport {\n CELL_CONTEXT_MENU_CURSOR_OFFSET,\n COPY_FEEDBACK_DURATION,\n CELL_CONTEXT_MENU_VIEWPORT_MARGIN,\n CELL_CONTEXT_MENU_Z_INDEX,\n} from './constants';\n\ntype TRowOption = { key: string; label: React.ReactNode; isVisible?: boolean };\n\n/** Result of the per-row availability check for row actions. */\ntype TRowOptionsFilter =\n | { status: 'off' }\n | { status: 'loading' }\n | { status: 'ready'; available: Record<string, boolean> }\n | { status: 'failed' };\n\n/** One rendered menu line: a declared item, a row-action node supplied by the table, or the row-action placeholder. */\ntype TMenuRow =\n | { kind: 'item'; key: string; item: ICellContextMenuItem }\n | { kind: 'node'; key: string; node: React.ReactNode; withDividerBefore?: boolean }\n | { kind: 'skeleton'; key: string; withDividerBefore?: boolean };\n\ninterface CellContextMenuPortalProps {\n state: ICellContextMenuState | null;\n config?: ICellContextMenuConfig | null;\n /** The table's row actions, appended to the menu — same list the three-dot cell renders. */\n rowOptions?: TRowOption[] | ((rowData: Record<string, unknown>) => TRowOption[] | null) | null;\n /** Per-row availability check for `rowOptions`, mirroring the three-dot cell so both menus agree. */\n asyncRowOptionsFilter?: ((rowId: string) => Promise<Record<string, boolean>>) | null;\n /** Checked row ids, enabling the \"Copy selected rows\" item. */\n checkedIds?: (string | number)[];\n /** Table rows, used to build the text for selected rows that are scrolled out of view. */\n rows?: Record<string, unknown>[];\n /** Visible columns in display order, used to order the copied values. */\n columns?: IColumn[];\n /** The table's row link, enabling the \"Copy Link\" / \"Open in New Tab\" items. */\n rowLinkConfig?: IRowLinkConfig | null;\n onClose: () => void;\n}\n\n/** Clipboard write with a fallback for browsers / insecure contexts without the async clipboard API. */\nconst writeToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator?.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // fall through to the textarea fallback\n }\n\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand('copy');\n document.body.removeChild(textarea);\n return copied;\n } catch {\n return false;\n }\n};\n\n/** An already basename-resolved href (from `useHref`); the clipboard and a new tab both need a full URL. */\nconst toAbsoluteUrl = (href: string): string => {\n if (!href) return '';\n\n try {\n return new URL(href, window.location.origin).href;\n } catch {\n return '';\n }\n};\n\nconst resolveFlag = (\n flag: boolean | ((context: ICellContextMenuContext) => boolean) | undefined,\n context: ICellContextMenuContext,\n fallback: boolean,\n): boolean => {\n if (flag === undefined) return fallback;\n return typeof flag === 'function' ? flag(context) : flag;\n};\n\nconst MenuItemButton: React.FC<{\n item: ICellContextMenuItem;\n isDisabled: boolean;\n isActive: boolean;\n onSelect: () => void;\n onHover: () => void;\n}> = ({ item, isDisabled, isActive, onSelect, onHover }) => (\n <button\n type='button'\n role='menuitem'\n data-menu-item\n disabled={isDisabled}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={cn(\n 'flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none',\n isDisabled\n ? 'opacity-50 cursor-not-allowed'\n : cn(\n 'cursor-pointer',\n item.isDanger\n ? 'text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950'\n : 'text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600',\n ),\n )}\n onClick={onSelect}\n onMouseEnter={() => !isDisabled && onHover()}\n >\n {item.icon ? (\n <span className={cn('flex shrink-0 items-center', item.isDanger ? 'text-error-600 dark:text-error-400' : 'text-neutral-500 dark:text-black-300')}>\n {item.icon}\n </span>\n ) : null}\n <span className='flex-1 truncate'>{item.label}</span>\n {item.shortcut ? <span className='shrink-0 text-xs text-neutral-400 dark:text-black-300'>{item.shortcut}</span> : null}\n </button>\n);\n\n/**\n * Right-click menu for data cells. Rendered once per table and positioned at the\n * cursor; `DataCell` opens it through `openCellContextMenu` on the table context.\n */\nexport const CellContextMenuPortal: React.FC<CellContextMenuPortalProps> = ({\n state, config, rowOptions, asyncRowOptionsFilter, checkedIds, rows, columns, rowLinkConfig, onClose,\n}) => {\n const tableConfig = useTableConfig();\n const t = useMemo(() => tableConfig?.t ?? ((key: string) => key), [tableConfig]);\n const menuRef = useRef<HTMLDivElement>(null);\n const [position, setPosition] = useState<{ left: number; top: number } | null>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [copyState, setCopyState] = useState<{ key: string; isCopied: boolean } | null>(null);\n const [rowOptionsFilter, setRowOptionsFilter] = useState<TRowOptionsFilter>({ status: 'off' });\n const closeTimer = useRef<ReturnType<typeof setTimeout>>();\n\n const context = useMemo<ICellContextMenuContext | null>(\n () => (state ? { ...state.target, close: onClose } : null),\n [state, onClose],\n );\n\n const handleCopy = useCallback(\n async (key: string, text: string, menuContext: ICellContextMenuContext) => {\n if (copyState) return;\n\n const isCopied = await writeToClipboard(text);\n\n if (isCopied) {\n config?.onCopy?.(text, menuContext);\n tableConfig?.showNotification?.('success', t('Copied to clipboard'));\n } else {\n tableConfig?.showNotification?.('error', t('Could not copy to clipboard'));\n }\n\n // Confirmed inline instead of with a toast, so the menu owns its own feedback.\n setCopyState({ key, isCopied });\n closeTimer.current = setTimeout(() => onClose(), COPY_FEEDBACK_DURATION);\n },\n [config, tableConfig, t, onClose, copyState],\n );\n\n const buildCopyItem = useCallback(\n (key: string, label: string, text: string, icon?: React.ReactNode): ICellContextMenuItem => {\n const isDone = copyState?.key === key;\n\n return {\n key,\n label: !isDone ? label : copyState?.isCopied ? t('Copied') : t('Copy failed'),\n icon:\n isDone && copyState?.isCopied ? (\n <CheckIcon size={16} className='text-success-600 dark:text-success-400' />\n ) : (\n icon ?? <ContentCopyIcon size={16} />\n ),\n isDisabled: !text,\n keepOpenOnClick: true,\n onClick: (menuContext) => handleCopy(key, text, menuContext),\n };\n },\n [copyState, handleCopy, t],\n );\n\n const rowJson = useMemo(() => getRowJson(state?.target.rowData, columns), [state?.target.rowData, columns]);\n // Only while the menu is open — otherwise every checkbox tick would serialize the selection.\n const selectedRowsJson = useMemo(() => (state ? getSelectedRowsJson(rows, columns, checkedIds) : ''), [state, rows, columns, checkedIds]);\n const selectedCount = checkedIds?.length ?? 0;\n\n /** The router path from `linkTo`, before the router's basename (e.g. `/integrations`) is applied. */\n const rowLinkPath = useMemo(() => {\n if (!state || !rowLinkConfig?.isEnabled || !rowLinkConfig.linkTo || state.target.column?.disableRowClick) return '';\n\n return rowLinkConfig.linkTo(String(state.target.rowId), state.target.rowData) || '';\n }, [state, rowLinkConfig]);\n\n // `useHref` resolves `rowLinkPath` the same way a <Link> would, basename included — a manual\n // `new URL(path, location.href)` would silently drop a router basename like `/integrations`.\n const rowLinkResolvedHref = useHref(rowLinkPath || '/');\n\n /** The row link as an absolute URL — empty unless the table opted in, and never on a cell that opts out of the row link. */\n const rowLinkHref = useMemo(() => {\n if (!rowLinkPath) return '';\n\n return toAbsoluteUrl(rowLinkResolvedHref);\n }, [rowLinkPath, rowLinkResolvedHref]);\n\n const openInNewTab = useCallback(() => {\n if (rowLinkHref) window.open(rowLinkHref, '_blank', 'noopener,noreferrer');\n }, [rowLinkHref]);\n\n const items = useMemo<ICellContextMenuItem[]>(() => {\n if (!context) return [];\n\n const defaultItems: ICellContextMenuItem[] = config?.hideDefaultItems\n ? []\n : [\n buildCopyItem('copy-cell', config?.copyLabel ?? t('Copy Cell'), context.text),\n buildCopyItem('copy-row', t('Copy Row'), rowJson),\n ...(selectedCount > 0\n ? [\n buildCopyItem(\n 'copy-selected-rows',\n selectedCount === 1 ? t('Copy Selected Row') : `${t('Copy Selected Rows')} (${selectedCount})`,\n selectedRowsJson,\n ),\n ]\n : []),\n ...(rowLinkHref && !config?.hideLinkItems\n ? [\n {\n ...buildCopyItem('copy-link', t('Copy Link'), rowLinkHref, <LinkIcon size={16} />),\n withDividerBefore: true,\n },\n {\n key: 'open-in-new-tab',\n label: t('Open in New Tab'),\n icon: <OpenInNewIcon size={16} />,\n onClick: openInNewTab,\n },\n ]\n : []),\n ];\n\n const extraItems = typeof config?.items === 'function' ? config.items(context) : config?.items ?? [];\n\n return [...defaultItems, ...extraItems].filter((item) => resolveFlag(item.isVisible, context, true));\n }, [config, context, buildCopyItem, selectedCount, rowJson, selectedRowsJson, rowLinkHref, openInNewTab, t]);\n\n /** The table's own row actions, resolved for the right-clicked row. */\n const resolvedRowOptions = useMemo<TRowOption[]>(() => {\n if (!state || config?.includeRowOptions === false || !rowOptions) return [];\n\n const list = typeof rowOptions === 'function' ? rowOptions(state.target.rowData) : rowOptions;\n\n return (list ?? []).filter((option) => option.isVisible !== false);\n }, [state, rowOptions, config?.includeRowOptions]);\n\n const hasRowOptions = resolvedRowOptions.length > 0;\n\n /** Row actions can be gated per row by the API — ask before showing them, exactly as the three-dot cell does. */\n useEffect(() => {\n if (!state || !hasRowOptions || !asyncRowOptionsFilter) {\n setRowOptionsFilter({ status: 'off' });\n return;\n }\n\n let isCancelled = false;\n setRowOptionsFilter({ status: 'loading' });\n\n asyncRowOptionsFilter(String(state.target.rowId))\n .then((available) => !isCancelled && setRowOptionsFilter({ status: 'ready', available }))\n .catch(() => !isCancelled && setRowOptionsFilter({ status: 'failed' }));\n\n return () => {\n isCancelled = true;\n };\n }, [state, hasRowOptions, asyncRowOptionsFilter]);\n\n const allowedRowOptions = useMemo<TRowOption[]>(() => {\n if (rowOptionsFilter.status === 'off') return resolvedRowOptions;\n if (rowOptionsFilter.status !== 'ready') return [];\n\n const { available } = rowOptionsFilter;\n\n return resolvedRowOptions.filter((option) => available[option.key] ?? true);\n }, [resolvedRowOptions, rowOptionsFilter]);\n\n const menuRows = useMemo<TMenuRow[]>(() => {\n const itemRows: TMenuRow[] = items.map((item) => ({ kind: 'item', key: item.key, item }));\n const needsDivider = itemRows.length > 0;\n\n if (rowOptionsFilter.status === 'loading') {\n return [...itemRows, { kind: 'skeleton', key: 'row-options-loading', withDividerBefore: needsDivider }];\n }\n\n return [\n ...itemRows,\n ...allowedRowOptions.map<TMenuRow>((option, index) => ({\n kind: 'node',\n key: `row-option-${option.key}`,\n node: option.label,\n withDividerBefore: needsDivider && index === 0,\n })),\n ];\n }, [items, allowedRowOptions, rowOptionsFilter.status]);\n\n const isRowNavigable = useCallback(\n (row: TMenuRow): boolean => (row.kind === 'item' ? !(context && resolveFlag(row.item.isDisabled, context, false)) : row.kind === 'node'),\n [context],\n );\n\n const firstNavigableIndex = useMemo(() => menuRows.findIndex(isRowNavigable), [menuRows, isRowNavigable]);\n\n /** Clamp into the viewport once the menu has been measured; row actions can arrive after the first paint. */\n useLayoutEffect(() => {\n if (!state || !menuRef.current) {\n setPosition(null);\n return;\n }\n\n const { width, height } = menuRef.current.getBoundingClientRect();\n const margin = CELL_CONTEXT_MENU_VIEWPORT_MARGIN;\n const offset = CELL_CONTEXT_MENU_CURSOR_OFFSET;\n\n // Flip to the other side of the cursor when there is no room, then clamp.\n const left = state.x + width + margin > window.innerWidth ? state.x - width - offset : state.x + offset;\n const top = state.y + height + margin > window.innerHeight ? state.y - height - offset : state.y + offset;\n\n setPosition({\n left: Math.max(margin, Math.min(left, window.innerWidth - width - margin)),\n top: Math.max(margin, Math.min(top, window.innerHeight - height - margin)),\n });\n }, [state, menuRows.length]);\n\n useEffect(() => {\n setCopyState(null);\n return () => clearTimeout(closeTimer.current);\n }, [state]);\n\n useEffect(() => {\n if (!state) {\n setActiveIndex(-1);\n return;\n }\n setActiveIndex(firstNavigableIndex);\n }, [state, firstNavigableIndex]);\n\n /** Focus follows the active row so the menu is keyboard operable; row actions bring their own button. */\n useEffect(() => {\n if (!state || activeIndex < 0) return;\n\n const row = menuRef.current?.querySelectorAll<HTMLElement>('[data-menu-item]')[activeIndex];\n const focusTarget = row?.matches('button') ? row : row?.querySelector('button') ?? row;\n\n // preventScroll: a focus-driven scroll would immediately close the menu.\n focusTarget?.focus({ preventScroll: true });\n }, [state, activeIndex]);\n\n const moveActiveIndex = useCallback(\n (direction: 1 | -1) => {\n if (menuRows.length === 0) return;\n setActiveIndex((current) => {\n let next = current;\n for (let step = 0; step < menuRows.length; step += 1) {\n next = (next + direction + menuRows.length) % menuRows.length;\n if (isRowNavigable(menuRows[next])) return next;\n }\n return current;\n });\n },\n [menuRows, isRowNavigable],\n );\n\n useEffect(() => {\n if (!state) return;\n\n const handlePointerDown = (event: MouseEvent | TouchEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) onClose();\n };\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopPropagation();\n onClose();\n return;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n moveActiveIndex(event.key === 'ArrowDown' ? 1 : -1);\n }\n };\n // Any scroll (table viewport included) detaches the menu from its cell, so close it.\n const handleScroll = () => onClose();\n\n // Deferred so the right click that opened the menu does not immediately close it.\n const timeoutId = setTimeout(() => {\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('touchstart', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n window.addEventListener('resize', handleScroll);\n }, 0);\n\n return () => {\n clearTimeout(timeoutId);\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('touchstart', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('resize', handleScroll);\n };\n }, [state, onClose, moveActiveIndex]);\n\n if (!state || !context || menuRows.length === 0) return null;\n\n if (tableConfig?.renderCellContextMenu) {\n return tableConfig.renderCellContextMenu({ state, context, items, rowOptions: allowedRowOptions, onClose }) as JSX.Element;\n }\n\n const handleItemClick = async (item: ICellContextMenuItem): Promise<void> => {\n if (resolveFlag(item.isDisabled, context, false)) return;\n if (!item.keepOpenOnClick) onClose();\n await item.onClick?.(context);\n };\n\n return createPortal(\n <div\n ref={menuRef}\n role='menu'\n aria-label={t('Cell actions')}\n data-testid='cell-context-menu'\n className={cn(\n 'fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter',\n 'bg-white dark:bg-black-700',\n 'border border-neutral-200 dark:border-black-600',\n 'shadow-lg dark:shadow-black/40',\n config?.className,\n )}\n style={{\n left: position?.left ?? state.x,\n top: position?.top ?? state.y,\n zIndex: CELL_CONTEXT_MENU_Z_INDEX,\n // Hidden until measured so the flip/clamp never flashes at the wrong spot.\n visibility: position ? 'visible' : 'hidden',\n }}\n onContextMenu={(event) => event.preventDefault()}\n >\n {menuRows.map((row, index) => (\n <React.Fragment key={row.key}>\n {(row.kind === 'item' ? row.item.withDividerBefore && index > 0 : row.withDividerBefore) ? (\n <div className='my-1 h-px bg-neutral-200 dark:bg-black-600' />\n ) : null}\n {row.kind === 'item' ? (\n <MenuItemButton\n item={row.item}\n isDisabled={resolveFlag(row.item.isDisabled, context, false)}\n isActive={index === activeIndex}\n onSelect={() => void handleItemClick(row.item)}\n onHover={() => setActiveIndex(index)}\n />\n ) : row.kind === 'skeleton' ? (\n <div className='px-3 py-2' data-testid='cell-context-menu-loading'>\n <div className='h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600' />\n </div>\n ) : (\n /* Row actions are rendered as the table supplied them — they carry their own button and handler. */\n <div data-menu-item tabIndex={-1} className='outline-none [&_button]:w-full' onClick={onClose} onMouseEnter={() => setActiveIndex(index)}>\n {row.node}\n </div>\n )}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n );\n};\n"],"names":["writeToClipboard","text","textarea","copied","toAbsoluteUrl","href","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","rowLinkConfig","onClose","tableConfig","useTableConfig","t","useMemo","key","menuRef","useRef","position","setPosition","useState","activeIndex","setActiveIndex","copyState","setCopyState","rowOptionsFilter","setRowOptionsFilter","closeTimer","handleCopy","useCallback","menuContext","isCopied","COPY_FEEDBACK_DURATION","buildCopyItem","label","icon","isDone","CheckIcon","ContentCopyIcon","rowJson","getRowJson","selectedRowsJson","getSelectedRowsJson","selectedCount","rowLinkPath","rowLinkResolvedHref","useHref","rowLinkHref","openInNewTab","items","defaultItems","LinkIcon","OpenInNewIcon","extraItems","resolvedRowOptions","option","hasRowOptions","useEffect","isCancelled","available","allowedRowOptions","menuRows","itemRows","needsDivider","index","isRowNavigable","row","firstNavigableIndex","useLayoutEffect","width","height","margin","CELL_CONTEXT_MENU_VIEWPORT_MARGIN","offset","CELL_CONTEXT_MENU_CURSOR_OFFSET","left","top","moveActiveIndex","direction","current","next","step","handlePointerDown","event","handleKeyDown","handleScroll","timeoutId","handleItemClick","createPortal","CELL_CONTEXT_MENU_Z_INDEX","React"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
- import { jsx as c, jsxs as Y } from "react/jsx-runtime";
2
- import { useTableConfig as Q } from "../../../providers/design-system-provider/hooks.es.js";
3
- import { getRowJson as ee, getSelectedRowsJson as te } from "./copy-text.es.js";
1
+ import { jsx as c, jsxs as Q } from "react/jsx-runtime";
2
+ import { useTableConfig as te } from "../../../providers/design-system-provider/hooks.es.js";
3
+ import { getRowJson as ne, getSelectedRowsJson as re } from "./copy-text.es.js";
4
4
  import S from "../../../_virtual/index.es.js";
5
- import ne, { useMemo as f, useRef as G, useState as O, useCallback as C, useEffect as E, useLayoutEffect as re } from "react";
6
- import { createPortal as oe } from "react-dom";
7
- import { COPY_FEEDBACK_DURATION as ie, CELL_CONTEXT_MENU_VIEWPORT_MARGIN as le, CELL_CONTEXT_MENU_Z_INDEX as se, CELL_CONTEXT_MENU_CURSOR_OFFSET as ae } from "./constants.es.js";
8
- import { CheckIcon as ce, ContentCopyIcon as de, LinkIcon as ue, OpenInNewIcon as me } from "../../icon/icons.generated.es.js";
9
- const fe = async (t) => {
5
+ import oe, { useMemo as f, useRef as Z, useState as O, useCallback as C, useEffect as E, useLayoutEffect as ie } from "react";
6
+ import { createPortal as le } from "react-dom";
7
+ import { useHref as se } from "react-router-dom";
8
+ import { COPY_FEEDBACK_DURATION as ae, CELL_CONTEXT_MENU_VIEWPORT_MARGIN as ce, CELL_CONTEXT_MENU_Z_INDEX as ue, CELL_CONTEXT_MENU_CURSOR_OFFSET as de } from "./constants.es.js";
9
+ import { CheckIcon as me, ContentCopyIcon as fe, LinkIcon as pe, OpenInNewIcon as be } from "../../icon/icons.generated.es.js";
10
+ const we = async (t) => {
10
11
  try {
11
12
  if (navigator?.clipboard?.writeText)
12
13
  return await navigator.clipboard.writeText(t), !0;
@@ -15,19 +16,19 @@ const fe = async (t) => {
15
16
  try {
16
17
  const o = document.createElement("textarea");
17
18
  o.value = t, o.setAttribute("readonly", ""), o.style.position = "fixed", o.style.opacity = "0", document.body.appendChild(o), o.select();
18
- const d = document.execCommand("copy");
19
- return document.body.removeChild(o), d;
19
+ const u = document.execCommand("copy");
20
+ return document.body.removeChild(o), u;
20
21
  } catch {
21
22
  return !1;
22
23
  }
23
- }, pe = (t) => {
24
+ }, he = (t) => {
24
25
  if (!t) return "";
25
26
  try {
26
- return new URL(t, window.location.href).href;
27
+ return new URL(t, window.location.origin).href;
27
28
  } catch {
28
29
  return "";
29
30
  }
30
- }, _ = (t, o, d) => t === void 0 ? d : typeof t == "function" ? t(o) : t, be = ({ item: t, isDisabled: o, isActive: d, onSelect: y, onHover: x }) => /* @__PURE__ */ Y(
31
+ }, _ = (t, o, u) => t === void 0 ? u : typeof t == "function" ? t(o) : t, ke = ({ item: t, isDisabled: o, isActive: u, onSelect: y, onHover: x }) => /* @__PURE__ */ Q(
31
32
  "button",
32
33
  {
33
34
  type: "button",
@@ -35,7 +36,7 @@ const fe = async (t) => {
35
36
  "data-menu-item": !0,
36
37
  disabled: o,
37
38
  "aria-disabled": o,
38
- tabIndex: d ? 0 : -1,
39
+ tabIndex: u ? 0 : -1,
39
40
  className: S(
40
41
  "flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",
41
42
  o ? "opacity-50 cursor-not-allowed" : S(
@@ -51,71 +52,71 @@ const fe = async (t) => {
51
52
  t.shortcut ? /* @__PURE__ */ c("span", { className: "shrink-0 text-xs text-neutral-400 dark:text-black-300", children: t.shortcut }) : null
52
53
  ]
53
54
  }
54
- ), Ee = ({
55
+ ), Re = ({
55
56
  state: t,
56
57
  config: o,
57
- rowOptions: d,
58
+ rowOptions: u,
58
59
  asyncRowOptionsFilter: y,
59
60
  checkedIds: x,
60
- rows: P,
61
+ rows: H,
61
62
  columns: N,
62
63
  rowLinkConfig: I,
63
- onClose: u
64
+ onClose: d
64
65
  }) => {
65
- const p = Q(), l = f(() => p?.t ?? ((e) => e), [p]), b = G(null), [A, F] = O(null), [D, v] = O(-1), [h, H] = O(null), [w, R] = O({ status: "off" }), J = G(), s = f(
66
- () => t ? { ...t.target, close: u } : null,
67
- [t, u]
68
- ), X = C(
66
+ const p = te(), l = f(() => p?.t ?? ((e) => e), [p]), b = Z(null), [A, F] = O(null), [D, v] = O(-1), [w, J] = O(null), [h, R] = O({ status: "off" }), X = Z(), s = f(
67
+ () => t ? { ...t.target, close: d } : null,
68
+ [t, d]
69
+ ), V = C(
69
70
  async (e, n, r) => {
70
- if (h) return;
71
- const i = await fe(n);
72
- i ? (o?.onCopy?.(n, r), p?.showNotification?.("success", l("Copied to clipboard"))) : p?.showNotification?.("error", l("Could not copy to clipboard")), H({ key: e, isCopied: i }), J.current = setTimeout(() => u(), ie);
71
+ if (w) return;
72
+ const i = await we(n);
73
+ i ? (o?.onCopy?.(n, r), p?.showNotification?.("success", l("Copied to clipboard"))) : p?.showNotification?.("error", l("Could not copy to clipboard")), J({ key: e, isCopied: i }), X.current = setTimeout(() => d(), ae);
73
74
  },
74
- [o, p, l, u, h]
75
+ [o, p, l, d, w]
75
76
  ), g = C(
76
77
  (e, n, r, i) => {
77
- const a = h?.key === e;
78
+ const a = w?.key === e;
78
79
  return {
79
80
  key: e,
80
- label: a ? h?.isCopied ? l("Copied") : l("Copy failed") : n,
81
- icon: a && h?.isCopied ? /* @__PURE__ */ c(ce, { size: 16, className: "text-success-600 dark:text-success-400" }) : i ?? /* @__PURE__ */ c(de, { size: 16 }),
81
+ label: a ? w?.isCopied ? l("Copied") : l("Copy failed") : n,
82
+ icon: a && w?.isCopied ? /* @__PURE__ */ c(me, { size: 16, className: "text-success-600 dark:text-success-400" }) : i ?? /* @__PURE__ */ c(fe, { size: 16 }),
82
83
  isDisabled: !r,
83
84
  keepOpenOnClick: !0,
84
- onClick: (z) => X(e, r, z)
85
+ onClick: (z) => V(e, r, z)
85
86
  };
86
87
  },
87
- [h, X, l]
88
- ), V = f(() => ee(t?.target.rowData, N), [t?.target.rowData, N]), W = f(() => t ? te(P, N, x) : "", [t, P, N, x]), T = x?.length ?? 0, k = f(() => !t || !I?.isEnabled || !I.linkTo || t.target.column?.disableRowClick ? "" : pe(I.linkTo(String(t.target.rowId), t.target.rowData)), [t, I]), $ = C(() => {
88
+ [w, V, l]
89
+ ), W = f(() => ne(t?.target.rowData, N), [t?.target.rowData, N]), $ = f(() => t ? re(H, N, x) : "", [t, H, N, x]), T = x?.length ?? 0, B = f(() => !t || !I?.isEnabled || !I.linkTo || t.target.column?.disableRowClick ? "" : I.linkTo(String(t.target.rowId), t.target.rowData) || "", [t, I]), j = se(B || "/"), k = f(() => B ? he(j) : "", [B, j]), q = C(() => {
89
90
  k && window.open(k, "_blank", "noopener,noreferrer");
90
- }, [k]), B = f(() => {
91
+ }, [k]), P = f(() => {
91
92
  if (!s) return [];
92
93
  const e = o?.hideDefaultItems ? [] : [
93
94
  g("copy-cell", o?.copyLabel ?? l("Copy Cell"), s.text),
94
- g("copy-row", l("Copy Row"), V),
95
+ g("copy-row", l("Copy Row"), W),
95
96
  ...T > 0 ? [
96
97
  g(
97
98
  "copy-selected-rows",
98
99
  T === 1 ? l("Copy Selected Row") : `${l("Copy Selected Rows")} (${T})`,
99
- W
100
+ $
100
101
  )
101
102
  ] : [],
102
103
  ...k && !o?.hideLinkItems ? [
103
104
  {
104
- ...g("copy-link", l("Copy Link"), k, /* @__PURE__ */ c(ue, { size: 16 })),
105
+ ...g("copy-link", l("Copy Link"), k, /* @__PURE__ */ c(pe, { size: 16 })),
105
106
  withDividerBefore: !0
106
107
  },
107
108
  {
108
109
  key: "open-in-new-tab",
109
110
  label: l("Open in New Tab"),
110
- icon: /* @__PURE__ */ c(me, { size: 16 }),
111
- onClick: $
111
+ icon: /* @__PURE__ */ c(be, { size: 16 }),
112
+ onClick: q
112
113
  }
113
114
  ] : []
114
115
  ], n = typeof o?.items == "function" ? o.items(s) : o?.items ?? [];
115
116
  return [...e, ...n].filter((r) => _(r.isVisible, s, !0));
116
- }, [o, s, g, T, V, W, k, $, l]), L = f(() => !t || o?.includeRowOptions === !1 || !d ? [] : ((typeof d == "function" ? d(t.target.rowData) : d) ?? []).filter((n) => n.isVisible !== !1), [t, d, o?.includeRowOptions]), j = L.length > 0;
117
+ }, [o, s, g, T, W, $, k, q, l]), L = f(() => !t || o?.includeRowOptions === !1 || !u ? [] : ((typeof u == "function" ? u(t.target.rowData) : u) ?? []).filter((n) => n.isVisible !== !1), [t, u, o?.includeRowOptions]), K = L.length > 0;
117
118
  E(() => {
118
- if (!t || !j || !y) {
119
+ if (!t || !K || !y) {
119
120
  R({ status: "off" });
120
121
  return;
121
122
  }
@@ -123,15 +124,15 @@ const fe = async (t) => {
123
124
  return R({ status: "loading" }), y(String(t.target.rowId)).then((n) => !e && R({ status: "ready", available: n })).catch(() => !e && R({ status: "failed" })), () => {
124
125
  e = !0;
125
126
  };
126
- }, [t, j, y]);
127
+ }, [t, K, y]);
127
128
  const U = f(() => {
128
- if (w.status === "off") return L;
129
- if (w.status !== "ready") return [];
130
- const { available: e } = w;
129
+ if (h.status === "off") return L;
130
+ if (h.status !== "ready") return [];
131
+ const { available: e } = h;
131
132
  return L.filter((n) => e[n.key] ?? !0);
132
- }, [L, w]), m = f(() => {
133
- const e = B.map((r) => ({ kind: "item", key: r.key, item: r })), n = e.length > 0;
134
- return w.status === "loading" ? [...e, { kind: "skeleton", key: "row-options-loading", withDividerBefore: n }] : [
133
+ }, [L, h]), m = f(() => {
134
+ const e = P.map((r) => ({ kind: "item", key: r.key, item: r })), n = e.length > 0;
135
+ return h.status === "loading" ? [...e, { kind: "skeleton", key: "row-options-loading", withDividerBefore: n }] : [
135
136
  ...e,
136
137
  ...U.map((r, i) => ({
137
138
  kind: "node",
@@ -140,32 +141,32 @@ const fe = async (t) => {
140
141
  withDividerBefore: n && i === 0
141
142
  }))
142
143
  ];
143
- }, [B, U, w.status]), M = C(
144
+ }, [P, U, h.status]), M = C(
144
145
  (e) => e.kind === "item" ? !(s && _(e.item.isDisabled, s, !1)) : e.kind === "node",
145
146
  [s]
146
- ), q = f(() => m.findIndex(M), [m, M]);
147
- re(() => {
147
+ ), G = f(() => m.findIndex(M), [m, M]);
148
+ ie(() => {
148
149
  if (!t || !b.current) {
149
150
  F(null);
150
151
  return;
151
152
  }
152
- const { width: e, height: n } = b.current.getBoundingClientRect(), r = le, i = ae, a = t.x + e + r > window.innerWidth ? t.x - e - i : t.x + i, z = t.y + n + r > window.innerHeight ? t.y - n - i : t.y + i;
153
+ const { width: e, height: n } = b.current.getBoundingClientRect(), r = ce, i = de, a = t.x + e + r > window.innerWidth ? t.x - e - i : t.x + i, z = t.y + n + r > window.innerHeight ? t.y - n - i : t.y + i;
153
154
  F({
154
155
  left: Math.max(r, Math.min(a, window.innerWidth - e - r)),
155
156
  top: Math.max(r, Math.min(z, window.innerHeight - n - r))
156
157
  });
157
- }, [t, m.length]), E(() => (H(null), () => clearTimeout(J.current)), [t]), E(() => {
158
+ }, [t, m.length]), E(() => (J(null), () => clearTimeout(X.current)), [t]), E(() => {
158
159
  if (!t) {
159
160
  v(-1);
160
161
  return;
161
162
  }
162
- v(q);
163
- }, [t, q]), E(() => {
163
+ v(G);
164
+ }, [t, G]), E(() => {
164
165
  if (!t || D < 0) return;
165
166
  const e = b.current?.querySelectorAll("[data-menu-item]")[D];
166
167
  (e?.matches("button") ? e : e?.querySelector("button") ?? e)?.focus({ preventScroll: !0 });
167
168
  }, [t, D]);
168
- const K = C(
169
+ const Y = C(
169
170
  (e) => {
170
171
  m.length !== 0 && v((n) => {
171
172
  let r = n;
@@ -179,26 +180,26 @@ const fe = async (t) => {
179
180
  if (E(() => {
180
181
  if (!t) return;
181
182
  const e = (a) => {
182
- b.current && !b.current.contains(a.target) && u();
183
+ b.current && !b.current.contains(a.target) && d();
183
184
  }, n = (a) => {
184
185
  if (a.key === "Escape") {
185
- a.stopPropagation(), u();
186
+ a.stopPropagation(), d();
186
187
  return;
187
188
  }
188
- (a.key === "ArrowDown" || a.key === "ArrowUp") && (a.preventDefault(), K(a.key === "ArrowDown" ? 1 : -1));
189
- }, r = () => u(), i = setTimeout(() => {
189
+ (a.key === "ArrowDown" || a.key === "ArrowUp") && (a.preventDefault(), Y(a.key === "ArrowDown" ? 1 : -1));
190
+ }, r = () => d(), i = setTimeout(() => {
190
191
  document.addEventListener("mousedown", e), document.addEventListener("touchstart", e), document.addEventListener("keydown", n), document.addEventListener("scroll", r, !0), window.addEventListener("resize", r);
191
192
  }, 0);
192
193
  return () => {
193
194
  clearTimeout(i), document.removeEventListener("mousedown", e), document.removeEventListener("touchstart", e), document.removeEventListener("keydown", n), document.removeEventListener("scroll", r, !0), window.removeEventListener("resize", r);
194
195
  };
195
- }, [t, u, K]), !t || !s || m.length === 0) return null;
196
+ }, [t, d, Y]), !t || !s || m.length === 0) return null;
196
197
  if (p?.renderCellContextMenu)
197
- return p.renderCellContextMenu({ state: t, context: s, items: B, rowOptions: U, onClose: u });
198
- const Z = async (e) => {
199
- _(e.isDisabled, s, !1) || (e.keepOpenOnClick || u(), await e.onClick?.(s));
198
+ return p.renderCellContextMenu({ state: t, context: s, items: P, rowOptions: U, onClose: d });
199
+ const ee = async (e) => {
200
+ _(e.isDisabled, s, !1) || (e.keepOpenOnClick || d(), await e.onClick?.(s));
200
201
  };
201
- return oe(
202
+ return le(
202
203
  /* @__PURE__ */ c(
203
204
  "div",
204
205
  {
@@ -216,25 +217,25 @@ const fe = async (t) => {
216
217
  style: {
217
218
  left: A?.left ?? t.x,
218
219
  top: A?.top ?? t.y,
219
- zIndex: se,
220
+ zIndex: ue,
220
221
  // Hidden until measured so the flip/clamp never flashes at the wrong spot.
221
222
  visibility: A ? "visible" : "hidden"
222
223
  },
223
224
  onContextMenu: (e) => e.preventDefault(),
224
- children: m.map((e, n) => /* @__PURE__ */ Y(ne.Fragment, { children: [
225
+ children: m.map((e, n) => /* @__PURE__ */ Q(oe.Fragment, { children: [
225
226
  (e.kind === "item" ? e.item.withDividerBefore && n > 0 : e.withDividerBefore) ? /* @__PURE__ */ c("div", { className: "my-1 h-px bg-neutral-200 dark:bg-black-600" }) : null,
226
227
  e.kind === "item" ? /* @__PURE__ */ c(
227
- be,
228
+ ke,
228
229
  {
229
230
  item: e.item,
230
231
  isDisabled: _(e.item.isDisabled, s, !1),
231
232
  isActive: n === D,
232
- onSelect: () => void Z(e.item),
233
+ onSelect: () => void ee(e.item),
233
234
  onHover: () => v(n)
234
235
  }
235
236
  ) : e.kind === "skeleton" ? /* @__PURE__ */ c("div", { className: "px-3 py-2", "data-testid": "cell-context-menu-loading", children: /* @__PURE__ */ c("div", { className: "h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600" }) }) : (
236
237
  /* Row actions are rendered as the table supplied them — they carry their own button and handler. */
237
- /* @__PURE__ */ c("div", { "data-menu-item": !0, tabIndex: -1, className: "outline-none [&_button]:w-full", onClick: u, onMouseEnter: () => v(n), children: e.node })
238
+ /* @__PURE__ */ c("div", { "data-menu-item": !0, tabIndex: -1, className: "outline-none [&_button]:w-full", onClick: d, onMouseEnter: () => v(n), children: e.node })
238
239
  )
239
240
  ] }, e.key))
240
241
  }
@@ -243,6 +244,6 @@ const fe = async (t) => {
243
244
  );
244
245
  };
245
246
  export {
246
- Ee as CellContextMenuPortal
247
+ Re as CellContextMenuPortal
247
248
  };
248
249
  //# sourceMappingURL=CellContextMenuPortal.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CellContextMenuPortal.es.js","sources":["../../../../src/components/data-display/infinite-table/CellContextMenuPortal.tsx"],"sourcesContent":["import { useTableConfig } from '../../../providers/design-system-provider/hooks';\nimport { CheckIcon, ContentCopyIcon, LinkIcon, OpenInNewIcon } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\n IRowLinkConfig,\n} from './types';\nimport { getRowJson, getSelectedRowsJson } from './copy-text';\nimport cn from 'classnames';\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n CELL_CONTEXT_MENU_CURSOR_OFFSET,\n COPY_FEEDBACK_DURATION,\n CELL_CONTEXT_MENU_VIEWPORT_MARGIN,\n CELL_CONTEXT_MENU_Z_INDEX,\n} from './constants';\n\ntype TRowOption = { key: string; label: React.ReactNode; isVisible?: boolean };\n\n/** Result of the per-row availability check for row actions. */\ntype TRowOptionsFilter =\n | { status: 'off' }\n | { status: 'loading' }\n | { status: 'ready'; available: Record<string, boolean> }\n | { status: 'failed' };\n\n/** One rendered menu line: a declared item, a row-action node supplied by the table, or the row-action placeholder. */\ntype TMenuRow =\n | { kind: 'item'; key: string; item: ICellContextMenuItem }\n | { kind: 'node'; key: string; node: React.ReactNode; withDividerBefore?: boolean }\n | { kind: 'skeleton'; key: string; withDividerBefore?: boolean };\n\ninterface CellContextMenuPortalProps {\n state: ICellContextMenuState | null;\n config?: ICellContextMenuConfig | null;\n /** The table's row actions, appended to the menu — same list the three-dot cell renders. */\n rowOptions?: TRowOption[] | ((rowData: Record<string, unknown>) => TRowOption[] | null) | null;\n /** Per-row availability check for `rowOptions`, mirroring the three-dot cell so both menus agree. */\n asyncRowOptionsFilter?: ((rowId: string) => Promise<Record<string, boolean>>) | null;\n /** Checked row ids, enabling the \"Copy selected rows\" item. */\n checkedIds?: (string | number)[];\n /** Table rows, used to build the text for selected rows that are scrolled out of view. */\n rows?: Record<string, unknown>[];\n /** Visible columns in display order, used to order the copied values. */\n columns?: IColumn[];\n /** The table's row link, enabling the \"Copy Link\" / \"Open in New Tab\" items. */\n rowLinkConfig?: IRowLinkConfig | null;\n onClose: () => void;\n}\n\n/** Clipboard write with a fallback for browsers / insecure contexts without the async clipboard API. */\nconst writeToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator?.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // fall through to the textarea fallback\n }\n\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand('copy');\n document.body.removeChild(textarea);\n return copied;\n } catch {\n return false;\n }\n};\n\n/** `linkTo` returns a router path; the clipboard and a new tab both need a full URL. */\nconst toAbsoluteUrl = (path: string): string => {\n if (!path) return '';\n\n try {\n return new URL(path, window.location.href).href;\n } catch {\n return '';\n }\n};\n\nconst resolveFlag = (\n flag: boolean | ((context: ICellContextMenuContext) => boolean) | undefined,\n context: ICellContextMenuContext,\n fallback: boolean,\n): boolean => {\n if (flag === undefined) return fallback;\n return typeof flag === 'function' ? flag(context) : flag;\n};\n\nconst MenuItemButton: React.FC<{\n item: ICellContextMenuItem;\n isDisabled: boolean;\n isActive: boolean;\n onSelect: () => void;\n onHover: () => void;\n}> = ({ item, isDisabled, isActive, onSelect, onHover }) => (\n <button\n type='button'\n role='menuitem'\n data-menu-item\n disabled={isDisabled}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={cn(\n 'flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none',\n isDisabled\n ? 'opacity-50 cursor-not-allowed'\n : cn(\n 'cursor-pointer',\n item.isDanger\n ? 'text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950'\n : 'text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600',\n ),\n )}\n onClick={onSelect}\n onMouseEnter={() => !isDisabled && onHover()}\n >\n {item.icon ? (\n <span className={cn('flex shrink-0 items-center', item.isDanger ? 'text-error-600 dark:text-error-400' : 'text-neutral-500 dark:text-black-300')}>\n {item.icon}\n </span>\n ) : null}\n <span className='flex-1 truncate'>{item.label}</span>\n {item.shortcut ? <span className='shrink-0 text-xs text-neutral-400 dark:text-black-300'>{item.shortcut}</span> : null}\n </button>\n);\n\n/**\n * Right-click menu for data cells. Rendered once per table and positioned at the\n * cursor; `DataCell` opens it through `openCellContextMenu` on the table context.\n */\nexport const CellContextMenuPortal: React.FC<CellContextMenuPortalProps> = ({\n state, config, rowOptions, asyncRowOptionsFilter, checkedIds, rows, columns, rowLinkConfig, onClose,\n}) => {\n const tableConfig = useTableConfig();\n const t = useMemo(() => tableConfig?.t ?? ((key: string) => key), [tableConfig]);\n const menuRef = useRef<HTMLDivElement>(null);\n const [position, setPosition] = useState<{ left: number; top: number } | null>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [copyState, setCopyState] = useState<{ key: string; isCopied: boolean } | null>(null);\n const [rowOptionsFilter, setRowOptionsFilter] = useState<TRowOptionsFilter>({ status: 'off' });\n const closeTimer = useRef<ReturnType<typeof setTimeout>>();\n\n const context = useMemo<ICellContextMenuContext | null>(\n () => (state ? { ...state.target, close: onClose } : null),\n [state, onClose],\n );\n\n const handleCopy = useCallback(\n async (key: string, text: string, menuContext: ICellContextMenuContext) => {\n if (copyState) return;\n\n const isCopied = await writeToClipboard(text);\n\n if (isCopied) {\n config?.onCopy?.(text, menuContext);\n tableConfig?.showNotification?.('success', t('Copied to clipboard'));\n } else {\n tableConfig?.showNotification?.('error', t('Could not copy to clipboard'));\n }\n\n // Confirmed inline instead of with a toast, so the menu owns its own feedback.\n setCopyState({ key, isCopied });\n closeTimer.current = setTimeout(() => onClose(), COPY_FEEDBACK_DURATION);\n },\n [config, tableConfig, t, onClose, copyState],\n );\n\n const buildCopyItem = useCallback(\n (key: string, label: string, text: string, icon?: React.ReactNode): ICellContextMenuItem => {\n const isDone = copyState?.key === key;\n\n return {\n key,\n label: !isDone ? label : copyState?.isCopied ? t('Copied') : t('Copy failed'),\n icon:\n isDone && copyState?.isCopied ? (\n <CheckIcon size={16} className='text-success-600 dark:text-success-400' />\n ) : (\n icon ?? <ContentCopyIcon size={16} />\n ),\n isDisabled: !text,\n keepOpenOnClick: true,\n onClick: (menuContext) => handleCopy(key, text, menuContext),\n };\n },\n [copyState, handleCopy, t],\n );\n\n const rowJson = useMemo(() => getRowJson(state?.target.rowData, columns), [state?.target.rowData, columns]);\n // Only while the menu is open — otherwise every checkbox tick would serialize the selection.\n const selectedRowsJson = useMemo(() => (state ? getSelectedRowsJson(rows, columns, checkedIds) : ''), [state, rows, columns, checkedIds]);\n const selectedCount = checkedIds?.length ?? 0;\n\n /** The row link as an absolute URL — empty unless the table opted in, and never on a cell that opts out of the row link. */\n const rowLinkHref = useMemo(() => {\n if (!state || !rowLinkConfig?.isEnabled || !rowLinkConfig.linkTo || state.target.column?.disableRowClick) return '';\n\n return toAbsoluteUrl(rowLinkConfig.linkTo(String(state.target.rowId), state.target.rowData));\n }, [state, rowLinkConfig]);\n\n const openInNewTab = useCallback(() => {\n if (rowLinkHref) window.open(rowLinkHref, '_blank', 'noopener,noreferrer');\n }, [rowLinkHref]);\n\n const items = useMemo<ICellContextMenuItem[]>(() => {\n if (!context) return [];\n\n const defaultItems: ICellContextMenuItem[] = config?.hideDefaultItems\n ? []\n : [\n buildCopyItem('copy-cell', config?.copyLabel ?? t('Copy Cell'), context.text),\n buildCopyItem('copy-row', t('Copy Row'), rowJson),\n ...(selectedCount > 0\n ? [\n buildCopyItem(\n 'copy-selected-rows',\n selectedCount === 1 ? t('Copy Selected Row') : `${t('Copy Selected Rows')} (${selectedCount})`,\n selectedRowsJson,\n ),\n ]\n : []),\n ...(rowLinkHref && !config?.hideLinkItems\n ? [\n {\n ...buildCopyItem('copy-link', t('Copy Link'), rowLinkHref, <LinkIcon size={16} />),\n withDividerBefore: true,\n },\n {\n key: 'open-in-new-tab',\n label: t('Open in New Tab'),\n icon: <OpenInNewIcon size={16} />,\n onClick: openInNewTab,\n },\n ]\n : []),\n ];\n\n const extraItems = typeof config?.items === 'function' ? config.items(context) : config?.items ?? [];\n\n return [...defaultItems, ...extraItems].filter((item) => resolveFlag(item.isVisible, context, true));\n }, [config, context, buildCopyItem, selectedCount, rowJson, selectedRowsJson, rowLinkHref, openInNewTab, t]);\n\n /** The table's own row actions, resolved for the right-clicked row. */\n const resolvedRowOptions = useMemo<TRowOption[]>(() => {\n if (!state || config?.includeRowOptions === false || !rowOptions) return [];\n\n const list = typeof rowOptions === 'function' ? rowOptions(state.target.rowData) : rowOptions;\n\n return (list ?? []).filter((option) => option.isVisible !== false);\n }, [state, rowOptions, config?.includeRowOptions]);\n\n const hasRowOptions = resolvedRowOptions.length > 0;\n\n /** Row actions can be gated per row by the API — ask before showing them, exactly as the three-dot cell does. */\n useEffect(() => {\n if (!state || !hasRowOptions || !asyncRowOptionsFilter) {\n setRowOptionsFilter({ status: 'off' });\n return;\n }\n\n let isCancelled = false;\n setRowOptionsFilter({ status: 'loading' });\n\n asyncRowOptionsFilter(String(state.target.rowId))\n .then((available) => !isCancelled && setRowOptionsFilter({ status: 'ready', available }))\n .catch(() => !isCancelled && setRowOptionsFilter({ status: 'failed' }));\n\n return () => {\n isCancelled = true;\n };\n }, [state, hasRowOptions, asyncRowOptionsFilter]);\n\n const allowedRowOptions = useMemo<TRowOption[]>(() => {\n if (rowOptionsFilter.status === 'off') return resolvedRowOptions;\n if (rowOptionsFilter.status !== 'ready') return [];\n\n const { available } = rowOptionsFilter;\n\n return resolvedRowOptions.filter((option) => available[option.key] ?? true);\n }, [resolvedRowOptions, rowOptionsFilter]);\n\n const menuRows = useMemo<TMenuRow[]>(() => {\n const itemRows: TMenuRow[] = items.map((item) => ({ kind: 'item', key: item.key, item }));\n const needsDivider = itemRows.length > 0;\n\n if (rowOptionsFilter.status === 'loading') {\n return [...itemRows, { kind: 'skeleton', key: 'row-options-loading', withDividerBefore: needsDivider }];\n }\n\n return [\n ...itemRows,\n ...allowedRowOptions.map<TMenuRow>((option, index) => ({\n kind: 'node',\n key: `row-option-${option.key}`,\n node: option.label,\n withDividerBefore: needsDivider && index === 0,\n })),\n ];\n }, [items, allowedRowOptions, rowOptionsFilter.status]);\n\n const isRowNavigable = useCallback(\n (row: TMenuRow): boolean => (row.kind === 'item' ? !(context && resolveFlag(row.item.isDisabled, context, false)) : row.kind === 'node'),\n [context],\n );\n\n const firstNavigableIndex = useMemo(() => menuRows.findIndex(isRowNavigable), [menuRows, isRowNavigable]);\n\n /** Clamp into the viewport once the menu has been measured; row actions can arrive after the first paint. */\n useLayoutEffect(() => {\n if (!state || !menuRef.current) {\n setPosition(null);\n return;\n }\n\n const { width, height } = menuRef.current.getBoundingClientRect();\n const margin = CELL_CONTEXT_MENU_VIEWPORT_MARGIN;\n const offset = CELL_CONTEXT_MENU_CURSOR_OFFSET;\n\n // Flip to the other side of the cursor when there is no room, then clamp.\n const left = state.x + width + margin > window.innerWidth ? state.x - width - offset : state.x + offset;\n const top = state.y + height + margin > window.innerHeight ? state.y - height - offset : state.y + offset;\n\n setPosition({\n left: Math.max(margin, Math.min(left, window.innerWidth - width - margin)),\n top: Math.max(margin, Math.min(top, window.innerHeight - height - margin)),\n });\n }, [state, menuRows.length]);\n\n useEffect(() => {\n setCopyState(null);\n return () => clearTimeout(closeTimer.current);\n }, [state]);\n\n useEffect(() => {\n if (!state) {\n setActiveIndex(-1);\n return;\n }\n setActiveIndex(firstNavigableIndex);\n }, [state, firstNavigableIndex]);\n\n /** Focus follows the active row so the menu is keyboard operable; row actions bring their own button. */\n useEffect(() => {\n if (!state || activeIndex < 0) return;\n\n const row = menuRef.current?.querySelectorAll<HTMLElement>('[data-menu-item]')[activeIndex];\n const focusTarget = row?.matches('button') ? row : row?.querySelector('button') ?? row;\n\n // preventScroll: a focus-driven scroll would immediately close the menu.\n focusTarget?.focus({ preventScroll: true });\n }, [state, activeIndex]);\n\n const moveActiveIndex = useCallback(\n (direction: 1 | -1) => {\n if (menuRows.length === 0) return;\n setActiveIndex((current) => {\n let next = current;\n for (let step = 0; step < menuRows.length; step += 1) {\n next = (next + direction + menuRows.length) % menuRows.length;\n if (isRowNavigable(menuRows[next])) return next;\n }\n return current;\n });\n },\n [menuRows, isRowNavigable],\n );\n\n useEffect(() => {\n if (!state) return;\n\n const handlePointerDown = (event: MouseEvent | TouchEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) onClose();\n };\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopPropagation();\n onClose();\n return;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n moveActiveIndex(event.key === 'ArrowDown' ? 1 : -1);\n }\n };\n // Any scroll (table viewport included) detaches the menu from its cell, so close it.\n const handleScroll = () => onClose();\n\n // Deferred so the right click that opened the menu does not immediately close it.\n const timeoutId = setTimeout(() => {\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('touchstart', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n window.addEventListener('resize', handleScroll);\n }, 0);\n\n return () => {\n clearTimeout(timeoutId);\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('touchstart', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('resize', handleScroll);\n };\n }, [state, onClose, moveActiveIndex]);\n\n if (!state || !context || menuRows.length === 0) return null;\n\n if (tableConfig?.renderCellContextMenu) {\n return tableConfig.renderCellContextMenu({ state, context, items, rowOptions: allowedRowOptions, onClose }) as JSX.Element;\n }\n\n const handleItemClick = async (item: ICellContextMenuItem): Promise<void> => {\n if (resolveFlag(item.isDisabled, context, false)) return;\n if (!item.keepOpenOnClick) onClose();\n await item.onClick?.(context);\n };\n\n return createPortal(\n <div\n ref={menuRef}\n role='menu'\n aria-label={t('Cell actions')}\n data-testid='cell-context-menu'\n className={cn(\n 'fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter',\n 'bg-white dark:bg-black-700',\n 'border border-neutral-200 dark:border-black-600',\n 'shadow-lg dark:shadow-black/40',\n config?.className,\n )}\n style={{\n left: position?.left ?? state.x,\n top: position?.top ?? state.y,\n zIndex: CELL_CONTEXT_MENU_Z_INDEX,\n // Hidden until measured so the flip/clamp never flashes at the wrong spot.\n visibility: position ? 'visible' : 'hidden',\n }}\n onContextMenu={(event) => event.preventDefault()}\n >\n {menuRows.map((row, index) => (\n <React.Fragment key={row.key}>\n {(row.kind === 'item' ? row.item.withDividerBefore && index > 0 : row.withDividerBefore) ? (\n <div className='my-1 h-px bg-neutral-200 dark:bg-black-600' />\n ) : null}\n {row.kind === 'item' ? (\n <MenuItemButton\n item={row.item}\n isDisabled={resolveFlag(row.item.isDisabled, context, false)}\n isActive={index === activeIndex}\n onSelect={() => void handleItemClick(row.item)}\n onHover={() => setActiveIndex(index)}\n />\n ) : row.kind === 'skeleton' ? (\n <div className='px-3 py-2' data-testid='cell-context-menu-loading'>\n <div className='h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600' />\n </div>\n ) : (\n /* Row actions are rendered as the table supplied them — they carry their own button and handler. */\n <div data-menu-item tabIndex={-1} className='outline-none [&_button]:w-full' onClick={onClose} onMouseEnter={() => setActiveIndex(index)}>\n {row.node}\n </div>\n )}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n );\n};\n"],"names":["writeToClipboard","text","textarea","copied","toAbsoluteUrl","path","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","rowLinkConfig","onClose","tableConfig","useTableConfig","t","useMemo","key","menuRef","useRef","position","setPosition","useState","activeIndex","setActiveIndex","copyState","setCopyState","rowOptionsFilter","setRowOptionsFilter","closeTimer","handleCopy","useCallback","menuContext","isCopied","COPY_FEEDBACK_DURATION","buildCopyItem","label","icon","isDone","CheckIcon","ContentCopyIcon","rowJson","getRowJson","selectedRowsJson","getSelectedRowsJson","selectedCount","rowLinkHref","openInNewTab","items","defaultItems","LinkIcon","OpenInNewIcon","extraItems","resolvedRowOptions","option","hasRowOptions","useEffect","isCancelled","available","allowedRowOptions","menuRows","itemRows","needsDivider","index","isRowNavigable","row","firstNavigableIndex","useLayoutEffect","width","height","margin","CELL_CONTEXT_MENU_VIEWPORT_MARGIN","offset","CELL_CONTEXT_MENU_CURSOR_OFFSET","left","top","moveActiveIndex","direction","current","next","step","handlePointerDown","event","handleKeyDown","handleScroll","timeoutId","handleItemClick","createPortal","CELL_CONTEXT_MENU_Z_INDEX","React"],"mappings":";;;;;;;;AAwDA,MAAMA,KAAmB,OAAOC,MAAmC;AACjE,MAAI;AACF,QAAI,WAAW,WAAW;AACxB,mBAAM,UAAU,UAAU,UAAUA,CAAI,GACjC;AAAA,EAEX,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAMC,IAAW,SAAS,cAAc,UAAU;AAClD,IAAAA,EAAS,QAAQD,GACjBC,EAAS,aAAa,YAAY,EAAE,GACpCA,EAAS,MAAM,WAAW,SAC1BA,EAAS,MAAM,UAAU,KACzB,SAAS,KAAK,YAAYA,CAAQ,GAClCA,EAAS,OAAA;AACT,UAAMC,IAAS,SAAS,YAAY,MAAM;AAC1C,oBAAS,KAAK,YAAYD,CAAQ,GAC3BC;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF,GAGMC,KAAgB,CAACC,MAAyB;AAC9C,MAAI,CAACA,EAAM,QAAO;AAElB,MAAI;AACF,WAAO,IAAI,IAAIA,GAAM,OAAO,SAAS,IAAI,EAAE;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF,GAEMC,IAAc,CAClBC,GACAC,GACAC,MAEIF,MAAS,SAAkBE,IACxB,OAAOF,KAAS,aAAaA,EAAKC,CAAO,IAAID,GAGhDG,KAMD,CAAC,EAAE,MAAAC,GAAM,YAAAC,GAAY,UAAAC,GAAU,UAAAC,GAAU,SAAAC,QAC5C,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,MAAK;AAAA,IACL,MAAK;AAAA,IACL,kBAAc;AAAA,IACd,UAAUJ;AAAA,IACV,iBAAeA;AAAA,IACf,UAAUC,IAAW,IAAI;AAAA,IACzB,WAAWI;AAAA,MACT;AAAA,MACAL,IACI,kCACAK;AAAA,QACE;AAAA,QACAN,EAAK,WACD,2IACA;AAAA,MAAA;AAAA,IACN;AAAA,IAEN,SAASG;AAAA,IACT,cAAc,MAAM,CAACF,KAAcG,EAAA;AAAA,IAElC,UAAA;AAAA,MAAAJ,EAAK,OACJ,gBAAAO,EAAC,QAAA,EAAK,WAAWD,EAAG,8BAA8BN,EAAK,WAAW,uCAAuC,sCAAsC,GAC5I,UAAAA,EAAK,MACR,IACE;AAAA,MACJ,gBAAAO,EAAC,QAAA,EAAK,WAAU,mBAAmB,YAAK,OAAM;AAAA,MAC7CP,EAAK,WAAW,gBAAAO,EAAC,QAAA,EAAK,WAAU,yDAAyD,UAAAP,EAAK,UAAS,IAAU;AAAA,IAAA;AAAA,EAAA;AACpH,GAOWQ,KAA8D,CAAC;AAAA,EAC1E,OAAAC;AAAA,EAAO,QAAAC;AAAA,EAAQ,YAAAC;AAAA,EAAY,uBAAAC;AAAA,EAAuB,YAAAC;AAAA,EAAY,MAAAC;AAAA,EAAM,SAAAC;AAAA,EAAS,eAAAC;AAAA,EAAe,SAAAC;AAC9F,MAAM;AACJ,QAAMC,IAAcC,EAAA,GACdC,IAAIC,EAAQ,MAAMH,GAAa,MAAM,CAACI,MAAgBA,IAAM,CAACJ,CAAW,CAAC,GACzEK,IAAUC,EAAuB,IAAI,GACrC,CAACC,GAAUC,CAAW,IAAIC,EAA+C,IAAI,GAC7E,CAACC,GAAaC,CAAc,IAAIF,EAAS,EAAE,GAC3C,CAACG,GAAWC,CAAY,IAAIJ,EAAoD,IAAI,GACpF,CAACK,GAAkBC,CAAmB,IAAIN,EAA4B,EAAE,QAAQ,OAAO,GACvFO,IAAaV,EAAA,GAEb3B,IAAUwB;AAAA,IACd,MAAOZ,IAAQ,EAAE,GAAGA,EAAM,QAAQ,OAAOQ,MAAY;AAAA,IACrD,CAACR,GAAOQ,CAAO;AAAA,EAAA,GAGXkB,IAAaC;AAAA,IACjB,OAAOd,GAAahC,GAAc+C,MAAyC;AACzE,UAAIP,EAAW;AAEf,YAAMQ,IAAW,MAAMjD,GAAiBC,CAAI;AAE5C,MAAIgD,KACF5B,GAAQ,SAASpB,GAAM+C,CAAW,GAClCnB,GAAa,mBAAmB,WAAWE,EAAE,qBAAqB,CAAC,KAEnEF,GAAa,mBAAmB,SAASE,EAAE,6BAA6B,CAAC,GAI3EW,EAAa,EAAE,KAAAT,GAAK,UAAAgB,GAAU,GAC9BJ,EAAW,UAAU,WAAW,MAAMjB,EAAA,GAAWsB,EAAsB;AAAA,IACzE;AAAA,IACA,CAAC7B,GAAQQ,GAAaE,GAAGH,GAASa,CAAS;AAAA,EAAA,GAGvCU,IAAgBJ;AAAA,IACpB,CAACd,GAAamB,GAAenD,GAAcoD,MAAiD;AAC1F,YAAMC,IAASb,GAAW,QAAQR;AAElC,aAAO;AAAA,QACL,KAAAA;AAAA,QACA,OAAQqB,IAAiBb,GAAW,WAAWV,EAAE,QAAQ,IAAIA,EAAE,aAAa,IAA3DqB;AAAA,QACjB,MACEE,KAAUb,GAAW,6BAClBc,IAAA,EAAU,MAAM,IAAI,WAAU,0CAAyC,IAExEF,KAAQ,gBAAAnC,EAACsC,IAAA,EAAgB,MAAM,IAAI;AAAA,QAEvC,YAAY,CAACvD;AAAA,QACb,iBAAiB;AAAA,QACjB,SAAS,CAAC+C,MAAgBF,EAAWb,GAAKhC,GAAM+C,CAAW;AAAA,MAAA;AAAA,IAE/D;AAAA,IACA,CAACP,GAAWK,GAAYf,CAAC;AAAA,EAAA,GAGrB0B,IAAUzB,EAAQ,MAAM0B,GAAWtC,GAAO,OAAO,SAASM,CAAO,GAAG,CAACN,GAAO,OAAO,SAASM,CAAO,CAAC,GAEpGiC,IAAmB3B,EAAQ,MAAOZ,IAAQwC,GAAoBnC,GAAMC,GAASF,CAAU,IAAI,IAAK,CAACJ,GAAOK,GAAMC,GAASF,CAAU,CAAC,GAClIqC,IAAgBrC,GAAY,UAAU,GAGtCsC,IAAc9B,EAAQ,MACtB,CAACZ,KAAS,CAACO,GAAe,aAAa,CAACA,EAAc,UAAUP,EAAM,OAAO,QAAQ,kBAAwB,KAE1GhB,GAAcuB,EAAc,OAAO,OAAOP,EAAM,OAAO,KAAK,GAAGA,EAAM,OAAO,OAAO,CAAC,GAC1F,CAACA,GAAOO,CAAa,CAAC,GAEnBoC,IAAehB,EAAY,MAAM;AACrC,IAAIe,KAAa,OAAO,KAAKA,GAAa,UAAU,qBAAqB;AAAA,EAC3E,GAAG,CAACA,CAAW,CAAC,GAEVE,IAAQhC,EAAgC,MAAM;AAClD,QAAI,CAACxB,EAAS,QAAO,CAAA;AAErB,UAAMyD,IAAuC5C,GAAQ,mBACjD,KACA;AAAA,MACE8B,EAAc,aAAa9B,GAAQ,aAAaU,EAAE,WAAW,GAAGvB,EAAQ,IAAI;AAAA,MAC5E2C,EAAc,YAAYpB,EAAE,UAAU,GAAG0B,CAAO;AAAA,MAChD,GAAII,IAAgB,IAChB;AAAA,QACEV;AAAA,UACE;AAAA,UACAU,MAAkB,IAAI9B,EAAE,mBAAmB,IAAI,GAAGA,EAAE,oBAAoB,CAAC,KAAK8B,CAAa;AAAA,UAC3FF;AAAA,QAAA;AAAA,MACF,IAEF,CAAA;AAAA,MACJ,GAAIG,KAAe,CAACzC,GAAQ,gBACxB;AAAA,QACE;AAAA,UACE,GAAG8B,EAAc,aAAapB,EAAE,WAAW,GAAG+B,GAAa,gBAAA5C,EAACgD,IAAA,EAAS,MAAM,GAAA,CAAI,CAAE;AAAA,UACjF,mBAAmB;AAAA,QAAA;AAAA,QAErB;AAAA,UACE,KAAK;AAAA,UACL,OAAOnC,EAAE,iBAAiB;AAAA,UAC1B,MAAM,gBAAAb,EAACiD,IAAA,EAAc,MAAM,GAAA,CAAI;AAAA,UAC/B,SAASJ;AAAA,QAAA;AAAA,MACX,IAEF,CAAA;AAAA,IAAC,GAGLK,IAAa,OAAO/C,GAAQ,SAAU,aAAaA,EAAO,MAAMb,CAAO,IAAIa,GAAQ,SAAS,CAAA;AAElG,WAAO,CAAC,GAAG4C,GAAc,GAAGG,CAAU,EAAE,OAAO,CAACzD,MAASL,EAAYK,EAAK,WAAWH,GAAS,EAAI,CAAC;AAAA,EACrG,GAAG,CAACa,GAAQb,GAAS2C,GAAeU,GAAeJ,GAASE,GAAkBG,GAAaC,GAAchC,CAAC,CAAC,GAGrGsC,IAAqBrC,EAAsB,MAC3C,CAACZ,KAASC,GAAQ,sBAAsB,MAAS,CAACC,IAAmB,CAAA,MAE5D,OAAOA,KAAe,aAAaA,EAAWF,EAAM,OAAO,OAAO,IAAIE,MAEnE,CAAA,GAAI,OAAO,CAACgD,MAAWA,EAAO,cAAc,EAAK,GAChE,CAAClD,GAAOE,GAAYD,GAAQ,iBAAiB,CAAC,GAE3CkD,IAAgBF,EAAmB,SAAS;AAGlD,EAAAG,EAAU,MAAM;AACd,QAAI,CAACpD,KAAS,CAACmD,KAAiB,CAAChD,GAAuB;AACtD,MAAAqB,EAAoB,EAAE,QAAQ,OAAO;AACrC;AAAA,IACF;AAEA,QAAI6B,IAAc;AAClB,WAAA7B,EAAoB,EAAE,QAAQ,WAAW,GAEzCrB,EAAsB,OAAOH,EAAM,OAAO,KAAK,CAAC,EAC7C,KAAK,CAACsD,MAAc,CAACD,KAAe7B,EAAoB,EAAE,QAAQ,SAAS,WAAA8B,EAAA,CAAW,CAAC,EACvF,MAAM,MAAM,CAACD,KAAe7B,EAAoB,EAAE,QAAQ,SAAA,CAAU,CAAC,GAEjE,MAAM;AACX,MAAA6B,IAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAACrD,GAAOmD,GAAehD,CAAqB,CAAC;AAEhD,QAAMoD,IAAoB3C,EAAsB,MAAM;AACpD,QAAIW,EAAiB,WAAW,MAAO,QAAO0B;AAC9C,QAAI1B,EAAiB,WAAW,QAAS,QAAO,CAAA;AAEhD,UAAM,EAAE,WAAA+B,MAAc/B;AAEtB,WAAO0B,EAAmB,OAAO,CAACC,MAAWI,EAAUJ,EAAO,GAAG,KAAK,EAAI;AAAA,EAC5E,GAAG,CAACD,GAAoB1B,CAAgB,CAAC,GAEnCiC,IAAW5C,EAAoB,MAAM;AACzC,UAAM6C,IAAuBb,EAAM,IAAI,CAACrD,OAAU,EAAE,MAAM,QAAQ,KAAKA,EAAK,KAAK,MAAAA,EAAA,EAAO,GAClFmE,IAAeD,EAAS,SAAS;AAEvC,WAAIlC,EAAiB,WAAW,YACvB,CAAC,GAAGkC,GAAU,EAAE,MAAM,YAAY,KAAK,uBAAuB,mBAAmBC,GAAc,IAGjG;AAAA,MACL,GAAGD;AAAA,MACH,GAAGF,EAAkB,IAAc,CAACL,GAAQS,OAAW;AAAA,QACrD,MAAM;AAAA,QACN,KAAK,cAAcT,EAAO,GAAG;AAAA,QAC7B,MAAMA,EAAO;AAAA,QACb,mBAAmBQ,KAAgBC,MAAU;AAAA,MAAA,EAC7C;AAAA,IAAA;AAAA,EAEN,GAAG,CAACf,GAAOW,GAAmBhC,EAAiB,MAAM,CAAC,GAEhDqC,IAAiBjC;AAAA,IACrB,CAACkC,MAA4BA,EAAI,SAAS,SAAS,EAAEzE,KAAWF,EAAY2E,EAAI,KAAK,YAAYzE,GAAS,EAAK,KAAKyE,EAAI,SAAS;AAAA,IACjI,CAACzE,CAAO;AAAA,EAAA,GAGJ0E,IAAsBlD,EAAQ,MAAM4C,EAAS,UAAUI,CAAc,GAAG,CAACJ,GAAUI,CAAc,CAAC;AAGxG,EAAAG,GAAgB,MAAM;AACpB,QAAI,CAAC/D,KAAS,CAACc,EAAQ,SAAS;AAC9B,MAAAG,EAAY,IAAI;AAChB;AAAA,IACF;AAEA,UAAM,EAAE,OAAA+C,GAAO,QAAAC,EAAA,IAAWnD,EAAQ,QAAQ,sBAAA,GACpCoD,IAASC,IACTC,IAASC,IAGTC,IAAOtE,EAAM,IAAIgE,IAAQE,IAAS,OAAO,aAAalE,EAAM,IAAIgE,IAAQI,IAASpE,EAAM,IAAIoE,GAC3FG,IAAMvE,EAAM,IAAIiE,IAASC,IAAS,OAAO,cAAclE,EAAM,IAAIiE,IAASG,IAASpE,EAAM,IAAIoE;AAEnG,IAAAnD,EAAY;AAAA,MACV,MAAM,KAAK,IAAIiD,GAAQ,KAAK,IAAII,GAAM,OAAO,aAAaN,IAAQE,CAAM,CAAC;AAAA,MACzE,KAAK,KAAK,IAAIA,GAAQ,KAAK,IAAIK,GAAK,OAAO,cAAcN,IAASC,CAAM,CAAC;AAAA,IAAA,CAC1E;AAAA,EACH,GAAG,CAAClE,GAAOwD,EAAS,MAAM,CAAC,GAE3BJ,EAAU,OACR9B,EAAa,IAAI,GACV,MAAM,aAAaG,EAAW,OAAO,IAC3C,CAACzB,CAAK,CAAC,GAEVoD,EAAU,MAAM;AACd,QAAI,CAACpD,GAAO;AACV,MAAAoB,EAAe,EAAE;AACjB;AAAA,IACF;AACA,IAAAA,EAAe0C,CAAmB;AAAA,EACpC,GAAG,CAAC9D,GAAO8D,CAAmB,CAAC,GAG/BV,EAAU,MAAM;AACd,QAAI,CAACpD,KAASmB,IAAc,EAAG;AAE/B,UAAM0C,IAAM/C,EAAQ,SAAS,iBAA8B,kBAAkB,EAAEK,CAAW;AAI1F,KAHoB0C,GAAK,QAAQ,QAAQ,IAAIA,IAAMA,GAAK,cAAc,QAAQ,KAAKA,IAGtE,MAAM,EAAE,eAAe,GAAA,CAAM;AAAA,EAC5C,GAAG,CAAC7D,GAAOmB,CAAW,CAAC;AAEvB,QAAMqD,IAAkB7C;AAAA,IACtB,CAAC8C,MAAsB;AACrB,MAAIjB,EAAS,WAAW,KACxBpC,EAAe,CAACsD,MAAY;AAC1B,YAAIC,IAAOD;AACX,iBAASE,IAAO,GAAGA,IAAOpB,EAAS,QAAQoB,KAAQ;AAEjD,cADAD,KAAQA,IAAOF,IAAYjB,EAAS,UAAUA,EAAS,QACnDI,EAAeJ,EAASmB,CAAI,CAAC,EAAG,QAAOA;AAE7C,eAAOD;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAClB,GAAUI,CAAc;AAAA,EAAA;AA0C3B,MAvCAR,EAAU,MAAM;AACd,QAAI,CAACpD,EAAO;AAEZ,UAAM6E,IAAoB,CAACC,MAAmC;AAC5D,MAAIhE,EAAQ,WAAW,CAACA,EAAQ,QAAQ,SAASgE,EAAM,MAAc,KAAGtE,EAAA;AAAA,IAC1E,GACMuE,IAAgB,CAACD,MAAyB;AAC9C,UAAIA,EAAM,QAAQ,UAAU;AAC1B,QAAAA,EAAM,gBAAA,GACNtE,EAAA;AACA;AAAA,MACF;AACA,OAAIsE,EAAM,QAAQ,eAAeA,EAAM,QAAQ,eAC7CA,EAAM,eAAA,GACNN,EAAgBM,EAAM,QAAQ,cAAc,IAAI,EAAE;AAAA,IAEtD,GAEME,IAAe,MAAMxE,EAAA,GAGrByE,IAAY,WAAW,MAAM;AACjC,eAAS,iBAAiB,aAAaJ,CAAiB,GACxD,SAAS,iBAAiB,cAAcA,CAAiB,GACzD,SAAS,iBAAiB,WAAWE,CAAa,GAClD,SAAS,iBAAiB,UAAUC,GAAc,EAAI,GACtD,OAAO,iBAAiB,UAAUA,CAAY;AAAA,IAChD,GAAG,CAAC;AAEJ,WAAO,MAAM;AACX,mBAAaC,CAAS,GACtB,SAAS,oBAAoB,aAAaJ,CAAiB,GAC3D,SAAS,oBAAoB,cAAcA,CAAiB,GAC5D,SAAS,oBAAoB,WAAWE,CAAa,GACrD,SAAS,oBAAoB,UAAUC,GAAc,EAAI,GACzD,OAAO,oBAAoB,UAAUA,CAAY;AAAA,IACnD;AAAA,EACF,GAAG,CAAChF,GAAOQ,GAASgE,CAAe,CAAC,GAEhC,CAACxE,KAAS,CAACZ,KAAWoE,EAAS,WAAW,EAAG,QAAO;AAExD,MAAI/C,GAAa;AACf,WAAOA,EAAY,sBAAsB,EAAE,OAAAT,GAAO,SAAAZ,GAAS,OAAAwD,GAAO,YAAYW,GAAmB,SAAA/C,GAAS;AAG5G,QAAM0E,IAAkB,OAAO3F,MAA8C;AAC3E,IAAIL,EAAYK,EAAK,YAAYH,GAAS,EAAK,MAC1CG,EAAK,mBAAiBiB,EAAA,GAC3B,MAAMjB,EAAK,UAAUH,CAAO;AAAA,EAC9B;AAEA,SAAO+F;AAAA,IACL,gBAAArF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKgB;AAAA,QACL,MAAK;AAAA,QACL,cAAYH,EAAE,cAAc;AAAA,QAC5B,eAAY;AAAA,QACZ,WAAWd;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACAI,GAAQ;AAAA,QAAA;AAAA,QAEV,OAAO;AAAA,UACL,MAAMe,GAAU,QAAQhB,EAAM;AAAA,UAC9B,KAAKgB,GAAU,OAAOhB,EAAM;AAAA,UAC5B,QAAQoF;AAAA;AAAA,UAER,YAAYpE,IAAW,YAAY;AAAA,QAAA;AAAA,QAErC,eAAe,CAAC8D,MAAUA,EAAM,eAAA;AAAA,QAE/B,UAAAtB,EAAS,IAAI,CAACK,GAAKF,MAClB,gBAAA/D,EAACyF,GAAM,UAAN,EACG,UAAA;AAAA,WAAAxB,EAAI,SAAS,SAASA,EAAI,KAAK,qBAAqBF,IAAQ,IAAIE,EAAI,qBACpE,gBAAA/D,EAAC,OAAA,EAAI,WAAU,8CAA6C,IAC1D;AAAA,UACH+D,EAAI,SAAS,SACZ,gBAAA/D;AAAA,YAACR;AAAA,YAAA;AAAA,cACC,MAAMuE,EAAI;AAAA,cACV,YAAY3E,EAAY2E,EAAI,KAAK,YAAYzE,GAAS,EAAK;AAAA,cAC3D,UAAUuE,MAAUxC;AAAA,cACpB,UAAU,MAAM,KAAK+D,EAAgBrB,EAAI,IAAI;AAAA,cAC7C,SAAS,MAAMzC,EAAeuC,CAAK;AAAA,YAAA;AAAA,UAAA,IAEnCE,EAAI,SAAS,+BACd,OAAA,EAAI,WAAU,aAAY,eAAY,6BACrC,UAAA,gBAAA/D,EAAC,OAAA,EAAI,WAAU,uEAAsE,GACvF;AAAA;AAAA,8BAGC,OAAA,EAAI,kBAAc,IAAC,UAAU,IAAI,WAAU,kCAAiC,SAASU,GAAS,cAAc,MAAMY,EAAeuC,CAAK,GACpI,YAAI,KAAA,CACP;AAAA;AAAA,QAAA,EAAA,GApBiBE,EAAI,GAsBzB,CACD;AAAA,MAAA;AAAA,IAAA;AAAA,IAEH,SAAS;AAAA,EAAA;AAEb;"}
1
+ {"version":3,"file":"CellContextMenuPortal.es.js","sources":["../../../../src/components/data-display/infinite-table/CellContextMenuPortal.tsx"],"sourcesContent":["import { useTableConfig } from '../../../providers/design-system-provider/hooks';\nimport { CheckIcon, ContentCopyIcon, LinkIcon, OpenInNewIcon } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\n IRowLinkConfig,\n} from './types';\nimport { getRowJson, getSelectedRowsJson } from './copy-text';\nimport cn from 'classnames';\nimport React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useHref } from 'react-router-dom';\n\nimport {\n CELL_CONTEXT_MENU_CURSOR_OFFSET,\n COPY_FEEDBACK_DURATION,\n CELL_CONTEXT_MENU_VIEWPORT_MARGIN,\n CELL_CONTEXT_MENU_Z_INDEX,\n} from './constants';\n\ntype TRowOption = { key: string; label: React.ReactNode; isVisible?: boolean };\n\n/** Result of the per-row availability check for row actions. */\ntype TRowOptionsFilter =\n | { status: 'off' }\n | { status: 'loading' }\n | { status: 'ready'; available: Record<string, boolean> }\n | { status: 'failed' };\n\n/** One rendered menu line: a declared item, a row-action node supplied by the table, or the row-action placeholder. */\ntype TMenuRow =\n | { kind: 'item'; key: string; item: ICellContextMenuItem }\n | { kind: 'node'; key: string; node: React.ReactNode; withDividerBefore?: boolean }\n | { kind: 'skeleton'; key: string; withDividerBefore?: boolean };\n\ninterface CellContextMenuPortalProps {\n state: ICellContextMenuState | null;\n config?: ICellContextMenuConfig | null;\n /** The table's row actions, appended to the menu — same list the three-dot cell renders. */\n rowOptions?: TRowOption[] | ((rowData: Record<string, unknown>) => TRowOption[] | null) | null;\n /** Per-row availability check for `rowOptions`, mirroring the three-dot cell so both menus agree. */\n asyncRowOptionsFilter?: ((rowId: string) => Promise<Record<string, boolean>>) | null;\n /** Checked row ids, enabling the \"Copy selected rows\" item. */\n checkedIds?: (string | number)[];\n /** Table rows, used to build the text for selected rows that are scrolled out of view. */\n rows?: Record<string, unknown>[];\n /** Visible columns in display order, used to order the copied values. */\n columns?: IColumn[];\n /** The table's row link, enabling the \"Copy Link\" / \"Open in New Tab\" items. */\n rowLinkConfig?: IRowLinkConfig | null;\n onClose: () => void;\n}\n\n/** Clipboard write with a fallback for browsers / insecure contexts without the async clipboard API. */\nconst writeToClipboard = async (text: string): Promise<boolean> => {\n try {\n if (navigator?.clipboard?.writeText) {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // fall through to the textarea fallback\n }\n\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n textarea.select();\n const copied = document.execCommand('copy');\n document.body.removeChild(textarea);\n return copied;\n } catch {\n return false;\n }\n};\n\n/** An already basename-resolved href (from `useHref`); the clipboard and a new tab both need a full URL. */\nconst toAbsoluteUrl = (href: string): string => {\n if (!href) return '';\n\n try {\n return new URL(href, window.location.origin).href;\n } catch {\n return '';\n }\n};\n\nconst resolveFlag = (\n flag: boolean | ((context: ICellContextMenuContext) => boolean) | undefined,\n context: ICellContextMenuContext,\n fallback: boolean,\n): boolean => {\n if (flag === undefined) return fallback;\n return typeof flag === 'function' ? flag(context) : flag;\n};\n\nconst MenuItemButton: React.FC<{\n item: ICellContextMenuItem;\n isDisabled: boolean;\n isActive: boolean;\n onSelect: () => void;\n onHover: () => void;\n}> = ({ item, isDisabled, isActive, onSelect, onHover }) => (\n <button\n type='button'\n role='menuitem'\n data-menu-item\n disabled={isDisabled}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={cn(\n 'flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none',\n isDisabled\n ? 'opacity-50 cursor-not-allowed'\n : cn(\n 'cursor-pointer',\n item.isDanger\n ? 'text-error-600 dark:text-error-400 hover:bg-error-50 dark:hover:bg-error-950 focus-visible:bg-error-50 dark:focus-visible:bg-error-950'\n : 'text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-black-600 focus-visible:bg-neutral-100 dark:focus-visible:bg-black-600',\n ),\n )}\n onClick={onSelect}\n onMouseEnter={() => !isDisabled && onHover()}\n >\n {item.icon ? (\n <span className={cn('flex shrink-0 items-center', item.isDanger ? 'text-error-600 dark:text-error-400' : 'text-neutral-500 dark:text-black-300')}>\n {item.icon}\n </span>\n ) : null}\n <span className='flex-1 truncate'>{item.label}</span>\n {item.shortcut ? <span className='shrink-0 text-xs text-neutral-400 dark:text-black-300'>{item.shortcut}</span> : null}\n </button>\n);\n\n/**\n * Right-click menu for data cells. Rendered once per table and positioned at the\n * cursor; `DataCell` opens it through `openCellContextMenu` on the table context.\n */\nexport const CellContextMenuPortal: React.FC<CellContextMenuPortalProps> = ({\n state, config, rowOptions, asyncRowOptionsFilter, checkedIds, rows, columns, rowLinkConfig, onClose,\n}) => {\n const tableConfig = useTableConfig();\n const t = useMemo(() => tableConfig?.t ?? ((key: string) => key), [tableConfig]);\n const menuRef = useRef<HTMLDivElement>(null);\n const [position, setPosition] = useState<{ left: number; top: number } | null>(null);\n const [activeIndex, setActiveIndex] = useState(-1);\n const [copyState, setCopyState] = useState<{ key: string; isCopied: boolean } | null>(null);\n const [rowOptionsFilter, setRowOptionsFilter] = useState<TRowOptionsFilter>({ status: 'off' });\n const closeTimer = useRef<ReturnType<typeof setTimeout>>();\n\n const context = useMemo<ICellContextMenuContext | null>(\n () => (state ? { ...state.target, close: onClose } : null),\n [state, onClose],\n );\n\n const handleCopy = useCallback(\n async (key: string, text: string, menuContext: ICellContextMenuContext) => {\n if (copyState) return;\n\n const isCopied = await writeToClipboard(text);\n\n if (isCopied) {\n config?.onCopy?.(text, menuContext);\n tableConfig?.showNotification?.('success', t('Copied to clipboard'));\n } else {\n tableConfig?.showNotification?.('error', t('Could not copy to clipboard'));\n }\n\n // Confirmed inline instead of with a toast, so the menu owns its own feedback.\n setCopyState({ key, isCopied });\n closeTimer.current = setTimeout(() => onClose(), COPY_FEEDBACK_DURATION);\n },\n [config, tableConfig, t, onClose, copyState],\n );\n\n const buildCopyItem = useCallback(\n (key: string, label: string, text: string, icon?: React.ReactNode): ICellContextMenuItem => {\n const isDone = copyState?.key === key;\n\n return {\n key,\n label: !isDone ? label : copyState?.isCopied ? t('Copied') : t('Copy failed'),\n icon:\n isDone && copyState?.isCopied ? (\n <CheckIcon size={16} className='text-success-600 dark:text-success-400' />\n ) : (\n icon ?? <ContentCopyIcon size={16} />\n ),\n isDisabled: !text,\n keepOpenOnClick: true,\n onClick: (menuContext) => handleCopy(key, text, menuContext),\n };\n },\n [copyState, handleCopy, t],\n );\n\n const rowJson = useMemo(() => getRowJson(state?.target.rowData, columns), [state?.target.rowData, columns]);\n // Only while the menu is open — otherwise every checkbox tick would serialize the selection.\n const selectedRowsJson = useMemo(() => (state ? getSelectedRowsJson(rows, columns, checkedIds) : ''), [state, rows, columns, checkedIds]);\n const selectedCount = checkedIds?.length ?? 0;\n\n /** The router path from `linkTo`, before the router's basename (e.g. `/integrations`) is applied. */\n const rowLinkPath = useMemo(() => {\n if (!state || !rowLinkConfig?.isEnabled || !rowLinkConfig.linkTo || state.target.column?.disableRowClick) return '';\n\n return rowLinkConfig.linkTo(String(state.target.rowId), state.target.rowData) || '';\n }, [state, rowLinkConfig]);\n\n // `useHref` resolves `rowLinkPath` the same way a <Link> would, basename included — a manual\n // `new URL(path, location.href)` would silently drop a router basename like `/integrations`.\n const rowLinkResolvedHref = useHref(rowLinkPath || '/');\n\n /** The row link as an absolute URL — empty unless the table opted in, and never on a cell that opts out of the row link. */\n const rowLinkHref = useMemo(() => {\n if (!rowLinkPath) return '';\n\n return toAbsoluteUrl(rowLinkResolvedHref);\n }, [rowLinkPath, rowLinkResolvedHref]);\n\n const openInNewTab = useCallback(() => {\n if (rowLinkHref) window.open(rowLinkHref, '_blank', 'noopener,noreferrer');\n }, [rowLinkHref]);\n\n const items = useMemo<ICellContextMenuItem[]>(() => {\n if (!context) return [];\n\n const defaultItems: ICellContextMenuItem[] = config?.hideDefaultItems\n ? []\n : [\n buildCopyItem('copy-cell', config?.copyLabel ?? t('Copy Cell'), context.text),\n buildCopyItem('copy-row', t('Copy Row'), rowJson),\n ...(selectedCount > 0\n ? [\n buildCopyItem(\n 'copy-selected-rows',\n selectedCount === 1 ? t('Copy Selected Row') : `${t('Copy Selected Rows')} (${selectedCount})`,\n selectedRowsJson,\n ),\n ]\n : []),\n ...(rowLinkHref && !config?.hideLinkItems\n ? [\n {\n ...buildCopyItem('copy-link', t('Copy Link'), rowLinkHref, <LinkIcon size={16} />),\n withDividerBefore: true,\n },\n {\n key: 'open-in-new-tab',\n label: t('Open in New Tab'),\n icon: <OpenInNewIcon size={16} />,\n onClick: openInNewTab,\n },\n ]\n : []),\n ];\n\n const extraItems = typeof config?.items === 'function' ? config.items(context) : config?.items ?? [];\n\n return [...defaultItems, ...extraItems].filter((item) => resolveFlag(item.isVisible, context, true));\n }, [config, context, buildCopyItem, selectedCount, rowJson, selectedRowsJson, rowLinkHref, openInNewTab, t]);\n\n /** The table's own row actions, resolved for the right-clicked row. */\n const resolvedRowOptions = useMemo<TRowOption[]>(() => {\n if (!state || config?.includeRowOptions === false || !rowOptions) return [];\n\n const list = typeof rowOptions === 'function' ? rowOptions(state.target.rowData) : rowOptions;\n\n return (list ?? []).filter((option) => option.isVisible !== false);\n }, [state, rowOptions, config?.includeRowOptions]);\n\n const hasRowOptions = resolvedRowOptions.length > 0;\n\n /** Row actions can be gated per row by the API — ask before showing them, exactly as the three-dot cell does. */\n useEffect(() => {\n if (!state || !hasRowOptions || !asyncRowOptionsFilter) {\n setRowOptionsFilter({ status: 'off' });\n return;\n }\n\n let isCancelled = false;\n setRowOptionsFilter({ status: 'loading' });\n\n asyncRowOptionsFilter(String(state.target.rowId))\n .then((available) => !isCancelled && setRowOptionsFilter({ status: 'ready', available }))\n .catch(() => !isCancelled && setRowOptionsFilter({ status: 'failed' }));\n\n return () => {\n isCancelled = true;\n };\n }, [state, hasRowOptions, asyncRowOptionsFilter]);\n\n const allowedRowOptions = useMemo<TRowOption[]>(() => {\n if (rowOptionsFilter.status === 'off') return resolvedRowOptions;\n if (rowOptionsFilter.status !== 'ready') return [];\n\n const { available } = rowOptionsFilter;\n\n return resolvedRowOptions.filter((option) => available[option.key] ?? true);\n }, [resolvedRowOptions, rowOptionsFilter]);\n\n const menuRows = useMemo<TMenuRow[]>(() => {\n const itemRows: TMenuRow[] = items.map((item) => ({ kind: 'item', key: item.key, item }));\n const needsDivider = itemRows.length > 0;\n\n if (rowOptionsFilter.status === 'loading') {\n return [...itemRows, { kind: 'skeleton', key: 'row-options-loading', withDividerBefore: needsDivider }];\n }\n\n return [\n ...itemRows,\n ...allowedRowOptions.map<TMenuRow>((option, index) => ({\n kind: 'node',\n key: `row-option-${option.key}`,\n node: option.label,\n withDividerBefore: needsDivider && index === 0,\n })),\n ];\n }, [items, allowedRowOptions, rowOptionsFilter.status]);\n\n const isRowNavigable = useCallback(\n (row: TMenuRow): boolean => (row.kind === 'item' ? !(context && resolveFlag(row.item.isDisabled, context, false)) : row.kind === 'node'),\n [context],\n );\n\n const firstNavigableIndex = useMemo(() => menuRows.findIndex(isRowNavigable), [menuRows, isRowNavigable]);\n\n /** Clamp into the viewport once the menu has been measured; row actions can arrive after the first paint. */\n useLayoutEffect(() => {\n if (!state || !menuRef.current) {\n setPosition(null);\n return;\n }\n\n const { width, height } = menuRef.current.getBoundingClientRect();\n const margin = CELL_CONTEXT_MENU_VIEWPORT_MARGIN;\n const offset = CELL_CONTEXT_MENU_CURSOR_OFFSET;\n\n // Flip to the other side of the cursor when there is no room, then clamp.\n const left = state.x + width + margin > window.innerWidth ? state.x - width - offset : state.x + offset;\n const top = state.y + height + margin > window.innerHeight ? state.y - height - offset : state.y + offset;\n\n setPosition({\n left: Math.max(margin, Math.min(left, window.innerWidth - width - margin)),\n top: Math.max(margin, Math.min(top, window.innerHeight - height - margin)),\n });\n }, [state, menuRows.length]);\n\n useEffect(() => {\n setCopyState(null);\n return () => clearTimeout(closeTimer.current);\n }, [state]);\n\n useEffect(() => {\n if (!state) {\n setActiveIndex(-1);\n return;\n }\n setActiveIndex(firstNavigableIndex);\n }, [state, firstNavigableIndex]);\n\n /** Focus follows the active row so the menu is keyboard operable; row actions bring their own button. */\n useEffect(() => {\n if (!state || activeIndex < 0) return;\n\n const row = menuRef.current?.querySelectorAll<HTMLElement>('[data-menu-item]')[activeIndex];\n const focusTarget = row?.matches('button') ? row : row?.querySelector('button') ?? row;\n\n // preventScroll: a focus-driven scroll would immediately close the menu.\n focusTarget?.focus({ preventScroll: true });\n }, [state, activeIndex]);\n\n const moveActiveIndex = useCallback(\n (direction: 1 | -1) => {\n if (menuRows.length === 0) return;\n setActiveIndex((current) => {\n let next = current;\n for (let step = 0; step < menuRows.length; step += 1) {\n next = (next + direction + menuRows.length) % menuRows.length;\n if (isRowNavigable(menuRows[next])) return next;\n }\n return current;\n });\n },\n [menuRows, isRowNavigable],\n );\n\n useEffect(() => {\n if (!state) return;\n\n const handlePointerDown = (event: MouseEvent | TouchEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) onClose();\n };\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopPropagation();\n onClose();\n return;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n moveActiveIndex(event.key === 'ArrowDown' ? 1 : -1);\n }\n };\n // Any scroll (table viewport included) detaches the menu from its cell, so close it.\n const handleScroll = () => onClose();\n\n // Deferred so the right click that opened the menu does not immediately close it.\n const timeoutId = setTimeout(() => {\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('touchstart', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n window.addEventListener('resize', handleScroll);\n }, 0);\n\n return () => {\n clearTimeout(timeoutId);\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('touchstart', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n window.removeEventListener('resize', handleScroll);\n };\n }, [state, onClose, moveActiveIndex]);\n\n if (!state || !context || menuRows.length === 0) return null;\n\n if (tableConfig?.renderCellContextMenu) {\n return tableConfig.renderCellContextMenu({ state, context, items, rowOptions: allowedRowOptions, onClose }) as JSX.Element;\n }\n\n const handleItemClick = async (item: ICellContextMenuItem): Promise<void> => {\n if (resolveFlag(item.isDisabled, context, false)) return;\n if (!item.keepOpenOnClick) onClose();\n await item.onClick?.(context);\n };\n\n return createPortal(\n <div\n ref={menuRef}\n role='menu'\n aria-label={t('Cell actions')}\n data-testid='cell-context-menu'\n className={cn(\n 'fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter',\n 'bg-white dark:bg-black-700',\n 'border border-neutral-200 dark:border-black-600',\n 'shadow-lg dark:shadow-black/40',\n config?.className,\n )}\n style={{\n left: position?.left ?? state.x,\n top: position?.top ?? state.y,\n zIndex: CELL_CONTEXT_MENU_Z_INDEX,\n // Hidden until measured so the flip/clamp never flashes at the wrong spot.\n visibility: position ? 'visible' : 'hidden',\n }}\n onContextMenu={(event) => event.preventDefault()}\n >\n {menuRows.map((row, index) => (\n <React.Fragment key={row.key}>\n {(row.kind === 'item' ? row.item.withDividerBefore && index > 0 : row.withDividerBefore) ? (\n <div className='my-1 h-px bg-neutral-200 dark:bg-black-600' />\n ) : null}\n {row.kind === 'item' ? (\n <MenuItemButton\n item={row.item}\n isDisabled={resolveFlag(row.item.isDisabled, context, false)}\n isActive={index === activeIndex}\n onSelect={() => void handleItemClick(row.item)}\n onHover={() => setActiveIndex(index)}\n />\n ) : row.kind === 'skeleton' ? (\n <div className='px-3 py-2' data-testid='cell-context-menu-loading'>\n <div className='h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600' />\n </div>\n ) : (\n /* Row actions are rendered as the table supplied them — they carry their own button and handler. */\n <div data-menu-item tabIndex={-1} className='outline-none [&_button]:w-full' onClick={onClose} onMouseEnter={() => setActiveIndex(index)}>\n {row.node}\n </div>\n )}\n </React.Fragment>\n ))}\n </div>,\n document.body,\n );\n};\n"],"names":["writeToClipboard","text","textarea","copied","toAbsoluteUrl","href","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","rowLinkConfig","onClose","tableConfig","useTableConfig","t","useMemo","key","menuRef","useRef","position","setPosition","useState","activeIndex","setActiveIndex","copyState","setCopyState","rowOptionsFilter","setRowOptionsFilter","closeTimer","handleCopy","useCallback","menuContext","isCopied","COPY_FEEDBACK_DURATION","buildCopyItem","label","icon","isDone","CheckIcon","ContentCopyIcon","rowJson","getRowJson","selectedRowsJson","getSelectedRowsJson","selectedCount","rowLinkPath","rowLinkResolvedHref","useHref","rowLinkHref","openInNewTab","items","defaultItems","LinkIcon","OpenInNewIcon","extraItems","resolvedRowOptions","option","hasRowOptions","useEffect","isCancelled","available","allowedRowOptions","menuRows","itemRows","needsDivider","index","isRowNavigable","row","firstNavigableIndex","useLayoutEffect","width","height","margin","CELL_CONTEXT_MENU_VIEWPORT_MARGIN","offset","CELL_CONTEXT_MENU_CURSOR_OFFSET","left","top","moveActiveIndex","direction","current","next","step","handlePointerDown","event","handleKeyDown","handleScroll","timeoutId","handleItemClick","createPortal","CELL_CONTEXT_MENU_Z_INDEX","React"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lax-wp/design-system",
3
3
  "private": false,
4
- "version": "0.14.56",
4
+ "version": "0.14.58",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",