@lax-wp/design-system 0.14.37 → 0.14.38

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 c=require("react/jsx-runtime"),W=require("../../../providers/design-system-provider/hooks.cjs.js"),$=require("./copy-text.cjs.js"),R=require("../../../_virtual/index.cjs.js"),i=require("react"),K=require("react-dom"),N=require("./constants.cjs.js"),X=require("../../icon/icons.generated.cjs.js"),G=async t=>{try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(t),!0}catch{}try{const o=document.createElement("textarea");o.value=t,o.setAttribute("readonly",""),o.style.position="fixed",o.style.opacity="0",document.body.appendChild(o),o.select();const d=document.execCommand("copy");return document.body.removeChild(o),d}catch{return!1}},D=(t,o,d)=>t===void 0?d:typeof t=="function"?t(o):t,Y=({item:t,isDisabled:o,isActive:d,onSelect:y,onHover:k})=>c.jsxs("button",{type:"button",role:"menuitem","data-menu-item":!0,disabled:o,"aria-disabled":o,tabIndex:d?0:-1,className:R("flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",o?"opacity-50 cursor-not-allowed":R("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:y,onMouseEnter:()=>!o&&k(),children:[t.icon?c.jsx("span",{className:R("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,c.jsx("span",{className:"flex-1 truncate",children:t.label}),t.shortcut?c.jsx("span",{className:"shrink-0 text-xs text-neutral-400 dark:text-black-300",children:t.shortcut}):null]}),Z=({state:t,config:o,rowOptions:d,asyncRowOptionsFilter:y,checkedIds:k,rows:O,columns:_,onClose:m})=>{const p=W.useTableConfig(),a=i.useMemo(()=>p?.t??(e=>e),[p]),b=i.useRef(null),[I,j]=i.useState(null),[v,w]=i.useState(-1),[x,A]=i.useState(null),[h,C]=i.useState({status:"off"}),q=i.useRef(),l=i.useMemo(()=>t?{...t.target,close:m}:null,[t,m]),P=i.useCallback(async(e,n,r)=>{if(x)return;const s=await G(n);s?(o?.onCopy?.(n,r),p?.showNotification?.("success",a("Copied to clipboard"))):p?.showNotification?.("error",a("Could not copy to clipboard")),A({key:e,isCopied:s}),q.current=setTimeout(()=>m(),N.COPY_FEEDBACK_DURATION)},[o,p,a,m,x]),g=i.useCallback((e,n,r)=>{const s=x?.key===e;return{key:e,label:s?x?.isCopied?a("Copied"):a("Copy failed"):n,icon:s&&x?.isCopied?c.jsx(X.CheckIcon,{size:16,className:"text-success-600 dark:text-success-400"}):c.jsx(X.ContentCopyIcon,{size:16}),isDisabled:!r,keepOpenOnClick:!0,onClick:u=>P(e,r,u)}},[x,P,a]),B=i.useMemo(()=>$.getSelectedRowsText(O,_,k),[O,_,k]),E=k?.length??0,L=i.useMemo(()=>{if(!l)return[];const e=o?.hideDefaultItems?[]:[g("copy-content",o?.copyLabel??a("Copy content"),l.text),g("copy-row",a("Copy row"),l.rowText),...E>0?[g("copy-selected-rows",E===1?a("Copy selected row"):`${a("Copy selected rows")} (${E})`,B)]:[]],n=typeof o?.items=="function"?o.items(l):o?.items??[];return[...e,...n].filter(r=>D(r.isVisible,l,!0))},[o,l,g,E,B,a]),M=i.useMemo(()=>!t||o?.includeRowOptions===!1||!d?[]:((typeof d=="function"?d(t.target.rowData):d)??[]).filter(n=>n.isVisible!==!1),[t,d,o?.includeRowOptions]),U=M.length>0;i.useEffect(()=>{if(!t||!U||!y){C({status:"off"});return}let e=!1;return C({status:"loading"}),y(String(t.target.rowId)).then(n=>!e&&C({status:"ready",available:n})).catch(()=>!e&&C({status:"failed"})),()=>{e=!0}},[t,U,y]);const S=i.useMemo(()=>{if(h.status==="off")return M;if(h.status!=="ready")return[];const{available:e}=h;return M.filter(n=>e[n.key]??!0)},[M,h]),f=i.useMemo(()=>{const e=L.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,...S.map((r,s)=>({kind:"node",key:`row-option-${r.key}`,node:r.label,withDividerBefore:n&&s===0}))]},[L,S,h.status]),T=i.useCallback(e=>e.kind==="item"?!(l&&D(e.item.isDisabled,l,!1)):e.kind==="node",[l]),z=i.useMemo(()=>f.findIndex(T),[f,T]);i.useLayoutEffect(()=>{if(!t||!b.current){j(null);return}const{width:e,height:n}=b.current.getBoundingClientRect(),r=N.CELL_CONTEXT_MENU_VIEWPORT_MARGIN,s=N.CELL_CONTEXT_MENU_CURSOR_OFFSET,u=t.x+e+r>window.innerWidth?t.x-e-s:t.x+s,V=t.y+n+r>window.innerHeight?t.y-n-s:t.y+s;j({left:Math.max(r,Math.min(u,window.innerWidth-e-r)),top:Math.max(r,Math.min(V,window.innerHeight-n-r))})},[t,f.length]),i.useEffect(()=>(A(null),()=>clearTimeout(q.current)),[t]),i.useEffect(()=>{if(!t){w(-1);return}w(z)},[t,z]),i.useEffect(()=>{if(!t||v<0)return;const e=b.current?.querySelectorAll("[data-menu-item]")[v];(e?.matches("button")?e:e?.querySelector("button")??e)?.focus({preventScroll:!0})},[t,v]);const F=i.useCallback(e=>{f.length!==0&&w(n=>{let r=n;for(let s=0;s<f.length;s+=1)if(r=(r+e+f.length)%f.length,T(f[r]))return r;return n})},[f,T]);if(i.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(),F(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,F]),!t||!l||f.length===0)return null;if(p?.renderCellContextMenu)return p.renderCellContextMenu({state:t,context:l,items:L,rowOptions:S,onClose:m});const H=async e=>{D(e.isDisabled,l,!1)||(e.keepOpenOnClick||m(),await e.onClick?.(l))};return K.createPortal(c.jsx("div",{ref:b,role:"menu","aria-label":a("Cell actions"),"data-testid":"cell-context-menu",className:R("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",o?.className),style:{left:I?.left??t.x,top:I?.top??t.y,zIndex:N.CELL_CONTEXT_MENU_Z_INDEX,visibility:I?"visible":"hidden"},onContextMenu:e=>e.preventDefault(),children:f.map((e,n)=>c.jsxs(i.Fragment,{children:[(e.kind==="item"?e.item.withDividerBefore&&n>0:e.withDividerBefore)?c.jsx("div",{className:"my-1 h-px bg-neutral-200 dark:bg-black-600"}):null,e.kind==="item"?c.jsx(Y,{item:e.item,isDisabled:D(e.item.isDisabled,l,!1),isActive:n===v,onSelect:()=>void H(e.item),onHover:()=>w(n)}):e.kind==="skeleton"?c.jsx("div",{className:"px-3 py-2","data-testid":"cell-context-menu-loading",children:c.jsx("div",{className:"h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600"})}):c.jsx("div",{"data-menu-item":!0,tabIndex:-1,className:"outline-none [&_button]:w-full",onClick:m,onMouseEnter:()=>w(n),children:e.node})]},e.key))}),document.body)};exports.CellContextMenuPortal=Z;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),$=require("../../../providers/design-system-provider/hooks.cjs.js"),X=require("./copy-text.cjs.js"),I=require("../../../_virtual/index.cjs.js"),i=require("react"),K=require("react-dom"),N=require("./constants.cjs.js"),H=require("../../icon/icons.generated.cjs.js"),G=async t=>{try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(t),!0}catch{}try{const o=document.createElement("textarea");o.value=t,o.setAttribute("readonly",""),o.style.position="fixed",o.style.opacity="0",document.body.appendChild(o),o.select();const d=document.execCommand("copy");return document.body.removeChild(o),d}catch{return!1}},T=(t,o,d)=>t===void 0?d:typeof t=="function"?t(o):t,Y=({item:t,isDisabled:o,isActive:d,onSelect:y,onHover:k})=>a.jsxs("button",{type:"button",role:"menuitem","data-menu-item":!0,disabled:o,"aria-disabled":o,tabIndex:d?0:-1,className:I("flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",o?"opacity-50 cursor-not-allowed":I("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:y,onMouseEnter:()=>!o&&k(),children:[t.icon?a.jsx("span",{className:I("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,a.jsx("span",{className:"flex-1 truncate",children:t.label}),t.shortcut?a.jsx("span",{className:"shrink-0 text-xs text-neutral-400 dark:text-black-300",children:t.shortcut}):null]}),Z=({state:t,config:o,rowOptions:d,asyncRowOptionsFilter:y,checkedIds:k,rows:_,columns:v,onClose:m})=>{const p=$.useTableConfig(),c=i.useMemo(()=>p?.t??(e=>e),[p]),b=i.useRef(null),[S,j]=i.useState(null),[g,w]=i.useState(-1),[x,A]=i.useState(null),[h,C]=i.useState({status:"off"}),q=i.useRef(),l=i.useMemo(()=>t?{...t.target,close:m}:null,[t,m]),P=i.useCallback(async(e,n,r)=>{if(x)return;const s=await G(n);s?(o?.onCopy?.(n,r),p?.showNotification?.("success",c("Copied to clipboard"))):p?.showNotification?.("error",c("Could not copy to clipboard")),A({key:e,isCopied:s}),q.current=setTimeout(()=>m(),N.COPY_FEEDBACK_DURATION)},[o,p,c,m,x]),E=i.useCallback((e,n,r)=>{const s=x?.key===e;return{key:e,label:s?x?.isCopied?c("Copied"):c("Copy failed"):n,icon:s&&x?.isCopied?a.jsx(H.CheckIcon,{size:16,className:"text-success-600 dark:text-success-400"}):a.jsx(H.ContentCopyIcon,{size:16}),isDisabled:!r,keepOpenOnClick:!0,onClick:u=>P(e,r,u)}},[x,P,c]),B=i.useMemo(()=>X.getRowJson(t?.target.rowData,v),[t?.target.rowData,v]),U=i.useMemo(()=>t?X.getSelectedRowsJson(_,v,k):"",[t,_,v,k]),M=k?.length??0,L=i.useMemo(()=>{if(!l)return[];const e=o?.hideDefaultItems?[]:[E("copy-cell",o?.copyLabel??c("Copy Cell"),l.text),E("copy-row",c("Copy Row"),B),...M>0?[E("copy-selected-rows",M===1?c("Copy Selected Row"):`${c("Copy Selected Rows")} (${M})`,U)]:[]],n=typeof o?.items=="function"?o.items(l):o?.items??[];return[...e,...n].filter(r=>T(r.isVisible,l,!0))},[o,l,E,M,B,U,c]),R=i.useMemo(()=>!t||o?.includeRowOptions===!1||!d?[]:((typeof d=="function"?d(t.target.rowData):d)??[]).filter(n=>n.isVisible!==!1),[t,d,o?.includeRowOptions]),z=R.length>0;i.useEffect(()=>{if(!t||!z||!y){C({status:"off"});return}let e=!1;return C({status:"loading"}),y(String(t.target.rowId)).then(n=>!e&&C({status:"ready",available:n})).catch(()=>!e&&C({status:"failed"})),()=>{e=!0}},[t,z,y]);const O=i.useMemo(()=>{if(h.status==="off")return R;if(h.status!=="ready")return[];const{available:e}=h;return R.filter(n=>e[n.key]??!0)},[R,h]),f=i.useMemo(()=>{const e=L.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,...O.map((r,s)=>({kind:"node",key:`row-option-${r.key}`,node:r.label,withDividerBefore:n&&s===0}))]},[L,O,h.status]),D=i.useCallback(e=>e.kind==="item"?!(l&&T(e.item.isDisabled,l,!1)):e.kind==="node",[l]),F=i.useMemo(()=>f.findIndex(D),[f,D]);i.useLayoutEffect(()=>{if(!t||!b.current){j(null);return}const{width:e,height:n}=b.current.getBoundingClientRect(),r=N.CELL_CONTEXT_MENU_VIEWPORT_MARGIN,s=N.CELL_CONTEXT_MENU_CURSOR_OFFSET,u=t.x+e+r>window.innerWidth?t.x-e-s:t.x+s,W=t.y+n+r>window.innerHeight?t.y-n-s:t.y+s;j({left:Math.max(r,Math.min(u,window.innerWidth-e-r)),top:Math.max(r,Math.min(W,window.innerHeight-n-r))})},[t,f.length]),i.useEffect(()=>(A(null),()=>clearTimeout(q.current)),[t]),i.useEffect(()=>{if(!t){w(-1);return}w(F)},[t,F]),i.useEffect(()=>{if(!t||g<0)return;const e=b.current?.querySelectorAll("[data-menu-item]")[g];(e?.matches("button")?e:e?.querySelector("button")??e)?.focus({preventScroll:!0})},[t,g]);const J=i.useCallback(e=>{f.length!==0&&w(n=>{let r=n;for(let s=0;s<f.length;s+=1)if(r=(r+e+f.length)%f.length,D(f[r]))return r;return n})},[f,D]);if(i.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(),J(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,J]),!t||!l||f.length===0)return null;if(p?.renderCellContextMenu)return p.renderCellContextMenu({state:t,context:l,items:L,rowOptions:O,onClose:m});const V=async e=>{T(e.isDisabled,l,!1)||(e.keepOpenOnClick||m(),await e.onClick?.(l))};return K.createPortal(a.jsx("div",{ref:b,role:"menu","aria-label":c("Cell actions"),"data-testid":"cell-context-menu",className:I("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",o?.className),style:{left:S?.left??t.x,top:S?.top??t.y,zIndex:N.CELL_CONTEXT_MENU_Z_INDEX,visibility:S?"visible":"hidden"},onContextMenu:e=>e.preventDefault(),children:f.map((e,n)=>a.jsxs(i.Fragment,{children:[(e.kind==="item"?e.item.withDividerBefore&&n>0:e.withDividerBefore)?a.jsx("div",{className:"my-1 h-px bg-neutral-200 dark:bg-black-600"}):null,e.kind==="item"?a.jsx(Y,{item:e.item,isDisabled:T(e.item.isDisabled,l,!1),isActive:n===g,onSelect:()=>void V(e.item),onHover:()=>w(n)}):e.kind==="skeleton"?a.jsx("div",{className:"px-3 py-2","data-testid":"cell-context-menu-loading",children:a.jsx("div",{className:"h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600"})}):a.jsx("div",{"data-menu-item":!0,tabIndex:-1,className:"outline-none [&_button]:w-full",onClick:m,onMouseEnter:()=>w(n),children:e.node})]},e.key))}),document.body)};exports.CellContextMenuPortal=Z;
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 } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\n} from './types';\nimport { getSelectedRowsText } 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 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\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, 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): 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 <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 selectedRowsText = useMemo(() => getSelectedRowsText(rows, columns, checkedIds), [rows, columns, checkedIds]);\n const selectedCount = checkedIds?.length ?? 0;\n\n const items = useMemo<ICellContextMenuItem[]>(() => {\n if (!context) return [];\n\n const defaultItems: ICellContextMenuItem[] = config?.hideDefaultItems\n ? []\n : [\n buildCopyItem('copy-content', config?.copyLabel ?? t('Copy content'), context.text),\n buildCopyItem('copy-row', t('Copy row'), context.rowText),\n ...(selectedCount > 0\n ? [\n buildCopyItem(\n 'copy-selected-rows',\n selectedCount === 1 ? t('Copy selected row') : `${t('Copy selected rows')} (${selectedCount})`,\n selectedRowsText,\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, selectedRowsText, 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","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","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","isDone","CheckIcon","ContentCopyIcon","selectedRowsText","getSelectedRowsText","selectedCount","items","defaultItems","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 } from '../../icon';\nimport type {\n ICellContextMenuConfig,\n ICellContextMenuContext,\n ICellContextMenuItem,\n ICellContextMenuState,\n IColumn,\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 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\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, 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): 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 <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 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 ];\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, 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","resolveFlag","flag","context","fallback","MenuItemButton","item","isDisabled","isActive","onSelect","onHover","jsxs","cn","jsx","CellContextMenuPortal","state","config","rowOptions","asyncRowOptionsFilter","checkedIds","rows","columns","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","isDone","CheckIcon","ContentCopyIcon","rowJson","getRowJson","selectedRowsJson","getSelectedRowsJson","selectedCount","items","defaultItems","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,12 @@
1
1
  import { jsx as m, jsxs as j } from "react/jsx-runtime";
2
2
  import { useTableConfig as G } from "../../../providers/design-system-provider/hooks.es.js";
3
- import { getSelectedRowsText as Y } from "./copy-text.es.js";
4
- import M from "../../../_virtual/index.es.js";
5
- import Z, { useMemo as f, useRef as $, useState as I, useCallback as L, useEffect as v, useLayoutEffect as J } from "react";
6
- import { createPortal as Q } from "react-dom";
7
- import { COPY_FEEDBACK_DURATION as ee, CELL_CONTEXT_MENU_VIEWPORT_MARGIN as te, CELL_CONTEXT_MENU_Z_INDEX as ne, CELL_CONTEXT_MENU_CURSOR_OFFSET as re } from "./constants.es.js";
8
- import { CheckIcon as oe, ContentCopyIcon as ie } from "../../icon/icons.generated.es.js";
9
- const le = async (t) => {
3
+ import { getRowJson as Y, getSelectedRowsJson as Z } from "./copy-text.es.js";
4
+ import _ from "../../../_virtual/index.es.js";
5
+ import Q, { useMemo as f, useRef as $, useState as T, useCallback as L, useEffect as v, useLayoutEffect as ee } from "react";
6
+ import { createPortal as te } from "react-dom";
7
+ import { COPY_FEEDBACK_DURATION as ne, CELL_CONTEXT_MENU_VIEWPORT_MARGIN as re, CELL_CONTEXT_MENU_Z_INDEX as oe, CELL_CONTEXT_MENU_CURSOR_OFFSET as ie } from "./constants.es.js";
8
+ import { CheckIcon as le, ContentCopyIcon as se } from "../../icon/icons.generated.es.js";
9
+ const ae = async (t) => {
10
10
  try {
11
11
  if (navigator?.clipboard?.writeText)
12
12
  return await navigator.clipboard.writeText(t), !0;
@@ -20,7 +20,7 @@ const le = async (t) => {
20
20
  } catch {
21
21
  return !1;
22
22
  }
23
- }, R = (t, o, c) => t === void 0 ? c : typeof t == "function" ? t(o) : t, se = ({ item: t, isDisabled: o, isActive: c, onSelect: k, onHover: x }) => /* @__PURE__ */ j(
23
+ }, M = (t, o, c) => t === void 0 ? c : typeof t == "function" ? t(o) : t, ce = ({ item: t, isDisabled: o, isActive: c, onSelect: k, onHover: w }) => /* @__PURE__ */ j(
24
24
  "button",
25
25
  {
26
26
  type: "button",
@@ -29,154 +29,154 @@ const le = async (t) => {
29
29
  disabled: o,
30
30
  "aria-disabled": o,
31
31
  tabIndex: c ? 0 : -1,
32
- className: M(
32
+ className: _(
33
33
  "flex w-full items-center gap-3 px-3 py-2 text-sm font-medium text-left outline-none",
34
- o ? "opacity-50 cursor-not-allowed" : M(
34
+ o ? "opacity-50 cursor-not-allowed" : _(
35
35
  "cursor-pointer",
36
36
  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"
37
37
  )
38
38
  ),
39
39
  onClick: k,
40
- onMouseEnter: () => !o && x(),
40
+ onMouseEnter: () => !o && w(),
41
41
  children: [
42
- t.icon ? /* @__PURE__ */ m("span", { className: M("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,
42
+ t.icon ? /* @__PURE__ */ m("span", { className: _("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,
43
43
  /* @__PURE__ */ m("span", { className: "flex-1 truncate", children: t.label }),
44
44
  t.shortcut ? /* @__PURE__ */ m("span", { className: "shrink-0 text-xs text-neutral-400 dark:text-black-300", children: t.shortcut }) : null
45
45
  ]
46
46
  }
47
- ), he = ({
47
+ ), ke = ({
48
48
  state: t,
49
49
  config: o,
50
50
  rowOptions: c,
51
51
  asyncRowOptionsFilter: k,
52
- checkedIds: x,
53
- rows: A,
54
- columns: B,
55
- onClose: u
52
+ checkedIds: w,
53
+ rows: B,
54
+ columns: g,
55
+ onClose: d
56
56
  }) => {
57
- const p = G(), s = f(() => p?.t ?? ((e) => e), [p]), b = $(null), [_, P] = I(null), [g, w] = I(-1), [h, U] = I(null), [y, C] = I({ status: "off" }), z = $(), l = f(
58
- () => t ? { ...t.target, close: u } : null,
59
- [t, u]
57
+ const p = G(), s = f(() => p?.t ?? ((e) => e), [p]), b = $(null), [O, P] = T(null), [C, x] = T(-1), [h, U] = T(null), [y, E] = T({ status: "off" }), z = $(), l = f(
58
+ () => t ? { ...t.target, close: d } : null,
59
+ [t, d]
60
60
  ), F = L(
61
61
  async (e, n, r) => {
62
62
  if (h) return;
63
- const i = await le(n);
64
- i ? (o?.onCopy?.(n, r), p?.showNotification?.("success", s("Copied to clipboard"))) : p?.showNotification?.("error", s("Could not copy to clipboard")), U({ key: e, isCopied: i }), z.current = setTimeout(() => u(), ee);
63
+ const i = await ae(n);
64
+ i ? (o?.onCopy?.(n, r), p?.showNotification?.("success", s("Copied to clipboard"))) : p?.showNotification?.("error", s("Could not copy to clipboard")), U({ key: e, isCopied: i }), z.current = setTimeout(() => d(), ne);
65
65
  },
66
- [o, p, s, u, h]
67
- ), E = L(
66
+ [o, p, s, d, h]
67
+ ), N = L(
68
68
  (e, n, r) => {
69
69
  const i = h?.key === e;
70
70
  return {
71
71
  key: e,
72
72
  label: i ? h?.isCopied ? s("Copied") : s("Copy failed") : n,
73
- icon: i && h?.isCopied ? /* @__PURE__ */ m(oe, { size: 16, className: "text-success-600 dark:text-success-400" }) : /* @__PURE__ */ m(ie, { size: 16 }),
73
+ icon: i && h?.isCopied ? /* @__PURE__ */ m(le, { size: 16, className: "text-success-600 dark:text-success-400" }) : /* @__PURE__ */ m(se, { size: 16 }),
74
74
  isDisabled: !r,
75
75
  keepOpenOnClick: !0,
76
76
  onClick: (a) => F(e, r, a)
77
77
  };
78
78
  },
79
79
  [h, F, s]
80
- ), X = f(() => Y(A, B, x), [A, B, x]), N = x?.length ?? 0, O = f(() => {
80
+ ), J = f(() => Y(t?.target.rowData, g), [t?.target.rowData, g]), X = f(() => t ? Z(B, g, w) : "", [t, B, g, w]), D = w?.length ?? 0, S = f(() => {
81
81
  if (!l) return [];
82
82
  const e = o?.hideDefaultItems ? [] : [
83
- E("copy-content", o?.copyLabel ?? s("Copy content"), l.text),
84
- E("copy-row", s("Copy row"), l.rowText),
85
- ...N > 0 ? [
86
- E(
83
+ N("copy-cell", o?.copyLabel ?? s("Copy Cell"), l.text),
84
+ N("copy-row", s("Copy Row"), J),
85
+ ...D > 0 ? [
86
+ N(
87
87
  "copy-selected-rows",
88
- N === 1 ? s("Copy selected row") : `${s("Copy selected rows")} (${N})`,
88
+ D === 1 ? s("Copy Selected Row") : `${s("Copy Selected Rows")} (${D})`,
89
89
  X
90
90
  )
91
91
  ] : []
92
92
  ], n = typeof o?.items == "function" ? o.items(l) : o?.items ?? [];
93
- return [...e, ...n].filter((r) => R(r.isVisible, l, !0));
94
- }, [o, l, E, N, X, s]), T = f(() => !t || o?.includeRowOptions === !1 || !c ? [] : ((typeof c == "function" ? c(t.target.rowData) : c) ?? []).filter((n) => n.isVisible !== !1), [t, c, o?.includeRowOptions]), H = T.length > 0;
93
+ return [...e, ...n].filter((r) => M(r.isVisible, l, !0));
94
+ }, [o, l, N, D, J, X, s]), R = f(() => !t || o?.includeRowOptions === !1 || !c ? [] : ((typeof c == "function" ? c(t.target.rowData) : c) ?? []).filter((n) => n.isVisible !== !1), [t, c, o?.includeRowOptions]), H = R.length > 0;
95
95
  v(() => {
96
96
  if (!t || !H || !k) {
97
- C({ status: "off" });
97
+ E({ status: "off" });
98
98
  return;
99
99
  }
100
100
  let e = !1;
101
- return C({ status: "loading" }), k(String(t.target.rowId)).then((n) => !e && C({ status: "ready", available: n })).catch(() => !e && C({ status: "failed" })), () => {
101
+ return E({ status: "loading" }), k(String(t.target.rowId)).then((n) => !e && E({ status: "ready", available: n })).catch(() => !e && E({ status: "failed" })), () => {
102
102
  e = !0;
103
103
  };
104
104
  }, [t, H, k]);
105
- const S = f(() => {
106
- if (y.status === "off") return T;
105
+ const A = f(() => {
106
+ if (y.status === "off") return R;
107
107
  if (y.status !== "ready") return [];
108
108
  const { available: e } = y;
109
- return T.filter((n) => e[n.key] ?? !0);
110
- }, [T, y]), d = f(() => {
111
- const e = O.map((r) => ({ kind: "item", key: r.key, item: r })), n = e.length > 0;
109
+ return R.filter((n) => e[n.key] ?? !0);
110
+ }, [R, y]), u = f(() => {
111
+ const e = S.map((r) => ({ kind: "item", key: r.key, item: r })), n = e.length > 0;
112
112
  return y.status === "loading" ? [...e, { kind: "skeleton", key: "row-options-loading", withDividerBefore: n }] : [
113
113
  ...e,
114
- ...S.map((r, i) => ({
114
+ ...A.map((r, i) => ({
115
115
  kind: "node",
116
116
  key: `row-option-${r.key}`,
117
117
  node: r.label,
118
118
  withDividerBefore: n && i === 0
119
119
  }))
120
120
  ];
121
- }, [O, S, y.status]), D = L(
122
- (e) => e.kind === "item" ? !(l && R(e.item.isDisabled, l, !1)) : e.kind === "node",
121
+ }, [S, A, y.status]), I = L(
122
+ (e) => e.kind === "item" ? !(l && M(e.item.isDisabled, l, !1)) : e.kind === "node",
123
123
  [l]
124
- ), V = f(() => d.findIndex(D), [d, D]);
125
- J(() => {
124
+ ), V = f(() => u.findIndex(I), [u, I]);
125
+ ee(() => {
126
126
  if (!t || !b.current) {
127
127
  P(null);
128
128
  return;
129
129
  }
130
- const { width: e, height: n } = b.current.getBoundingClientRect(), r = te, i = re, a = t.x + e + r > window.innerWidth ? t.x - e - i : t.x + i, K = t.y + n + r > window.innerHeight ? t.y - n - i : t.y + i;
130
+ const { width: e, height: n } = b.current.getBoundingClientRect(), r = re, i = ie, a = t.x + e + r > window.innerWidth ? t.x - e - i : t.x + i, K = t.y + n + r > window.innerHeight ? t.y - n - i : t.y + i;
131
131
  P({
132
132
  left: Math.max(r, Math.min(a, window.innerWidth - e - r)),
133
133
  top: Math.max(r, Math.min(K, window.innerHeight - n - r))
134
134
  });
135
- }, [t, d.length]), v(() => (U(null), () => clearTimeout(z.current)), [t]), v(() => {
135
+ }, [t, u.length]), v(() => (U(null), () => clearTimeout(z.current)), [t]), v(() => {
136
136
  if (!t) {
137
- w(-1);
137
+ x(-1);
138
138
  return;
139
139
  }
140
- w(V);
140
+ x(V);
141
141
  }, [t, V]), v(() => {
142
- if (!t || g < 0) return;
143
- const e = b.current?.querySelectorAll("[data-menu-item]")[g];
142
+ if (!t || C < 0) return;
143
+ const e = b.current?.querySelectorAll("[data-menu-item]")[C];
144
144
  (e?.matches("button") ? e : e?.querySelector("button") ?? e)?.focus({ preventScroll: !0 });
145
- }, [t, g]);
145
+ }, [t, C]);
146
146
  const W = L(
147
147
  (e) => {
148
- d.length !== 0 && w((n) => {
148
+ u.length !== 0 && x((n) => {
149
149
  let r = n;
150
- for (let i = 0; i < d.length; i += 1)
151
- if (r = (r + e + d.length) % d.length, D(d[r])) return r;
150
+ for (let i = 0; i < u.length; i += 1)
151
+ if (r = (r + e + u.length) % u.length, I(u[r])) return r;
152
152
  return n;
153
153
  });
154
154
  },
155
- [d, D]
155
+ [u, I]
156
156
  );
157
157
  if (v(() => {
158
158
  if (!t) return;
159
159
  const e = (a) => {
160
- b.current && !b.current.contains(a.target) && u();
160
+ b.current && !b.current.contains(a.target) && d();
161
161
  }, n = (a) => {
162
162
  if (a.key === "Escape") {
163
- a.stopPropagation(), u();
163
+ a.stopPropagation(), d();
164
164
  return;
165
165
  }
166
166
  (a.key === "ArrowDown" || a.key === "ArrowUp") && (a.preventDefault(), W(a.key === "ArrowDown" ? 1 : -1));
167
- }, r = () => u(), i = setTimeout(() => {
167
+ }, r = () => d(), i = setTimeout(() => {
168
168
  document.addEventListener("mousedown", e), document.addEventListener("touchstart", e), document.addEventListener("keydown", n), document.addEventListener("scroll", r, !0), window.addEventListener("resize", r);
169
169
  }, 0);
170
170
  return () => {
171
171
  clearTimeout(i), document.removeEventListener("mousedown", e), document.removeEventListener("touchstart", e), document.removeEventListener("keydown", n), document.removeEventListener("scroll", r, !0), window.removeEventListener("resize", r);
172
172
  };
173
- }, [t, u, W]), !t || !l || d.length === 0) return null;
173
+ }, [t, d, W]), !t || !l || u.length === 0) return null;
174
174
  if (p?.renderCellContextMenu)
175
- return p.renderCellContextMenu({ state: t, context: l, items: O, rowOptions: S, onClose: u });
175
+ return p.renderCellContextMenu({ state: t, context: l, items: S, rowOptions: A, onClose: d });
176
176
  const q = async (e) => {
177
- R(e.isDisabled, l, !1) || (e.keepOpenOnClick || u(), await e.onClick?.(l));
177
+ M(e.isDisabled, l, !1) || (e.keepOpenOnClick || d(), await e.onClick?.(l));
178
178
  };
179
- return Q(
179
+ return te(
180
180
  /* @__PURE__ */ m(
181
181
  "div",
182
182
  {
@@ -184,7 +184,7 @@ const le = async (t) => {
184
184
  role: "menu",
185
185
  "aria-label": s("Cell actions"),
186
186
  "data-testid": "cell-context-menu",
187
- className: M(
187
+ className: _(
188
188
  "fixed min-w-[180px] max-w-[280px] py-1 rounded-lg font-inter",
189
189
  "bg-white dark:bg-black-700",
190
190
  "border border-neutral-200 dark:border-black-600",
@@ -192,27 +192,27 @@ const le = async (t) => {
192
192
  o?.className
193
193
  ),
194
194
  style: {
195
- left: _?.left ?? t.x,
196
- top: _?.top ?? t.y,
197
- zIndex: ne,
195
+ left: O?.left ?? t.x,
196
+ top: O?.top ?? t.y,
197
+ zIndex: oe,
198
198
  // Hidden until measured so the flip/clamp never flashes at the wrong spot.
199
- visibility: _ ? "visible" : "hidden"
199
+ visibility: O ? "visible" : "hidden"
200
200
  },
201
201
  onContextMenu: (e) => e.preventDefault(),
202
- children: d.map((e, n) => /* @__PURE__ */ j(Z.Fragment, { children: [
202
+ children: u.map((e, n) => /* @__PURE__ */ j(Q.Fragment, { children: [
203
203
  (e.kind === "item" ? e.item.withDividerBefore && n > 0 : e.withDividerBefore) ? /* @__PURE__ */ m("div", { className: "my-1 h-px bg-neutral-200 dark:bg-black-600" }) : null,
204
204
  e.kind === "item" ? /* @__PURE__ */ m(
205
- se,
205
+ ce,
206
206
  {
207
207
  item: e.item,
208
- isDisabled: R(e.item.isDisabled, l, !1),
209
- isActive: n === g,
208
+ isDisabled: M(e.item.isDisabled, l, !1),
209
+ isActive: n === C,
210
210
  onSelect: () => void q(e.item),
211
- onHover: () => w(n)
211
+ onHover: () => x(n)
212
212
  }
213
213
  ) : e.kind === "skeleton" ? /* @__PURE__ */ m("div", { className: "px-3 py-2", "data-testid": "cell-context-menu-loading", children: /* @__PURE__ */ m("div", { className: "h-3.5 w-full animate-pulse rounded bg-neutral-200 dark:bg-black-600" }) }) : (
214
214
  /* Row actions are rendered as the table supplied them — they carry their own button and handler. */
215
- /* @__PURE__ */ m("div", { "data-menu-item": !0, tabIndex: -1, className: "outline-none [&_button]:w-full", onClick: u, onMouseEnter: () => w(n), children: e.node })
215
+ /* @__PURE__ */ m("div", { "data-menu-item": !0, tabIndex: -1, className: "outline-none [&_button]:w-full", onClick: d, onMouseEnter: () => x(n), children: e.node })
216
216
  )
217
217
  ] }, e.key))
218
218
  }
@@ -221,6 +221,6 @@ const le = async (t) => {
221
221
  );
222
222
  };
223
223
  export {
224
- he as CellContextMenuPortal
224
+ ke as CellContextMenuPortal
225
225
  };
226
226
  //# sourceMappingURL=CellContextMenuPortal.es.js.map