@dashfoo/react 0.1.0 → 0.2.0

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/dist/index.js CHANGED
@@ -1,2 +1,9 @@
1
- "use client";import{Fragment as e,createContext as t,forwardRef as n,useCallback as r,useContext as i,useEffect as a,useImperativeHandle as o,useInsertionEffect as s,useLayoutEffect as c,useMemo as l,useRef as u,useState as d}from"react";import{canRedo as f,canUndo as p,dashfooMachine as m,dragDockMachine as h,findTabset as g,fromJSON as _,normalize as v,reducer as y,resolveDockTarget as b,toJSON as x,zoneRect as S}from"@dashfoo/core";import{useActorRef as C,useSelector as w}from"@xstate/react";import{Accessibility as T,DragDropManager as E,Draggable as D,Feedback as O,KeyboardSensor as k}from"@dnd-kit/dom";import{Fragment as A,jsx as j,jsxs as M}from"react/jsx-runtime";import{Group as N,Panel as P,Separator as F}from"react-resizable-panels";const I=t(null),L=()=>{let e=i(I);if(e===null)throw Error(`dashfoo components must be rendered inside <DashfooLayout>.`);return e},R=()=>{let e=new Map;return{getItem:t=>e.get(t)??null,removeItem:t=>{e.delete(t)},setItem:(t,n)=>{e.set(t,n)}}},z={getItem:e=>{if(typeof window>`u`)return null;try{return window.localStorage.getItem(e)}catch{return null}},removeItem:e=>{if(!(typeof window>`u`))try{window.localStorage.removeItem(e)}catch{}},setItem:(e,t)=>{if(!(typeof window>`u`))try{window.localStorage.setItem(e,t)}catch(e){console.warn(`[dashfoo] failed to persist layout`,e)}}},B=(e,t)=>{let n=u(e);a(()=>{n.current=e});let[i]=d(()=>{if(e===null||t===void 0)return t;let n=e.storage.getItem(e.key);if(n===null)return t;try{return _(n)}catch{return t}});a(()=>{let e=n.current;if(e===null)return;let t=e.storage.getItem(e.key);if(t!==null)try{_(t)}catch(t){console.warn(`[dashfoo] discarding unreadable persisted layout`,t),e.storage.removeItem(e.key)}},[]);let o=u(e?.key);a(()=>{e!==null&&e.key!==o.current&&(console.warn(`[dashfoo] persist key changed for a mounted layout; the displayed layout still reflects the previous key — remount (key={persistKey}) to load the new key`),o.current=e.key)},[e]);let s=u(null),c=u(null),l=r(()=>{s.current!==null&&(clearTimeout(s.current),s.current=null);let e=n.current;c.current!==null&&e!==null&&(e.storage.setItem(c.current.key,c.current.value),c.current=null)},[]),f=r(e=>{let t=n.current;t!==null&&(c.current={key:t.key,value:x(e)},s.current!==null&&clearTimeout(s.current),s.current=setTimeout(l,t.debounceMs))},[l]);return a(()=>()=>{l()},[l]),{clear:r(()=>{s.current!==null&&(clearTimeout(s.current),s.current=null),c.current=null;let e=n.current;e!==null&&e.storage.removeItem(e.key)},[]),initialModel:i,save:f}},V=e=>{let{defaultModel:t,model:n,onAction:i,onActiveTabsetChange:o,onMaximizedTabsetChange:s,onModelChange:c}=e,l=n??t;if(l===void 0)throw Error("useDashfooStore requires either a `model` or a `defaultModel`.");let u=C(m,{input:{model:v(l)}}),d=w(u,e=>e.context.history);a(()=>{n!==void 0&&u.send({model:v(n),type:`SET_MODEL`})},[u,n]);let h=n??d.present,g=r((e,t,n)=>{Object.is(e,t)||(c?.(t,n),t.activeTabsetId!==e.activeTabsetId&&o?.(t.activeTabsetId),t.maximizedTabsetId!==e.maximizedTabsetId&&s?.(t.maximizedTabsetId))},[c,o,s]),_=r(e=>{let t=i?i(e):e;if(!t)return;let r=(()=>{if(n===void 0){let e=u.getSnapshot().context.history.present;return u.send({action:t,type:`DISPATCH`}),{after:u.getSnapshot().context.history.present,before:e}}return{after:y(n,t),before:v(n)}})();g(r.before,r.after,t)},[u,n,g,i]),b=r(()=>{if(n!==void 0)return;let e=u.getSnapshot().context.history.present;u.send({type:`UNDO`});let t=u.getSnapshot().context.history.present;g(e,t)},[u,n,g]);return{canRedo:()=>f(u.getSnapshot().context.history),canUndo:()=>p(u.getSnapshot().context.history),dispatch:_,model:h,redo:r(()=>{if(n!==void 0)return;let e=u.getSnapshot().context.history.present;u.send({type:`REDO`});let t=u.getSnapshot().context.history.present;g(e,t)},[u,n,g]),setModel:r(e=>{u.send({model:v(e),type:`SET_MODEL`})},[u]),undo:b}},H=t(null),ee=t(null),te=()=>{let e=u(null),t=u(null);return{draggableRef:t,elementRef:e,ref:r(n=>{e.current=n,t.current&&(t.current.element=n??void 0)},[])}},ne=(e,t,n)=>{let r=i(H),{draggableRef:o,elementRef:s,ref:c}=te(),{data:l,id:u}=e;return a(()=>{let e=r?.manager;if(!e||t)return;let n=new D({data:{...l,label:``},id:u},e);return n.element=s.current??void 0,o.current=n,()=>{n.destroy(),o.current=null}},[r,l,t,o,s,u]),a(()=>{let e=o.current;e&&(e.data={...l,label:n})},[l,o,n]),{ref:c}},re=(e,t=!1,n=``)=>ne({data:l(()=>({type:`tab`}),[]),id:e},t,n),ie=(e,t=!1,n=``)=>ne({data:l(()=>({tabsetId:e,type:`tabset`}),[e]),id:`grip-${e}`},t,n),ae=e=>{let t=i(H);return{ref:r(n=>{t?.registerTabset(e,n)},[t,e])}},U=()=>i(ee),W=(e,t)=>e.x>=t.x&&e.x<=t.x+t.width&&e.y>=t.y&&e.y<=t.y+t.height,oe=(e,t)=>{let n=e.findIndex(e=>t<e.x+e.width/2);return n===-1?e.length:n},se=(e,t,n)=>{let r=t[n],i=t.at(-1),a=r?.x??(i?i.x+i.width:e.x);return{height:e.height,width:2,x:a-1,y:e.y}},ce=(e,t,n)=>!(e===`grip-${t}`||n.length===1&&n[0]===e),G=(e,t)=>[...e.querySelectorAll(`[data-dashfoo="tab"]`)].flatMap(e=>e.dataset.tabId===t?[]:[e.getBoundingClientRect()]),le=(e,t)=>[...e.querySelectorAll(`[data-dashfoo="tab-item"]`)].flatMap(e=>e.querySelector(`[data-dashfoo="tab"]`)?.dataset.tabId===t?[]:[e.getBoundingClientRect()]),ue=(e,t,n,r)=>{let i=t.querySelector(`[data-dashfoo="tabstrip"]`);if(i&&W(n,i.getBoundingClientRect()))return{index:oe(G(i,r),n.x),location:`center`,targetId:e};let a=b(n,t.getBoundingClientRect()),o=a.kind===`tab`?`center`:`split-${a.edge}`;return o===`center`&&i?{index:G(i,r).length,location:o,targetId:e}:{location:o,targetId:e}},K={boxSizing:`border-box`,pointerEvents:`none`,position:`fixed`,transition:`var(--dashfoo-dock-transition, left 60ms, top 60ms, width 60ms, height 60ms)`,zIndex:9999},de=e=>({...K,background:`var(--dashfoo-dock-fill, oklch(0.556 0 0 / 0.18))`,border:`var(--dashfoo-dock-border-width, 1px) solid var(--dashfoo-dock-border, oklch(0.708 0 0 / 0.75))`,borderRadius:`var(--dashfoo-dock-radius, 6px)`,height:e.height,left:e.x,top:e.y,width:e.width}),fe=e=>({...K,background:`var(--dashfoo-dock-line, oklch(0.556 0 0))`,borderRadius:`var(--dashfoo-dock-line-radius, 2px)`,height:e.height,left:e.x,top:e.y,width:e.width}),pe=({actorRef:e,getTabsetElement:t})=>{let n=w(e,e=>e.context.intent),r=w(e,e=>e.context.subject?.id);if(!n)return null;let i=t(n.targetId);if(!i)return null;if(n.location===`center`){let e=i.querySelector(`[data-dashfoo="tabstrip"]`);if(e)return j(`div`,{"data-dashfoo":`dock-indicator`,style:fe(se(e.getBoundingClientRect(),le(e,r),n.index??0))},`line`)}return j(`div`,{"data-dashfoo":`dock-indicator`,style:de(S(i.getBoundingClientRect(),n.location))},`pane`)},q={x:12,y:8},me={left:0,position:`fixed`,top:0,zIndex:9999},he=({overlayRef:e,preview:t})=>t?j(`div`,{"data-dashfoo":`drag-preview`,ref:e,style:{...me,transform:`translate(${t.x}px, ${t.y}px)`},children:t.label}):null,ge=e=>{let t=e?.data?.label;return typeof t==`string`?t:``},_e=({children:e,onCommit:t,splitDock:n=!0})=>{let i=C(h),o=w(i,e=>e.context.subject),c=u(new Map),f=u(null),[p,m]=d(null),[g]=d(()=>new E({plugins:e=>e.filter(e=>e!==T&&e!==O),sensors:e=>e.filter(e=>e!==k)}));s(()=>()=>g.destroy(),[g]),a(()=>{let e=i.on(`COMMIT`,e=>{t(e.action)});return()=>{e.unsubscribe()}},[i,t]);let _=r((e,t)=>{t?c.current.set(e,t):c.current.delete(e)},[]),v=r(e=>c.current.get(e),[]),y=r(e=>{for(let[t,n]of c.current)if(W(e,n.getBoundingClientRect()))return{element:n,id:t}},[]),b=r((e,t,r,i)=>{if(!ce(i,e,[...t.querySelectorAll(`[data-dashfoo="tab"]`)].map(e=>e.dataset.tabId??``)))return null;let a=ue(e,t,r,i);return!n&&a.location.startsWith(`split-`)?{location:`center`,targetId:e}:a},[n]),x=r(e=>{let t=f.current;t&&(t.style.transform=`translate(${e.x+q.x}px, ${e.y+q.y}px)`)},[]),S=r(e=>{f.current=e},[]);a(()=>{let e=e=>{let t=e.operation.source;if(!t)return;let n=t.data?.type===`tabset`,r=e.operation.position.current;m({label:ge(t),x:r.x+q.x,y:r.y+q.y}),i.send({subject:{id:String(n?t.data.tabsetId:t.id),kind:n?`tabset`:`tab`},type:`START`})},t=e=>{let t=e.operation,n=t.position.current;x(n);let r=t.source?String(t.source.id):void 0,a=y(n);i.send({intent:a?b(a.id,a.element,n,r):null,type:`OVER`})},n=e=>{if(m(null),e.canceled){i.send({type:`CANCEL`});return}let t=e.operation,n=t.position.current,r=t.source?String(t.source.id):void 0,a=y(n);a&&i.send({intent:b(a.id,a.element,n,r),type:`OVER`}),i.send({type:`DROP`})},r=g.monitor.addEventListener(`dragstart`,e),a=g.monitor.addEventListener(`dragmove`,t),o=g.monitor.addEventListener(`dragend`,n);return()=>{r(),a(),o()}},[i,g,x,b,y]);let D=l(()=>({manager:g,registerTabset:_}),[g,_]);return j(H.Provider,{value:D,children:M(ee.Provider,{value:o,children:[e,j(pe,{actorRef:i,getTabsetElement:v}),j(he,{overlayRef:S,preview:p})]})})},ve=e=>{let t=e.getBoundingClientRect();return[...e.querySelectorAll(`[data-dashfoo="tab"]`)].flatMap(e=>{let n=e.getBoundingClientRect();return(n.right>t.right+1||n.left<t.left-1)&&e.dataset.tabId?[e.dataset.tabId]:[]})},ye=(e,t)=>{let[n,r]=d([]);return a(()=>{let t=e.current;if(!t)return;let n=()=>{r(ve(t))};n();let i=new ResizeObserver(n);return i.observe(t),t.addEventListener(`scroll`,n,{passive:!0}),()=>{i.disconnect(),t.removeEventListener(`scroll`,n)}},[e,t]),n},J=(e,t)=>`dashfoo-tab-${e}-${t}`,Y=e=>`dashfoo-panel-${e}`,be=(e,t)=>t+1<e?t+1:t-1,xe={pointerEvents:`none`},X=({children:e})=>j(`svg`,{"aria-hidden":`true`,fill:`none`,height:`12`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,style:xe,viewBox:`0 0 24 24`,width:`12`,children:e}),Se=()=>M(X,{children:[j(`path`,{d:`M18 6 6 18`}),j(`path`,{d:`m6 6 12 12`})]}),Ce=()=>M(X,{children:[j(`circle`,{cx:`12`,cy:`5`,r:`1`}),j(`circle`,{cx:`19`,cy:`5`,r:`1`}),j(`circle`,{cx:`5`,cy:`5`,r:`1`}),j(`circle`,{cx:`12`,cy:`12`,r:`1`}),j(`circle`,{cx:`19`,cy:`12`,r:`1`}),j(`circle`,{cx:`5`,cy:`12`,r:`1`}),j(`circle`,{cx:`12`,cy:`19`,r:`1`}),j(`circle`,{cx:`19`,cy:`19`,r:`1`}),j(`circle`,{cx:`5`,cy:`19`,r:`1`})]}),we=({maximized:e})=>e?M(X,{children:[j(`path`,{d:`m14 10 7-7`}),j(`path`,{d:`M20 10h-6V4`}),j(`path`,{d:`m3 21 7-7`}),j(`path`,{d:`M4 14h6v6`})]}):M(X,{children:[j(`path`,{d:`M15 3h6v6`}),j(`path`,{d:`m21 3-7 7`}),j(`path`,{d:`m3 21 7-7`}),j(`path`,{d:`M9 21H3v-6`})]}),Te=({name:e,onCancel:t,onCommit:n})=>{let r=u(null),i=u(!1);return a(()=>{r.current?.focus(),r.current?.select()},[]),j(`input`,{"aria-label":`Rename ${e}`,"data-dashfoo":`tab-rename`,defaultValue:e,onBlur:e=>{i.current||(i.current=!0,n(e.currentTarget.value))},onKeyDown:e=>{e.key===`Enter`?(i.current=!0,n(e.currentTarget.value)):e.key===`Escape`&&(i.current=!0,t())},ref:r,type:`text`})},Ee=({closable:e,index:t,onClose:n,renamable:r,selected:i,tab:o,tabsetId:s})=>{let{dispatch:c,renderTabLabel:l}=L(),{ref:f}=re(o.id,o.enableDrag===!1,o.name),p=U(),m=p?.kind===`tab`&&p.id===o.id,[h,g]=d(!1),_=u(null),v=u(!1);return a(()=>{v.current&&!h&&_.current?.querySelector(`[data-dashfoo="tab"]`)?.focus(),v.current=h},[h]),M(`span`,{"data-dashfoo":`tab-item`,"data-dragging":m||void 0,ref:_,children:[h?j(Te,{name:o.name,onCancel:()=>{g(!1)},onCommit:e=>{g(!1);let t=e.trim();t&&t!==o.name&&c({name:t,tabId:o.id,type:`renameTab`})}}):j(`button`,{"aria-controls":Y(s),"aria-label":l?o.name:void 0,"aria-selected":t===i,"data-dashfoo":`tab`,"data-tab-id":o.id,id:J(s,o.id),onClick:()=>{c({index:t,tabsetId:s,type:`selectTab`})},onDoubleClick:()=>{r&&g(!0)},ref:f,role:`tab`,tabIndex:t===i?0:-1,type:`button`,children:l?l(o):o.name}),e&&!h?j(`button`,{"aria-label":`Close ${o.name}`,"data-dashfoo":`tab-close`,onClick:e=>{e.stopPropagation(),n(o.id)},tabIndex:t===i?0:-1,type:`button`,children:j(Se,{})}):null]})},De=()=>M(`svg`,{"aria-hidden":`true`,fill:`currentColor`,height:`10`,viewBox:`0 0 10 10`,width:`10`,children:[j(`circle`,{cx:`2`,cy:`5`,r:`1`}),j(`circle`,{cx:`5`,cy:`5`,r:`1`}),j(`circle`,{cx:`8`,cy:`5`,r:`1`})]}),Oe={position:`absolute`,right:0,top:`100%`,zIndex:10},ke=({items:e,onSelect:t})=>{let[n,r]=d(!1),[i,o]=d(0),s=u(null),c=u(null),l=u([]);a(()=>{if(!n)return;let e=e=>{e.target instanceof Node&&!s.current?.contains(e.target)&&r(!1)};return document.addEventListener(`pointerdown`,e),()=>{document.removeEventListener(`pointerdown`,e)}},[n]),a(()=>{n&&l.current[0]?.focus()},[n]);let f=()=>{r(!1),c.current?.focus()},p=e=>{o(e),l.current[e]?.focus()},m=()=>{o(0),r(e=>!e)},h=e=>{t(e),f()};return M(`div`,{"data-dashfoo":`tab-overflow-root`,ref:s,style:{position:`relative`},children:[j(`button`,{"aria-expanded":n,"aria-haspopup":`menu`,"aria-label":`More tabs`,"data-dashfoo":`tab-overflow`,onClick:m,ref:c,type:`button`,children:j(De,{})}),n?j(`div`,{"data-dashfoo":`tab-overflow-menu`,onBlur:e=>{e.relatedTarget instanceof Node&&s.current?.contains(e.relatedTarget)||r(!1)},onKeyDown:t=>{let n=e.length-1;switch(t.key){case`ArrowDown`:t.preventDefault(),p(i>=n?0:i+1);break;case`ArrowUp`:t.preventDefault(),p(i<=0?n:i-1);break;case`Home`:t.preventDefault(),p(0);break;case`End`:t.preventDefault(),p(n);break;case`Escape`:t.preventDefault(),f();break;default:break}},role:`menu`,style:Oe,tabIndex:-1,children:e.map((e,t)=>j(`button`,{"data-dashfoo":`tab-overflow-item`,onClick:()=>h(e.id),ref:e=>{l.current[t]=e},role:`menuitem`,tabIndex:t===i?0:-1,type:`button`,children:e.name},e.id))}):null]})},Ae={display:`flex`,flexDirection:`column`,height:`100%`,minHeight:0,minWidth:0,width:`100%`},je={display:`flex`,flexShrink:0},Me={display:`flex`,minWidth:0,overflowX:`auto`},Z={flex:1,minHeight:0,overflow:`auto`},Ne={alignItems:`center`,display:`flex`,flexShrink:0,marginInlineStart:`auto`},Pe=({tab:e})=>{let{renderTab:t}=L();return t(e)},Fe=({node:e})=>{let{closableTabs:t,dispatch:n,draggableTabsets:r,keepMounted:i,maximizable:o,maximizedTabsetId:s,renamableTabs:c,renderTabsetToolbar:d,tabLocation:f,tabStripEnabled:p}=L(),{ref:m}=ae(e.id),h=U(),g=s===e.id,_=u(null),v=u(null),y=u(!1),b=t&&e.enableClose!==!1,x=o&&e.enableMaximize!==!1,S=h?.kind===`tab`?e.children.findIndex(e=>e.id===h.id):-1,C=S!==-1&&S===e.selected?be(e.children.length,S):e.selected,w=e.children[C],T=h?.kind===`tabset`&&h.id===e.id,{ref:E}=ie(e.id,!r||g,w?.name??``),D=()=>{n({tabsetId:g?null:e.id,type:`setMaximizedTabset`})},O=ye(_,e.children.map(e=>`${e.id}:${e.name}`).join(`|`)),k=l(()=>{let t=new Map(e.children.map(e=>[e.id,e.name]));return O.map(e=>({id:e,name:t.get(e)??e}))},[O,e.children]),N=t=>{let r=e.children.findIndex(e=>e.id===t);r!==-1&&(n({index:r,tabsetId:e.id,type:`selectTab`}),_.current?.querySelector(`#${CSS.escape(J(e.id,t))}`)?.scrollIntoView({block:`nearest`,inline:`nearest`}))},P=e=>{y.current=!0,n({tabId:e,type:`deleteTab`})};a(()=>{if(!y.current)return;y.current=!1;let t=e.children[e.selected]?.id;t?_.current?.querySelector(`#${CSS.escape(J(e.id,t))}`)?.focus():v.current?.focus()},[e.children,e.selected,e.id]);let F=p?M(`div`,{"data-dashfoo":`tabstrip`,style:je,children:[j(`div`,{"aria-label":e.name??`Tabs`,"aria-orientation":`horizontal`,"data-dashfoo":`tablist`,onKeyDown:t=>{if(!(t.target instanceof HTMLElement)||!t.target.closest(`[role="tab"]`))return;let r=e.children.length;if(r===0)return;let i={ArrowLeft:(e.selected-1+r)%r,ArrowRight:(e.selected+1)%r,End:r-1,Home:0}[t.key];if(i===void 0)return;t.preventDefault(),n({index:i,tabsetId:e.id,type:`selectTab`});let a=e.children[i]?.id;a&&_.current?.querySelector(`#${CSS.escape(J(e.id,a))}`)?.focus()},ref:_,role:`tablist`,style:Me,tabIndex:-1,children:e.children.map((t,n)=>j(Ee,{closable:b&&t.enableClose!==!1,index:n,onClose:P,renamable:c&&t.enableRename!==!1,selected:C,tab:t,tabsetId:e.id},t.id))}),x||d||k.length>0||r&&!g?M(`div`,{"data-dashfoo":`tabset-toolbar`,style:Ne,children:[k.length>0?j(ke,{items:k,onSelect:N}):null,r&&!g?j(`button`,{"aria-label":`Move tabset`,"data-dashfoo":`tabset-grip`,ref:E,type:`button`,children:j(Ce,{})}):null,d?.(e),x?j(`button`,{"aria-label":g?`Restore`:`Maximize`,"aria-pressed":g,"data-dashfoo":`tabset-maximize`,onClick:D,type:`button`,children:j(we,{maximized:g})}):null]}):null]}):null,I=i&&e.children.length>0?e.children.map((t,n)=>j(`div`,{"aria-labelledby":J(e.id,t.id),"data-dashfoo":`tabcontent`,hidden:n!==C||void 0,id:n===C?Y(e.id):void 0,role:n===C?`tabpanel`:void 0,style:Z,tabIndex:n===C?0:void 0,children:j(Pe,{tab:t})},t.id)):w?j(`div`,{"aria-labelledby":J(e.id,w.id),"data-dashfoo":`tabcontent`,id:Y(e.id),role:`tabpanel`,style:Z,tabIndex:0,children:j(Pe,{tab:w})}):j(`div`,{"data-dashfoo":`tabcontent`,style:Z});return j(`div`,{"data-dashfoo":`tabset`,"data-dragging-source":T||void 0,"data-tab-location":f,ref:e=>{m(e),v.current=e},style:Ae,tabIndex:-1,children:f===`bottom`?M(A,{children:[I,F]}):M(A,{children:[F,I]})})},Ie=e=>`${e.value}${e.unit}`,Le=e=>e?.unit===`px`?e.value:void 0,Re={display:`flex`,flex:1,minHeight:0,minWidth:0},ze=.01,Be=(e,t)=>e.reduce((e,n)=>(e[n.id]=(n.weight??1)/t*100,e),{}),Ve=(e,t)=>{let n=Object.keys(e),r=Object.keys(t);return n.length===r.length?r.every(n=>Math.abs((e[n]??NaN)-t[n])<=ze):!1},He=(e,t,n)=>{let r=Le(e.min);if(r!==void 0)return r;if(e.min!==void 0)return;if(e.type===`tabset`)return n;let i=[];for(let r of e.children){let e=He(r,t,n);if(e===void 0)return;i.push(e)}if(i.length!==0)return e.orientation===t?i.reduce((e,t)=>e+t,0):Math.max(...i)},Q=({node:t})=>{let{dispatch:n,tabsetMinSize:r}=L(),i=t.orientation===`row`?`horizontal`:`vertical`,a=t.children.reduce((e,t)=>e+(t.weight??1),0),o=l(()=>Be(t.children,a),[t.children,a]),s=u(!1),d=u(null),f=u(!1);return c(()=>{let e=d.current;if(!e||Ve(e.getLayout(),o))return;f.current=!0,e.setLayout(o);let t=requestAnimationFrame(()=>{f.current=!1});return()=>{cancelAnimationFrame(t),f.current=!1}},[o]),j(N,{"data-dashfoo":`row`,groupRef:d,onLayoutChanged:e=>{if(!s.current){s.current=!0;return}if(f.current)return;let r=t.children.map(t=>e[t.id]??t.weight??1);r.some((e,n)=>Math.abs(e-(t.children[n]?.weight??1))>ze)&&n({rowId:t.id,type:`adjustSplit`,weights:r})},orientation:i,style:Re,children:t.children.map((n,i)=>{let o=(n.weight??1)/a*100,s=n.min?Ie(n.min):void 0;if(s===void 0){let e=He(n,t.orientation,r);s=e===void 0?void 0:`${e}px`}let c=n.max?Ie(n.max):void 0;return M(e,{children:[i>0?j(F,{"data-dashfoo":`splitter`}):null,j(P,{defaultSize:`${o}%`,id:n.id,maxSize:c,minSize:s,children:n.type===`row`?j(Q,{node:n}):j(Fe,{node:n})})]},n.id)})},t.children.map(e=>e.id).join(`|`))},Ue=(e,t)=>e===void 0||!t?null:typeof e==`string`?{debounceMs:300,key:e,storage:z}:{debounceMs:e.debounceMs??300,key:e.key,storage:e.storage??z},We=new Set,Ge={display:`flex`,height:`100%`,width:`100%`},Ke=n((e,t)=>{let{closableTabs:n=!0,components:i,defaultModel:a,draggableTabsets:s=!0,factory:c,keepMounted:u=!1,maximizable:d=!0,model:f,onAction:p,onActiveTabsetChange:m,onMaximizedTabsetChange:h,onModelChange:_,persist:v,renamableTabs:y=!0,renderTabLabel:b,renderTabsetToolbar:x}=e,S=B(l(()=>Ue(v,a!==void 0),[v,a]),a),C=r((e,t)=>{S.save(e),_?.(e,t)},[_,S]),w=V({defaultModel:S.initialModel??a,model:f,onAction:p,onActiveTabsetChange:m,onMaximizedTabsetChange:h,onModelChange:C});o(t,()=>({addTab:(e,t)=>w.dispatch({index:t.index,location:t.location??`center`,tab:e,targetId:t.targetId,type:`addNode`}),canRedo:w.canRedo,canUndo:w.canUndo,closeTab:e=>w.dispatch({tabId:e,type:`deleteTab`}),dispatch:w.dispatch,getModel:()=>w.model,maximizeTabset:e=>w.dispatch({tabsetId:e,type:`setMaximizedTabset`}),redo:w.redo,renameTab:(e,t)=>w.dispatch({name:t,tabId:e,type:`renameTab`}),resetLayout:()=>{S.clear(),a!==void 0&&w.setModel(a)},selectTab:(e,t)=>w.dispatch({index:t,tabsetId:e,type:`selectTab`}),undo:w.undo}),[a,S,w]);let T=r(e=>{if(c)return c(e);let t=i?.[e.component];return t?j(t,{node:e}):(i&&!We.has(e.component)&&(We.add(e.component),console.warn(`[dashfoo] no component registered for "${e.component}"`)),null)},[i,c]),E=w.model.global,D=n&&E.tabEnableClose!==!1,O=y&&E.tabEnableRename!==!1,k=d&&E.tabSetEnableMaximize!==!1,A=E.tabLocation??`top`,M=E.tabSetMinSize??320,N=E.tabSetEnableTabStrip!==!1,P=l(()=>({closableTabs:D,dispatch:w.dispatch,draggableTabsets:s,keepMounted:u,maximizable:k,maximizedTabsetId:w.model.maximizedTabsetId,renamableTabs:O,renderTab:T,renderTabLabel:b,renderTabsetToolbar:x,tabLocation:A,tabsetMinSize:M,tabStripEnabled:N}),[s,D,k,O,u,T,b,x,w.dispatch,w.model.maximizedTabsetId,A,M,N]),F=w.dispatch,L=E.enableSplitDock!==!1,R=E.splitterSize===void 0?Ge:{...Ge,"--dashfoo-splitter-size":`${E.splitterSize}px`},z=w.model.maximizedTabsetId?g(w.model,w.model.maximizedTabsetId):void 0;return j(I.Provider,{value:P,children:j(_e,{onCommit:F,splitDock:L,children:j(`div`,{"data-dashfoo":`layout`,style:R,children:z?j(Fe,{node:z}):j(Q,{node:w.model.layout})})})})});Ke.displayName=`DashfooLayout`;const qe={Badge:e=>j(`span`,{...e,"data-dashfoo":`panel-badge`}),Body:e=>j(`div`,{...e,"data-dashfoo":`panel-body`}),Header:e=>j(`div`,{...e,"data-dashfoo":`panel-header`}),Icon:e=>j(`span`,{...e,"data-dashfoo":`panel-icon`}),Root:e=>j(`div`,{...e,"data-dashfoo":`panel`}),Title:e=>j(`span`,{...e,"data-dashfoo":`panel-title`})},Je=()=>typeof window<`u`&&typeof window.matchMedia==`function`,Ye=(e,t)=>{let{query:n}=e;return n?`maxWidth`in n?t<=n.maxWidth:Je()&&window.matchMedia(n.media).matches:!0},$=(e,t)=>{let n=e.at(-1);if(!n)throw Error(`useResponsiveModel requires at least one breakpoint.`);return e.find(e=>Ye(e,t))??n},Xe=({breakpoints:e})=>{let[t,n]=d(1/0),[,i]=d(0),o=u(null),s=r(e=>{if(o.current?.disconnect(),!e)return;let t=new ResizeObserver(e=>{let t=e[0];t&&n(t.contentRect.width)});t.observe(e),o.current=t},[]);a(()=>()=>{o.current?.disconnect()},[]),a(()=>{if(!Je())return;let t=e.flatMap(e=>e.query&&`media`in e.query?[window.matchMedia(e.query.media)]:[]);if(t.length===0)return;let n=()=>{i(e=>e+1)};for(let e of t)e.addEventListener(`change`,n);return()=>{for(let e of t)e.removeEventListener(`change`,n)}},[e]);let c=$(e,t);return{breakpoint:c.id,containerRef:s,defaultModel:c.model,key:c.id}};export{I as DashfooContext,Ke as DashfooLayout,qe as Panel,$ as activeBreakpoint,z as localStorageAdapter,Ye as matchBreakpoint,R as memoryStorageAdapter,L as useDashfooContext,V as useDashfooStore,B as usePersistence,Xe as useResponsiveModel};
1
+ "use client";import{canRedo as e,canUndo as t,dashfooMachine as n,dragDockMachine as r,findTabset as i,fromJSON as a,normalize as o,reducer as s,resolveDockTarget as c,tabNodeSchema as l,toJSON as u,zoneRect as d}from"@dashfoo/core";import{Fragment as f,createContext as p,createElement as m,forwardRef as h,useCallback as g,useContext as _,useEffect as v,useId as y,useImperativeHandle as b,useInsertionEffect as x,useLayoutEffect as S,useMemo as C,useRef as w,useState as T}from"react";import{useActorRef as E,useSelector as D}from"@xstate/react";import{Accessibility as O,DragDropManager as k,Draggable as A,Feedback as ee,PointerSensor as te}from"@dnd-kit/dom";import{createStore as j,useStore as M}from"zustand";import{Fragment as ne,jsx as N,jsxs as P}from"react/jsx-runtime";import{Group as re,Panel as ie,Separator as ae}from"react-resizable-panels";const oe=()=>{let e=new Map;return{getItem:t=>e.get(t)??null,removeItem:t=>{e.delete(t)},setItem:(t,n)=>{e.set(t,n)}}},F={getItem:e=>{if(typeof window>`u`)return null;try{return window.localStorage.getItem(e)}catch{return null}},removeItem:e=>{if(!(typeof window>`u`))try{window.localStorage.removeItem(e)}catch{}},setItem:(e,t)=>{if(!(typeof window>`u`))try{window.localStorage.setItem(e,t)}catch(e){console.warn(`[dashfoo] failed to persist layout`,e)}}},se=(e,t)=>{let n=w(e);v(()=>{n.current=e});let[r]=T(()=>{if(e===null||t===void 0)return t;let n=e.storage.getItem(e.key);if(n===null)return t;try{return a(n)}catch{return t}});v(()=>{let e=n.current;if(e===null)return;let t=e.storage.getItem(e.key);if(t!==null)try{a(t)}catch(t){console.warn(`[dashfoo] discarding unreadable persisted layout`,t),e.storage.removeItem(e.key)}},[]);let i=w(e?.key);v(()=>{e!==null&&e.key!==i.current&&(console.warn(`[dashfoo] persist key changed for a mounted layout; the displayed layout still reflects the previous key — remount (key={persistKey}) to load the new key`),i.current=e.key)},[e]);let o=w(null),s=w(null),c=g(()=>{o.current!==null&&(clearTimeout(o.current),o.current=null),s.current!==null&&(s.current.storage.setItem(s.current.key,s.current.value),s.current=null)},[]),l=g(e=>{let t=n.current;t!==null&&(s.current={key:t.key,storage:t.storage,value:u(e)},o.current!==null&&clearTimeout(o.current),o.current=setTimeout(c,t.debounceMs))},[c]);return v(()=>{let e=()=>{c()},t=()=>{document.visibilityState===`hidden`&&c()};return window.addEventListener(`pagehide`,e),document.addEventListener(`visibilitychange`,t),()=>{window.removeEventListener(`pagehide`,e),document.removeEventListener(`visibilitychange`,t),c()}},[c]),{clear:g(()=>{o.current!==null&&(clearTimeout(o.current),o.current=null),s.current=null;let e=n.current;e!==null&&e.storage.removeItem(e.key)},[]),initialModel:r,save:l}},ce=r=>{let{defaultModel:i,model:a,onAction:c,onActiveTabsetChange:l,onMaximizedTabsetChange:u,onModelChange:d}=r,f=a??i;if(f===void 0)throw Error("useDashfooStore requires either a `model` or a `defaultModel`.");let p=E(n,{input:{model:o(f)}}),m=D(p,e=>e.context.history);v(()=>{a!==void 0&&p.send({model:o(a),type:`SET_MODEL`})},[p,a]);let h=a??m.present,_=g((e,t,n)=>{Object.is(e,t)||(d?.(t,n),t.activeTabsetId!==e.activeTabsetId&&l?.(t.activeTabsetId),t.maximizedTabsetId!==e.maximizedTabsetId&&u?.(t.maximizedTabsetId))},[d,l,u]),y=g(e=>{let t=c?c(e):e;if(!t)return;let n=(()=>{if(a===void 0){let e=p.getSnapshot().context.history.present;return p.send({action:t,type:`DISPATCH`}),{after:p.getSnapshot().context.history.present,before:e}}return{after:s(a,t),before:o(a)}})();_(n.before,n.after,t)},[p,a,_,c]),b=g(()=>{if(a!==void 0)return;let e=p.getSnapshot().context.history.present;p.send({type:`UNDO`});let t=p.getSnapshot().context.history.present;_(e,t)},[p,a,_]);return{canRedo:()=>e(p.getSnapshot().context.history),canUndo:()=>t(p.getSnapshot().context.history),dispatch:y,model:h,redo:g(()=>{if(a!==void 0)return;let e=p.getSnapshot().context.history.present;p.send({type:`REDO`});let t=p.getSnapshot().context.history.present;_(e,t)},[p,a,_]),setModel:g(e=>{p.send({model:o(e),type:`SET_MODEL`})},[p]),undo:b}},le=(e,t)=>{let{target:n}=e;if(!(n instanceof Element))return!1;let r=n.closest(`
2
+ input:not([disabled]),
3
+ select:not([disabled]),
4
+ textarea:not([disabled]),
5
+ button:not([disabled]),
6
+ a[href],
7
+ [contenteditable]:not([contenteditable="false"])
8
+ `);return r!==null&&r!==t.element},ue=()=>new k({plugins:e=>e.filter(e=>e!==O&&e!==ee),sensors:()=>[te.configure({preventActivation:le})]}),I=p(null),L=p(null),de=()=>j(()=>({subject:null})),fe=de(),pe=p(null),me=()=>{let e=w(null),t=w(null);return{draggableRef:t,elementRef:e,ref:g(n=>{e.current=n,t.current&&(t.current.element=n??void 0)},[])}},R=(e,t,n)=>{let r=_(I),i=_(L),a=r?.manager??i,{draggableRef:o,elementRef:s,ref:c}=me(),{data:l,id:u}=e;return v(()=>{if(!a||t)return;let e=new A({data:{...l,label:``},id:u},a);return e.element=s.current??void 0,o.current=e,()=>{e.destroy(),o.current=null}},[l,t,o,s,u,a]),v(()=>{let e=o.current;e&&(e.data={...l,label:n})},[l,o,n]),{ref:c}},he=(e,t=!1,n=``)=>R({data:C(()=>({type:`tab`}),[]),id:e},t,n),ge=(e,t=!1,n=``)=>R({data:C(()=>({tabsetId:e,type:`tabset`}),[e]),id:`grip-${e}`},t,n),_e=e=>{let t=_(I);return{ref:g(n=>{t?.registerTabset(e,n)},[t,e])}},ve=({createTab:e,disabled:t=!1,label:n=``})=>{let r=y(),i=w(e);return v(()=>{i.current=e}),R({data:C(()=>({createTab:()=>i.current(),type:`external`}),[]),id:`external-${r}`},t,n)},z=()=>M(_(pe)??fe,e=>e.subject),ye=e=>j(()=>e),B=p(null),V=e=>{let t=_(B);if(t===null)throw Error(`dashfoo components must be rendered inside <DashfooLayout> or <Layout.Root>.`);return M(t,e)},H=(e,t)=>e.x>=t.x&&e.x<=t.x+t.width&&e.y>=t.y&&e.y<=t.y+t.height,be=(e,t)=>{let n=e.findIndex(e=>t<e.x+e.width/2);return n===-1?e.length:n},xe=(e,t,n,r)=>{let i=t[n],a=t.at(-1),o=i??a,s=i?.x??(a?a.x+a.width:e.x),c=Math.min(r.width,e.width),l=o?.height??Math.min(r.height,e.height);return{height:l,width:c,x:Math.max(e.x,Math.min(s,e.x+e.width-c)),y:o?.y??e.y+e.height-l}},Se=(e,t,n)=>!(e===`grip-${t}`||n.length===1&&n[0]===e),Ce=new Set,U=(e,t)=>{Ce.has(e)||(Ce.add(e),console.warn(`[dashfoo] ${t}`))},we={boxSizing:`border-box`,pointerEvents:`none`,position:`fixed`,transition:`var(--dashfoo-dock-transition, left 60ms, top 60ms, width 60ms, height 60ms)`,zIndex:9999},Te=e=>({...we,background:`var(--dashfoo-dock-fill, oklch(0.556 0 0 / 0.18))`,border:`var(--dashfoo-dock-border-width, 1px) solid var(--dashfoo-dock-border, oklch(0.708 0 0 / 0.75))`,borderRadius:`var(--dashfoo-dock-radius, 6px)`,height:e.height,left:e.x,top:e.y,width:e.width}),Ee=e=>({...Te(e),borderRadius:`var(--dashfoo-dock-tab-radius, var(--dashfoo-dock-radius, 6px))`}),De=(e,t)=>[...e.querySelectorAll(`[data-dashfoo="tab-item"]`)].flatMap(e=>e.querySelector(`[data-dashfoo="tab"]`)?.dataset.tabId===t?[]:[e.getBoundingClientRect()]),Oe={height:32,width:96},ke=(e,t)=>e||(t.length>0?{height:t.reduce((e,t)=>e+t.height,0)/t.length,width:t.reduce((e,t)=>e+t.width,0)/t.length}:Oe),Ae=({actorRef:e,getSourceSize:t,getTabsetElement:n})=>{let r=D(e,e=>e.context.intent),i=D(e,e=>e.context.subject?.id);if(!r)return null;let a=n(r.targetId);if(!a)return null;if(r.location===`center`){let e=a.querySelector(`[data-dashfoo="tabstrip"]`);if(e){let n=De(e,i);return N(`div`,{"data-dashfoo":`dock-indicator`,style:Ee(xe(e.getBoundingClientRect(),n,r.index??0,ke(t(),n)))})}}return N(`div`,{"data-dashfoo":`dock-indicator`,style:Te(d(a.getBoundingClientRect(),r.location))})},je={left:0,position:`fixed`,top:0,zIndex:9999},Me=({overlayRef:e,preview:t})=>t?N(`div`,{"data-dashfoo":`drag-preview`,ref:e,style:{...je,transform:`translate(${t.x}px, ${t.y}px)`},children:t.label}):null,Ne=(e,t)=>[...e.querySelectorAll(`[data-dashfoo="tab"]`)].flatMap(e=>e.dataset.tabId===t?[]:[e.getBoundingClientRect()]),Pe=(e,t,n,r)=>{let i=t.querySelector(`[data-dashfoo="tabstrip"]`);if(i&&H(n,i.getBoundingClientRect()))return{index:be(Ne(i,r),n.x),location:`center`,targetId:e};let a=c(n,t.getBoundingClientRect()),o=a.kind===`tab`?`center`:`split-${a.edge}`;return o===`center`&&i?{index:Ne(i,r).length,location:o,targetId:e}:{location:o,targetId:e}},W={x:12,y:8},Fe=e=>{let t=e?.data?.label;return typeof t==`string`?t:``},Ie=e=>typeof e==`function`,Le=e=>{if(!e)return;let t=(e.closest(`[data-dashfoo="tab-item"]`)??e).getBoundingClientRect();return t.width>0&&t.height>0?{height:t.height,width:t.width}:void 0},Re=e=>{let t=e.data;if(t?.type===`tabset`)return{id:String(t.tabsetId),kind:`tabset`};if(t?.type===`external`){if(!Ie(t.createTab))return console.warn(`[dashfoo] external drag source is missing its createTab function`),null;let n;try{n=t.createTab()}catch(e){return console.warn(`[dashfoo] external drag source createTab threw`,e),null}let r=l.safeParse(n);return r.success?{id:String(e.id),kind:`external`,tab:r.data}:(console.warn(`[dashfoo] external drag source returned an invalid tab`,r.error),null)}return{id:String(e.id),kind:`tab`}},ze=({children:e,onCommit:t,splitDock:n})=>{let i=E(r),a=_(B),o=w(new Map),s=w(null),c=w(void 0),[l,u]=T(null),d=_(L),[f]=T(()=>d?null:ue());x(()=>()=>f?.destroy(),[f]);let p=d??f;if(p===null)throw Error(`[dashfoo] DashfooDragProvider unmounted while its layout is still mounted; keep the provider above the layout or remount the layout`);let[m]=T(()=>de());v(()=>{let e=i.subscribe(e=>{let t=e.context.subject;m.getState().subject!==t&&m.setState({subject:t})});return()=>{e.unsubscribe()}},[i,m]),v(()=>{let e=i.on(`COMMIT`,e=>{let n=t??a?.getState().dispatch;if(!n){U(`drag-layer-no-commit`,`Layout.DragLayer has neither an onCommit prop nor a <Layout.Root> above it; drops are ignored`);return}n(e.action)});return()=>{e.unsubscribe()}},[i,a,t]);let h=g((e,t)=>{t?o.current.set(e,t):o.current.delete(e)},[]),y=g(e=>o.current.get(e),[]),b=g(()=>c.current,[]),S=g(e=>{for(let[t,n]of o.current)if(H(e,n.getBoundingClientRect()))return{element:n,id:t}},[]),D=g((e,t,r,i)=>{if(!Se(i,e,[...t.querySelectorAll(`[data-dashfoo="tab"]`)].map(e=>e.dataset.tabId??``)))return null;let o=Pe(e,t,r,i);return!(n??a?.getState().splitDock??!0)&&o.location.startsWith(`split-`)?{location:`center`,targetId:e}:o},[a,n]),O=g(e=>{let t=s.current;t&&(t.style.transform=`translate(${e.x+W.x}px, ${e.y+W.y}px)`)},[]),k=g(e=>{s.current=e},[]);v(()=>{let e=e=>{let t=e.operation.source;if(!t)return;let n=Re(t);if(!n)return;let r=e.operation.position.current;c.current=Le(t.element),u({label:Fe(t),x:r.x+W.x,y:r.y+W.y}),i.send({subject:n,type:`START`})},t=e=>{let t=e.operation,n=t.position.current;O(n);let r=t.source?String(t.source.id):void 0,a=S(n);i.send({intent:a?D(a.id,a.element,n,r):null,type:`OVER`})},n=e=>{if(u(null),c.current=void 0,e.canceled){i.send({type:`CANCEL`});return}let t=e.operation,n=t.position.current,r=t.source?String(t.source.id):void 0,a=S(n);a&&i.send({intent:D(a.id,a.element,n,r),type:`OVER`}),i.send({type:`DROP`})},r=p.monitor.addEventListener(`dragstart`,e),a=p.monitor.addEventListener(`dragmove`,t),o=p.monitor.addEventListener(`dragend`,n);return()=>{r(),a(),o()}},[i,p,O,D,S]);let A=C(()=>({manager:p,registerTabset:h}),[p,h]);return N(I.Provider,{value:A,children:P(pe.Provider,{value:m,children:[e,N(Ae,{actorRef:i,getSourceSize:b,getTabsetElement:y}),N(Me,{overlayRef:k,preview:l})]})})},Be={display:`flex`,height:`100%`,width:`100%`},Ve=({children:e,closableTabs:t=!0,dispatch:n,draggableTabsets:r=!0,keepMounted:i=!1,maximizable:a=!0,model:o,renamableTabs:s=!0,renderTab:c,renderTabLabel:l,renderTabsetToolbar:u,style:d,...f})=>{let p=o.global,m={closableTabs:t&&p.tabEnableClose!==!1,dispatch:n,draggableTabsets:r,keepMounted:i,maximizable:a&&p.tabSetEnableMaximize!==!1,maximizedTabsetId:o.maximizedTabsetId,renamableTabs:s&&p.tabEnableRename!==!1,renderTab:c,renderTabLabel:l,renderTabsetToolbar:u,splitDock:p.enableSplitDock!==!1,tabLocation:p.tabLocation??`top`,tabsetMinSize:p.tabSetMinSize??320,tabStripEnabled:p.tabSetEnableTabStrip!==!1},[h]=T(()=>ye(m));S(()=>{h.setState(m)});let g=p.splitterSize===void 0?{...Be,...d}:{...Be,"--dashfoo-splitter-size":`${p.splitterSize}px`,...d};return N(B.Provider,{value:h,children:N(`div`,{...f,"data-dashfoo":`layout`,style:g,children:e})})},G=(e,t)=>`dashfoo-tab-${e}-${t}`,K=e=>`dashfoo-panel-${e}`,He=(e,t,n)=>e?.querySelector(`#${CSS.escape(G(t,n))}`)??null,Ue=e=>j((t,n)=>({...e,cancelRename:()=>t({editingTabId:null}),closeTab:e=>{t({restoreFocus:!0}),n().dispatch({tabId:e,type:`deleteTab`})},commitRename:(e,r)=>{t({editingTabId:null});let{node:i,renameTab:a}=n(),o=r.trim(),s=i.children.find(t=>t.id===e)?.name;o&&o!==s&&a(e,o)},editingTabId:null,overflowItems:[],registerRenameInput:()=>(t(e=>({renameInputCount:e.renameInputCount+1})),()=>t(e=>({renameInputCount:e.renameInputCount-1}))),registerTablist:e=>{if(e){let r=n().tablistElement;r&&r!==e&&U(`duplicate-tablist-${n().node.id}`,`more than one <Tabset.Tablist> under the same <Tabset.Root>; the last one wins for keyboard focus and overflow`),t({tablistElement:e});return}t({tablistElement:null})},renameInputCount:0,renameTab:(e,t)=>n().dispatch({name:t,tabId:e,type:`renameTab`}),restoreFocus:!1,selectOverflowTab:e=>{let{dispatch:t,node:r,tablistElement:i}=n(),a=r.children.findIndex(t=>t.id===e);a!==-1&&(t({index:a,tabsetId:r.id,type:`selectTab`}),He(i,r.id,e)?.scrollIntoView({block:`nearest`,inline:`nearest`}))},selectTab:(e,t)=>{let{dispatch:r,node:i,tablistElement:a}=n();if(r({index:e,tabsetId:i.id,type:`selectTab`}),t?.focus){let t=i.children[e]?.id;t&&He(a,i.id,t)?.focus()}},startEditing:e=>{let{node:r,renameInputCount:i,tabsRenamable:a}=n(),o=r.children.find(t=>t.id===e);if(!(!a||o?.enableRename===!1)){if(i===0){U(`missing-rename-input-${r.id}`,`startEditing needs a <Tabset.RenameInput> in the composition; ignoring`);return}t({editingTabId:e})}},tablistElement:null,toggleMaximize:()=>{let{dispatch:e,isMaximized:t,node:r}=n();e({tabsetId:t?null:r.id,type:`setMaximizedTabset`})}})),q=p(null),J=e=>{let t=_(q);if(t===null)throw Error(`dashfoo Tabset parts must be rendered inside <Tabset.Root>.`);return M(t,e)},We=p(null),Y=()=>{let e=_(We);if(e===null)throw Error(`dashfoo tab parts must be rendered inside <Tabset.Tab>.`);return e},Ge={flex:1,minHeight:0,overflow:`auto`},Ke=({render:e,tab:t})=>{let n=V(e=>e.renderTab);return e?e(t):n(t)},qe=({children:e,style:t,...n})=>{let r=J(e=>e.node),i=J(e=>e.visualSelected),a=V(e=>e.keepMounted),o={...Ge,...t};if(a&&r.children.length>0)return r.children.map((t,a)=>m(`div`,{...n,"aria-labelledby":G(r.id,t.id),"data-dashfoo":`tabcontent`,hidden:a!==i||void 0,id:a===i?K(r.id):void 0,key:t.id,role:a===i?`tabpanel`:void 0,style:o,tabIndex:a===i?0:void 0},N(Ke,{render:e,tab:t})));let s=r.children[i];return s?N(`div`,{...n,"aria-labelledby":G(r.id,s.id),"data-dashfoo":`tabcontent`,id:K(r.id),role:`tabpanel`,style:o,tabIndex:0,children:N(Ke,{render:e,tab:s})}):N(`div`,{...n,"data-dashfoo":`tabcontent`,style:o})},Je=()=>P(`svg`,{"aria-hidden":`true`,fill:`currentColor`,height:`10`,viewBox:`0 0 10 10`,width:`10`,children:[N(`circle`,{cx:`2`,cy:`5`,r:`1`}),N(`circle`,{cx:`5`,cy:`5`,r:`1`}),N(`circle`,{cx:`8`,cy:`5`,r:`1`})]}),Ye={position:`absolute`,right:0,top:`100%`,zIndex:10},Xe=({items:e,onSelect:t})=>{let[n,r]=T(!1),[i,a]=T(0),o=w(null),s=w(null),c=w([]);v(()=>{if(!n)return;let e=e=>{e.target instanceof Node&&!o.current?.contains(e.target)&&r(!1)};return document.addEventListener(`pointerdown`,e),()=>{document.removeEventListener(`pointerdown`,e)}},[n]),v(()=>{n&&c.current[0]?.focus()},[n]);let l=()=>{r(!1),s.current?.focus()},u=e=>{a(e),c.current[e]?.focus()},d=()=>{a(0),r(e=>!e)},f=e=>{t(e),l()};return P(`div`,{"data-dashfoo":`tab-overflow-root`,ref:o,style:{position:`relative`},children:[N(`button`,{"aria-expanded":n,"aria-haspopup":`menu`,"aria-label":`More tabs`,"data-dashfoo":`tab-overflow`,onClick:d,ref:s,type:`button`,children:N(Je,{})}),n?N(`div`,{"data-dashfoo":`tab-overflow-menu`,onBlur:e=>{e.relatedTarget instanceof Node&&o.current?.contains(e.relatedTarget)||r(!1)},onKeyDown:t=>{let n=e.length-1;switch(t.key){case`ArrowDown`:t.preventDefault(),u(i>=n?0:i+1);break;case`ArrowUp`:t.preventDefault(),u(i<=0?n:i-1);break;case`Home`:t.preventDefault(),u(0);break;case`End`:t.preventDefault(),u(n);break;case`Escape`:t.preventDefault(),l();break;default:break}},role:`menu`,style:Ye,tabIndex:-1,children:e.map((e,t)=>N(`button`,{"data-dashfoo":`tab-overflow-item`,onClick:()=>f(e.id),ref:e=>{c.current[t]=e},role:`menuitem`,tabIndex:t===i?0:-1,type:`button`,children:e.name},e.id))}):null]})},Ze=()=>{let e=J(e=>e.overflowItems),t=J(e=>e.selectOverflowTab);return e.length===0?null:N(Xe,{items:e,onSelect:t})},Qe=e=>{let t=e.getBoundingClientRect();return[...e.querySelectorAll(`[data-dashfoo="tab"]`)].flatMap(e=>{let n=e.getBoundingClientRect();return(n.right>t.right+1||n.left<t.left-1)&&e.dataset.tabId?[e.dataset.tabId]:[]})},$e=(e,t)=>{let[n,r]=T([]);return v(()=>{let t=()=>{r(t=>{let n=e?Qe(e):[];return n.length===0&&t.length===0?t:n})};if(t(),!e)return;let n=new ResizeObserver(t);return n.observe(e),e.addEventListener(`scroll`,t,{passive:!0}),()=>{n.disconnect(),e.removeEventListener(`scroll`,t)}},[e,t]),n},et=(e,t)=>t+1<e?t+1:t-1,tt={display:`flex`,flexDirection:`column`,height:`100%`,minHeight:0,minWidth:0,width:`100%`},nt=({children:e,node:t,ref:n,style:r,...i})=>{let a=V(e=>e.closableTabs),o=V(e=>e.dispatch),s=V(e=>e.maximizable),c=V(e=>e.maximizedTabsetId),l=V(e=>e.renamableTabs),u=V(e=>e.tabLocation),{ref:d}=_e(t.id),f=z(),p=w(null),m=c===t.id,h=s&&t.enableMaximize!==!1,g=a&&t.enableClose!==!1,_=l,y=f?.kind===`tab`?t.children.findIndex(e=>e.id===f.id):-1,b=y!==-1&&y===t.selected?et(t.children.length,y):t.selected,x=t.children[b],E=f?.kind===`tabset`&&f.id===t.id,D={activeTab:x,dispatch:o,isMaximized:m,node:t,showMaximize:h,tabsClosable:g,tabsRenamable:_,visualSelected:b},[O]=T(()=>Ue(D));S(()=>{O.setState(D)});let k=$e(M(O,e=>e.tablistElement),t.children.map(e=>`${e.id}:${e.name}`).join(`|`)),A=C(()=>{let e=new Map(t.children.map(e=>[e.id,e.name]));return k.map(t=>({id:t,name:e.get(t)??t}))},[k,t.children]);return S(()=>{O.setState({overflowItems:A})},[A,O]),v(()=>{if(!O.getState().restoreFocus)return;O.setState({restoreFocus:!1});let e=t.children[t.selected]?.id;e?p.current?.querySelector(`#${CSS.escape(G(t.id,e))}`)?.focus():p.current?.focus()},[t.children,t.selected,t.id,O]),N(q.Provider,{value:O,children:N(`div`,{...i,"data-dashfoo":`tabset`,"data-dragging-source":E||void 0,"data-tab-location":u,ref:e=>{d(e),p.current=e,typeof n==`function`?n(e):n&&(n.current=e)},style:{...tt,...r},tabIndex:-1,children:e})})},rt=(e,t)=>{typeof e==`function`?e(t):e&&(e.current=t)},X=(...e)=>t=>{for(let n of e)rt(n,t)},it=({children:e,ref:t,tab:n,...r})=>{let i=_(q),a=J(e=>e.node),o=J(e=>e.editingTabId===n.id),s=z(),c=s?.kind===`tab`&&s.id===n.id,l=w(null),u=w(!1),d=a.children.findIndex(e=>e.id===n.id);v(()=>{i?.getState().node.children.some(e=>e.id===n.id)===!1&&U(`orphan-tab-${n.id}`,`<Tabset.Tab> for "${n.id}" is not a child of its Tabset.Root's node; it renders but can never be selected`)},[d===-1,i,n.id]),v(()=>{u.current&&!o&&l.current?.querySelector(`[data-dashfoo="tab"]`)?.focus(),u.current=o},[o]);let f=C(()=>({index:d,tab:n}),[d,n]),p=C(()=>X(l,t),[t]);return N(We.Provider,{value:f,children:N(`span`,{...r,"data-dashfoo":`tab-item`,"data-dragging":c||void 0,ref:p,children:e})})},at=({children:e,onClick:t,onDoubleClick:n,ref:r,...i})=>{let{index:a,tab:o}=Y(),s=J(e=>e.node),c=J(e=>e.editingTabId===o.id),l=J(e=>e.selectTab),u=J(e=>e.startEditing),d=J(e=>e.tabsRenamable),f=J(e=>e.visualSelected),p=V(e=>e.renderTabLabel),{ref:m}=he(o.id,o.enableDrag===!1,o.name),h=C(()=>X(m,r),[m,r]);if(c)return null;let g=a===f,_=d&&o.enableRename!==!1,v=e=>{t?.(e),l(a)},y=e=>{n?.(e),_&&u(o.id)};return N(`button`,{"aria-label":p?o.name:void 0,...i,"aria-controls":K(s.id),"aria-selected":g,"data-dashfoo":`tab`,"data-tab-id":o.id,id:G(s.id,o.id),onClick:v,onDoubleClick:y,ref:h,role:`tab`,tabIndex:g?0:-1,type:`button`,children:e??(p?p(o):o.name)})},ot={pointerEvents:`none`},Z=({children:e})=>N(`svg`,{"aria-hidden":`true`,fill:`none`,height:`12`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`,style:ot,viewBox:`0 0 24 24`,width:`12`,children:e}),st=()=>P(Z,{children:[N(`path`,{d:`M18 6 6 18`}),N(`path`,{d:`m6 6 12 12`})]}),ct=()=>P(Z,{children:[N(`circle`,{cx:`12`,cy:`5`,r:`1`}),N(`circle`,{cx:`19`,cy:`5`,r:`1`}),N(`circle`,{cx:`5`,cy:`5`,r:`1`}),N(`circle`,{cx:`12`,cy:`12`,r:`1`}),N(`circle`,{cx:`19`,cy:`12`,r:`1`}),N(`circle`,{cx:`5`,cy:`12`,r:`1`}),N(`circle`,{cx:`12`,cy:`19`,r:`1`}),N(`circle`,{cx:`19`,cy:`19`,r:`1`}),N(`circle`,{cx:`5`,cy:`19`,r:`1`})]}),lt=({maximized:e})=>e?P(Z,{children:[N(`path`,{d:`m14 10 7-7`}),N(`path`,{d:`M20 10h-6V4`}),N(`path`,{d:`m3 21 7-7`}),N(`path`,{d:`M4 14h6v6`})]}):P(Z,{children:[N(`path`,{d:`M15 3h6v6`}),N(`path`,{d:`m21 3-7 7`}),N(`path`,{d:`m3 21 7-7`}),N(`path`,{d:`M9 21H3v-6`})]}),ut=({defaultValue:e,onBlur:t,onKeyDown:n,ref:r,...i})=>{let{tab:a}=Y(),o=J(e=>e.cancelRename),s=J(e=>e.commitRename),c=w(null),l=w(!1);v(()=>{c.current?.focus(),c.current?.select()},[]);let u=e=>{n?.(e),e.key===`Enter`?(l.current=!0,s(a.id,e.currentTarget.value)):e.key===`Escape`&&(l.current=!0,o())},d=e=>{t?.(e),!l.current&&(l.current=!0,s(a.id,e.currentTarget.value))};return N(`input`,{"aria-label":`Rename ${a.name}`,...i,"data-dashfoo":`tab-rename`,defaultValue:e??a.name,onBlur:d,onKeyDown:u,ref:e=>{c.current=e,typeof r==`function`?r(e):r&&(r.current=e)},type:`text`})},dt=e=>{let{tab:t}=Y(),n=J(e=>e.editingTabId===t.id),r=J(e=>e.registerRenameInput);return v(()=>r(),[r]),n?N(ut,{...e}):null},ft=({children:e,onClick:t,...n})=>{let{index:r,tab:i}=Y(),a=J(e=>e.closeTab),o=J(e=>e.editingTabId===i.id),s=J(e=>e.tabsClosable),c=J(e=>e.visualSelected);if(!(s&&i.enableClose!==!1)||o)return null;let l=e=>{t?.(e),e.stopPropagation(),a(i.id)};return N(`button`,{"aria-label":`Close ${i.name}`,...n,"data-dashfoo":`tab-close`,onClick:l,tabIndex:r===c?0:-1,type:`button`,children:e??N(st,{})})},pt={display:`flex`,flexShrink:0},mt={display:`flex`,minWidth:0,overflowX:`auto`},ht=({style:e,...t})=>N(`div`,{...t,"data-dashfoo":`tabstrip`,style:{...pt,...e}}),gt=({onKeyDown:e,ref:t,style:n,...r})=>{let i=J(e=>e.node),a=J(e=>e.registerTablist),o=J(e=>e.selectTab),s=t=>{if(e?.(t),t.defaultPrevented||!(t.target instanceof HTMLElement)||!t.target.closest(`[role="tab"]`))return;let n=i.children.length;if(n===0)return;let r={ArrowLeft:(i.selected-1+n)%n,ArrowRight:(i.selected+1)%n,End:n-1,Home:0}[t.key];r!==void 0&&(t.preventDefault(),o(r,{focus:!0}))},c=C(()=>X(a,t),[a,t]);return N(`div`,{"aria-label":i.name??`Tabs`,...r,"aria-orientation":`horizontal`,"data-dashfoo":`tablist`,onKeyDown:s,ref:c,role:`tablist`,style:{...mt,...n},tabIndex:-1})},_t={alignItems:`center`,display:`flex`,flexShrink:0,marginInlineStart:`auto`},vt=({style:e,...t})=>N(`div`,{...t,"data-dashfoo":`tabset-toolbar`,style:{..._t,...e}}),yt=({children:e,ref:t,...n})=>{let r=J(e=>e.activeTab?.name??``),i=J(e=>e.isMaximized),a=J(e=>e.node),o=!V(e=>e.draggableTabsets)||i,{ref:s}=ge(a.id,o,r),c=C(()=>X(s,t),[s,t]);return o?null:N(`button`,{"aria-label":`Move tabset`,...n,"data-dashfoo":`tabset-grip`,ref:c,type:`button`,children:e??N(ct,{})})},Q=({children:e,onClick:t,...n})=>{let r=J(e=>e.isMaximized),i=J(e=>e.showMaximize),a=J(e=>e.toggleMaximize);if(!i)return null;let o=e=>{t?.(e),a()};return N(`button`,{"aria-label":r?`Restore`:`Maximize`,...n,"aria-pressed":r,"data-dashfoo":`tabset-maximize`,onClick:o,type:`button`,children:e??N(lt,{maximized:r})})},bt=()=>{let e=V(e=>e.draggableTabsets),t=V(e=>e.renderTabsetToolbar),n=V(e=>e.tabLocation),r=V(e=>e.tabStripEnabled),i=J(e=>e.isMaximized),a=J(e=>e.node),o=J(e=>e.overflowItems.length),s=J(e=>e.showMaximize)||t!==void 0||o>0||e&&!i,c=r?P(ht,{children:[N(gt,{children:a.children.map(e=>P(it,{tab:e,children:[N(at,{}),N(dt,{}),N(ft,{})]},e.id))}),s?P(vt,{children:[N(Ze,{}),N(yt,{}),t?.(a),N(Q,{})]}):null]}):null,l=N(qe,{});return n===`bottom`?P(ne,{children:[l,c]}):P(ne,{children:[c,l]})},xt=({node:e})=>N(nt,{node:e,children:N(bt,{})}),St=e=>`${e.value}${e.unit}`,Ct=e=>e?.unit===`px`?e.value:void 0,wt={display:`flex`,flex:1,minHeight:0,minWidth:0},Tt=.01,Et=(e,t)=>e.reduce((e,n)=>(e[n.id]=(n.weight??1)/t*100,e),{}),Dt=(e,t)=>{let n=Object.keys(e),r=Object.keys(t);return n.length===r.length?r.every(n=>Math.abs((e[n]??NaN)-t[n])<=Tt):!1},Ot=(e,t,n)=>{let r=Ct(e.min);if(r!==void 0)return r;if(e.min!==void 0)return;if(e.type===`tabset`)return n;let i=[];for(let r of e.children){let e=Ot(r,t,n);if(e===void 0)return;i.push(e)}if(i.length!==0)return e.orientation===t?i.reduce((e,t)=>e+t,0):Math.max(...i)},kt=({node:e,renderTabset:t})=>{let n=V(e=>e.dispatch),r=V(e=>e.tabsetMinSize),i=e.orientation===`row`?`horizontal`:`vertical`,a=e.children.reduce((e,t)=>e+(t.weight??1),0),o=C(()=>Et(e.children,a),[e.children,a]),s=w(!1),c=w(null),l=w(!1);return S(()=>{let e=c.current;if(!e||Dt(e.getLayout(),o))return;l.current=!0,e.setLayout(o);let t=requestAnimationFrame(()=>{l.current=!1});return()=>{cancelAnimationFrame(t),l.current=!1}},[o]),N(re,{"data-dashfoo":`row`,groupRef:c,onLayoutChanged:t=>{if(!s.current){s.current=!0;return}if(l.current)return;let r=e.children.map(e=>t[e.id]??e.weight??1);r.some((t,n)=>Math.abs(t-(e.children[n]?.weight??1))>Tt)&&n({rowId:e.id,type:`adjustSplit`,weights:r})},orientation:i,style:wt,children:e.children.map((n,i)=>{let o=(n.weight??1)/a*100,s=n.min?St(n.min):void 0;if(s===void 0){let t=Ot(n,e.orientation,r);s=t===void 0?void 0:`${t}px`}let c=n.max?St(n.max):void 0;return P(f,{children:[i>0?N(ae,{"data-dashfoo":`splitter`}):null,N(ie,{defaultSize:`${o}%`,id:n.id,maxSize:c,minSize:s,children:n.type===`row`?N(kt,{node:n,renderTabset:t}):t?.(n)??N(xt,{node:n})})]},n.id)})},e.children.map(e=>e.id).join(`|`))},$={DragLayer:ze,Root:Ve,Rows:kt,Tabset:xt},At=(e,t)=>e===void 0||!t?null:typeof e==`string`?{debounceMs:300,key:e,storage:F}:{debounceMs:e.debounceMs??300,key:e.key,storage:e.storage??F},jt=new Set,Mt=h((e,t)=>{let{closableTabs:n=!0,components:r,defaultModel:a,draggableTabsets:o=!0,factory:s,keepMounted:c=!1,maximizable:l=!0,model:u,onAction:d,onActiveTabsetChange:f,onMaximizedTabsetChange:p,onModelChange:m,persist:h,renamableTabs:_=!0,renderTabLabel:v,renderTabsetToolbar:y}=e,x=se(C(()=>At(h,a!==void 0),[h,a]),a),S=g((e,t)=>{x.save(e),m?.(e,t)},[m,x]),w=ce({defaultModel:x.initialModel??a,model:u,onAction:d,onActiveTabsetChange:f,onMaximizedTabsetChange:p,onModelChange:S});b(t,()=>({addTab:(e,t)=>w.dispatch({index:t.index,location:t.location??`center`,tab:e,targetId:t.targetId,type:`addNode`}),canRedo:w.canRedo,canUndo:w.canUndo,closeTab:e=>w.dispatch({tabId:e,type:`deleteTab`}),dispatch:w.dispatch,getModel:()=>w.model,maximizeTabset:e=>w.dispatch({tabsetId:e,type:`setMaximizedTabset`}),redo:w.redo,renameTab:(e,t)=>w.dispatch({name:t,tabId:e,type:`renameTab`}),resetLayout:()=>{x.clear(),a!==void 0&&w.setModel(a)},selectTab:(e,t)=>w.dispatch({index:t,tabsetId:e,type:`selectTab`}),undo:w.undo}),[a,x,w]);let T=g(e=>{if(s)return s(e);let t=r?.[e.component];return t?N(t,{node:e}):(r&&!jt.has(e.component)&&(jt.add(e.component),console.warn(`[dashfoo] no component registered for "${e.component}"`)),null)},[r,s]),E=w.model.maximizedTabsetId?i(w.model,w.model.maximizedTabsetId):void 0;return N($.Root,{closableTabs:n,dispatch:w.dispatch,draggableTabsets:o,keepMounted:c,maximizable:l,model:w.model,renamableTabs:_,renderTab:T,renderTabLabel:v,renderTabsetToolbar:y,children:N($.DragLayer,{children:E?N($.Tabset,{node:E}):N($.Rows,{node:w.model.layout})})})});Mt.displayName=`DashfooLayout`;const Nt=({children:e})=>{let[t]=T(ue);return x(()=>()=>t.destroy(),[t]),N(L.Provider,{value:t,children:e})},Pt={Badge:e=>N(`span`,{...e,"data-dashfoo":`panel-badge`}),Body:e=>N(`div`,{...e,"data-dashfoo":`panel-body`}),Header:e=>N(`div`,{...e,"data-dashfoo":`panel-header`}),Icon:e=>N(`span`,{...e,"data-dashfoo":`panel-icon`}),Root:e=>N(`div`,{...e,"data-dashfoo":`panel`}),Title:e=>N(`span`,{...e,"data-dashfoo":`panel-title`})},Ft={CloseButton:ft,Content:qe,Grip:yt,MaximizeButton:Q,OverflowMenu:Ze,RenameInput:dt,Root:nt,Tab:it,Tablist:gt,TabStrip:ht,Toolbar:vt,Trigger:at},It=()=>typeof window<`u`&&typeof window.matchMedia==`function`,Lt=(e,t)=>{let{query:n}=e;return n?`maxWidth`in n?t<=n.maxWidth:It()&&window.matchMedia(n.media).matches:!0},Rt=(e,t)=>{let n=e.at(-1);if(!n)throw Error(`useResponsiveModel requires at least one breakpoint.`);return e.find(e=>Lt(e,t))??n},zt=({breakpoints:e})=>{let[t,n]=T(1/0),[,r]=T(0),i=w(null),a=g(e=>{if(i.current?.disconnect(),!e)return;let t=new ResizeObserver(e=>{let t=e[0];t&&n(t.contentRect.width)});t.observe(e),i.current=t},[]);v(()=>()=>{i.current?.disconnect()},[]),v(()=>{if(!It())return;let t=e.flatMap(e=>e.query&&`media`in e.query?[window.matchMedia(e.query.media)]:[]);if(t.length===0)return;let n=()=>{r(e=>e+1)};for(let e of t)e.addEventListener(`change`,n);return()=>{for(let e of t)e.removeEventListener(`change`,n)}},[e]);let o=Rt(e,t);return{breakpoint:o.id,containerRef:a,defaultModel:o.model,key:o.id}};export{Nt as DashfooDragProvider,Mt as DashfooLayout,$ as Layout,Pt as Panel,Ft as Tabset,Rt as activeBreakpoint,F as localStorageAdapter,Lt as matchBreakpoint,oe as memoryStorageAdapter,ce as useDashfooStore,z as useDragSubject,ve as useExternalTabSource,V as useLayout,se as usePersistence,zt as useResponsiveModel,Y as useTab,J as useTabset};
2
9
  //# sourceMappingURL=index.js.map