dockview
Version:
React docking layout manager — tabs, groups, grids, splitviews, drag and drop, floating panels
8 lines (7 loc) • 16.6 kB
JavaScript
/**
* dockview
* @version 6.2.2
* @link https://github.com/mathuo/dockview
* @license MIT
*/
import{DockviewDisposable as e,DockviewEmitter as t,DockviewMutableDisposable as n,DockviewCompositeDisposable as o,PROPERTY_KEYS_DOCKVIEW as r,createDockview as a,SplitviewPanel as i,SplitviewApi as s,PROPERTY_KEYS_SPLITVIEW as c,createSplitview as p,GridviewPanel as l,GridviewApi as d,PROPERTY_KEYS_GRIDVIEW as u,createGridview as m,PROPERTY_KEYS_PANEVIEW as h,createPaneview as f}from"dockview-core";export*from"dockview-core";import v from"react";import C from"react-dom";const P=(e,t)=>{const[,n]=v.useState(0),o=v.useRef(e.componentProps);return v.useImperativeHandle(t,()=>({update:e=>{o.current=Object.assign(Object.assign({},o.current),e),n(e=>e+1)}}),[]),v.createElement(e.component,o.current)};P.displayName="DockviewReactJsBridge";const w=(()=>{let e=1;return{next:()=>`dockview_react_portal_key_${(e++).toString()}`}})(),b=v.createContext({});class g{constructor(e,t,n,o,r){this.parent=e,this.portalStore=t,this.component=n,this.parameters=o,this.context=r,this._initialProps={},this.disposed=!1,this.createPortal()}update(e){if(this.disposed)throw new Error("invalid operation: resource is already disposed");this.componentInstance?this.componentInstance.update(e):this._initialProps=Object.assign(Object.assign({},this._initialProps),e)}createPortal(){if(this.disposed)throw new Error("invalid operation: resource is already disposed");if(!y(this.component))throw new Error("Dockview: Only React.memo(...), React.ForwardRef(...) and functional components are accepted as components");const e=v.createElement(v.forwardRef(P),{component:this.component,componentProps:this.parameters,ref:e=>{this.componentInstance=e,Object.keys(this._initialProps).length>0&&(this.componentInstance.update(this._initialProps),this._initialProps={})}}),t=this.context?v.createElement(b.Provider,{value:this.context},e):e,n=C.createPortal(t,this.parent,w.next());this.ref={portal:n,disposable:this.portalStore.addPortal(n)}}dispose(){var e;null===(e=this.ref)||void 0===e||e.disposable.dispose(),this.disposed=!0}}const _=()=>{const[t,n]=v.useState([]);v.useDebugValue(`Portal count: ${t.length}`);return[t,v.useCallback(t=>{n(e=>[...e,t]);let o=!1;return e.from(()=>{if(o)throw new Error("invalid operation: resource already disposed");o=!0,n(e=>e.filter(e=>e!==t))})},[])]};function y(e){return"function"==typeof e||!!(null==e?void 0:e.$$typeof)}class E{get element(){return this._element}constructor(e,n,o){this.id=e,this.component=n,this.reactPortalStore=o,this._onDidFocus=new t,this.onDidFocus=this._onDidFocus.event,this._onDidBlur=new t,this.onDidBlur=this._onDidBlur.event,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.height="100%",this._element.style.width="100%"}focus(){}init(e){this.part=new g(this.element,this.reactPortalStore,this.component,{params:e.params,api:e.api,containerApi:e.containerApi})}update(e){var t;null===(t=this.part)||void 0===t||t.update({params:e.params})}layout(e,t){}dispose(){var e;this._onDidFocus.dispose(),this._onDidBlur.dispose(),null===(e=this.part)||void 0===e||e.dispose()}}class D{get element(){return this._element}constructor(e,t,n){this.id=e,this.component=t,this.reactPortalStore=n,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.height="100%",this._element.style.width="100%"}focus(){}init(e){this.part=new g(this.element,this.reactPortalStore,this.component,{params:e.params,api:e.api,containerApi:e.containerApi,tabLocation:e.tabLocation})}update(e){var t;null===(t=this.part)||void 0===t||t.update({params:e.params})}layout(e,t){}dispose(){var e;null===(e=this.part)||void 0===e||e.dispose()}}class A{get element(){return this._element}constructor(e,t,n){this.id=e,this.component=t,this.reactPortalStore=n,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.height="100%",this._element.style.width="100%"}init(e){this.part=new g(this.element,this.reactPortalStore,this.component,{group:e.group,containerApi:e.containerApi})}focus(){}update(e){var t,n,o;this.parameters&&(this.parameters.params=e.params),null===(t=this.part)||void 0===t||t.update({params:null!==(o=null===(n=this.parameters)||void 0===n?void 0:n.params)&&void 0!==o?o:{}})}layout(e,t){}dispose(){var e;null===(e=this.part)||void 0===e||e.dispose()}}class O{get element(){return this._element}get part(){return this._part}constructor(e,t,o){this.component=e,this.reactPortalStore=t,this._group=o,this.mutableDisposable=new n,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.height="100%",this._element.style.width="100%"}init(e){this.mutableDisposable.value=new o(this._group.model.onDidAddPanel(()=>{this.updatePanels()}),this._group.model.onDidRemovePanel(()=>{this.updatePanels()}),this._group.model.onDidActivePanelChange(()=>{this.updateActivePanel()}),e.api.onDidActiveChange(()=>{this.updateGroupActive()}),e.api.onDidLocationChange(e=>{this.updateLocation(e.location)})),this._part=new g(this.element,this.reactPortalStore,this.component,{api:e.api,containerApi:e.containerApi,panels:this._group.model.panels,activePanel:this._group.model.activePanel,isGroupActive:this._group.api.isActive,group:this._group,headerPosition:this._group.model.headerPosition,location:e.api.location})}dispose(){var e;this.mutableDisposable.dispose(),null===(e=this._part)||void 0===e||e.dispose()}update(e){var t;null===(t=this._part)||void 0===t||t.update(e.params)}updatePanels(){this.update({params:{panels:this._group.model.panels}})}updateActivePanel(){this.update({params:{activePanel:this._group.model.activePanel}})}updateGroupActive(){this.update({params:{isGroupActive:this._group.api.isActive}})}updateLocation(e){this.update({params:{location:e}})}}class R{get element(){return this._element}constructor(e,t,n){this.id=e,this.component=t,this.reactPortalStore=n,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.height="100%",this._element.style.width="100%"}init(e){this.part=new g(this._element,this.reactPortalStore,this.component,e)}dispose(){var e;null===(e=this.part)||void 0===e||e.dispose()}}class S{get element(){return this._element}constructor(e,t){this.component=e,this.reactPortalStore=t,this._element=document.createElement("div"),this._element.className="dv-react-part",this._element.style.display="inline-flex"}init(e){this.part=new g(this._element,this.reactPortalStore,this.component,{tabGroup:e.tabGroup,api:e.api})}update(e){var t;null===(t=this.part)||void 0===t||t.update({tabGroup:e.tabGroup})}dispose(){var e;null===(e=this.part)||void 0===e||e.dispose()}}function H(e,t){return e?n=>new O(e,t,n):void 0}const k="props.defaultTabComponent";const L=v.forwardRef((e,t)=>{const n=v.useRef(null),o=v.useRef(void 0),[i,s]=_();v.useImperativeHandle(t,()=>n.current,[]);const c=v.useRef({});return v.useEffect(()=>{const t={};r.forEach(n=>{const o=n,r=e[o];o in e&&r!==c.current[o]&&(t[o]=r)}),o.current&&o.current.updateOptions(t),c.current=e},r.map(t=>e[t])),v.useEffect(()=>{var t;if(!n.current)return;const i=null!==(t=e.tabComponents)&&void 0!==t?t:{};e.defaultTabComponent&&(i[k]=e.defaultTabComponent);const c={createLeftHeaderActionComponent:H(e.leftHeaderActionsComponent,{addPortal:s}),createRightHeaderActionComponent:H(e.rightHeaderActionsComponent,{addPortal:s}),createPrefixHeaderActionComponent:H(e.prefixHeaderActionsComponent,{addPortal:s}),createComponent:t=>new E(t.id,e.components[t.name],{addPortal:s}),createTabComponent:e=>new D(e.id,i[e.name],{addPortal:s}),createWatermarkComponent:e.watermarkComponent?()=>new A("watermark",e.watermarkComponent,{addPortal:s}):void 0,defaultTabComponent:e.defaultTabComponent?k:void 0,createContextMenuItemComponent:e=>{if(e.component)return new R(e.id,e.component,{addPortal:s})}},p=function(e){return r.reduce((t,n)=>(n in e&&(t[n]=e[n]),t),{})}(e);if(e.tabGroupChipComponent){const t=e.tabGroupChipComponent;p.createTabGroupChipComponent=()=>new S(t,{addPortal:s})}const l=a(n.current,Object.assign(Object.assign({},p),c)),{clientWidth:d,clientHeight:u}=n.current;return l.layout(d,u),e.onReady&&e.onReady({api:l}),o.current=l,()=>{o.current=void 0,l.dispose()}},[]),v.useEffect(()=>{if(!o.current)return()=>{};const t=o.current.onDidDrop(t=>{e.onDidDrop&&e.onDidDrop(t)});return()=>{t.dispose()}},[e.onDidDrop]),v.useEffect(()=>{if(!o.current)return()=>{};const t=o.current.onWillDrop(t=>{e.onWillDrop&&e.onWillDrop(t)});return()=>{t.dispose()}},[e.onWillDrop]),v.useEffect(()=>{o.current&&o.current.updateOptions({createTabGroupChipComponent:e.tabGroupChipComponent?()=>new S(e.tabGroupChipComponent,{addPortal:s}):void 0})},[e.tabGroupChipComponent]),v.useEffect(()=>{o.current&&o.current.updateOptions({createComponent:t=>new E(t.id,e.components[t.name],{addPortal:s})})},[e.components]),v.useEffect(()=>{var t;if(!o.current)return;const n=null!==(t=e.tabComponents)&&void 0!==t?t:{};e.defaultTabComponent&&(n[k]=e.defaultTabComponent),o.current.updateOptions({defaultTabComponent:e.defaultTabComponent?k:void 0,createTabComponent:e=>new D(e.id,n[e.name],{addPortal:s})})},[e.tabComponents,e.defaultTabComponent]),v.useEffect(()=>{o.current&&o.current.updateOptions({createWatermarkComponent:e.watermarkComponent?()=>new A("watermark",e.watermarkComponent,{addPortal:s}):void 0})},[e.watermarkComponent]),v.useEffect(()=>{o.current&&o.current.updateOptions({createRightHeaderActionComponent:H(e.rightHeaderActionsComponent,{addPortal:s})})},[e.rightHeaderActionsComponent]),v.useEffect(()=>{o.current&&o.current.updateOptions({createLeftHeaderActionComponent:H(e.leftHeaderActionsComponent,{addPortal:s})})},[e.leftHeaderActionsComponent]),v.useEffect(()=>{o.current&&o.current.updateOptions({createPrefixHeaderActionComponent:H(e.prefixHeaderActionsComponent,{addPortal:s})})},[e.prefixHeaderActionsComponent]),v.createElement("div",{style:{height:"100%",width:"100%"},ref:n},i)});L.displayName="DockviewComponent","function"==typeof SuppressedError&&SuppressedError;const x=()=>v.createElement("svg",{height:"11",width:"11",viewBox:"0 0 28 28","aria-hidden":"false",focusable:!1,className:"dv-svg"},v.createElement("path",{d:"M2.1 27.3L0 25.2L11.55 13.65L0 2.1L2.1 0L13.65 11.55L25.2 0L27.3 2.1L15.75 13.65L27.3 25.2L25.2 27.3L13.65 15.75L2.1 27.3Z"}));const j=e=>{var{api:t,containerApi:n,params:o,hideClose:r,closeActionOverride:a,onPointerDown:i,onPointerUp:s,onPointerLeave:c,tabLocation:p}=e,l=function(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(o=Object.getOwnPropertySymbols(e);r<o.length;r++)t.indexOf(o[r])<0&&Object.prototype.propertyIsEnumerable.call(e,o[r])&&(n[o[r]]=e[o[r]])}return n}(e,["api","containerApi","params","hideClose","closeActionOverride","onPointerDown","onPointerUp","onPointerLeave","tabLocation"]);const d=function(e){const[t,n]=v.useState(e.title);return v.useEffect(()=>{const o=e.onDidTitleChange(e=>{n(e.title)});return t!==e.title&&n(e.title),()=>{o.dispose()}},[e]),t}(t),u=v.useRef(!1),m=v.useCallback(e=>{e.preventDefault(),a?a():t.close()},[t,a]),h=v.useCallback(e=>{e.preventDefault()},[]),f=v.useCallback(e=>{u.current=1===e.button,null==i||i(e)},[i]),C=v.useCallback(e=>{u&&1===e.button&&!r&&(u.current=!1,m(e)),null==s||s(e)},[s,m,r]),P=v.useCallback(e=>{u.current=!1,null==c||c(e)},[c]);return v.createElement("div",Object.assign({"data-testid":"dockview-dv-default-tab"},l,{onPointerDown:f,onPointerUp:C,onPointerLeave:P,className:"dv-default-tab"}),v.createElement("span",{className:"dv-default-tab-content"},d),!r&&v.createElement("div",{className:"dv-default-tab-action",onPointerDown:h,onClick:m},v.createElement(x,null)))};class G extends i{constructor(e,t,n,o){super(e,t),this.reactComponent=n,this.reactPortalStore=o}getComponent(){var e,t;return new g(this.element,this.reactPortalStore,this.reactComponent,{params:null!==(t=null===(e=this._params)||void 0===e?void 0:e.params)&&void 0!==t?t:{},api:this.api,containerApi:new s(this._params.accessor)})}}const N=v.forwardRef((e,t)=>{const n=v.useRef(null),o=v.useRef(void 0),[r,a]=_();v.useImperativeHandle(t,()=>n.current,[]);const i=v.useRef({});return v.useEffect(()=>{const t={};c.forEach(n=>{const o=n,r=e[o];o in e&&r!==i.current[o]&&(t[o]=r)}),o.current&&o.current.updateOptions(t),i.current=e},c.map(t=>e[t])),v.useEffect(()=>{if(!n.current)return()=>{};const t={createComponent:t=>new G(t.id,t.name,e.components[t.name],{addPortal:a})},r=p(n.current,Object.assign(Object.assign({},function(e){return c.reduce((t,n)=>(n in e&&(t[n]=e[n]),t),{})}(e)),t)),{clientWidth:i,clientHeight:s}=n.current;return r.layout(i,s),e.onReady&&e.onReady({api:r}),o.current=r,()=>{o.current=void 0,r.dispose()}},[]),v.useEffect(()=>{o.current&&o.current.updateOptions({createComponent:t=>new G(t.id,t.name,e.components[t.name],{addPortal:a})})},[e.components]),v.createElement("div",{style:{height:"100%",width:"100%"},ref:n},r)});N.displayName="SplitviewComponent";class T extends l{constructor(e,t,n,o){super(e,t),this.reactComponent=n,this.reactPortalStore=o}getComponent(){var e,t;return new g(this.element,this.reactPortalStore,this.reactComponent,{params:null!==(t=null===(e=this._params)||void 0===e?void 0:e.params)&&void 0!==t?t:{},api:this.api,containerApi:new d(this._params.accessor)})}}const I=v.forwardRef((e,t)=>{const n=v.useRef(null),o=v.useRef(void 0),[r,a]=_();v.useImperativeHandle(t,()=>n.current,[]);const i=v.useRef({});return v.useEffect(()=>{const t={};u.forEach(n=>{const o=n,r=e[o];o in e&&r!==i.current[o]&&(t[o]=r)}),o.current&&o.current.updateOptions(t),i.current=e},u.map(t=>e[t])),v.useEffect(()=>{if(!n.current)return()=>{};const t={createComponent:t=>new T(t.id,t.name,e.components[t.name],{addPortal:a})},r=m(n.current,Object.assign(Object.assign({},function(e){return u.reduce((t,n)=>(n in e&&(t[n]=e[n]),t),{})}(e)),t)),{clientWidth:i,clientHeight:s}=n.current;return r.layout(i,s),e.onReady&&e.onReady({api:r}),o.current=r,()=>{o.current=void 0,r.dispose()}},[]),v.useEffect(()=>{o.current&&o.current.updateOptions({createComponent:t=>new T(t.id,t.name,e.components[t.name],{addPortal:a})})},[e.components]),v.createElement("div",{style:{height:"100%",width:"100%"},ref:n},r)});I.displayName="GridviewComponent";class W{get element(){return this._element}constructor(e,t,n){this.id=e,this.component=t,this.reactPortalStore=n,this._element=document.createElement("div"),this._element.style.height="100%",this._element.style.width="100%"}init(e){this.part=new g(this.element,this.reactPortalStore,this.component,{params:e.params,api:e.api,title:e.title,containerApi:e.containerApi})}toJSON(){return{id:this.id}}update(e){var t;null===(t=this.part)||void 0===t||t.update(e.params)}dispose(){var e;null===(e=this.part)||void 0===e||e.dispose()}}const B=v.forwardRef((e,t)=>{const n=v.useRef(null),o=v.useRef(void 0),[r,a]=_();v.useImperativeHandle(t,()=>n.current,[]);const i=v.useRef({});return v.useEffect(()=>{const t={};h.forEach(n=>{const o=n,r=e[o];o in e&&r!==i.current[o]&&(t[o]=r)}),o.current&&o.current.updateOptions(t),i.current=e},h.map(t=>e[t])),v.useEffect(()=>{var t;if(!n.current)return()=>{};const r=null!==(t=e.headerComponents)&&void 0!==t?t:{},i={createComponent:t=>new W(t.id,e.components[t.name],{addPortal:a}),createHeaderComponent:e=>new W(e.id,r[e.name],{addPortal:a})},s=f(n.current,Object.assign(Object.assign({},function(e){return h.reduce((t,n)=>(n in e&&(t[n]=e[n]),t),{})}(e)),i)),{clientWidth:c,clientHeight:p}=n.current;return s.layout(c,p),e.onReady&&e.onReady({api:s}),o.current=s,()=>{o.current=void 0,s.dispose()}},[]),v.useEffect(()=>{o.current&&o.current.updateOptions({createComponent:t=>new W(t.id,e.components[t.name],{addPortal:a})})},[e.components]),v.useEffect(()=>{var t;if(!o.current)return;const n=null!==(t=e.headerComponents)&&void 0!==t?t:{};o.current.updateOptions({createHeaderComponent:e=>new W(e.id,n[e.name],{addPortal:a})})},[e.headerComponents]),v.useEffect(()=>{if(!o.current)return()=>{};const t=o.current.onDidDrop(t=>{e.onDidDrop&&e.onDidDrop(t)});return()=>{t.dispose()}},[e.onDidDrop]),v.createElement("div",{style:{height:"100%",width:"100%"},ref:n},r)});B.displayName="PaneviewComponent";export{j as DockviewDefaultTab,L as DockviewReact,I as GridviewReact,B as PaneviewReact,g as ReactPart,b as ReactPartContext,N as SplitviewReact,y as isReactComponent,_ as usePortalsLifecycle};