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