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