@vuu-ui/vuu-popups 0.8.10 → 0.8.11-debug

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.
package/cjs/index.js CHANGED
@@ -1,2 +1,1986 @@
1
- "use strict";var Bt=Object.create;var ae=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var $t=Object.getPrototypeOf,Kt=Object.prototype.hasOwnProperty;var Ft=(e,t)=>{for(var n in t)ae(e,n,{get:t[n],enumerable:!0})},We=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Ot(t))!Kt.call(e,r)&&r!==n&&ae(e,r,{get:()=>t[r],enumerable:!(o=St(t,r))||o.enumerable});return e};var k=(e,t,n)=>(n=e!=null?Bt($t(e)):{},We(t||!e||!e.__esModule?ae(n,"default",{value:e,enumerable:!0}):n,e)),Wt=e=>We(ae({},"__esModule",{value:!0}),e);var Bn={};Ft(Bn,{ContextMenu:()=>fe,ContextMenuContext:()=>re,ContextMenuProvider:()=>dn,Dialog:()=>Ut,DialogService:()=>se,MenuItem:()=>ne,MenuItemGroup:()=>te,MenuList:()=>de,Popup:()=>yn,PopupComponent:()=>Cn,PopupMenu:()=>Rn,PopupService:()=>L,Portal:()=>De,PortalDeprecated:()=>ee,Prompt:()=>kn,Separator:()=>Le,Tooltip:()=>Nn,createContainer:()=>ve,installTheme:()=>Vt,isMenuItemLabel:()=>me,reasonIsClickAway:()=>ke,reasonIsMenuAction:()=>He,renderPortal:()=>Z,useAnchoredPosition:()=>ie,useContextMenu:()=>Ae,useTooltip:()=>Dn});module.exports=Wt(Bn);var Ye=require("@salt-ds/lab"),le=require("@salt-ds/core"),we=k(require("classnames")),q=require("react");var _=require("react"),Ve=k(require("react-dom"));var qe=k(require("react-dom")),Ge=k(require("classnames")),qt=1,Gt=({className:e,dataMode:t,x:n=0,y:o=0,win:r=window})=>{let s=r.document.createElement("div");return s.className=(0,Ge.default)(`vuuPopup ${qt++}`,e),s.style.cssText=`left:${n}px; top:${o}px;`,t&&(s.dataset.mode=t),r.document.body.appendChild(s),s},ve=e=>Gt(e),Z=(e,t,n,o,r)=>{t.style.cssText=`left:${n}px; top:${o}px;position: absolute;`,qe.render(e,t,r)};var Ue=require("@vuu-ui/vuu-shell"),Xe=k(require("classnames")),ee=function({children:t,x:n=0,y:o=0,onRender:r}){let[s,u,p]=(0,Ue.useThemeAttributes)(),a=(0,_.useMemo)(()=>ve({className:(0,Xe.default)(s,u),dataMode:p}),[p,u,s]);return(0,_.useLayoutEffect)(()=>{Z(t,a,n,o,r)},[t,r,a,n,o]),(0,_.useLayoutEffect)(()=>()=>{var i;a&&(Ve.unmountComponentAtNode(a),a.classList.contains("vuuPopup")&&((i=a.parentElement)==null||i.removeChild(a)))},[a]),null};var Vt=e=>{let t=getComputedStyle(document.body).getPropertyValue("--installed-themes");document.body.style.setProperty("--installed-themes",`${t} ${e}`)};var W=require("react/jsx-runtime"),Ee="vuuDialog",Ut=({children:e,className:t,isOpen:n=!1,onClose:o,title:r,hideCloseButton:s=!1,...u})=>{let p=(0,q.useRef)(null),[a]=(0,q.useState)(0),[i]=(0,q.useState)(0),m=(0,q.useCallback)(()=>{o==null||o()},[o]),l=(0,q.useCallback)(()=>{},[]);return n?(0,W.jsx)(ee,{onRender:l,x:a,y:i,children:(0,W.jsx)(Ye.Scrim,{className:`${Ee}-scrim`,open:n,autoFocusRef:p,children:(0,W.jsxs)("div",{...u,className:(0,we.default)(Ee,t),ref:p,children:[(0,W.jsxs)("div",{className:(0,we.default)("vuuToolbarProxy",`${Ee}-header`),children:[(0,W.jsx)(le.Text,{className:"dialogHeader",children:r}),!s&&(0,W.jsx)(le.Button,{onClick:m,"data-align":"end","data-icon":"close"},"close")]}),e]})})}):null};var X=require("react");var K=k(require("react")),Te=k(require("classnames")),nt=require("@vuu-ui/vuu-layout");var B=require("react");var ze=e=>e.closest("[data-root='true']")!==null,Je=(e,t)=>{var n;return e.ariaHasPopup==="true"&&((n=e.dataset)==null?void 0:n.idx)===`${t}`||e.querySelector(`:scope > [data-idx='${t}'][aria-haspopup='true']`)!==null};function Xt(e,...t){let n=new Set(e);for(let o of t)for(let r of o)n.add(r);return n}var Yt="Enter";var zt="Delete",Jt=new Set([Yt,zt]),jt=new Set(["Tab"]),Qt=new Set(["ArrowRight","ArrowLeft"]),je=new Set(["Home","End","ArrowDown","ArrowUp"]),Qe=new Set(["Home","End","ArrowRight","ArrowLeft"]),Zt=new Set(["F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"]),to=Xt(Jt,Qe,je,Qt,Zt,jt);var Ze=({key:e},t="vertical")=>(t==="vertical"?je:Qe).has(e);var pe=require("@vuu-ui/vuu-utils"),_e=({autoHighlightFirstItem:e=!1,count:t,defaultHighlightedIdx:n,highlightedIndex:o,onActivate:r,onHighlight:s,onCloseMenu:u,onOpenMenu:p})=>{var I;if((0,pe.isValidNumber)(o)&&(0,pe.isValidNumber)(n))throw Error("useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx");let a=(0,pe.isValidNumber)(o),i=(0,B.useRef)((I=n!=null?n:o)!=null?I:e?0:-1),[,m]=(0,B.useState)(null),l=(0,B.useCallback)(C=>{i.current=C,s==null||s(C),m({})},[s]),c=(0,B.useCallback)(C=>{C!==i.current&&(a||l(C))},[a,l]),f=(0,B.useRef)(!0),v=(0,B.useRef)(!1),b=C=>v.current=C,P=a?o:i.current,y=(0,B.useCallback)(C=>{let g=_t(t,C.key,i.current);g!==i.current&&c(g)},[t,c]),E=(0,B.useCallback)(C=>{if(Ze(C))C.preventDefault(),C.stopPropagation(),f.current=!0,y(C);else if((C.key==="ArrowRight"||C.key==="Enter")&&Je(C.target,P)){let d=C.target.querySelector(`:scope > [data-idx='${P}']`);d&&(p==null||p(d))}else C.key==="ArrowLeft"&&!ze(C.target)?u(P):C.key==="Enter"?(C.preventDefault(),C.stopPropagation(),r&&r(P)):C.key==="Tab"&&u(-1)},[P,y,r,u,p]),x=(0,B.useMemo)(()=>({onFocus:()=>{P===-1&&l(0)},onKeyDown:E,onMouseDownCapture:()=>{f.current=!1,b(!0)},onMouseMove:()=>{f.current&&(f.current=!1)},onMouseLeave:()=>{f.current=!0,b(!1),c(-1)}}),[E,P,l,c]);return{focusVisible:f.current?P:-1,controlledHighlighting:a,highlightedIndex:P,setHighlightedIndex:c,listProps:x,setIgnoreFocus:b}};function _t(e,t,n){return t==="ArrowUp"?n>0?n-1:n:n===null?0:n===e-1?n:n+1}var U=k(require("react"));var Re=e=>e.type===te||!!e.props["data-group"],en=e=>{if(Array.isArray(e)&&me(e[0]))return e[0]},tn=(e,t,n,o=!1)=>{let{props:{children:r}}=e;return{childWithId:U.default.cloneElement(e,{hasSeparator:o,id:`${t}`,key:t,children:n?en(r):r}),grandChildren:n?r:void 0}},et=(e,t)=>{let n=(0,U.useCallback)(()=>{let s=(u,p=t,a={},i={})=>{let m=a[p]=[],l=0,c=!1;return U.default.Children.forEach(u,f=>{if(!me(f))if(f.type===Le)c=!0;else{let v=Re(f),b=`${p}-${l}`,{props:{action:P,options:y}}=f,{childWithId:E,grandChildren:x}=tn(f,b,v,c);m.push(E),x?s(x,b,a,i):i[b]={action:P,options:y},l+=1,c=!1}}),[a,i]};return s(e)},[t,e]),[o,r]=(0,U.useMemo)(()=>n(),[n]);return[o,r]};var $=require("react/jsx-runtime"),tt="vuuMenuList",Le=()=>(0,$.jsx)("li",{className:"vuuMenuItem-divider"}),te=()=>null,ne=({children:e,idx:t,...n})=>(0,$.jsx)("div",{...n,children:e}),ot=({children:e})=>(0,$.jsx)($.Fragment,{children:e});ot.displayName="MenuItemLabel";ne.Label=ot;var nn=e=>K.default.isValidElement(e)&&typeof e.type!="string"&&"displayName"in e.type?e.type.displayName:void 0,me=e=>nn(e)==="MenuItemLabel",on=e=>e.props["data-icon"],de=({activatedByKeyboard:e,childMenuShowing:t,children:n,className:o,defaultHighlightedIdx:r,highlightedIdx:s,id:u,isRoot:p,listItemProps:a,onHighlightMenuItem:i,onActivate:m,onCloseMenu:l,onOpenMenu:c,...f})=>{let v=(0,nt.useId)(u),b=(0,K.useRef)(null),P=(0,K.useMemo)(()=>new Map,[]),y=h=>{var w;let M=(w=b.current)==null?void 0:w.querySelector(`:scope > [data-idx='${h}']`);M!=null&&M.id&&(m==null||m(M.id))},{focusVisible:E,highlightedIndex:x,listProps:I}=_e({count:K.default.Children.count(n),defaultHighlightedIdx:r,highlightedIndex:s,onActivate:y,onHighlight:i,onOpenMenu:c,onCloseMenu:l}),C=t==null?E:-1;(0,K.useLayoutEffect)(()=>{var h;t===void 0&&e&&((h=b.current)==null||h.focus())},[e,t]);let g=()=>x===void 0||x===-1?void 0:P.get(x);function d(){let h={...a,role:"menuitem"},M=(R,H,D)=>H?[(0,$.jsx)("span",{className:"vuuIconContainer","data-icon":D},"icon")].concat(R):R;function w(R,H,D,Se){var Fe;let{children:Oe,className:kt,"data-icon":$e,id:ce,hasSeparator:At,label:Ce,...Nt}=H.props,xe=Re(H),Ke=xe&&t===ce,Dt=Ke?`${v}-${ce}`:void 0;R.push((0,$.jsx)(ne,{...Nt,...h,...rn(ce,D,(Fe=H.key)!=null?Fe:ce,x,C,kt,At),"aria-controls":Dt,"aria-haspopup":xe||void 0,"aria-expanded":Ke||void 0,children:M(xe&&Ce!=null?Ce:Oe,Se,$e)}))}let N=[];if(n.length>0){let R=n.some(on);n.forEach((H,D)=>{w(N,H,D,R)})}return N}return(0,$.jsx)("div",{...f,...I,"aria-activedescendant":g(),className:(0,Te.default)(tt,o,{[`${tt}-childMenuShowing`]:t!==void 0}),"data-root":p||void 0,id:v,ref:b,role:"menu",children:d()})},rn=(e,t,n,o,r,s,u)=>({id:`menuitem-${e}`,key:n!=null?n:t,"data-idx":t,"data-highlighted":t===o||void 0,className:(0,Te.default)("vuuMenuItem",s,{"vuuMenuItem-separator":u,focusVisible:r===t})});de.displayName="MenuList";var T=require("react");var Ie=e=>e==null?void 0:e.closest("[data-idx],[aria-posinset]");var st=(e,t,n)=>e.map((o,r)=>r===e.length-1?{...o,[n]:o[n]-t}:o),sn=(e,t)=>st(e,t,"left"),un=(e,t)=>st(e,t,"top"),cn=(e,t)=>{let[n,o]=t.slice(-2),r=document.getElementById(`${e}-${o.id}`);if(r===null)throw Error(`useCascade.flipSides element with id ${o.id} not found`);let{width:s}=r.getBoundingClientRect();return t.map(u=>u===o?{...u,left:n.left-(s-2)}:u)},an=(e,t)=>{let[{left:n,top:o}]=t.slice(-1),{offsetWidth:r,offsetTop:s}=e;return{left:n+r,top:s+o}},it=(e,t)=>{let n=e.lastIndexOf("-");return n>-1?e.slice(9,n):t},ln=e=>e.slice(9),rt=({ariaExpanded:e,ariaHasPopup:t,id:n},o)=>{if(n.startsWith("menuitem"))return{hostMenuId:it(n,o),targetMenuId:ln(n),menuItemId:n,isGroup:t==="true",isOpen:e==="true"};throw Error(`getMenuItemDetails #${n} is not a menuitem`)},ut=({id:e,onActivate:t,onMouseEnterItem:n,position:{x:o,y:r}})=>{let[,s]=(0,T.useState)({}),u=(0,T.useRef)([{id:e,left:o,top:r}]),p=(0,T.useCallback)(g=>u.current.findIndex(d=>d.id===g)!==-1,[]),a=(0,T.useCallback)(g=>{let d=c.current[g];if(d===void 0)throw Error(`getOpenMenuState no entry for menu ${g}`);return d},[]),i=(0,T.useCallback)(g=>{u.current=g,s({})},[]),m=(0,T.useRef)(),l=(0,T.useRef)(),c=(0,T.useRef)({[e]:"no-popup"}),f=(0,T.useCallback)((g=e,d,h=null)=>{if(g===e&&h===null)i([{id:e,left:o,top:r}]);else{c.current[g]="popup-open";let M=document.getElementById(h);if(M!==null){let{left:w,top:N}=an(M,u.current);i(u.current.concat({id:d,left:w,top:N}))}else throw Error(`openMenu no menuItem ${h}`)}},[e,o,r,i]),v=(0,T.useCallback)(g=>{if(g===e)i([]);else{let d=u.current.slice(),h=d.pop();c.current[h.id]="no-popup";let M=d.at(-1);M&&(c.current[M.id]="no-popup"),i(d)}},[e,i]),b=(0,T.useCallback)(g=>{let d=u.current.slice(),h=g.slice(9),{id:M}=d.at(-1);for(;d.length>1&&!h.startsWith(M);){let w=it(M,e);d.pop(),c.current[M]="no-popup",c.current[w]="no-popup",{id:M}=d[d.length-1]}d.length<u.current.length&&i(d)},[e,i]),P=(0,T.useCallback)(()=>{m.current&&(clearTimeout(m.current),m.current=void 0)},[]),y=(0,T.useCallback)((g,d,h)=>{P(),m.current=window.setTimeout(()=>{b(h),c.current[g]="popup-open",c.current[d]="no-popup",f(g,d,h)},400)},[P,b,f]),E=(0,T.useCallback)((g,d,h)=>{c.current[d]="pending-close",l.current=window.setTimeout(()=>{b(h)},400)},[b]),x=(0,T.useCallback)(()=>{let{current:g}=u,[d]=g.slice(-1),h=document.getElementById(d.id);if(h){let{right:M,bottom:w}=h.getBoundingClientRect(),{clientHeight:N,clientWidth:R}=document.body;if(M>R){let H=g.length>1?cn(e,g):sn(g,M-R);i(H)}else if(w>N){let H=un(g,w-N);i(H)}typeof h.tabIndex=="number"&&h.focus()}else console.log(`no element found with if ${d.id}`)},[e,i]),I=(0,T.useCallback)(g=>{let{hostMenuId:d,targetMenuId:h,menuItemId:M,isGroup:w,isOpen:N}=rt(g,e),{current:{[d]:R}}=c;if(R==="no-popup"&&w)c.current[d]="popup-pending",y(d,h,M);else if(R==="popup-pending"&&!w)c.current[d]="no-popup",clearTimeout(m.current),m.current=void 0;else if(R==="popup-pending"&&w)clearTimeout(m.current),y(d,h,M);else if(R==="popup-open")if(p(h)){let H=a(h);switch(b(M),H){case"pending-close":clearTimeout(l.current),l.current=void 0,c.current[h]="no-popup",P();break;default:}}else{let[H,D]=u.current.slice(-2);H.id===d&&c.current[D.id]!=="pending-close"?(E(d,D.id,M),w&&!N&&y(d,h,M)):H.id===d&&w&&M!==D.id&&c.current[D.id]==="pending-close"||w?y(d,h,M):c.current[D.id]!=="pending-close"&&b(M)}R==="pending-close"&&(P(),clearTimeout(l.current),l.current=void 0,c.current[d]="popup-open")},[P,b,a,p,e,E,y]),C=(0,T.useMemo)(()=>({onMouseEnter:g=>{let d=Ie(g.target);I(d),n(g,d.id)},onClick:g=>{let d=Ie(g.target),{isGroup:h,menuItemId:M}=rt(d,e);h?I(d):t(M)}}),[t,n,e,I]);return{closeMenu:v,handleRender:x,listItemProps:C,openMenu:I,openMenus:u.current}};var ct=require("@vuu-ui/vuu-layout");var oe=require("react/jsx-runtime"),at=require("react"),pn=()=>{},fe=({activatedByKeyboard:e,children:t,className:n,id:o,onClose:r=()=>{},position:s={x:0,y:0},style:u,...p})=>{let a=(0,X.useRef)(r);a.current=r;let i=(0,ct.useId)(o),m=(0,X.useRef)(pn),[l,c]=et(t,i),f=(0,X.useRef)(e),v=(0,X.useCallback)(()=>{f.current=!1},[]),b=(0,X.useCallback)(M=>{let w=M.slice(9),{action:N,options:R}=c[w];m.current(i),r({type:"menu-action",menuId:N,options:R})},[c,i,r]),{closeMenu:P,listItemProps:y,openMenu:E,openMenus:x,handleRender:I}=ut({id:`${i}`,onActivate:b,onMouseEnterItem:v,position:s});m.current=P;let C=()=>{f.current=!0,P()},g=()=>{},d=x.length-1,h=M=>{if(!(M>=d)){let{id:w}=x[M+1];return w}};return(0,oe.jsx)(oe.Fragment,{children:x.map(({id:M,left:w,top:N},R,H)=>{let D=h(R);return(0,oe.jsx)(ee,{x:w,y:N,onRender:I,children:(0,at.createElement)(de,{...p,activatedByKeyboard:f.current,childMenuShowing:D,className:n,id:M,isRoot:R===0,key:R,listItemProps:y,onActivate:b,onHighlightMenuItem:g,onCloseMenu:C,onOpenMenu:E,style:u,tabIndex:R===H.length-1?0:void 0},l[M])},R)})})};fe.displayName="ContextMenu";var z=require("react"),Me=require("react/jsx-runtime"),re=(0,z.createContext)(null),mn=({children:e,context:t,menuActionHandler:n,menuBuilder:o})=>{let r=(0,z.useMemo)(()=>t!=null&&t.menuBuilders&&o?t.menuBuilders.concat(o):o?[o]:(t==null?void 0:t.menuBuilders)||[],[t,o]),s=(0,z.useCallback)(u=>{var p;if(n!=null&&n(u)||(p=t==null?void 0:t.menuActionHandler)!=null&&p.call(t,u))return!0},[t,n]);return(0,Me.jsx)(re.Provider,{value:{menuActionHandler:s,menuBuilders:r},children:e})},dn=({children:e,label:t,menuActionHandler:n,menuBuilder:o})=>(0,Me.jsx)(re.Consumer,{children:r=>(0,Me.jsx)(mn,{context:r,label:t,menuActionHandler:n,menuBuilder:o,children:e})});var ht=require("@vuu-ui/vuu-shell"),bt=require("@vuu-ui/vuu-utils"),yt=k(require("classnames")),G=require("react");var lt=k(require("classnames")),O=k(require("react")),J=k(require("react-dom"));var Y=!1,S=[],He=e=>(e==null?void 0:e.type)==="menu-action",ke=e=>(e==null?void 0:e.type)==="click-away";function ge(e){if(e.key==="Esc"){if(S.length)mt();else if(Y){let t=document.body.querySelector(".vuuDialog");t&&J.default.unmountComponentAtNode(t)}}}function pt(e){if(S.length){let t=document.body.querySelectorAll(".vuuPopup");for(let n=0;n<t.length;n++)if(t[n].contains(e.target))return;mt({mouseEvt:e,type:"click-away"})}}function mt(e){if(S.length===1)L.hidePopup(e,"anon","all");else if(S.length){let t=document.body.querySelectorAll(".vuuPopup");for(let n=0;n<t.length;n++)J.default.unmountComponentAtNode(t[n]);dt("*")}}function fn(){Y===!1&&(Y=!0,window.addEventListener("keydown",ge,!0))}function Mn(){Y&&(Y=!1,window.removeEventListener("keydown",ge,!0))}function gn(e){S.indexOf(e)===-1&&(S.push(e),Y===!1&&(window.addEventListener("keydown",ge,!0),window.addEventListener("click",pt,!0)))}function dt(e){if(S.length){if(e==="*")S.length=0;else{let t=S.indexOf(e);t!==-1&&S.splice(t,1)}S.length===0&&Y===!1&&(window.removeEventListener("keydown",ge,!0),window.removeEventListener("click",pt,!0))}}var hn=({children:e,position:t,style:n})=>{let o=(0,lt.default)("hwPopup","hwPopupContainer",t);return(0,O.createElement)("div",{className:o,style:n},e)},bn=1,L=class{static showPopup({group:t="all",name:n="anon",left:o=0,position:r="",right:s="auto",top:u=0,width:p="auto",component:a}){if(!a)throw Error("PopupService showPopup, no component supplied");typeof a.props.onClose=="function"?L.onClose=a.props.onClose:L.onClose=void 0,gn(n),document.addEventListener("keydown",L.escapeKeyListener,!0);let i=document.body.querySelector(".vuuPopup."+t);i===null&&(i=document.createElement("div"),i.className="vuuPopup "+t,document.body.appendChild(i));let m={width:p};Z((0,O.createElement)(hn,{key:bn++,position:r,style:m},a),i,o,u,()=>{L.keepWithinThePage(i,s)})}static escapeKeyListener(t){t.key==="Escape"&&L.hidePopup({type:"escape",event:t})}static hidePopup(t,n="anon",o="all"){var r;if(S.indexOf(n)!==-1){dt(n);let s=document.body.querySelector(`.vuuPopup.${o}`);s&&J.default.unmountComponentAtNode(s)}document.removeEventListener("keydown",L.escapeKeyListener,!0),(r=L==null?void 0:L.onClose)==null||r.call(L,t)}static keepWithinThePage(t,n="auto"){let o=t.querySelector(".vuuPopupContainer > *");if(o){let{top:r,left:s,width:u,height:p,right:a}=o.getBoundingClientRect(),i=window.innerWidth,l=window.innerHeight-(r+p);l<0&&(o.style.top=Math.round(r)+l+"px");let c=i-(s+u);if(c<0&&(o.style.left=Math.round(s)+c+"px"),typeof n=="number"&&n!==a){let f=n-a;o.style.left=s+f+"px"}}}},se=class{static showDialog(t){let n=".vuuDialog",o=t.props.onClose;fn(),J.default.render(O.default.cloneElement(t,{container:n,onClose:()=>{se.closeDialog(),o&&o()}}),document.body.querySelector(n))}static closeDialog(){Mn();let t=document.body.querySelector(".vuuDialog");t&&J.default.unmountComponentAtNode(t)}},yn=e=>{let t=(0,O.useRef)(),n=(0,O.useRef)(null),o=(r,s)=>{let{name:u,group:p,depth:a,width:i}=r,m,l;if(t.current&&(window.clearTimeout(t.current),t.current=void 0),r.close===!0)L.hidePopup(void 0,u,p);else{let{position:c,children:f}=r,{left:v,top:b,width:P,bottom:y}=s;c==="below"?(m=v,l=y):c==="above"&&(m=v,l=b),t.current=window.setTimeout(()=>{L.showPopup({name:u,group:p,depth:a,position:c,left:m,top:l,width:i||P,component:f})},10)}};return(0,O.useEffect)(()=>{if(n.current){let r=n.current.parentElement,s=r==null?void 0:r.getBoundingClientRect();s&&o(e,s)}return()=>{L.hidePopup(void 0,e.name,e.group)}},[e]),O.default.createElement("div",{className:"popup-proxy",ref:n})};var ft=k(require("classnames")),Mt=require("@vuu-ui/vuu-shell");var he=require("react"),Pn=(e,t,n,o)=>{let{bottom:r,left:s,right:u,top:p,width:a}=e.getBoundingClientRect();switch(t){case"below":return{left:s+n,top:r+o};case"right":return{left:u+n,top:p+o};case"below-center":return{left:s+a/2+n,top:r+o};case"below-full-width":return{left:s+n,top:r+o,width:a};default:throw Error("Popup getPositionRelativeToAnchor only supported placement values are below and right")}},ie=({anchorElement:e,offsetLeft:t=0,offsetTop:n=0,placement:o})=>{let[r,s]=(0,he.useState)();return(0,he.useLayoutEffect)(()=>{if(e.current){let u=Pn(e.current,o,t,n);s(u)}},[e,t,n,o]),r};var gt=require("react/jsx-runtime"),Cn=({children:e,className:t,anchorElement:n,placement:o})=>{let[r,s,u]=(0,Mt.useThemeAttributes)(),p=ie({anchorElement:n,placement:o});return p===void 0?null:(0,gt.jsx)("div",{className:(0,ft.default)("vuuPortal",t,r,s),"data-mode":u,style:p,children:e})};var be=require("react/jsx-runtime"),Ae=(e,t)=>{let n=(0,G.useContext)(re),[o,r,s]=(0,ht.useThemeAttributes)(),u=(0,G.useCallback)((i,m,l)=>{let c=[];for(let f of i)c=c.concat(f(m,l));return c},[]),p=(0,G.useCallback)((i,m,{ContextMenuProps:l,contextMenu:c,...f})=>{var b,P;if((b=i.stopPropagation)==null||b.call(i),(P=i.preventDefault)==null||P.call(i),c)return vn({x:i.clientX,y:i.clientY},c);let v=[];if(e&&v.push(e),n&&Array.isArray(n==null?void 0:n.menuBuilders)&&n.menuBuilders.length>0&&v.push(...n.menuBuilders),v.length>0){let y=u(v,m,f),E=x=>(t==null?void 0:t(x))===!0?!0:n==null?void 0:n.menuActionHandler(x);y.length&&E&&En(i,y,E,{...l,className:(0,yt.default)(l==null?void 0:l.className,o,r),"data-mode":s})}else console.warn("useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)")},[u,n,s,r,t,e,o]),a=(0,G.useCallback)(()=>{console.log("hide comnytext menu")},[]);return[p,a]},xn={},vn=(e,t)=>{L.showPopup({focus:!0,left:0,top:0,component:(0,G.cloneElement)(t,{position:e})})},En=(e,t,n,{position:o,...r}=xn)=>{let s=i=>{let m=(l,c)=>(0,bt.isGroupMenuItemDescriptor)(l)?(0,be.jsx)(te,{label:l.label,children:l.children.map(m)},c):(0,be.jsx)(ne,{action:l.action,className:l.className,"data-icon":l.icon,options:l.options,children:l.label},c);return i.map(m)},u=i=>{var m;He(i)&&(n(i),L.hidePopup()),(m=r==null?void 0:r.onClose)==null||m.call(r,i)},p=o!=null?o:{x:e.clientX,y:e.clientY},a=(0,be.jsx)(fe,{...r,className:"vuuContextMenu",onClose:u,position:p,children:s(t)});L.showPopup({left:0,top:0,component:a,focus:!0})};var V=require("react");var Pt=k(require("classnames")),Ct=require("@salt-ds/core"),xt=require("@vuu-ui/vuu-layout");var vt=require("react/jsx-runtime"),Ne="vuuPopupMenu",wn=e=>{if(e){let{bottom:t,left:n}=e.getBoundingClientRect();return{x:n,y:t+6}}},Rn=({className:e,label:t,icon:n=t?"chevron-down":"more-vert",id:o,menuActionHandler:r,menuBuilder:s,menuLocation:u="header",menuOptions:p,onMenuClose:a,tabIndex:i=0,...m})=>{let l=(0,V.useRef)(null),c=(0,V.useRef)(!1),[f,v]=(0,V.useState)(!1),b=(0,xt.useId)(o),[P]=Ae(s,r),y=(0,V.useCallback)(x=>{v(!1),ke(x)?x.mouseEvt.target===l.current&&(c.current=!0):requestAnimationFrame(()=>{var I;a==null||a(x),i!==-1&&((I=l.current)==null||I.focus())})},[a,i]),E=(0,V.useCallback)(x=>{c.current?c.current=!1:(v(!0),P(x,u,{ContextMenuProps:{className:"vuuPopupMenuList",id:`${b}-menu`,onClose:y,position:wn(l.current)},...p}))},[y,b,u,p,P]);return(0,vt.jsx)(Ct.Button,{...m,"aria-controls":`${b}-menu-root`,"aria-expanded":f,"aria-haspopup":"menu",className:(0,Pt.default)(Ne,e,{[`${Ne}-withCaption`]:t!==void 0,[`${Ne}-open`]:f}),"data-icon":n,id:b,onClick:E,ref:l,tabIndex:i,variant:"secondary",children:t})};var Et=require("@vuu-ui/vuu-shell"),j=require("react"),wt=require("react-dom");function Ln(e){return typeof e=="function"?e():e}var Tn="vuu-portal-root",De=({children:e,container:t=document.body,id:n=Tn,open:o=!0})=>{var l;let[r,s]=(0,j.useState)(!1),u=(0,j.useRef)(null),p=(l=Ln(t))!=null?l:document.body,[a,i,m]=(0,Et.useThemeAttributes)();return(0,j.useLayoutEffect)(()=>{let c=document.getElementById(n);c?u.current=c:(u.current=document.createElement("div"),u.current.id=n);let f=u.current;p.contains(f)||p.appendChild(f),f.classList.add(a,i),f.dataset.mode=m,s(!0)},[n,p,a,i,m]),o&&r&&u.current&&e?(0,wt.createPortal)(e,u.current):null};var Rt=require("@vuu-ui/vuu-shell"),Be=require("@salt-ds/core"),Lt=k(require("classnames")),ue=require("react");var F=require("react/jsx-runtime"),Q="vuuPrompt",In={current:document.body},Hn={},kn=({PopupProps:e=Hn,cancelButtonLabel:t="Cancel",confirmButtonLabel:n="Confirm",icon:o,onCancel:r,onConfirm:s,style:u,text:p,title:a,variant:i="info",...m})=>{let{anchorElement:l=In,offsetLeft:c=0,offsetTop:f=0,placement:v="below"}=e,[b,P,y]=(0,Rt.useThemeAttributes)(),E=ie({anchorElement:l,offsetLeft:c,offsetTop:f,placement:v}),x=(0,ue.useRef)(null),I=(0,ue.useRef)(null);return(0,ue.useLayoutEffect)(()=>{if(x.current&&(x.current.showModal(),I.current&&I.current.focus(),v.endsWith("center"))){let{width:C}=x.current.getBoundingClientRect();x.current.style.marginLeft=`-${C/2}px`}},[v]),(0,F.jsx)("dialog",{...m,className:(0,Lt.default)(Q,`${Q}-${i}`,b),"data-mode":y,ref:x,style:{...u,...E},children:(0,F.jsxs)("form",{className:`${Q}-form`,children:[(0,F.jsx)("div",{className:`${Q}-header`,"data-icon":o,children:a}),(0,F.jsx)("div",{className:`${Q}-text`,children:p}),(0,F.jsxs)("div",{className:`${Q}-buttonBar`,children:[(0,F.jsx)(Be.Button,{onClick:r,variant:"secondary",children:t}),(0,F.jsx)(Be.Button,{onClick:s,ref:I,value:"default",children:n})]})]})})};var ye=require("react"),An=(e,t,n,o)=>{let{bottom:r,height:s,left:u,right:p,top:a,width:i}=e.getBoundingClientRect(),m=u+i/2,l=a+s/2;switch(t){case"above":return{left:m+n,top:a+o};case"below":return{left:m+n,top:r+o};case"right":return{left:p+n,top:l+n};case"left":return{left:u+n,top:l+n};default:throw Error("Tooltip getPositionRelativeToAnchor only supported placement values are left, right, below and right")}},Tt=({anchorElement:e,offsetLeft:t=0,offsetTop:n=0,placement:o})=>{let[r,s]=(0,ye.useState)();return(0,ye.useLayoutEffect)(()=>{if(e.current){let u=An(e.current,o,t,n);s(u)}},[e,t,n,o]),r};var Pe=require("react/jsx-runtime"),It="vuuTooltip",Nn=({anchorElement:e,children:t,id:n,onMouseEnter:o,onMouseLeave:r,placement:s})=>{let u=Tt({anchorElement:e,placement:s});return u===void 0?null:(0,Pe.jsx)(De,{children:(0,Pe.jsx)("div",{className:It,"data-align":s,id:n,style:u,children:(0,Pe.jsx)("span",{className:`${It}-content`,onMouseEnter:o,onMouseLeave:r,children:t})})})};var A=require("react"),Ht=require("@vuu-ui/vuu-layout"),Dn=({id:e,placement:t="right",tooltipContent:n})=>{let o=(0,A.useRef)(),r=(0,A.useRef)(null),s=(0,A.useRef)(),u=(0,A.useRef)(),[p,a]=(0,A.useState)(),i=(0,Ht.useId)(e),m=(0,A.useCallback)(y=>{var E;y.key==="Escape"&&((E=o.current)==null||E.call(o))},[]);o.current=(0,A.useCallback)(()=>{a(void 0),document.removeEventListener("keydown",m)},[m]);let l=(0,A.useCallback)(()=>{window.clearTimeout(u.current)},[]),c=(0,A.useCallback)(()=>{var y;(y=o.current)==null||y.call(o)},[]),f=(0,A.useCallback)(()=>{let{current:y}=r;y&&(a({anchorElement:r,children:n,id:`${i}-tooltip`,onMouseEnter:l,onMouseLeave:c,placement:t}),document.addEventListener("keydown",m)),s.current=void 0},[m,l,c,i,t,n]),v=(0,A.useCallback)(y=>{let E=y.target;E&&(r.current=E,s.current=window.setTimeout(f,800))},[f]),b=(0,A.useCallback)(()=>{r.current&&(s.current?(window.clearTimeout(s.current),s.current=void 0):o.current&&(u.current=window.setTimeout(o.current,200)))},[]);return{anchorProps:{"aria-describedby":`${i}-tooltip`,onMouseEnter:v,onMouseLeave:b},tooltipProps:p}};
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ ContextMenu: () => ContextMenu,
34
+ ContextMenuContext: () => ContextMenuContext,
35
+ ContextMenuProvider: () => ContextMenuProvider,
36
+ Dialog: () => Dialog,
37
+ DialogHeader: () => DialogHeader,
38
+ DialogService: () => DialogService,
39
+ MenuItem: () => MenuItem,
40
+ MenuItemGroup: () => MenuItemGroup,
41
+ MenuList: () => MenuList,
42
+ NotificationLevel: () => NotificationLevel,
43
+ NotificationsContext: () => NotificationsContext,
44
+ NotificationsProvider: () => NotificationsProvider,
45
+ PopupComponent: () => PopupComponent,
46
+ PopupMenu: () => PopupMenu,
47
+ PopupService: () => PopupService,
48
+ Portal: () => Portal,
49
+ Prompt: () => Prompt,
50
+ Separator: () => Separator,
51
+ ToastNotification: () => ToastNotification,
52
+ Tooltip: () => Tooltip,
53
+ createContainer: () => createContainer,
54
+ isMenuItemLabel: () => isMenuItemLabel,
55
+ reasonIsClickAway: () => reasonIsClickAway,
56
+ reasonIsMenuAction: () => reasonIsMenuAction,
57
+ renderPortal: () => renderPortal,
58
+ useAnchoredPosition: () => useAnchoredPosition,
59
+ useContextMenu: () => useContextMenu,
60
+ useNotifications: () => useNotifications,
61
+ useTooltip: () => useTooltip
62
+ });
63
+ module.exports = __toCommonJS(src_exports);
64
+
65
+ // src/dialog/Dialog.tsx
66
+ var import_lab = require("@salt-ds/lab");
67
+ var import_classnames2 = __toESM(require("classnames"));
68
+ var import_react2 = require("react");
69
+
70
+ // src/portal/Portal.tsx
71
+ var import_vuu_shell = require("@vuu-ui/vuu-shell");
72
+ var import_react = require("react");
73
+ var import_react_dom = require("react-dom");
74
+ function getContainer(container) {
75
+ return typeof container === "function" ? container() : container;
76
+ }
77
+ var DEFAULT_ID = "vuu-portal-root";
78
+ var Portal = ({
79
+ children,
80
+ container: containerProp = document.body,
81
+ id = DEFAULT_ID,
82
+ onRender,
83
+ open = true,
84
+ themeAttributes
85
+ }) => {
86
+ var _a;
87
+ const [mounted, setMounted] = (0, import_react.useState)(false);
88
+ const portalRef = (0, import_react.useRef)(null);
89
+ const container = (_a = getContainer(containerProp)) != null ? _a : document.body;
90
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell.useThemeAttributes)(themeAttributes);
91
+ (0, import_react.useLayoutEffect)(() => {
92
+ const root = document.getElementById(id);
93
+ if (root) {
94
+ portalRef.current = root;
95
+ } else {
96
+ portalRef.current = document.createElement("div");
97
+ portalRef.current.id = id;
98
+ }
99
+ const el = portalRef.current;
100
+ if (!container.contains(el)) {
101
+ container.appendChild(el);
102
+ }
103
+ el.classList.add(themeClass, densityClass);
104
+ el.dataset.mode = dataMode;
105
+ setMounted(true);
106
+ }, [id, container, themeClass, densityClass, dataMode]);
107
+ (0, import_react.useLayoutEffect)(() => {
108
+ requestAnimationFrame(() => {
109
+ onRender == null ? void 0 : onRender();
110
+ });
111
+ }, [onRender]);
112
+ if (open && mounted && portalRef.current && children) {
113
+ return (0, import_react_dom.createPortal)(children, portalRef.current);
114
+ }
115
+ return null;
116
+ };
117
+
118
+ // src/dialog-header/DialogHeader.tsx
119
+ var import_core = require("@salt-ds/core");
120
+ var import_classnames = __toESM(require("classnames"));
121
+ var import_jsx_runtime = require("react/jsx-runtime");
122
+ var classBase = "vuuDialogHeader";
123
+ var DialogHeader = ({
124
+ hideCloseButton = false,
125
+ title,
126
+ onClose,
127
+ ...htmlAttributes
128
+ }) => {
129
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...htmlAttributes, className: (0, import_classnames.default)(classBase, "vuuToolbarProxy"), children: [
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.Text, { className: "dialogHeader", children: title }),
131
+ !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
+ import_core.Button,
133
+ {
134
+ onClick: onClose,
135
+ "data-align": "end",
136
+ "data-icon": "close",
137
+ variant: "secondary"
138
+ },
139
+ "close"
140
+ )
141
+ ] });
142
+ };
143
+
144
+ // src/dialog/Dialog.tsx
145
+ var import_jsx_runtime2 = require("react/jsx-runtime");
146
+ var classBase2 = "vuuDialog";
147
+ var Dialog = ({
148
+ children,
149
+ className,
150
+ isOpen = false,
151
+ onClose,
152
+ title,
153
+ hideCloseButton = false,
154
+ ...props
155
+ }) => {
156
+ const root = (0, import_react2.useRef)(null);
157
+ const close = (0, import_react2.useCallback)(() => {
158
+ onClose == null ? void 0 : onClose();
159
+ }, [onClose]);
160
+ if (!isOpen) {
161
+ return null;
162
+ }
163
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lab.Scrim, { className: `${classBase2}-scrim`, open: isOpen, autoFocusRef: root, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ...props, className: (0, import_classnames2.default)(classBase2, className), ref: root, children: [
164
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
165
+ DialogHeader,
166
+ {
167
+ hideCloseButton,
168
+ onClose: close,
169
+ title
170
+ }
171
+ ),
172
+ children
173
+ ] }) }) });
174
+ };
175
+
176
+ // src/menu/ContextMenu.tsx
177
+ var import_react7 = require("react");
178
+
179
+ // src/menu/MenuList.tsx
180
+ var import_react5 = __toESM(require("react"));
181
+ var import_classnames3 = __toESM(require("classnames"));
182
+ var import_vuu_layout = require("@vuu-ui/vuu-layout");
183
+
184
+ // src/menu/use-keyboard-navigation.ts
185
+ var import_react3 = require("react");
186
+
187
+ // src/menu/utils.ts
188
+ var isRoot = (el) => el.closest(`[data-root='true']`) !== null;
189
+ var hasPopup = (el, idx) => {
190
+ var _a;
191
+ return el.ariaHasPopup === "true" && ((_a = el.dataset) == null ? void 0 : _a.idx) === `${idx}` || el.querySelector(`:scope > [data-index='${idx}'][aria-haspopup='true']`) !== null;
192
+ };
193
+
194
+ // src/menu/key-code.ts
195
+ function union(set1, ...sets) {
196
+ const result = new Set(set1);
197
+ for (const set of sets) {
198
+ for (const element of set) {
199
+ result.add(element);
200
+ }
201
+ }
202
+ return result;
203
+ }
204
+ var Enter = "Enter";
205
+ var Delete = "Delete";
206
+ var actionKeys = /* @__PURE__ */ new Set([Enter, Delete]);
207
+ var focusKeys = /* @__PURE__ */ new Set(["Tab"]);
208
+ var arrowLeftRightKeys = /* @__PURE__ */ new Set(["ArrowRight", "ArrowLeft"]);
209
+ var verticalNavigationKeys = /* @__PURE__ */ new Set(["Home", "End", "ArrowDown", "ArrowUp"]);
210
+ var horizontalNavigationKeys = /* @__PURE__ */ new Set([
211
+ "Home",
212
+ "End",
213
+ "ArrowRight",
214
+ "ArrowLeft"
215
+ ]);
216
+ var functionKeys = /* @__PURE__ */ new Set([
217
+ "F1",
218
+ "F2",
219
+ "F3",
220
+ "F4",
221
+ "F5",
222
+ "F6",
223
+ "F7",
224
+ "F8",
225
+ "F9",
226
+ "F10",
227
+ "F11",
228
+ "F12"
229
+ ]);
230
+ var specialKeys = union(
231
+ actionKeys,
232
+ horizontalNavigationKeys,
233
+ verticalNavigationKeys,
234
+ arrowLeftRightKeys,
235
+ functionKeys,
236
+ focusKeys
237
+ );
238
+ var isNavigationKey = ({ key }, orientation = "vertical") => {
239
+ const navigationKeys = orientation === "vertical" ? verticalNavigationKeys : horizontalNavigationKeys;
240
+ return navigationKeys.has(key);
241
+ };
242
+
243
+ // src/menu/use-keyboard-navigation.ts
244
+ var import_vuu_utils = require("@vuu-ui/vuu-utils");
245
+ var useKeyboardNavigation = ({
246
+ autoHighlightFirstItem = false,
247
+ count,
248
+ defaultHighlightedIdx,
249
+ highlightedIndex: highlightedIndexProp,
250
+ onActivate,
251
+ onHighlight,
252
+ // onKeyDown,
253
+ onCloseMenu,
254
+ onOpenMenu
255
+ }) => {
256
+ var _a;
257
+ if ((0, import_vuu_utils.isValidNumber)(highlightedIndexProp) && (0, import_vuu_utils.isValidNumber)(defaultHighlightedIdx)) {
258
+ throw Error(
259
+ "useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx"
260
+ );
261
+ }
262
+ const controlledHighlighting = (0, import_vuu_utils.isValidNumber)(highlightedIndexProp);
263
+ const highlightedIndexRef = (0, import_react3.useRef)(
264
+ (_a = defaultHighlightedIdx != null ? defaultHighlightedIdx : highlightedIndexProp) != null ? _a : autoHighlightFirstItem ? 0 : -1
265
+ );
266
+ const [, forceRender] = (0, import_react3.useState)(null);
267
+ const setHighlightedIdx = (0, import_react3.useCallback)(
268
+ (idx) => {
269
+ highlightedIndexRef.current = idx;
270
+ onHighlight == null ? void 0 : onHighlight(idx);
271
+ forceRender({});
272
+ },
273
+ [onHighlight]
274
+ );
275
+ const setHighlightedIndex = (0, import_react3.useCallback)(
276
+ (idx) => {
277
+ if (idx !== highlightedIndexRef.current) {
278
+ if (!controlledHighlighting) {
279
+ setHighlightedIdx(idx);
280
+ }
281
+ }
282
+ },
283
+ [controlledHighlighting, setHighlightedIdx]
284
+ );
285
+ const keyBoardNavigation = (0, import_react3.useRef)(true);
286
+ const ignoreFocus = (0, import_react3.useRef)(false);
287
+ const setIgnoreFocus = (value) => ignoreFocus.current = value;
288
+ const highlightedIndex = controlledHighlighting ? highlightedIndexProp : highlightedIndexRef.current;
289
+ const navigateChildldItems = (0, import_react3.useCallback)(
290
+ (e) => {
291
+ const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);
292
+ if (nextIdx !== highlightedIndexRef.current) {
293
+ setHighlightedIndex(nextIdx);
294
+ }
295
+ },
296
+ [count, setHighlightedIndex]
297
+ );
298
+ const handleKeyDown = (0, import_react3.useCallback)(
299
+ (e) => {
300
+ if (isNavigationKey(e)) {
301
+ e.preventDefault();
302
+ e.stopPropagation();
303
+ keyBoardNavigation.current = true;
304
+ navigateChildldItems(e);
305
+ } else if ((e.key === "ArrowRight" || e.key === "Enter") && hasPopup(e.target, highlightedIndex)) {
306
+ const menuEl = e.target;
307
+ const menuItemEl = menuEl.querySelector(
308
+ `:scope > [data-index='${highlightedIndex}']`
309
+ );
310
+ if (menuItemEl) {
311
+ onOpenMenu == null ? void 0 : onOpenMenu(menuItemEl, true);
312
+ }
313
+ } else if (e.key === "ArrowLeft" && !isRoot(e.target)) {
314
+ onCloseMenu(highlightedIndex);
315
+ } else if (e.key === "Enter") {
316
+ e.preventDefault();
317
+ e.stopPropagation();
318
+ onActivate && onActivate(highlightedIndex);
319
+ } else if (e.key === "Tab") {
320
+ onCloseMenu(-1);
321
+ }
322
+ },
323
+ [
324
+ highlightedIndex,
325
+ navigateChildldItems,
326
+ onActivate,
327
+ onCloseMenu,
328
+ onOpenMenu
329
+ ]
330
+ );
331
+ const listProps = (0, import_react3.useMemo)(
332
+ () => ({
333
+ onFocus: () => {
334
+ if (highlightedIndex === -1) {
335
+ setHighlightedIdx(0);
336
+ }
337
+ },
338
+ onKeyDown: handleKeyDown,
339
+ onMouseDownCapture: () => {
340
+ keyBoardNavigation.current = false;
341
+ setIgnoreFocus(true);
342
+ },
343
+ // onMouseEnter would seem less expensive but it misses some cases
344
+ onMouseMove: () => {
345
+ if (keyBoardNavigation.current) {
346
+ keyBoardNavigation.current = false;
347
+ }
348
+ },
349
+ onMouseLeave: () => {
350
+ keyBoardNavigation.current = true;
351
+ setIgnoreFocus(false);
352
+ setHighlightedIndex(-1);
353
+ }
354
+ }),
355
+ [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex]
356
+ );
357
+ return {
358
+ focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,
359
+ controlledHighlighting,
360
+ highlightedIndex,
361
+ setHighlightedIndex,
362
+ // keyBoardNavigation,
363
+ listProps,
364
+ setIgnoreFocus
365
+ };
366
+ };
367
+ function nextItemIdx(count, key, idx) {
368
+ if (key === "ArrowUp") {
369
+ if (idx > 0) {
370
+ return idx - 1;
371
+ } else {
372
+ return idx;
373
+ }
374
+ } else {
375
+ if (idx === null) {
376
+ return 0;
377
+ } else if (idx === count - 1) {
378
+ return idx;
379
+ } else {
380
+ return idx + 1;
381
+ }
382
+ }
383
+ }
384
+
385
+ // src/menu/use-items-with-ids-next.ts
386
+ var import_react4 = __toESM(require("react"));
387
+ var isMenuItemGroup = (child) => child.type === MenuItemGroup || !!child.props["data-group"];
388
+ var getLabelFromChildren = (children) => {
389
+ if (Array.isArray(children) && isMenuItemLabel(children[0])) {
390
+ return children[0];
391
+ }
392
+ };
393
+ var assignId = (child, path, group, hasSeparator = false) => {
394
+ const {
395
+ props: { children }
396
+ } = child;
397
+ return {
398
+ childWithId: import_react4.default.cloneElement(child, {
399
+ hasSeparator,
400
+ id: `${path}`,
401
+ key: path,
402
+ children: group ? getLabelFromChildren(children) : children
403
+ }),
404
+ grandChildren: group ? children : void 0
405
+ };
406
+ };
407
+ var useItemsWithIdsNext = (childrenProp, rootId) => {
408
+ const normalizeChildren = (0, import_react4.useCallback)(() => {
409
+ const collectChildren = (children, path = rootId, menus2 = {}, actions2 = {}) => {
410
+ const list = menus2[path] = [];
411
+ let idx = 0;
412
+ let hasSeparator = false;
413
+ import_react4.default.Children.forEach(children, (child) => {
414
+ if (isMenuItemLabel(child)) {
415
+ } else if (child.type === Separator) {
416
+ hasSeparator = true;
417
+ } else {
418
+ const hasChildItems = isMenuItemGroup(child);
419
+ const childPath = `${path}-${idx}`;
420
+ const {
421
+ props: { action, options }
422
+ } = child;
423
+ const { childWithId, grandChildren } = assignId(
424
+ child,
425
+ childPath,
426
+ hasChildItems,
427
+ hasSeparator
428
+ );
429
+ list.push(childWithId);
430
+ if (grandChildren) {
431
+ collectChildren(grandChildren, childPath, menus2, actions2);
432
+ } else {
433
+ actions2[childPath] = { action, options };
434
+ }
435
+ idx += 1;
436
+ hasSeparator = false;
437
+ }
438
+ });
439
+ return [menus2, actions2];
440
+ };
441
+ return collectChildren(childrenProp);
442
+ }, [rootId, childrenProp]);
443
+ const [menus, actions] = (0, import_react4.useMemo)(
444
+ () => normalizeChildren(),
445
+ [normalizeChildren]
446
+ );
447
+ return [menus, actions];
448
+ };
449
+
450
+ // src/menu/MenuList.tsx
451
+ var import_jsx_runtime3 = require("react/jsx-runtime");
452
+ var classBase3 = "vuuMenuList";
453
+ var Separator = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { className: "vuuMenuItem-divider" });
454
+ var MenuItemGroup = () => null;
455
+ var MenuItem = ({
456
+ children,
457
+ idx,
458
+ options,
459
+ ...props
460
+ }) => {
461
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...props, children });
462
+ };
463
+ var MenuItemLabel = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
464
+ MenuItemLabel.displayName = "MenuItemLabel";
465
+ MenuItem.Label = MenuItemLabel;
466
+ var getDisplayName = (item) => import_react5.default.isValidElement(item) && typeof item.type !== "string" && "displayName" in item.type ? item.type.displayName : void 0;
467
+ var isMenuItemLabel = (item) => getDisplayName(item) === "MenuItemLabel";
468
+ var hasIcon = (child) => child.props["data-icon"];
469
+ var MenuList = ({
470
+ activatedByKeyboard,
471
+ childMenuShowing,
472
+ children,
473
+ className,
474
+ defaultHighlightedIdx,
475
+ highlightedIdx: highlightedIdxProp,
476
+ id: idProp,
477
+ isRoot: isRoot2,
478
+ listItemProps,
479
+ onHighlightMenuItem,
480
+ onActivate,
481
+ onCloseMenu,
482
+ openMenu: onOpenMenu,
483
+ ...props
484
+ }) => {
485
+ const id = (0, import_vuu_layout.useId)(idProp);
486
+ const root = (0, import_react5.useRef)(null);
487
+ const mapIdxToId = (0, import_react5.useMemo)(() => /* @__PURE__ */ new Map(), []);
488
+ const handleActivate = (idx) => {
489
+ var _a;
490
+ const el = (_a = root.current) == null ? void 0 : _a.querySelector(`:scope > [data-index='${idx}']`);
491
+ (el == null ? void 0 : el.id) && (onActivate == null ? void 0 : onActivate(el.id));
492
+ };
493
+ const { focusVisible, highlightedIndex, listProps } = useKeyboardNavigation({
494
+ count: import_react5.default.Children.count(children),
495
+ defaultHighlightedIdx,
496
+ highlightedIndex: highlightedIdxProp,
497
+ onActivate: handleActivate,
498
+ onHighlight: onHighlightMenuItem,
499
+ onOpenMenu,
500
+ onCloseMenu
501
+ });
502
+ const appliedFocusVisible = childMenuShowing == void 0 ? focusVisible : -1;
503
+ (0, import_react5.useLayoutEffect)(() => {
504
+ var _a;
505
+ if (childMenuShowing === void 0 && activatedByKeyboard) {
506
+ (_a = root.current) == null ? void 0 : _a.focus();
507
+ }
508
+ }, [activatedByKeyboard, childMenuShowing]);
509
+ const getActiveDescendant = () => highlightedIndex === void 0 || highlightedIndex === -1 ? void 0 : mapIdxToId.get(highlightedIndex);
510
+ function renderContent() {
511
+ const propsCommonToAllListItems = {
512
+ ...listItemProps,
513
+ role: "menuitem"
514
+ };
515
+ const maybeIcon = (childElement, withIcon, iconName) => withIcon ? [
516
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
517
+ "span",
518
+ {
519
+ className: "vuuIconContainer",
520
+ "data-icon": iconName
521
+ },
522
+ "icon"
523
+ )
524
+ ].concat(childElement) : childElement;
525
+ function addClonedChild(list, child, idx, withIcon) {
526
+ var _a;
527
+ const {
528
+ children: children2,
529
+ className: className2,
530
+ "data-icon": iconName,
531
+ id: itemId,
532
+ hasSeparator,
533
+ label,
534
+ ...props2
535
+ } = child.props;
536
+ const hasSubMenu = isMenuItemGroup(child);
537
+ const subMenuShowing = hasSubMenu && childMenuShowing === itemId;
538
+ const ariaControls = subMenuShowing ? `${id}-${itemId}` : void 0;
539
+ list.push(
540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
541
+ MenuItem,
542
+ {
543
+ ...props2,
544
+ ...propsCommonToAllListItems,
545
+ ...getMenuItemProps(
546
+ itemId,
547
+ idx,
548
+ (_a = child.key) != null ? _a : itemId,
549
+ highlightedIndex,
550
+ appliedFocusVisible,
551
+ className2,
552
+ hasSeparator
553
+ ),
554
+ "aria-controls": ariaControls,
555
+ "aria-haspopup": hasSubMenu || void 0,
556
+ "aria-expanded": subMenuShowing || void 0,
557
+ children: hasSubMenu ? maybeIcon(label != null ? label : children2, withIcon, iconName) : maybeIcon(children2, withIcon, iconName)
558
+ }
559
+ )
560
+ );
561
+ }
562
+ const listItems = [];
563
+ if (children.length > 0) {
564
+ const withIcon = children.some(hasIcon);
565
+ children.forEach((child, idx) => {
566
+ addClonedChild(listItems, child, idx, withIcon);
567
+ });
568
+ }
569
+ return listItems;
570
+ }
571
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
572
+ "div",
573
+ {
574
+ ...props,
575
+ ...listProps,
576
+ "aria-activedescendant": getActiveDescendant(),
577
+ className: (0, import_classnames3.default)(classBase3, className, {
578
+ [`${classBase3}-childMenuShowing`]: childMenuShowing !== void 0
579
+ }),
580
+ "data-root": isRoot2 || void 0,
581
+ id,
582
+ ref: root,
583
+ role: "menu",
584
+ children: renderContent()
585
+ }
586
+ );
587
+ };
588
+ var getMenuItemProps = (itemId, idx, key, highlightedIdx, focusVisible, className, hasSeparator) => ({
589
+ id: `menuitem-${itemId}`,
590
+ key: key != null ? key : idx,
591
+ "data-index": idx,
592
+ "data-highlighted": idx === highlightedIdx || void 0,
593
+ className: (0, import_classnames3.default)("vuuMenuItem", className, {
594
+ "vuuMenuItem-separator": hasSeparator,
595
+ focusVisible: focusVisible === idx
596
+ })
597
+ });
598
+ MenuList.displayName = "MenuList";
599
+
600
+ // src/menu/use-cascade.ts
601
+ var import_react6 = require("react");
602
+
603
+ // src/menu/list-dom-utils.ts
604
+ var closestListItem = (el) => el == null ? void 0 : el.closest("[data-index],[aria-posinset]");
605
+
606
+ // src/menu/use-cascade.ts
607
+ var nudge = (menus, distance, pos) => {
608
+ return menus.map(
609
+ (m, i) => i === menus.length - 1 ? {
610
+ ...m,
611
+ [pos]: m[pos] - distance
612
+ } : m
613
+ );
614
+ };
615
+ var nudgeLeft = (menus, distance) => nudge(menus, distance, "left");
616
+ var nudgeUp = (menus, distance) => nudge(menus, distance, "top");
617
+ var flipSides = (id, menus) => {
618
+ const [parentMenu, menu] = menus.slice(-2);
619
+ const el = document.getElementById(`${id}-${menu.id}`);
620
+ if (el === null) {
621
+ throw Error(`useCascade.flipSides element with id ${menu.id} not found`);
622
+ }
623
+ const { width } = el.getBoundingClientRect();
624
+ return menus.map(
625
+ (m) => m === menu ? {
626
+ ...m,
627
+ left: parentMenu.left - (width - 2)
628
+ } : m
629
+ );
630
+ };
631
+ var getPosition = (el, openMenus) => {
632
+ const [{ left, top: menuTop }] = openMenus.slice(-1);
633
+ const { offsetWidth: width, offsetTop: top } = el;
634
+ return { left: left + width, top: top + menuTop };
635
+ };
636
+ var getHostMenuId = (id, rootId) => {
637
+ console.log(`getHostMenuId from ${id} and ${rootId}`);
638
+ const pos = id.lastIndexOf("-");
639
+ if (id.startsWith("menuitem")) {
640
+ return pos > -1 ? id.slice(9, pos) : rootId;
641
+ } else {
642
+ return pos > -1 ? id.slice(0, pos) : rootId;
643
+ }
644
+ };
645
+ var getTargetMenuId = (id) => id.slice(9);
646
+ var getMenuItemDetails = ({ ariaExpanded, ariaHasPopup, id }, rootId) => {
647
+ if (id.startsWith("menuitem")) {
648
+ return {
649
+ hostMenuId: getHostMenuId(id, rootId),
650
+ targetMenuId: getTargetMenuId(id),
651
+ menuItemId: id,
652
+ isGroup: ariaHasPopup === "true",
653
+ isOpen: ariaExpanded === "true"
654
+ };
655
+ } else {
656
+ throw Error(`getMenuItemDetails #${id} is not a menuitem`);
657
+ }
658
+ };
659
+ var useCascade = ({
660
+ id: rootId,
661
+ onActivate,
662
+ onMouseEnterItem,
663
+ position: { x: posX, y: posY }
664
+ }) => {
665
+ const [, forceRefresh] = (0, import_react6.useState)({});
666
+ const openMenus = (0, import_react6.useRef)([
667
+ { id: rootId, left: posX, top: posY }
668
+ ]);
669
+ const menuIsOpen = (0, import_react6.useCallback)(
670
+ (menuId) => openMenus.current.findIndex((menu) => menu.id === menuId) !== -1,
671
+ []
672
+ );
673
+ const getOpenMenuStatus = (0, import_react6.useCallback)((menuId) => {
674
+ const state = menuState.current[menuId];
675
+ if (state === void 0) {
676
+ throw Error(`getOpenMenuState no entry for menu ${menuId}`);
677
+ }
678
+ return state;
679
+ }, []);
680
+ const setOpenMenus = (0, import_react6.useCallback)((menus) => {
681
+ console.log(`setOpenMenus`, {
682
+ menus
683
+ });
684
+ openMenus.current = menus;
685
+ forceRefresh({});
686
+ }, []);
687
+ const menuOpenPendingTimeout = (0, import_react6.useRef)();
688
+ const menuClosePendingTimeout = (0, import_react6.useRef)();
689
+ const menuState = (0, import_react6.useRef)({ [rootId]: "no-popup" });
690
+ const openMenu = (0, import_react6.useCallback)(
691
+ (hostMenuId = rootId, targetMenuId, itemId = null) => {
692
+ console.log(
693
+ `open menu hostMenuId ${hostMenuId} targetMenuId ${targetMenuId} itemId ${itemId}`
694
+ );
695
+ if (hostMenuId === rootId && itemId === null) {
696
+ setOpenMenus([{ id: rootId, left: posX, top: posY }]);
697
+ } else {
698
+ console.log(`openMenu set ${hostMenuId} status to popup-open`);
699
+ menuState.current[hostMenuId] = "popup-open";
700
+ const el = document.getElementById(itemId);
701
+ if (el !== null) {
702
+ const { left, top } = getPosition(el, openMenus.current);
703
+ setOpenMenus(
704
+ openMenus.current.concat({ id: targetMenuId, left, top })
705
+ );
706
+ } else {
707
+ throw Error(`openMenu no menuItem ${itemId}`);
708
+ }
709
+ }
710
+ },
711
+ [rootId, posX, posY, setOpenMenus]
712
+ );
713
+ const closeMenu = (0, import_react6.useCallback)(
714
+ (menuId) => {
715
+ console.log(`closeMenu ${menuId}`);
716
+ if (menuId === rootId) {
717
+ console.log("close child menu of root");
718
+ setOpenMenus([]);
719
+ } else {
720
+ const menus = openMenus.current.slice();
721
+ const lastMenu = menus.pop();
722
+ menuState.current[lastMenu.id] = "no-popup";
723
+ const parentMenu = menus.at(-1);
724
+ if (parentMenu) {
725
+ menuState.current[parentMenu.id] = "no-popup";
726
+ }
727
+ console.log(`closeMenu setOpenMenus`, {
728
+ menus
729
+ });
730
+ setOpenMenus(menus);
731
+ }
732
+ },
733
+ [rootId, setOpenMenus]
734
+ );
735
+ const closeMenus = (0, import_react6.useCallback)(
736
+ (menuItemId) => {
737
+ console.log(`closeMenus ${menuItemId}`);
738
+ const menus = openMenus.current.slice();
739
+ const menuItemMenuId = menuItemId.slice(9);
740
+ let { id: lastMenuId } = menus.at(-1);
741
+ while (menus.length > 1 && !menuItemMenuId.startsWith(lastMenuId)) {
742
+ const parentMenuId = getHostMenuId(lastMenuId, rootId);
743
+ console.log(
744
+ `parentMenuId of lastMenuId ${lastMenuId} and rootId ${rootId} is ${parentMenuId}`
745
+ );
746
+ menus.pop();
747
+ console.log(
748
+ `set state to no-popup for ${lastMenuId} and ${parentMenuId}`
749
+ );
750
+ menuState.current[lastMenuId] = "no-popup";
751
+ menuState.current[parentMenuId] = "no-popup";
752
+ ({ id: lastMenuId } = menus[menus.length - 1]);
753
+ }
754
+ if (menus.length < openMenus.current.length) {
755
+ console.log(`closeMenus setOpenMenus`, {
756
+ menus
757
+ });
758
+ setOpenMenus(menus);
759
+ }
760
+ },
761
+ [rootId, setOpenMenus]
762
+ );
763
+ const clearAnyScheduledOpenTasks = (0, import_react6.useCallback)(() => {
764
+ if (menuOpenPendingTimeout.current) {
765
+ clearTimeout(menuOpenPendingTimeout.current);
766
+ menuOpenPendingTimeout.current = void 0;
767
+ }
768
+ }, []);
769
+ const scheduleOpen = (0, import_react6.useCallback)(
770
+ (hostMenuId, targetMenuId, menuItemId, delay = 300) => {
771
+ clearAnyScheduledOpenTasks();
772
+ menuOpenPendingTimeout.current = window.setTimeout(() => {
773
+ closeMenus(menuItemId);
774
+ menuState.current[hostMenuId] = "popup-open";
775
+ menuState.current[targetMenuId] = "no-popup";
776
+ openMenu(hostMenuId, targetMenuId, menuItemId);
777
+ }, delay);
778
+ },
779
+ [clearAnyScheduledOpenTasks, closeMenus, openMenu]
780
+ );
781
+ const scheduleClose = (0, import_react6.useCallback)(
782
+ (hostMenuId, openMenuId, itemId) => {
783
+ menuState.current[openMenuId] = "pending-close";
784
+ menuClosePendingTimeout.current = window.setTimeout(() => {
785
+ closeMenus(itemId);
786
+ }, 400);
787
+ },
788
+ [closeMenus]
789
+ );
790
+ const handleRender = (0, import_react6.useCallback)(() => {
791
+ const { current: menus } = openMenus;
792
+ const menu = menus.at(-1);
793
+ const el = menu ? document.getElementById(menu.id) : void 0;
794
+ if (el) {
795
+ const { right, bottom } = el.getBoundingClientRect();
796
+ const { clientHeight, clientWidth } = document.body;
797
+ if (right > clientWidth) {
798
+ const newMenus = menus.length > 1 ? flipSides(rootId, menus) : nudgeLeft(menus, right - clientWidth);
799
+ setOpenMenus(newMenus);
800
+ } else if (bottom > clientHeight) {
801
+ const newMenus = nudgeUp(menus, bottom - clientHeight);
802
+ setOpenMenus(newMenus);
803
+ }
804
+ if (typeof el.tabIndex === "number") {
805
+ el.focus();
806
+ }
807
+ } else {
808
+ console.log(`useCascade no element found with if ${menu == null ? void 0 : menu.id}`);
809
+ }
810
+ }, [rootId, setOpenMenus]);
811
+ const triggerChildMenu = (0, import_react6.useCallback)(
812
+ (menuItemEl, immediate = false) => {
813
+ const { hostMenuId, targetMenuId, menuItemId, isGroup, isOpen } = getMenuItemDetails(menuItemEl, rootId);
814
+ const {
815
+ current: { [hostMenuId]: state }
816
+ } = menuState;
817
+ const delay = immediate ? 0 : void 0;
818
+ if (state === "no-popup" && isGroup) {
819
+ menuState.current[hostMenuId] = "popup-pending";
820
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
821
+ } else if (state === "popup-pending" && !isGroup) {
822
+ menuState.current[hostMenuId] = "no-popup";
823
+ clearTimeout(menuOpenPendingTimeout.current);
824
+ menuOpenPendingTimeout.current = void 0;
825
+ } else if (state === "popup-pending" && isGroup) {
826
+ clearTimeout(menuOpenPendingTimeout.current);
827
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
828
+ } else if (state === "popup-open") {
829
+ if (menuIsOpen(targetMenuId)) {
830
+ const menuStatus = getOpenMenuStatus(targetMenuId);
831
+ closeMenus(menuItemId);
832
+ switch (menuStatus) {
833
+ case "pending-close":
834
+ clearTimeout(menuClosePendingTimeout.current);
835
+ menuClosePendingTimeout.current = void 0;
836
+ menuState.current[targetMenuId] = "no-popup";
837
+ clearAnyScheduledOpenTasks();
838
+ break;
839
+ default:
840
+ }
841
+ } else {
842
+ const [parentOfLastOpenedMenu, lastOpenedMenu] = openMenus.current.slice(-2);
843
+ console.log(`about to check id on `, {
844
+ openMenus,
845
+ parentOfLastOpenedMenu,
846
+ lastOpenedMenu
847
+ });
848
+ if (parentOfLastOpenedMenu.id === hostMenuId && menuState.current[lastOpenedMenu.id] !== "pending-close") {
849
+ scheduleClose(hostMenuId, lastOpenedMenu.id, menuItemId);
850
+ if (isGroup && !isOpen) {
851
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
852
+ }
853
+ } else if (parentOfLastOpenedMenu.id === hostMenuId && isGroup && menuItemId !== lastOpenedMenu.id && menuState.current[lastOpenedMenu.id] === "pending-close") {
854
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
855
+ } else if (isGroup) {
856
+ scheduleOpen(hostMenuId, targetMenuId, menuItemId, delay);
857
+ } else if (!(menuState.current[lastOpenedMenu.id] === "pending-close")) {
858
+ closeMenus(menuItemId);
859
+ }
860
+ }
861
+ }
862
+ if (state === "pending-close") {
863
+ clearAnyScheduledOpenTasks();
864
+ clearTimeout(menuClosePendingTimeout.current);
865
+ menuClosePendingTimeout.current = void 0;
866
+ menuState.current[hostMenuId] = "popup-open";
867
+ }
868
+ },
869
+ [
870
+ clearAnyScheduledOpenTasks,
871
+ closeMenus,
872
+ getOpenMenuStatus,
873
+ menuIsOpen,
874
+ rootId,
875
+ scheduleClose,
876
+ scheduleOpen
877
+ ]
878
+ );
879
+ const listItemProps = (0, import_react6.useMemo)(
880
+ () => ({
881
+ onMouseEnter: (evt) => {
882
+ const menuItemEl = closestListItem(evt.target);
883
+ console.log(`onMouseEnter ${menuItemEl == null ? void 0 : menuItemEl.id}`);
884
+ triggerChildMenu(menuItemEl);
885
+ onMouseEnterItem(evt, menuItemEl.id);
886
+ },
887
+ onClick: (evt) => {
888
+ console.log("click");
889
+ const listItemEl = closestListItem(evt.target);
890
+ const { isGroup, menuItemId } = getMenuItemDetails(listItemEl, rootId);
891
+ if (isGroup) {
892
+ triggerChildMenu(listItemEl);
893
+ } else {
894
+ onActivate(menuItemId);
895
+ }
896
+ }
897
+ }),
898
+ [onActivate, onMouseEnterItem, rootId, triggerChildMenu]
899
+ );
900
+ return {
901
+ closeMenu,
902
+ handleRender,
903
+ listItemProps,
904
+ openMenu: triggerChildMenu,
905
+ openMenus: openMenus.current
906
+ };
907
+ };
908
+
909
+ // src/menu/ContextMenu.tsx
910
+ var import_vuu_layout2 = require("@vuu-ui/vuu-layout");
911
+ var import_jsx_runtime4 = require("react/jsx-runtime");
912
+ var import_react8 = require("react");
913
+ var noop = () => void 0;
914
+ var ContextMenu = ({
915
+ PortalProps: PortalProps2,
916
+ activatedByKeyboard,
917
+ children: childrenProp,
918
+ className,
919
+ id: idProp,
920
+ onClose = () => void 0,
921
+ position = { x: 0, y: 0 },
922
+ style,
923
+ ...menuListProps
924
+ }) => {
925
+ const closeHandlerRef = (0, import_react7.useRef)(onClose);
926
+ closeHandlerRef.current = onClose;
927
+ const id = (0, import_vuu_layout2.useId)(idProp);
928
+ const closeMenuRef = (0, import_react7.useRef)(noop);
929
+ const [menus, actions] = useItemsWithIdsNext(childrenProp, id);
930
+ const navigatingWithKeyboard = (0, import_react7.useRef)(activatedByKeyboard);
931
+ const handleMouseEnterItem = (0, import_react7.useCallback)(() => {
932
+ navigatingWithKeyboard.current = false;
933
+ }, []);
934
+ const handleActivate = (0, import_react7.useCallback)(
935
+ (menuItemId) => {
936
+ const actionId = menuItemId.slice(9);
937
+ const { action, options } = actions[actionId];
938
+ closeMenuRef.current(id);
939
+ onClose({
940
+ type: "menu-action",
941
+ menuId: action,
942
+ options
943
+ });
944
+ },
945
+ [actions, id, onClose]
946
+ );
947
+ const {
948
+ closeMenu,
949
+ listItemProps,
950
+ openMenu: onOpenMenu,
951
+ openMenus,
952
+ handleRender
953
+ } = useCascade({
954
+ // FIXME
955
+ id: `${id}`,
956
+ onActivate: handleActivate,
957
+ onMouseEnterItem: handleMouseEnterItem,
958
+ position
959
+ });
960
+ closeMenuRef.current = closeMenu;
961
+ const handleCloseMenu = () => {
962
+ navigatingWithKeyboard.current = true;
963
+ closeMenu();
964
+ };
965
+ const handleHighlightMenuItem = () => {
966
+ };
967
+ const lastMenu = openMenus.length - 1;
968
+ const getChildMenuId = (i) => {
969
+ if (i >= lastMenu) {
970
+ return void 0;
971
+ } else {
972
+ const { id: id2 } = openMenus[i + 1];
973
+ return id2;
974
+ }
975
+ };
976
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: openMenus.map(({ id: menuId, left, top }, i, all) => {
977
+ const childMenuId = getChildMenuId(i);
978
+ return /* @__PURE__ */ (0, import_react8.createElement)(Portal, { ...PortalProps2, key: i, onRender: handleRender }, /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
979
+ PopupComponent,
980
+ {
981
+ anchorElement: { current: document.body },
982
+ placement: "absolute",
983
+ position: { left, top },
984
+ children: /* @__PURE__ */ (0, import_react8.createElement)(
985
+ MenuList,
986
+ {
987
+ ...menuListProps,
988
+ activatedByKeyboard: navigatingWithKeyboard.current,
989
+ childMenuShowing: childMenuId,
990
+ className,
991
+ id: menuId,
992
+ isRoot: i === 0,
993
+ key: i,
994
+ listItemProps,
995
+ onActivate: handleActivate,
996
+ onHighlightMenuItem: handleHighlightMenuItem,
997
+ onCloseMenu: handleCloseMenu,
998
+ openMenu: onOpenMenu,
999
+ style,
1000
+ tabIndex: i === all.length - 1 ? 0 : void 0
1001
+ },
1002
+ menus[menuId]
1003
+ )
1004
+ }
1005
+ ));
1006
+ }) });
1007
+ };
1008
+ ContextMenu.displayName = "ContextMenu";
1009
+
1010
+ // src/menu/context-menu-provider.tsx
1011
+ var import_react9 = require("react");
1012
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1013
+ var ContextMenuContext = (0, import_react9.createContext)(
1014
+ null
1015
+ );
1016
+ var Provider = ({
1017
+ children,
1018
+ context,
1019
+ menuActionHandler,
1020
+ menuBuilder
1021
+ }) => {
1022
+ const menuBuilders = (0, import_react9.useMemo)(() => {
1023
+ if ((context == null ? void 0 : context.menuBuilders) && menuBuilder) {
1024
+ return context.menuBuilders.concat(menuBuilder);
1025
+ } else if (menuBuilder) {
1026
+ return [menuBuilder];
1027
+ } else {
1028
+ return (context == null ? void 0 : context.menuBuilders) || [];
1029
+ }
1030
+ }, [context, menuBuilder]);
1031
+ const handleMenuAction = (0, import_react9.useCallback)(
1032
+ (reason) => {
1033
+ var _a;
1034
+ if (menuActionHandler == null ? void 0 : menuActionHandler(reason)) {
1035
+ return true;
1036
+ }
1037
+ if ((_a = context == null ? void 0 : context.menuActionHandler) == null ? void 0 : _a.call(context, reason)) {
1038
+ return true;
1039
+ }
1040
+ },
1041
+ [context, menuActionHandler]
1042
+ );
1043
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1044
+ ContextMenuContext.Provider,
1045
+ {
1046
+ value: {
1047
+ menuActionHandler: handleMenuAction,
1048
+ menuBuilders
1049
+ },
1050
+ children
1051
+ }
1052
+ );
1053
+ };
1054
+ var ContextMenuProvider = ({
1055
+ children,
1056
+ label,
1057
+ menuActionHandler,
1058
+ menuBuilder
1059
+ }) => {
1060
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ContextMenuContext.Consumer, { children: (parentContext) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1061
+ Provider,
1062
+ {
1063
+ context: parentContext,
1064
+ label,
1065
+ menuActionHandler,
1066
+ menuBuilder,
1067
+ children
1068
+ }
1069
+ ) });
1070
+ };
1071
+
1072
+ // src/menu/useContextMenu.tsx
1073
+ var import_vuu_utils2 = require("@vuu-ui/vuu-utils");
1074
+ var import_react12 = require("react");
1075
+
1076
+ // src/popup/popup-service.ts
1077
+ var import_classnames5 = __toESM(require("classnames"));
1078
+ var import_react10 = __toESM(require("react"));
1079
+ var import_react_dom2 = __toESM(require("react-dom"));
1080
+
1081
+ // src/portal-deprecated/render-portal.tsx
1082
+ var ReactDOM = __toESM(require("react-dom"));
1083
+ var import_classnames4 = __toESM(require("classnames"));
1084
+ var containerId = 1;
1085
+ var getPortalContainer = ({
1086
+ className,
1087
+ dataMode,
1088
+ x = 0,
1089
+ y = 0,
1090
+ win = window
1091
+ }) => {
1092
+ const el = win.document.createElement("div");
1093
+ el.className = (0, import_classnames4.default)(`vuuPopup ${containerId++}`, className);
1094
+ el.style.cssText = `left:${x}px; top:${y}px;`;
1095
+ if (dataMode) {
1096
+ el.dataset.mode = dataMode;
1097
+ }
1098
+ win.document.body.appendChild(el);
1099
+ return el;
1100
+ };
1101
+ var createContainer = (props) => getPortalContainer(props);
1102
+ var renderPortal = (component, container, x, y, onRender) => {
1103
+ container.style.cssText = `left:${x}px; top:${y}px;position: absolute;`;
1104
+ ReactDOM.render(component, container, onRender);
1105
+ };
1106
+
1107
+ // src/popup/popup-service.ts
1108
+ var _dialogOpen = false;
1109
+ var _popups = [];
1110
+ var reasonIsMenuAction = (reason) => (reason == null ? void 0 : reason.type) === "menu-action";
1111
+ var reasonIsClickAway = (reason) => (reason == null ? void 0 : reason.type) === "click-away";
1112
+ function specialKeyHandler(e) {
1113
+ if (e.key === "Esc") {
1114
+ if (_popups.length) {
1115
+ closeAllPopups();
1116
+ } else if (_dialogOpen) {
1117
+ const dialogRoot = document.body.querySelector(".vuuDialog");
1118
+ if (dialogRoot) {
1119
+ import_react_dom2.default.unmountComponentAtNode(dialogRoot);
1120
+ }
1121
+ }
1122
+ }
1123
+ }
1124
+ function outsideClickHandler(e) {
1125
+ if (_popups.length) {
1126
+ const popupContainers = document.body.querySelectorAll(
1127
+ ".vuuPopup,#vuu-portal-root"
1128
+ );
1129
+ for (let i = 0; i < popupContainers.length; i++) {
1130
+ if (popupContainers[i].contains(e.target)) {
1131
+ return;
1132
+ }
1133
+ }
1134
+ closeAllPopups({ mouseEvt: e, type: "click-away" });
1135
+ }
1136
+ }
1137
+ function closeAllPopups(reason) {
1138
+ if (_popups.length === 1) {
1139
+ PopupService.hidePopup(reason, "anon", "all");
1140
+ } else if (_popups.length) {
1141
+ const popupContainers = document.body.querySelectorAll(".vuuPopup");
1142
+ for (let i = 0; i < popupContainers.length; i++) {
1143
+ import_react_dom2.default.unmountComponentAtNode(popupContainers[i]);
1144
+ }
1145
+ popupClosed("*");
1146
+ }
1147
+ }
1148
+ function dialogOpened() {
1149
+ if (_dialogOpen === false) {
1150
+ _dialogOpen = true;
1151
+ window.addEventListener("keydown", specialKeyHandler, true);
1152
+ }
1153
+ }
1154
+ function dialogClosed() {
1155
+ if (_dialogOpen) {
1156
+ _dialogOpen = false;
1157
+ window.removeEventListener("keydown", specialKeyHandler, true);
1158
+ }
1159
+ }
1160
+ function popupOpened(name) {
1161
+ if (_popups.indexOf(name) === -1) {
1162
+ _popups.push(name);
1163
+ if (_dialogOpen === false) {
1164
+ window.addEventListener("keydown", specialKeyHandler, true);
1165
+ window.addEventListener("click", outsideClickHandler, true);
1166
+ }
1167
+ }
1168
+ }
1169
+ function popupClosed(name) {
1170
+ if (_popups.length) {
1171
+ if (name === "*") {
1172
+ _popups.length = 0;
1173
+ } else {
1174
+ const pos = _popups.indexOf(name);
1175
+ if (pos !== -1) {
1176
+ _popups.splice(pos, 1);
1177
+ }
1178
+ }
1179
+ if (_popups.length === 0 && _dialogOpen === false) {
1180
+ window.removeEventListener("keydown", specialKeyHandler, true);
1181
+ window.removeEventListener("click", outsideClickHandler, true);
1182
+ }
1183
+ }
1184
+ }
1185
+ var PopupComponent2 = ({
1186
+ children,
1187
+ position,
1188
+ style
1189
+ }) => {
1190
+ const className = (0, import_classnames5.default)("hwPopup", "hwPopupContainer", position);
1191
+ return (0, import_react10.createElement)("div", { className, style }, children);
1192
+ };
1193
+ var incrementingKey = 1;
1194
+ var PopupService = class {
1195
+ static showPopup({
1196
+ group = "all",
1197
+ name = "anon",
1198
+ left = 0,
1199
+ position = "",
1200
+ right = "auto",
1201
+ top = 0,
1202
+ width = "auto",
1203
+ component
1204
+ }) {
1205
+ if (!component) {
1206
+ throw Error(`PopupService showPopup, no component supplied`);
1207
+ }
1208
+ if (typeof component.props.onClose === "function") {
1209
+ PopupService.onClose = component.props.onClose;
1210
+ } else {
1211
+ PopupService.onClose = void 0;
1212
+ }
1213
+ popupOpened(name);
1214
+ document.addEventListener("keydown", PopupService.escapeKeyListener, true);
1215
+ let el = document.body.querySelector(".vuuPopup." + group);
1216
+ if (el === null) {
1217
+ el = document.createElement("div");
1218
+ el.className = "vuuPopup " + group;
1219
+ document.body.appendChild(el);
1220
+ }
1221
+ const style = { width };
1222
+ renderPortal(
1223
+ (0, import_react10.createElement)(
1224
+ PopupComponent2,
1225
+ { key: incrementingKey++, position, style },
1226
+ component
1227
+ ),
1228
+ el,
1229
+ left,
1230
+ top,
1231
+ () => {
1232
+ PopupService.keepWithinThePage(el, right);
1233
+ }
1234
+ );
1235
+ }
1236
+ static escapeKeyListener(evt) {
1237
+ if (evt.key === "Escape") {
1238
+ PopupService.hidePopup({ type: "escape", event: evt });
1239
+ }
1240
+ }
1241
+ static hidePopup(reason, name = "anon", group = "all") {
1242
+ var _a;
1243
+ if (_popups.indexOf(name) !== -1) {
1244
+ popupClosed(name);
1245
+ const popupRoot = document.body.querySelector(`.vuuPopup.${group}`);
1246
+ if (popupRoot) {
1247
+ import_react_dom2.default.unmountComponentAtNode(popupRoot);
1248
+ }
1249
+ }
1250
+ document.removeEventListener(
1251
+ "keydown",
1252
+ PopupService.escapeKeyListener,
1253
+ true
1254
+ );
1255
+ (_a = PopupService == null ? void 0 : PopupService.onClose) == null ? void 0 : _a.call(PopupService, reason);
1256
+ }
1257
+ static keepWithinThePage(el, right = "auto") {
1258
+ const target = el.querySelector(".vuuPopupContainer > *");
1259
+ if (target) {
1260
+ const {
1261
+ top,
1262
+ left,
1263
+ width,
1264
+ height,
1265
+ right: currentRight
1266
+ } = target.getBoundingClientRect();
1267
+ const w = window.innerWidth;
1268
+ const h = window.innerHeight;
1269
+ const overflowH = h - (top + height);
1270
+ if (overflowH < 0) {
1271
+ target.style.top = Math.round(top) + overflowH + "px";
1272
+ }
1273
+ const overflowW = w - (left + width);
1274
+ if (overflowW < 0) {
1275
+ target.style.left = Math.round(left) + overflowW + "px";
1276
+ }
1277
+ if (typeof right === "number" && right !== currentRight) {
1278
+ const adjustment = right - currentRight;
1279
+ target.style.left = left + adjustment + "px";
1280
+ }
1281
+ }
1282
+ }
1283
+ };
1284
+ var DialogService = class {
1285
+ static showDialog(dialog) {
1286
+ const containerEl = ".vuuDialog";
1287
+ const onClose = dialog.props.onClose;
1288
+ dialogOpened();
1289
+ import_react_dom2.default.render(
1290
+ import_react10.default.cloneElement(dialog, {
1291
+ container: containerEl,
1292
+ onClose: () => {
1293
+ DialogService.closeDialog();
1294
+ if (onClose) {
1295
+ onClose();
1296
+ }
1297
+ }
1298
+ }),
1299
+ document.body.querySelector(containerEl)
1300
+ );
1301
+ }
1302
+ static closeDialog() {
1303
+ dialogClosed();
1304
+ const dialogRoot = document.body.querySelector(".vuuDialog");
1305
+ if (dialogRoot) {
1306
+ import_react_dom2.default.unmountComponentAtNode(dialogRoot);
1307
+ }
1308
+ }
1309
+ };
1310
+
1311
+ // src/popup/Popup.tsx
1312
+ var import_classnames6 = __toESM(require("classnames"));
1313
+
1314
+ // src/popup/useAnchoredPosition.ts
1315
+ var import_react11 = require("react");
1316
+ var getPositionRelativeToAnchor = (anchorElement, placement, offsetLeft, offsetTop, minWidth, dimensions) => {
1317
+ const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
1318
+ switch (placement) {
1319
+ case "below":
1320
+ return { left: left + offsetLeft, top: bottom + offsetTop };
1321
+ case "right":
1322
+ return { left: right + offsetLeft, top: top + offsetTop };
1323
+ case "below-center":
1324
+ return { left: left + width / 2 + offsetLeft, top: bottom + offsetTop };
1325
+ case "below-full-width":
1326
+ return {
1327
+ left: left + offsetLeft,
1328
+ minWidth,
1329
+ top: bottom + offsetTop,
1330
+ width
1331
+ };
1332
+ case "center":
1333
+ if (dimensions) {
1334
+ return {
1335
+ left: width / 2 - dimensions.width / 2 + offsetLeft,
1336
+ top: height / 2 - dimensions.height / 2 + offsetTop,
1337
+ visibility: "visible"
1338
+ };
1339
+ } else {
1340
+ return {
1341
+ left: width / 2 + offsetLeft,
1342
+ top: height / 2 + offsetTop,
1343
+ visibility: "hidden"
1344
+ };
1345
+ }
1346
+ default:
1347
+ throw Error(
1348
+ "Popup getPositionRelativeToAnchor only supported placement values are below and right"
1349
+ );
1350
+ }
1351
+ };
1352
+ var useAnchoredPosition = ({
1353
+ anchorElement,
1354
+ minWidth,
1355
+ offsetLeft = 0,
1356
+ offsetTop = 0,
1357
+ placement,
1358
+ position: positionProp
1359
+ }) => {
1360
+ const popupRef = (0, import_react11.useRef)(null);
1361
+ const [position, setPosition] = (0, import_react11.useState)(positionProp);
1362
+ (0, import_react11.useLayoutEffect)(() => {
1363
+ if (placement === "absolute" && positionProp) {
1364
+ setPosition(positionProp);
1365
+ } else if (anchorElement.current) {
1366
+ const dimensions = popupRef.current === null ? void 0 : popupRef.current.getBoundingClientRect();
1367
+ const position2 = getPositionRelativeToAnchor(
1368
+ anchorElement.current,
1369
+ placement,
1370
+ offsetLeft,
1371
+ offsetTop,
1372
+ minWidth,
1373
+ dimensions
1374
+ );
1375
+ setPosition(position2);
1376
+ }
1377
+ }, [anchorElement, minWidth, offsetLeft, offsetTop, placement, positionProp]);
1378
+ const popupCallbackRef = (0, import_react11.useCallback)(
1379
+ (el) => {
1380
+ popupRef.current = el;
1381
+ if (el && placement === "center" && anchorElement.current) {
1382
+ const { height, width } = el.getBoundingClientRect();
1383
+ setPosition(
1384
+ getPositionRelativeToAnchor(
1385
+ anchorElement.current,
1386
+ placement,
1387
+ offsetLeft,
1388
+ offsetTop,
1389
+ void 0,
1390
+ { height, width }
1391
+ )
1392
+ );
1393
+ }
1394
+ },
1395
+ [anchorElement, offsetLeft, offsetTop, placement]
1396
+ );
1397
+ return {
1398
+ position,
1399
+ popupRef: placement === "center" ? popupCallbackRef : void 0
1400
+ };
1401
+ };
1402
+
1403
+ // src/popup/Popup.tsx
1404
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1405
+ var PopupComponent = ({
1406
+ children,
1407
+ className,
1408
+ anchorElement,
1409
+ minWidth,
1410
+ placement,
1411
+ position: positionProp
1412
+ }) => {
1413
+ const { popupRef, position } = useAnchoredPosition({
1414
+ anchorElement,
1415
+ minWidth,
1416
+ placement,
1417
+ position: positionProp
1418
+ });
1419
+ return position === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: (0, import_classnames6.default)(`vuuPortal`, className), ref: popupRef, style: position, children });
1420
+ };
1421
+
1422
+ // src/menu/useContextMenu.tsx
1423
+ var import_vuu_shell2 = require("@vuu-ui/vuu-shell");
1424
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1425
+ var useContextMenu = (menuBuilder, menuActionHandler) => {
1426
+ const ctx = (0, import_react12.useContext)(ContextMenuContext);
1427
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell2.useThemeAttributes)();
1428
+ const themeAttributes = (0, import_react12.useMemo)(
1429
+ () => ({
1430
+ themeClass,
1431
+ densityClass,
1432
+ dataMode
1433
+ }),
1434
+ [dataMode, densityClass, themeClass]
1435
+ );
1436
+ const buildMenuOptions = (0, import_react12.useCallback)(
1437
+ (menuBuilders, location, options) => {
1438
+ let results = [];
1439
+ for (const menuBuilder2 of menuBuilders) {
1440
+ results = results.concat(menuBuilder2(location, options));
1441
+ }
1442
+ return results;
1443
+ },
1444
+ []
1445
+ );
1446
+ const handleShowContextMenu = (0, import_react12.useCallback)(
1447
+ (e, location, { ContextMenuProps: ContextMenuProps2, contextMenu, ...options }) => {
1448
+ var _a, _b;
1449
+ (_a = e.stopPropagation) == null ? void 0 : _a.call(e);
1450
+ (_b = e.preventDefault) == null ? void 0 : _b.call(e);
1451
+ if (contextMenu) {
1452
+ return showContextMenuComponent(
1453
+ {
1454
+ x: e.clientX,
1455
+ y: e.clientY
1456
+ },
1457
+ contextMenu
1458
+ );
1459
+ }
1460
+ const menuBuilders = [];
1461
+ if (menuBuilder) {
1462
+ menuBuilders.push(menuBuilder);
1463
+ }
1464
+ if (ctx && Array.isArray(ctx == null ? void 0 : ctx.menuBuilders) && ctx.menuBuilders.length > 0) {
1465
+ menuBuilders.push(...ctx.menuBuilders);
1466
+ }
1467
+ if (menuBuilders.length > 0) {
1468
+ const menuItemDescriptors = buildMenuOptions(
1469
+ menuBuilders,
1470
+ location,
1471
+ options
1472
+ );
1473
+ const menuHandler = (action) => {
1474
+ if ((menuActionHandler == null ? void 0 : menuActionHandler(action)) === true) {
1475
+ return true;
1476
+ } else {
1477
+ return ctx == null ? void 0 : ctx.menuActionHandler(action);
1478
+ }
1479
+ };
1480
+ if (menuItemDescriptors.length && menuHandler) {
1481
+ showContextMenu(e, menuItemDescriptors, menuHandler, {
1482
+ PortalProps: {
1483
+ themeAttributes
1484
+ },
1485
+ ...ContextMenuProps2
1486
+ });
1487
+ }
1488
+ } else {
1489
+ console.warn(
1490
+ "useContextMenu, no menuBuilders configured. These should be supplied via the ContextMenuProvider(s)"
1491
+ );
1492
+ }
1493
+ },
1494
+ [buildMenuOptions, ctx, menuActionHandler, menuBuilder, themeAttributes]
1495
+ );
1496
+ const hideContextMenu = (0, import_react12.useCallback)(() => {
1497
+ console.log("hide context menu");
1498
+ }, []);
1499
+ return [handleShowContextMenu, hideContextMenu];
1500
+ };
1501
+ var NO_OPTIONS = {};
1502
+ var showContextMenuComponent = (position, contextMenu) => {
1503
+ PopupService.showPopup({
1504
+ focus: true,
1505
+ left: 0,
1506
+ top: 0,
1507
+ component: (0, import_react12.cloneElement)(contextMenu, { position })
1508
+ });
1509
+ };
1510
+ var showContextMenu = (e, menuDescriptors, handleContextMenuAction, {
1511
+ position: positionProp,
1512
+ ...contextMenuProps
1513
+ } = NO_OPTIONS) => {
1514
+ const menuItems = (menuDescriptors2) => {
1515
+ const fromDescriptor = (menuItem, i) => (0, import_vuu_utils2.isGroupMenuItemDescriptor)(menuItem) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuItemGroup, { label: menuItem.label, children: menuItem.children.map(fromDescriptor) }, i) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1516
+ MenuItem,
1517
+ {
1518
+ action: menuItem.action,
1519
+ className: menuItem.className,
1520
+ "data-icon": menuItem.icon,
1521
+ options: menuItem.options,
1522
+ children: menuItem.label
1523
+ },
1524
+ i
1525
+ );
1526
+ return menuDescriptors2.map(fromDescriptor);
1527
+ };
1528
+ const handleClose = (reason) => {
1529
+ var _a;
1530
+ if (reasonIsMenuAction(reason)) {
1531
+ handleContextMenuAction(reason);
1532
+ PopupService.hidePopup();
1533
+ }
1534
+ (_a = contextMenuProps == null ? void 0 : contextMenuProps.onClose) == null ? void 0 : _a.call(contextMenuProps, reason);
1535
+ };
1536
+ const position = positionProp != null ? positionProp : {
1537
+ x: e.clientX,
1538
+ y: e.clientY
1539
+ };
1540
+ const component = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1541
+ ContextMenu,
1542
+ {
1543
+ ...contextMenuProps,
1544
+ onClose: handleClose,
1545
+ position,
1546
+ children: menuItems(menuDescriptors)
1547
+ }
1548
+ );
1549
+ PopupService.showPopup({ left: 0, top: 0, component, focus: true });
1550
+ };
1551
+
1552
+ // src/popup-menu/PopupMenu.tsx
1553
+ var import_react13 = require("react");
1554
+ var import_classnames7 = __toESM(require("classnames"));
1555
+ var import_core2 = require("@salt-ds/core");
1556
+ var import_vuu_layout3 = require("@vuu-ui/vuu-layout");
1557
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1558
+ var classBase4 = "vuuPopupMenu";
1559
+ var getPosition2 = (element) => {
1560
+ if (element) {
1561
+ const { bottom, left } = element.getBoundingClientRect();
1562
+ return { x: left, y: bottom + 6 };
1563
+ }
1564
+ };
1565
+ var PopupMenu = ({
1566
+ className,
1567
+ label,
1568
+ icon = label ? "chevron-down" : "more-vert",
1569
+ id: idProp,
1570
+ menuActionHandler,
1571
+ menuBuilder,
1572
+ menuLocation = "header",
1573
+ menuOptions,
1574
+ onMenuClose,
1575
+ tabIndex = 0,
1576
+ ...htmlAttributes
1577
+ }) => {
1578
+ const rootRef = (0, import_react13.useRef)(null);
1579
+ const suppressShowMenuRef = (0, import_react13.useRef)(false);
1580
+ const [menuOpen, setMenuOpen] = (0, import_react13.useState)(false);
1581
+ const id = (0, import_vuu_layout3.useId)(idProp);
1582
+ const [showContextMenu2] = useContextMenu(menuBuilder, menuActionHandler);
1583
+ const handleOpenMenu = (0, import_react13.useCallback)((el) => {
1584
+ console.log(`menu Open `, {
1585
+ el
1586
+ });
1587
+ }, []);
1588
+ const handleMenuClose = (0, import_react13.useCallback)(
1589
+ (reason) => {
1590
+ setMenuOpen(false);
1591
+ if (reasonIsClickAway(reason)) {
1592
+ const target = reason.mouseEvt.target;
1593
+ if (target === rootRef.current) {
1594
+ suppressShowMenuRef.current = true;
1595
+ }
1596
+ } else {
1597
+ requestAnimationFrame(() => {
1598
+ var _a;
1599
+ onMenuClose == null ? void 0 : onMenuClose(reason);
1600
+ if (tabIndex !== -1) {
1601
+ (_a = rootRef.current) == null ? void 0 : _a.focus();
1602
+ }
1603
+ });
1604
+ }
1605
+ },
1606
+ [onMenuClose, tabIndex]
1607
+ );
1608
+ const showMenu = (0, import_react13.useCallback)(
1609
+ (e) => {
1610
+ if (suppressShowMenuRef.current) {
1611
+ suppressShowMenuRef.current = false;
1612
+ } else {
1613
+ setMenuOpen(true);
1614
+ showContextMenu2(e, menuLocation, {
1615
+ ContextMenuProps: {
1616
+ id: `${id}-menu`,
1617
+ onClose: handleMenuClose,
1618
+ openMenu: handleOpenMenu,
1619
+ position: getPosition2(rootRef.current)
1620
+ },
1621
+ ...menuOptions
1622
+ });
1623
+ }
1624
+ },
1625
+ [
1626
+ handleMenuClose,
1627
+ handleOpenMenu,
1628
+ id,
1629
+ menuLocation,
1630
+ menuOptions,
1631
+ showContextMenu2
1632
+ ]
1633
+ );
1634
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1635
+ import_core2.Button,
1636
+ {
1637
+ ...htmlAttributes,
1638
+ "aria-controls": `${id}-menu-root`,
1639
+ "aria-expanded": menuOpen,
1640
+ "aria-haspopup": "menu",
1641
+ className: (0, import_classnames7.default)(classBase4, className, {
1642
+ [`${classBase4}-withCaption`]: label !== void 0,
1643
+ [`${classBase4}-open`]: menuOpen
1644
+ }),
1645
+ "data-icon": icon,
1646
+ id,
1647
+ onClick: showMenu,
1648
+ ref: rootRef,
1649
+ tabIndex,
1650
+ variant: "secondary",
1651
+ children: label
1652
+ }
1653
+ );
1654
+ };
1655
+
1656
+ // src/prompt/Prompt.tsx
1657
+ var import_vuu_shell3 = require("@vuu-ui/vuu-shell");
1658
+ var import_core3 = require("@salt-ds/core");
1659
+ var import_classnames8 = __toESM(require("classnames"));
1660
+ var import_react14 = require("react");
1661
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1662
+ var classBase5 = "vuuPrompt";
1663
+ var AnchorBody = { current: document.body };
1664
+ var EMPTY_PROPS = {};
1665
+ var Prompt = ({
1666
+ PopupProps = EMPTY_PROPS,
1667
+ cancelButtonLabel = "Cancel",
1668
+ confirmButtonLabel = "Confirm",
1669
+ icon,
1670
+ onCancel,
1671
+ onConfirm,
1672
+ style,
1673
+ text,
1674
+ title,
1675
+ variant = "info",
1676
+ ...htmlAttributes
1677
+ }) => {
1678
+ const {
1679
+ anchorElement = AnchorBody,
1680
+ offsetLeft = 0,
1681
+ offsetTop = 0,
1682
+ placement = "below"
1683
+ } = PopupProps;
1684
+ const [themeClass, densityClass, dataMode] = (0, import_vuu_shell3.useThemeAttributes)();
1685
+ const { position } = useAnchoredPosition({
1686
+ anchorElement,
1687
+ offsetLeft,
1688
+ offsetTop,
1689
+ placement
1690
+ });
1691
+ const rootRef = (0, import_react14.useRef)(null);
1692
+ const confirmRef = (0, import_react14.useRef)(null);
1693
+ (0, import_react14.useLayoutEffect)(() => {
1694
+ if (rootRef.current) {
1695
+ rootRef.current.showModal();
1696
+ if (confirmRef.current) {
1697
+ confirmRef.current.focus();
1698
+ }
1699
+ if (placement.endsWith("center")) {
1700
+ const { width } = rootRef.current.getBoundingClientRect();
1701
+ rootRef.current.style.marginLeft = `-${width / 2}px`;
1702
+ }
1703
+ }
1704
+ }, [placement]);
1705
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1706
+ "dialog",
1707
+ {
1708
+ ...htmlAttributes,
1709
+ className: (0, import_classnames8.default)(classBase5, `${classBase5}-${variant}`, themeClass),
1710
+ "data-mode": dataMode,
1711
+ ref: rootRef,
1712
+ style: { ...style, ...position },
1713
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("form", { className: `${classBase5}-form`, children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `${classBase5}-header`, "data-icon": icon, children: title }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `${classBase5}-text`, children: text }),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `${classBase5}-buttonBar`, children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core3.Button, { onClick: onCancel, variant: "secondary", children: cancelButtonLabel }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core3.Button, { onClick: onConfirm, ref: confirmRef, value: "default", children: confirmButtonLabel })
1719
+ ] })
1720
+ ] })
1721
+ }
1722
+ );
1723
+ };
1724
+
1725
+ // src/tooltip/useAnchoredPosition.ts
1726
+ var import_react15 = require("react");
1727
+ var getPositionRelativeToAnchor2 = (anchorElement, placement, offsetLeft, offsetTop) => {
1728
+ const { bottom, height, left, right, top, width } = anchorElement.getBoundingClientRect();
1729
+ const midX = left + width / 2;
1730
+ const midY = top + height / 2;
1731
+ switch (placement) {
1732
+ case "above":
1733
+ return { left: midX + offsetLeft, top: top + offsetTop };
1734
+ case "below":
1735
+ return { left: midX + offsetLeft, top: bottom + offsetTop };
1736
+ case "right":
1737
+ return { left: right + offsetLeft, top: midY + offsetLeft };
1738
+ case "left":
1739
+ return { left: left + offsetLeft, top: midY + offsetLeft };
1740
+ default:
1741
+ throw Error(
1742
+ "Tooltip getPositionRelativeToAnchor only supported placement values are left, right, below and right"
1743
+ );
1744
+ }
1745
+ };
1746
+ var useAnchoredPosition2 = ({
1747
+ anchorElement,
1748
+ offsetLeft = 0,
1749
+ offsetTop = 0,
1750
+ placement
1751
+ }) => {
1752
+ const [position, setPosition] = (0, import_react15.useState)();
1753
+ (0, import_react15.useLayoutEffect)(() => {
1754
+ if (anchorElement.current) {
1755
+ const position2 = getPositionRelativeToAnchor2(
1756
+ anchorElement.current,
1757
+ placement,
1758
+ offsetLeft,
1759
+ offsetTop
1760
+ );
1761
+ setPosition(position2);
1762
+ }
1763
+ }, [anchorElement, offsetLeft, offsetTop, placement]);
1764
+ return position;
1765
+ };
1766
+
1767
+ // src/tooltip/Tooltip.tsx
1768
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1769
+ var classBase6 = "vuuTooltip";
1770
+ var Tooltip = ({
1771
+ anchorElement,
1772
+ children,
1773
+ id,
1774
+ onMouseEnter,
1775
+ onMouseLeave,
1776
+ placement
1777
+ }) => {
1778
+ const position = useAnchoredPosition2({ anchorElement, placement });
1779
+ if (position === void 0) {
1780
+ return null;
1781
+ }
1782
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1783
+ "div",
1784
+ {
1785
+ className: classBase6,
1786
+ "data-align": placement,
1787
+ id,
1788
+ style: position,
1789
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1790
+ "span",
1791
+ {
1792
+ className: `${classBase6}-content`,
1793
+ onMouseEnter,
1794
+ onMouseLeave,
1795
+ children
1796
+ }
1797
+ )
1798
+ }
1799
+ ) });
1800
+ };
1801
+
1802
+ // src/tooltip/useTooltip.ts
1803
+ var import_react16 = require("react");
1804
+ var import_vuu_layout4 = require("@vuu-ui/vuu-layout");
1805
+ var useTooltip = ({
1806
+ id: idProp,
1807
+ placement = "right",
1808
+ tooltipContent
1809
+ }) => {
1810
+ const hideTooltipRef = (0, import_react16.useRef)();
1811
+ const anchorElementRef = (0, import_react16.useRef)(null);
1812
+ const mouseEnterTimerRef = (0, import_react16.useRef)();
1813
+ const mouseLeaveTimerRef = (0, import_react16.useRef)();
1814
+ const [tooltipProps, setTooltipProps] = (0, import_react16.useState)();
1815
+ const id = (0, import_vuu_layout4.useId)(idProp);
1816
+ const escapeListener = (0, import_react16.useCallback)((evt) => {
1817
+ var _a;
1818
+ if (evt.key === "Escape") {
1819
+ (_a = hideTooltipRef.current) == null ? void 0 : _a.call(hideTooltipRef);
1820
+ }
1821
+ }, []);
1822
+ hideTooltipRef.current = (0, import_react16.useCallback)(() => {
1823
+ setTooltipProps(void 0);
1824
+ document.removeEventListener("keydown", escapeListener);
1825
+ }, [escapeListener]);
1826
+ const handleMouseEnterTooltip = (0, import_react16.useCallback)(() => {
1827
+ window.clearTimeout(mouseLeaveTimerRef.current);
1828
+ }, []);
1829
+ const handleMouseLeaveTooltip = (0, import_react16.useCallback)(() => {
1830
+ var _a;
1831
+ (_a = hideTooltipRef.current) == null ? void 0 : _a.call(hideTooltipRef);
1832
+ }, []);
1833
+ const showTooltip = (0, import_react16.useCallback)(() => {
1834
+ const { current: anchorEl } = anchorElementRef;
1835
+ if (anchorEl) {
1836
+ setTooltipProps({
1837
+ anchorElement: anchorElementRef,
1838
+ children: tooltipContent,
1839
+ id: `${id}-tooltip`,
1840
+ onMouseEnter: handleMouseEnterTooltip,
1841
+ onMouseLeave: handleMouseLeaveTooltip,
1842
+ placement
1843
+ });
1844
+ document.addEventListener("keydown", escapeListener);
1845
+ }
1846
+ mouseEnterTimerRef.current = void 0;
1847
+ }, [
1848
+ escapeListener,
1849
+ handleMouseEnterTooltip,
1850
+ handleMouseLeaveTooltip,
1851
+ id,
1852
+ placement,
1853
+ tooltipContent
1854
+ ]);
1855
+ const handleMouseEnter = (0, import_react16.useCallback)(
1856
+ (evt) => {
1857
+ const el = evt.target;
1858
+ if (el) {
1859
+ anchorElementRef.current = el;
1860
+ mouseEnterTimerRef.current = window.setTimeout(showTooltip, 800);
1861
+ }
1862
+ },
1863
+ [showTooltip]
1864
+ );
1865
+ const handleMouseLeave = (0, import_react16.useCallback)(() => {
1866
+ if (anchorElementRef.current)
1867
+ if (mouseEnterTimerRef.current) {
1868
+ window.clearTimeout(mouseEnterTimerRef.current);
1869
+ mouseEnterTimerRef.current = void 0;
1870
+ } else {
1871
+ if (hideTooltipRef.current) {
1872
+ mouseLeaveTimerRef.current = window.setTimeout(
1873
+ hideTooltipRef.current,
1874
+ 200
1875
+ );
1876
+ }
1877
+ }
1878
+ }, []);
1879
+ const anchorProps = {
1880
+ "aria-describedby": `${id}-tooltip`,
1881
+ onMouseEnter: handleMouseEnter,
1882
+ onMouseLeave: handleMouseLeave
1883
+ };
1884
+ return {
1885
+ anchorProps,
1886
+ tooltipProps
1887
+ };
1888
+ };
1889
+
1890
+ // src/notifications/NotificationsProvider.tsx
1891
+ var import_react17 = __toESM(require("react"));
1892
+ var import_classnames9 = __toESM(require("classnames"));
1893
+ var import_vuu_utils3 = require("@vuu-ui/vuu-utils");
1894
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1895
+ var toastDisplayDuration = 6e3;
1896
+ var horizontalTransitionDuration = 1e3;
1897
+ var verticalTransitionDuration = 300;
1898
+ var toastHeight = 56;
1899
+ var toastWidth = 300;
1900
+ var toastContainerContentGap = 10;
1901
+ var toastContainerLeftPadding = 10;
1902
+ var toastContainerRightPadding = 50;
1903
+ var classBase7 = "vuuToastNotifications";
1904
+ var NotificationLevel = /* @__PURE__ */ ((NotificationLevel2) => {
1905
+ NotificationLevel2["Info"] = "info";
1906
+ NotificationLevel2["Success"] = "success";
1907
+ NotificationLevel2["Warning"] = "warning";
1908
+ NotificationLevel2["Error"] = "error";
1909
+ return NotificationLevel2;
1910
+ })(NotificationLevel || {});
1911
+ var NotificationsContext = import_react17.default.createContext({
1912
+ notify: () => "have you forgotten to provide a NotificationProvider?"
1913
+ });
1914
+ var NotificationsProvider = (props) => {
1915
+ const [notifications, setNotifications] = (0, import_react17.useState)([]);
1916
+ const notify = (0, import_react17.useCallback)((notification) => {
1917
+ const newNotification = { ...notification, id: (0, import_vuu_utils3.getUniqueId)() };
1918
+ setNotifications((prev) => [...prev, newNotification]);
1919
+ setTimeout(() => {
1920
+ setNotifications((prev) => prev.filter((n) => n !== newNotification));
1921
+ }, toastDisplayDuration + horizontalTransitionDuration * 2);
1922
+ }, []);
1923
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(NotificationsContext.Provider, { value: { notify }, children: [
1924
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1925
+ "div",
1926
+ {
1927
+ className: `${classBase7}-toastContainer`,
1928
+ style: {
1929
+ width: toastWidth + toastContainerRightPadding + toastContainerLeftPadding
1930
+ },
1931
+ children: notifications.map((notification, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1932
+ ToastNotification,
1933
+ {
1934
+ top: (toastHeight + toastContainerContentGap) * i,
1935
+ notification
1936
+ },
1937
+ notification.id
1938
+ ))
1939
+ }
1940
+ ),
1941
+ props.children
1942
+ ] });
1943
+ };
1944
+ var useNotifications = () => (0, import_react17.useContext)(NotificationsContext);
1945
+ var ToastNotification = (props) => {
1946
+ const { top, notification, animated = true } = props;
1947
+ const [right, setRight] = (0, import_react17.useState)(-toastWidth - toastContainerRightPadding);
1948
+ (0, import_react17.useEffect)(() => {
1949
+ setRight(toastContainerRightPadding);
1950
+ if (animated) {
1951
+ setTimeout(
1952
+ () => setRight(-toastWidth - toastContainerRightPadding),
1953
+ toastDisplayDuration + horizontalTransitionDuration
1954
+ );
1955
+ }
1956
+ }, [animated]);
1957
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1958
+ "div",
1959
+ {
1960
+ className: (0, import_classnames9.default)(`${classBase7}-toast`, notification.type),
1961
+ style: {
1962
+ height: toastHeight,
1963
+ right,
1964
+ width: toastWidth,
1965
+ top,
1966
+ transition: animated ? `right ${horizontalTransitionDuration}ms, top ${verticalTransitionDuration}ms ` : "none"
1967
+ },
1968
+ children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1970
+ "div",
1971
+ {
1972
+ className: (0, import_classnames9.default)(
1973
+ `${classBase7}-toastIcon`,
1974
+ `${notification.type}-icon`
1975
+ )
1976
+ }
1977
+ ),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${classBase7}-toastContent`, children: [
1979
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { className: `${classBase7}-toastHeader`, children: notification.header }),
1980
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: notification.body })
1981
+ ] })
1982
+ ]
1983
+ }
1984
+ );
1985
+ };
2
1986
  //# sourceMappingURL=index.js.map