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